diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionIdManager.java b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionIdManager.java index ceb0d1c760d0..7ca6a58b7391 100644 --- a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionIdManager.java +++ b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionIdManager.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.session.infinispan; import java.util.Random; +import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @@ -32,7 +33,8 @@ import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import org.infinispan.Cache; +import org.infinispan.commons.api.BasicCache; + @@ -51,18 +53,25 @@ * * where [id] is the id of the session. * + * If the first session to be added is not immortal (ie it has a timeout on it) then + * the corresponding session id is entered into infinispan with an idle expiry timeout + * equivalent to double the session's timeout (the multiplier is configurable). + * + * * Having one entry per in-use session id means that there is no contention on * cache entries (as would be the case if a single entry was kept containing a * list of in-use session ids). * - * TODO synchronization + * */ public class InfinispanSessionIdManager extends AbstractSessionIdManager { private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); - protected final static String ID_KEY = "__o.e.j.s.infinispanIdMgr__"; - protected Cache _cache; + public final static String ID_KEY = "__o.e.j.s.infinispanIdMgr__"; + public static final int DEFAULT_IDLE_EXPIRY_MULTIPLE = 2; + protected BasicCache _cache; private Server _server; + private int _idleExpiryMultiple = DEFAULT_IDLE_EXPIRY_MULTIPLE; @@ -131,7 +140,8 @@ public boolean idInUse(String id) String clusterId = getClusterId(id); - //ask the cluster + //ask the cluster - this should also tickle the idle expiration timer on the sessionid entry + //keeping it valid try { return exists(clusterId); @@ -154,13 +164,35 @@ public boolean idInUse(String id) @Override public void addSession(HttpSession session) { - if (session == null) - return; + if (session == null) + return; + + //insert into the cache and set an idle expiry on the entry that + //is based off the max idle time configured for the session. If the + //session is immortal, then there is no idle expiry on the corresponding + //session id + if (session.getMaxInactiveInterval() == 0) + insert (((AbstractSession)session).getClusterId()); + else + insert (((AbstractSession)session).getClusterId(), session.getMaxInactiveInterval() * getIdleExpiryMultiple()); + } + - //insert into the cache - insert (((AbstractSession)session).getClusterId()); + public void setIdleExpiryMultiple (int multiplier) + { + if (multiplier <= 1) + { + LOG.warn("Idle expiry multiple of {} for session ids set to less than minimum. Using value of {} instead.", multiplier, DEFAULT_IDLE_EXPIRY_MULTIPLE); + } + _idleExpiryMultiple = multiplier; } + public int getIdleExpiryMultiple () + { + return _idleExpiryMultiple; + } + + /** * Remove a session id from the list of in-use ids. * @@ -245,16 +277,38 @@ public void renewSessionId(String oldClusterId, String oldNodeId, HttpServletReq } - public Cache getCache() + /** + * Get the cache. + * @return + */ + public BasicCache getCache() { return _cache; } - public void setCache(Cache cache) + /** + * Set the cache. + * @param cache + */ + public void setCache(BasicCache cache) { this._cache = cache; } + + + /** + * Do any operation to the session id in the cache to + * ensure its idle expiry time moves forward + * @param id + */ + public void touch (String id) + { + exists(id); + } + + + /** * Ask the cluster if a particular id exists. * @@ -266,10 +320,7 @@ protected boolean exists (String id) if (_cache == null) throw new IllegalStateException ("No cache"); - Object key =_cache.get(makeKey(id)); - if (key == null) - return false; - return true; + return _cache.containsKey(makeKey(id)); } @@ -287,6 +338,19 @@ protected void insert (String id) } + /** + * Put a session id into the cluster with an idle expiry. + * + * @param id + */ + protected void insert (String id, long idleTimeOutSec) + { + if (_cache == null) + throw new IllegalStateException ("No cache"); + + _cache.putIfAbsent(makeKey(id),id,-1L, TimeUnit.SECONDS, idleTimeOutSec, TimeUnit.SECONDS); + } + /** * Remove a session id from the cluster. diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionManager.java b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionManager.java index ca4d80899de7..6e79a2a46365 100644 --- a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionManager.java +++ b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionManager.java @@ -42,6 +42,8 @@ import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler; import org.eclipse.jetty.util.thread.Scheduler; import org.infinispan.Cache; +import org.infinispan.commons.api.BasicCache; +import org.omg.CORBA._IDLTypeStub; /** * InfinispanSessionManager @@ -73,7 +75,7 @@ public class InfinispanSessionManager extends AbstractSessionManager /** * Clustered cache of sessions */ - private Cache _cache; + private BasicCache _cache; /** @@ -197,7 +199,7 @@ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassN lastNode = in.readUTF(); //last managing node expiry = in.readLong(); maxInactive = in.readLong(); - HashMap attributes = (HashMap)in.readObject(); + attributes = (HashMap)in.readObject(); } } @@ -205,102 +207,6 @@ private void readObject(java.io.ObjectInputStream in) throws IOException, ClassN - /** - * SerializableSession - * - * Helper class that is responsible for de/serialization of the non-serializable session object. - */ - public class SerializableSession implements Serializable - { - - /** - * - */ - private static final long serialVersionUID = -7603529353470249059L; - private transient Session _session; - - - public SerializableSession () - { - - } - - public SerializableSession (Session session) - { - setSession(session); - } - - /** - * Existing session - * @param session - */ - public void setSession (Session session) - { - _session = session; - } - - public Session getSession () - { - return _session; - } - - - private void writeObject(java.io.ObjectOutputStream out) throws IOException - { - if (_session == null) - throw new IOException ("No session to serialize"); - - out.writeUTF(_session.getClusterId()); //session id - out.writeUTF(_session.getContextPath()); //context path - out.writeUTF(_session.getVHost()); //first vhost - - out.writeLong(_session.getAccessed());//accessTime - out.writeLong(_session.getLastAccessedTime()); //lastAccessTime - out.writeLong(_session.getCreationTime()); //time created - out.writeLong(_session.getCookieSetTime());//time cookie was set - out.writeUTF(_session.getLastNode()); //name of last node managing - - out.writeLong(_session.getExpiry()); - out.writeLong(_session.getMaxInactiveInterval()); - out.writeObject(_session.getAttributeMap()); - } - - - private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException - { - String clusterId = in.readUTF(); - String context = in.readUTF(); - String vhost = in.readUTF(); - - Long accessed = in.readLong();//accessTime - Long lastAccessed = in.readLong(); //lastAccessTime - Long created = in.readLong(); //time created - Long cookieSet = in.readLong();//time cookie was set - String lastNode = in.readUTF(); //last managing node - Long expiry = in.readLong(); - Long maxIdle = in.readLong(); - HashMap attributes = (HashMap)in.readObject(); - Session session = new Session(clusterId, created, accessed, maxIdle); - session.setCookieSetTime(cookieSet); - session.setLastAccessedTime(lastAccessed); - session.setLastNode(lastNode); - session.setContextPath(context); - session.setVHost(vhost); - session.setExpiry(expiry); - session.addAttributes(attributes); - setSession(session); - } - - - private void readObjectNoData() throws ObjectStreamException - { - setSession(null); - } - - - } - - /** * Session * @@ -317,11 +223,6 @@ public class Session extends MemSession private String _contextPath; - /** - * The number of currently active request threads in this session - */ - private AtomicInteger _activeThreads = new AtomicInteger(0); - /** * The time in msec since the epoch at which this session should expire @@ -341,12 +242,24 @@ public class Session extends MemSession private String _lastNode; + /** + * If dirty, session needs to be (re)sent to cluster + */ + protected boolean _dirty=false; + + /** * Any virtual hosts for the context with which this session is associated */ private String _vhost; + + + /** + * Count of how many threads are active in this session + */ + private AtomicInteger _activeThreads = new AtomicInteger(0); @@ -364,6 +277,7 @@ protected Session (HttpServletRequest request) _lastNode = getSessionIdManager().getWorkerName(); setVHost(InfinispanSessionManager.getVirtualHost(_context)); setContextPath(InfinispanSessionManager.getContextPath(_context)); + _activeThreads.incrementAndGet(); //access will not be called on a freshly created session so increment here } @@ -404,13 +318,13 @@ protected boolean access(long time) LOG.debug("Access session({}) for context {} on worker {}", getId(), getContextPath(), getSessionIdManager().getWorkerName()); try { - _lock.lock(); + long now = System.currentTimeMillis(); + //lock so that no other thread can call access or complete until the first one has refreshed the session object if necessary + _lock.lock(); //a request thread is entering if (_activeThreads.incrementAndGet() == 1) { - long now = System.currentTimeMillis(); - //if the first thread, check that the session in memory is not stale, if we're checking for stale sessions if (getStaleIntervalSec() > 0 && (now - getLastSyncTime()) >= (getStaleIntervalSec() * 1000L)) { @@ -448,28 +362,65 @@ protected void complete() { super.complete(); - //if this is the last request thread to be in the session - if (_activeThreads.decrementAndGet() == 0) + //lock so that no other thread that might be calling access can proceed until this complete is done + _lock.lock(); + + try { - try + //if this is the last request thread to be in the session + if (_activeThreads.decrementAndGet() == 0) { - //an invalid session will already have been removed from the - //local session map and deleted from the cluster. If its valid save - //it to the cluster. - //TODO consider doing only periodic saves if only the last access - //time to the session changes - if (isValid()) + try { - willPassivate(); - save(this); - didActivate(); + //an invalid session will already have been removed from the + //local session map and deleted from the cluster. If its valid save + //it to the cluster. + //TODO consider doing only periodic saves if only the last access + //time to the session changes + if (isValid()) + { + //if session still valid && its dirty or stale or never been synced, write it to the cluster + //otherwise, we just keep the updated last access time in memory + if (_dirty || getLastSyncTime() == 0 || isStale(System.currentTimeMillis())) + { + willPassivate(); + save(this); + didActivate(); + } + } + } + catch (Exception e) + { + LOG.warn("Problem saving session({})",getId(), e); + } + finally + { + _dirty = false; } } - catch (Exception e) - { - LOG.warn("Problem saving session({})",getId(), e); - } - } + } + finally + { + _lock.unlock(); + } + } + + /** Test if the session is stale + * @param atTime + * @return + */ + protected boolean isStale (long atTime) + { + return (getStaleIntervalSec() > 0) && (atTime - getLastSyncTime() >= (getStaleIntervalSec()*1000L)); + } + + + /** Test if the session is dirty + * @return + */ + protected boolean isDirty () + { + return _dirty; } /** @@ -483,6 +434,8 @@ protected void timeout() super.timeout(); } + + /** * Reload the session from the cluster. If the node that * last managed the session from the cluster is ourself, @@ -494,8 +447,8 @@ protected void timeout() private void refresh () { //get fresh copy from the cluster - Session fresh = load(getId()); - + Session fresh = load(makeKey(getClusterId(), _context)); + //if the session no longer exists, invalidate if (fresh == null) { @@ -564,6 +517,7 @@ public long getExpiry () public void swapId (String newId, String newNodeId) { + //TODO probably synchronize rather than use the access/complete lock? _lock.lock(); setClusterId(newId); setNodeId(newNodeId); @@ -577,7 +531,7 @@ public void setAttribute (String name, Object value) if (value == null && old == null) return; //if same as remove attribute but attribute was already removed, no change - //TODO _dirty = true; + _dirty = true; } @@ -709,7 +663,7 @@ public void scavenge () candidateIds.add(entry.getKey()); } } - + for (String candidateId:candidateIds) { if (LOG.isDebugEnabled()) @@ -719,7 +673,8 @@ public void scavenge () if (candidateSession != null) { //double check the state of the session in the cache, as the - //session may have migrated to another node + //session may have migrated to another node. This leaves a window + //where the cached session may have been changed by another node Session cachedSession = load(makeKey(candidateId, _context)); if (cachedSession == null) { @@ -755,8 +710,7 @@ public long getScavengeInterval () /** - * Set the interval between runs of the scavenger. As this will be a costly - * exercise (need to iterate over all cache entries) it should not be run too + * Set the interval between runs of the scavenger. It should not be run too * often. * * @@ -803,7 +757,7 @@ public void setScavengeInterval (long sec) * * @return */ - public Cache getCache() + public BasicCache getCache() { return _cache; } @@ -815,7 +769,7 @@ public Cache getCache() * * @param cache */ - public void setCache (Cache cache) + public void setCache (BasicCache cache) { this._cache = cache; } @@ -873,7 +827,6 @@ public AbstractSession getSession(String idInCluster) { Session session = null; - //try and find the session in this node's memory Session memSession = (Session)_sessions.get(idInCluster); @@ -940,7 +893,7 @@ public AbstractSession getSession(String idInCluster) } catch (Exception e) { - LOG.warn("Unable to load session {}", idInCluster, e); + LOG.warn("Unable to load session="+idInCluster, e); return null; } } @@ -955,8 +908,28 @@ public AbstractSession getSession(String idInCluster) @Override protected void shutdownSessions() throws Exception { - //TODO if implementing period saves, if we might have un-saved changes, - //then we need to write them back to the clustered cache + Set keys = new HashSet(_sessions.keySet()); + for (String key:keys) + { + Session session = _sessions.remove(key); //take the session out of the session list + //If the session is dirty, then write it to the cluster. + //If the session is simply stale do NOT write it to the cluster, as some other node + //may have started managing that session - this means that the last accessed/expiry time + //will not be updated, meaning it may look like it can expire sooner than it should. + try + { + if (session.isDirty()) + { + if (LOG.isDebugEnabled()) + LOG.debug("Saving dirty session {} before exiting ", session.getId()); + save(session); + } + } + catch (Exception e) + { + LOG.warn(e); + } + } } @@ -1029,7 +1002,7 @@ protected Session load (String key) throw new IllegalStateException("No cache"); if (LOG.isDebugEnabled()) LOG.debug("Loading session {} from cluster", key); - //SerializableSession storableSession = (SerializableSession)_cache.get(key); + SerializableSessionData storableSession = (SerializableSessionData)_cache.get(key); if (storableSession == null) { @@ -1038,7 +1011,6 @@ protected Session load (String key) } else { - //Session session = storableSession.getSession(); Session session = new Session (storableSession); session.setLastSyncTime(System.currentTimeMillis()); return session; @@ -1062,7 +1034,20 @@ protected void save (InfinispanSessionManager.Session session) if (LOG.isDebugEnabled()) LOG.debug("Writing session {} to cluster", session.getId()); SerializableSessionData storableSession = new SerializableSessionData(session); - _cache.put(makeKey(session, _context), storableSession); + + //Put an idle timeout on the cache entry if the session is not immortal - + //if no requests arrive at any node before this timeout occurs, or no node + //scavenges the session before this timeout occurs, the session will be removed. + //NOTE: that no session listeners can be called for this. + InfinispanSessionIdManager sessionIdManager = (InfinispanSessionIdManager)getSessionIdManager(); + if (storableSession.maxInactive > 0) + _cache.put(makeKey(session, _context), storableSession, -1, TimeUnit.SECONDS, storableSession.maxInactive*sessionIdManager.getIdleExpiryMultiple(), TimeUnit.SECONDS); + else + _cache.put(makeKey(session, _context), storableSession); + + //tickle the session id manager to keep the sessionid entry for this session up-to-date + sessionIdManager.touch(session.getClusterId()); + session.setLastSyncTime(System.currentTimeMillis()); } @@ -1074,7 +1059,7 @@ protected void save (InfinispanSessionManager.Session session) * @param session */ protected void delete (InfinispanSessionManager.Session session) - { + { if (_cache == null) throw new IllegalStateException("No cache"); if (LOG.isDebugEnabled()) LOG.debug("Removing session {} from cluster", session.getId()); diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java similarity index 92% rename from tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java rename to tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java index acff35611b23..90e428cf0f25 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/LightLoadTest.java +++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/ScatterGunLoadTest.java @@ -21,9 +21,9 @@ import org.junit.Test; /** - * LightLoadTest + * ScatterGunLoadTest */ -public class LightLoadTest extends AbstractLightLoadTest +public class ScatterGunLoadTest extends AbstractScatterGunLoadTest { public AbstractTestServer createServer(int port) diff --git a/tests/test-sessions/test-infinispan-sessions/pom.xml b/tests/test-sessions/test-infinispan-sessions/pom.xml index c94a6e18ab5a..d39696dac57f 100644 --- a/tests/test-sessions/test-infinispan-sessions/pom.xml +++ b/tests/test-sessions/test-infinispan-sessions/pom.xml @@ -41,6 +41,9 @@ maven-surefire-plugin false + + org/eclipse/jetty/server/session/*.java + @@ -108,14 +111,20 @@ jetty-test-helper test + + org.infinispan + infinispan-client-hotrod + 7.1.1.Final + test + - - mongodb + remote - mongodb.enabled + hotrod.enabled true @@ -125,12 +134,13 @@ org.apache.maven.plugins maven-surefire-plugin - false + + **/*.java + ---> diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSessionServer.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSessionServer.java index 6cb5db399f82..c6b21229a58c 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSessionServer.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSessionServer.java @@ -24,6 +24,7 @@ import org.eclipse.jetty.session.infinispan.InfinispanSessionIdManager; import org.eclipse.jetty.session.infinispan.InfinispanSessionManager; import org.infinispan.Cache; +import org.infinispan.commons.api.BasicCache; import org.infinispan.commons.util.CloseableIteratorSet; public class InfinispanTestSessionServer extends AbstractTestServer @@ -34,14 +35,14 @@ public class InfinispanTestSessionServer extends AbstractTestServer - public InfinispanTestSessionServer(int port, Cache config) + public InfinispanTestSessionServer(int port, BasicCache config) { this(port, 30, 10, config); } - public InfinispanTestSessionServer(int port, int maxInactivePeriod, int scavengePeriod, Cache config) + public InfinispanTestSessionServer(int port, int maxInactivePeriod, int scavengePeriod, BasicCache config) { super(port, maxInactivePeriod, scavengePeriod, config); } @@ -53,7 +54,7 @@ public SessionIdManager newSessionIdManager(Object config) { InfinispanSessionIdManager idManager = new InfinispanSessionIdManager(getServer()); idManager.setWorkerName("w"+(__workers++)); - idManager.setCache((Cache)config); + idManager.setCache((BasicCache)config); return idManager; } @@ -75,22 +76,40 @@ public SessionHandler newSessionHandler(SessionManager sessionManager) return new SessionHandler(sessionManager); } + public boolean exists (String id) + { + BasicCache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache(); + if (cache != null) + { + return cache.containsKey(id); + } + + return false; + } + + public Object get (String id) + { + BasicCache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache(); + if (cache != null) + { + return cache.get(id); + } + + return null; + } public void dumpCache () { - Cache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache(); + BasicCache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache(); if (cache != null) { - System.err.println(cache.getName()+" contains "+cache.size()+" entries"); - CloseableIteratorSet keys = cache.keySet(); - for (String key:keys) - System.err.println(key + " "+cache.get(key)); + System.err.println(cache.getName()+" contains "+cache.size()+" entries"); } } public void clearCache () { - Cache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache(); + BasicCache cache = ((InfinispanSessionIdManager)_sessionIdManager).getCache(); if (cache != null) cache.clear(); } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java index 44123a590d1d..10afc28defca 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InvalidationSessionTest.java @@ -19,17 +19,6 @@ package org.eclipse.jetty.server.session; -import java.io.File; - -import org.eclipse.jetty.server.SessionManager; -import org.eclipse.jetty.session.infinispan.InfinispanSessionIdManager; -import org.eclipse.jetty.session.infinispan.InfinispanSessionManager; -import org.eclipse.jetty.util.IO; -import org.infinispan.Cache; -import org.infinispan.configuration.cache.Configuration; -import org.infinispan.configuration.cache.ConfigurationBuilder; -import org.infinispan.manager.DefaultCacheManager; -import org.infinispan.manager.EmbeddedCacheManager; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -66,20 +55,6 @@ public static void teardown () throws Exception public AbstractTestServer createServer(int port) { return new InfinispanTestSessionServer(port, __testSupport.getCache()); - -// return new InfinispanTestSessionServer(port, __cache) -// { -// -// @Override -// public SessionManager newSessionManager() -// { -// InfinispanSessionManager sessionManager = new InfinispanSessionManager(); -// sessionManager.setSessionIdManager((InfinispanSessionIdManager)_sessionIdManager); -// sessionManager.setStaleIntervalSec(__staleSec); -// sessionManager.setCache(((InfinispanSessionIdManager)_sessionIdManager).getCache()); -// return sessionManager; -// } -// }; } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java new file mode 100644 index 000000000000..44a9c1785c05 --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java @@ -0,0 +1,66 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server.session; + +import org.junit.AfterClass; +import org.junit.BeforeClass; + +/** + * SameNodeLoadTest + * + * + */ +public class SameNodeLoadTest extends AbstractSameNodeLoadTest +{ + + public static InfinispanTestSupport __testSupport; + + + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new InfinispanTestSupport(); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + /** + * @see org.eclipse.jetty.server.session.AbstractSameNodeLoadTest#createServer(int) + */ + @Override + public AbstractTestServer createServer(int port) + { + InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, __testSupport.getCache()); + return server; + } + + @Override + public void testLoad() throws Exception + { + super.testLoad(); + } + +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClientCrossContextSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClientCrossContextSessionTest.java new file mode 100644 index 000000000000..c7fe124e9cee --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClientCrossContextSessionTest.java @@ -0,0 +1,69 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server.session.remote; + + +import org.eclipse.jetty.server.session.AbstractClientCrossContextSessionTest; +import org.eclipse.jetty.server.session.AbstractTestServer; +import org.eclipse.jetty.server.session.InfinispanTestSessionServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +/** + * RemoteClientCrossContextSessionTest + * + * + */ +public class RemoteClientCrossContextSessionTest extends AbstractClientCrossContextSessionTest +{ + public static RemoteInfinispanTestSupport __testSupport; + + + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + + @Override + public AbstractTestServer createServer(int port) + { + InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, __testSupport.getCache()); + return server; + } + + @Test + public void testCrossContextDispatch() throws Exception + { + super.testCrossContextDispatch(); + } + +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmortalSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmortalSessionTest.java new file mode 100644 index 000000000000..3654fe02a82a --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteImmortalSessionTest.java @@ -0,0 +1,74 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server.session.remote; + +import org.eclipse.jetty.server.session.AbstractImmortalSessionTest; +import org.eclipse.jetty.server.session.AbstractTestServer; +import org.eclipse.jetty.server.session.InfinispanTestSessionServer; +import org.infinispan.Cache; +import org.infinispan.configuration.cache.ConfigurationBuilder; +import org.infinispan.manager.DefaultCacheManager; +import org.infinispan.manager.EmbeddedCacheManager; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +/** + * ImmortalSessionTest + * + * + */ +public class RemoteImmortalSessionTest extends AbstractImmortalSessionTest +{ + + + public static RemoteInfinispanTestSupport __testSupport; + + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + + /** + * @see org.eclipse.jetty.server.session.AbstractImmortalSessionTest#createServer(int, int, int) + */ + @Override + public AbstractTestServer createServer(int port, int maxInactiveMs, int scavengeMs) + { + return new InfinispanTestSessionServer(port, maxInactiveMs, scavengeMs, __testSupport.getCache()); + } + + @Override + public void testImmortalSession() throws Exception + { + super.testImmortalSession(); + } + + +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInfinispanTestSupport.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInfinispanTestSupport.java new file mode 100644 index 000000000000..a936e20a4afe --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInfinispanTestSupport.java @@ -0,0 +1,88 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server.session.remote; + +import java.io.File; + +import org.eclipse.jetty.util.IO; +import org.infinispan.Cache; +import org.infinispan.client.hotrod.RemoteCache; +import org.infinispan.client.hotrod.RemoteCacheManager; +import org.infinispan.configuration.cache.Configuration; +import org.infinispan.configuration.cache.ConfigurationBuilder; +import org.infinispan.configuration.global.GlobalConfigurationBuilder; +import org.infinispan.manager.DefaultCacheManager; +import org.infinispan.manager.EmbeddedCacheManager; + +/** + * RemoteInfinispanTestSupport + * + * + */ +public class RemoteInfinispanTestSupport +{ + public static final String DEFAULT_CACHE_NAME = "session_test_cache"; + public RemoteCache _cache; + private String _name; + public static RemoteCacheManager _manager; + + static + { + try + { + _manager = new RemoteCacheManager(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + public RemoteInfinispanTestSupport () + { + this (null); + } + + public RemoteInfinispanTestSupport(String cacheName) + { + if (cacheName == null) + cacheName = DEFAULT_CACHE_NAME+System.currentTimeMillis(); + + _name = cacheName; + } + + + + public RemoteCache getCache () + { + return _cache; + } + + public void setup () throws Exception + { + _cache = _manager.getCache(_name); + } + + + public void teardown () throws Exception + { + + } +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInvalidationSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInvalidationSessionTest.java new file mode 100644 index 000000000000..95841c6d5e60 --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInvalidationSessionTest.java @@ -0,0 +1,93 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server.session.remote; + +import org.eclipse.jetty.server.session.AbstractInvalidationSessionTest; +import org.eclipse.jetty.server.session.AbstractTestServer; +import org.eclipse.jetty.server.session.InfinispanTestSessionServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +/** + * InvalidationSessionTest + * + * + */ +public class RemoteInvalidationSessionTest extends AbstractInvalidationSessionTest +{ + + public static RemoteInfinispanTestSupport __testSupport; + public static long __staleSec = 3L; + + + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + /** + * @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#createServer(int) + */ + @Override + public AbstractTestServer createServer(int port) + { + return new InfinispanTestSessionServer(port, __testSupport.getCache()); + } + + + + + @Override + public void testInvalidation() throws Exception + { + super.testInvalidation(); + } + + /** + * @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#pause() + */ + @Override + public void pause() + { + //This test moves a session from node 1 to node 2, then invalidates the session back on node1. This + //should never happen with a decent load balancer. + //The infinispan session manager on node 2 will hold the session in local memory for a specific (configurable) + //amount of time. We've set the stale session time to 3 sec, so we need to pause for at least this long before making + //another request to node2 so + //that the node will re-load the session from the database and discover that it has gone. + try + { + Thread.sleep(2 * __staleSec * 1000); + } + catch (InterruptedException e) + { + } + } + +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLastAccessTimeTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLastAccessTimeTest.java new file mode 100644 index 000000000000..e4e82fa99a75 --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLastAccessTimeTest.java @@ -0,0 +1,67 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server.session.remote; + +import java.io.File; + +import org.eclipse.jetty.server.session.AbstractLastAccessTimeTest; +import org.eclipse.jetty.server.session.AbstractTestServer; +import org.eclipse.jetty.server.session.InfinispanTestSessionServer; +import org.eclipse.jetty.util.IO; +import org.infinispan.Cache; +import org.infinispan.configuration.cache.Configuration; +import org.infinispan.configuration.cache.ConfigurationBuilder; +import org.infinispan.manager.DefaultCacheManager; +import org.infinispan.manager.EmbeddedCacheManager; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +public class RemoteLastAccessTimeTest extends AbstractLastAccessTimeTest +{ + public static RemoteInfinispanTestSupport __testSupport; + + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + + @Override + public AbstractTestServer createServer(int port, int max, int scavenge) + { + return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache()); + } + + @Override + public void testLastAccessTime() throws Exception + { + super.testLastAccessTime(); + } + + +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLocalSessionScavengingTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLocalSessionScavengingTest.java new file mode 100644 index 000000000000..1881ab7bb727 --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteLocalSessionScavengingTest.java @@ -0,0 +1,61 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server.session.remote; + +import org.eclipse.jetty.server.session.AbstractLocalSessionScavengingTest; +import org.eclipse.jetty.server.session.AbstractTestServer; +import org.eclipse.jetty.server.session.InfinispanTestSessionServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +/** + * LocalSessionScavengingTest + * + * + */ +public class RemoteLocalSessionScavengingTest extends AbstractLocalSessionScavengingTest +{ + + public static RemoteInfinispanTestSupport __testSupport; + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + + /** + * @see org.eclipse.jetty.server.session.AbstractLocalSessionScavengingTest#createServer(int, int, int) + */ + @Override + public AbstractTestServer createServer(int port, int max, int scavenge) + { + return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache()); + } + +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteNewSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteNewSessionTest.java new file mode 100644 index 000000000000..d46d64b8957f --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteNewSessionTest.java @@ -0,0 +1,69 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server.session.remote; + +import org.eclipse.jetty.server.session.AbstractNewSessionTest; +import org.eclipse.jetty.server.session.AbstractTestServer; +import org.eclipse.jetty.server.session.InfinispanTestSessionServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +/** + * NewSessionTest + * + * + */ +public class RemoteNewSessionTest extends AbstractNewSessionTest +{ + + public static RemoteInfinispanTestSupport __testSupport; + + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + /** + * @see org.eclipse.jetty.server.session.AbstractNewSessionTest#createServer(int, int, int) + */ + @Override + public AbstractTestServer createServer(int port, int max, int scavenge) + { + return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache()); + } + + + @Override + public void testNewSession() throws Exception + { + super.testNewSession(); + } + + +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteReentrantRequestSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteReentrantRequestSessionTest.java new file mode 100644 index 000000000000..fedb5b9e3d86 --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteReentrantRequestSessionTest.java @@ -0,0 +1,67 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server.session.remote; + +import org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest; +import org.eclipse.jetty.server.session.AbstractTestServer; +import org.eclipse.jetty.server.session.InfinispanTestSessionServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +/** + * ReentrantRequestSessionTest + * + * + */ +public class RemoteReentrantRequestSessionTest extends AbstractReentrantRequestSessionTest +{ + public static RemoteInfinispanTestSupport __testSupport; + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + + /** + * @see org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest#createServer(int) + */ + @Override + public AbstractTestServer createServer(int port) + { + return new InfinispanTestSessionServer(port, __testSupport.getCache()); + } + + @Override + public void testReentrantRequestSession() throws Exception + { + super.testReentrantRequestSession(); + } + + +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteRemoveSessionTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteRemoveSessionTest.java new file mode 100644 index 000000000000..26ce9ce3d7e6 --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteRemoveSessionTest.java @@ -0,0 +1,61 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server.session.remote; + +import org.eclipse.jetty.server.session.AbstractRemoveSessionTest; +import org.eclipse.jetty.server.session.AbstractTestServer; +import org.eclipse.jetty.server.session.InfinispanTestSessionServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class RemoteRemoveSessionTest extends AbstractRemoveSessionTest +{ + + public static RemoteInfinispanTestSupport __testSupport; + + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + + @Override + public AbstractTestServer createServer(int port, int max, int scavenge) + { + InfinispanTestSessionServer s = new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache()); + return s; + } + + @Test + public void testRemoveSession() throws Exception + { + super.testRemoveSession(); + } + +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSameNodeLoadTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSameNodeLoadTest.java new file mode 100644 index 000000000000..ea98f0f8b6ed --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSameNodeLoadTest.java @@ -0,0 +1,69 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server.session.remote; + +import org.eclipse.jetty.server.session.AbstractSameNodeLoadTest; +import org.eclipse.jetty.server.session.AbstractTestServer; +import org.eclipse.jetty.server.session.InfinispanTestSessionServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +/** + * SameNodeLoadTest + * + * + */ +public class RemoteSameNodeLoadTest extends AbstractSameNodeLoadTest +{ + + public static RemoteInfinispanTestSupport __testSupport; + + + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + /** + * @see org.eclipse.jetty.server.session.AbstractSameNodeLoadTest#createServer(int) + */ + @Override + public AbstractTestServer createServer(int port) + { + InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, __testSupport.getCache()); + return server; + } + + @Override + public void testLoad() throws Exception + { + super.testLoad(); + } + +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionExpiryTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionExpiryTest.java new file mode 100644 index 000000000000..b328a902dd10 --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionExpiryTest.java @@ -0,0 +1,73 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server.session.remote; + +import org.eclipse.jetty.server.session.AbstractSessionExpiryTest; +import org.eclipse.jetty.server.session.AbstractTestServer; +import org.eclipse.jetty.server.session.InfinispanTestSessionServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class RemoteSessionExpiryTest extends AbstractSessionExpiryTest +{ + + public static RemoteInfinispanTestSupport __testSupport; + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + @Override + public AbstractTestServer createServer(int port, int max, int scavenge) + { + InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache()); + return server; + } + + @Test + @Override + public void testSessionNotExpired() throws Exception + { + super.testSessionNotExpired(); + } + + @Test + @Override + public void testSessionExpiry() throws Exception + { + super.testSessionExpiry(); + } + + @Override + public void verifySessionDestroyed (TestHttpSessionListener listener, String sessionId) + { + //noop - sessions that expired when the InfinispanSessionManager was not running are not reloaded and do not have their listeners called on them. + } +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionInvalidateAndCreateTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionInvalidateAndCreateTest.java new file mode 100644 index 000000000000..581354edf8b0 --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionInvalidateAndCreateTest.java @@ -0,0 +1,69 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server.session.remote; + +import org.eclipse.jetty.server.session.AbstractSessionInvalidateAndCreateTest; +import org.eclipse.jetty.server.session.AbstractTestServer; +import org.eclipse.jetty.server.session.InfinispanTestSessionServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +/** + * SessionInvalidateAndCreateTest + * + * + */ +public class RemoteSessionInvalidateAndCreateTest extends AbstractSessionInvalidateAndCreateTest +{ + public static RemoteInfinispanTestSupport __testSupport; + + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + + /** + * @see org.eclipse.jetty.server.session.AbstractSessionInvalidateAndCreateTest#createServer(int, int, int) + */ + @Override + public AbstractTestServer createServer(int port, int max, int scavenge) + { + return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache()); + } + + @Override + public void testSessionScavenge() throws Exception + { + super.testSessionScavenge(); + } + + + +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionMigrationTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionMigrationTest.java new file mode 100644 index 000000000000..ded67c582f23 --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionMigrationTest.java @@ -0,0 +1,68 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server.session.remote; + +import org.eclipse.jetty.server.session.AbstractSessionMigrationTest; +import org.eclipse.jetty.server.session.AbstractTestServer; +import org.eclipse.jetty.server.session.InfinispanTestSessionServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +/** + * RemoteSessionMigrationTest + * + * + */ +public class RemoteSessionMigrationTest extends AbstractSessionMigrationTest +{ + + public static RemoteInfinispanTestSupport __testSupport; + + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + /** + * @see org.eclipse.jetty.server.session.AbstractSessionMigrationTest#createServer(int) + */ + @Override + public AbstractTestServer createServer(int port) + { + return new InfinispanTestSessionServer(port, __testSupport.getCache()); + } + + @Override + public void testSessionMigration() throws Exception + { + super.testSessionMigration(); + } + + +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionRenewTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionRenewTest.java new file mode 100644 index 000000000000..f39fcb2ed575 --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionRenewTest.java @@ -0,0 +1,70 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + + +package org.eclipse.jetty.server.session.remote; + +import org.eclipse.jetty.server.session.AbstractSessionRenewTest; +import org.eclipse.jetty.server.session.AbstractTestServer; +import org.eclipse.jetty.server.session.InfinispanTestSessionServer; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * SessionRenewTest + * + * + */ +public class RemoteSessionRenewTest extends AbstractSessionRenewTest +{ + + public static RemoteInfinispanTestSupport __testSupport; + + + @BeforeClass + public static void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @AfterClass + public static void teardown () throws Exception + { + __testSupport.teardown(); + } + + + /** + * @see org.eclipse.jetty.server.session.AbstractSessionRenewTest#createServer(int, int, int) + */ + @Override + public AbstractTestServer createServer(int port, int max, int scavenge) + { + return new InfinispanTestSessionServer(port, max, scavenge, __testSupport.getCache()); + } + + @Test + public void testSessionRenewal() throws Exception + { + super.testSessionRenewal(); + } + + +} diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LightLoadTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ScatterGunLoadTest.java similarity index 87% rename from tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LightLoadTest.java rename to tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ScatterGunLoadTest.java index 8828c8dc62ea..0e5af91da260 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/LightLoadTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ScatterGunLoadTest.java @@ -18,14 +18,14 @@ package org.eclipse.jetty.nosql.mongodb; -import org.eclipse.jetty.server.session.AbstractLightLoadTest; +import org.eclipse.jetty.server.session.AbstractScatterGunLoadTest; import org.eclipse.jetty.server.session.AbstractTestServer; import org.junit.Test; /** - * LightLoadTest + * ScatterGunLoadTest */ -public class LightLoadTest extends AbstractLightLoadTest +public class ScatterGunLoadTest extends AbstractScatterGunLoadTest { public AbstractTestServer createServer(int port) diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSameNodeLoadTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSameNodeLoadTest.java new file mode 100644 index 000000000000..999858fb5b8c --- /dev/null +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSameNodeLoadTest.java @@ -0,0 +1,231 @@ +// +// ======================================================================== +// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server.session; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNotNull; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Random; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; +import org.junit.Test; + + +/** + * AbstractSameNodeLoadTest + * + * This test performs multiple concurrent requests for the same session on the same node. + * + */ +public abstract class AbstractSameNodeLoadTest +{ + protected boolean _stress = Boolean.getBoolean( "STRESS" ); + + public abstract AbstractTestServer createServer(int port); + + @Test + public void testLoad() throws Exception + { + if ( _stress ) + { + String contextPath = ""; + String servletMapping = "/server"; + AbstractTestServer server1 = createServer( 0 ); + server1.addContext( contextPath ).addServlet( TestServlet.class, servletMapping ); + + try + { + server1.start(); + int port1 = server1.getPort(); + + HttpClient client = new HttpClient(); + client.start(); + try + { + String url = "http://localhost:" + port1 + contextPath + servletMapping; + + + //create session via first server + ContentResponse response1 = client.GET(url + "?action=init"); + assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); + String sessionCookie = response1.getHeaders().getStringField( "Set-Cookie" ); + assertTrue(sessionCookie != null); + // Mangle the cookie, replacing Path with $Path, etc. + sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); + + //simulate 10 clients making 100 requests each + ExecutorService executor = Executors.newCachedThreadPool(); + int clientsCount = 10; + CyclicBarrier barrier = new CyclicBarrier( clientsCount + 1 ); + int requestsCount = 100; + Worker[] workers = new Worker[clientsCount]; + for ( int i = 0; i < clientsCount; ++i ) + { + workers[i] = new Worker(barrier, client, requestsCount, sessionCookie, url); + executor.execute( workers[i] ); + } + // Wait for all workers to be ready + barrier.await(); + long start = System.nanoTime(); + + // Wait for all workers to be done + barrier.await(); + long end = System.nanoTime(); + long elapsed = TimeUnit.NANOSECONDS.toMillis( end - start ); + System.out.println( "elapsed ms: " + elapsed ); + + executor.shutdownNow(); + + // Perform one request to get the result + Request request = client.newRequest( url + "?action=result" ); + request.header("Cookie", sessionCookie); + ContentResponse response2 = request.send(); + assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); + String response = response2.getContentAsString(); + System.out.println( "get = " + response ); + assertEquals(response.trim(), String.valueOf( clientsCount * requestsCount ) ); + } + finally + { + client.stop(); + } + } + finally + { + server1.stop(); + } + } + } + + public static class Worker implements Runnable + { + public static int COUNT = 0; + + private final HttpClient client; + + private final CyclicBarrier barrier; + + private final int requestsCount; + + private final String sessionCookie; + + private final String url; + + private final String name; + + + public Worker(CyclicBarrier barrier, HttpClient client, int requestsCount, String sessionCookie, String url) + { + this.client = client; + this.barrier = barrier; + this.requestsCount = requestsCount; + this.sessionCookie = sessionCookie; + this.url = url; + this.name = ""+(COUNT++); + } + + + public void run() + { + try + { + // Wait for all workers to be ready + barrier.await(); + + Random random = new Random( System.nanoTime() ); + + for ( int i = 0; i < requestsCount; ++i ) + { + int pauseMsec = random.nextInt(1000); + + //wait a random number of milliseconds between requests up to 1 second + if (pauseMsec > 0) + { + Thread.currentThread().sleep(pauseMsec); + } + Request request = client.newRequest(url + "?action=increment"); + request.header("Cookie", sessionCookie); + ContentResponse response = request.send(); + assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + } + + // Wait for all workers to be done + barrier.await(); + } + catch ( Exception x ) + { + throw new RuntimeException( x ); + } + } + } + + public static class TestServlet + extends HttpServlet + { + @Override + protected void doGet( HttpServletRequest request, HttpServletResponse response ) + throws ServletException, IOException + { + String action = request.getParameter( "action" ); + if ( "init".equals( action ) ) + { + HttpSession session = request.getSession( true ); + session.setAttribute( "value", 0 ); + } + else if ( "increment".equals( action ) ) + { + HttpSession session = request.getSession( false ); + assertNotNull(session); + synchronized(session) + { + int value = (Integer) session.getAttribute( "value" ); + session.setAttribute( "value", value + 1 ); + } + } + else if ( "result".equals( action ) ) + { + HttpSession session = request.getSession( false ); + assertNotNull(session); + Integer value = null; + synchronized (session) + { + value = (Integer) session.getAttribute( "value" ); + } + PrintWriter writer = response.getWriter(); + writer.println( value ); + writer.flush(); + } + } + } +} diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractScatterGunLoadTest.java similarity index 94% rename from tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java rename to tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractScatterGunLoadTest.java index d06ddf4c8f26..7839e118077b 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractLightLoadTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractScatterGunLoadTest.java @@ -42,9 +42,15 @@ /** - * AbstractLightLoadTest + * AbstractScatterGunLoadTest + * + * This is an unrealistic test. It takes a scatter-gun approach to smearing a + * single session across 2 different nodes at once. + * + * In the real world, we must have a load balancer that uses sticky sessions + * to keep the session pinned to a particular node. */ -public abstract class AbstractLightLoadTest +public abstract class AbstractScatterGunLoadTest { protected boolean _stress = Boolean.getBoolean( "STRESS" ); @@ -80,6 +86,7 @@ public void testLightLoad() urls[0] = "http://localhost:" + port1 + contextPath + servletMapping; urls[1] = "http://localhost:" + port2 + contextPath + servletMapping; + //create session via first server ContentResponse response1 = client.GET(urls[0] + "?action=init"); assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); String sessionCookie = response1.getHeaders().get( "Set-Cookie" ); @@ -87,6 +94,7 @@ public void testLightLoad() // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); + //simulate 50 clients making 100 requests each ExecutorService executor = Executors.newCachedThreadPool(); int clientsCount = 50; CyclicBarrier barrier = new CyclicBarrier( clientsCount + 1 ); @@ -216,7 +224,7 @@ protected void doGet( HttpServletRequest request, HttpServletResponse response ) } else if ( "increment".equals( action ) ) { - // Without synchronization, because it is taken care by Jetty/Terracotta + // Without synchronization HttpSession session = request.getSession( false ); int value = (Integer) session.getAttribute( "value" ); session.setAttribute( "value", value + 1 ); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractStopSessionManagerPreserveSessionTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractStopSessionManagerPreserveSessionTest.java index 2aa4c8bd0e8c..a7f5c878bbdc 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractStopSessionManagerPreserveSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractStopSessionManagerPreserveSessionTest.java @@ -35,6 +35,11 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.junit.Test; +/** + * AbstractStopSessionManagerPreserveSessionTest + * + * + */ public abstract class AbstractStopSessionManagerPreserveSessionTest { public String _id;