/** * Tests update of session expiration in memcached (like {@link * #testExpirationOfSessionsInMemcachedIfBackupWasSkippedSimple()}) but for the scenario where * many readonly requests occur: in this case, we cannot just use <em>maxInactiveInterval - * secondsSinceLastBackup</em> (in {@link MemcachedSessionService#updateExpirationInMemcached}) to * determine if an expiration update is required, but we must use the last expiration time sent to * memcached. * * @throws Exception if something goes wrong with the http communication with tomcat */ @Test(enabled = true, dataProviderClass = TestUtils.class, dataProvider = STICKYNESS_PROVIDER) public void testExpirationOfSessionsInMemcachedIfBackupWasSkippedManyReadonlyRequests( final SessionAffinityMode stickyness) throws Exception { final SessionManager manager = _tomcat1.getManager(); setStickyness(stickyness); // set to 1 sec above (in setup), default is 10 seconds final int delay = manager.getContainer().getBackgroundProcessorDelay(); manager.setMaxInactiveInterval(delay * 4); final String sessionId1 = makeRequest(_httpClient, _portTomcat1, null); assertNotNull(sessionId1, "No session created."); assertWaitingWithProxy(Predicates.<MemcachedClientIF>notNull(), 200l, _memcached) .get(sessionId1); /* after 3 seconds make another request without changing the session, so that * it's not sent to memcached */ Thread.sleep(TimeUnit.SECONDS.toMillis(delay * 3)); assertEquals( makeRequest(_httpClient, _portTomcat1, sessionId1), sessionId1, "SessionId should be the same"); assertNotNull(_memcached.get(sessionId1), "Session should still exist in memcached."); /* after another 3 seconds make another request without changing the session */ Thread.sleep(TimeUnit.SECONDS.toMillis(delay * 3)); assertEquals( makeRequest(_httpClient, _portTomcat1, sessionId1), sessionId1, "SessionId should be the same"); assertNotNull(_memcached.get(sessionId1), "Session should still exist in memcached."); /* after another nearly 4 seconds (maxInactiveInterval) check that the session is still alive in memcached, * this would have been expired without an updated expiration */ Thread.sleep(TimeUnit.SECONDS.toMillis(manager.getMaxInactiveInterval()) - 500); assertNotNull(_memcached.get(sessionId1), "Session should still exist in memcached."); /* after another second in sticky mode (more than 4 seconds since the last request), or an two times the * maxInactiveInterval in non-sticky mode (we must keep sessions in memcached with double expirationtime) * the session must be expired in memcached */ Thread.sleep(TimeUnit.SECONDS.toMillis(delay) + 500); assertNotSame( makeRequest(_httpClient, _portTomcat1, sessionId1), sessionId1, "The sessionId should have changed due to expired sessin"); }
/** * Test for issue #60 (Add possibility to disable msm at runtime): start msm disabled and * afterwards enable */ @Test(enabled = true) public void testStartMsmDisabled() throws Exception { // shutdown our server and our client _memcached.shutdown(); _daemon.stop(); // start a new tomcat with msm initially disabled _tomcat1.stop(); Thread.sleep(500); final String memcachedNodes = _memcachedNodeId + ":localhost:" + _memcachedPort; _tomcat1 = getTestUtils() .tomcatBuilder() .port(_portTomcat1) .memcachedNodes(memcachedNodes) .sticky(true) .enabled(false) .jvmRoute("app1") .buildAndStart(); LOG.info("Waiting, check logs to see if the client causes any 'Connection refused' logging..."); Thread.sleep(1000); // some basic tests for session functionality checkSessionFunctionalityWithMsmDisabled(); // start memcached, client and reenable msm _daemon.start(); _memcached = createMemcachedClient(memcachedNodes, new InetSocketAddress("localhost", _memcachedPort)); _tomcat1.getManager().setEnabled(true); // Wait a little bit, so that msm's memcached client can connect and is ready when test starts Thread.sleep(100); // memcached based stuff should work again final String sessionId1 = makeRequest(_httpClient, _portTomcat1, null); assertNotNull(sessionId1, "No session created."); assertNotNull( new SessionIdFormat().extractMemcachedId(sessionId1), "memcached node id missing with msm switched to enabled"); Thread.sleep(50); assertNotNull(_memcached.get(sessionId1), "Session not available in memcached."); waitForSessionExpiration(true); assertNull(_memcached.get(sessionId1), "Expired session still existing in memcached"); }
@Test public void flush() throws CacheException { EasyMock.expect(client.flush()).andReturn(getFuture(true)); EasyMock.replay(client); clientWrapper.flush(); EasyMock.verify(client); }
@Test public void delete() throws TimeoutException, CacheException { EasyMock.expect(client.delete("key1")).andReturn(getFuture(true)); EasyMock.replay(client); assertTrue(clientWrapper.delete("key1")); EasyMock.verify(client); }
@AfterMethod public void tearDown() throws Exception { _memcached.shutdown(); _tomcat1.stop(); _httpClient.getConnectionManager().shutdown(); _daemon.stop(); }
@Test public void getString() throws TimeoutException, CacheException { EasyMock.expect(client.get("key1")).andReturn("test-value"); EasyMock.replay(client); assertEquals("test-value", clientWrapper.get("key1")); EasyMock.verify(client); }
@Test public void decrStringIntLong() throws TimeoutException, CacheException { EasyMock.expect(client.decr("key1", 1, 10L)).andReturn(2L); EasyMock.replay(client); assertEquals(2L, clientWrapper.decr("key1", 1, 10)); EasyMock.verify(client); }
@Test public void addStringIntObject() throws TimeoutException, CacheException { EasyMock.expect(client.add("test", 1000, "value")).andReturn(getFuture(true)); EasyMock.replay(client); assertTrue(clientWrapper.add("test", 1000, "value")); EasyMock.verify(client); }
@Test public void getTranscoder() { EasyMock.expect(client.getTranscoder()).andReturn(null); EasyMock.replay(client); clientWrapper.getTranscoder(); EasyMock.verify(client); }
@Test public void shutdown() { client.shutdown(); EasyMock.expectLastCall(); EasyMock.replay(client); clientWrapper.shutdown(); EasyMock.verify(client); }
@Test @SuppressWarnings("unchecked") public void getAvailableServers() { Collection<SocketAddress> servers = EasyMock.createMock(Collection.class); EasyMock.expect(client.getAvailableServers()).andReturn(servers); EasyMock.replay(client); assertEquals(servers, clientWrapper.getAvailableServers()); EasyMock.verify(client); }
@Test @SuppressWarnings("unchecked") public void getStringMemcacheTranscoderOfTLong() throws TimeoutException, CacheException { CacheTranscoder transcoder = EasyMock.createMock(CacheTranscoder.class); EasyMock.expect(client.asyncGet(EasyMock.eq("key1"), EasyMock.anyObject(Transcoder.class))) .andReturn(getFuture("test-value")); EasyMock.replay(client); assertEquals("test-value", clientWrapper.get("key1", transcoder, 100)); EasyMock.verify(client); }
@Test @SuppressWarnings("unchecked") public void getBulkCollectionOfString() throws TimeoutException, CacheException { Collection<String> keys = EasyMock.createMock(Collection.class); Map<String, Object> results = EasyMock.createMock(Map.class); EasyMock.expect(client.getBulk(keys)).andReturn(results); EasyMock.replay(client); assertEquals(results, clientWrapper.getBulk(keys)); EasyMock.verify(client); }
@Test(enabled = true, dataProviderClass = TestUtils.class, dataProvider = STICKYNESS_PROVIDER) public void testSessionAvailableInMemcached(final SessionAffinityMode sessionAffinity) throws IOException, InterruptedException, HttpException { setStickyness(sessionAffinity); final String sessionId1 = makeRequest(_httpClient, _portTomcat1, null); assertNotNull(sessionId1, "No session created."); Thread.sleep(50); assertNotNull(_memcached.get(sessionId1), "Session not available in memcached."); }
@Test(enabled = true, dataProviderClass = TestUtils.class, dataProvider = STICKYNESS_PROVIDER) public void testInvalidatedSessionRemovedFromMemcached( @Nonnull final SessionAffinityMode sessionAffinity) throws IOException, InterruptedException, HttpException { setStickyness(sessionAffinity); final String sessionId1 = makeRequest(_httpClient, _portTomcat1, null); assertNotNull(sessionId1, "No session created."); final Response response = get(_httpClient, _portTomcat1, PATH_INVALIDATE, sessionId1); assertNull(response.getResponseSessionId()); assertEquals(_daemon.getCache().getGetMisses(), 1); // 1 is ok assertNull(_memcached.get(sessionId1), "Invalidated session still existing in memcached"); if (!sessionAffinity.isSticky()) { assertNull( _memcached.get(createValidityInfoKeyName(sessionId1)), "ValidityInfo for invalidated session still exists in memcached."); } }
/** * Tests, that for a session that was not sent to memcached (because it's attributes were not * modified), the expiration is updated so that they don't expire in memcached before they expire * in tomcat. * * @throws Exception if something goes wrong with the http communication with tomcat */ @Test(enabled = true, dataProviderClass = TestUtils.class, dataProvider = STICKYNESS_PROVIDER) public void testExpirationOfSessionsInMemcachedIfBackupWasSkippedSimple( final SessionAffinityMode stickyness) throws Exception { final SessionManager manager = _tomcat1.getManager(); setStickyness(stickyness); // set to 1 sec above (in setup), default is 10 seconds final int delay = manager.getContainer().getBackgroundProcessorDelay(); manager.setMaxInactiveInterval(delay * 4); final String sessionId1 = makeRequest(_httpClient, _portTomcat1, null); assertNotNull(sessionId1, "No session created."); assertNotNull(_memcached.get(sessionId1), "Session not available in memcached."); /* after 2 seconds make another request without changing the session, so that * it's not sent to memcached */ Thread.sleep(TimeUnit.SECONDS.toMillis(delay * 2)); assertEquals( makeRequest(_httpClient, _portTomcat1, sessionId1), sessionId1, "SessionId should be the same"); /* after another 3 seconds check that the session is still alive in memcached, * this would have been expired without an updated expiration */ Thread.sleep(TimeUnit.SECONDS.toMillis(delay * 3)); assertNotNull(_memcached.get(sessionId1), "Session should still exist in memcached."); /* after another >1 second (4 seconds since the last request) * the session must be expired in memcached */ Thread.sleep( TimeUnit.SECONDS.toMillis(delay) + 500); // +1000 just to be sure that we're >4 secs assertNotSame( makeRequest(_httpClient, _portTomcat1, sessionId1), sessionId1, "The sessionId should have changed due to expired sessin"); }
/** Test for issue #60 (Add possibility to disable msm at runtime): disable msm */ @Test(enabled = true) public void testDisableMsmAtRuntime() throws InterruptedException, IOException, ExecutionException, TimeoutException, LifecycleException, HttpException { final SessionManager manager = _tomcat1.getManager(); manager.setSticky(true); // disable msm, shutdown our server and our client manager.setEnabled(false); _memcached.shutdown(); _daemon.stop(); checkSessionFunctionalityWithMsmDisabled(); }
@Test(enabled = true, dataProviderClass = TestUtils.class, dataProvider = STICKYNESS_PROVIDER) public void testExpiredSessionRemovedFromMemcached( @Nonnull final SessionAffinityMode sessionAffinity) throws IOException, InterruptedException, HttpException { setStickyness(sessionAffinity); final String sessionId1 = makeRequest(_httpClient, _portTomcat1, null); assertNotNull(sessionId1, "No session created."); waitForSessionExpiration(sessionAffinity.isSticky()); assertNull(_memcached.get(sessionId1), "Expired session still existing in memcached"); }
@Test @SuppressWarnings("unchecked") public void addStringIntTMemcacheTranscoderOfT() throws TimeoutException, CacheException { CacheTranscoder transcoder = EasyMock.createMock(CacheTranscoder.class); EasyMock.expect( client.add( EasyMock.eq("test"), EasyMock.eq(1000), EasyMock.eq("value"), EasyMock.anyObject(Transcoder.class))) .andReturn(getFuture(true)); EasyMock.replay(client, transcoder); assertTrue(clientWrapper.add("test", 1000, "value", transcoder)); EasyMock.verify(client, transcoder); }
@Test(enabled = true, dataProviderClass = TestUtils.class, dataProvider = STICKYNESS_PROVIDER) public void testSessionAvailableInMemcachedWithCookiesDisabled( final SessionAffinityMode sessionAffinity) throws Exception { _tomcat1.stop(); _tomcat1 = tcBuilder() .sticky(sessionAffinity.isSticky()) .cookies(false) .jvmRoute("app1") .buildAndStart(); final Response response = get(_httpClient, _portTomcat1, null); final String sessionId = response.get(TestServlet.ID); assertNotNull(sessionId, "No session created."); Thread.sleep(50); assertNotNull(_memcached.get(sessionId), "Session not available in memcached."); }
private void doUpdate(final JoinPoint jp, final Object retVal) throws Throwable { if (isCacheDisabled()) { LOG.debug("Caching is disabled."); return; } final MemcachedClientIF cache = getMemcachedClient(); final Method methodToCache = getMethodToCache(jp); List<UpdateSingleCache> lAnnotations; if (methodToCache.getAnnotation(UpdateSingleCache.class) != null) { lAnnotations = Arrays.asList(methodToCache.getAnnotation(UpdateSingleCache.class)); } else { lAnnotations = Arrays.asList(methodToCache.getAnnotation(UpdateSingleCaches.class).value()); } for (int i = 0; i < lAnnotations.size(); i++) { // This is injected caching. If anything goes wrong in the caching, LOG the crap outta it, // but do not let it surface up past the AOP injection itself. try { final AnnotationInfo info = getAnnotationInfo(lAnnotations.get(i), methodToCache.getName(), getJitterDefault()); final String baseKey = CacheBase.getBaseKey( info.getAsString(AType.KEY_TEMPLATE), info.getAsInteger(AType.KEY_INDEX, null), retVal, jp.getArgs(), methodToCache.toString(), factory, methodStore); final String cacheKey = buildCacheKey( baseKey, info.getAsString(AType.NAMESPACE), info.getAsString(AType.KEY_PREFIX)); Object dataObject = getIndexObject( info.getAsInteger(AType.DATA_INDEX, null), retVal, jp.getArgs(), methodToCache.toString()); dataObject = UpdateSingleCacheAdvice.getMergedData( dataObject, info.getAsString(AType.DATA_TEMPLATE, null), retVal, jp.getArgs(), factory); final Class dataTemplateType = (Class) info.getAsType(AType.DATA_TEMPLATE_TYPE, String.class); final Object submission = (dataObject == null) ? new PertinentNegativeNull() : applyDataTemplateType(dataObject, dataTemplateType); boolean cacheable = true; if (submission instanceof CacheConditionally) { cacheable = ((CacheConditionally) submission).isCacheable(); } if (cacheable) { cache.set( cacheKey, calculateJitteredExpiration( info.getAsInteger(AType.EXPIRATION), info.getAsInteger(AType.JITTER)), submission); } // Notify the observers that a cache interaction happened. final List<UpdateSingleCacheListener> listeners = getPertinentListeners( UpdateSingleCacheListener.class, info.getAsString(AType.NAMESPACE)); if (listeners != null && !listeners.isEmpty()) { for (final UpdateSingleCacheListener listener : listeners) { try { listener.triggeredUpdateSingleCache( info.getAsString(AType.NAMESPACE), info.getAsString(AType.KEY_PREFIX, null), baseKey, dataObject, retVal, jp.getArgs()); } catch (Exception ex) { LOG.warn("Problem when triggering a listener.", ex); } } } } catch (Exception ex) { if (LOG.isDebugEnabled()) { LOG.warn("Caching on " + jp.toShortString() + " aborted due to an error.", ex); } else { LOG.warn( "Caching on " + jp.toShortString() + " aborted due to an error: " + ex.getMessage()); } } } }
@Override public Object get(final String key) { return _memcached.get(key); }