diff --git a/jetty-gcloud/jetty-gcloud-memcached-session-manager/pom.xml b/jetty-gcloud/jetty-gcloud-memcached-session-manager/pom.xml
new file mode 100644
index 00000000000..767ea0163ad
--- /dev/null
+++ b/jetty-gcloud/jetty-gcloud-memcached-session-manager/pom.xml
@@ -0,0 +1,57 @@
+
+
+
+ org.eclipse.jetty.gcloud
+ gcloud-parent
+ 9.3.10-SNAPSHOT
+
+
+ 4.0.0
+ jetty-gcloud-memcached-session-manager
+ Jetty :: GCloud :: Memcached Session Manager
+
+
+
+ org.eclipse.jetty.gcloud
+ jetty-gcloud-session-manager
+ ${project.version}
+
+
+ com.googlecode.xmemcached
+ xmemcached
+ 2.0.0
+
+
+ org.eclipse.jetty.toolchain
+ jetty-test-helper
+ test
+
+
+
+
+ ${project.groupId}.memcached.session
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ true
+
+
+
+ manifest
+
+
+
+ org.eclipse.jetty.gcloud.memcached.session.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}";
+
+
+
+
+
+
+
+
+
diff --git a/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/config/modules/gcloud-memcached-sessions.mod b/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/config/modules/gcloud-memcached-sessions.mod
new file mode 100644
index 00000000000..ee6329d92a0
--- /dev/null
+++ b/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/config/modules/gcloud-memcached-sessions.mod
@@ -0,0 +1,20 @@
+#
+# Jetty GCloudDatastore with Memcached Session Manager module
+#
+
+[depend]
+gcloud-sessions
+
+
+[files]
+maven://com.googlecode.xmemcached/xmemcached/2.0.0|lib/xmemcached/xmemcached-2.0.0.jar
+
+[lib]
+lib/jetty-gcloud-memcached-session-manager-${jetty.version}.jar
+lib/xmemcached/*.jar
+
+[license]
+Xmemcached is an open source project hosted on Github and released under the Apache 2.0 license.
+https://github.com/killme2008/xmemcached
+http://www.apache.org/licenses/LICENSE-2.0.html
+
diff --git a/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/java/org/eclipse/jetty/gcloud/memcached/session/GCloudMemcachedSessionManager.java b/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/java/org/eclipse/jetty/gcloud/memcached/session/GCloudMemcachedSessionManager.java
new file mode 100644
index 00000000000..207e0bca912
--- /dev/null
+++ b/jetty-gcloud/jetty-gcloud-memcached-session-manager/src/main/java/org/eclipse/jetty/gcloud/memcached/session/GCloudMemcachedSessionManager.java
@@ -0,0 +1,350 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.Map;
+
+import org.eclipse.jetty.gcloud.session.GCloudSessionManager;
+import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+import com.google.gcloud.datastore.Key;
+
+import net.rubyeye.xmemcached.MemcachedClient;
+import net.rubyeye.xmemcached.XMemcachedClientBuilder;
+import net.rubyeye.xmemcached.transcoders.SerializingTranscoder;
+
+/**
+ * GCloudMemcachedSessionManager
+ *
+ * Use memcached in front of GCloudDataStore
+ *
+ */
+public class GCloudMemcachedSessionManager extends GCloudSessionManager
+{
+ private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
+
+ protected String _host;
+ protected String _port;
+ protected MemcachedClient _client;
+ protected int _expirySec = 0;
+
+
+
+ /**
+ * ContextClassloaderSerializingTranscoder
+ *
+ * A xmemcached transcoder that will use the thread context classloader to
+ * resolve classes during object deserialization: necessary for Servlet Spec
+ * classloading order of context classloader first.
+ *
+ */
+ public class ContextClassloaderSerializingTranscoder extends SerializingTranscoder
+ {
+
+ @Override
+ protected Object deserialize(byte[] in)
+ {
+
+ if (in == null)
+ return null;
+
+ Object rv = null;
+ try (ByteArrayInputStream bis = new ByteArrayInputStream(in);ObjectInputStream is = new ClassLoadingObjectInputStream(bis);)
+ {
+
+ rv = is.readObject();
+ }
+ catch (IOException e)
+ {
+ LOG.warn("Caught IOException decoding " + in.length + " bytes of data", e);
+ }
+ catch (ClassNotFoundException e)
+ {
+ LOG.warn("Caught CNFE decoding " + in.length + " bytes of data", e);
+ }
+
+ return rv;
+
+ }
+ }
+
+
+
+ /**
+ * MemcacheSession
+ *
+ * Needed to make a constructor public.
+ */
+ public class MemcacheSession extends GCloudSessionManager.Session
+ {
+
+ public MemcacheSession(String sessionId, long created, long accessed, long maxInterval)
+ {
+ super(sessionId, created, accessed, maxInterval);
+ }
+ }
+
+ /**
+ * Every time a Session is put into the cache one of these objects
+ * is created to copy the data out of the in-memory session, and
+ * every time an object is read from the cache one of these objects
+ * a fresh Session object is created based on the data held by this
+ * object.
+ */
+ public class SerializableSessionData implements Serializable
+ {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -7779120106058533486L;
+ String clusterId;
+ String contextPath;
+ String vhost;
+ long accessed;
+ long lastAccessed;
+ long createTime;
+ long cookieSetTime;
+ String lastNode;
+ long expiry;
+ long maxInactive;
+ Map attributes;
+
+
+
+ public SerializableSessionData()
+ {}
+
+
+ public SerializableSessionData(Session s)
+ {
+ clusterId = s.getClusterId();
+ contextPath = s.getContextPath();
+ vhost = s.getVHost();
+ accessed = s.getAccessed();
+ lastAccessed = s.getLastAccessedTime();
+ createTime = s.getCreationTime();
+ cookieSetTime = s.getCookieSetTime();
+ lastNode = s.getLastNode();
+ expiry = s.getExpiry();
+ maxInactive = s.getMaxInactiveInterval();
+ attributes = s.getAttributeMap();
+ }
+
+
+ private void writeObject(java.io.ObjectOutputStream out) throws IOException
+ {
+ out.writeUTF(clusterId); //session id
+ out.writeUTF(contextPath); //context path
+ out.writeUTF(vhost); //first vhost
+
+ out.writeLong(accessed);//accessTime
+ out.writeLong(lastAccessed); //lastAccessTime
+ out.writeLong(createTime); //time created
+ out.writeLong(cookieSetTime);//time cookie was set
+ out.writeUTF(lastNode); //name of last node managing
+
+ out.writeLong(expiry);
+ out.writeLong(maxInactive);
+ out.writeObject(attributes);
+ }
+
+ private void readObject(java.io.ObjectInputStream ois) throws IOException, ClassNotFoundException
+ {
+ clusterId = ois.readUTF();
+ contextPath = ois.readUTF();
+ vhost = ois.readUTF();
+ accessed = ois.readLong();//accessTime
+ lastAccessed = ois.readLong(); //lastAccessTime
+ createTime = ois.readLong(); //time created
+ cookieSetTime = ois.readLong();//time cookie was set
+ lastNode = ois.readUTF(); //last managing node
+ expiry = ois.readLong();
+ maxInactive = ois.readLong();
+ Object o = ois.readObject();
+ attributes = ((Map)o);
+ }
+ }
+
+
+
+
+
+
+ /**
+ * @return the expiry setting for memcached
+ */
+ public int getExpirySec()
+ {
+ return _expirySec;
+ }
+
+ /**
+ * @param expirySec the time in seconds for an item to remain in memcached
+ */
+ public void setExpirySec(int expirySec)
+ {
+ _expirySec = expirySec;
+ }
+
+
+ @Override
+ public void doStart() throws Exception
+ {
+ if (StringUtil.isBlank(_host) || StringUtil.isBlank(_port))
+ throw new IllegalStateException("Memcached host and/or port not configured");
+
+ XMemcachedClientBuilder builder = new XMemcachedClientBuilder(_host+":"+_port);
+ _client = builder.build();
+ _client.setTranscoder(new ContextClassloaderSerializingTranscoder());
+ super.doStart();
+ }
+
+ @Override
+ public void doStop() throws Exception
+ {
+ _client.shutdown();
+ super.doStop();
+ }
+
+ @Override
+ protected Session load(Key key) throws Exception
+ {
+ //first try the memcache cache
+ if (LOG.isDebugEnabled()) LOG.debug("Loading key {} from memcached ", key.name());
+ Session session = loadFromMemcached(key.name());
+ if (session != null)
+ return session;
+
+ //then try gcloudatastore
+ return super.load(key);
+ }
+
+ /**
+ * @param key the key for the memcache item
+ * @return the Session inflated from memcache
+ * @throws Exception
+ */
+ protected Session loadFromMemcached(String key) throws Exception
+ {
+ SerializableSessionData sd = _client.get(key);
+
+ if (sd == null)
+ return null;
+
+ Session session = new MemcacheSession (sd.clusterId, sd.createTime, sd.accessed, sd.maxInactive);
+ session.setLastNode(sd.lastNode);
+ session.setContextPath(sd.contextPath);
+ session.setVHost(sd.vhost);
+ session.setCookieSetTime(sd.cookieSetTime);
+ session.setLastAccessedTime(sd.lastAccessed);
+ session.setLastNode(sd.lastNode);
+ session.setExpiry(sd.expiry);
+ session.addAttributes(sd.attributes);
+ return session;
+ }
+
+
+ @Override
+ protected void save(Session session) throws Exception
+ {
+ //save to gcloud and then memcache
+ super.save(session);
+ saveToMemcached(session);
+ }
+
+
+
+ @Override
+ protected void delete (GCloudSessionManager.Session session)
+ {
+ Exception memcacheException = null;
+ try
+ {
+ deleteFromMemcached(session);
+ }
+ catch (Exception e)
+ {
+ memcacheException = e;
+ }
+
+ super.delete(session);
+ if (memcacheException != null)
+ throw new RuntimeException(memcacheException);
+ }
+
+
+ protected void deleteFromMemcached(Session session) throws Exception
+ {
+ Key gcloudKey = makeKey(session, _context);
+ _client.delete(gcloudKey.name());
+ }
+
+ /**
+ * Store the session into memcached
+ * @param session the Session to be serialized
+ * @throws Exception
+ */
+ protected void saveToMemcached(Session session) throws Exception
+ {
+ Key gcloudKey = makeKey(session, _context);
+ _client.set(gcloudKey.name(), getExpirySec(), new SerializableSessionData(session));
+ }
+
+ /**
+ * @return the host address of the memcached server
+ */
+ public String getHost()
+ {
+ return _host;
+ }
+
+ /**
+ * @param host the host address of the memcached server
+ */
+ public void setHost(String host)
+ {
+ _host = host;
+ }
+
+ /**
+ * @return the port of the memcached server
+ */
+ public String getPort()
+ {
+ return _port;
+ }
+
+ /**
+ * @param port the port of the memcached server
+ */
+ public void setPort(String port)
+ {
+ _port = port;
+ }
+
+
+}
diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionManager.java b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionManager.java
index 640aec58645..8d8f91625d8 100644
--- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionManager.java
+++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionManager.java
@@ -19,7 +19,10 @@
package org.eclipse.jetty.gcloud.session;
import java.io.ByteArrayOutputStream;
+import java.io.Externalizable;
import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
@@ -239,86 +242,7 @@ public class GCloudSessionManager extends AbstractSessionManager
}
}
- /*
- * Every time a Session is put into the cache one of these objects
- * is created to copy the data out of the in-memory session, and
- * every time an object is read from the cache one of these objects
- * a fresh Session object is created based on the data held by this
- * object.
- */
- public class SerializableSessionData implements Serializable
- {
- /**
- *
- */
- private static final long serialVersionUID = -7779120106058533486L;
- String clusterId;
- String contextPath;
- String vhost;
- long accessed;
- long lastAccessed;
- long createTime;
- long cookieSetTime;
- String lastNode;
- long expiry;
- long maxInactive;
- Map attributes;
-
- public SerializableSessionData()
- {
-
- }
-
-
- public SerializableSessionData(Session s)
- {
- clusterId = s.getClusterId();
- contextPath = s.getContextPath();
- vhost = s.getVHost();
- accessed = s.getAccessed();
- lastAccessed = s.getLastAccessedTime();
- createTime = s.getCreationTime();
- cookieSetTime = s.getCookieSetTime();
- lastNode = s.getLastNode();
- expiry = s.getExpiry();
- maxInactive = s.getMaxInactiveInterval();
- attributes = s.getAttributeMap(); // TODO pointer, not a copy
- }
-
- private void writeObject(java.io.ObjectOutputStream out) throws IOException
- {
- out.writeUTF(clusterId); //session id
- out.writeUTF(contextPath); //context path
- out.writeUTF(vhost); //first vhost
-
- out.writeLong(accessed);//accessTime
- out.writeLong(lastAccessed); //lastAccessTime
- out.writeLong(createTime); //time created
- out.writeLong(cookieSetTime);//time cookie was set
- out.writeUTF(lastNode); //name of last node managing
-
- out.writeLong(expiry);
- out.writeLong(maxInactive);
- out.writeObject(attributes);
- }
-
- private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
- {
- clusterId = in.readUTF();
- contextPath = in.readUTF();
- vhost = in.readUTF();
-
- accessed = in.readLong();//accessTime
- lastAccessed = in.readLong(); //lastAccessTime
- createTime = in.readLong(); //time created
- cookieSetTime = in.readLong();//time cookie was set
- lastNode = in.readUTF(); //last managing node
- expiry = in.readLong();
- maxInactive = in.readLong();
- attributes = (HashMap)in.readObject();
- }
-
- }
+
@@ -1139,7 +1063,7 @@ public class GCloudSessionManager extends AbstractSessionManager
if (_datastore == null)
throw new IllegalStateException("No DataStore");
- if (LOG.isDebugEnabled()) LOG.debug("Loading session {} from DataStore", key);
+ if (LOG.isDebugEnabled()) LOG.debug("Loading session {} from DataStore ", key);
Entity entity = _datastore.get(key);
if (entity == null)
@@ -1222,7 +1146,7 @@ public class GCloudSessionManager extends AbstractSessionManager
* @param session
* @return
*/
- private Key makeKey (Session session, Context context)
+ protected Key makeKey (Session session, Context context)
{
return makeKey(session.getId(), context);
}
@@ -1241,12 +1165,24 @@ public class GCloudSessionManager extends AbstractSessionManager
* @param session
* @return
*/
- private Key makeKey (String id, Context context)
+ protected Key makeKey (String id, Context context)
+ {
+ return _keyFactory.newKey(canonicalizeKey(id,context));
+ }
+
+
+ /**
+ * Make a unique string from the session id and info from its Context
+ * @param id the id of the Session
+ * @param context the Context in which the Session exists
+ * @return a unique string representing the id of the session in the context
+ */
+ protected String canonicalizeKey(String id, Context context)
{
String key = getContextPath(context);
key = key + "_" + getVirtualHost(context);
key = key+"_"+id;
- return _keyFactory.newKey(key);
+ return key;
}
/**
diff --git a/tests/test-sessions/pom.xml b/tests/test-sessions/pom.xml
index 7b323c1e867..a6fb98a1986 100644
--- a/tests/test-sessions/pom.xml
+++ b/tests/test-sessions/pom.xml
@@ -36,5 +36,6 @@
test-mongodb-sessions
test-infinispan-sessions
test-gcloud-sessions
+ test-gcloud-memcached-sessions
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/pom.xml b/tests/test-sessions/test-gcloud-memcached-sessions/pom.xml
new file mode 100644
index 00000000000..b0082e5ea5d
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/pom.xml
@@ -0,0 +1,110 @@
+
+
+
+ 4.0.0
+
+ org.eclipse.jetty.tests
+ test-sessions-parent
+ 9.3.10-SNAPSHOT
+
+ test-gcloud-memcached-sessions
+ Jetty Tests :: Sessions :: GCloud with Memcached
+ http://www.eclipse.org/jetty
+
+ ${project.groupId}.sessions.gcloud.memcached
+
+
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+
+
+ true
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ true
+
+
+
+
+
+
+ org.eclipse.jetty
+ jetty-server
+ ${project.version}
+
+
+ org.eclipse.jetty
+ jetty-webapp
+ ${project.version}
+
+
+ org.eclipse.jetty
+ jetty-client
+ ${project.version}
+
+
+ org.eclipse.jetty.tests
+ test-sessions-common
+ ${project.version}
+
+
+ org.eclipse.jetty.gcloud
+ jetty-gcloud-memcached-session-manager
+ ${project.version}
+
+
+ org.eclipse.jetty.toolchain
+ jetty-test-helper
+ test
+
+
+
+
+ gcloud
+
+
+ gcloud.enabled
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ false
+
+ jetty9-work
+ http://localhost:8088
+
+
+
+
+
+
+
+
+
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ClientCrossContextSessionTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ClientCrossContextSessionTest.java
new file mode 100644
index 00000000000..aeb0d68d01a
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ClientCrossContextSessionTest.java
@@ -0,0 +1,66 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractClientCrossContextSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * ClientCrossContextSessionTest
+ *
+ *
+ */
+public class ClientCrossContextSessionTest extends AbstractClientCrossContextSessionTest
+{
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _testSupport.setUp();
+ }
+
+ @AfterClass
+ public static void teardown () throws Exception
+ {
+ _testSupport.tearDown();
+ }
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractClientCrossContextSessionTest#createServer(int)
+ */
+ @Override
+ public AbstractTestServer createServer(int port)
+ {
+ return new GCloudTestServer(port, _testSupport.getConfiguration());
+ }
+
+ @Test
+ @Override
+ public void testCrossContextDispatch() throws Exception
+ {
+ super.testCrossContextDispatch();
+ }
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ForwardedSessionTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ForwardedSessionTest.java
new file mode 100644
index 00000000000..aa37e069b07
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ForwardedSessionTest.java
@@ -0,0 +1,58 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractForwardedSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * ForwardedSessionTest
+ *
+ *
+ */
+public class ForwardedSessionTest extends AbstractForwardedSessionTest
+{
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _testSupport.setUp();
+ }
+
+ @AfterClass
+ public static void teardown () throws Exception
+ {
+ _testSupport.tearDown();
+ }
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractForwardedSessionTest#createServer(int)
+ */
+ @Override
+ public AbstractTestServer createServer(int port)
+ {
+ return new GCloudTestServer(port, _testSupport.getConfiguration());
+ }
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/GCloudSessionTestSupport.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/GCloudSessionTestSupport.java
new file mode 100644
index 00000000000..6bf5c81380b
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/GCloudSessionTestSupport.java
@@ -0,0 +1,389 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.eclipse.jetty.gcloud.session.GCloudConfiguration;
+import org.eclipse.jetty.gcloud.session.GCloudSessionManager;
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.resource.JarResource;
+import org.eclipse.jetty.util.resource.Resource;
+
+import com.google.api.client.util.Strings;
+import com.google.gcloud.datastore.Datastore;
+import com.google.gcloud.datastore.DatastoreFactory;
+import com.google.gcloud.datastore.Entity;
+import com.google.gcloud.datastore.GqlQuery;
+import com.google.gcloud.datastore.Key;
+import com.google.gcloud.datastore.ProjectionEntity;
+import com.google.gcloud.datastore.Query;
+import com.google.gcloud.datastore.Query.ResultType;
+import com.google.gcloud.datastore.QueryResults;
+import com.google.gcloud.datastore.StructuredQuery;
+import com.google.gcloud.datastore.StructuredQuery.Projection;
+
+import net.rubyeye.xmemcached.MemcachedClient;
+import net.rubyeye.xmemcached.XMemcachedClientBuilder;
+
+/**
+ * GCloudSessionTestSupport
+ *
+ *
+ */
+public class GCloudSessionTestSupport
+{
+
+ public static class MemcacheFlusher
+ {
+ protected XMemcachedClientBuilder _builder;
+ protected MemcachedClient _client;
+
+
+ public MemcacheFlusher()
+ {
+ try
+ {
+ _builder = new XMemcachedClientBuilder("localhost:11211");
+ _client = _builder.build();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void flush () throws Exception
+ {
+ _client.flushAllWithNoReply();
+ }
+ }
+
+ private static class ProcessOutputReader implements Runnable
+ {
+ private InputStream _is;
+ private String _startupSentinel;
+ private BufferedReader _reader;
+
+ public ProcessOutputReader (InputStream is, String startupSentinel)
+ throws Exception
+ {
+ _is = is;
+ _startupSentinel = startupSentinel;
+ _reader = new BufferedReader(new InputStreamReader(_is));
+ if (!Strings.isNullOrEmpty(_startupSentinel))
+ {
+ String line;
+ while ((line = _reader.readLine()) != (null) && !line.contains(_startupSentinel))
+ {
+ //System.err.println(line);
+ }
+ }
+ }
+
+
+ public void run()
+ {
+ String line;
+ try
+ {
+ while ((line = _reader.readLine()) != (null))
+ {
+ }
+ }
+ catch (IOException ignore)
+ {
+ /* ignore */
+ }
+ finally
+ {
+ IO.close(_reader);
+ }
+ }
+ }
+
+
+ public static String DEFAULT_PROJECTID = "jetty9-work";
+ public static String DEFAULT_PORT = "8088";
+ public static String DEFAULT_HOST = "http://localhost:"+DEFAULT_PORT;
+ public static String DEFAULT_GCD_ZIP = "gcd-v1beta2-rev1-2.1.2b.zip";
+ public static String DEFAULT_GCD_UNPACKED = "gcd-v1beta2-rev1-2.1.2b";
+ public static String DEFAULT_DOWNLOAD_URL = "http://storage.googleapis.com/gcd/tools/";
+
+ static MemcacheFlusher _flusher = new MemcacheFlusher();
+
+ String _projectId;
+ String _testServerUrl;
+ String _testPort;
+ File _datastoreDir;
+ File _gcdInstallDir;
+ File _gcdUnpackedDir;
+ Datastore _ds;
+
+ public GCloudSessionTestSupport (File gcdInstallDir)
+ {
+ _gcdInstallDir = gcdInstallDir;
+ if (_gcdInstallDir == null)
+ _gcdInstallDir = new File (System.getProperty("java.io.tmpdir"));
+
+ _projectId = System.getProperty("DATASTORE_DATASET", System.getenv("DATASTORE_DATASET"));
+ if (_projectId == null)
+ {
+ _projectId = DEFAULT_PROJECTID;
+ System.setProperty("DATASTORE_DATASET", _projectId);
+ }
+ _testServerUrl = System.getProperty("DATASTORE_HOST", System.getenv("DATASTORE_HOST"));
+ if (_testServerUrl == null)
+ {
+ _testServerUrl = DEFAULT_HOST;
+ _testPort = DEFAULT_PORT;
+ System.setProperty("DATASTORE_HOST", _testServerUrl);
+ }
+ else
+ {
+ int i = _testServerUrl.lastIndexOf(':');
+ _testPort = _testServerUrl.substring(i+1);
+ }
+ }
+
+ public GCloudSessionTestSupport ()
+ {
+ this(null);
+ }
+
+ public GCloudConfiguration getConfiguration ()
+ {
+ return new GCloudConfiguration();
+ }
+
+
+ public void setUp()
+ throws Exception
+ {
+ downloadGCD();
+ createDatastore();
+ startDatastore();
+ }
+
+
+ public void downloadGCD()
+ throws Exception
+ {
+ File zipFile = new File (_gcdInstallDir, DEFAULT_GCD_ZIP);
+ _gcdUnpackedDir = new File (_gcdInstallDir, DEFAULT_GCD_UNPACKED);
+ File gcdSh = new File (_gcdUnpackedDir, "gcd.sh");
+ if (gcdSh.exists())
+ return;
+
+
+ if (_gcdInstallDir.exists() && !zipFile.exists())
+ {
+ //download it
+ ReadableByteChannel rbc = Channels.newChannel(new URL(DEFAULT_DOWNLOAD_URL+DEFAULT_GCD_ZIP).openStream());
+ try (FileOutputStream fos = new FileOutputStream(zipFile))
+ {
+ fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
+ }
+ }
+
+ if (zipFile.exists())
+ {
+ //unpack it
+ Resource zipResource = JarResource.newJarResource(Resource.newResource(zipFile));
+ zipResource.copyTo(_gcdInstallDir);
+ }
+
+ System.err.println("GCD downloaded and unpacked");
+ }
+
+
+
+ public void createDatastore ()
+ throws Exception
+ {
+
+ _datastoreDir = Files.createTempDirectory("gcloud-sessions").toFile();
+ _datastoreDir.deleteOnExit();
+
+ ProcessBuilder processBuilder = new ProcessBuilder();
+ processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
+ processBuilder.directory(_datastoreDir);
+ if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows"))
+ {
+ processBuilder.command("cmd", "/C", new File(_gcdUnpackedDir, "gcd.cmd").getAbsolutePath(), "create", "-p", _projectId, _projectId);
+ processBuilder.redirectOutput(new File("NULL:"));
+ }
+ else
+ {
+ processBuilder.redirectOutput(new File("/tmp/run.out"));
+ processBuilder.command("bash", new File(_gcdUnpackedDir, "gcd.sh").getAbsolutePath(), "create", "-p",_projectId, _projectId);
+ }
+
+ Process temp = processBuilder.start();
+ System.err.println("Create outcome: "+temp.waitFor());
+ }
+
+
+ public void startDatastore()
+ throws Exception
+ {
+ //start the datastore for the test
+ ProcessBuilder processBuilder = new ProcessBuilder();
+ processBuilder.directory(_datastoreDir);
+ processBuilder.redirectErrorStream(true);
+ if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("windows"))
+ {
+ processBuilder.command("cmd", "/C", new File(_gcdUnpackedDir, "gcd.cmd").getAbsolutePath(), "start", "--testing", "--allow_remote_shutdown","--port="+_testPort, _projectId);
+ }
+ else
+ {
+ processBuilder.command("bash", new File(_gcdUnpackedDir, "gcd.sh").getAbsolutePath(), "start", "--testing", "--allow_remote_shutdown", "--port="+_testPort, _projectId);
+ }
+
+ System.err.println("Starting datastore");
+ Process temp = processBuilder.start();
+ ProcessOutputReader reader = new ProcessOutputReader(temp.getInputStream(), "Dev App Server is now running");
+ Thread readerThread = new Thread(reader, "GCD reader");
+ readerThread.setDaemon(true);
+ readerThread.start();
+ }
+
+ public void stopDatastore()
+ throws Exception
+ {
+ //Send request to terminate test datastore
+ URL url = new URL("http", "localhost", Integer.parseInt(_testPort.trim()), "/_ah/admin/quit");
+ HttpURLConnection con = (HttpURLConnection) url.openConnection();
+ con.setRequestMethod("POST");
+ con.setDoOutput(true);
+ con.setDoInput(true);
+ OutputStream out = con.getOutputStream();
+ out.write("".getBytes());
+ out.flush();
+ InputStream in = con.getInputStream();
+ while (in.read() != -1)
+ {
+ // consume input
+
+ }
+
+ System.err.println("Stop issued");
+ }
+
+
+ public void clearDatastore()
+ {
+ org.eclipse.jetty.util.IO.delete(_datastoreDir);
+ }
+
+ public void tearDown()
+ throws Exception
+ {
+ stopDatastore();
+ clearDatastore();
+ _flusher.flush();
+ }
+
+ public void ensureDatastore()
+ throws Exception
+ {
+ if (_ds == null)
+ _ds = DatastoreFactory.instance().get(getConfiguration().getDatastoreOptions());
+ }
+ public void listSessions () throws Exception
+ {
+ ensureDatastore();
+ GqlQuery.Builder builder = Query.gqlQueryBuilder(ResultType.ENTITY, "select * from "+GCloudSessionManager.KIND);
+
+ Query query = builder.build();
+
+ QueryResults results = _ds.run(query);
+ assertNotNull(results);
+ System.err.println("SESSIONS::::::::");
+ while (results.hasNext())
+ {
+
+ Entity e = results.next();
+ System.err.println(e.getString("clusterId")+" expires at "+e.getLong("expiry"));
+ }
+ System.err.println("END OF SESSIONS::::::::");
+ }
+
+ public void assertSessions(int count) throws Exception
+ {
+ ensureDatastore();
+ StructuredQuery keyOnlyProjectionQuery = Query.projectionEntityQueryBuilder()
+ .kind(GCloudSessionManager.KIND)
+ .projection(Projection.property("__key__"))
+ .limit(100)
+ .build();
+ QueryResults results = _ds.run(keyOnlyProjectionQuery);
+ assertNotNull(results);
+ int actual = 0;
+ while (results.hasNext())
+ {
+ results.next();
+ ++actual;
+ }
+ assertEquals(count, actual);
+ }
+
+ public void deleteSessions () throws Exception
+ {
+ ensureDatastore();
+ StructuredQuery keyOnlyProjectionQuery = Query.projectionEntityQueryBuilder()
+ .kind(GCloudSessionManager.KIND)
+ .projection(Projection.property("__key__"))
+ .limit(100)
+ .build();
+ QueryResults results = _ds.run(keyOnlyProjectionQuery);
+ if (results != null)
+ {
+ List keys = new ArrayList();
+
+ while (results.hasNext())
+ {
+ ProjectionEntity pe = results.next();
+ keys.add(pe.key());
+ }
+
+ _ds.delete(keys.toArray(new Key[keys.size()]));
+ }
+
+ assertSessions(0);
+ }
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/GCloudTestServer.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/GCloudTestServer.java
new file mode 100644
index 00000000000..a144fe96514
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/GCloudTestServer.java
@@ -0,0 +1,105 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.gcloud.session.GCloudConfiguration;
+import org.eclipse.jetty.gcloud.session.GCloudSessionIdManager;
+import org.eclipse.jetty.server.SessionIdManager;
+import org.eclipse.jetty.server.SessionManager;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.server.session.SessionHandler;
+
+import com.google.gcloud.datastore.Datastore;
+import com.google.gcloud.datastore.DatastoreFactory;
+
+/**
+ * GCloudTestServer
+ *
+ *
+ */
+public class GCloudTestServer extends AbstractTestServer
+{
+ static int __workers=0;
+ public static int STALE_INTERVAL_SEC = 1;
+
+
+
+ /**
+ * @param port
+ * @param maxInactivePeriod
+ * @param scavengePeriod
+ * @param sessionIdMgrConfig
+ */
+ public GCloudTestServer(int port, int maxInactivePeriod, int scavengePeriod, GCloudConfiguration config)
+ {
+ super(port, maxInactivePeriod, scavengePeriod, config);
+ }
+
+ /**
+ * @param port
+ * @param configuration
+ */
+ public GCloudTestServer(int port, GCloudConfiguration configuration)
+ {
+ super(port, 30,10, configuration);
+ }
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionIdManager(java.lang.Object)
+ */
+ @Override
+ public SessionIdManager newSessionIdManager(Object config)
+ {
+ GCloudSessionIdManager idManager = new GCloudSessionIdManager(getServer());
+ idManager.setWorkerName("w"+(__workers++));
+ idManager.setConfig((GCloudConfiguration)config);
+ return idManager;
+ }
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionManager()
+ */
+ @Override
+ public SessionManager newSessionManager()
+ {
+ GCloudMemcachedSessionManager sessionManager = new GCloudMemcachedSessionManager();
+ sessionManager.setSessionIdManager((GCloudSessionIdManager)_sessionIdManager);
+ sessionManager.setStaleIntervalSec(STALE_INTERVAL_SEC);
+ sessionManager.setScavengeIntervalSec(_scavengePeriod);
+ sessionManager.setExpirySec(0);
+ sessionManager.setHost("localhost");
+ sessionManager.setPort("11211");
+ return sessionManager;
+
+ }
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractTestServer#newSessionHandler(org.eclipse.jetty.server.SessionManager)
+ */
+ @Override
+ public SessionHandler newSessionHandler(SessionManager sessionManager)
+ {
+ return new SessionHandler(sessionManager);
+ }
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ImmortalSessionTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ImmortalSessionTest.java
new file mode 100644
index 00000000000..4fb57db00c1
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ImmortalSessionTest.java
@@ -0,0 +1,69 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractImmortalSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * ImmortalSessionTest
+ *
+ *
+ */
+public class ImmortalSessionTest extends AbstractImmortalSessionTest
+{
+ static GCloudSessionTestSupport _testSupport;
+
+ /**
+ * @throws Exception
+ */
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _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 GCloudTestServer(port, port, scavengeMs, _testSupport.getConfiguration());
+ }
+
+ @Test
+ @Override
+ public void testImmortalSession() throws Exception
+ {
+ super.testImmortalSession();
+ }
+
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/InvalidationSessionTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/InvalidationSessionTest.java
new file mode 100644
index 00000000000..521deec9f34
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/InvalidationSessionTest.java
@@ -0,0 +1,78 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractInvalidationSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+/**
+ * InvalidationSessionTest
+ *
+ *
+ */
+public class InvalidationSessionTest extends AbstractInvalidationSessionTest
+{
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _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 GCloudTestServer(port, _testSupport.getConfiguration());
+ }
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#pause()
+ */
+ @Override
+ public void pause()
+ {
+ //This test moves around a session between 2 nodes. After it is invalidated on the 1st node,
+ //it will still be in the memory of the 2nd node. We need to wait until after the stale time
+ //has expired on node2 for it to reload the session and discover it has been deleted.
+ try
+ {
+ Thread.currentThread().sleep((2*GCloudTestServer.STALE_INTERVAL_SEC)*1000);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ }
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/LastAccessTimeTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/LastAccessTimeTest.java
new file mode 100644
index 00000000000..8963cda46a6
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/LastAccessTimeTest.java
@@ -0,0 +1,66 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractLastAccessTimeTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * LastAccessTimeTest
+ *
+ *
+ */
+public class LastAccessTimeTest extends AbstractLastAccessTimeTest
+{
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _testSupport.setUp();
+ }
+
+ @AfterClass
+ public static void teardown () throws Exception
+ {
+ _testSupport.tearDown();
+ }
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractLastAccessTimeTest#createServer(int, int, int)
+ */
+ @Override
+ public AbstractTestServer createServer(int port, int max, int scavenge)
+ {
+ return new GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+ }
+
+ @Test
+ @Override
+ public void testLastAccessTime() throws Exception
+ {
+ super.testLastAccessTime();
+ }
+
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/LocalSessionScavengingTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/LocalSessionScavengingTest.java
new file mode 100644
index 00000000000..5aff70bf054
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/LocalSessionScavengingTest.java
@@ -0,0 +1,67 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractLocalSessionScavengingTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * LocalSessionScavengingTest
+ *
+ *
+ */
+public class LocalSessionScavengingTest extends AbstractLocalSessionScavengingTest
+{
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _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 GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+ }
+
+ @Test
+ @Override
+ public void testLocalSessionsScavenging() throws Exception
+ {
+ super.testLocalSessionsScavenging();
+ }
+
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/NewSessionTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/NewSessionTest.java
new file mode 100644
index 00000000000..6eebb2a6169
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/NewSessionTest.java
@@ -0,0 +1,71 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import java.io.File;
+
+import org.eclipse.jetty.server.session.AbstractNewSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * NewSessionTest
+ *
+ *
+ */
+public class NewSessionTest extends AbstractNewSessionTest
+{
+ GCloudSessionTestSupport _testSupport;
+
+ @Before
+ public void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _testSupport.setUp();
+ }
+
+ @After
+ public 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 GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+ }
+
+ @Test
+ public void testNewSession() throws Exception
+ {
+ super.testNewSession();
+ }
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/OrphanedSessionTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/OrphanedSessionTest.java
new file mode 100644
index 00000000000..8ca53b1f2ef
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/OrphanedSessionTest.java
@@ -0,0 +1,71 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractOrphanedSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * OrphanedSessionTest
+ *
+ *
+ */
+public class OrphanedSessionTest extends AbstractOrphanedSessionTest
+{
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _testSupport.setUp();
+ }
+
+ @AfterClass
+ public static void teardown () throws Exception
+ {
+ _testSupport.tearDown();
+ }
+
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractOrphanedSessionTest#createServer(int, int, int)
+ */
+ @Override
+ public AbstractTestServer createServer(int port, int max, int scavenge)
+ {
+ return new GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+ }
+
+ @Test
+ @Override
+ public void testOrphanedSession() throws Exception
+ {
+ super.testOrphanedSession();
+ _testSupport.assertSessions(0);
+ }
+
+
+
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ReentrantRequestSessionTest.java
new file mode 100644
index 00000000000..79212bd848b
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ReentrantRequestSessionTest.java
@@ -0,0 +1,68 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractReentrantRequestSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * ReentrantRequestSessionTest
+ *
+ *
+ */
+public class ReentrantRequestSessionTest extends AbstractReentrantRequestSessionTest
+{
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _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 GCloudTestServer(port, _testSupport.getConfiguration());
+ }
+
+ @Test
+ @Override
+ public void testReentrantRequestSession() throws Exception
+ {
+ super.testReentrantRequestSession();
+ }
+
+
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/RemoveSessionTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/RemoveSessionTest.java
new file mode 100644
index 00000000000..4392ff38d5c
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/RemoveSessionTest.java
@@ -0,0 +1,71 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractRemoveSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * RemoveSessionTest
+ *
+ *
+ */
+public class RemoveSessionTest extends AbstractRemoveSessionTest
+{
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _testSupport.setUp();
+ }
+
+ @AfterClass
+ public static void teardown () throws Exception
+ {
+ _testSupport.tearDown();
+ }
+
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractRemoveSessionTest#createServer(int, int, int)
+ */
+ @Override
+ public AbstractTestServer createServer(int port, int max, int scavenge)
+ {
+ return new GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+ }
+
+ @Test
+ @Override
+ public void testRemoveSession() throws Exception
+ {
+ super.testRemoveSession();
+ }
+
+
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SameNodeLoadTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SameNodeLoadTest.java
new file mode 100644
index 00000000000..2bfe350244d
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SameNodeLoadTest.java
@@ -0,0 +1,67 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractSameNodeLoadTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SameNodeLoadTest
+ *
+ *
+ */
+public class SameNodeLoadTest extends AbstractSameNodeLoadTest
+{
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _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)
+ {
+ return new GCloudTestServer(port, _testSupport.getConfiguration());
+ }
+
+ @Test
+ @Override
+ public void testLoad() throws Exception
+ {
+ super.testLoad();
+ }
+
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ServerCrossContextSessionTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ServerCrossContextSessionTest.java
new file mode 100644
index 00000000000..43d86234b43
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/ServerCrossContextSessionTest.java
@@ -0,0 +1,67 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractServerCrossContextSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * ServerCrossContextSessionTest
+ *
+ *
+ */
+public class ServerCrossContextSessionTest extends AbstractServerCrossContextSessionTest
+{
+
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _testSupport.setUp();
+ }
+
+ @AfterClass
+ public static void teardown () throws Exception
+ {
+ _testSupport.tearDown();
+ }
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractServerCrossContextSessionTest#createServer(int)
+ */
+ @Override
+ public AbstractTestServer createServer(int port)
+ {
+ return new GCloudTestServer(port, _testSupport.getConfiguration());
+ }
+
+ @Test
+ @Override
+ public void testCrossContextDispatch() throws Exception
+ {
+ super.testCrossContextDispatch();
+ }
+
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionExpiryTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionExpiryTest.java
new file mode 100644
index 00000000000..7c3cbadd9bd
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionExpiryTest.java
@@ -0,0 +1,107 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractSessionExpiryTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SessionExpiryTest
+ *
+ *
+ */
+public class SessionExpiryTest extends AbstractSessionExpiryTest
+{
+
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _testSupport.setUp();
+ }
+
+ @AfterClass
+ public static void teardown () throws Exception
+ {
+ _testSupport.tearDown();
+ }
+
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractSessionExpiryTest#createServer(int, int, int)
+ */
+ @Override
+ public AbstractTestServer createServer(int port, int max, int scavenge)
+ {
+ return new GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+ }
+
+ @Test
+ @Override
+ public void testSessionNotExpired() throws Exception
+ {
+ super.testSessionNotExpired();
+ _testSupport.deleteSessions();
+ }
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractSessionExpiryTest#testSessionExpiry()
+ */
+ @Test
+ @Override
+ public void testSessionExpiry() throws Exception
+ {
+ super.testSessionExpiry();
+ _testSupport.assertSessions(0);
+ }
+
+ @Override
+ public void verifySessionCreated(TestHttpSessionListener listener, String sessionId)
+ {
+ super.verifySessionCreated(listener, sessionId);
+ try
+ {
+ _testSupport.assertSessions(1);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void verifySessionDestroyed(TestHttpSessionListener listener, String sessionId)
+ {
+ super.verifySessionDestroyed(listener, sessionId);
+ try
+ {
+ _testSupport.assertSessions(0);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionInvalidateAndCreateTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionInvalidateAndCreateTest.java
new file mode 100644
index 00000000000..d932f2f165d
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionInvalidateAndCreateTest.java
@@ -0,0 +1,69 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractSessionInvalidateAndCreateTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SessionInvalidateAndCreateTest
+ *
+ *
+ */
+public class SessionInvalidateAndCreateTest extends AbstractSessionInvalidateAndCreateTest
+{
+
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _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 GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+ }
+
+ @Test
+ @Override
+ public void testSessionScavenge() throws Exception
+ {
+ super.testSessionScavenge();
+ }
+
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionMigrationTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionMigrationTest.java
new file mode 100644
index 00000000000..10dd1dcd293
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionMigrationTest.java
@@ -0,0 +1,68 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractSessionMigrationTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SessionMigrationTest
+ *
+ *
+ */
+public class SessionMigrationTest extends AbstractSessionMigrationTest
+{
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _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 GCloudTestServer(port, _testSupport.getConfiguration());
+ }
+
+
+ @Test
+ @Override
+ public void testSessionMigration() throws Exception
+ {
+ super.testSessionMigration();
+ }
+
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionRenewTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionRenewTest.java
new file mode 100644
index 00000000000..068032ea1df
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionRenewTest.java
@@ -0,0 +1,67 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractSessionRenewTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SessionRenewTest
+ *
+ *
+ */
+public class SessionRenewTest extends AbstractSessionRenewTest
+{
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _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 GCloudTestServer(port,max, scavenge, _testSupport.getConfiguration());
+ }
+
+ @Test
+ @Override
+ public void testSessionRenewal() throws Exception
+ {
+ super.testSessionRenewal();
+ }
+
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionValueSavingTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionValueSavingTest.java
new file mode 100644
index 00000000000..a39accf30cc
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/SessionValueSavingTest.java
@@ -0,0 +1,68 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import org.eclipse.jetty.server.session.AbstractSessionValueSavingTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * SessionValueSavingTest
+ *
+ *
+ */
+public class SessionValueSavingTest extends AbstractSessionValueSavingTest
+{
+
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _testSupport.setUp();
+ }
+
+ @AfterClass
+ public static void teardown () throws Exception
+ {
+ _testSupport.tearDown();
+ }
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractSessionValueSavingTest#createServer(int, int, int)
+ */
+ @Override
+ public AbstractTestServer createServer(int port, int max, int scavenge)
+ {
+ return new GCloudTestServer(port, max, scavenge, _testSupport.getConfiguration());
+ }
+
+ @Test
+ @Override
+ public void testSessionValueSaving() throws Exception
+ {
+ super.testSessionValueSaving();
+ }
+
+
+}
diff --git a/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/StopSessionManagerPreserveSessionTest.java b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/StopSessionManagerPreserveSessionTest.java
new file mode 100644
index 00000000000..c4c98dba07e
--- /dev/null
+++ b/tests/test-sessions/test-gcloud-memcached-sessions/src/test/java/org/eclipse/jetty/gcloud/memcached/session/StopSessionManagerPreserveSessionTest.java
@@ -0,0 +1,95 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2016 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.gcloud.memcached.session;
+
+import static org.junit.Assert.fail;
+import org.eclipse.jetty.server.session.AbstractStopSessionManagerPreserveSessionTest;
+import org.eclipse.jetty.server.session.AbstractTestServer;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * StopSessionManagerPreserveSessionTest
+ *
+ *
+ */
+public class StopSessionManagerPreserveSessionTest extends AbstractStopSessionManagerPreserveSessionTest
+{
+ static GCloudSessionTestSupport _testSupport;
+
+ @BeforeClass
+ public static void setup () throws Exception
+ {
+ _testSupport = new GCloudSessionTestSupport();
+ _testSupport.setUp();
+ }
+
+ @AfterClass
+ public static void teardown () throws Exception
+ {
+ _testSupport.tearDown();
+ }
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractStopSessionManagerPreserveSessionTest#checkSessionPersisted(boolean)
+ */
+ @Override
+ public void checkSessionPersisted(boolean expected)
+ {
+ try
+ {
+ _testSupport.assertSessions(1);
+ }
+ catch (Exception e)
+ {
+ fail(e.getMessage());
+ }
+
+ }
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractStopSessionManagerPreserveSessionTest#createServer(int)
+ */
+ @Override
+ public AbstractTestServer createServer(int port)
+ {
+ return new GCloudTestServer(port, _testSupport.getConfiguration());
+ }
+
+ /**
+ * @see org.eclipse.jetty.server.session.AbstractStopSessionManagerPreserveSessionTest#configureSessionManagement(org.eclipse.jetty.servlet.ServletContextHandler)
+ */
+ @Override
+ public void configureSessionManagement(ServletContextHandler context)
+ {
+
+ }
+
+ @Test
+ @Override
+ public void testStopSessionManagerPreserveSession() throws Exception
+ {
+ super.testStopSessionManagerPreserveSession();
+ }
+
+
+}