/** * Test for issue #49: Sessions not associated with a memcached node don't get associated as soon * as a memcached is available * * @throws InterruptedException * @throws IOException * @throws TimeoutException * @throws ExecutionException */ @Test(enabled = true) public void testNotAssociatedSessionGetsAssociatedIssue49() throws InterruptedException, IOException, ExecutionException, TimeoutException { _daemon.stop(); final SessionManager manager = _tomcat1.getManager(); manager.setMaxInactiveInterval(5); manager.setSticky(true); final SessionIdFormat sessionIdFormat = new SessionIdFormat(); final Session session = manager.createSession(null); assertNull(sessionIdFormat.extractMemcachedId(session.getId())); _daemon.start(); // Wait so that the daemon will be available and the client can reconnect (async get didn't do // the trick) Thread.sleep(4000); final String newSessionId = manager.getMemcachedSessionService().changeSessionIdOnMemcachedFailover(session.getId()); assertNotNull(newSessionId); assertEquals(newSessionId, session.getId()); assertEquals(sessionIdFormat.extractMemcachedId(newSessionId), _memcachedNodeId); }
private void waitForSessionExpiration(final boolean sticky) throws InterruptedException { final SessionManager manager = _tomcat1.getManager(); assertEquals(manager.getMemcachedSessionService().isSticky(), sticky); final Container container = manager.getContainer(); final long timeout = TimeUnit.SECONDS.toMillis( sticky ? container.getBackgroundProcessorDelay() + manager.getMaxInactiveInterval() : 2 * manager.getMaxInactiveInterval()) + 1000; Thread.sleep(timeout); }
/** 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(); }
/** * 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"); }
private void setStickyness(final SessionAffinityMode sessionAffinity) { if (!sessionAffinity.isSticky()) { _tomcat1.getEngine().setJvmRoute(null); } final SessionManager manager = _tomcat1.getManager(); manager.setSticky(sessionAffinity.isSticky()); try { waitForReconnect(manager.getMemcachedSessionService().getMemcached(), 1, 500); } catch (final InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } }
/** * 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"); }
@BeforeMethod public void setUp() throws Exception { _service = mock(MemcachedSessionService.class); _request = mock(Request.class); _response = mock(Response.class); final Context _contextContainer = mock(Context.class); final Host _hostContainer = mock(Host.class); final SessionManager _manager = mock(SessionManager.class); when(_service.getManager()).thenReturn(_manager); when(_manager.getContainer()).thenReturn(_contextContainer); when(_contextContainer.getParent()).thenReturn(_hostContainer); when(_contextContainer.getPath()).thenReturn("/"); _sessionTrackerValve = createSessionTrackerValve(); _nextValve = mock(Valve.class); _sessionTrackerValve.setNext(_nextValve); _sessionTrackerValve.setContainer(_hostContainer); _memcachedNodesManager = mock(MemcachedNodesManager.class); _sessionIdFormat = mock(SessionIdFormat.class); when(_request.getRequestURI()).thenReturn("/someRequest"); when(_request.getMethod()).thenReturn("GET"); when(_request.getQueryString()).thenReturn(null); when(_request.getContext()).thenReturn(_contextContainer); when(_request.getNote(eq(RequestTrackingHostValve.REQUEST_PROCESSED))).thenReturn(Boolean.TRUE); when(_request.getNote(eq(RequestTrackingHostValve.SESSION_ID_CHANGED))) .thenReturn(Boolean.FALSE); when(_sessionIdFormat.extractMemcachedId(anyString())).thenReturn(PRIMARY_NODE_IDENTIFIER); when(_service.getMemcachedNodesManager()).thenReturn(_memcachedNodesManager); when(_memcachedNodesManager.isNodeAvailable(PRIMARY_NODE_IDENTIFIER)) .thenReturn(IS_PRIMARY_MEMCACHED_NODE_OPERATIONAL); when(_memcachedNodesManager.getSessionIdFormat()).thenReturn(_sessionIdFormat); }
private static Principal deserializePrincipal(final byte[] data, final SessionManager manager) { ByteArrayInputStream bis = null; ObjectInputStream ois = null; try { bis = new ByteArrayInputStream(data); ois = new ObjectInputStream(bis); return manager.readPrincipal(ois); } catch (final IOException e) { throw new IllegalArgumentException("Could not deserialize principal", e); } catch (final ClassNotFoundException e) { throw new IllegalArgumentException("Could not deserialize principal", e); } finally { closeSilently(bis); closeSilently(ois); } }
static DeserializationResult deserializeSessionFields( final byte[] data, final SessionManager manager) throws InvalidVersionException { final MemcachedBackupSession result = manager.newMemcachedBackupSession(); final short version = (short) decodeNum(data, 0, 2); if (version != CURRENT_VERSION) { throw new InvalidVersionException( "The version " + version + " does not match the current version " + CURRENT_VERSION, version); } final short sessionFieldsDataLength = (short) decodeNum(data, 2, 2); result.setCreationTimeInternal(decodeNum(data, 4, 8)); result.setLastAccessedTimeInternal(decodeNum(data, 12, 8)); result.setMaxInactiveInterval((int) decodeNum(data, 20, 4)); result.setIsNewInternal(decodeBoolean(data, 24)); result.setIsValidInternal(decodeBoolean(data, 25)); result.setThisAccessedTimeInternal(decodeNum(data, 26, 8)); result.setLastBackupTime(decodeNum(data, 34, 8)); final short idLength = (short) decodeNum(data, 42, 2); result.setIdInternal(decodeString(data, 44, idLength)); final short authTypeId = (short) decodeNum(data, 44 + idLength, 2); result.setAuthTypeInternal(AuthType.valueOfId(authTypeId).getValue()); final int currentIdx = 44 + idLength + 2; final short principalDataLength = (short) decodeNum(data, currentIdx, 2); if (principalDataLength > 0) { final byte[] principalData = new byte[principalDataLength]; System.arraycopy(data, currentIdx + 2, principalData, 0, principalDataLength); result.setPrincipalInternal(deserializePrincipal(principalData, manager)); } final byte[] attributesData = new byte[data.length - sessionFieldsDataLength]; System.arraycopy( data, sessionFieldsDataLength, attributesData, 0, data.length - sessionFieldsDataLength); return new DeserializationResult(result, attributesData); }