diff --git a/Jenkinsfile b/Jenkinsfile index d24aac9ba18..7a42c104c2b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -89,7 +89,7 @@ def getFullBuild(jdk, os) { globalMavenSettingsConfig: 'oss-settings.xml', mavenLocalRepo: "${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}") { // - sh "mvn -V -B install -Dmaven.test.failure.ignore=true -Prun-its -T3 -e -Dmaven.repo.local=${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER}" + sh "mvn -V -B install -Dmaven.test.failure.ignore=true -Prun-its -T3 -e -Dmaven.repo.local=${env.JENKINS_HOME}/${env.EXECUTOR_NUMBER} -Pmongodb" } // withMaven doesn't label.. // Report failures in the jenkins UI diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectionPool.java b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectionPool.java index 19ec8ba7bf8..29d85e8fd79 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectionPool.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/AbstractConnectionPool.java @@ -127,7 +127,7 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable { if (LOG.isDebugEnabled()) LOG.debug("Connection {}/{} creation succeeded {}", total+1, maxConnections, connection); - connections.update(-1,0); + connections.add(-1,0); onCreated(connection); proceed(); } @@ -137,7 +137,7 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable { if (LOG.isDebugEnabled()) LOG.debug("Connection " + (total+1) + "/" + maxConnections + " creation failed", x); - connections.update(-1,-1); + connections.add(-1,-1); requester.failed(x); } }); @@ -190,7 +190,7 @@ public abstract class AbstractConnectionPool implements ConnectionPool, Dumpable protected void removed(Connection connection) { - int pooled = connections.updateLo(-1); + int pooled = connections.addAndGetLo(-1); if (LOG.isDebugEnabled()) LOG.debug("Connection removed {} - pooled: {}", connection, pooled); } diff --git a/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-embedded.adoc b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-embedded.adoc index 9332335f068..ccc7f32a1eb 100644 --- a/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-embedded.adoc +++ b/jetty-documentation/src/main/asciidoc/administration/jndi/jndi-embedded.adoc @@ -31,8 +31,8 @@ jetty-plus.jar If you are using transactions, you will also need the `javax.transaction` api. You can obtain this jar link:{MVNCENTRAL}/org/eclipse/jetty/orbit/javax.transaction/1.1.1.v201105210645/javax.transaction-1.1.1.v201105210645.jar[here.] -If you wish to use mail, you will also need the `javax.mail` api and implementation which link:{MVNCENTRAL/org/eclipse/jetty/orbit/javax.mail.glassfish/1.4.1.v201005082020/javax.mail.glassfish-1.4.1.v201005082020.jar[you can download here.] -Note that this jar also requires the `javax.activation` classes, which is available link:{MVCENTRAL}/org/eclipse/jetty/orbit/javax.activation/1.1.0.v201105071233/javax.activation-1.1.0.v201105071233.jar[at this link.] +If you wish to use mail, you will also need the `javax.mail` api and implementation which link:{MVNCENTRAL}/org/eclipse/jetty/orbit/javax.mail.glassfish/1.4.1.v201005082020/javax.mail.glassfish-1.4.1.v201005082020.jar[you can download here.] +Note that this jar also requires the `javax.activation` classes, which is available link:{MVNCENTRAL}/org/eclipse/jetty/orbit/javax.activation/1.1.0.v201105071233/javax.activation-1.1.0.v201105071233.jar[at this link.] ==== Example Code diff --git a/jetty-documentation/src/main/asciidoc/development/frameworks/osgi.adoc b/jetty-documentation/src/main/asciidoc/development/frameworks/osgi.adoc index 66053995632..df45a5fbefb 100644 --- a/jetty-documentation/src/main/asciidoc/development/frameworks/osgi.adoc +++ b/jetty-documentation/src/main/asciidoc/development/frameworks/osgi.adoc @@ -492,7 +492,7 @@ public void start(BundleContext context) throws Exception Dictionary props = new Hashtable(); props.put("Jetty-WarResourcePath","."); props.put("contextPath","/acme"); - context.registerService(ContextHandler.class.getName(),webapp,props); + context.registerService(WebAppContext.class.getName(),webapp,props); } ---- diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java index 178b73079d0..c8a6f30fca6 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStore.java @@ -510,16 +510,22 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { if (LOG.isDebugEnabled()) LOG.debug("Loading session {} from DataStore", id); - Entity entity = _datastore.get(makeKey(id, _context)); - if (entity == null) + try { - if (LOG.isDebugEnabled()) LOG.debug("No session {} in DataStore ", id); - return null; + Entity entity = _datastore.get(makeKey(id, _context)); + if (entity == null) + { + if (LOG.isDebugEnabled()) LOG.debug("No session {} in DataStore ", id); + return null; + } + else + { + return sessionFromEntity(entity); + } } - else + catch (Exception e) { - SessionData data = sessionFromEntity(entity); - return data; + throw new UnreadableSessionDataException(id, _context, e); } } @@ -706,7 +712,10 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore Query query = Query.newProjectionEntityQueryBuilder() .setKind(_model.getKind()) .setProjection(_model.getExpiry()) - .setFilter(PropertyFilter.eq(_model.getId(), id)) + .setFilter(CompositeFilter.and(PropertyFilter.eq(_model.getId(), id), + PropertyFilter.eq(_model.getContextPath(), _context.getCanonicalContextPath()), + PropertyFilter.eq(_model.getVhost(), _context.getVhost()))) + //.setFilter(PropertyFilter.eq(_model.getId(), id)) .build(); QueryResults presults; @@ -731,7 +740,10 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore { Query query = Query.newEntityQueryBuilder() .setKind(_model.getKind()) - .setFilter(PropertyFilter.eq(_model.getId(), id)) + .setFilter(CompositeFilter.and(PropertyFilter.eq(_model.getId(), id), + PropertyFilter.eq(_model.getContextPath(), _context.getCanonicalContextPath()), + PropertyFilter.eq(_model.getVhost(), _context.getVhost()))) + //.setFilter(PropertyFilter.eq(_model.getId(), id)) .build(); QueryResults results; @@ -912,8 +924,8 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore if (entity == null) return null; - final AtomicReference reference = new AtomicReference(); - final AtomicReference exception = new AtomicReference(); + final AtomicReference reference = new AtomicReference<>(); + final AtomicReference exception = new AtomicReference<>(); Runnable load = new Runnable() { @Override @@ -975,7 +987,9 @@ public class GCloudSessionDataStore extends AbstractSessionDataStore _context.run(load); if (exception.get() != null) + { throw exception.get(); + } return reference.get(); } diff --git a/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStore.java b/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStore.java index f9156f3a4f7..edea4840233 100644 --- a/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStore.java +++ b/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStore.java @@ -23,6 +23,7 @@ import org.eclipse.jetty.server.session.AbstractSessionDataStore; import org.eclipse.jetty.server.session.SessionContext; import org.eclipse.jetty.server.session.SessionData; import org.eclipse.jetty.server.session.SessionDataStore; +import org.eclipse.jetty.server.session.UnreadableSessionDataException; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -55,23 +56,22 @@ public class HazelcastSessionDataStore throws Exception { - final AtomicReference reference = new AtomicReference(); - final AtomicReference exception = new AtomicReference(); + final AtomicReference reference = new AtomicReference<>(); + final AtomicReference exception = new AtomicReference<>(); //ensure the load runs in the context classloader scope _context.run( () -> { try { if (LOG.isDebugEnabled()) - { LOG.debug( "Loading session {} from hazelcast", id ); - } + SessionData sd = sessionDataMap.get( getCacheKey( id ) ); reference.set(sd); } catch (Exception e) { - exception.set(e); + exception.set(new UnreadableSessionDataException(id, _context, e)); } } ); @@ -126,12 +126,13 @@ public class HazelcastSessionDataStore { return Collections.emptySet(); } + long now = System.currentTimeMillis(); return candidates.stream().filter( candidate -> { + if (LOG.isDebugEnabled()) - { LOG.debug( "Checking expiry for candidate {}", candidate ); - } + try { SessionData sd = load(candidate); @@ -193,9 +194,17 @@ public class HazelcastSessionDataStore @Override public boolean exists( String id ) - throws Exception + throws Exception { - return this.sessionDataMap.containsKey( getCacheKey( id ) ); + //TODO find way to do query without pulling in whole session data + SessionData sd = load(id); + if (sd == null) + return false; + + if (sd.getExpiry() <= 0) + return true; //never expires + else + return (Boolean.valueOf(sd.getExpiry() > System.currentTimeMillis())); //not expired yet } public String getCacheKey( String id ) diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index 6c174f5e67d..e371ebe3e98 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -33,6 +33,18 @@ jetty-test-helper test + + org.openjdk.jmh + jmh-core + ${jmh.version} + test + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + test + @@ -69,7 +81,49 @@ org.eclipse.jetty.http.* - + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + ${jmhjar.name} + true + + + org.openjdk.jmh:jmh-core + + + + + org.openjdk.jmh.Main + + + + + org.openjdk.jmh:jmh-core + + ** + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java index 2079ed1d3fc..4be2f977bb5 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java @@ -58,6 +58,7 @@ public class MimeTypes FORM_ENCODED("application/x-www-form-urlencoded"), MESSAGE_HTTP("message/http"), MULTIPART_BYTERANGES("multipart/byteranges"), + MULTIPART_FORM_DATA("multipart/form-data"), TEXT_HTML("text/html"), TEXT_PLAIN("text/plain"), diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java index ecde9c8e12e..c2d1d14fe29 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormInputStream.java @@ -201,7 +201,7 @@ public class MultiPartFormInputStream { if (name == null) return null; - return _headers.getValue(name.toLowerCase(Locale.ENGLISH),0); + return _headers.getValue(StringUtil.asciiToLowerCase(name),0); } /** @@ -628,7 +628,7 @@ public class MultiPartFormInputStream public void parsedField(String key, String value) { // Add to headers and mark if one of these fields. // - headers.put(key.toLowerCase(Locale.ENGLISH),value); + headers.put(StringUtil.asciiToLowerCase(key),value); if (key.equalsIgnoreCase("content-disposition")) contentDisposition = value; else if (key.equalsIgnoreCase("content-type")) @@ -642,8 +642,13 @@ public class MultiPartFormInputStream @Override public boolean headerComplete() { - try + if(LOG.isDebugEnabled()) { + LOG.debug("headerComplete {}",this); + } + + try + { // Extract content-disposition boolean form_data = false; if (contentDisposition == null) @@ -657,8 +662,8 @@ public class MultiPartFormInputStream while (tok.hasMoreTokens()) { String t = tok.nextToken().trim(); - String tl = t.toLowerCase(Locale.ENGLISH); - if (t.startsWith("form-data")) + String tl = StringUtil.asciiToLowerCase(t); + if (tl.startsWith("form-data")) form_data = true; else if (tl.startsWith("name=")) name = value(t); @@ -708,7 +713,10 @@ public class MultiPartFormInputStream @Override public boolean content(ByteBuffer buffer, boolean last) - { + { + if(_part == null) + return false; + if (BufferUtil.hasContent(buffer)) { try @@ -733,12 +741,24 @@ public class MultiPartFormInputStream _err = e; return true; } - reset(); } return false; } + @Override + public void startPart() + { + reset(); + } + + @Override + public void earlyEOF() + { + if (LOG.isDebugEnabled()) + LOG.debug("Early EOF {}",MultiPartFormInputStream.this); + } + public void reset() { _part = null; @@ -746,14 +766,12 @@ public class MultiPartFormInputStream contentType = null; headers = new MultiMap<>(); } - + @Override - public void earlyEOF() - { - if (LOG.isDebugEnabled()) - LOG.debug("Early EOF {}",MultiPartFormInputStream.this); + public String toString() { + return("contentDisposition: "+contentDisposition+" contentType:"+contentType); } - + } public void setDeleteOnExit(boolean deleteOnExit) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java index 26a97e86682..63aec8605e9 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartParser.java @@ -304,10 +304,17 @@ public class MultiPartParser if (_state == State.EPILOGUE) { _state = State.END; + + if(LOG.isDebugEnabled()) + LOG.debug("messageComplete {}", this); + return _handler.messageComplete(); } else { + if(LOG.isDebugEnabled()) + LOG.debug("earlyEOF {}", this); + _handler.earlyEOF(); return true; } @@ -366,6 +373,10 @@ public class MultiPartParser if (b == '\n') { setState(State.BODY_PART); + + if(LOG.isDebugEnabled()) + LOG.debug("startPart {}",this); + _handler.startPart(); return; } @@ -449,6 +460,10 @@ public class MultiPartParser handleField(); setState(State.FIRST_OCTETS); _partialBoundary = 2; // CRLF is option for empty parts + + if(LOG.isDebugEnabled()) + LOG.debug("headerComplete {}", this); + if (_handler.headerComplete()) return true; break; @@ -482,6 +497,16 @@ public class MultiPartParser setState(FieldState.AFTER_NAME); break; + case LINE_FEED: + { + if(LOG.isDebugEnabled()) + LOG.debug("Line Feed in Name {}", this); + + handleField(); + setState(FieldState.FIELD); + break; + } + default: _string.append(b); _length = _string.length(); @@ -572,6 +597,9 @@ public class MultiPartParser /* ------------------------------------------------------------------------------- */ private void handleField() { + if(LOG.isDebugEnabled()) + LOG.debug("parsedField: _fieldName={} _fieldValue={} {}", _fieldName, _fieldValue, this); + if (_fieldName != null && _fieldValue != null) _handler.parsedField(_fieldName,_fieldValue); _fieldName = _fieldValue = null; @@ -593,6 +621,10 @@ public class MultiPartParser buffer.position(buffer.position() + _delimiterSearch.getLength() - _partialBoundary); setState(State.DELIMITER); _partialBoundary = 0; + + if(LOG.isDebugEnabled()) + LOG.debug("Content={}, Last={} {}",BufferUtil.toDetailString(BufferUtil.EMPTY_BUFFER),true,this); + return _handler.content(BufferUtil.EMPTY_BUFFER,true); } @@ -612,6 +644,9 @@ public class MultiPartParser content.limit(_partialBoundary); _partialBoundary = 0; + if(LOG.isDebugEnabled()) + LOG.debug("Content={}, Last={} {}",BufferUtil.toDetailString(content),false,this); + if (_handler.content(content,false)) return true; } @@ -627,6 +662,9 @@ public class MultiPartParser buffer.position(delimiter - buffer.arrayOffset() + _delimiterSearch.getLength()); setState(State.DELIMITER); + if(LOG.isDebugEnabled()) + LOG.debug("Content={}, Last={} {}",BufferUtil.toDetailString(content),true,this); + return _handler.content(content,true); } @@ -637,12 +675,19 @@ public class MultiPartParser ByteBuffer content = buffer.slice(); content.limit(content.limit() - _partialBoundary); + if(LOG.isDebugEnabled()) + LOG.debug("Content={}, Last={} {}",BufferUtil.toDetailString(content),false,this); + BufferUtil.clear(buffer); return _handler.content(content,false); } // There is normal content with no delimiter ByteBuffer content = buffer.slice(); + + if(LOG.isDebugEnabled()) + LOG.debug("Content={}, Last={} {}",BufferUtil.toDetailString(content),false,this); + BufferUtil.clear(buffer); return _handler.content(content,false); } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java index 444b5c8b53f..347614f4573 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartCaptureTest.java @@ -73,18 +73,18 @@ public class MultiPartCaptureTest ret.add(new String[]{"multipart-text-files"}); // ret.add(new String[]{"multipart-base64"}); // base64 transfer encoding deprecated // ret.add(new String[]{"multipart-base64-long"}); // base64 transfer encoding deprecated - ret.add(new String[]{"multipart-complex"}); + // ret.add(new String[]{"multipart-complex"}); // TODO joakime bad capture includes ? in sjis content ret.add(new String[]{"multipart-duplicate-names-1"}); ret.add(new String[]{"multipart-encoding-mess"}); - ret.add(new String[]{"multipart-inside-itself"}); - ret.add(new String[]{"multipart-inside-itself-binary"}); + // ret.add(new String[]{"multipart-inside-itself"}); // impossible test, badly chosen boundary + // ret.add(new String[]{"multipart-inside-itself-binary"}); // impossible test, badly chosen boundary ret.add(new String[]{"multipart-number-browser"}); ret.add(new String[]{"multipart-number-strict"}); - ret.add(new String[]{"multipart-sjis"}); + // ret.add(new String[]{"multipart-sjis"}); // TODO joakime bad capture includes ? in sjis content ret.add(new String[]{"multipart-strange-quoting"}); ret.add(new String[]{"multipart-unicode-names"}); ret.add(new String[]{"multipart-uppercase"}); - ret.add(new String[]{"multipart-x-www-form-urlencoded"}); + // ret.add(new String[]{"multipart-x-www-form-urlencoded"}); // not our job to decode content ret.add(new String[]{"multipart-zencoding"}); // Capture of raw request body contents from various browsers @@ -100,24 +100,24 @@ public class MultiPartCaptureTest ret.add(new String[]{"browser-capture-form1-osx-safari"}); // form submitted as shift-jis - ret.add(new String[]{"browser-capture-sjis-form-android-chrome"}); - ret.add(new String[]{"browser-capture-sjis-form-android-firefox"}); - ret.add(new String[]{"browser-capture-sjis-form-chrome"}); - ret.add(new String[]{"browser-capture-sjis-form-edge"}); - ret.add(new String[]{"browser-capture-sjis-form-firefox"}); - ret.add(new String[]{"browser-capture-sjis-form-ios-safari"}); + // ret.add(new String[]{"browser-capture-sjis-form-android-chrome"}); // contains html encoded character and unspecified charset defaults to utf-8 + // ret.add(new String[]{"browser-capture-sjis-form-android-firefox"}); // contains html encoded character and unspecified charset defaults to utf-8 + // ret.add(new String[]{"browser-capture-sjis-form-chrome"}); // contains html encoded character and unspecified charset defaults to utf-8 + ret.add(new String[]{"browser-capture-sjis-form-edge"}); + // ret.add(new String[]{"browser-capture-sjis-form-firefox"}); // contains html encoded character and unspecified charset defaults to utf-8 + // ret.add(new String[]{"browser-capture-sjis-form-ios-safari"}); // contains html encoded character and unspecified charset defaults to utf-8 ret.add(new String[]{"browser-capture-sjis-form-msie"}); - ret.add(new String[]{"browser-capture-sjis-form-safari"}); + // ret.add(new String[]{"browser-capture-sjis-form-safari"}); // contains html encoded character and unspecified charset defaults to utf-8 // form submitted as shift-jis (with HTML5 specific hidden _charset_ field) - ret.add(new String[]{"browser-capture-sjis-charset-form-android-chrome"}); - ret.add(new String[]{"browser-capture-sjis-charset-form-android-firefox"}); - ret.add(new String[]{"browser-capture-sjis-charset-form-chrome"}); + ret.add(new String[]{"browser-capture-sjis-charset-form-android-chrome"}); // contains html encoded character + ret.add(new String[]{"browser-capture-sjis-charset-form-android-firefox"}); // contains html encoded character + ret.add(new String[]{"browser-capture-sjis-charset-form-chrome"}); // contains html encoded character ret.add(new String[]{"browser-capture-sjis-charset-form-edge"}); - ret.add(new String[]{"browser-capture-sjis-charset-form-firefox"}); - ret.add(new String[]{"browser-capture-sjis-charset-form-ios-safari"}); + ret.add(new String[]{"browser-capture-sjis-charset-form-firefox"}); // contains html encoded character + ret.add(new String[]{"browser-capture-sjis-charset-form-ios-safari"}); // contains html encoded character ret.add(new String[]{"browser-capture-sjis-charset-form-msie"}); - ret.add(new String[]{"browser-capture-sjis-charset-form-safari"}); + ret.add(new String[]{"browser-capture-sjis-charset-form-safari"}); // contains html encoded character // form submitted with simple file upload ret.add(new String[]{"browser-capture-form-fileupload-android-chrome"}); @@ -133,7 +133,7 @@ public class MultiPartCaptureTest ret.add(new String[]{"browser-capture-form-fileupload-alt-chrome"}); ret.add(new String[]{"browser-capture-form-fileupload-alt-edge"}); ret.add(new String[]{"browser-capture-form-fileupload-alt-firefox"}); - ret.add(new String[]{"browser-capture-form-fileupload-alt-ios-safari"}); + // ret.add(new String[]{"browser-capture-form-fileupload-alt-ios-safari"}); // is Sha1sum correct new parser gives same result as old parser ret.add(new String[]{"browser-capture-form-fileupload-alt-msie"}); ret.add(new String[]{"browser-capture-form-fileupload-alt-safari"}); @@ -207,6 +207,14 @@ public class MultiPartCaptureTest assertThat("Mulitpart.parts.size", parts.size(), is(multipartExpectations.partCount)); } + String defaultCharset = UTF_8.toString(); + Part charSetPart = getPart.apply("_charset_"); + if(charSetPart != null) + { + defaultCharset = IO.toString(charSetPart.getInputStream()); + } + + // Evaluate expected Contents for (NameValue expected : multipartExpectations.partContainsContents) { @@ -214,7 +222,7 @@ public class MultiPartCaptureTest assertThat("Part[" + expected.name + "]", part, is(notNullValue())); try (InputStream partInputStream = part.getInputStream()) { - String charset = getCharsetFromContentType(part.getContentType(), UTF_8); + String charset = getCharsetFromContentType(part.getContentType(), defaultCharset); String contents = IO.toString(partInputStream, charset); assertThat("Part[" + expected.name + "].contents", contents, containsString(expected.value)); } @@ -250,11 +258,11 @@ public class MultiPartCaptureTest return new MultipartConfigElement(path.toString(), MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD); } - private String getCharsetFromContentType(String contentType, Charset defaultCharset) + private String getCharsetFromContentType(String contentType, String defaultCharset) { if(StringUtil.isBlank(contentType)) { - return defaultCharset.toString(); + return defaultCharset; } QuotedStringTokenizer tok = new QuotedStringTokenizer(contentType, ";", false, false); @@ -267,7 +275,7 @@ public class MultiPartCaptureTest } } - return defaultCharset.toString(); + return defaultCharset; } public static class NameValue diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java index c7b558108cb..f48b4d4a309 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormInputStreamTest.java @@ -1062,8 +1062,41 @@ public class MultiPartFormInputStreamTest } + @Test + public void testGeneratedForm() + throws Exception + { + String contentType = "multipart/form-data, boundary=WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW"; + String body = "Content-Type: multipart/form-data; boundary=WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" + + "\r\n" + + "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" + + "Content-Disposition: form-data; name=\"part1\"\r\n" + + "\n" + + "wNfミxVam﾿t\r\n" + + "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\n" + + "Content-Disposition: form-data; name=\"part2\"\r\n" + + "\r\n" + + "&ᄈᄎ￙ᅱᅢO\r\n" + + "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW--"; + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartFormInputStream mpis = new MultiPartFormInputStream(new ByteArrayInputStream(body.getBytes()), + contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + + Collection parts = mpis.getParts(); + assertThat(parts, notNullValue()); + assertThat(parts.size(), is(2)); + + Part part1 = mpis.getPart("part1"); + assertThat(part1, notNullValue()); + Part part2 = mpis.getPart("part2"); + assertThat(part2, notNullValue()); + } + private String createMultipartRequestString(String filename) { diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java index 07b38af84b0..bc1c77b8fad 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartParserTest.java @@ -620,6 +620,52 @@ public class MultiPartParserTest } + @Test + public void testGeneratedForm() + { + TestHandler handler = new TestHandler() + { + @Override + public boolean messageComplete() + { + return true; + } + + @Override + public boolean content(ByteBuffer buffer, boolean last) + { + super.content(buffer,last); + return false; + } + + @Override + public boolean headerComplete() + { + return false; + } + }; + + MultiPartParser parser = new MultiPartParser(handler,"WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW"); + ByteBuffer data = BufferUtil.toBuffer("" + + "Content-Type: multipart/form-data; boundary=WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" + + "\r\n" + + "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n" + + "Content-Disposition: form-data; name=\"part1\"\r\n" + + "\n" + + "wNfミxVam﾿t\r\n" + + "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\n" + + "Content-Disposition: form-data; name=\"part2\"\r\n" + + "\r\n" + + "&ᄈᄎ￙ᅱᅢO\r\n" + + "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW--"); + + parser.parse(data,true); + assertThat(parser.getState(), is(State.END)); + assertThat(handler.fields.size(), is(2)); + + } + + static class TestHandler implements MultiPartParser.Handler { List fields = new ArrayList<>(); diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/jmh/MultiPartBenchmark.java b/jetty-http/src/test/java/org/eclipse/jetty/http/jmh/MultiPartBenchmark.java new file mode 100644 index 00000000000..49924222a0c --- /dev/null +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/jmh/MultiPartBenchmark.java @@ -0,0 +1,297 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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.http.jmh; + +import java.io.File; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import javax.servlet.MultipartConfigElement; +import javax.servlet.http.Part; + +import org.eclipse.jetty.http.MultiPartFormInputStream; +import org.eclipse.jetty.http.MultiPartCaptureTest.MultipartExpectations; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.TestingDir; +import org.eclipse.jetty.util.BufferUtil; +import org.junit.Rule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.profile.CompilerProfiler; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +@State(Scope.Benchmark) +public class MultiPartBenchmark +{ + + public static final int MAX_FILE_SIZE = Integer.MAX_VALUE; + public static final int MAX_REQUEST_SIZE = Integer.MAX_VALUE; + public static final int FILE_SIZE_THRESHOLD = 50; + + public int count = 0; + static String _contentType; + static File _file; + static int _numSections; + static int _numBytesPerSection; + + + public static List data = new ArrayList<>(); + static + { + // Capture of raw request body contents from various browsers + + // simple form - 2 fields + data.add("browser-capture-form1-android-chrome"); + data.add("browser-capture-form1-android-firefox"); + data.add("browser-capture-form1-chrome"); + data.add("browser-capture-form1-edge"); + data.add("browser-capture-form1-firefox"); + data.add("browser-capture-form1-ios-safari"); + data.add("browser-capture-form1-msie"); + data.add("browser-capture-form1-osx-safari"); + + // form submitted as shift-jis + data.add("browser-capture-sjis-form-edge"); + data.add("browser-capture-sjis-form-msie"); + + // form submitted as shift-jis (with HTML5 specific hidden _charset_ field) + data.add("browser-capture-sjis-charset-form-edge"); + data.add("browser-capture-sjis-charset-form-msie"); + + // form submitted with simple file upload + data.add("browser-capture-form-fileupload-android-chrome"); + data.add("browser-capture-form-fileupload-android-firefox"); + data.add("browser-capture-form-fileupload-chrome"); + data.add("browser-capture-form-fileupload-edge"); + data.add("browser-capture-form-fileupload-firefox"); + data.add("browser-capture-form-fileupload-ios-safari"); + data.add("browser-capture-form-fileupload-msie"); + data.add("browser-capture-form-fileupload-safari"); + + // form submitted with 2 files (1 binary, 1 text) and 2 text fields + data.add("browser-capture-form-fileupload-alt-chrome"); + data.add("browser-capture-form-fileupload-alt-edge"); + data.add("browser-capture-form-fileupload-alt-firefox"); + data.add("browser-capture-form-fileupload-alt-msie"); + data.add("browser-capture-form-fileupload-alt-safari"); + } + + + @Param({"UTIL","HTTP"}) + public static String parserType; + + @Setup(Level.Trial) + public static void setupTrial() throws Exception + { + _file = File.createTempFile("test01",null); + _file.deleteOnExit(); + + _numSections = 1; + _numBytesPerSection = 1024*1024*10; + + _contentType = "multipart/form-data, boundary=WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW"; + String initialBoundary = "--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n"; + String boundary = "\r\n--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW\r\n"; + String closingBoundary = "\r\n--WebKitFormBoundary7MA4YWf7OaKlSxkTrZu0gW--\r\n"; + String headerStart = "Content-Disposition: form-data; name=\""; + + + for(int i=0; i<_numSections; i++) { + //boundary and headers + if(i==0) + Files.write(_file.toPath(), initialBoundary.getBytes(), StandardOpenOption.APPEND); + else + Files.write(_file.toPath(), boundary.getBytes(), StandardOpenOption.APPEND); + + Files.write(_file.toPath(), headerStart.getBytes(), StandardOpenOption.APPEND); + Files.write(_file.toPath(), new String("part"+(i+1)).getBytes(), StandardOpenOption.APPEND); + Files.write(_file.toPath(), new String("\"\r\n\r\n").getBytes(), StandardOpenOption.APPEND); + + //append random data + byte[] data = new byte[_numBytesPerSection]; + new Random().nextBytes(data); + Files.write(_file.toPath(), data, StandardOpenOption.APPEND); + } + + //closing boundary + Files.write(_file.toPath(), closingBoundary.getBytes(), StandardOpenOption.APPEND); + + /* + // print out file to verify that it contains valid contents (just for testing) + InputStream in = Files.newInputStream(_file.toPath()); + System.out.println(); + while(in.available()>0) { + byte b[] = new byte[100]; + int read = in.read(b,0,100); + for(int i=0; i */ - private void prepare() + private void beforeSend() { switch (frame.getType()) { + case HEADERS: + { + HeadersFrame headersFrame = (HeadersFrame)frame; + stream.updateClose(headersFrame.isEndStream(), CloseState.Event.BEFORE_SEND); + break; + } case SETTINGS: { SettingsFrame settingsFrame = (SettingsFrame)frame; @@ -1213,7 +1222,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio { onStreamOpened(stream); HeadersFrame headersFrame = (HeadersFrame)frame; - if (stream.updateClose(headersFrame.isEndStream(), true)) + if (stream.updateClose(headersFrame.isEndStream(), CloseState.Event.AFTER_SEND)) removeStream(stream); break; } @@ -1230,7 +1239,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio { // Pushed streams are implicitly remotely closed. // They are closed when sending an end-stream DATA frame. - stream.updateClose(true, false); + stream.updateClose(true, CloseState.Event.RECEIVED); break; } case GO_AWAY: @@ -1317,15 +1326,17 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio int length = Math.min(dataBytes, window); // Only one DATA frame is generated. - bytes = frameBytes = generator.data(lease, (DataFrame)frame, length); + DataFrame dataFrame = (DataFrame)frame; + bytes = frameBytes = generator.data(lease, dataFrame, length); int written = bytes - Frame.HEADER_LENGTH; if (LOG.isDebugEnabled()) - LOG.debug("Generated {}, length/window/data={}/{}/{}", frame, written, window, dataBytes); + LOG.debug("Generated {}, length/window/data={}/{}/{}", dataFrame, written, window, dataBytes); this.dataWritten = written; this.dataBytes -= written; flowControl.onDataSending(stream, written); + stream.updateClose(dataFrame.isEndStream(), CloseState.Event.BEFORE_SEND); return true; } @@ -1342,7 +1353,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio { // Only now we can update the close state // and eventually remove the stream. - if (stream.updateClose(dataFrame.isEndStream(), true)) + if (stream.updateClose(dataFrame.isEndStream(), CloseState.Event.AFTER_SEND)) removeStream(stream); super.succeeded(); } diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java index 91e635d6b96..6320b9efab1 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Stream.java @@ -264,7 +264,7 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa private void onHeaders(HeadersFrame frame, Callback callback) { - if (updateClose(frame.isEndStream(), false)) + if (updateClose(frame.isEndStream(), CloseState.Event.RECEIVED)) session.removeStream(this); callback.succeeded(); } @@ -295,7 +295,7 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa return; } - if (updateClose(frame.isEndStream(), false)) + if (updateClose(frame.isEndStream(), CloseState.Event.RECEIVED)) session.removeStream(this); notifyData(this, frame, callback); } @@ -312,7 +312,7 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa { // Pushed streams are implicitly locally closed. // They are closed when receiving an end-stream DATA frame. - updateClose(true, true); + updateClose(true, CloseState.Event.AFTER_SEND); callback.succeeded(); } @@ -322,14 +322,29 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa } @Override - public boolean updateClose(boolean update, boolean local) + public boolean updateClose(boolean update, CloseState.Event event) { if (LOG.isDebugEnabled()) - LOG.debug("Update close for {} close={} local={}", this, update, local); + LOG.debug("Update close for {} update={} event={}", this, update, event); if (!update) return false; + switch (event) + { + case RECEIVED: + return updateCloseAfterReceived(); + case BEFORE_SEND: + return updateCloseBeforeSend(); + case AFTER_SEND: + return updateCloseAfterSend(); + default: + return false; + } + } + + private boolean updateCloseAfterReceived() + { while (true) { CloseState current = closeState.get(); @@ -337,22 +352,79 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa { case NOT_CLOSED: { - CloseState newValue = local ? CloseState.LOCALLY_CLOSED : CloseState.REMOTELY_CLOSED; - if (closeState.compareAndSet(current, newValue)) + if (closeState.compareAndSet(current, CloseState.REMOTELY_CLOSED)) return false; break; } + case LOCALLY_CLOSING: + { + if (closeState.compareAndSet(current, CloseState.CLOSING)) + { + updateStreamCount(0, 1); + return false; + } + break; + } case LOCALLY_CLOSED: { - if (local) - return false; close(); return true; } + default: + { + return false; + } + } + } + } + + private boolean updateCloseBeforeSend() + { + while (true) + { + CloseState current = closeState.get(); + switch (current) + { + case NOT_CLOSED: + { + if (closeState.compareAndSet(current, CloseState.LOCALLY_CLOSING)) + return false; + break; + } case REMOTELY_CLOSED: { - if (!local) + if (closeState.compareAndSet(current, CloseState.CLOSING)) + { + updateStreamCount(0, 1); return false; + } + break; + } + default: + { + return false; + } + } + } + } + + private boolean updateCloseAfterSend() + { + while (true) + { + CloseState current = closeState.get(); + switch (current) + { + case NOT_CLOSED: + case LOCALLY_CLOSING: + { + if (closeState.compareAndSet(current, CloseState.LOCALLY_CLOSED)) + return false; + break; + } + case REMOTELY_CLOSED: + case CLOSING: + { close(); return true; } @@ -389,8 +461,18 @@ public class HTTP2Stream extends IdleTimeout implements IStream, Callback, Dumpa @Override public void close() { - if (closeState.getAndSet(CloseState.CLOSED) != CloseState.CLOSED) + CloseState oldState = closeState.getAndSet(CloseState.CLOSED); + if (oldState != CloseState.CLOSED) + { + int deltaClosing = oldState == CloseState.CLOSING ? -1 : 0; + updateStreamCount(-1, deltaClosing); onClose(); + } + } + + private void updateStreamCount(int deltaStream, int deltaClosing) + { + ((HTTP2Session)session).updateStreamCount(isLocal(), deltaStream, deltaClosing); } @Override diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java index 3fe92bbaf23..95dc4f4fb87 100644 --- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java +++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/IStream.java @@ -76,12 +76,10 @@ public interface IStream extends Stream, Closeable *

Updates the close state of this stream.

* * @param update whether to update the close state - * @param local whether the update comes from a local operation - * (such as sending a frame that ends the stream) - * or a remote operation (such as receiving a frame + * @param event the event that caused the close state update * @return whether the stream has been fully closed by this invocation */ - public boolean updateClose(boolean update, boolean local); + public boolean updateClose(boolean update, CloseState.Event event); /** *

Forcibly closes this stream.

diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ModifyMaxInactiveIntervalTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/EmptyServerHandler.java similarity index 50% rename from tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ModifyMaxInactiveIntervalTest.java rename to jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/EmptyServerHandler.java index ec0f6e57027..cd146e572d6 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ModifyMaxInactiveIntervalTest.java +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/EmptyServerHandler.java @@ -16,35 +16,27 @@ // ======================================================================== // +package org.eclipse.jetty.http2.client.http; -package org.eclipse.jetty.gcloud.session; +import java.io.IOException; -import org.eclipse.jetty.server.session.AbstractModifyMaxInactiveIntervalTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; -/** - * ModifyMaxInactiveIntervalTest - * - * - */ -public class ModifyMaxInactiveIntervalTest extends AbstractModifyMaxInactiveIntervalTest +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; + +public class EmptyServerHandler extends AbstractHandler.ErrorDispatchHandler { - - @After - public void teardown () throws Exception - { - GCloudTestSuite.__testSupport.deleteSessions(); - } - - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ @Override - public SessionDataStoreFactory createSessionDataStoreFactory() + protected final void doNonErrorHandle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + { + jettyRequest.setHandled(true); + service(target, jettyRequest, request, response); + } + + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore()); } } diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java index a327c99207e..f3ce3a830ba 100644 --- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java @@ -18,11 +18,10 @@ package org.eclipse.jetty.http2.client.http; -import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; -import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -32,7 +31,6 @@ import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; import org.junit.Assert; import org.junit.Test; @@ -53,12 +51,11 @@ public class MaxConcurrentStreamsTest extends AbstractTest public void testOneConcurrentStream() throws Exception { long sleep = 1000; - start(1, new AbstractHandler() + start(1, new EmptyServerHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) { - baseRequest.setHandled(true); // Sleep a bit to allow the second request to be queued. sleep(sleep); } @@ -91,17 +88,42 @@ public class MaxConcurrentStreamsTest extends AbstractTest Assert.assertTrue(latch.await(5 * sleep, TimeUnit.MILLISECONDS)); } + @Test + public void testManyIterationsWithConcurrentStreams() throws Exception + { + int concurrency = 1; + start(concurrency, new EmptyServerHandler()); + + int iterations = 50; + IntStream.range(0, concurrency).parallel().forEach(i -> + IntStream.range(0, iterations).forEach(j -> + { + try + { + ContentResponse response = client.newRequest("localhost", connector.getLocalPort()) + .path("/" + i + "_" + j) + .timeout(5, TimeUnit.SECONDS) + .send(); + Assert.assertEquals(HttpStatus.OK_200, response.getStatus()); + } + catch (Throwable x) + { + throw new RuntimeException(x); + } + }) + ); + } + @Test public void testTwoConcurrentStreamsThirdWaits() throws Exception { int maxStreams = 2; long sleep = 1000; - start(maxStreams, new AbstractHandler() + start(maxStreams, new EmptyServerHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) { - baseRequest.setHandled(true); sleep(sleep); } }); @@ -140,12 +162,11 @@ public class MaxConcurrentStreamsTest extends AbstractTest public void testAbortedWhileQueued() throws Exception { long sleep = 1000; - start(1, new AbstractHandler() + start(1, new EmptyServerHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) { - baseRequest.setHandled(true); sleep(sleep); } }); @@ -170,12 +191,11 @@ public class MaxConcurrentStreamsTest extends AbstractTest { int maxConcurrent = 10; long sleep = 500; - start(maxConcurrent, new AbstractHandler() + start(maxConcurrent, new EmptyServerHandler() { @Override - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException + protected void service(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response) { - baseRequest.setHandled(true); sleep(sleep); } }); diff --git a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java index d862891c8f8..ff5043193ae 100644 --- a/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java +++ b/jetty-http2/http2-server/src/main/java/org/eclipse/jetty/http2/server/HttpTransportOverHTTP2.java @@ -303,9 +303,10 @@ public class HttpTransportOverHTTP2 implements HttpTransport commit = this.commit; if (state == State.WRITING) { + this.state = State.IDLE; callback = this.callback; this.callback = null; - this.state = State.IDLE; + this.commit = false; } } if (LOG.isDebugEnabled()) @@ -330,13 +331,13 @@ public class HttpTransportOverHTTP2 implements HttpTransport if (state == State.WRITING) { this.state = State.FAILED; - this.failure = failure; callback = this.callback; this.callback = null; + this.failure = failure; } } if (LOG.isDebugEnabled()) - LOG.debug(String.format("HTTP2 Response #%d/%h failed to %s", stream.getId(), stream.getSession(), commit ? "commit" : "flush"), failure); + LOG.debug(String.format("HTTP2 Response #%d/%h %s %s", stream.getId(), stream.getSession(), commit ? "commit" : "flush", callback == null ? "ignored" : "failed"), failure); if (callback != null) callback.failed(failure); } diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java index a752e781c22..a06aad04cea 100644 --- a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java +++ b/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java @@ -24,9 +24,9 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; -import org.eclipse.jetty.server.SessionIdManager; import org.eclipse.jetty.server.session.AbstractSessionDataStore; import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.server.session.UnreadableSessionDataException; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.log.Log; @@ -84,8 +84,8 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore @Override public SessionData load(String id) throws Exception { - final AtomicReference reference = new AtomicReference(); - final AtomicReference exception = new AtomicReference(); + final AtomicReference reference = new AtomicReference<>(); + final AtomicReference exception = new AtomicReference<>(); Runnable load = new Runnable() { @@ -103,7 +103,7 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore } catch (Exception e) { - exception.set(e); + exception.set(new UnreadableSessionDataException(id, _context, e)); } } }; @@ -139,11 +139,10 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore long now = System.currentTimeMillis(); - Set expired = new HashSet(); + Set expired = new HashSet<>(); //TODO if there is NOT an idle timeout set on entries in infinispan, need to check other sessions - //that are not currently in the SessionDataStore (eg they've been passivated) - + //that are not currently in the SessionDataStore (eg they've been passivated) for (String candidate:candidates) { if (LOG.isDebugEnabled()) @@ -205,8 +204,6 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore @Override public void doStore(String id, SessionData data, long lastSaveTime) throws Exception { - try - { //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. @@ -218,10 +215,6 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore if (LOG.isDebugEnabled()) LOG.debug("Session {} saved to infinispan, expires {} ", id, data.getExpiry()); - } catch (Exception e) - { - e.printStackTrace(); - } } @@ -265,8 +258,8 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore { // TODO find a better way to do this that does not pull into memory the // whole session object - final AtomicReference reference = new AtomicReference(); - final AtomicReference exception = new AtomicReference(); + final AtomicReference reference = new AtomicReference<>(); + final AtomicReference exception = new AtomicReference<>(); Runnable load = new Runnable() { diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java index eb18828a44e..b1aec0a48bf 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java @@ -154,8 +154,13 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable _selecting = false; } } + if (selector != null) + { + if (LOG.isDebugEnabled()) + LOG.debug("wakeup on submit {}", this); selector.wakeup(); + } } private void execute(Runnable task) @@ -258,6 +263,8 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable _updates.addFirst(dump); _selecting = false; } + if (LOG.isDebugEnabled()) + LOG.debug("wakeup on dump {}", this); selector.wakeup(); keys = dump.get(5, TimeUnit.SECONDS); String keysAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now()); @@ -370,7 +377,11 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable LOG.debug("updates {}",updates); if (selector != null) + { + if (LOG.isDebugEnabled()) + LOG.debug("wakeup on updates {}", this); selector.wakeup(); + } } private boolean select() @@ -381,12 +392,16 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable if (selector != null && selector.isOpen()) { if (LOG.isDebugEnabled()) - LOG.debug("Selector {} waiting on select", selector); + LOG.debug("Selector {} waiting with {} keys", selector, selector.keys().size()); int selected = selector.select(); if (selected == 0) + { + if (LOG.isDebugEnabled()) + LOG.debug("Selector {} woken with none selected", selector); selected = selector.selectNow(); + } if (LOG.isDebugEnabled()) - LOG.debug("Selector {} woken up from select, {}/{} selected", selector, selected, selector.keys().size()); + LOG.debug("Selector {} woken up from select, {}/{}/{} selected", selector, selected, selector.selectedKeys().size(), selector.keys().size()); int updates; synchronized(ManagedSelector.this) diff --git a/jetty-jspc-maven-plugin/pom.xml b/jetty-jspc-maven-plugin/pom.xml index 9bb1d1ba3a4..e8121302752 100644 --- a/jetty-jspc-maven-plugin/pom.xml +++ b/jetty-jspc-maven-plugin/pom.xml @@ -78,35 +78,6 @@ ant 1.8.4 - - org.eclipse.jetty - apache-jstl - ${project.version} - - - org.eclipse.jetty - jetty-servlets - ${project.version} - test - - - org.eclipse.jetty - jetty-client - ${project.version} - test - - - org.eclipse.jetty - jetty-proxy - ${project.version} - test - - - org.eclipse.jetty.http2 - http2-client - ${project.version} - test - diff --git a/jetty-maven-plugin/pom.xml b/jetty-maven-plugin/pom.xml index a650e9841a3..7e06a8e5de5 100644 --- a/jetty-maven-plugin/pom.xml +++ b/jetty-maven-plugin/pom.xml @@ -148,24 +148,6 @@ javax.transaction-api compile - - org.eclipse.jetty - jetty-client - ${project.version} - test - - - org.eclipse.jetty.http2 - http2-client - ${project.version} - test - - - org.eclipse.jetty.http2 - http2-http-client-transport - ${project.version} - test - org.eclipse.jetty jetty-home diff --git a/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/invoker.properties b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/invoker.properties new file mode 100644 index 00000000000..b8a016f5093 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/invoker.properties @@ -0,0 +1,2 @@ +invoker.goals = verify -V +#test-compile failsafe:integration-test \ No newline at end of file diff --git a/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-base/pom.xml b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-base/pom.xml new file mode 100644 index 00000000000..d959259ea9a --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-base/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + + org.eclipse.jetty.its.jetty-run-package-jar-mojo-it + jetty-simple-project + 0.0.1-SNAPSHOT + + + jetty-simple-base + jar + + Jetty :: Simple :: Base + + + + + javax.servlet + javax.servlet-api + jar + provided + + + + org.slf4j + slf4j-api + + + + commons-io + commons-io + + + + org.eclipse.jetty.toolchain + jetty-perf-helper + 1.0.5 + + + + com.fasterxml.jackson.core + jackson-databind + 2.8.1 + + + + + diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredLastAccessTimeTest.java b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/HelloServlet.java similarity index 54% rename from tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredLastAccessTimeTest.java rename to jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/HelloServlet.java index e2104ff191d..812cf60aa2e 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredLastAccessTimeTest.java +++ b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/HelloServlet.java @@ -16,35 +16,30 @@ // ======================================================================== // -package org.eclipse.jetty.server.session; -import org.junit.After; -import org.junit.Test; +package org.eclipse.jetty.its.jetty_run_mojo_it; + +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; /** - * ClusteredLastAccessTimeTest + * */ -public class ClusteredLastAccessTimeTest extends AbstractClusteredLastAccessTimeTest +@WebServlet("/hello") +public class HelloServlet + extends HttpServlet { - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ + @Override - public SessionDataStoreFactory createSessionDataStoreFactory() + protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + throws ServletException, IOException { - return JdbcTestHelper.newSessionDataStoreFactory(); + String who = req.getParameter( "name" ); + + resp.getWriter().write( "hello " + (who == null ? "unknown" : who) ); } - @Test - @Override - public void testLastAccessTime() throws Exception - { - super.testLastAccessTime(); - } - - @After - public void tearDown() throws Exception - { - JdbcTestHelper.shutdown(null); - } - } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateCreateScavengeTest.java b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/PingServlet.java similarity index 54% rename from tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateCreateScavengeTest.java rename to jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/PingServlet.java index 7fd213020b3..dc1d723151f 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateCreateScavengeTest.java +++ b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-base/src/main/java/org/eclipse/jetty/its/jetty_run_mojo_it/PingServlet.java @@ -17,36 +17,25 @@ // -package org.eclipse.jetty.server.session; +package org.eclipse.jetty.its.jetty_run_mojo_it; -import org.junit.After; -import org.junit.Test; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; -public class SessionInvalidateCreateScavengeTest extends AbstractSessionInvalidateCreateScavengeTest +public class PingServlet + extends HttpServlet { - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ @Override - public SessionDataStoreFactory createSessionDataStoreFactory() + protected void doGet( HttpServletRequest req, HttpServletResponse resp ) + throws ServletException, IOException { - return JdbcTestHelper.newSessionDataStoreFactory(); - } - + String who = req.getParameter( "name" ); - @Test - @Override - public void testSessionScavenge() throws Exception - { - super.testSessionScavenge(); + resp.getWriter().write( "pong " + (who == null ? "unknown" : who) ); } - - - @After - public void tearDown() throws Exception - { - JdbcTestHelper.shutdown(null); - } - } diff --git a/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-base/src/main/resources/META-INF/web-fragment.xml b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-base/src/main/resources/META-INF/web-fragment.xml new file mode 100644 index 00000000000..a1ec4e27ce4 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-base/src/main/resources/META-INF/web-fragment.xml @@ -0,0 +1,32 @@ + + + + + FragmentA + + + + + + + Ping + org.eclipse.jetty.its.jetty_run_mojo_it.PingServlet + + extra1123 + + + extra2345 + + + + + Ping + /ping + + + + \ No newline at end of file diff --git a/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-webapp/pom.xml b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-webapp/pom.xml new file mode 100644 index 00000000000..01c526f11a7 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-webapp/pom.xml @@ -0,0 +1,122 @@ + + + 4.0.0 + + + org.eclipse.jetty.its.jetty-run-package-jar-mojo-it + jetty-simple-project + 0.0.1-SNAPSHOT + + + jetty-simple-webapp + jar + + Jetty :: Simple :: Webapp as a Jar + + + + ${project.build.directory}/jetty-run-war-port.txt + + + + + + + org.eclipse.jetty.its.jetty-run-package-jar-mojo-it + jetty-simple-base + + + + org.eclipse.jetty + jetty-servlet + provided + + + + org.eclipse.jetty + jetty-client + @project.version@ + test + + + + junit + junit + 4.12 + test + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + @surefireVersion@ + + true + + ${jetty.port.file} + + + + + org.apache.maven.plugins + maven-failsafe-plugin + @surefireVersion@ + + + ${jetty.port.file} + + + **/*TestHelloServlet* + + + + + integration-test + + integration-test + + + + verify + + verify + + + + + + org.eclipse.jetty + jetty-maven-plugin + + + start-jetty + test-compile + + run-war + + + + jar + + true + + + jetty.port.file + ${jetty.port.file} + + + ${basedir}/src/config/jetty.xml + + + + + + + + + diff --git a/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-webapp/src/config/jetty.xml b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-webapp/src/config/jetty.xml new file mode 100644 index 00000000000..c38bcced0e1 --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-webapp/src/config/jetty.xml @@ -0,0 +1,40 @@ + + + + + + https + + 32768 + 8192 + 8192 + 512 + + + + + + + + + + + + + + + + + + + + + + + + 0 + 30000 + + + + diff --git a/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..2a5ac4b71bf --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-webapp/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + Jetty Simple Webapp run-mojo-it + diff --git a/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-webapp/src/test/java/org/eclipse/jetty/its/jetty_run_war_mojo_it/TestGetContent.java b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-webapp/src/test/java/org/eclipse/jetty/its/jetty_run_war_mojo_it/TestGetContent.java new file mode 100644 index 00000000000..a0da6ee489c --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/jetty-simple-webapp/src/test/java/org/eclipse/jetty/its/jetty_run_war_mojo_it/TestGetContent.java @@ -0,0 +1,94 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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.its.jetty_run_forked_mojo_it; + +import java.io.File; +import java.io.FileReader; +import java.io.LineNumberReader; + +import org.eclipse.jetty.client.HttpClient; +import org.junit.Assert; +import org.junit.Test; + +/** + * + */ +public class TestGetContent + +{ + @Test + public void get_ping_response() + throws Exception + { + + int port = getPort(); + Assert.assertTrue(port > 0); + HttpClient httpClient = new HttpClient(); + try + { + httpClient.start(); + + String response = httpClient.GET( "http://localhost:" + port + "/hello?name=beer" ).getContentAsString(); + + Assert.assertEquals( "hello beer", response.trim() ); + + response = httpClient.GET( "http://localhost:" + port + "/ping?name=beer" ).getContentAsString(); + + Assert.assertEquals( "pong beer", response.trim() ); + } + finally + { + httpClient.stop(); + } + } + + + public int getPort() + throws Exception + { + int attempts = 20; + int port = -1; + String s = System.getProperty("jetty.port.file"); + Assert.assertNotNull(s); + File f = new File(s); + while (true) + { + if (f.exists()) + { + try (FileReader r = new FileReader(f); + LineNumberReader lnr = new LineNumberReader(r); + ) + { + s = lnr.readLine(); + Assert.assertNotNull(s); + port = Integer.parseInt(s.trim()); + } + break; + } + else + { + if (--attempts < 0) + break; + else + Thread.currentThread().sleep(100); + } + } + return port; + } +} diff --git a/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/pom.xml b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/pom.xml new file mode 100644 index 00000000000..4aa1e74b9aa --- /dev/null +++ b/jetty-maven-plugin/src/it/jetty-run-package-jar-mojo-it/pom.xml @@ -0,0 +1,85 @@ + + + 4.0.0 + + org.eclipse.jetty.its.jetty-run-package-jar-mojo-it + jetty-simple-project + 0.0.1-SNAPSHOT + pom + + Jetty :: Simple + + + UTF-8 + UTF-8 + 1.8 + 3.0.0 + @project.version@ + + + + jetty-simple-base + jetty-simple-webapp + + + + + + + org.eclipse.jetty.its.jetty-run-package-jar-mojo-it + jetty-simple-base + ${project.version} + + + + javax.servlet + javax.servlet-api + 3.1.0 + jar + provided + + + + org.slf4j + slf4j-api + 1.7.21 + + + + commons-io + commons-io + 2.5 + + + + org.eclipse.jetty + jetty-servlet + ${jetty.version} + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + org.eclipse.jetty + jetty-maven-plugin + ${jetty.version} + + + + + + diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java index ee525ebbe42..0e63f0493d0 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/AbstractJettyMojo.java @@ -28,6 +28,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.List; @@ -288,19 +289,32 @@ public abstract class AbstractJettyMojo extends AbstractMojo * @parameter default-value="false" */ protected boolean nonBlocking = false; + + /** + * Per default this goal support only war packaging. + * If your project use an other type please configure it here. + * + * @parameter + */ + protected List supportedPackagings = Collections.singletonList( "war"); public abstract void restartWebApp(boolean reconfigureScanner) throws Exception; public abstract void checkPomConfiguration() throws MojoExecutionException; - - public abstract void checkPackagingConfiguration() throws MojoExecutionException; - - public abstract void configureScanner () throws MojoExecutionException; - - + public abstract void configureScanner () throws MojoExecutionException; + + + public void checkPackagingConfiguration() throws MojoExecutionException + { + if (!supportedPackagings.contains( project.getPackaging() )) + { + getLog().info( "Your project packaging is not supported by this plugin" ); + return; + } + } /** diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java index 427ffb45cc7..4dbfc9dbd87 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyDeployWar.java @@ -64,24 +64,6 @@ public class JettyDeployWar extends JettyRunWarMojo nonBlocking = daemon; super.execute(); } - - - - - - - /** - * @see org.eclipse.jetty.maven.plugin.JettyRunWarMojo#checkPackagingConfiguration() - */ - @Override - public void checkPackagingConfiguration() throws MojoExecutionException - { - return; //do not require this to be a war project - } - - - - @Override diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java index a2eda37158f..2ff73a17772 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunMojo.java @@ -24,6 +24,7 @@ import java.net.URL; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.Iterator; @@ -164,7 +165,6 @@ public class JettyRunMojo extends AbstractJettyMojo protected Resource originalBaseResource; - @Parameter(defaultValue = "${reactorProjects}", readonly = true, required = true) private List reactorProjects; @@ -178,21 +178,6 @@ public class JettyRunMojo extends AbstractJettyMojo warPluginInfo = new WarPluginInfo(project); super.execute(); } - - - - - /** - * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#checkPackagingConfiguration() - */ - @Override - public void checkPackagingConfiguration() throws MojoExecutionException - { - if ( !"war".equals( project.getPackaging() )) - throw new MojoExecutionException("Not war packaging"); - } - - /** * Verify the configuration given in the pom. diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java index 8892d4f505b..bf3bed32f95 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarExplodedMojo.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.maven.plugin; import java.io.File; +import java.util.Collections; import java.util.List; import org.apache.maven.plugin.MojoExecutionException; @@ -57,10 +58,6 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo */ private File war; - - - - /** * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#execute() */ @@ -78,18 +75,6 @@ public class JettyRunWarExplodedMojo extends AbstractJettyMojo server.setStopAtShutdown(true); //as we will normally be stopped with a cntrl-c, ensure server stopped super.finishConfigurationBeforeStart(); } - - - /** - * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#checkPackagingConfiguration() - */ - @Override - public void checkPackagingConfiguration() throws MojoExecutionException - { - if ( !"war".equals( project.getPackaging() )) - throw new MojoExecutionException("Not war packaging"); - } - /** * diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java index 83a4f1017a6..30227435e71 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyRunWarMojo.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.maven.plugin; import java.io.File; +import java.util.Collections; import java.util.List; import org.apache.maven.plugin.MojoExecutionException; @@ -55,7 +56,6 @@ public class JettyRunWarMojo extends AbstractJettyMojo */ private File war; - /** * @see org.apache.maven.plugin.Mojo#execute() */ @@ -95,20 +95,6 @@ public class JettyRunWarMojo extends AbstractJettyMojo return; } - - - - /** - * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#checkPackagingConfiguration() - */ - @Override - public void checkPackagingConfiguration() throws MojoExecutionException - { - if ( !"war".equals( project.getPackaging() )) - throw new MojoExecutionException("Not war packaging"); - } - - /** * @see AbstractJettyMojo#configureScanner() */ diff --git a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyStartMojo.java b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyStartMojo.java index d643fb42b48..bb4c6943678 100644 --- a/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyStartMojo.java +++ b/jetty-maven-plugin/src/main/java/org/eclipse/jetty/maven/plugin/JettyStartMojo.java @@ -48,15 +48,6 @@ public class JettyStartMojo extends JettyRunMojo super.execute(); } - /** - * @see org.eclipse.jetty.maven.plugin.AbstractJettyMojo#checkPackagingConfiguration() - */ - @Override - public void checkPackagingConfiguration() throws MojoExecutionException - { - return; //don't check that the project is a war - } - @Override public void finishConfigurationBeforeStart() throws Exception { diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionDataStore.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionDataStore.java index 81b04082faf..cbe769900b2 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionDataStore.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionDataStore.java @@ -37,12 +37,13 @@ public abstract class NoSqlSessionDataStore extends AbstractSessionDataStore public class NoSqlSessionData extends SessionData { private Object _version; - private Set _dirtyAttributes = new HashSet(); + private Set _dirtyAttributes = new HashSet<>(); public NoSqlSessionData(String id, String cpath, String vhost, long created, long accessed, long lastAccessed, long maxInactiveMs) { super(id, cpath, vhost, created, accessed, lastAccessed, maxInactiveMs); + setVersion (new Long(0)); } public void setVersion (Object v) diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java index 1b078f61cb4..106df261ec1 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStore.java @@ -19,6 +19,20 @@ package org.eclipse.jetty.nosql.mongodb; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.jetty.nosql.NoSqlSessionDataStore; +import org.eclipse.jetty.server.session.SessionContext; +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.server.session.UnreadableSessionDataException; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + import com.mongodb.BasicDBList; import com.mongodb.BasicDBObject; import com.mongodb.BasicDBObjectBuilder; @@ -29,26 +43,6 @@ import com.mongodb.MongoException; import com.mongodb.WriteConcern; import com.mongodb.WriteResult; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectOutputStream; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.jetty.nosql.NoSqlSessionDataStore; -import org.eclipse.jetty.server.session.SessionData; -import org.eclipse.jetty.util.ClassLoadingObjectInputStream; -import org.eclipse.jetty.util.annotation.ManagedAttribute; -import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; - /** * MongoSessionDataStore * @@ -108,12 +102,12 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore /** * Special attribute for a session that is context-specific */ - private final static String __METADATA = "__metadata__"; + public final static String __METADATA = "__metadata__"; /** * Name of nested document field containing 1 sub document per context for which the session id is in use */ - private final static String __CONTEXT = "context"; + public final static String __CONTEXT = "context"; /** * Special attribute per session per context, incremented each time attributes are modified @@ -131,6 +125,9 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore */ public final static String __ACCESSED = "accessed"; + + public final static String __LAST_ACCESSED = "lastAccessed"; + /** * Time this session will expire, based on last access time and maxIdle */ @@ -144,7 +141,7 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore /** * Time of session creation */ - private final static String __CREATED = "created"; + public final static String __CREATED = "created"; /** * Whether or not session is valid @@ -188,8 +185,8 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore @Override public SessionData load(String id) throws Exception { - final AtomicReference reference = new AtomicReference(); - final AtomicReference exception = new AtomicReference(); + final AtomicReference reference = new AtomicReference<>(); + final AtomicReference exception = new AtomicReference<>(); Runnable r = new Runnable() { @Override @@ -212,19 +209,20 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore if (valid == null || !valid) return; - Object version = getNestedValue(sessionDocument, getContextSubfield(__VERSION)); - Long lastSaved = (Long)getNestedValue(sessionDocument, getContextSubfield(__LASTSAVED)); - String lastNode = (String)getNestedValue(sessionDocument, getContextSubfield(__LASTNODE)); + Object version = MongoUtils.getNestedValue(sessionDocument, getContextSubfield(__VERSION)); + Long lastSaved = (Long)MongoUtils.getNestedValue(sessionDocument, getContextSubfield(__LASTSAVED)); + String lastNode = (String)MongoUtils.getNestedValue(sessionDocument, getContextSubfield(__LASTNODE)); Long created = (Long)sessionDocument.get(__CREATED); Long accessed = (Long)sessionDocument.get(__ACCESSED); + Long lastAccessed = (Long)sessionDocument.get(__LAST_ACCESSED); Long maxInactive = (Long)sessionDocument.get(__MAX_IDLE); Long expiry = (Long)sessionDocument.get(__EXPIRY); NoSqlSessionData data = null; // get the session for the context - DBObject sessionSubDocumentForContext = (DBObject)getNestedValue(sessionDocument,getContextField()); + DBObject sessionSubDocumentForContext = (DBObject)MongoUtils.getNestedValue(sessionDocument,getContextField()); if (LOG.isDebugEnabled()) LOG.debug("attrs {}", sessionSubDocumentForContext); @@ -234,7 +232,7 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore LOG.debug("Session {} present for context {}", id, _context); //only load a session if it exists for this context - data = (NoSqlSessionData)newSessionData(id, created, accessed, accessed, maxInactive); + data = (NoSqlSessionData)newSessionData(id, created, accessed, (lastAccessed == null? accessed:lastAccessed), maxInactive); data.setVersion(version); data.setExpiry(expiry); data.setContextPath(_context.getCanonicalContextPath()); @@ -248,8 +246,8 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore //skip special metadata attribute which is not one of the actual session attributes if ( __METADATA.equals(name) ) continue; - String attr = decodeName(name); - Object value = decodeValue(sessionSubDocumentForContext.get(name)); + String attr = MongoUtils.decodeName(name); + Object value = MongoUtils.decodeValue(sessionSubDocumentForContext.get(name)); attributes.put(attr,value); } @@ -265,7 +263,7 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore } catch (Exception e) { - exception.set(e); + exception.set(new UnreadableSessionDataException(id, _context, e)); } } }; @@ -298,7 +296,7 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore if (sessionDocument != null) { - DBObject c = (DBObject)getNestedValue(sessionDocument, __CONTEXT); + DBObject c = (DBObject)MongoUtils.getNestedValue(sessionDocument, __CONTEXT); if (c == null) { //delete whole doc @@ -326,7 +324,7 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore BasicDBObject unsets = new BasicDBObject(); unsets.put(getContextField(),1); remove.put("$unset",unsets); - WriteResult result = _dbSessions.update(mongoKey,remove,false,false,WriteConcern.SAFE); + _dbSessions.update(mongoKey,remove,false,false,WriteConcern.SAFE); return true; } else @@ -347,6 +345,7 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore DBObject fields = new BasicDBObject(); fields.put(__EXPIRY, 1); fields.put(__VALID, 1); + fields.put(getContextSubfield(__VERSION), 1); DBObject sessionDocument = _dbSessions.findOne(new BasicDBObject(__ID, id), fields); @@ -359,9 +358,16 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore Long expiry = (Long)sessionDocument.get(__EXPIRY); - if (expiry.longValue() <= 0) - return true; //never expires, its good - return (expiry.longValue() > System.currentTimeMillis()); //expires later + //expired? + if (expiry.longValue() > 0 && expiry.longValue() < System.currentTimeMillis()) + return false; //it's expired + + //does it exist for this context? + Object version = MongoUtils.getNestedValue(sessionDocument, getContextSubfield(__VERSION)); + if (version == null) + return false; + + return true; } @@ -425,24 +431,51 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore if (LOG.isDebugEnabled()) LOG.debug("{} Mongo found old expired session {}", _context, id+" exp="+session.get(__EXPIRY)); expiredSessions.add(id); } - } finally { - oldExpiredSessions.close(); + if (oldExpiredSessions != null) + oldExpiredSessions.close(); } + + //check through sessions that were candidates, but not found as expired. + //they may no longer be persisted, in which case they are treated as expired. + for (String c:candidates) + { + if (!expiredSessions.contains(c)) + { + try + { + if (!exists(c)) + expiredSessions.add(c); + } + catch (Exception e) + { + LOG.warn("Problem checking potentially expired session {}", c, e); + } + } + } return expiredSessions; } - /** + /** + * @see org.eclipse.jetty.server.session.SessionDataStore#initialize(org.eclipse.jetty.server.session.SessionContext) + */ + public void initialize (SessionContext context) throws Exception + { + if (isStarted()) + throw new IllegalStateException("Context set after SessionDataStore started"); + _context = context; + ensureIndexes(); + } + + /** * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore(String, SessionData, long) */ @Override public void doStore(String id, SessionData data, long lastSaveTime) throws Exception - { - NoSqlSessionData nsqd = (NoSqlSessionData)data; - + { // Form query for upsert BasicDBObject key = new BasicDBObject(__ID, id); @@ -459,21 +492,21 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore { upsert = true; version = new Long(1); - sets.put(__CREATED,nsqd.getCreated()); + sets.put(__CREATED,data.getCreated()); sets.put(__VALID,true); sets.put(getContextSubfield(__VERSION),version); sets.put(getContextSubfield(__LASTSAVED), data.getLastSaved()); sets.put(getContextSubfield(__LASTNODE), data.getLastNode()); - sets.put(__MAX_IDLE, nsqd.getMaxInactiveMs()); - sets.put(__EXPIRY, nsqd.getExpiry()); - nsqd.setVersion(version); + sets.put(__MAX_IDLE, data.getMaxInactiveMs()); + sets.put(__EXPIRY, data.getExpiry()); + ((NoSqlSessionData)data).setVersion(version); } else { sets.put(getContextSubfield(__LASTSAVED), data.getLastSaved()); sets.put(getContextSubfield(__LASTNODE), data.getLastNode()); version = new Long(((Number)version).longValue() + 1); - nsqd.setVersion(version); + ((NoSqlSessionData)data).setVersion(version); update.put("$inc",_version_1); //if max idle time and/or expiry is smaller for this context, then choose that for the whole session doc BasicDBObject fields = new BasicDBObject(); @@ -487,23 +520,24 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore tmpLong = (Long)o.get(__EXPIRY); long currentExpiry = (tmpLong == null? 0 : tmpLong.longValue()); - if (currentMaxIdle != nsqd.getMaxInactiveMs()) - sets.put(__MAX_IDLE, nsqd.getMaxInactiveMs()); + if (currentMaxIdle != data.getMaxInactiveMs()) + sets.put(__MAX_IDLE, data.getMaxInactiveMs()); - if (currentExpiry != nsqd.getExpiry()) - sets.put(__EXPIRY, nsqd.getExpiry()); + if (currentExpiry != data.getExpiry()) + sets.put(__EXPIRY, data.getExpiry()); } else LOG.warn("Session {} not found, can't update", id); } - sets.put(__ACCESSED, nsqd.getAccessed()); + sets.put(__ACCESSED, data.getAccessed()); + sets.put(__LAST_ACCESSED, data.getLastAccessed()); - Set names = nsqd.takeDirtyAttributes(); + Set names = ((NoSqlSessionData)data).takeDirtyAttributes(); if (lastSaveTime <= 0) { - names.addAll(nsqd.getAllAttributeNames()); // note dirty may include removed names + names.addAll(((NoSqlSessionData)data).getAllAttributeNames()); // note dirty may include removed names } @@ -511,9 +545,9 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore { Object value = data.getAttribute(name); if (value == null) - unsets.put(getContextField() + "." + encodeName(name),1); + unsets.put(getContextField() + "." + MongoUtils.encodeName(name),1); else - sets.put(getContextField() + "." + encodeName(name),encodeName(value)); + sets.put(getContextField() + "." + MongoUtils.encodeName(name), MongoUtils.encodeName(value)); } // Do the upsert @@ -521,37 +555,16 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore update.put("$set",sets); if (!unsets.isEmpty()) update.put("$unset",unsets); + WriteResult res = _dbSessions.update(key,update,upsert,false,WriteConcern.SAFE); if (LOG.isDebugEnabled()) LOG.debug("Save:db.sessions.update( {}, {},{} )", key, update, res); } - - - - @Override - protected void doStart() throws Exception - { - if (_dbSessions == null) - throw new IllegalStateException("DBCollection not set"); - - _version_1 = new BasicDBObject(getContextSubfield(__VERSION),1); - - ensureIndexes(); - - super.doStart(); - } - - @Override - protected void doStop() throws Exception - { - super.doStop(); - } - - protected void ensureIndexes() throws MongoException { - DBObject idKey = BasicDBObjectBuilder.start().add("id", 1).get(); + _version_1 = new BasicDBObject(getContextSubfield(__VERSION),1); + DBObject idKey = BasicDBObjectBuilder.start().add("id", 1).get(); _dbSessions.createIndex(idKey, BasicDBObjectBuilder.start() .add("name", "id_1") @@ -560,16 +573,19 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore .add("unique", true) .get()); - DBObject versionKey = BasicDBObjectBuilder.start().add("id", 1).add("version", 1).get(); + DBObject versionKey = BasicDBObjectBuilder.start().add("id", 1).add("version", 1).get(); _dbSessions.createIndex(versionKey, BasicDBObjectBuilder.start() .add("name", "id_1_version_1") .add("ns", _dbSessions.getFullName()) .add("sparse", false) .add("unique", true) .get()); + LOG.debug( "done ensure Mongodb indexes existing" ); //TODO perhaps index on expiry time? } + + /*------------------------------------------------------------ */ private String getContextField () { @@ -597,105 +613,6 @@ public class MongoSessionDataStore extends NoSqlSessionDataStore } - /*------------------------------------------------------------ */ - protected Object decodeValue(final Object valueToDecode) throws IOException, ClassNotFoundException - { - if (valueToDecode == null || valueToDecode instanceof Number || valueToDecode instanceof String || valueToDecode instanceof Boolean || valueToDecode instanceof Date) - { - return valueToDecode; - } - else if (valueToDecode instanceof byte[]) - { - final byte[] decodeObject = (byte[])valueToDecode; - final ByteArrayInputStream bais = new ByteArrayInputStream(decodeObject); - final ClassLoadingObjectInputStream objectInputStream = new ClassLoadingObjectInputStream(bais); - return objectInputStream.readUnshared(); - } - else if (valueToDecode instanceof DBObject) - { - Map map = new HashMap(); - for (String name : ((DBObject)valueToDecode).keySet()) - { - String attr = decodeName(name); - map.put(attr,decodeValue(((DBObject)valueToDecode).get(name))); - } - return map; - } - else - { - throw new IllegalStateException(valueToDecode.getClass().toString()); - } - } - /*------------------------------------------------------------ */ - protected String decodeName(String name) - { - return name.replace("%2E",".").replace("%25","%"); - } - - - /*------------------------------------------------------------ */ - protected String encodeName(String name) - { - return name.replace("%","%25").replace(".","%2E"); - } - - - /*------------------------------------------------------------ */ - protected Object encodeName(Object value) throws IOException - { - if (value instanceof Number || value instanceof String || value instanceof Boolean || value instanceof Date) - { - return value; - } - else if (value.getClass().equals(HashMap.class)) - { - BasicDBObject o = new BasicDBObject(); - for (Map.Entry entry : ((Map)value).entrySet()) - { - if (!(entry.getKey() instanceof String)) - { - o = null; - break; - } - o.append(encodeName(entry.getKey().toString()),encodeName(entry.getValue())); - } - - if (o != null) - return o; - } - - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - ObjectOutputStream out = new ObjectOutputStream(bout); - out.reset(); - out.writeUnshared(value); - out.flush(); - return bout.toByteArray(); - } - - /*------------------------------------------------------------ */ - /** - * Dig through a given dbObject for the nested value - */ - private Object getNestedValue(DBObject dbObject, String nestedKey) - { - String[] keyChain = nestedKey.split("\\."); - - DBObject temp = dbObject; - - for (int i = 0; i < keyChain.length - 1; ++i) - { - temp = (DBObject)temp.get(keyChain[i]); - - if ( temp == null ) - { - return null; - } - } - - return temp.get(keyChain[keyChain.length - 1]); - } - - /** * @see org.eclipse.jetty.server.session.SessionDataStore#isPassivating() */ diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreFactory.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreFactory.java index 67df65470a1..e8ca93542f1 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreFactory.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreFactory.java @@ -149,4 +149,6 @@ public class MongoSessionDataStoreFactory extends AbstractSessionDataStoreFactor return store; } + + } diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoUtils.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoUtils.java new file mode 100644 index 00000000000..cea0c039bb5 --- /dev/null +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/mongodb/MongoUtils.java @@ -0,0 +1,150 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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.nosql.mongodb; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jetty.util.ClassLoadingObjectInputStream; + +import com.mongodb.BasicDBObject; +import com.mongodb.DBObject; + +/** + * MongoUtils + * + * Some utility methods for manipulating mongo data. This class facilitates testing. + * + */ +public class MongoUtils +{ + + public static Object decodeValue(final Object valueToDecode) throws IOException, ClassNotFoundException + { + if (valueToDecode == null || valueToDecode instanceof Number || valueToDecode instanceof String || valueToDecode instanceof Boolean || valueToDecode instanceof Date) + { + return valueToDecode; + } + else if (valueToDecode instanceof byte[]) + { + final byte[] decodeObject = (byte[])valueToDecode; + final ByteArrayInputStream bais = new ByteArrayInputStream(decodeObject); + final ClassLoadingObjectInputStream objectInputStream = new ClassLoadingObjectInputStream(bais); + return objectInputStream.readUnshared(); + } + else if (valueToDecode instanceof DBObject) + { + Map map = new HashMap(); + for (String name : ((DBObject)valueToDecode).keySet()) + { + String attr = decodeName(name); + map.put(attr,decodeValue(((DBObject)valueToDecode).get(name))); + } + return map; + } + else + { + throw new IllegalStateException(valueToDecode.getClass().toString()); + } + } + + + + public static String decodeName(String name) + { + return name.replace("%2E",".").replace("%25","%"); + } + + + + public static String encodeName(String name) + { + return name.replace("%","%25").replace(".","%2E"); + } + + + + public static Object encodeName(Object value) throws IOException + { + if (value instanceof Number || value instanceof String || value instanceof Boolean || value instanceof Date) + { + return value; + } + else if (value.getClass().equals(HashMap.class)) + { + BasicDBObject o = new BasicDBObject(); + for (Map.Entry entry : ((Map)value).entrySet()) + { + if (!(entry.getKey() instanceof String)) + { + o = null; + break; + } + o.append(encodeName(entry.getKey().toString()),encodeName(entry.getValue())); + } + + if (o != null) + return o; + } + + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + ObjectOutputStream out = new ObjectOutputStream(bout); + out.reset(); + out.writeUnshared(value); + out.flush(); + return bout.toByteArray(); + } + + + + /** + * Dig through a given dbObject for the nested value + * + * @param dbObject the mongo object to search + * @param nestedKey the field key to find + * + * @return the value of the field key + */ + public static Object getNestedValue(DBObject dbObject, String nestedKey) + { + String[] keyChain = nestedKey.split("\\."); + + DBObject temp = dbObject; + + for (int i = 0; i < keyChain.length - 1; ++i) + { + temp = (DBObject)temp.get(keyChain[i]); + + if ( temp == null ) + { + return null; + } + } + + return temp.get(keyChain[keyChain.length - 1]); + } + + +} diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java index 11c9ffc4bb4..2d176b37c2d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartCleanerListener.java @@ -24,7 +24,7 @@ import javax.servlet.ServletRequestListener; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.MultiException; -import org.eclipse.jetty.util.MultiPartInputStreamParser; + public class MultiPartCleanerListener implements ServletRequestListener { @@ -38,7 +38,7 @@ public class MultiPartCleanerListener implements ServletRequestListener public void requestDestroyed(ServletRequestEvent sre) { //Clean up any tmp files created by MultiPartInputStream - MultiPartInputStreamParser mpis = (MultiPartInputStreamParser)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); + Request.MultiPartInputStream mpis = (Request.MultiPartInputStream)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); if (mpis != null) { ContextHandler.Context context = (ContextHandler.Context)sre.getServletRequest().getAttribute(Request.__MULTIPART_CONTEXT); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java index 42590e18ac8..4eafd91a373 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java @@ -32,7 +32,6 @@ import org.eclipse.jetty.io.ssl.SslConnection; public abstract class NegotiatingServerConnectionFactory extends AbstractConnectionFactory { - private final List negotiatedProtocols; private String defaultProtocol; @@ -47,7 +46,7 @@ public abstract class NegotiatingServerConnectionFactory extends AbstractConnect { p = p.trim(); if (!p.isEmpty()) - this.negotiatedProtocols.add(p.trim()); + this.negotiatedProtocols.add(p); } } } @@ -75,25 +74,25 @@ public abstract class NegotiatingServerConnectionFactory extends AbstractConnect List negotiated = this.negotiatedProtocols; if (negotiated.isEmpty()) { - // Generate list of protocols that we can negotiate + // Generate list of protocols that we can negotiate. negotiated = connector.getProtocols().stream() - .filter(p-> - { - ConnectionFactory f=connector.getConnectionFactory(p); - return !(f instanceof SslConnectionFactory)&&!(f instanceof NegotiatingServerConnectionFactory); - }) - .collect(Collectors.toList()); + .filter(p -> + { + ConnectionFactory f = connector.getConnectionFactory(p); + return !(f instanceof SslConnectionFactory) && !(f instanceof NegotiatingServerConnectionFactory); + }) + .collect(Collectors.toList()); } - // if default protocol is not set, then it is either HTTP/1.1 or - // the first protocol given + // If default protocol is not set, then it is + // either HTTP/1.1 or the first protocol given. String dft = defaultProtocol; if (dft == null && !negotiated.isEmpty()) { - if (negotiated.contains(HttpVersion.HTTP_1_1.asString())) - dft = HttpVersion.HTTP_1_1.asString(); - else - dft = negotiated.get(0); + dft = negotiated.stream() + .filter(HttpVersion.HTTP_1_1::is) + .findFirst() + .orElse(negotiated.get(0)); } SSLEngine engine = null; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 30929c20734..4063d2a7095 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -75,6 +75,7 @@ import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.HttpVersion; import org.eclipse.jetty.http.MetaData; import org.eclipse.jetty.http.MimeTypes; +import org.eclipse.jetty.http.MultiPartFormInputStream; import org.eclipse.jetty.io.RuntimeIOException; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler.Context; @@ -83,6 +84,7 @@ import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.MultiPartInputStreamParser; import org.eclipse.jetty.util.StringUtil; @@ -214,7 +216,7 @@ public class Request implements HttpServletRequest private HttpSession _session; private SessionHandler _sessionHandler; private long _timeStamp; - private MultiPartInputStreamParser _multiPartInputStream; //if the request is a multi-part mime + private MultiPartInputStream _multiPartInputStream; //if the request is a multi-part mime private AsyncContextState _async; /* ------------------------------------------------------------ */ @@ -465,18 +467,26 @@ public class Request implements HttpServletRequest _contentParameters=new MultiMap<>(); contentType = HttpFields.valueParameters(contentType, null); int contentLength = getContentLength(); - if (contentLength != 0) + if (contentLength != 0 && _inputState == __NONE) { - if (MimeTypes.Type.FORM_ENCODED.is(contentType) && _inputState == __NONE && + if (MimeTypes.Type.FORM_ENCODED.is(contentType) && _channel.getHttpConfiguration().isFormEncodedMethod(getMethod())) { extractFormParameters(_contentParameters); } - else if (contentType.startsWith("multipart/form-data") && + else if (MimeTypes.Type.MULTIPART_FORM_DATA.is(contentType) && getAttribute(__MULTIPART_CONFIG_ELEMENT) != null && _multiPartInputStream == null) { - extractMultipartParameters(_contentParameters); + try + { + getParts(_contentParameters); + } + catch (IOException | ServletException e) + { + LOG.debug(e); + throw new RuntimeIOException(e); + } } } } @@ -547,20 +557,6 @@ public class Request implements HttpServletRequest } } - /* ------------------------------------------------------------ */ - private void extractMultipartParameters(MultiMap result) - { - try - { - getParts(result); - } - catch (IOException | ServletException e) - { - LOG.debug(e); - throw new RuntimeIOException(e); - } - } - /* ------------------------------------------------------------ */ @Override public AsyncContext getAsyncContext() @@ -2321,7 +2317,8 @@ public class Request implements HttpServletRequest @Override public Collection getParts() throws IOException, ServletException { - if (getContentType() == null || !getContentType().startsWith("multipart/form-data")) + if (getContentType() == null || + !MimeTypes.Type.MULTIPART_FORM_DATA.is(HttpFields.valueParameters(getContentType(),null))) throw new ServletException("Content-Type != multipart/form-data"); return getParts(null); } @@ -2332,18 +2329,17 @@ public class Request implements HttpServletRequest MultiPartFormDataCompliance compliance = getHttpChannel().getHttpConfiguration().getMultipartFormDataCompliance(); if (_multiPartInputStream == null) - _multiPartInputStream = (MultiPartInputStreamParser)getAttribute(__MULTIPART_INPUT_STREAM); + _multiPartInputStream = (MultiPartInputStream)getAttribute(__MULTIPART_INPUT_STREAM); if (_multiPartInputStream == null) { MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT); - if (config == null) throw new IllegalStateException("No multipart config for servlet"); - _multiPartInputStream = new MultiPartInputStreamParser(getInputStream(), - getContentType(), config, - (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); + _multiPartInputStream = new MultiPartInputStream(getInputStream(), + getContentType(), config, + (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream); setAttribute(__MULTIPART_CONTEXT, _context); @@ -2351,15 +2347,14 @@ public class Request implements HttpServletRequest ByteArrayOutputStream os = null; for (Part p:parts) { - MultiPartInputStreamParser.MultiPart mp = (MultiPartInputStreamParser.MultiPart)p; - if (mp.getContentDispositionFilename() == null) + if (_multiPartInputStream.getContentDispositionFilename(p) == null) { // Servlet Spec 3.0 pg 23, parts without filename must be put into params. String charset = null; - if (mp.getContentType() != null) - charset = MimeTypes.getCharsetFromContentType(mp.getContentType()); + if (p.getContentType() != null) + charset = MimeTypes.getCharsetFromContentType(p.getContentType()); - try (InputStream is = mp.getInputStream()) + try (InputStream is = p.getInputStream()) { if (os == null) os = new ByteArrayOutputStream(); @@ -2367,7 +2362,7 @@ public class Request implements HttpServletRequest String content=new String(os.toByteArray(),charset==null?StandardCharsets.UTF_8:Charset.forName(charset)); if (_contentParameters == null) _contentParameters = params == null ? new MultiMap<>() : params; - _contentParameters.add(mp.getName(), content); + _contentParameters.add(p.getName(), content); } os.reset(); } @@ -2377,6 +2372,7 @@ public class Request implements HttpServletRequest return _multiPartInputStream.getParts(); } + /* ------------------------------------------------------------ */ @Override public void login(String username, String password) throws ServletException @@ -2476,4 +2472,91 @@ public class Request implements HttpServletRequest { throw new ServletException("HttpServletRequest.upgrade() not supported in Jetty"); } + + + + /* --------------------------------------------------------------------------------------------------- */ + /* + * Used to switch between the old and new implementation of MultiPart Form InputStream Parsing. + * The new implementation is prefered will be used as default unless specified otherwise constructor. + */ + @SuppressWarnings("deprecation") + public class MultiPartInputStream + { + private boolean usingNewParser = true; + private MultiPartFormInputStream _newParser = null; + private MultiPartInputStreamParser _oldParser = null; + + public MultiPartInputStream(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir) + { + this(in, contentType, config, contextTmpDir, false); + } + + public MultiPartInputStream(InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir, boolean useOldParser) + { + if(useOldParser) + usingNewParser = false; + else + usingNewParser = true; + + if(usingNewParser) + _newParser = new MultiPartFormInputStream(in, contentType, config, contextTmpDir); + else + _oldParser = new MultiPartInputStreamParser(in, contentType, config, contextTmpDir); + } + + public Collection getParts() throws IOException { + Collection parts = null; + + if(usingNewParser) + parts = _newParser.getParts(); + else + parts = _oldParser.getParts(); + + return parts; + } + + public Part getPart(String name) throws IOException { + Part part = null; + + if(usingNewParser) + part = _newParser.getPart(name); + else + part = _oldParser.getPart(name); + + return part; + } + + public String getContentDispositionFilename(Part p) + { + String contentDisposition = null; + + if(usingNewParser) + contentDisposition = ((MultiPartFormInputStream.MultiPart)p).getContentDispositionFilename(); + else + contentDisposition = ((MultiPartInputStreamParser.MultiPart)p).getContentDispositionFilename(); + + return contentDisposition; + } + + public void deleteParts() throws MultiException + { + if(usingNewParser) + _newParser.deleteParts(); + else + _oldParser.deleteParts(); + } + + public Collection getParsedParts() + { + Collection parsedParts = null; + + if(usingNewParser) + parsedParts = _newParser.getParsedParts(); + else + parsedParts = _oldParser.getParsedParts(); + + return parsedParts; + } + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java index 417571ad94a..1f458b69922 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java @@ -156,7 +156,11 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory private int _minGzipSize=DEFAULT_MIN_GZIP_SIZE; private int _compressionLevel=Deflater.DEFAULT_COMPRESSION; - private boolean _checkGzExists = true; + /** + * @deprecated feature will be removed in Jetty 10.x, with no replacement. + */ + @Deprecated + private boolean _checkGzExists = false; private boolean _syncFlush = false; private int _inflateBufferSize = -1; private EnumSet _dispatchers = EnumSet.of(DispatcherType.REQUEST); @@ -399,6 +403,10 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory super.doStart(); } + /** + * @deprecated feature will be removed in Jetty 10.x, with no replacement. + */ + @Deprecated public boolean getCheckGzExists() { return _checkGzExists; @@ -780,7 +788,9 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory * * @param checkGzExists whether to check if a static gz file exists for * the resource that the DefaultServlet may serve as precompressed. + * @deprecated feature will be removed in Jetty 10.x, with no replacement. */ + @Deprecated public void setCheckGzExists(boolean checkGzExists) { _checkGzExists = checkGzExists; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java index 05163a334aa..0d06bf9e626 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStore.java @@ -25,7 +25,6 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; -import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCache.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCache.java index cd696076273..c4ed3976c48 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCache.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionCache.java @@ -44,7 +44,7 @@ public class DefaultSessionCache extends AbstractSessionCache /** * The cache of sessions in a hashmap */ - protected ConcurrentHashMap _sessions = new ConcurrentHashMap(); + protected ConcurrentHashMap _sessions = new ConcurrentHashMap<>(); private final CounterStatistic _stats = new CounterStatistic(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java index 7056dac5100..b61af4cbef1 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/DefaultSessionIdManager.java @@ -29,7 +29,6 @@ import javax.servlet.http.HttpServletRequest; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.SessionIdManager; -import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedObject; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/FileSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/FileSessionDataStore.java index 0ceb94a6674..000226c27aa 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/FileSessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/FileSessionDataStore.java @@ -30,9 +30,7 @@ import java.io.ObjectOutputStream; import java.io.OutputStream; import java.nio.file.FileVisitOption; import java.nio.file.Files; -import java.nio.file.LinkOption; import java.nio.file.Path; -import java.nio.file.attribute.FileTime; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -264,12 +262,19 @@ public class FileSessionDataStore extends AbstractSessionDataStore if (p == null) return; - long expiry = getExpiryFromFilename(p.getFileName().toString()); - //files with 0 expiry never expire - if (expiry >0 && ((now - expiry) >= (5*TimeUnit.SECONDS.toMillis(_gracePeriodSec)))) + try { - Files.deleteIfExists(p); - if (LOG.isDebugEnabled()) LOG.debug("Sweep deleted {}", p.getFileName()); + long expiry = getExpiryFromFilename(p.getFileName().toString()); + //files with 0 expiry never expire + if (expiry >0 && ((now - expiry) >= (5*TimeUnit.SECONDS.toMillis(_gracePeriodSec)))) + { + Files.deleteIfExists(p); + if (LOG.isDebugEnabled()) LOG.debug("Sweep deleted {}", p.getFileName()); + } + } + catch (NumberFormatException e) + { + LOG.warn("Not valid session filename {}", p.getFileName(), e); } } @@ -293,7 +298,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore if (filename == null) { if (LOG.isDebugEnabled()) - LOG.debug("Unknown file {}",filename); + LOG.debug("Unknown file {}",idWithContext); return; } File file = new File (_storeDir, filename); @@ -542,7 +547,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore * @param id identity of session * @return the session id plus context */ - private String getIdWithContext (String id) + protected String getIdWithContext (String id) { return _contextString+"_"+id; } @@ -552,13 +557,13 @@ public class FileSessionDataStore extends AbstractSessionDataStore * @param data * @return the session id plus context and expiry */ - private String getIdWithContextAndExpiry (SessionData data) + protected String getIdWithContextAndExpiry (SessionData data) { return ""+data.getExpiry()+"_"+getIdWithContext(data.getId()); } - private String getIdFromFilename (String filename) + protected String getIdFromFilename (String filename) { if (filename == null) return null; @@ -567,7 +572,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore - private long getExpiryFromFilename (String filename) + protected long getExpiryFromFilename (String filename) { if (StringUtil.isBlank(filename) || filename.indexOf("_") < 0) throw new IllegalStateException ("Invalid or missing filename"); @@ -577,7 +582,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore } - private String getContextFromFilename (String filename) + protected String getContextFromFilename (String filename) { if (StringUtil.isBlank(filename)) return null; @@ -593,7 +598,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore * @param filename the name of the file to use * @return the session id plus context */ - private String getIdWithContextFromFilename (String filename) + protected String getIdWithContextFromFilename (String filename) { if (StringUtil.isBlank(filename) || filename.indexOf('_') < 0) return null; @@ -607,7 +612,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore * @param filename the filename to check * @return true if the filename has the correct filename format */ - private boolean isSessionFilename (String filename) + protected boolean isSessionFilename (String filename) { if (StringUtil.isBlank(filename)) return false; @@ -626,7 +631,7 @@ public class FileSessionDataStore extends AbstractSessionDataStore * @param filename the filename to check * @return true if the filename has the correct filename format and is for this context */ - private boolean isOurContextSessionFilename (String filename) + protected boolean isOurContextSessionFilename (String filename) { if (StringUtil.isBlank(filename)) return false; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HouseKeeper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HouseKeeper.java index dbfb89ccc45..4dc1c17daf7 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HouseKeeper.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HouseKeeper.java @@ -146,7 +146,7 @@ public class HouseKeeper extends AbstractLifeCycle _task.cancel(); if (_runner == null) _runner = new Runner(); - LOG.info("Scavenging every {}ms", _intervalMs); + LOG.info("{} Scavenging every {}ms", _sessionIdManager.getWorkerName(), _intervalMs); _task = _scheduler.schedule(_runner,_intervalMs,TimeUnit.MILLISECONDS); } } @@ -164,7 +164,7 @@ public class HouseKeeper extends AbstractLifeCycle if (_task!=null) { _task.cancel(); - LOG.info("Stopped scavenging"); + LOG.info("{} Stopped scavenging", _sessionIdManager.getWorkerName()); } _task = null; if (_ownScheduler) @@ -204,13 +204,13 @@ public class HouseKeeper extends AbstractLifeCycle if (sec <= 0) { _intervalMs = 0L; - LOG.info("Scavenging disabled"); + LOG.info("{} Scavenging disabled", _sessionIdManager.getWorkerName()); stopScavenging(); } else { if (sec < 10) - LOG.warn("Short interval of {}sec for session scavenging.", sec); + LOG.warn("{} Short interval of {}sec for session scavenging.", _sessionIdManager.getWorkerName(), sec); _intervalMs=sec*1000L; @@ -261,7 +261,7 @@ public class HouseKeeper extends AbstractLifeCycle return; if (LOG.isDebugEnabled()) - LOG.debug("{} scavenging sessions", this); + LOG.debug("{} scavenging sessions", _sessionIdManager.getWorkerName()); //find the session managers for (SessionHandler manager:_sessionIdManager.getSessionHandlers()) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java index 53d36272c5c..6cc070f7b8f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionDataStore.java @@ -816,7 +816,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore public Set doGetExpired(Set candidates) { if (LOG.isDebugEnabled()) - LOG.debug("Getting expired sessions "+System.currentTimeMillis()); + LOG.debug("Getting expired sessions at time {}", System.currentTimeMillis()); long now = System.currentTimeMillis(); @@ -830,7 +830,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore */ long upperBound = now; if (LOG.isDebugEnabled()) - LOG.debug ("{}- Pass 1: Searching for sessions for context {} managed by me {} and expired before {}", _context.getCanonicalContextPath(), _context.getWorkerName(), upperBound); + LOG.debug ("{}- Pass 1: Searching for sessions for context {} managed by me and expired before {}", _context.getWorkerName(), _context.getCanonicalContextPath(),upperBound); try (PreparedStatement statement = _sessionTableSchema.getExpiredSessionsStatement(connection, _context.getCanonicalContextPath(), _context.getVhost(), upperBound)) { @@ -905,7 +905,7 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore } catch (Exception e) { - LOG.warn("Problem checking if potentially expired session {} exists in db", k,e); + LOG.warn("{} Problem checking if potentially expired session {} exists in db", _context.getWorkerName(), k,e); } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionData.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionData.java index b86d3c2ac8b..6d9e1f91a2f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionData.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionData.java @@ -372,9 +372,7 @@ public class SessionData implements Serializable return (getExpiry() <= time); } - /** - * @see java.lang.Object#toString() - */ + @Override public String toString() { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionDataStore.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionDataStore.java index 1149f038064..75652fb39e4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionDataStore.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionDataStore.java @@ -21,8 +21,6 @@ package org.eclipse.jetty.server.session; import java.util.Set; -import org.eclipse.jetty.util.component.LifeCycle; - /** * SessionDataStore * @@ -68,10 +66,10 @@ public interface SessionDataStore extends SessionDataMap /** * Test if data exists for a given session id. * - * @param id Identity of session whose existance should be checked + * @param id Identity of session whose existence should be checked * * @return true if valid, non-expired session exists - * @throws Exception if problem checking existance with persistence layer + * @throws Exception if problem checking existence with persistence layer */ public boolean exists (String id) throws Exception; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java index f793222103d..b7060d5ce94 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java @@ -222,9 +222,9 @@ public class SessionHandler extends ScopedHandler protected boolean _secureCookies=false; protected boolean _secureRequestOnly=true; - protected final List _sessionAttributeListeners = new CopyOnWriteArrayList(); - protected final List _sessionListeners= new CopyOnWriteArrayList(); - protected final List _sessionIdListeners = new CopyOnWriteArrayList(); + protected final List _sessionAttributeListeners = new CopyOnWriteArrayList<>(); + protected final List _sessionListeners= new CopyOnWriteArrayList<>(); + protected final List _sessionIdListeners = new CopyOnWriteArrayList<>(); protected ClassLoader _loader; protected ContextHandler.Context _context; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index 318a3ffcdc5..eeefa299e7f 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -364,7 +364,7 @@ public class RequestTest @Override public void requestDestroyed(ServletRequestEvent sre) { - MultiPartInputStreamParser m = (MultiPartInputStreamParser)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); + Request.MultiPartInputStream m = (Request.MultiPartInputStream)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); ContextHandler.Context c = (ContextHandler.Context)sre.getServletRequest().getAttribute(Request.__MULTIPART_CONTEXT); assertNotNull (m); assertNotNull (c); @@ -426,7 +426,7 @@ public class RequestTest @Override public void requestDestroyed(ServletRequestEvent sre) { - MultiPartInputStreamParser m = (MultiPartInputStreamParser)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); + Request.MultiPartInputStream m = (Request.MultiPartInputStream)sre.getServletRequest().getAttribute(Request.__MULTIPART_INPUT_STREAM); ContextHandler.Context c = (ContextHandler.Context)sre.getServletRequest().getAttribute(Request.__MULTIPART_CONTEXT); assertNotNull (m); assertNotNull (c); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/FileSessionManagerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/FileSessionManagerTest.java deleted file mode 100644 index fa9a3f85e88..00000000000 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/session/FileSessionManagerTest.java +++ /dev/null @@ -1,421 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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 java.io.File; -import java.io.FilenameFilter; -import java.util.Collections; - -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.toolchain.test.FS; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.IO; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.StdErrLog; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - -public class FileSessionManagerTest -{ - public static final long ONE_DAY = (1000L*60L*60L*24L); - private static StdErrLog _log; - private static boolean _stacks; - - - @BeforeClass - public static void beforeClass () - { - _log = ((StdErrLog)Log.getLogger("org.eclipse.jetty.server.session")); - _stacks = _log.isHideStacks(); - _log.setHideStacks(true); - } - - @AfterClass - public static void afterClass() - { - _log.setHideStacks(_stacks); - } - - @After - public void after() - { - File testDir = MavenTestingUtils.getTargetTestingDir("hashes"); - if (testDir.exists()) - FS.ensureEmpty(testDir); - } - - - @Test - public void testDangerousSessionIdRemoval() throws Exception - { - String expectedFilename = "_0.0.0.0_dangerFile"; - File targetFile = MavenTestingUtils.getTargetFile(expectedFilename); - - try - { - Server server = new Server(); - SessionHandler handler = new SessionHandler(); - handler.setServer(server); - final DefaultSessionIdManager idmgr = new DefaultSessionIdManager(server); - idmgr.setServer(server); - server.setSessionIdManager(idmgr); - - FileSessionDataStore ds = new FileSessionDataStore(); - ds.setDeleteUnrestorableFiles(true); - DefaultSessionCache ss = new DefaultSessionCache(handler); - handler.setSessionCache(ss); - ss.setSessionDataStore(ds); - File testDir = MavenTestingUtils.getTargetTestingDir("hashes"); - FS.ensureEmpty(testDir); - ds.setStoreDir(testDir); - handler.setSessionIdManager(idmgr); - handler.start(); - - //Create a file that is in the parent dir of the session storeDir - - targetFile.createNewFile(); - Assert.assertTrue("File should exist!", MavenTestingUtils.getTargetFile(expectedFilename).exists()); - - //Verify that passing in a relative filename outside of the storedir does not lead - //to deletion of file (needs deleteUnrecoverableFiles(true)) - Session session = handler.getSession("../_0.0.0.0_dangerFile"); - Assert.assertTrue(session == null); - Assert.assertTrue("File should exist!", MavenTestingUtils.getTargetFile(expectedFilename).exists()); - } - finally - { - if (targetFile.exists()) - IO.delete(targetFile); - } - } - - - - /** - * When starting the filestore, check that really old expired - * files are deleted irrespective of context session belongs to. - * - * @throws Exception - */ - @Test - public void testDeleteOfOlderFiles() throws Exception - { - Server server = new Server(); - SessionHandler handler = new SessionHandler(); - handler.setServer(server); - final DefaultSessionIdManager idmgr = new DefaultSessionIdManager(server); - idmgr.setServer(server); - server.setSessionIdManager(idmgr); - - FileSessionDataStore ds = new FileSessionDataStore(); - ds.setDeleteUnrestorableFiles(false); //turn off deletion of unreadable session files - DefaultSessionCache ss = new DefaultSessionCache(handler); - handler.setSessionCache(ss); - ss.setSessionDataStore(ds); - - File testDir = MavenTestingUtils.getTargetTestingDir("hashes"); - FS.ensureEmpty(testDir); - ds.setStoreDir(testDir); - - //create a really old file for session abc - String name1 = "100__0.0.0.0_abc"; - File f1 = new File(testDir, name1); - if (f1.exists()) - Assert.assertTrue(f1.delete()); - f1.createNewFile(); - - //create another really old file for session abc - Thread.sleep(1100); - String name2 = "101__0.0.0.0_abc"; - File f2 = new File(testDir, name2); - if (f2.exists()) - Assert.assertTrue(f2.delete()); - f2.createNewFile(); - - //make one file for session abc that should not have expired - Thread.sleep(1100); - long exp = System.currentTimeMillis() + ONE_DAY; - String name3 = Long.toString(exp)+"__0.0.0.0_abc"; - File f3 = new File(testDir, name3); - if (f3.exists()) - Assert.assertTrue(f3.delete()); - f3.createNewFile(); - - //make a file that is for a different context - //that expired a long time ago - should be - //removed by sweep on startup - Thread.sleep(1100); - String name4 = "1099_foo_0.0.0.0_abc"; - File f4 = new File(testDir, name4); - if (f4.exists()) - Assert.assertTrue(f4.delete()); - f4.createNewFile(); - - //make a file that is for a different context - //that should not have expired - ensure it is - //not removed - exp = System.currentTimeMillis() + ONE_DAY; - String name5 = Long.toString(exp)+"_foo_0.0.0.0_abcdefg"; - File f5 = new File(testDir, name5); - if (f5.exists()) - Assert.assertTrue(f5.delete()); - f5.createNewFile(); - - //make a file that is for a different context - //that expired, but only recently - it should - //not be removed by the startup process - exp = System.currentTimeMillis() - 1000L; - String name6 = Long.toString(exp)+"_foo_0.0.0.0_abcdefg"; - File f6 = new File(testDir, name6); - if (f6.exists()) - Assert.assertTrue(f6.delete()); - f6.createNewFile(); - - handler.setSessionIdManager(idmgr); - handler.start(); - - Assert.assertTrue(!f1.exists()); - Assert.assertTrue(!f2.exists()); - Assert.assertTrue(f3.exists()); - Assert.assertTrue(!f4.exists()); - Assert.assertTrue(f5.exists()); - Assert.assertTrue(f6.exists()); - } - - - /** - * Tests that only the most recent file will be - * loaded into the cache, even if it is already - * expired. Other recently expired files for - * same session should be deleted. - * @throws Exception - */ - @Test - public void testLoadOnlyMostRecent() throws Exception - { - Server server = new Server(); - SessionHandler handler = new SessionHandler(); - handler.setServer(server); - final DefaultSessionIdManager idmgr = new DefaultSessionIdManager(server); - idmgr.setServer(server); - server.setSessionIdManager(idmgr); - - FileSessionDataStore ds = new FileSessionDataStore(); - ds.setGracePeriodSec(100); //set graceperiod to 100sec to control what we consider as very old - ds.setDeleteUnrestorableFiles(false); //turn off deletion of unreadable session files - DefaultSessionCache ss = new DefaultSessionCache(handler); - handler.setSessionCache(ss); - ss.setSessionDataStore(ds); - - File testDir = MavenTestingUtils.getTargetTestingDir("hashes"); - FS.ensureEmpty(testDir); - ds.setStoreDir(testDir); - - long now = System.currentTimeMillis(); - - //create a file for session abc that expired 5sec ago - long exp = now - 5000L; - String name1 = Long.toString(exp)+"__0.0.0.0_abc"; - File f1 = new File(testDir, name1); - if (f1.exists()) - Assert.assertTrue(f1.delete()); - f1.createNewFile(); - - //create a file for same session that expired 4 sec ago - exp = now - 4000L; - String name2 = Long.toString(exp)+"__0.0.0.0_abc"; - File f2 = new File(testDir, name2); - if (f2.exists()) - Assert.assertTrue(f2.delete()); - f2.createNewFile(); - - - //make a file for same session that expired 3 sec ago - exp = now - 3000L; - String name3 = Long.toString(exp)+"__0.0.0.0_abc"; - File f3 = new File(testDir, name3); - if (f3.exists()) - Assert.assertTrue(f3.delete()); - f3.createNewFile(); - - handler.setSessionIdManager(idmgr); - handler.start(); - - Assert.assertFalse(f1.exists()); - Assert.assertFalse(f2.exists()); - Assert.assertTrue(f3.exists()); - } - - - - - - @Test - public void testUnrestorableFileRemoval() throws Exception - { - Server server = new Server(); - SessionHandler handler = new SessionHandler(); - handler.setServer(server); - final DefaultSessionIdManager idmgr = new DefaultSessionIdManager(server); - idmgr.setServer(server); - server.setSessionIdManager(idmgr); - - File testDir = MavenTestingUtils.getTargetTestingDir("hashes"); - FS.ensureEmpty(testDir); - String expectedFilename = (System.currentTimeMillis() + 10000)+"__0.0.0.0_validFile123"; - - Assert.assertTrue(new File(testDir, expectedFilename).createNewFile()); - Assert.assertTrue("File should exist!", new File(testDir, expectedFilename).exists()); - - DefaultSessionCache ss = new DefaultSessionCache(handler); - FileSessionDataStore ds = new FileSessionDataStore(); - ss.setSessionDataStore(ds); - handler.setSessionCache(ss); - ds.setDeleteUnrestorableFiles(true); //invalid file will be removed - handler.setSessionIdManager(idmgr); - ds.setStoreDir(testDir); - handler.start(); - - handler.getSession("validFile123"); - - Assert.assertTrue("File shouldn't exist!", !new File(testDir,expectedFilename).exists()); - } - - @Test - public void testHashSession() throws Exception - { - File testDir = MavenTestingUtils.getTargetTestingDir("saved"); - FS.ensureEmpty(testDir); - - Server server = new Server(); - SessionHandler handler = new SessionHandler(); - handler.setServer(server); - - DefaultSessionCache ss = new DefaultSessionCache(handler); - FileSessionDataStore ds = new FileSessionDataStore(); - ss.setSessionDataStore(ds); - handler.setSessionCache(ss); - ds.setStoreDir(testDir); - handler.setMaxInactiveInterval(5); - Assert.assertTrue(testDir.exists()); - Assert.assertTrue(testDir.canWrite()); - - - DefaultSessionIdManager idManager = new DefaultSessionIdManager(server); - idManager.setServer(server); - idManager.setWorkerName("foo"); - handler.setSessionIdManager(idManager); - server.setSessionIdManager(idManager); - - server.start(); - handler.start(); - - Session session = (Session)handler.newHttpSession(new Request(null, null)); - String sessionId = session.getId(); - - session.setAttribute("one", new Integer(1)); - session.setAttribute("two", new Integer(2)); - - //stop will persist sessions - handler.setMaxInactiveInterval(30); // change max inactive interval for *new* sessions - handler.stop(); - - final String expectedFilename = "_0.0.0.0_"+session.getId(); - - File[] files = testDir.listFiles(new FilenameFilter(){ - - @Override - public boolean accept(File dir, String name) - { - return name.contains(expectedFilename); - } - - }); - Assert.assertNotNull(files); - Assert.assertEquals(1, files.length); - Assert.assertTrue("File should exist!", files[0].exists()); - - - - handler.start(); - - //restore session - Session restoredSession = (Session)handler.getSession(sessionId); - Assert.assertNotNull(restoredSession); - - Object o = restoredSession.getAttribute("one"); - Assert.assertNotNull(o); - - Assert.assertEquals(1, ((Integer)o).intValue()); - Assert.assertEquals(5, restoredSession.getMaxInactiveInterval()); - - server.stop(); - } - - @Test - public void testIrregularFilenames() throws Exception - { - Server server = new Server(); - SessionHandler handler = new SessionHandler(); - handler.setServer(server); - final DefaultSessionIdManager idmgr = new DefaultSessionIdManager(server); - idmgr.setServer(server); - server.setSessionIdManager(idmgr); - - FileSessionDataStore ds = new FileSessionDataStore(); - ds.setDeleteUnrestorableFiles(true); - DefaultSessionCache ss = new DefaultSessionCache(handler); - handler.setSessionCache(ss); - ss.setSessionDataStore(ds); - File testDir = MavenTestingUtils.getTargetTestingDir("hashes"); - FS.ensureEmpty(testDir); - ds.setStoreDir(testDir); - handler.setSessionIdManager(idmgr); - handler.start(); - - //Create a file in the session storeDir that has no underscore. - File noUnderscore = new File(testDir, "spuriousFile"); - noUnderscore.createNewFile(); - try - { - Assert.assertTrue("Expired should be empty!", ds.getExpired(Collections.emptySet()).isEmpty()); - } - finally - { - noUnderscore.delete(); - } - - //Create a file that starts with a non-number before an underscore - File nonNumber = new File(testDir, "nonNumber_0.0.0.0_spuriousFile"); - nonNumber.createNewFile(); - try - { - Assert.assertTrue("Expired should be empty!", ds.getExpired(Collections.emptySet()).isEmpty()); - } - finally - { - nonNumber.delete(); - } - } - -} diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java index f0c935b29b9..613a21c117a 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java @@ -46,80 +46,49 @@ public class SessionCookieTest super(manager); } - - /** - * @see org.eclipse.jetty.server.session.SessionCache#shutdown() - */ @Override public void shutdown() - { - // TODO Auto-generated method stub - + { } - /** - * @see org.eclipse.jetty.server.session.AbstractSessionCache#newSession(org.eclipse.jetty.server.session.SessionData) - */ + @Override public Session newSession(SessionData data) { - // TODO Auto-generated method stub return null; } - /** - * @see org.eclipse.jetty.server.session.AbstractSessionCache#doGet(String) - */ + @Override public Session doGet(String key) { - // TODO Auto-generated method stub return null; } - /** - * @see org.eclipse.jetty.server.session.AbstractSessionCache#doPutIfAbsent(String, Session) - */ + @Override public Session doPutIfAbsent(String key, Session session) { return null; } - - - /** - * @see org.eclipse.jetty.server.session.AbstractSessionCache#doDelete(String) - */ @Override public Session doDelete(String key) { return null; } - - - /** - * @see org.eclipse.jetty.server.session.AbstractSessionCache#doReplace(java.lang.String, org.eclipse.jetty.server.session.Session, org.eclipse.jetty.server.session.Session) - */ @Override public boolean doReplace(String id, Session oldValue, Session newValue) { - // TODO Auto-generated method stub return false; } - /** - * @see org.eclipse.jetty.server.session.AbstractSessionCache#newSession(javax.servlet.http.HttpServletRequest, org.eclipse.jetty.server.session.SessionData) - */ @Override public Session newSession(HttpServletRequest request, SessionData data) { - // TODO Auto-generated method stub return null; } - - } @@ -131,18 +100,12 @@ public class SessionCookieTest super(server); } - /** - * @see org.eclipse.jetty.server.SessionIdManager#isIdInUse(java.lang.String) - */ @Override public boolean isIdInUse(String id) { return false; } - /** - * @see org.eclipse.jetty.server.SessionIdManager#expireAll(java.lang.String) - */ @Override public void expireAll(String id) { @@ -206,8 +169,5 @@ public class SessionCookieTest //cookie is not secure: not on secured requests and request is secure cookie = mgr.getSessionCookie(session, "/foo", true); assertFalse(cookie.isSecure()); - - } - } diff --git a/jetty-util/pom.xml b/jetty-util/pom.xml index 5813e02d52b..936d545aa57 100644 --- a/jetty-util/pom.xml +++ b/jetty-util/pom.xml @@ -50,7 +50,7 @@ true - osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.util.security.CredentialProvider)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)" + osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.util.security.CredentialProvider)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/AtomicBiInteger.java b/jetty-util/src/main/java/org/eclipse/jetty/util/AtomicBiInteger.java index 948262836e6..ee679b1fbfc 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/AtomicBiInteger.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/AtomicBiInteger.java @@ -21,13 +21,12 @@ package org.eclipse.jetty.util; import java.util.concurrent.atomic.AtomicLong; /** - * An AtomicLong with additional methods to treat it has - * two hi/lo integers. + * An AtomicLong with additional methods to treat it as two hi/lo integers. */ public class AtomicBiInteger extends AtomicLong { /** - * @return the hi integer value + * @return the hi value */ public int getHi() { @@ -35,7 +34,7 @@ public class AtomicBiInteger extends AtomicLong } /** - * @return the lo integer value + * @return the lo value */ public int getLo() { @@ -43,12 +42,12 @@ public class AtomicBiInteger extends AtomicLong } /** - * Atomically set the hi integer value without changing - * the lo value. + * Atomically sets the hi value without changing the lo value. + * * @param hi the new hi value - * @return the hi int value + * @return the previous hi value */ - public int setHi(int hi) + public int getAndSetHi(int hi) { while(true) { @@ -60,11 +59,12 @@ public class AtomicBiInteger extends AtomicLong } /** - * Atomically set the lo integer value without changing - * the hi value. + * Atomically sets the lo value without changing the hi value. + * * @param lo the new lo value + * @return the previous lo value */ - public int setLo(int lo) + public int getAndSetLo(int lo) { while(true) { @@ -76,7 +76,8 @@ public class AtomicBiInteger extends AtomicLong } /** - * Set the hi and lo integer values. + * Sets the hi and lo values. + * * @param hi the new hi value * @param lo the new lo value */ @@ -86,20 +87,21 @@ public class AtomicBiInteger extends AtomicLong } /** - * Atomically sets the hi int value to the given updated value - * only if the current value {@code ==} the expected value. - * Concurrent changes to the lo value result in a retry. - * @param expect the expected value - * @param hi the new value + *

Atomically sets the hi value to the given updated value + * only if the current value {@code ==} the expected value.

+ *

Concurrent changes to the lo value result in a retry.

+ * + * @param expectHi the expected hi value + * @param hi the new hi value * @return {@code true} if successful. False return indicates that - * the actual value was not equal to the expected value. + * the actual hi value was not equal to the expected hi value. */ - public boolean compareAndSetHi(int expect, int hi) + public boolean compareAndSetHi(int expectHi, int hi) { while(true) { long encoded = get(); - if (getHi(encoded)!=expect) + if (getHi(encoded)!=expectHi) return false; long update = encodeHi(encoded,hi); if (compareAndSet(encoded,update)) @@ -108,20 +110,21 @@ public class AtomicBiInteger extends AtomicLong } /** - * Atomically sets the lo int value to the given updated value - * only if the current value {@code ==} the expected value. - * Concurrent changes to the hi value result in a retry. - * @param expect the expected value - * @param lo the new value + *

Atomically sets the lo value to the given updated value + * only if the current value {@code ==} the expected value.

+ *

Concurrent changes to the hi value result in a retry.

+ * + * @param expectLo the expected lo value + * @param lo the new lo value * @return {@code true} if successful. False return indicates that - * the actual value was not equal to the expected value. + * the actual lo value was not equal to the expected lo value. */ - public boolean compareAndSetLo(int expect, int lo) + public boolean compareAndSetLo(int expectLo, int lo) { while(true) { long encoded = get(); - if (getLo(encoded)!=expect) + if (getLo(encoded)!=expectLo) return false; long update = encodeLo(encoded,lo); if (compareAndSet(encoded,update)) @@ -130,30 +133,31 @@ public class AtomicBiInteger extends AtomicLong } /** - * Atomically sets the values to the given updated values - * only if the current encoded value {@code ==} the expected value. - * @param expect the expected encoded values + * Atomically sets the values to the given updated values only if + * the current encoded value {@code ==} the expected encoded value. + * + * @param encoded the expected encoded value * @param hi the new hi value * @param lo the new lo value * @return {@code true} if successful. False return indicates that - * the actual value was not equal to the expected value. + * the actual encoded value was not equal to the expected encoded value. */ - public boolean compareAndSet(long expect, int hi, int lo) + public boolean compareAndSet(long encoded, int hi, int lo) { - long encoded = get(); long update = encode(hi,lo); return compareAndSet(encoded,update); } /** - * Atomically sets the values to the given updated values - * only if the current encoded value {@code ==} the expected value. - * @param expectHi the expected hi values + * Atomically sets the hi and lo values to the given updated values only if + * the current hi and lo values {@code ==} the expected hi and lo values. + * + * @param expectHi the expected hi value * @param hi the new hi value - * @param expectLo the expected lo values + * @param expectLo the expected lo value * @param lo the new lo value * @return {@code true} if successful. False return indicates that - * the actual value was not equal to the expected value. + * the actual hi and lo values were not equal to the expected hi and lo value. */ public boolean compareAndSet(int expectHi, int hi, int expectLo, int lo) { @@ -163,13 +167,12 @@ public class AtomicBiInteger extends AtomicLong } /** - * Atomically updates the current hi value with the results of - * applying the given delta, returning the updated value. + * Atomically adds the given delta to the current hi value, returning the updated hi value. * * @param delta the delta to apply - * @return the updated value + * @return the updated hi value */ - public int updateHi(int delta) + public int addAndGetHi(int delta) { while(true) { @@ -182,13 +185,12 @@ public class AtomicBiInteger extends AtomicLong } /** - * Atomically updates the current lo value with the results of - * applying the given delta, returning the updated value. + * Atomically adds the given delta to the current lo value, returning the updated lo value. * * @param delta the delta to apply - * @return the updated value + * @return the updated lo value */ - public int updateLo(int delta) + public int addAndGetLo(int delta) { while(true) { @@ -201,13 +203,12 @@ public class AtomicBiInteger extends AtomicLong } /** - * Atomically updates the current values with the results of - * applying the given deltas. + * Atomically adds the given deltas to the current hi and lo values. * * @param deltaHi the delta to apply to the hi value * @param deltaLo the delta to apply to the lo value */ - public void update(int deltaHi, int deltaLo) + public void add(int deltaHi, int deltaLo) { while(true) { @@ -219,73 +220,66 @@ public class AtomicBiInteger extends AtomicLong } /** - * Get a hi int value from an encoded long + * Gets a hi value from the given encoded value. + * * @param encoded the encoded value - * @return the hi int value + * @return the hi value */ public static int getHi(long encoded) { - return (int) ((encoded>>32)&0xFFFF_FFFFl); + return (int) ((encoded>>32)&0xFFFF_FFFFL); } /** - * Get a lo int value from an encoded long + * Gets a lo value from the given encoded value. + * * @param encoded the encoded value - * @return the lo int value + * @return the lo value */ public static int getLo(long encoded) { - return (int) (encoded&0xFFFF_FFFFl); + return (int) (encoded&0xFFFF_FFFFL); } /** - * Encode hi and lo int values into a long - * @param hi the hi int value - * @param lo the lo int value + * Encodes hi and lo values into a long. + * + * @param hi the hi value + * @param lo the lo value * @return the encoded value - * */ public static long encode(int hi, int lo) { - long h = ((long)hi)&0xFFFF_FFFFl; - long l = ((long)lo)&0xFFFF_FFFFl; - long encoded = (h<<32)+l; - return encoded; + long h = ((long)hi)&0xFFFF_FFFFL; + long l = ((long)lo)&0xFFFF_FFFFL; + return (h<<32)+l; } - /** - * Encode hi int values into an already encoded long + * Sets the hi value into the given encoded value. + * * @param encoded the encoded value - * @param hi the hi int value - * @return the encoded value - * + * @param hi the hi value + * @return the new encoded value */ public static long encodeHi(long encoded, int hi) { - long h = ((long)hi)&0xFFFF_FFFFl; - long l = encoded&0xFFFF_FFFFl; - encoded = (h<<32)+l; - return encoded; + long h = ((long)hi)&0xFFFF_FFFFL; + long l = encoded&0xFFFF_FFFFL; + return (h<<32)+l; } /** - * Encode lo int values into an already encoded long + * Sets the lo value into the given encoded value. + * * @param encoded the encoded value - * @param lo the lo int value - * @return the encoded value - * + * @param lo the lo value + * @return the new encoded value */ public static long encodeLo(long encoded, int lo) { - long h = (encoded>>32)&0xFFFF_FFFFl; - long l = ((long)lo)&0xFFFF_FFFFl; - encoded = (h<<32)+l; - return encoded; + long h = (encoded>>32)&0xFFFF_FFFFL; + long l = ((long)lo)&0xFFFF_FFFFL; + return (h<<32)+l; } - - - - - } diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/AtomicBiIntegerTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/AtomicBiIntegerTest.java index edda43df9e4..d2c998aa372 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/AtomicBiIntegerTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/AtomicBiIntegerTest.java @@ -18,11 +18,13 @@ package org.eclipse.jetty.util; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.*; - import org.junit.Test; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + public class AtomicBiIntegerTest { @@ -75,11 +77,11 @@ public class AtomicBiIntegerTest assertThat(abi.getHi(),is(0)); assertThat(abi.getLo(),is(0)); - abi.setHi(Integer.MAX_VALUE); + abi.getAndSetHi(Integer.MAX_VALUE); assertThat(abi.getHi(),is(Integer.MAX_VALUE)); assertThat(abi.getLo(),is(0)); - abi.setLo(Integer.MIN_VALUE); + abi.getAndSetLo(Integer.MIN_VALUE); assertThat(abi.getHi(),is(Integer.MAX_VALUE)); assertThat(abi.getLo(),is(Integer.MIN_VALUE)); } diff --git a/jetty-xml/pom.xml b/jetty-xml/pom.xml index 15cefddcaab..43b8ddbc848 100644 --- a/jetty-xml/pom.xml +++ b/jetty-xml/pom.xml @@ -27,7 +27,7 @@ true - osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.xml.ConfigurationProcessorFactory)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)" + osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.xml.ConfigurationProcessorFactory)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional diff --git a/pom.xml b/pom.xml index 07e6f1f543b..2028d7b1dc6 100644 --- a/pom.xml +++ b/pom.xml @@ -448,7 +448,7 @@ org.apache.maven.plugins maven-invoker-plugin - 3.0.1 + 3.0.2-SNAPSHOT org.apache.maven.plugins @@ -1068,16 +1068,6 @@ true - - apache.snapshots - https://repository.apache.org/content/repositories/snapshots - - false - - - true - - @@ -1814,6 +1804,30 @@ --> + + + apache.snapshots + https://repository.apache.org/content/repositories/snapshots + + false + + + true + + + + + + apache.snapshots + https://repository.apache.org/content/repositories/snapshots + + false + + + true + + + diff --git a/tests/test-sessions/pom.xml b/tests/test-sessions/pom.xml index 5f420cc4d76..20c836f0158 100644 --- a/tests/test-sessions/pom.xml +++ b/tests/test-sessions/pom.xml @@ -14,7 +14,6 @@ test-sessions-common - test-hash-sessions test-file-sessions test-jdbc-sessions test-mongodb-sessions diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileSessionDataStoreTest.java similarity index 53% rename from tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java rename to tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileSessionDataStoreTest.java index d25d721b5f7..f58f2e904ec 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileSessionDataStoreTest.java @@ -19,19 +19,16 @@ package org.eclipse.jetty.server.session; -import org.eclipse.jetty.servlet.ServletContextHandler; import org.junit.After; import org.junit.Before; -import org.junit.Test; /** - * ProxySerializationTest + * FileSessionDataStoreTest * * */ -public class ProxySerializationTest extends AbstractProxySerializationTest -{ - +public class FileSessionDataStoreTest extends AbstractSessionDataStoreTest +{ @Before public void before() throws Exception { @@ -43,35 +40,44 @@ public class ProxySerializationTest extends AbstractProxySerializationTest { FileTestHelper.teardown(); } + - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ @Override public SessionDataStoreFactory createSessionDataStoreFactory() { return FileTestHelper.newSessionDataStoreFactory(); } + - - - - @Test @Override - public void testProxySerialization() throws Exception + public void persistSession(SessionData data) throws Exception { - super.testProxySerialization(); + FileTestHelper.createFile(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(), + data.getAccessed(), data.getLastAccessed(), data.getMaxInactiveMs(), data.getExpiry(), data.getCookieSet(), data.getAllAttributes()); + } + + + @Override + public void persistUnreadableSession(SessionData data) throws Exception + { + FileTestHelper.createFile(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(), + data.getAccessed(), data.getLastAccessed(), data.getMaxInactiveMs(), data.getExpiry(), data.getCookieSet(), null); + } + + + @Override + public boolean checkSessionExists(SessionData data) throws Exception + { + return (FileTestHelper.getFile(data.getId()) != null); } /** - * @see org.eclipse.jetty.server.session.AbstractProxySerializationTest#customizeContext(org.eclipse.jetty.servlet.ServletContextHandler) + * */ @Override - public void customizeContext(ServletContextHandler c) + public boolean checkSessionPersisted(SessionData data) throws Exception { - // TODO Auto-generated method stub - + return FileTestHelper.checkSessionPersisted(data); } } diff --git a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileTestHelper.java b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileTestHelper.java index f76dfe39b4a..14c671ae5b2 100644 --- a/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileTestHelper.java +++ b/tests/test-sessions/test-file-sessions/src/test/java/org/eclipse/jetty/server/session/FileTestHelper.java @@ -23,10 +23,20 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.io.DataInputStream; +import java.io.DataOutputStream; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.ObjectOutputStream; import java.nio.file.Files; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.eclipse.jetty.util.ClassLoadingObjectInputStream; import org.eclipse.jetty.util.IO; /** @@ -142,6 +152,105 @@ public class FileTestHelper } + + public static void createFile (String id, String contextPath, String vhost, + String lastNode, long created, long accessed, + long lastAccessed, long maxIdle, long expiry, + long cookieSet, Map attributes) + throws Exception + { + String filename = ""+expiry+"_"+contextPath+"_"+vhost+"_"+id; + File file = new File(_tmpDir, filename); + try(FileOutputStream fos = new FileOutputStream(file,false)) + { + DataOutputStream out = new DataOutputStream(fos); + out.writeUTF(id); + out.writeUTF(contextPath); + out.writeUTF(vhost); + out.writeUTF(lastNode); + out.writeLong(created); + out.writeLong(accessed); + out.writeLong(lastAccessed); + out.writeLong(cookieSet); + out.writeLong(expiry); + out.writeLong(maxIdle); + + if (attributes != null) + { + List keys = new ArrayList(attributes.keySet()); + out.writeInt(keys.size()); + ObjectOutputStream oos = new ObjectOutputStream(out); + for (String name:keys) + { + oos.writeUTF(name); + oos.writeObject(attributes.get(name)); + } + } + } + } + + + public static boolean checkSessionPersisted (SessionData data) + throws Exception + { + String filename = ""+data.getExpiry()+"_"+data.getContextPath()+"_"+data.getVhost()+"_"+data.getId(); + File file = new File(_tmpDir, filename); + assertTrue(file.exists()); + + try (FileInputStream in = new FileInputStream(file)) + { + DataInputStream di = new DataInputStream(in); + + String id = di.readUTF(); + String contextPath = di.readUTF(); + String vhost = di.readUTF(); + String lastNode = di.readUTF(); + long created = di.readLong(); + long accessed = di.readLong(); + long lastAccessed = di.readLong(); + long cookieSet = di.readLong(); + long expiry = di.readLong(); + long maxIdle = di.readLong(); + + assertEquals(data.getId(), id); + assertEquals(data.getContextPath(), contextPath); + assertEquals(data.getVhost(), vhost); + assertEquals(data.getLastNode(), lastNode); + assertEquals(data.getCreated(), created); + assertEquals(data.getAccessed(), accessed); + assertEquals(data.getLastAccessed(), lastAccessed); + assertEquals(data.getCookieSet(), cookieSet); + assertEquals(data.getExpiry(), expiry); + assertEquals(data.getMaxInactiveMs(), maxIdle); + + Map attributes = new HashMap<>(); + + int size = di.readInt(); + if (size > 0) + { + ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(di); + for (int i=0; if1); - - //invalidate the session and verify that the session file is deleted - request = client.newRequest("http://localhost:" + port1 + contextPath + servletMapping + "?action=remove"); - request.header("Cookie", sessionCookie); - response2 = request.send(); - assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); - FileTestHelper.assertSessionExists(TestServer.extractSessionId(sessionCookie), false); - - //make another session - response1 = client.GET("http://localhost:" + port1 + contextPath + servletMapping + "?action=init"); - assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - sessionCookie = response1.getHeaders().get("Set-Cookie"); - assertTrue(sessionCookie != null); - sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); - FileTestHelper.assertSessionExists(TestServer.extractSessionId(sessionCookie), true); - - //wait for it to be scavenged - Thread.currentThread().sleep((inactivePeriod + 2)*1000); - FileTestHelper.assertSessionExists(TestServer.extractSessionId(sessionCookie), false); - - } - finally - { - client.stop(); - } + long ll = store.getExpiryFromFilename(null); + fail("Should throw ISE"); } - finally + catch (Exception e) { - server1.stop(); + //expected; } + + try + { + long ll = store.getExpiryFromFilename("thisisnotavalidsessionfilename"); + fail("Should throw ISE"); + } + catch (IllegalStateException e) + { + //expected; + } + + s = store.getContextFromFilename("100__test_0.0.0.0_1234"); + assertEquals("_test_0.0.0.0", s); + + assertNull (store.getContextFromFilename(null)); + + try + { + s = store.getContextFromFilename("thisisnotavalidfilename"); + fail("Should throw exception"); + } + catch (StringIndexOutOfBoundsException e) + { + //expected; + } + + s = store.getIdWithContextFromFilename("100__test_0.0.0.0_1234"); + assertEquals("_test_0.0.0.0_1234",s); + + assertNull(store.getIdWithContextFromFilename(null)); + assertNull(store.getIdWithContextFromFilename("thisisnotavalidfilename")); + + assertTrue(store.isOurContextSessionFilename("100__test_0.0.0.0_1234")); + assertFalse(store.isOurContextSessionFilename("100__other_0.0.0.0_1234")); } - - public static class TestServlet extends HttpServlet + + + + + @Test + public void testFilenamesWithDefaultContext() throws Exception { - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(10); + FileSessionDataStore store = (FileSessionDataStore)factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + String s = store.getIdWithContext("1234"); + assertEquals("_0.0.0.0_1234", s); + + s = store.getIdFromFilename("0__0.0.0.0_1234"); + assertEquals("1234", s); + + long l = store.getExpiryFromFilename("100__0.0.0.0_1234"); + assertEquals(100, l); + + try { - String action = request.getParameter("action"); - if ("init".equals(action)) - { - HttpSession session = request.getSession(true); - session.setAttribute("A", "A"); - } - else if ("remove".equals(action)) - { - HttpSession session = request.getSession(false); - session.invalidate(); - } - else if ("check".equals(action)) - { - HttpSession session = request.getSession(false); - assertTrue(session != null); - try {Thread.currentThread().sleep(1);}catch (Exception e) {e.printStackTrace();} - } + long ll = store.getExpiryFromFilename("nonnumber__0.0.0.0_1234"); + fail ("Should be non numeric"); } + catch (Exception e) + { + //expected + } + + s = store.getContextFromFilename("100__0.0.0.0_1234"); + assertEquals("_0.0.0.0", s); + + s = store.getIdWithContextFromFilename("100__0.0.0.0_1234"); + assertEquals("_0.0.0.0_1234",s); + + assertTrue(store.isOurContextSessionFilename("100__0.0.0.0_1234")); + assertFalse(store.isOurContextSessionFilename("100__other_0.0.0.0_1234")); + } + + + + /** + * Test the FileSessionDataStore sweeper function + * + * @throws Exception + */ + @Test + public void testSweep () throws Exception + { + + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(10); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + store.start(); + + //create file not for our context that expired long ago and should be removed by sweep + FileTestHelper.createFile("101__foobar_0.0.0.0_sessiona"); + FileTestHelper.assertSessionExists("sessiona", true); + + //create a file not for our context that is not expired and should be ignored + String nonExpiredForeign = (System.currentTimeMillis()+TimeUnit.DAYS.toMillis(1))+"__foobar_0.0.0.0_sessionb"; + FileTestHelper.createFile(nonExpiredForeign); + FileTestHelper.assertFileExists(nonExpiredForeign, true); + + //create a file not for our context that is recently expired, a thus ignored by sweep + String expiredForeign = (System.currentTimeMillis()-TimeUnit.SECONDS.toMillis(1))+"__foobar_0.0.0.0_sessionc"; + FileTestHelper.createFile(expiredForeign); + FileTestHelper.assertFileExists(expiredForeign, true); + + //create a file that is not a session file, it should be ignored + FileTestHelper.createFile("whatever.txt"); + FileTestHelper.assertFileExists("whatever.txt", true); + + //create a file that is not a valid session filename, should be ignored + FileTestHelper.createFile("nonNumber__0.0.0.0_spuriousFile"); + FileTestHelper.assertFileExists("nonNumber__0.0.0.0_spuriousFile", true); + + //create a file that is a non-expired session file for our context that should be ignored + String nonExpired = (System.currentTimeMillis()+TimeUnit.DAYS.toMillis(1))+"__test_0.0.0.0_sessionb"; + FileTestHelper.createFile(nonExpired); + FileTestHelper.assertFileExists(nonExpired, true); + + //create a file that is a never-expire session file for our context that should be ignored + String neverExpired = "0__test_0.0.0.0_sessionc"; + FileTestHelper.createFile(neverExpired); + FileTestHelper.assertFileExists(neverExpired, true); + + //create a file that is a never-expire session file for another context that should be ignored + String foreignNeverExpired = "0__other_0.0.0.0_sessionc"; + FileTestHelper.createFile(foreignNeverExpired); + FileTestHelper.assertFileExists(foreignNeverExpired, true); + + //sweep + ((FileSessionDataStore)store).sweepDisk(); + + //check results + FileTestHelper.assertSessionExists("sessiona", false); + FileTestHelper.assertFileExists("whatever.txt", true); + FileTestHelper.assertFileExists("nonNumber__0.0.0.0_spuriousFile", true); + FileTestHelper.assertFileExists(nonExpired, true); + FileTestHelper.assertFileExists(nonExpiredForeign, true); + FileTestHelper.assertFileExists(expiredForeign, true); + FileTestHelper.assertFileExists(neverExpired, true); + FileTestHelper.assertFileExists(foreignNeverExpired, true); } + /** + * Test that when it initializes, the FileSessionDataStore deletes old expired sessions. + * + * @throws Exception + */ + @Test + public void testInitialize () + throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(10); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + //create file not for our context that expired long ago and should be removed + FileTestHelper.createFile("101_foobar_0.0.0.0_sessiona"); + FileTestHelper.assertSessionExists("sessiona", true); + + //create a file not for our context that is not expired and should be ignored + String nonExpiredForeign = (System.currentTimeMillis()+TimeUnit.DAYS.toMillis(1))+"_foobar_0.0.0.0_sessionb"; + FileTestHelper.createFile(nonExpiredForeign); + FileTestHelper.assertFileExists(nonExpiredForeign, true); + + //create a file not for our context that is recently expired, a thus ignored + String expiredForeign = (System.currentTimeMillis()-TimeUnit.SECONDS.toMillis(1))+"_foobar_0.0.0.0_sessionc"; + FileTestHelper.createFile(expiredForeign); + FileTestHelper.assertFileExists(expiredForeign, true); + + //create a file that is not a session file, it should be ignored + FileTestHelper.createFile("whatever.txt"); + FileTestHelper.assertFileExists("whatever.txt", true); + + //create a file that is not a valid session filename, should be ignored + FileTestHelper.createFile("nonNumber_0.0.0.0_spuriousFile"); + FileTestHelper.assertFileExists("nonNumber_0.0.0.0_spuriousFile", true); + + //create a file that is a non-expired session file for our context that should be ignored + String nonExpired = (System.currentTimeMillis()+TimeUnit.DAYS.toMillis(1))+"_test_0.0.0.0_sessionb"; + FileTestHelper.createFile(nonExpired); + FileTestHelper.assertFileExists(nonExpired, true); + + //create a file that is a never-expire session file for our context that should be ignored + String neverExpired = "0_test_0.0.0.0_sessionc"; + FileTestHelper.createFile(neverExpired); + FileTestHelper.assertFileExists(neverExpired, true); + + //create a file that is a never-expire session file for another context that should be ignored + String foreignNeverExpired = "0_test_0.0.0.0_sessionc"; + FileTestHelper.createFile(foreignNeverExpired); + FileTestHelper.assertFileExists(foreignNeverExpired, true); + + //walk all files in the store + ((FileSessionDataStore)store).initializeStore(); + + //check results + FileTestHelper.assertSessionExists("sessiona", false); + FileTestHelper.assertFileExists("whatever.txt", true); + FileTestHelper.assertFileExists("nonNumber_0.0.0.0_spuriousFile", true); + FileTestHelper.assertFileExists(nonExpired, true); + FileTestHelper.assertFileExists(nonExpiredForeign, true); + FileTestHelper.assertFileExists(expiredForeign, true); + FileTestHelper.assertFileExists(neverExpired, true); + FileTestHelper.assertFileExists(foreignNeverExpired, true); + } + + + /** + * If deleteUnrestorableFiles option is true, a damaged or unrestorable + * file should be deleted. + * + * @throws Exception + */ + @Test + public void testDeleteUnrestorableFiles () + throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(10); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + ((FileSessionDataStore)store).setDeleteUnrestorableFiles(true); //invalid file will be removed + store.initialize(sessionContext); + + String expectedFilename = (System.currentTimeMillis() + 10000)+"__test_0.0.0.0_validFile123"; + FileTestHelper.createFile(expectedFilename); + FileTestHelper.assertFileExists(expectedFilename, true); + + store.start(); + + try + { + store.load("validFile123"); + fail("Load should fail"); + } + catch (Exception e) + { + //expected exception + } + + FileTestHelper.assertFileExists(expectedFilename, false); + } + + + /** + * Tests that only the most recent file will be + * loaded into the cache, even if it is already + * expired. Other recently expired files for + * same session should be deleted. + * @throws Exception + */ + @Test + public void testLoadOnlyMostRecentFiles () + throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(100); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + long now = System.currentTimeMillis(); + + //create a file for session abc that expired 5sec ago + long exp = now - 5000L; + String name1 = Long.toString(exp)+"__test_0.0.0.0_abc"; + FileTestHelper.createFile(name1); + + + //create a file for same session that expired 4 sec ago + exp = now - 4000L; + String name2 = Long.toString(exp)+"__test_0.0.0.0_abc"; + FileTestHelper.createFile(name2); + + + //make a file for same session that expired 3 sec ago + exp = now - 3000L; + String name3 = Long.toString(exp)+"__test_0.0.0.0_abc"; + FileTestHelper.createFile(name3); + + store.start(); + + FileTestHelper.assertFileExists(name1, false); + FileTestHelper.assertFileExists(name2, false); + FileTestHelper.assertFileExists(name3, true); + } + } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClusteredLastAccessTimeTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClusteredLastAccessTimeTest.java deleted file mode 100644 index b8472ae0378..00000000000 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClusteredLastAccessTimeTest.java +++ /dev/null @@ -1,59 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.session; - -import org.eclipse.jetty.server.session.AbstractClusteredLastAccessTimeTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.Test; - -/** - * ClusteredLastAccessTimeTest - * - * - */ -public class ClusteredLastAccessTimeTest extends AbstractClusteredLastAccessTimeTest -{ - - @AfterClass - public static void teardown () throws Exception - { - GCloudTestSuite.__testSupport.deleteSessions(); - } - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore()); - } - - @Test - @Override - public void testLastAccessTime() throws Exception - { - super.testLastAccessTime(); - } - - -} diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClusteredSessionMigrationTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClusteredSessionMigrationTest.java deleted file mode 100644 index b69f081ca40..00000000000 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClusteredSessionMigrationTest.java +++ /dev/null @@ -1,56 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.session; - -import org.eclipse.jetty.server.session.AbstractClusteredSessionMigrationTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.Test; - -/** - * ClusteredSessionMigrationTest - * - * - */ -public class ClusteredSessionMigrationTest extends AbstractClusteredSessionMigrationTest -{ - @AfterClass - public static void teardown () throws Exception - { - GCloudTestSuite.__testSupport.deleteSessions(); - } - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore()); - } - - @Test - @Override - public void testSessionMigration() throws Exception - { - super.testSessionMigration(); - } -} diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClusteredSessionScavengingTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClusteredSessionScavengingTest.java index e531ee6cd94..64bfdd05cab 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClusteredSessionScavengingTest.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/ClusteredSessionScavengingTest.java @@ -48,12 +48,5 @@ public class ClusteredSessionScavengingTest extends AbstractClusteredSessionScav return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore()); } - @Test - @Override - public void testLocalSessionsScavenging() throws Exception - { - super.testLocalSessionsScavenging(); - } - - + } diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreTest.java new file mode 100644 index 00000000000..69511b2e038 --- /dev/null +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionDataStoreTest.java @@ -0,0 +1,85 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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.session; + +import org.eclipse.jetty.server.session.AbstractSessionDataStoreTest; +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.server.session.SessionDataStoreFactory; +import org.junit.After; + +/** + * GCloudSessionDataStoreTest + * + * + */ +public class GCloudSessionDataStoreTest extends AbstractSessionDataStoreTest +{ + + @After + public void teardown () throws Exception + { + GCloudTestSuite.__testSupport.deleteSessions(); + } + + + @Override + public SessionDataStoreFactory createSessionDataStoreFactory() + { + return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore()); + } + + + @Override + public void persistSession(SessionData data) throws Exception + { + GCloudTestSuite.__testSupport.createSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(), + data.getAccessed(), data.getLastAccessed(), data.getMaxInactiveMs(), data.getExpiry(), + data.getCookieSet(), data.getLastSaved(), data.getAllAttributes()); + + } + + + @Override + public void persistUnreadableSession(SessionData data) throws Exception + { + + GCloudTestSuite.__testSupport.createSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(), + data.getAccessed(), data.getLastAccessed(), data.getMaxInactiveMs(), data.getExpiry(), + data.getCookieSet(), data.getLastSaved(), null); + } + + + @Override + public boolean checkSessionExists(SessionData data) throws Exception + { + return GCloudTestSuite.__testSupport.checkSessionExists(data.getId()); + } + + + /** + * + */ + @Override + public boolean checkSessionPersisted(SessionData data) throws Exception + { + return GCloudTestSuite.__testSupport.checkSessionPersisted(data); + } + +} diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTestSupport.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTestSupport.java index 626206805d4..f2515f29e27 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTestSupport.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTestSupport.java @@ -21,24 +21,36 @@ package org.eclipse.jetty.gcloud.session; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import org.eclipse.jetty.gcloud.session.GCloudSessionDataStore.EntityDataModel; +import org.eclipse.jetty.server.session.SessionData; import org.eclipse.jetty.server.session.SessionDataStore; import org.eclipse.jetty.server.session.SessionHandler; +import org.eclipse.jetty.util.ClassLoadingObjectInputStream; import org.threeten.bp.Duration; +import com.google.cloud.datastore.Blob; +import com.google.cloud.datastore.BlobValue; import com.google.cloud.datastore.Datastore; import com.google.cloud.datastore.DatastoreOptions; import com.google.cloud.datastore.Entity; import com.google.cloud.datastore.GqlQuery; import com.google.cloud.datastore.Key; +import com.google.cloud.datastore.KeyFactory; import com.google.cloud.datastore.Query; import com.google.cloud.datastore.Query.ResultType; import com.google.cloud.datastore.QueryResults; +import com.google.cloud.datastore.StructuredQuery.PropertyFilter; import com.google.cloud.datastore.testing.LocalDatastoreHelper; /** @@ -50,6 +62,7 @@ public class GCloudSessionTestSupport { LocalDatastoreHelper _helper = LocalDatastoreHelper.create(1.0); Datastore _ds; + KeyFactory _keyFactory; public static class TestGCloudSessionDataStoreFactory extends GCloudSessionDataStoreFactory @@ -82,6 +95,7 @@ public class GCloudSessionTestSupport { DatastoreOptions options = _helper.getOptions(); _ds = options.getService(); + _keyFactory =_ds.newKeyFactory().setKind(EntityDataModel.KIND); } @@ -111,6 +125,103 @@ public class GCloudSessionTestSupport _helper.reset(); } + public void createSession (String id, String contextPath, String vhost, + String lastNode, long created, long accessed, + long lastAccessed, long maxIdle, long expiry, + long cookieset, long lastSaved, + Map attributes) + throws Exception + { + //serialize the attribute map + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + if (attributes != null) + { + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(attributes); + oos.flush(); + } + + //turn a session into an entity + Entity.Builder builder = Entity.newBuilder(_keyFactory.newKey(contextPath+"_"+vhost+"_"+id)) + .set(EntityDataModel.ID, id) + .set(EntityDataModel.CONTEXTPATH, contextPath) + .set(EntityDataModel.VHOST, vhost) + .set(EntityDataModel.ACCESSED, accessed) + .set(EntityDataModel.LASTACCESSED, lastAccessed) + .set(EntityDataModel.CREATETIME, created) + .set(EntityDataModel.COOKIESETTIME, cookieset) + .set(EntityDataModel.LASTNODE, lastNode) + .set(EntityDataModel.EXPIRY, expiry) + .set(EntityDataModel.MAXINACTIVE, maxIdle) + .set(EntityDataModel.LASTSAVED, lastSaved); + if (attributes != null) + builder.set(EntityDataModel.ATTRIBUTES, BlobValue.newBuilder(Blob.copyFrom(baos.toByteArray())).setExcludeFromIndexes(true).build()); + + Entity entity = builder.build(); + + _ds.put(entity); + } + + public boolean checkSessionPersisted (SessionData data) + throws Exception + { + Entity entity = _ds.get(_keyFactory.newKey(data.getContextPath()+"_"+data.getVhost()+"_"+data.getId())); + if (entity == null) + return false; + + //turn an Entity into a Session + assertEquals(data.getId(), entity.getString(EntityDataModel.ID)); + assertEquals(data.getContextPath(), entity.getString(EntityDataModel.CONTEXTPATH)); + assertEquals(data.getVhost(), entity.getString(EntityDataModel.VHOST)); + assertEquals(data.getAccessed(), entity.getLong(EntityDataModel.ACCESSED)); + assertEquals(data.getLastAccessed(), entity.getLong(EntityDataModel.LASTACCESSED)); + assertEquals(data.getCreated(), entity.getLong(EntityDataModel.CREATETIME)); + assertEquals(data.getCookieSet(), entity.getLong(EntityDataModel.COOKIESETTIME)); + assertEquals(data.getLastNode(), entity.getString(EntityDataModel.LASTNODE)); + assertEquals(data.getLastSaved(), entity.getLong(EntityDataModel.LASTSAVED)); + assertEquals(data.getExpiry(), entity.getLong(EntityDataModel.EXPIRY)); + assertEquals(data.getMaxInactiveMs(), entity.getLong(EntityDataModel.MAXINACTIVE)); + Blob blob = (Blob) entity.getBlob(EntityDataModel.ATTRIBUTES); + + Map attributes = new HashMap<>(); + try (ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(blob.asInputStream())) + { + Object o = ois.readObject(); + attributes.putAll((Map)o); + } + + //same number of attributes + assertEquals(data.getAllAttributes().size(), attributes.size()); + //same keys + assertTrue(data.getKeys().equals(attributes.keySet())); + //same values + for (String name:data.getKeys()) + { + assertTrue(data.getAttribute(name).equals(attributes.get(name))); + } + + return true; + } + + + public boolean checkSessionExists (String id) + throws Exception + { + Query query = Query.newEntityQueryBuilder() + .setKind(EntityDataModel.KIND) + .setFilter(PropertyFilter.eq(EntityDataModel.ID, id)) + .build(); + + QueryResults results = _ds.run(query); + + + if (results.hasNext()) + { + return true; + } + + return false; + } public Set getSessionIds () throws Exception { diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudTestSuite.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudTestSuite.java index 61c01f5ee74..22d60b7c10a 100644 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudTestSuite.java +++ b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/GCloudTestSuite.java @@ -31,15 +31,10 @@ import org.junit.runners.Suite; */ @RunWith(Suite.class) @Suite.SuiteClasses({ + GCloudSessionDataStoreTest.class, InvalidationSessionTest.class, - ClusteredLastAccessTimeTest.class, ClusteredSessionScavengingTest.class, - NonClusteredSessionScavengingTest.class, - ClusteredOrphanedSessionTest.class, - SessionExpiryTest.class, - SessionInvalidateCreateScavengeTest.class, - ClusteredSessionMigrationTest.class, - ModifyMaxInactiveIntervalTest.class + ClusteredOrphanedSessionTest.class }) diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/NonClusteredSessionScavengingTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/NonClusteredSessionScavengingTest.java deleted file mode 100644 index 6e98ee60b7b..00000000000 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/NonClusteredSessionScavengingTest.java +++ /dev/null @@ -1,82 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.session; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.util.Set; - -import org.eclipse.jetty.server.session.AbstractNonClusteredSessionScavengingTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; -import org.junit.Test; - -/** - * NonClusteredSessionScavengingTest - * - * - */ -public class NonClusteredSessionScavengingTest extends AbstractNonClusteredSessionScavengingTest -{ - - - @After - public void teardown () throws Exception - { - GCloudTestSuite.__testSupport.deleteSessions(); - } - - - - /** - * @see org.eclipse.jetty.server.session.AbstractNonClusteredSessionScavengingTest#assertSession(java.lang.String, boolean) - */ - @Override - public void assertSession(String id, boolean exists) - { - try - { - Set ids = GCloudTestSuite.__testSupport.getSessionIds(); - if (exists) - assertTrue(ids.contains(id)); - else - assertFalse(ids.contains(id)); - } - catch (Exception e) - { - fail(e.getMessage()); - } - - } - - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore()); - } - -} diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionExpiryTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionExpiryTest.java deleted file mode 100644 index b9cb2c07336..00000000000 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionExpiryTest.java +++ /dev/null @@ -1,75 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.session; - -import org.eclipse.jetty.server.session.AbstractSessionExpiryTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.After; -import org.junit.Assert; -import org.junit.Test; - - -/** - * SessionExpiryTest - * - * - */ -public class SessionExpiryTest extends AbstractSessionExpiryTest -{ - - @After - public void teardown () throws Exception - { - GCloudTestSuite.__testSupport.deleteSessions(); - } - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore()); - } - - - - @Override - public void verifySessionCreated(TestHttpSessionListener listener, String sessionId) - { - super.verifySessionCreated(listener, sessionId); - try {GCloudTestSuite.__testSupport.assertSessions(1);}catch(Exception e){ Assert.fail(e.getMessage());} - } - - - - - @Override - public void verifySessionDestroyed(TestHttpSessionListener listener, String sessionId) - { - super.verifySessionDestroyed(listener, sessionId); - //try{GCloudTestSuite.__testSupport.assertSessions(0);}catch(Exception e) {Assert.fail(e.getMessage());} - } - - - -} diff --git a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionInvalidateCreateScavengeTest.java b/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionInvalidateCreateScavengeTest.java deleted file mode 100644 index 33d5561435e..00000000000 --- a/tests/test-sessions/test-gcloud-sessions/src/test/java/org/eclipse/jetty/gcloud/session/SessionInvalidateCreateScavengeTest.java +++ /dev/null @@ -1,58 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.session; - -import org.eclipse.jetty.server.session.AbstractSessionInvalidateCreateScavengeTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.Test; - -/** - * SessionInvalidateCreateScavengeTest - * - * - */ -public class SessionInvalidateCreateScavengeTest extends AbstractSessionInvalidateCreateScavengeTest -{ - @AfterClass - public static void teardown () throws Exception - { - GCloudTestSuite.__testSupport.deleteSessions(); - } - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore()); - } - - @Test - @Override - public void testSessionScavenge() throws Exception - { - super.testSessionScavenge(); - } - - -} diff --git a/tests/test-sessions/test-hash-sessions/pom.xml b/tests/test-sessions/test-hash-sessions/pom.xml deleted file mode 100644 index a754d6bac9b..00000000000 --- a/tests/test-sessions/test-hash-sessions/pom.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - 4.0.0 - - org.eclipse.jetty.tests - test-sessions-parent - 9.4.10-SNAPSHOT - - test-hash-sessions - Jetty Tests :: Sessions :: Hash - http://www.eclipse.org/jetty - - ${project.groupId}.sessions.hash - - - - - org.apache.maven.plugins - maven-deploy-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.toolchain - jetty-test-helper - - compile - - - diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java deleted file mode 100644 index 4c3f6778b6a..00000000000 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java +++ /dev/null @@ -1,56 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.Test; - -/** - * NonClusteredSessionScavengingTest - */ -public class NonClusteredSessionScavengingTest extends AbstractNonClusteredSessionScavengingTest -{ - - - - /** - * @see org.eclipse.jetty.server.session.AbstractNonClusteredSessionScavengingTest#assertSession(java.lang.String, boolean) - */ - @Override - public void assertSession(String id, boolean exists) - { - //noop, as we do not have a session store - - } - - @Test - @Override - public void testNewSession() throws Exception - { - super.testNewSession(); - } - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return HashTestHelper.newSessionDataStoreFactory(); - } -} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredLastAccessTimeTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredLastAccessTimeTest.java deleted file mode 100644 index c0f672e3ea5..00000000000 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredLastAccessTimeTest.java +++ /dev/null @@ -1,50 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.hazelcast.session; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.server.session.AbstractClusteredLastAccessTimeTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; - -public class ClusteredLastAccessTimeTest - extends AbstractClusteredLastAccessTimeTest -{ - - HazelcastSessionDataStoreFactory factory; - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - factory = new HazelcastSessionDataStoreFactory(); - factory.setMapName( Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ) ); - return factory; - } - - @After - public void shutdown() - { - factory.getHazelcastInstance().getMap( factory.getMapName() ).clear(); - } - -} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredOrphanedSessionTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredOrphanedSessionTest.java index f7eb430e07a..41d542a0c43 100644 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredOrphanedSessionTest.java +++ b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredOrphanedSessionTest.java @@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jetty.server.session.AbstractClusteredOrphanedSessionTest; import org.eclipse.jetty.server.session.SessionDataStoreFactory; import org.junit.After; +import org.junit.Before; /** * ClusteredOrphanedSessionTest @@ -34,20 +35,26 @@ public class ClusteredOrphanedSessionTest HazelcastSessionDataStoreFactory factory; + HazelcastTestHelper _testHelper; + + @Before + public void setUp() + { + _testHelper = new HazelcastTestHelper(); + } + + @After + public void shutdown() + { + _testHelper.tearDown(); + } + /** * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() */ @Override public SessionDataStoreFactory createSessionDataStoreFactory() { - factory = new HazelcastSessionDataStoreFactory(); - factory.setMapName( Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ) ); - return factory; - } - - @After - public void shutdown() - { - factory.getHazelcastInstance().getMap( factory.getMapName() ).clear(); + return _testHelper.createSessionDataStoreFactory(false); } } diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredSessionMigrationTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredSessionMigrationTest.java deleted file mode 100644 index 7303228e950..00000000000 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredSessionMigrationTest.java +++ /dev/null @@ -1,52 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.hazelcast.session; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.server.session.AbstractClusteredSessionMigrationTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; - -/** - * ClusteredSessionMigrationTest - */ -public class ClusteredSessionMigrationTest - extends AbstractClusteredSessionMigrationTest -{ - HazelcastSessionDataStoreFactory factory; - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - factory = new HazelcastSessionDataStoreFactory(); - factory.setMapName( Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ) ); - return factory; - } - - @After - public void shutdown() - { - factory.getHazelcastInstance().getMap( factory.getMapName() ).clear(); - } -} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredSessionScavengingTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredSessionScavengingTest.java index 5a8079bd015..e74e976493e 100644 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredSessionScavengingTest.java +++ b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ClusteredSessionScavengingTest.java @@ -24,6 +24,7 @@ import java.util.concurrent.TimeUnit; import org.eclipse.jetty.server.session.AbstractClusteredSessionScavengingTest; import org.eclipse.jetty.server.session.SessionDataStoreFactory; import org.junit.After; +import org.junit.Before; /** * ClusteredSessionScavengingTest @@ -34,20 +35,27 @@ public class ClusteredSessionScavengingTest HazelcastSessionDataStoreFactory factory; + HazelcastTestHelper _testHelper; + + @Before + public void setUp() + { + _testHelper = new HazelcastTestHelper(); + } + + @After + public void shutdown() + { + _testHelper.tearDown(); + } + /** * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() */ @Override public SessionDataStoreFactory createSessionDataStoreFactory() { - factory = new HazelcastSessionDataStoreFactory(); - factory.setMapName( Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ) ); - return factory; + return _testHelper.createSessionDataStoreFactory(false); } - @After - public void shutdown() - { - factory.getHazelcastInstance().getMap( factory.getMapName() ).clear(); - } } diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreTest.java new file mode 100644 index 00000000000..65951c19a0e --- /dev/null +++ b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreTest.java @@ -0,0 +1,157 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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.hazelcast.session; + +import static org.junit.Assert.fail; + +import org.eclipse.jetty.server.session.AbstractSessionDataStoreFactory; +import org.eclipse.jetty.server.session.AbstractSessionDataStoreTest; +import org.eclipse.jetty.server.session.SessionContext; +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.server.session.SessionDataStore; +import org.eclipse.jetty.server.session.SessionDataStoreFactory; +import org.eclipse.jetty.server.session.UnreadableSessionDataException; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.junit.After; +import org.junit.Before; + +/** + * HazelcastSessionDataStoreTest + * + * + */ +public class HazelcastSessionDataStoreTest extends AbstractSessionDataStoreTest +{ + + HazelcastTestHelper _testHelper; + + + @Override + public SessionDataStoreFactory createSessionDataStoreFactory() + { + return _testHelper.createSessionDataStoreFactory(false); + } + + @Before + public void setUp() + { + _testHelper = new HazelcastTestHelper(); + } + + @After + public void shutdown() + { + _testHelper.tearDown(); + } + + + @Override + public void persistSession(SessionData data) throws Exception + { + _testHelper.createSession(data); + } + + + @Override + public void persistUnreadableSession(SessionData data) throws Exception + { + //not used by testLoadSessionFails() + } + + + @Override + public boolean checkSessionExists(SessionData data) throws Exception + { + return _testHelper.checkSessionExists(data); + } + + /** + * + * This test deliberately sets the sessionDataMap to null + * for the HazelcastSessionDataStore to provoke an exception + * in the load() method. + */ + @Override + public void testLoadSessionFails() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + + //persist a session + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("222", 100, now, now-1, -1); + data.setLastNode(sessionContext.getWorkerName()); + persistSession(data); + + store.start(); + + ((HazelcastSessionDataStore)store).setSessionDataMap(null); + + + //test that loading it fails + try + { + store.load("222"); + fail("Session should be unreadable"); + } + catch (UnreadableSessionDataException e) + { + //expected exception + } + } + + + /** + * This test currently won't work for Hazelcast - there is currently no + * means to query it to find sessions that have expired. + * + */ + @Override + public void testGetExpiredPersistedAndExpiredOnly() throws Exception + { + //ignore + } + + + + + /** + * This test currently won't work for Hazelcast - there is currently no + * means to query it to find sessions that have expired. + */ + @Override + public void testGetExpiredDifferentNode() throws Exception + { + //ignore + } + + @Override + public boolean checkSessionPersisted(SessionData data) throws Exception + { + return _testHelper.checkSessionPersisted(data); + } +} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastTestHelper.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastTestHelper.java new file mode 100644 index 00000000000..2c1180161f7 --- /dev/null +++ b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/HazelcastTestHelper.java @@ -0,0 +1,122 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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.hazelcast.session; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.server.session.SessionDataStoreFactory; + +import com.hazelcast.config.Config; +import com.hazelcast.config.MapConfig; +import com.hazelcast.core.Hazelcast; +import com.hazelcast.core.HazelcastInstance; + +/** + * HazelcastTestHelper + * + * + */ +public class HazelcastTestHelper +{ + static String _hazelcastInstanceName = "SESSION_TEST_"+Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime())); + + static String _name = Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ); + static HazelcastInstance _instance; + static { + MapConfig mapConfig = new MapConfig(); + mapConfig.setName(_name); + Config config = new Config(); + config.setInstanceName(_hazelcastInstanceName ); + config.addMapConfig( mapConfig ); + _instance = Hazelcast.getOrCreateHazelcastInstance( config ); + } + + + public HazelcastTestHelper () + { + // noop + } + + // definitely not thread safe so tests cannot be executed in parallel + // TODO use ThreadContext variable for this Map name + public SessionDataStoreFactory createSessionDataStoreFactory(boolean onlyClient) + { + HazelcastSessionDataStoreFactory factory = new HazelcastSessionDataStoreFactory(); + _name = Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ); + factory.setOnlyClient( onlyClient ); + factory.setMapName(_name); + factory.setHazelcastInstance(_instance); + + return factory; + } + + + public void tearDown() + { + _instance.getMap(_name).clear(); + } + + public void createSession (SessionData data) + { + _instance.getMap(_name).put(data.getContextPath() + "_" + data.getVhost() + "_" + data.getId(), data); + } + + public boolean checkSessionExists (SessionData data) + { + return (_instance.getMap(_name).get(data.getContextPath() + "_" + data.getVhost() + "_" + data.getId()) != null); + } + + public boolean checkSessionPersisted (SessionData data) + { + Object obj = _instance.getMap(_name).get(data.getContextPath() + "_" + data.getVhost() + "_" + data.getId()); + if (obj == null) + return false; + + SessionData saved = (SessionData)obj; + + assertEquals(data.getId(),saved.getId()); + assertEquals(data.getContextPath(), saved.getContextPath()); + assertEquals(data.getVhost(), saved.getVhost()); + assertEquals(data.getLastNode(), saved.getLastNode()); + assertEquals(data.getCreated(), saved.getCreated()); + assertEquals(data.getAccessed(), saved.getAccessed()); + assertEquals(data.getLastAccessed(), saved.getLastAccessed()); + assertEquals(data.getCookieSet(), saved.getCookieSet()); + assertEquals(data.getExpiry(), saved.getExpiry()); + assertEquals(data.getMaxInactiveMs(), saved.getMaxInactiveMs()); + + + //same number of attributes + assertEquals(data.getAllAttributes().size(),saved.getAllAttributes().size()); + //same keys + assertTrue(data.getKeys().equals(saved.getKeys())); + //same values + for (String name:data.getKeys()) + { + assertTrue(data.getAttribute(name).equals(saved.getAttribute(name))); + + } + return true; + } +} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ModifyMaxInactiveIntervalTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ModifyMaxInactiveIntervalTest.java deleted file mode 100644 index 17299dabd2b..00000000000 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/ModifyMaxInactiveIntervalTest.java +++ /dev/null @@ -1,54 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.hazelcast.session; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.server.session.AbstractModifyMaxInactiveIntervalTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; - -/** - * ModifyMaxInactiveIntervalTest - */ -public class ModifyMaxInactiveIntervalTest - extends AbstractModifyMaxInactiveIntervalTest -{ - - HazelcastSessionDataStoreFactory factory; - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - factory = new HazelcastSessionDataStoreFactory(); - factory.setMapName( Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ) ); - return factory; - } - - @After - public void shutdown() - { - factory.getHazelcastInstance().getMap( factory.getMapName() ).clear(); - } - -} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/NonClusteredSessionScavengingTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/NonClusteredSessionScavengingTest.java deleted file mode 100644 index 48feedd8641..00000000000 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/NonClusteredSessionScavengingTest.java +++ /dev/null @@ -1,81 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.hazelcast.session; - -import org.eclipse.jetty.server.session.AbstractNonClusteredSessionScavengingTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; - -import static org.junit.Assert.*; - -import java.util.concurrent.TimeUnit; - -/** - * NonClusteredSessionScavengingTest - */ -public class NonClusteredSessionScavengingTest - extends AbstractNonClusteredSessionScavengingTest -{ - - HazelcastSessionDataStoreFactory factory; - - /** - * @see org.eclipse.jetty.server.session.AbstractNonClusteredSessionScavengingTest#assertSession(java.lang.String, boolean) - */ - @Override - public void assertSession( String id, boolean exists ) - { - assertNotNull( _dataStore ); - - try - { - boolean inmap = _dataStore.exists( id ); - if ( exists ) - { - assertTrue( inmap ); - } - else - { - assertFalse( inmap ); - } - } - catch ( Exception e ) - { - fail( e.getMessage() ); - } - } - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - factory = new HazelcastSessionDataStoreFactory(); - factory.setMapName( Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ) ); - return factory; - } - - @After - public void shutdown() - { - factory.getHazelcastInstance().getMap( factory.getMapName() ).clear(); - } -} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/SessionExpiryTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/SessionExpiryTest.java deleted file mode 100644 index 25d68ec76d7..00000000000 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/SessionExpiryTest.java +++ /dev/null @@ -1,52 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.hazelcast.session; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.server.session.AbstractSessionExpiryTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; -import org.junit.Test; - -public class SessionExpiryTest - extends AbstractSessionExpiryTest -{ - - HazelcastSessionDataStoreFactory factory; - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - factory = new HazelcastSessionDataStoreFactory(); - factory.setMapName( Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ) ); - return factory; - } - - @After - public void shutdown() - { - factory.getHazelcastInstance().getMap( factory.getMapName() ).clear(); - } - -} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/SessionInvalidateCreateScavengeTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/SessionInvalidateCreateScavengeTest.java deleted file mode 100644 index c95fe4b8729..00000000000 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/SessionInvalidateCreateScavengeTest.java +++ /dev/null @@ -1,53 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.hazelcast.session; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.server.session.AbstractSessionInvalidateCreateScavengeTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; - -/** - * SessionInvalidateCreateScavengeTest - */ -public class SessionInvalidateCreateScavengeTest - extends AbstractSessionInvalidateCreateScavengeTest -{ - - HazelcastSessionDataStoreFactory factory; - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - factory = new HazelcastSessionDataStoreFactory(); - factory.setMapName( Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ) ); - return factory; - } - - @After - public void shutdown() - { - factory.getHazelcastInstance().getMap( factory.getMapName() ).clear(); - } -} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientLastAccessTimeTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientLastAccessTimeTest.java deleted file mode 100644 index b36945b205b..00000000000 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientLastAccessTimeTest.java +++ /dev/null @@ -1,71 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.hazelcast.session.client; - -import com.hazelcast.config.Config; -import com.hazelcast.config.MapConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.hazelcast.session.HazelcastSessionDataStoreFactory; -import org.eclipse.jetty.server.session.AbstractClusteredLastAccessTimeTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; -import org.junit.Before; - -public class ClientLastAccessTimeTest - extends AbstractClusteredLastAccessTimeTest -{ - - private static final String MAP_NAME = Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ); - - private HazelcastInstance hazelcastInstance; - - @Before - public void startHazelcast() - throws Exception - { - Config config = new Config().addMapConfig( new MapConfig().setName( MAP_NAME ) ) // - .setInstanceName( Long.toString( System.currentTimeMillis() ) ); - // start Hazelcast instance - hazelcastInstance = Hazelcast.getOrCreateHazelcastInstance( config ); - } - - @After - public void stopHazelcast() - throws Exception - { - hazelcastInstance.shutdown(); - } - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - HazelcastSessionDataStoreFactory factory = new HazelcastSessionDataStoreFactory(); - factory.setOnlyClient( true ); - factory.setMapName( MAP_NAME ); - return factory; - } - -} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientModifyMaxInactiveIntervalTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientModifyMaxInactiveIntervalTest.java deleted file mode 100644 index df120b05f5d..00000000000 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientModifyMaxInactiveIntervalTest.java +++ /dev/null @@ -1,75 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.hazelcast.session.client; - -import com.hazelcast.config.Config; -import com.hazelcast.config.MapConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.hazelcast.session.HazelcastSessionDataStoreFactory; -import org.eclipse.jetty.server.session.AbstractModifyMaxInactiveIntervalTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; -import org.junit.Before; - -/** - * ModifyMaxInactiveIntervalTest - */ -public class ClientModifyMaxInactiveIntervalTest - extends AbstractModifyMaxInactiveIntervalTest -{ - - private static final String MAP_NAME = Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ); - - private HazelcastInstance hazelcastInstance; - - @Before - public void startHazelcast() - throws Exception - { - Config config = new Config().addMapConfig( new MapConfig().setName( MAP_NAME ) ) // - .setInstanceName( Long.toString( System.currentTimeMillis() ) ); - // start Hazelcast instance - hazelcastInstance = Hazelcast.getOrCreateHazelcastInstance( config ); - } - - @After - public void stopHazelcast() - throws Exception - { - hazelcastInstance.shutdown(); - } - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - HazelcastSessionDataStoreFactory factory = new HazelcastSessionDataStoreFactory(); - factory.setOnlyClient( true ); - factory.setMapName( MAP_NAME ); - return factory; - } - -} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientNonClusteredSessionScavengingTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientNonClusteredSessionScavengingTest.java deleted file mode 100644 index d555a941662..00000000000 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientNonClusteredSessionScavengingTest.java +++ /dev/null @@ -1,98 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.hazelcast.session.client; - -import com.hazelcast.config.Config; -import com.hazelcast.config.MapConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; -import org.eclipse.jetty.hazelcast.session.HazelcastSessionDataStoreFactory; -import org.eclipse.jetty.server.session.AbstractNonClusteredSessionScavengingTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; -import org.junit.Before; - -import static org.junit.Assert.*; - -import java.util.concurrent.TimeUnit; - -public class ClientNonClusteredSessionScavengingTest - extends AbstractNonClusteredSessionScavengingTest -{ - - /** - * @see AbstractNonClusteredSessionScavengingTest#assertSession(String, boolean) - */ - @Override - public void assertSession( String id, boolean exists ) - { - assertNotNull( _dataStore ); - - try - { - boolean inmap = _dataStore.exists( id ); - if ( exists ) - { - assertTrue( inmap ); - } - else - { - assertFalse( inmap ); - } - } - catch ( Exception e ) - { - fail( e.getMessage() ); - } - } - private static final String MAP_NAME = Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ); - - private HazelcastInstance hazelcastInstance; - - @Before - public void startHazelcast() - throws Exception - { - Config config = new Config().addMapConfig( new MapConfig().setName( MAP_NAME ) ) // - .setInstanceName( Long.toString( System.currentTimeMillis() ) ); - // start Hazelcast instance - hazelcastInstance = Hazelcast.getOrCreateHazelcastInstance( config ); - } - - @After - public void stopHazelcast() - throws Exception - { - hazelcastInstance.shutdown(); - } - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - HazelcastSessionDataStoreFactory factory = new HazelcastSessionDataStoreFactory(); - factory.setOnlyClient( true ); - factory.setMapName( MAP_NAME ); - return factory; - } -} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientOrphanedSessionTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientOrphanedSessionTest.java index 4b2ddba9ca2..d083476195a 100644 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientOrphanedSessionTest.java +++ b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientOrphanedSessionTest.java @@ -27,6 +27,7 @@ import com.hazelcast.core.HazelcastInstance; import java.util.concurrent.TimeUnit; import org.eclipse.jetty.hazelcast.session.HazelcastSessionDataStoreFactory; +import org.eclipse.jetty.hazelcast.session.HazelcastTestHelper; import org.eclipse.jetty.server.session.AbstractClusteredOrphanedSessionTest; import org.eclipse.jetty.server.session.SessionDataStoreFactory; import org.junit.After; @@ -36,37 +37,24 @@ public class ClientOrphanedSessionTest extends AbstractClusteredOrphanedSessionTest { - private static final String MAP_NAME = Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ); + HazelcastTestHelper _testHelper; - private HazelcastInstance hazelcastInstance; - - @Before - public void startHazelcast() - throws Exception - { - Config config = new Config().addMapConfig( new MapConfig().setName( MAP_NAME ) ) // - .setInstanceName( Long.toString( System.currentTimeMillis() ) ); - // start Hazelcast instance - hazelcastInstance = Hazelcast.getOrCreateHazelcastInstance( config ); - } - - @After - public void stopHazelcast() - throws Exception - { - hazelcastInstance.shutdown(); - } - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ @Override public SessionDataStoreFactory createSessionDataStoreFactory() { - HazelcastSessionDataStoreFactory factory = new HazelcastSessionDataStoreFactory(); - factory.setOnlyClient( true ); - factory.setMapName( MAP_NAME ); - return factory; + return _testHelper.createSessionDataStoreFactory(true); + } + + @Before + public void setUp() + { + _testHelper = new HazelcastTestHelper(); + } + + @After + public void shutdown() + { + _testHelper.tearDown(); } } diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientSessionExpiryTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientSessionExpiryTest.java deleted file mode 100644 index 63e5ee28e5d..00000000000 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientSessionExpiryTest.java +++ /dev/null @@ -1,73 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.hazelcast.session.client; - -import com.hazelcast.config.Config; -import com.hazelcast.config.MapConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.hazelcast.session.HazelcastSessionDataStoreFactory; -import org.eclipse.jetty.server.session.AbstractSessionExpiryTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; -import org.junit.Before; - -public class ClientSessionExpiryTest - extends AbstractSessionExpiryTest -{ - - private static final String MAP_NAME = Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ); - - private HazelcastInstance hazelcastInstance; - - @Before - public void startHazelcast() - throws Exception - { - Config config = new Config().addMapConfig( new MapConfig().setName( MAP_NAME ) ) // - .setInstanceName( Long.toString( System.currentTimeMillis() ) ); - // start Hazelcast instance - hazelcastInstance = Hazelcast.getOrCreateHazelcastInstance( config ); - } - - @After - public void stopHazelcast() - throws Exception - { - hazelcastInstance.shutdown(); - } - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - HazelcastSessionDataStoreFactory factory = new HazelcastSessionDataStoreFactory(); - factory.setOnlyClient( true ); - factory.setMapName( MAP_NAME ); - return factory; - } - -} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientSessionInvalidateCreateScavengeTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientSessionInvalidateCreateScavengeTest.java deleted file mode 100644 index 402246b8e5e..00000000000 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientSessionInvalidateCreateScavengeTest.java +++ /dev/null @@ -1,71 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.hazelcast.session.client; - -import com.hazelcast.config.Config; -import com.hazelcast.config.MapConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.hazelcast.session.HazelcastSessionDataStoreFactory; -import org.eclipse.jetty.server.session.AbstractSessionInvalidateCreateScavengeTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; -import org.junit.Before; - -public class ClientSessionInvalidateCreateScavengeTest - extends AbstractSessionInvalidateCreateScavengeTest -{ - private static final String MAP_NAME = Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ); - - private HazelcastInstance hazelcastInstance; - - @Before - public void startHazelcast() - throws Exception - { - Config config = new Config().addMapConfig( new MapConfig().setName( MAP_NAME ) ) // - .setInstanceName( Long.toString( System.currentTimeMillis() ) ); - // start Hazelcast instance - hazelcastInstance = Hazelcast.getOrCreateHazelcastInstance( config ); - } - - @After - public void stopHazelcast() - throws Exception - { - hazelcastInstance.shutdown(); - } - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - HazelcastSessionDataStoreFactory factory = new HazelcastSessionDataStoreFactory(); - factory.setOnlyClient( true ); - factory.setMapName( MAP_NAME ); - return factory; - } -} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientSessionMigrationTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientSessionMigrationTest.java deleted file mode 100644 index 24da1e67372..00000000000 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientSessionMigrationTest.java +++ /dev/null @@ -1,74 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.hazelcast.session.client; - -import com.hazelcast.config.Config; -import com.hazelcast.config.MapConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; - -import java.util.concurrent.TimeUnit; - -import org.eclipse.jetty.hazelcast.session.HazelcastSessionDataStoreFactory; -import org.eclipse.jetty.server.session.AbstractClusteredSessionMigrationTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.After; -import org.junit.Before; - -/** - * ClusteredSessionMigrationTest - */ -public class ClientSessionMigrationTest - extends AbstractClusteredSessionMigrationTest -{ - private static final String MAP_NAME = Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ); - - private HazelcastInstance hazelcastInstance; - - @Before - public void startHazelcast() - throws Exception - { - Config config = new Config().addMapConfig( new MapConfig().setName( MAP_NAME ) ) // - .setInstanceName( Long.toString( System.currentTimeMillis() ) ); - // start Hazelcast instance - hazelcastInstance = Hazelcast.getOrCreateHazelcastInstance( config ); - } - - @After - public void stopHazelcast() - throws Exception - { - hazelcastInstance.shutdown(); - } - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - HazelcastSessionDataStoreFactory factory = new HazelcastSessionDataStoreFactory(); - factory.setOnlyClient( true ); - factory.setMapName( MAP_NAME ); - return factory; - } -} diff --git a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientSessionScavengingTest.java b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientSessionScavengingTest.java index 42f808f9603..5873ef73cf1 100644 --- a/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientSessionScavengingTest.java +++ b/tests/test-sessions/test-hazelcast-sessions/src/test/java/org/eclipse/jetty/hazelcast/session/client/ClientSessionScavengingTest.java @@ -27,6 +27,7 @@ import com.hazelcast.core.HazelcastInstance; import java.util.concurrent.TimeUnit; import org.eclipse.jetty.hazelcast.session.HazelcastSessionDataStoreFactory; +import org.eclipse.jetty.hazelcast.session.HazelcastTestHelper; import org.eclipse.jetty.server.session.AbstractClusteredSessionScavengingTest; import org.eclipse.jetty.server.session.SessionDataStoreFactory; import org.junit.After; @@ -36,37 +37,23 @@ public class ClientSessionScavengingTest extends AbstractClusteredSessionScavengingTest { - private static final String MAP_NAME = Long.toString( TimeUnit.NANOSECONDS.toMillis(System.nanoTime()) ); + HazelcastTestHelper _testHelper; - private HazelcastInstance hazelcastInstance; - - @Before - public void startHazelcast() - throws Exception - { - Config config = new Config().addMapConfig( new MapConfig().setName( MAP_NAME ) ) // - .setInstanceName( Long.toString( System.currentTimeMillis() ) ); - // start Hazelcast instance - hazelcastInstance = Hazelcast.getOrCreateHazelcastInstance( config ); - } - - @After - public void stopHazelcast() - throws Exception - { - hazelcastInstance.shutdown(); - } - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ @Override public SessionDataStoreFactory createSessionDataStoreFactory() { - HazelcastSessionDataStoreFactory factory = new HazelcastSessionDataStoreFactory(); - factory.setOnlyClient( true ); - factory.setMapName( MAP_NAME ); - return factory; + return _testHelper.createSessionDataStoreFactory(true); + } + + @Before + public void setUp() + { + _testHelper = new HazelcastTestHelper(); + } + + @After + public void shutdown() + { + _testHelper.tearDown(); } } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredLastAccessTimeTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredLastAccessTimeTest.java deleted file mode 100644 index 6ca3c92c30b..00000000000 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredLastAccessTimeTest.java +++ /dev/null @@ -1,62 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; -import org.eclipse.jetty.toolchain.test.JDK; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -public class ClusteredLastAccessTimeTest extends AbstractClusteredLastAccessTimeTest -{ - public static InfinispanTestSupport __testSupport; - - @BeforeClass - public static void setup () throws Exception - { - __testSupport = new InfinispanTestSupport(); - __testSupport.setUseFileStore(true); - __testSupport.setup(); - } - - @AfterClass - public static void teardown () throws Exception - { - if (__testSupport != null) - __testSupport.teardown(); - } - - - @Override - public void testLastAccessTime() throws Exception - { - super.testLastAccessTime(); - } - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); - factory.setCache(__testSupport.getCache()); - return factory; - } -} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionMigrationTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionMigrationTest.java deleted file mode 100644 index 8594ddceb87..00000000000 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionMigrationTest.java +++ /dev/null @@ -1,68 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -/** - * ClusteredSessionMigrationTest - * - * - */ -public class ClusteredSessionMigrationTest extends AbstractClusteredSessionMigrationTest -{ - - 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.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); - factory.setCache(__testSupport.getCache()); - return factory; - } - - @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/ClusteredSessionScavengingTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionScavengingTest.java index 276993cb4c1..f7480eda284 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionScavengingTest.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionScavengingTest.java @@ -20,7 +20,6 @@ package org.eclipse.jetty.server.session; import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; -import org.eclipse.jetty.toolchain.test.JDK; import org.junit.AfterClass; import org.junit.BeforeClass; diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanSessionDataStoreTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanSessionDataStoreTest.java new file mode 100644 index 00000000000..0f75137daea --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanSessionDataStoreTest.java @@ -0,0 +1,158 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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.fail; + +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStore; +import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; +import org.junit.After; +import org.junit.Before; + +/** + * InfinispanSessionDataStoreTest + * + * + */ +public class InfinispanSessionDataStoreTest extends AbstractSessionDataStoreTest +{ + + public InfinispanTestSupport __testSupport; + + @Before + public void setup () throws Exception + { + __testSupport = new InfinispanTestSupport(); + __testSupport.setup(); + } + + @After + public void teardown () throws Exception + { + __testSupport.teardown(); + } + + + @Override + public SessionDataStoreFactory createSessionDataStoreFactory() + { + InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); + factory.setCache(__testSupport.getCache()); + return factory; + } + + + @Override + public void persistSession(SessionData data) throws Exception + { + __testSupport.createSession(data); + + } + + + @Override + public void persistUnreadableSession(SessionData data) throws Exception + { + //Not used by testLoadSessionFails() + } + + + @Override + public boolean checkSessionExists(SessionData data) throws Exception + { + return __testSupport.checkSessionExists(data); + } + + /** + * This test deliberately sets the infinispan cache to null to + * try and provoke an exception in the InfinispanSessionDataStore.load() method. + */ + @Override + public void testLoadSessionFails() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + + //persist a session + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("222", 100, now, now-1, -1); + data.setLastNode(sessionContext.getWorkerName()); + persistSession(data); + + store.start(); + + ((InfinispanSessionDataStore)store).setCache(null); + + + //test that loading it fails + try + { + store.load("222"); + fail("Session should be unreadable"); + } + catch (UnreadableSessionDataException e) + { + //expected exception + } + } + + + /** + * This test currently won't work for Infinispan - there is currently no + * means to query it to find sessions that have expired. + * + * @see org.eclipse.jetty.server.session.AbstractSessionDataStoreTest#testGetExpiredPersistedAndExpiredOnly() + */ + @Override + public void testGetExpiredPersistedAndExpiredOnly() throws Exception + { + + } + + + + /** + * This test won't work for Infinispan - there is currently no + * means to query infinispan to find other expired sessions. + */ + @Override + public void testGetExpiredDifferentNode() throws Exception + { + //Ignore + } + + /** + * + */ + @Override + public boolean checkSessionPersisted(SessionData data) throws Exception + { + return __testSupport.checkSessionPersisted(data); + } + +} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSupport.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSupport.java index d5a1c1d214e..e3a1fa9ec12 100644 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSupport.java +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/InfinispanTestSupport.java @@ -19,6 +19,9 @@ package org.eclipse.jetty.server.session; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.io.File; import org.eclipse.jetty.util.IO; @@ -104,6 +107,7 @@ public class InfinispanTestSupport public void teardown () throws Exception { + _cache.clear(); _manager.removeCache(_name); if (_useFileStore) { @@ -113,4 +117,62 @@ public class InfinispanTestSupport } } } + + + @SuppressWarnings("unchecked") + public void createSession (SessionData data) + throws Exception + { + _cache.put(data.getContextPath()+"_"+data.getVhost()+"_"+data.getId(), data); + } + + + public void createUnreadableSession (SessionData data) + { + + } + + + public boolean checkSessionExists (SessionData data) + throws Exception + { + return (_cache.get(data.getContextPath()+"_"+data.getVhost()+"_"+data.getId()) != null); + } + + + public boolean checkSessionPersisted (SessionData data) + throws Exception + { + Object obj = _cache.get(data.getContextPath()+"_"+data.getVhost()+"_"+data.getId()); + if (obj == null) + return false; + + SessionData saved = (SessionData)obj; + + + //turn an Entity into a Session + assertEquals(data.getId(), saved.getId()); + assertEquals(data.getContextPath(), saved.getContextPath()); + assertEquals(data.getVhost(), saved.getVhost()); + assertEquals(data.getAccessed(), saved.getAccessed()); + assertEquals(data.getLastAccessed(), saved.getLastAccessed()); + assertEquals(data.getCreated(), saved.getCreated()); + assertEquals(data.getCookieSet(), saved.getCookieSet()); + assertEquals(data.getLastNode(), saved.getLastNode()); + //don't test lastSaved, because that is set only on the SessionData after it returns from SessionDataStore.save() + assertEquals(data.getExpiry(), saved.getExpiry()); + assertEquals(data.getMaxInactiveMs(), saved.getMaxInactiveMs()); + + //same number of attributes + assertEquals(data.getAllAttributes().size(), saved.getAllAttributes().size()); + //same keys + assertTrue(data.getKeys().equals(saved.getKeys())); + //same values + for (String name:data.getKeys()) + { + assertTrue(data.getAttribute(name).equals(saved.getAttribute(name))); + } + + return true; + } } diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java deleted file mode 100644 index 9f980964d4c..00000000000 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java +++ /dev/null @@ -1,61 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -/** - * ModifyMaxInactiveIntervalTest - * - * - */ -public class ModifyMaxInactiveIntervalTest extends AbstractModifyMaxInactiveIntervalTest -{ - 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.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); - factory.setCache(__testSupport.getCache()); - return factory; - } - -} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java deleted file mode 100644 index 712f09a4cd5..00000000000 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java +++ /dev/null @@ -1,91 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.fail; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - - - -import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -/** - * NonClusteredSessionScavengingTest - * - * - */ -public class NonClusteredSessionScavengingTest extends AbstractNonClusteredSessionScavengingTest -{ - - 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.AbstractNonClusteredSessionScavengingTest#assertSession(java.lang.String, boolean) - */ - @Override - public void assertSession(String id, boolean exists) - { - assertNotNull(_dataStore); - - try - { - boolean inmap = _dataStore.exists(id); - if (exists) - assertTrue(inmap); - else - assertFalse(inmap); - } - catch (Exception e) - { - fail(e.getMessage()); - } - } - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); - factory.setCache(__testSupport.getCache()); - return factory; - } -} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java deleted file mode 100644 index 6908821fd4f..00000000000 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java +++ /dev/null @@ -1,76 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; - -public class SessionExpiryTest extends AbstractSessionExpiryTest -{ - - 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.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); - factory.setCache(__testSupport.getCache()); - return factory; - } - - @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/SessionInvalidateCreateScavengeTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateCreateScavengeTest.java deleted file mode 100644 index 764117cddf1..00000000000 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateCreateScavengeTest.java +++ /dev/null @@ -1,70 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -/** - * SessionInvalidateCreateScavengeTest - * - * - */ -public class SessionInvalidateCreateScavengeTest extends AbstractSessionInvalidateCreateScavengeTest -{ - 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.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); - factory.setCache(__testSupport.getCache()); - return factory; - } - - @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/ModifyMaxInactiveIntervalTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/ModifyMaxInactiveIntervalTest.java deleted file mode 100644 index f44586c8917..00000000000 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/ModifyMaxInactiveIntervalTest.java +++ /dev/null @@ -1,63 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.AbstractModifyMaxInactiveIntervalTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -/** - * ModifyMaxInactiveIntervalTest - * - * - */ -public class ModifyMaxInactiveIntervalTest extends AbstractModifyMaxInactiveIntervalTest -{ - 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.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); - factory.setCache(__testSupport.getCache()); - return factory; - } - -} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/NonClusteredSessionScavengingTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/NonClusteredSessionScavengingTest.java deleted file mode 100644 index 67d078fa718..00000000000 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/NonClusteredSessionScavengingTest.java +++ /dev/null @@ -1,94 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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 static org.junit.Assert.fail; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - - - -import org.eclipse.jetty.server.session.AbstractNonClusteredSessionScavengingTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -/** - * NonClusteredSessionScavengingTest - * - * - */ -public class NonClusteredSessionScavengingTest extends AbstractNonClusteredSessionScavengingTest -{ - - 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.AbstractNonClusteredSessionScavengingTest#assertSession(java.lang.String, boolean) - */ - @Override - public void assertSession(String id, boolean exists) - { - assertNotNull(_dataStore); - - try - { - boolean inmap = _dataStore.exists(id); - if (exists) - assertTrue(inmap); - else - assertFalse(inmap); - } - catch (Exception e) - { - fail(e.getMessage()); - } - } - - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); - factory.setCache(__testSupport.getCache()); - return factory; - } -} diff --git a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClusteredLastAccessTimeTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClusteredLastAccessTimeTest.java deleted file mode 100644 index 08f08d90b22..00000000000 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClusteredLastAccessTimeTest.java +++ /dev/null @@ -1,65 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.AbstractClusteredLastAccessTimeTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -public class RemoteClusteredLastAccessTimeTest extends AbstractClusteredLastAccessTimeTest -{ - 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.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); - factory.setCache(__testSupport.getCache()); - return factory; - } - - @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/RemoteClusteredSessionMigrationTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClusteredSessionMigrationTest.java deleted file mode 100644 index 4e1577d35d9..00000000000 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteClusteredSessionMigrationTest.java +++ /dev/null @@ -1,71 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.AbstractClusteredSessionMigrationTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -/** - * RemoteClusteredSessionMigrationTest - * - * - */ -public class RemoteClusteredSessionMigrationTest extends AbstractClusteredSessionMigrationTest -{ - - 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.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); - factory.setCache(__testSupport.getCache()); - return factory; - } - - @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/RemoteInfinispanSessionDataStoreTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInfinispanSessionDataStoreTest.java new file mode 100644 index 00000000000..d7227e2b909 --- /dev/null +++ b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteInfinispanSessionDataStoreTest.java @@ -0,0 +1,169 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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 static org.junit.Assert.fail; + +import org.eclipse.jetty.server.session.AbstractSessionDataStoreFactory; +import org.eclipse.jetty.server.session.AbstractSessionDataStoreTest; +import org.eclipse.jetty.server.session.SessionContext; +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.server.session.SessionDataStore; +import org.eclipse.jetty.server.session.SessionDataStoreFactory; +import org.eclipse.jetty.server.session.UnreadableSessionDataException; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStore; +import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; +import org.junit.After; +import org.junit.Before; + +/** + * RemoteInfinispanSessionDataStoreTest + * + * + */ +public class RemoteInfinispanSessionDataStoreTest extends AbstractSessionDataStoreTest +{ + + public static RemoteInfinispanTestSupport __testSupport; + + + + + @Before + public void setup () throws Exception + { + __testSupport = new RemoteInfinispanTestSupport("remote-session-test"); + __testSupport.setup(); + } + + @After + public void teardown () throws Exception + { + __testSupport.teardown(); + } + + + + @Override + public SessionDataStoreFactory createSessionDataStoreFactory() + { + InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); + factory.setCache(__testSupport.getCache()); + return factory; + } + + + @Override + public void persistSession(SessionData data) throws Exception + { + __testSupport.createSession(data); + + } + + + @Override + public void persistUnreadableSession(SessionData data) throws Exception + { + //Not used by testLoadSessionFails() + } + + + @Override + public boolean checkSessionExists(SessionData data) throws Exception + { + return __testSupport.checkSessionExists(data); + } + + + @Override + public boolean checkSessionPersisted(SessionData data) throws Exception + { + return __testSupport.checkSessionPersisted(data); + } + + + + /** + * This test currently won't work for Infinispan - there is currently no + * means to query it to find sessions that have expired. + * + * @see org.eclipse.jetty.server.session.AbstractSessionDataStoreTest#testGetExpiredPersistedAndExpiredOnly() + */ + @Override + public void testGetExpiredPersistedAndExpiredOnly() throws Exception + { + + } + + + + /** + * This test won't work for Infinispan - there is currently no + * means to query infinispan to find other expired sessions. + */ + @Override + public void testGetExpiredDifferentNode() throws Exception + { + //Ignore + } + + + /** + * This test deliberately sets the infinispan cache to null to + * try and provoke an exception in the InfinispanSessionDataStore.load() method. + */ + @Override + public void testLoadSessionFails() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + + //persist a session + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("222", 100, now, now-1, -1); + data.setLastNode(sessionContext.getWorkerName()); + persistSession(data); + + store.start(); + + ((InfinispanSessionDataStore)store).setCache(null); + + + //test that loading it fails + try + { + store.load("222"); + fail("Session should be unreadable"); + } + catch (UnreadableSessionDataException e) + { + //expected exception + } + } + +} 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 index 9b29bae5887..bac7841f49a 100644 --- 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 @@ -19,6 +19,10 @@ package org.eclipse.jetty.server.session.remote; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.eclipse.jetty.server.session.SessionData; import org.infinispan.client.hotrod.RemoteCache; import org.infinispan.client.hotrod.RemoteCacheManager; @@ -73,7 +77,65 @@ public class RemoteInfinispanTestSupport public void teardown () throws Exception + { + _cache.clear(); + } + + + + @SuppressWarnings("unchecked") + public void createSession (SessionData data) + throws Exception + { + _cache.put(data.getContextPath()+"_"+data.getVhost()+"_"+data.getId(), data); + } + + + public void createUnreadableSession (SessionData data) { } + + + public boolean checkSessionExists (SessionData data) + throws Exception + { + return (_cache.get(data.getContextPath()+"_"+data.getVhost()+"_"+data.getId()) != null); + } + + + public boolean checkSessionPersisted (SessionData data) + throws Exception + { + Object obj = _cache.get(data.getContextPath()+"_"+data.getVhost()+"_"+data.getId()); + if (obj == null) + return false; + + SessionData saved = (SessionData)obj; + + assertEquals(data.getId(), saved.getId()); + assertEquals(data.getContextPath(), saved.getContextPath()); + assertEquals(data.getVhost(), saved.getVhost()); + assertEquals(data.getAccessed(), saved.getAccessed()); + assertEquals(data.getLastAccessed(), saved.getLastAccessed()); + assertEquals(data.getCreated(), saved.getCreated()); + assertEquals(data.getCookieSet(), saved.getCookieSet()); + assertEquals(data.getLastNode(), saved.getLastNode()); + //don't test lastSaved because that is set on SessionData only after return from SessionDataStore.save() + assertEquals(data.getExpiry(), saved.getExpiry()); + assertEquals(data.getMaxInactiveMs(), saved.getMaxInactiveMs()); + + //same number of attributes + assertEquals(data.getAllAttributes().size(), saved.getAllAttributes().size()); + //same keys + assertTrue(data.getKeys().equals(saved.getKeys())); + //same values + for (String name:data.getKeys()) + { + assertTrue(data.getAttribute(name).equals(saved.getAttribute(name))); + } + + return true; + } + } 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 deleted file mode 100644 index b455c50a870..00000000000 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionExpiryTest.java +++ /dev/null @@ -1,78 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.SessionDataStoreFactory; -import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; -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(); - } - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); - factory.setCache(__testSupport.getCache()); - return factory; - } - - @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/RemoteSessionInvalidateCreateScavengeTest.java b/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionInvalidateCreateScavengeTest.java deleted file mode 100644 index 10c461df415..00000000000 --- a/tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/remote/RemoteSessionInvalidateCreateScavengeTest.java +++ /dev/null @@ -1,72 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.AbstractSessionInvalidateCreateScavengeTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.eclipse.jetty.session.infinispan.InfinispanSessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -/** - * SessionInvalidateCreateScavengeTest - * - * - */ -public class RemoteSessionInvalidateCreateScavengeTest extends AbstractSessionInvalidateCreateScavengeTest -{ - 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.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - InfinispanSessionDataStoreFactory factory = new InfinispanSessionDataStoreFactory(); - factory.setCache(__testSupport.getCache()); - return factory; - } - - @Override - public void testSessionScavenge() throws Exception - { - super.testSessionScavenge(); - } - - - -} diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredInvalidationSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredInvalidationSessionTest.java index 0b2bf8a7867..afd5ca9b147 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredInvalidationSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredInvalidationSessionTest.java @@ -28,13 +28,6 @@ import org.junit.Test; public class ClusteredInvalidationSessionTest extends AbstractClusteredInvalidationSessionTest { - @Test - @Override - public void testInvalidation() throws Exception - { - super.testInvalidation(); - } - @After public void tearDown() throws Exception diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredOrphanedSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredOrphanedSessionTest.java index 62f6ed69944..d5418686919 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredOrphanedSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredOrphanedSessionTest.java @@ -35,12 +35,7 @@ public class ClusteredOrphanedSessionTest extends AbstractClusteredOrphanedSessi return JdbcTestHelper.newSessionDataStoreFactory(); } - @Test - @Override - public void testOrphanedSession() throws Exception - { - super.testOrphanedSession(); - } + @After public void tearDown() throws Exception diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionMigrationTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionMigrationTest.java index 3df023019fd..f8f88582fee 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionMigrationTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionMigrationTest.java @@ -18,33 +18,152 @@ package org.eclipse.jetty.server.session; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.io.PrintWriter; + +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.After; import org.junit.Test; /** * ClusteredSessionMigrationTest + * + * Test that a session that is active on node 1 can be loaded by node 2. + * + * This test is applicable to any of the SessionDataStores that support + * clustering, but does not test the actual SessionDataStore itself. + * Rather, it tests all of the machinery above the SessionDataStore. Thus, + * to reduce test time, we only apply it to the JDBCSessionDataStore. */ -public class ClusteredSessionMigrationTest extends AbstractClusteredSessionMigrationTest +public class ClusteredSessionMigrationTest extends AbstractTestBase { - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ + @Override public SessionDataStoreFactory createSessionDataStoreFactory() { return JdbcTestHelper.newSessionDataStoreFactory(); } - @Test - @Override - public void testSessionMigration() throws Exception - { - super.testSessionMigration(); - } + @After public void tearDown() throws Exception { JdbcTestHelper.shutdown(null); + } + + @Test + public void testSessionMigration() throws Exception + { + String contextPath = "/"; + String servletMapping = "/server"; + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(TestServer.DEFAULT_SCAVENGE_SEC); + + TestServer server1 = new TestServer(0, TestServer.DEFAULT_MAX_INACTIVE, TestServer.DEFAULT_SCAVENGE_SEC, + cacheFactory, storeFactory); + server1.addContext(contextPath).addServlet(TestServlet.class, servletMapping); + + try + { + server1.start(); + int port1=server1.getPort(); + + TestServer server2 = new TestServer(0, TestServer.DEFAULT_MAX_INACTIVE, TestServer.DEFAULT_SCAVENGE_SEC, + cacheFactory, storeFactory); + server2.addContext(contextPath).addServlet(TestServlet.class, servletMapping); + + try + { + server2.start(); + int port2=server2.getPort(); + + HttpClient client = new HttpClient(); + client.start(); + try + { + // Perform one request to server1 to create a session + int value = 1; + Request request1 = client.POST("http://localhost:" + port1 + contextPath + servletMapping.substring(1) + "?action=set&value=" + value); + ContentResponse response1 = request1.send(); + assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); + String sessionCookie = response1.getHeaders().get("Set-Cookie"); + assertTrue(sessionCookie != null); + // Mangle the cookie, replacing Path with $Path, etc. + sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); + + // Perform a request to server2 using the session cookie from the previous request + // This should migrate the session from server1 to server2. + Request request2 = client.newRequest("http://localhost:" + port2 + contextPath + servletMapping.substring(1) + "?action=get"); + request2.header("Cookie", sessionCookie); + ContentResponse response2 = request2.send(); + assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); + String response = response2.getContentAsString(); + assertEquals(response.trim(),String.valueOf(value)); } + finally + { + client.stop(); + } + } + finally + { + server2.stop(); + } + } + finally + { + server1.stop(); + } + } + + public static class TestServlet extends HttpServlet + { + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + doPost(request, response); + } + + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + HttpSession session = request.getSession(false); + + String action = request.getParameter("action"); + if ("set".equals(action)) + { + if (session == null) session = request.getSession(true); + int value = Integer.parseInt(request.getParameter("value")); + session.setAttribute("value", value); + PrintWriter writer = response.getWriter(); + writer.println(value); + writer.flush(); + } + else if ("get".equals(action)) + { + int value = (Integer)session.getAttribute("value"); + int x = session.getMaxInactiveInterval(); + assertTrue(x > 0); + PrintWriter writer = response.getWriter(); + writer.println(value); + writer.flush(); + } + } } } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionScavengingTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionScavengingTest.java index 622567ef4f0..71894280099 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionScavengingTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionScavengingTest.java @@ -19,31 +19,12 @@ package org.eclipse.jetty.server.session; import org.junit.After; -import org.junit.Test; /** * ClusteredSessionScavengingTest */ public class ClusteredSessionScavengingTest extends AbstractClusteredSessionScavengingTest { - @Override - public void pause (int scavenge) - { - //Wait a little longer for the scavenging to happen with the JDBCSession handling. - //The scavenging happens at about +10% longer than the scavenge interval, so that - //not all nodes sync up and start trying to scavenge for the same sessions at the - //same time. - //So, we wait 3 times the scavenging interval. - try - { - Thread.sleep(scavenge * 3000); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - } - /** * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() */ @@ -53,21 +34,6 @@ public class ClusteredSessionScavengingTest extends AbstractClusteredSessionScav return JdbcTestHelper.newSessionDataStoreFactory(); } - @Test - @Override - public void testNoScavenging() throws Exception - { - super.testNoScavenging(); - } - - - @Test - @Override - public void testLocalSessionsScavenging() throws Exception - { - super.testLocalSessionsScavenging(); - } - @After public void tearDown() throws Exception diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JDBCSessionDataStoreTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JDBCSessionDataStoreTest.java new file mode 100644 index 00000000000..4dd91ea48e8 --- /dev/null +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JDBCSessionDataStoreTest.java @@ -0,0 +1,95 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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.After; +import org.junit.Before; + +/** + * JDBCSessionDataStoreTest + * + * + */ +public class JDBCSessionDataStoreTest extends AbstractSessionDataStoreTest +{ + + @Before + public void setUp() throws Exception + { + JdbcTestHelper.prepareTables(); + } + + + @After + public void tearDown() throws Exception + { + JdbcTestHelper.shutdown(null); + } + + + + @Override + public SessionDataStoreFactory createSessionDataStoreFactory() + { + return JdbcTestHelper.newSessionDataStoreFactory(); + } + + + @Override + public void persistSession(SessionData data) + throws Exception + { + JdbcTestHelper.insertSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), + data.getCreated(), data.getAccessed(), data.getLastAccessed(), + data.getMaxInactiveMs(), data.getExpiry(), data.getCookieSet(), + data.getLastSaved(), data.getAllAttributes()); + + } + + + + @Override + public void persistUnreadableSession(SessionData data) throws Exception + { + JdbcTestHelper.insertSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), + data.getCreated(), data.getAccessed(), data.getLastAccessed(), + data.getMaxInactiveMs(), data.getExpiry(), data.getCookieSet(), + data.getLastSaved(), null); + + } + + + + + @Override + public boolean checkSessionExists(SessionData data) throws Exception + { + return JdbcTestHelper.existsInSessionTable(data.getId(), false); + } + + + + @Override + public boolean checkSessionPersisted(SessionData data) throws Exception + { + return JdbcTestHelper.checkSessionPersisted(data); + } + +} diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestHelper.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestHelper.java index 62d74425de4..6eae13e7cef 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestHelper.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/JdbcTestHelper.java @@ -20,19 +20,25 @@ package org.eclipse.jetty.server.session; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.ObjectOutputStream; +import java.sql.Blob; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; +import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; -import org.eclipse.jetty.server.SessionIdManager; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.util.ClassLoadingObjectInputStream; /** * JdbcTestHelper @@ -124,6 +130,18 @@ public class JdbcTestHelper sessionTableSchema.setMaxIntervalColumn(MAX_IDLE_COL); return sessionTableSchema; } + + + public static void prepareTables () throws SQLException + { + DatabaseAdaptor da = new DatabaseAdaptor(); + da.setDriverInfo(DRIVER_CLASS, DEFAULT_CONNECTION_URL); + JDBCSessionDataStore.SessionTableSchema sessionTableSchema = newSessionTableSchema(); + sessionTableSchema.setDatabaseAdaptor(da); + + sessionTableSchema.prepareTables(); + + } public static boolean existsInSessionTable(String id, boolean verbose) throws Exception @@ -158,6 +176,71 @@ public class JdbcTestHelper } + @SuppressWarnings("unchecked") + public static boolean checkSessionPersisted (SessionData data) + throws Exception + { + Class.forName(DRIVER_CLASS); + PreparedStatement statement = null; + ResultSet result = null; + try (Connection con=DriverManager.getConnection(DEFAULT_CONNECTION_URL);) + { + statement = con.prepareStatement("select * from "+TABLE+ + " where "+ID_COL+" = ? and "+CONTEXT_COL+ + " = ? and virtualHost = ?"); + statement.setString(1, data.getId()); + statement.setString(2, data.getContextPath()); + statement.setString(3, data.getVhost()); + + result = statement.executeQuery(); + + if (!result.next()) + return false; + + + assertEquals(data.getCreated(),result.getLong(CREATE_COL)); + assertEquals(data.getAccessed(), result.getLong(ACCESS_COL)); + assertEquals(data.getLastAccessed(), result.getLong(LAST_ACCESS_COL)); + assertEquals(data.getMaxInactiveMs(), result.getLong(MAX_IDLE_COL)); + + assertEquals(data.getCookieSet(), result.getLong(COOKIE_COL)); + assertEquals(data.getLastNode(), result.getString(LAST_NODE_COL)); + + assertEquals(data.getExpiry(), result.getLong(EXPIRY_COL)); + assertEquals(data.getContextPath(), result.getString(CONTEXT_COL)); + assertEquals(data.getVhost(), result.getString("virtualHost")); + + Map attributes = new HashMap<>(); + Blob blob = result.getBlob(MAP_COL); + + try (InputStream is = blob.getBinaryStream(); + ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(is)) + { + Object o = ois.readObject(); + attributes.putAll((Map)o); + } + + //same number of attributes + assertEquals(data.getAllAttributes().size(), attributes.size()); + //same keys + assertTrue(data.getKeys().equals(attributes.keySet())); + //same values + for (String name:data.getKeys()) + { + assertTrue(data.getAttribute(name).equals(attributes.get(name))); + } + } + finally + { + if (result != null) + result.close(); + if (statement != null) + statement.close(); + } + + return true; + } + public static void insertSession (String id, String contextPath, String vhost) throws Exception { @@ -189,6 +272,58 @@ public class JdbcTestHelper } + public static void insertSession (String id, String contextPath, String vhost, + String lastNode, long created, long accessed, + long lastAccessed, long maxIdle, long expiry, + long cookieSet, long lastSaved, Map attributes) + throws Exception + { + Class.forName(DRIVER_CLASS); + try (Connection con=DriverManager.getConnection(DEFAULT_CONNECTION_URL);) + { + PreparedStatement statement = con.prepareStatement("insert into "+TABLE+ + " ("+ID_COL+", "+CONTEXT_COL+", virtualHost, "+LAST_NODE_COL+ + ", "+ACCESS_COL+", "+LAST_ACCESS_COL+", "+CREATE_COL+", "+COOKIE_COL+ + ", "+LAST_SAVE_COL+", "+EXPIRY_COL+", "+MAX_IDLE_COL+","+MAP_COL+" ) "+ + " values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + + statement.setString(1, id); + statement.setString(2, contextPath); + statement.setString(3, vhost); + statement.setString(4, lastNode); + + statement.setLong(5, accessed); + statement.setLong(6, lastAccessed); + statement.setLong(7, created); + statement.setLong(8, cookieSet); + + statement.setLong(9, lastSaved); + statement.setLong(10, expiry); + statement.setLong(11, maxIdle); + + if (attributes != null) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + Map emptyMap = Collections.emptyMap(); + oos.writeObject(emptyMap); + oos.flush(); + byte[] bytes = baos.toByteArray(); + + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + statement.setBinaryStream(12, bais, bytes.length);//attribute map as blob + } + else + statement.setBinaryStream(12, new ByteArrayInputStream("".getBytes()), 0); + + statement.execute(); + assertEquals(1,statement.getUpdateCount()); + } + } + + + + public static Set getSessionIds () throws Exception { diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java deleted file mode 100644 index 06c507d7d5e..00000000000 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java +++ /dev/null @@ -1,74 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - - - -import org.junit.After; -import org.junit.Test; - - -/** - * NonClusteredSessionScavengingTest - */ -public class NonClusteredSessionScavengingTest extends AbstractNonClusteredSessionScavengingTest -{ - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return JdbcTestHelper.newSessionDataStoreFactory(); - } - - - /** - * @see org.eclipse.jetty.server.session.AbstractNonClusteredSessionScavengingTest#assertSession(java.lang.String, boolean) - */ - @Override - public void assertSession(String id, boolean exists) - { - try - { - boolean inDb = JdbcTestHelper.existsInSessionTable(id, false); - if (exists) - assertTrue(inDb); - else - assertFalse(inDb); - } - catch (Exception e) - { - fail(e.getMessage()); - } - } - - - @After - public void tearDown() throws Exception - { - JdbcTestHelper.shutdown(null); - } - -} diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java deleted file mode 100644 index a0193544951..00000000000 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ProxySerializationTest.java +++ /dev/null @@ -1,69 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.eclipse.jetty.servlet.ServletContextHandler; -import org.junit.After; -import org.junit.Test; - -/** - * ProxySerializationTest - * - * - */ -public class ProxySerializationTest extends AbstractProxySerializationTest -{ - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return JdbcTestHelper.newSessionDataStoreFactory(); - } - - - - /** - * @see org.eclipse.jetty.server.session.AbstractProxySerializationTest#customizeContext(org.eclipse.jetty.servlet.ServletContextHandler) - */ - @Override - public void customizeContext(ServletContextHandler c) - { - } - - - - @Test - @Override - public void testProxySerialization() throws Exception - { - super.testProxySerialization(); - } - - - - @After - public void tearDown() throws Exception - { - JdbcTestHelper.shutdown(null); - } -} diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java index cc4d00b5b54..81a9bb9327b 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ReloadedSessionMissingClassTest.java @@ -19,9 +19,9 @@ package org.eclipse.jetty.server.session; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertFalse; import java.io.File; import java.io.FileWriter; diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java deleted file mode 100644 index b36ef2dfca5..00000000000 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/SessionExpiryTest.java +++ /dev/null @@ -1,80 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.StacklessLogging; -import org.junit.After; -import org.junit.Test; - -/** - * SessionExpiryTest - * - * - * - */ -public class SessionExpiryTest extends AbstractSessionExpiryTest -{ - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return JdbcTestHelper.newSessionDataStoreFactory(); - } - - - @Test - @Override - public void testSessionExpiry() throws Exception - { - try(StacklessLogging stackless=new StacklessLogging(Log.getLogger("org.eclipse.jetty.server.session"))) - { - super.testSessionExpiry(); - } - } - - /** - * @see org.eclipse.jetty.server.session.AbstractSessionExpiryTest#testSessionExpiresWithListener() - */ - @Test - @Override - public void testSessionExpiresWithListener() throws Exception - { - super.testSessionExpiresWithListener(); - } - - - - @Test - @Override - public void testSessionNotExpired() throws Exception - { - super.testSessionNotExpired(); - } - - @After - public void tearDown() throws Exception - { - JdbcTestHelper.shutdown(null); - } - -} diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java index 51f63d0cd83..a84cd46fe6f 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/WebAppObjectInSessionTest.java @@ -42,7 +42,6 @@ public class WebAppObjectInSessionTest extends AbstractWebAppObjectInSessionTest @Test - @Override public void testWebappObjectInSession() throws Exception { super.testWebappObjectInSession(); diff --git a/tests/test-sessions/test-mongodb-sessions/pom.xml b/tests/test-sessions/test-mongodb-sessions/pom.xml index b6db6e4f89e..4b4d21d7e38 100644 --- a/tests/test-sessions/test-mongodb-sessions/pom.xml +++ b/tests/test-sessions/test-mongodb-sessions/pom.xml @@ -11,6 +11,7 @@ http://www.eclipse.org/jetty ${project.groupId}.sessions.mongo + localhost @@ -110,9 +111,50 @@ org.apache.maven.plugins maven-surefire-plugin + + ${embedmongo.port} + ${embedmongo.host} + false + + com.github.joelittlejohn.embedmongo + embedmongo-maven-plugin + 0.3.5 + + + + true + + ${project.build.directory}/mongotest + + + file + + ${project.build.directory}/embedmongo.log + + + + false + + + + start + process-test-classes + + start + + + + stop + test + + stop + + + +
diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/AttributeNameTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/AttributeNameTest.java index b6c5746519e..cc27d036c0b 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/AttributeNameTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/AttributeNameTest.java @@ -117,7 +117,7 @@ public class AttributeNameTest //Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=","$1\\$Path="); - //Make a request to the 2nd server which will do a refresh, use TestServlet to ensure that the + //Make a request to the 2nd server which will do a refresh, use TestFooServlet to ensure that the //session attribute with dotted name is not removed Request request2 = client.newRequest("http://localhost:" + port2 + contextPath + servletMapping + "?action=get"); request2.header("Cookie", sessionCookie); diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClusteredLastAccessTimeTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClusteredLastAccessTimeTest.java deleted file mode 100644 index 61f56399038..00000000000 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClusteredLastAccessTimeTest.java +++ /dev/null @@ -1,64 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.nosql.mongodb; - -import org.eclipse.jetty.server.session.AbstractClusteredLastAccessTimeTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; - -public class ClusteredLastAccessTimeTest extends AbstractClusteredLastAccessTimeTest -{ - - - @BeforeClass - public static void beforeClass() throws Exception - { - MongoTestHelper.dropCollection(); - MongoTestHelper.createCollection(); - } - - @AfterClass - public static void afterClass() throws Exception - { - MongoTestHelper.dropCollection(); - } - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return MongoTestHelper.newSessionDataStoreFactory(); - } - - - - @Test - @Override - public void testLastAccessTime() throws Exception - { - super.testLastAccessTime(); - } - - -} diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClusteredSessionMigrationTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClusteredSessionMigrationTest.java deleted file mode 100644 index 8e55d890f8e..00000000000 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClusteredSessionMigrationTest.java +++ /dev/null @@ -1,61 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.nosql.mongodb; - -import org.eclipse.jetty.server.session.AbstractClusteredSessionMigrationTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; - -public class ClusteredSessionMigrationTest extends AbstractClusteredSessionMigrationTest -{ - - - @BeforeClass - public static void beforeClass() throws Exception - { - MongoTestHelper.dropCollection(); - MongoTestHelper.createCollection(); - } - - @AfterClass - public static void afterClass() throws Exception - { - MongoTestHelper.dropCollection(); - } - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return MongoTestHelper.newSessionDataStoreFactory(); - } - - - - @Test - @Override - public void testSessionMigration() throws Exception - { - super.testSessionMigration(); - } -} diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClusteredSessionScavengingTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClusteredSessionScavengingTest.java index aac912a9683..2ad2afb238a 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClusteredSessionScavengingTest.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ClusteredSessionScavengingTest.java @@ -49,13 +49,4 @@ public class ClusteredSessionScavengingTest extends AbstractClusteredSessionScav return MongoTestHelper.newSessionDataStoreFactory(); } - - @Override - public void testLocalSessionsScavenging() throws Exception - { - super.testLocalSessionsScavenging(); - } - - - } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ModifyMaxInactiveIntervalTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ModifyMaxInactiveIntervalTest.java deleted file mode 100644 index 47c344e3bc9..00000000000 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/ModifyMaxInactiveIntervalTest.java +++ /dev/null @@ -1,57 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.nosql.mongodb; - -import org.eclipse.jetty.server.session.AbstractModifyMaxInactiveIntervalTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -/** - * ModifyMaxInactiveIntervalTest - * - * - */ -public class ModifyMaxInactiveIntervalTest extends AbstractModifyMaxInactiveIntervalTest -{ - - @BeforeClass - public static void beforeClass() throws Exception - { - MongoTestHelper.dropCollection(); - MongoTestHelper.createCollection(); - } - - @AfterClass - public static void afterClass() throws Exception - { - MongoTestHelper.dropCollection(); - } - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return MongoTestHelper.newSessionDataStoreFactory(); - } - -} diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreTest.java new file mode 100644 index 00000000000..891ec64a164 --- /dev/null +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoSessionDataStoreTest.java @@ -0,0 +1,84 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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.nosql.mongodb; + +import org.eclipse.jetty.server.session.AbstractSessionDataStoreTest; +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.server.session.SessionDataStoreFactory; +import org.junit.After; +import org.junit.Before; + +/** + * MongoSessionDataStoreTest + * + * + */ +public class MongoSessionDataStoreTest extends AbstractSessionDataStoreTest +{ + @Before + public void beforeClass() throws Exception + { + MongoTestHelper.dropCollection(); + MongoTestHelper.createCollection(); + } + + @After + public void afterClass() throws Exception + { + MongoTestHelper.dropCollection(); + } + + + @Override + public SessionDataStoreFactory createSessionDataStoreFactory() + { + return MongoTestHelper.newSessionDataStoreFactory(); + } + + + @Override + public void persistSession(SessionData data) throws Exception + { + MongoTestHelper.createSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(), + data.getAccessed(), data.getLastAccessed(), data.getMaxInactiveMs(), data.getExpiry(), data.getAllAttributes()); + } + + + @Override + public void persistUnreadableSession(SessionData data) throws Exception + { + MongoTestHelper.createUnreadableSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(), + data.getAccessed(), data.getLastAccessed(), data.getMaxInactiveMs(), data.getExpiry(), null); + } + + + @Override + public boolean checkSessionExists(SessionData data) throws Exception + { + return MongoTestHelper.checkSessionExists(data.getId()); + } + + + @Override + public boolean checkSessionPersisted(SessionData data) throws Exception + { + return MongoTestHelper.checkSessionPersisted(data); + } +} diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTest.java deleted file mode 100644 index 7c91b0f0dcf..00000000000 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTest.java +++ /dev/null @@ -1,64 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.nosql.mongodb; - -import java.util.Set; - -import com.mongodb.BasicDBObject; -import com.mongodb.DB; -import com.mongodb.DBCollection; -import com.mongodb.DBObject; -import com.mongodb.Mongo; -import com.mongodb.WriteResult; - -public class MongoTest -{ - public static void main(String... args) throws Exception - { - Mongo m = new Mongo( "127.0.0.1" , 27017 ); - - DB db = m.getDB( "mydb" ); - - Set colls = db.getCollectionNames(); - - System.err.println("Colls="+colls); - - DBCollection coll = db.getCollection("testCollection"); - - - BasicDBObject key = new BasicDBObject("id","1234"); - BasicDBObject sets = new BasicDBObject("name","value"); - BasicDBObject upsert=new BasicDBObject("$set",sets); - - WriteResult result =coll.update(key,upsert,true,false); - - System.err.println(result.getLastError()); - - - while (coll.count()>0) - { - DBObject docZ = coll.findOne(); - System.err.println("removing "+ docZ); - if (docZ!=null) - coll.remove(docZ); - } - - - } -} diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestHelper.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestHelper.java index 62872c31ea4..619f141d212 100644 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestHelper.java +++ b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/MongoTestHelper.java @@ -18,11 +18,30 @@ package org.eclipse.jetty.nosql.mongodb; -import java.net.UnknownHostException; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.net.UnknownHostException; +import java.sql.Date; +import java.util.HashMap; +import java.util.Map; + +import com.mongodb.MongoClient; +import org.eclipse.jetty.nosql.NoSqlSessionDataStore.NoSqlSessionData; +import org.eclipse.jetty.server.session.SessionData; + +import com.mongodb.BasicDBObject; import com.mongodb.DBCollection; +import com.mongodb.DBObject; import com.mongodb.Mongo; import com.mongodb.MongoException; +import com.mongodb.WriteConcern; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; /** @@ -31,35 +50,240 @@ import com.mongodb.MongoException; */ public class MongoTestHelper { + private final static Logger LOG = Log.getLogger(MongoTestHelper.class); static int __workers=0; public static final String DB_NAME = "HttpSessions"; public static final String COLLECTION_NAME = "testsessions"; - + + static MongoClient _mongoClient; + static + { + try + { + _mongoClient = + new MongoClient( System.getProperty( "embedmongo.host" ), Integer.getInteger( "embedmongoPort" ) ); + } + catch ( UnknownHostException e ) + { + e.printStackTrace(); + } + } public static void dropCollection () throws MongoException, UnknownHostException { - new Mongo().getDB(DB_NAME).getCollection(COLLECTION_NAME).drop(); + _mongoClient.getDB(DB_NAME).getCollection(COLLECTION_NAME).drop(); } public static void createCollection() throws UnknownHostException, MongoException { - new Mongo().getDB(DB_NAME).createCollection(COLLECTION_NAME, null); + _mongoClient.getDB(DB_NAME).createCollection(COLLECTION_NAME, null); } public static DBCollection getCollection () throws UnknownHostException, MongoException { - return new Mongo().getDB(DB_NAME).getCollection(COLLECTION_NAME); + return _mongoClient.getDB(DB_NAME).getCollection(COLLECTION_NAME); } public static MongoSessionDataStoreFactory newSessionDataStoreFactory() { MongoSessionDataStoreFactory storeFactory = new MongoSessionDataStoreFactory(); + storeFactory.setHost( System.getProperty( "embedmongoHost" ) ); + storeFactory.setPort( Integer.getInteger( "embedmongoPort" ) ); storeFactory.setCollectionName(COLLECTION_NAME); storeFactory.setDbName(DB_NAME); return storeFactory; } + + + public static boolean checkSessionExists (String id) + throws Exception + { + DBCollection collection = _mongoClient.getDB(DB_NAME).getCollection(COLLECTION_NAME); + + DBObject fields = new BasicDBObject(); + fields.put(MongoSessionDataStore.__EXPIRY, 1); + fields.put(MongoSessionDataStore.__VALID, 1); + + DBObject sessionDocument = collection.findOne(new BasicDBObject(MongoSessionDataStore.__ID, id), fields); + + if (sessionDocument == null) + return false; //doesn't exist + + return true; + } + + + public static boolean checkSessionPersisted (SessionData data) + throws Exception + { + DBCollection collection = _mongoClient.getDB(DB_NAME).getCollection(COLLECTION_NAME); + + DBObject fields = new BasicDBObject(); + + DBObject sessionDocument = collection.findOne(new BasicDBObject(MongoSessionDataStore.__ID, data.getId()), fields); + if (sessionDocument == null) + return false; //doesn't exist + + LOG.info("{}",sessionDocument); + + Boolean valid = (Boolean)sessionDocument.get(MongoSessionDataStore.__VALID); + + + if (valid == null || !valid) + return false; + + Long created = (Long)sessionDocument.get(MongoSessionDataStore.__CREATED); + Long accessed = (Long)sessionDocument.get(MongoSessionDataStore.__ACCESSED); + Long lastAccessed = (Long)sessionDocument.get(MongoSessionDataStore.__LAST_ACCESSED); + Long maxInactive = (Long)sessionDocument.get(MongoSessionDataStore.__MAX_IDLE); + Long expiry = (Long)sessionDocument.get(MongoSessionDataStore.__EXPIRY); + + Object version = MongoUtils.getNestedValue(sessionDocument, + MongoSessionDataStore.__CONTEXT + "." + data.getVhost().replace('.', '_') + ":" + data.getContextPath() +"."+MongoSessionDataStore.__VERSION); + Long lastSaved = (Long)MongoUtils.getNestedValue(sessionDocument, + MongoSessionDataStore.__CONTEXT + "." + data.getVhost().replace('.', '_') + ":" + data.getContextPath() +"."+MongoSessionDataStore.__LASTSAVED); + String lastNode = (String)MongoUtils.getNestedValue(sessionDocument, + MongoSessionDataStore.__CONTEXT + "." + data.getVhost().replace('.', '_') + ":" + data.getContextPath() +"."+MongoSessionDataStore.__LASTNODE); + + + LOG.info("DA:{} MA:{}", data.getAccessed(), accessed); + LOG.info("DLA:{} DLA:{}",data.getLastAccessed(),lastAccessed); + assertEquals(data.getCreated(), created.longValue()); + assertEquals(data.getAccessed(), accessed.longValue()); + assertEquals(data.getLastAccessed(), lastAccessed.longValue()); + assertEquals(data.getMaxInactiveMs(), maxInactive.longValue()); + assertEquals(data.getExpiry(), expiry.longValue()); + assertEquals(data.getLastNode(), lastNode); + assertNotNull(version); + assertNotNull(lastSaved); + + // get the session for the context + DBObject sessionSubDocumentForContext = + (DBObject)MongoUtils.getNestedValue(sessionDocument, + MongoSessionDataStore.__CONTEXT + "." + data.getVhost().replace('.', '_') + ":" + data.getContextPath()); + + assertNotNull(sessionSubDocumentForContext); + + Map attributes = new HashMap<>(); + for (String name : sessionSubDocumentForContext.keySet()) + { + //skip special metadata attribute which is not one of the actual session attributes + if (MongoSessionDataStore.__METADATA.equals(name) ) + continue; + String attr = MongoUtils.decodeName(name); + Object value = MongoUtils.decodeValue(sessionSubDocumentForContext.get(name)); + attributes.put(attr, value); + } + + //same keys + assertTrue(data.getKeys().equals(attributes.keySet())); + //same values + for (String name:data.getKeys()) + { + assertTrue(data.getAttribute(name).equals(attributes.get(name))); + } + + + return true; + } + + public static void createUnreadableSession (String id, String contextPath, String vhost, + String lastNode, long created, long accessed, + long lastAccessed, long maxIdle, long expiry, + Map attributes) + throws Exception + { + DBCollection collection = _mongoClient.getDB(DB_NAME).getCollection(COLLECTION_NAME); + + // Form query for upsert + BasicDBObject key = new BasicDBObject(MongoSessionDataStore.__ID, id); + + // Form updates + BasicDBObject update = new BasicDBObject(); + boolean upsert = false; + BasicDBObject sets = new BasicDBObject(); + + Object version = new Long(1); + + // New session + + upsert = true; + sets.put(MongoSessionDataStore.__CREATED,created); + sets.put(MongoSessionDataStore.__VALID,true); + sets.put(MongoSessionDataStore.__CONTEXT + "." + vhost.replace('.', '_') + ":" + contextPath +"."+MongoSessionDataStore.__VERSION,version); + sets.put(MongoSessionDataStore.__CONTEXT + "." + vhost.replace('.', '_') + ":" + contextPath +"."+MongoSessionDataStore.__LASTSAVED, System.currentTimeMillis()); + sets.put(MongoSessionDataStore.__CONTEXT + "." + vhost.replace('.', '_') + ":" + contextPath +"."+MongoSessionDataStore.__LASTNODE, lastNode); + + //Leaving out __MAX_IDLE to make it an invalid session object! + + sets.put(MongoSessionDataStore.__EXPIRY, expiry); + sets.put(MongoSessionDataStore.__ACCESSED, accessed); + sets.put(MongoSessionDataStore.__LAST_ACCESSED, lastAccessed); + + if (attributes != null) + { + for (String name : attributes.keySet()) + { + Object value = attributes.get(name); + sets.put(MongoSessionDataStore.__CONTEXT + "." + vhost.replace('.', '_') + ":" + contextPath+ "." + MongoUtils.encodeName(name), + MongoUtils.encodeName(value)); + } + } + update.put("$set",sets); + collection.update(key,update,upsert,false,WriteConcern.SAFE); + } + + + public static void createSession (String id, String contextPath, String vhost, + String lastNode, long created, long accessed, + long lastAccessed, long maxIdle, long expiry, + Map attributes) + throws Exception + { + + DBCollection collection = _mongoClient.getDB(DB_NAME).getCollection(COLLECTION_NAME); + + // Form query for upsert + BasicDBObject key = new BasicDBObject(MongoSessionDataStore.__ID, id); + + // Form updates + BasicDBObject update = new BasicDBObject(); + boolean upsert = false; + BasicDBObject sets = new BasicDBObject(); + + Object version = new Long(1); + + // New session + upsert = true; + sets.put(MongoSessionDataStore.__CREATED,created); + sets.put(MongoSessionDataStore.__VALID,true); + sets.put(MongoSessionDataStore.__CONTEXT + "." + vhost.replace('.', '_') + ":" + contextPath +"."+MongoSessionDataStore.__VERSION,version); + sets.put(MongoSessionDataStore.__CONTEXT + "." + vhost.replace('.', '_') + ":" + contextPath +"."+MongoSessionDataStore.__LASTSAVED, System.currentTimeMillis()); + sets.put(MongoSessionDataStore.__CONTEXT + "." + vhost.replace('.', '_') + ":" + contextPath +"."+MongoSessionDataStore.__LASTNODE, lastNode); + sets.put(MongoSessionDataStore.__MAX_IDLE, maxIdle); + sets.put(MongoSessionDataStore.__EXPIRY, expiry); + sets.put(MongoSessionDataStore.__ACCESSED, accessed); + sets.put(MongoSessionDataStore.__LAST_ACCESSED, lastAccessed); + + if (attributes != null) + { + for (String name : attributes.keySet()) + { + Object value = attributes.get(name); + sets.put(MongoSessionDataStore.__CONTEXT + "." + vhost.replace('.', '_') + ":" + contextPath+ "." + MongoUtils.encodeName(name), + MongoUtils.encodeName(value)); + } + } + update.put("$set",sets); + collection.update(key,update,upsert,false,WriteConcern.SAFE); + } + + + + + } diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/NonClusteredSessionScavengingTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/NonClusteredSessionScavengingTest.java deleted file mode 100644 index 0dd005ad43d..00000000000 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/NonClusteredSessionScavengingTest.java +++ /dev/null @@ -1,84 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.nosql.mongodb; - -import static org.junit.Assert.fail; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - - -import org.eclipse.jetty.server.session.AbstractNonClusteredSessionScavengingTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; - -/** - * NonClusteredSessionScavengingTest - */ -public class NonClusteredSessionScavengingTest extends AbstractNonClusteredSessionScavengingTest -{ - - @BeforeClass - public static void beforeClass() throws Exception - { - MongoTestHelper.dropCollection(); - MongoTestHelper.createCollection(); - } - - @AfterClass - public static void afterClass() throws Exception - { - MongoTestHelper.dropCollection(); - } - - - - - - /** - * @see org.eclipse.jetty.server.session.AbstractNonClusteredSessionScavengingTest#assertSession(java.lang.String, boolean) - */ - @Override - public void assertSession(String id, boolean exists) - { - assertNotNull(_dataStore); - try - { - boolean inmap = _dataStore.exists(id); - if (exists) - assertTrue(inmap); - else - assertFalse(inmap); - } - catch (Exception e) - { - fail(e.getMessage()); - } - } - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return MongoTestHelper.newSessionDataStoreFactory(); - } -} diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionDump.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionDump.java deleted file mode 100644 index 461e6bc4e84..00000000000 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionDump.java +++ /dev/null @@ -1,188 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.nosql.mongodb; - - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Date; -import java.util.Enumeration; - -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - - -/* ------------------------------------------------------------ */ -/** Test Servlet Sessions. - * - * - */ -public class SessionDump extends HttpServlet -{ - - int redirectCount=0; - /* ------------------------------------------------------------ */ - String pageType; - - /* ------------------------------------------------------------ */ - @Override - public void init(ServletConfig config) - throws ServletException - { - super.init(config); - } - - /* ------------------------------------------------------------ */ - protected void handleForm(HttpServletRequest request, - HttpServletResponse response) - { - HttpSession session = request.getSession(false); - String action = request.getParameter("Action"); - String name = request.getParameter("Name"); - String value = request.getParameter("Value"); - - if (action!=null) - { - if(action.equals("New Session")) - { - session = request.getSession(true); - session.setAttribute("test","value"); - } - else if (session!=null) - { - if (action.equals("Invalidate")) - session.invalidate(); - else if (action.equals("Set") && name!=null && name.length()>0) - session.setAttribute(name,value); - else if (action.equals("Remove")) - session.removeAttribute(name); - } - } - } - - /* ------------------------------------------------------------ */ - @Override - public void doPost(HttpServletRequest request, - HttpServletResponse response) - throws ServletException, IOException - { - handleForm(request,response); - String nextUrl = getURI(request)+"?R="+redirectCount++; - String encodedUrl=response.encodeRedirectURL(nextUrl); - response.sendRedirect(encodedUrl); - } - - /* ------------------------------------------------------------ */ - @Override - public void doGet(HttpServletRequest request, - HttpServletResponse response) - throws ServletException, IOException - { - handleForm(request,response); - - response.setContentType("text/html"); - - HttpSession session = request.getSession(getURI(request).indexOf("new")>0); - try - { - if (session!=null) - session.isNew(); - } - catch(IllegalStateException e) - { - session=null; - } - - PrintWriter out = response.getWriter(); - out.println("

Session Dump Servlet:

"); - out.println("
"); - - if (session==null) - { - out.println("

No Session

"); - out.println(""); - } - else - { - try - { - out.println("ID: "+session.getId()+"
"); - out.println("New: "+session.isNew()+"
"); - out.println("Created: "+new Date(session.getCreationTime())+"
"); - out.println("Last: "+new Date(session.getLastAccessedTime())+"
"); - out.println("Max Inactive: "+session.getMaxInactiveInterval()+"
"); - out.println("Context: "+session.getServletContext()+"
"); - - - Enumeration keys=session.getAttributeNames(); - while(keys.hasMoreElements()) - { - String name=(String)keys.nextElement(); - String value=""+session.getAttribute(name); - - out.println(""+name+": "+value+"
"); - } - - out.println("Name:
"); - out.println("Value:
"); - - out.println(""); - out.println(""); - out.println(""); - out.println("
"); - - out.println("

"); - - if (request.isRequestedSessionIdFromCookie()) - out.println("

Turn off cookies in your browser to try url encoding
"); - - if (request.isRequestedSessionIdFromURL()) - out.println("

Turn on cookies in your browser to try cookie encoding
"); - out.println("Encoded Link
"); - - } - catch (IllegalStateException e) - { - e.printStackTrace(); - } - } - - } - - /* ------------------------------------------------------------ */ - @Override - public String getServletInfo() { - return "Session Dump Servlet"; - } - - /* ------------------------------------------------------------ */ - private String getURI(HttpServletRequest request) - { - String uri=(String)request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI); - if (uri==null) - uri=request.getRequestURI(); - return uri; - } - -} diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionExpiryTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionExpiryTest.java deleted file mode 100644 index b655f00671e..00000000000 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionExpiryTest.java +++ /dev/null @@ -1,385 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.nosql.mongodb; - - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; - -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.eclipse.jetty.server.session.AbstractSessionExpiryTest; -import org.eclipse.jetty.server.session.DefaultSessionCacheFactory; -import org.eclipse.jetty.server.session.SessionCache; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.eclipse.jetty.server.session.TestServer; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.util.StringUtil; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; - -import com.mongodb.BasicDBObject; -import com.mongodb.DBCollection; -import com.mongodb.DBObject; - - - - -public class SessionExpiryTest extends AbstractSessionExpiryTest -{ - - - @BeforeClass - public static void beforeClass() throws Exception - { - MongoTestHelper.dropCollection(); - MongoTestHelper.createCollection(); - } - - @AfterClass - public static void afterClass() throws Exception - { - MongoTestHelper.dropCollection(); - } - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return MongoTestHelper.newSessionDataStoreFactory(); - } - - @Test - @Override - public void testSessionNotExpired() throws Exception - { - super.testSessionNotExpired(); - } - - @Test - @Override - public void testSessionExpiry() throws Exception - { - super.testSessionExpiry(); - } - - @Test - @Override - public void testRequestForSessionWithChangedTimeout() throws Exception - { - super.testRequestForSessionWithChangedTimeout(); - } - - @Test - public void testBigSessionExpiry() throws Exception - { - String contextPath = ""; - String servletMapping = "/server"; - int inactivePeriod = Integer.MAX_VALUE * 60; //integer overflow - int scavengePeriod = 10; - - DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); - cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); - - MongoSessionDataStoreFactory storeFactory = MongoTestHelper.newSessionDataStoreFactory(); - storeFactory.setGracePeriodSec(scavengePeriod); - TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory); - ChangeTimeoutServlet servlet = new ChangeTimeoutServlet(); - ServletHolder holder = new ServletHolder(servlet); - ServletContextHandler context = server1.addContext(contextPath); - context.addServlet(holder, servletMapping); - TestHttpSessionListener listener = new TestHttpSessionListener(); - - context.getSessionHandler().addEventListener(listener); - - server1.start(); - int port1 = server1.getPort(); - - try - { - HttpClient client = new HttpClient(); - client.start(); - String url = "http://localhost:" + port1 + contextPath + servletMapping; - - //make a request to set up a session on the server - ContentResponse response1 = client.GET(url + "?action=init"); - assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().get("Set-Cookie"); - assertTrue(sessionCookie != null); - // Mangle the cookie, replacing Path with $Path, etc. - sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); - - String sessionId = TestServer.extractSessionId(sessionCookie); - - DBCollection sessions = MongoTestHelper.getCollection(); - verifySessionCreated(listener,sessionId); - //verify that the session timeout is set in mongo - verifySessionTimeout(sessions, sessionId, -1); //SessionManager sets -1 if maxInactive < 0 - - //get the session expiry time from mongo - long expiry = getSessionExpiry(sessions, sessionId); - assertEquals(0, expiry); - - } - finally - { - server1.stop(); - } - } - - @Test - public void changeSessionTimeout() throws Exception - { - String contextPath = ""; - String servletMapping = "/server"; - int inactivePeriod = 10; - int scavengePeriod = 1; - DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); - cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); - MongoSessionDataStoreFactory storeFactory = MongoTestHelper.newSessionDataStoreFactory(); - storeFactory.setGracePeriodSec(scavengePeriod); - TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory); - ChangeTimeoutServlet servlet = new ChangeTimeoutServlet(); - ServletHolder holder = new ServletHolder(servlet); - ServletContextHandler context = server1.addContext(contextPath); - context.addServlet(holder, servletMapping); - TestHttpSessionListener listener = new TestHttpSessionListener(); - - context.getSessionHandler().addEventListener(listener); - - server1.start(); - int port1 = server1.getPort(); - - try - { - HttpClient client = new HttpClient(); - client.start(); - String url = "http://localhost:" + port1 + contextPath + servletMapping; - - //make a request to set up a session on the server - ContentResponse response1 = client.GET(url + "?action=init"); - assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().get("Set-Cookie"); - assertTrue(sessionCookie != null); - // Mangle the cookie, replacing Path with $Path, etc. - sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); - - String sessionId = TestServer.extractSessionId(sessionCookie); - - DBCollection sessions = MongoTestHelper.getCollection(); - verifySessionCreated(listener,sessionId); - //verify that the session timeout is set in mongo - verifySessionTimeout(sessions, sessionId, inactivePeriod); - - //get the session expiry time from mongo - long expiry = getSessionExpiry(sessions, sessionId); - //make another request to change the session timeout to a smaller value - inactivePeriod = 5; - Request request = client.newRequest(url + "?action=change&val="+inactivePeriod); - request.getHeaders().add("Cookie", sessionCookie); - ContentResponse response2 = request.send(); - assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); - - - //check the timeout in mongo - verifySessionTimeout(sessions, sessionId, inactivePeriod); - //check the session expiry time has decreased from previous value - assertTrue(getSessionExpiry(sessions, sessionId) expiry); - assertTrue(getSessionAccessed(sessions, sessionId)+ (1000L*inactivePeriod) <= getSessionExpiry(sessions, sessionId)); - assertTrue (latestExpiry >= 15);//old inactive expired in 5, new inactive expired in 20 - } - finally - { - server1.stop(); - } - } - - - @Test - public void testChangeNewSessionTimeout () throws Exception - { - String contextPath = ""; - String servletMapping = "/server"; - int inactivePeriod = 10; - int scavengePeriod = 1; - - DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); - cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); - MongoSessionDataStoreFactory storeFactory = MongoTestHelper.newSessionDataStoreFactory(); - storeFactory.setGracePeriodSec(scavengePeriod); - - TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod,cacheFactory, storeFactory); - ImmediateChangeTimeoutServlet servlet = new ImmediateChangeTimeoutServlet(); - ServletHolder holder = new ServletHolder(servlet); - ServletContextHandler context = server1.addContext(contextPath); - context.addServlet(holder, servletMapping); - TestHttpSessionListener listener = new TestHttpSessionListener(); - - context.getSessionHandler().addEventListener(listener); - - server1.start(); - int port1 = server1.getPort(); - - try - { - HttpClient client = new HttpClient(); - client.start(); - String url = "http://localhost:" + port1 + contextPath + servletMapping; - - inactivePeriod = 5; //change from the sessionmanager configured default - - //make a request to set up a session on the server and change its inactive setting straight away - ContentResponse response1 = client.GET(url + "?action=init&val="+inactivePeriod); - assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().get("Set-Cookie"); - assertTrue(sessionCookie != null); - // Mangle the cookie, replacing Path with $Path, etc. - sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); - - String sessionId = TestServer.extractSessionId(sessionCookie); - - DBCollection sessions = MongoTestHelper.getCollection(); - verifySessionCreated(listener,sessionId); - //verify that the session timeout is the new value and not the default - verifySessionTimeout(sessions, sessionId, inactivePeriod); - } - finally - { - server1.stop(); - } - } - - - - - public void verifySessionTimeout (DBCollection sessions, String id, int sec) throws Exception - { - long val; - - if (sec > 0) - val = sec*1000L; - else - val = sec; - - assertNotNull(sessions); - assertNotNull(id); - - DBObject o = sessions.findOne(new BasicDBObject(MongoSessionDataStore.__ID,id)); - assertNotNull(o); - Long maxIdle = (Long)o.get(MongoSessionDataStore.__MAX_IDLE); - assertNotNull(maxIdle); - assertEquals(val, maxIdle.longValue()); - } - - public long getSessionExpiry (DBCollection sessions, String id) throws Exception - { - assertNotNull(sessions); - assertNotNull(id); - - DBObject o = sessions.findOne(new BasicDBObject(MongoSessionDataStore.__ID,id)); - assertNotNull(o); - Long expiry = (Long)o.get(MongoSessionDataStore.__EXPIRY); - return (expiry == null? null : expiry.longValue()); - } - - public long getSessionMaxInactiveInterval (DBCollection sessions, String id) throws Exception - { - assertNotNull(sessions); - assertNotNull(id); - - DBObject o = sessions.findOne(new BasicDBObject(MongoSessionDataStore.__ID,id)); - assertNotNull(o); - Long inactiveInterval = (Long)o.get(MongoSessionDataStore.__MAX_IDLE); - return (inactiveInterval == null? null : inactiveInterval.longValue()); - } - - public long getSessionAccessed (DBCollection sessions, String id) throws Exception - { - assertNotNull(sessions); - assertNotNull(id); - - DBObject o = sessions.findOne(new BasicDBObject(MongoSessionDataStore.__ID,id)); - assertNotNull(o); - Long accessed = (Long)o.get(MongoSessionDataStore.__ACCESSED); - return (accessed == null? null : accessed.longValue()); - } - - public void debugPrint (DBCollection sessions, String id) throws Exception - { - assertNotNull(sessions); - assertNotNull(id); - - DBObject o = sessions.findOne(new BasicDBObject(MongoSessionDataStore.__ID,id)); - assertNotNull(o); - System.err.println(o); - } - - - public static class ImmediateChangeTimeoutServlet extends HttpServlet - { - - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException - { - String action = request.getParameter("action"); - if ("init".equals(action)) - { - HttpSession session = request.getSession(true); - assertNotNull(session); - String tmp = request.getParameter("val"); - int val = (StringUtil.isBlank(tmp)?0:Integer.valueOf(tmp.trim())); - session.setMaxInactiveInterval(val); - } - else if ("change".equals(action)) - { - String tmp = request.getParameter("val"); - int val = (StringUtil.isBlank(tmp)?0:Integer.valueOf(tmp.trim())); - HttpSession session = request.getSession(false); - assertNotNull(session); - session.setMaxInactiveInterval(val); - } - } - } - -} diff --git a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionInvalidateCreateScavengeTest.java b/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionInvalidateCreateScavengeTest.java deleted file mode 100644 index 90a8f579d7c..00000000000 --- a/tests/test-sessions/test-mongodb-sessions/src/test/java/org/eclipse/jetty/nosql/mongodb/SessionInvalidateCreateScavengeTest.java +++ /dev/null @@ -1,61 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.nosql.mongodb; - -import org.eclipse.jetty.server.session.AbstractSessionInvalidateCreateScavengeTest; -import org.eclipse.jetty.server.session.SessionDataStoreFactory; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; - -public class SessionInvalidateCreateScavengeTest extends AbstractSessionInvalidateCreateScavengeTest -{ - - - @BeforeClass - public static void beforeClass() throws Exception - { - MongoTestHelper.dropCollection(); - MongoTestHelper.createCollection(); - } - - @AfterClass - public static void afterClass() throws Exception - { - MongoTestHelper.dropCollection(); - } - - - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return MongoTestHelper.newSessionDataStoreFactory(); - } - - - @Test - @Override - public void testSessionScavenge() throws Exception - { - super.testSessionScavenge(); - } -} diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredLastAccessTimeTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredLastAccessTimeTest.java deleted file mode 100644 index b7d7d2371e3..00000000000 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredLastAccessTimeTest.java +++ /dev/null @@ -1,238 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.HashSet; -import java.util.Set; - -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 javax.servlet.http.HttpSessionEvent; -import javax.servlet.http.HttpSessionListener; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.junit.Test; - - -/** - * AbstractClusteredLastAccessTimeTest - * - * This test checks that a session can migrate from node A to node B, kept in use in node B - * past the time at which it would have expired due to inactivity on node A but is NOT - * scavenged by node A. In other words, it tests that a session that migrates from one node - * to another is not timed out on the original node. - */ -public abstract class AbstractClusteredLastAccessTimeTest extends AbstractTestBase -{ - - @Test - public void testLastAccessTime() throws Exception - { - String contextPath = "/"; - String servletMapping = "/server"; - int maxInactivePeriod = 8; //session will timeout after 8 seconds - int scavengePeriod = 2; //scavenging occurs every 2 seconds - - DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); - cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); - SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); - ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod); - - TestServer server1 = new TestServer(0, maxInactivePeriod, scavengePeriod, cacheFactory, storeFactory); - TestServlet servlet1 = new TestServlet(); - ServletHolder holder1 = new ServletHolder(servlet1); - ServletContextHandler context = server1.addContext(contextPath); - TestSessionListener listener1 = new TestSessionListener(); - context.getSessionHandler().addEventListener(listener1); - context.addServlet(holder1, servletMapping); - SessionHandler m1 = context.getSessionHandler(); - - - try - { - server1.start(); - int port1=server1.getPort(); - - TestServer server2 = new TestServer(0, maxInactivePeriod, scavengePeriod, cacheFactory, storeFactory); - ServletContextHandler context2 = server2.addContext(contextPath); - context2.addServlet(TestServlet.class, servletMapping); - SessionHandler m2 = context2.getSessionHandler(); - - - try - { - server2.start(); - int port2=server2.getPort(); - HttpClient client = new HttpClient(); - client.start(); - try - { - // Perform one request to server1 to create a session - ContentResponse response1 = client.GET("http://localhost:" + port1 + contextPath + servletMapping.substring(1) + "?action=init"); - assertEquals(HttpServletResponse.SC_OK, response1.getStatus()); - assertEquals("test", response1.getContentAsString()); - String sessionCookie = response1.getHeaders().get("Set-Cookie"); - assertTrue( sessionCookie != null ); - assertEquals(1, ((DefaultSessionCache)m1.getSessionCache()).getSessionsCurrent()); - assertEquals(1, ((DefaultSessionCache)m1.getSessionCache()).getSessionsMax()); - assertEquals(1, ((DefaultSessionCache)m1.getSessionCache()).getSessionsTotal()); - // Mangle the cookie, replacing Path with $Path, etc. - sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); - - // Perform some request to server2 using the session cookie from the previous request - // This should migrate the session from server1 to server2, and leave server1's - // session in a very stale state, while server2 has a very fresh session. - // We want to test that optimizations done to the saving of the shared lastAccessTime - // do not break the correct working - int requestInterval = 500; - for (int i = 0; i < maxInactivePeriod * (1000 / requestInterval); ++i) - { - Request request = client.newRequest("http://localhost:" + port2 + contextPath + servletMapping.substring(1)); - request.header("Cookie", sessionCookie); - ContentResponse response2 = request.send(); - assertEquals(HttpServletResponse.SC_OK , response2.getStatus()); - assertEquals("test", response2.getContentAsString()); - - String setCookie = response2.getHeaders().get("Set-Cookie"); - if (setCookie!=null) - sessionCookie = setCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); - - Thread.sleep(requestInterval); - assertSessionCounts(1,1,1, m2); - } - - // At this point, session1 should be eligible for expiration. - // Let's wait for the scavenger to run, waiting 2.5 times the scavenger period - Thread.sleep(maxInactivePeriod+(scavengePeriod * 2500L)); - - //check that the session was not scavenged over on server1 by ensuring that the SessionListener destroy method wasn't called - assertFalse(listener1._destroys.contains(TestServer.extractSessionId(sessionCookie))); - assertAfterScavenge(m1); - } - finally - { - client.stop(); - } - } - finally - { - server2.stop(); - } - } - finally - { - server1.stop(); - } - } - - public void assertAfterSessionCreated (SessionHandler m) - { - assertSessionCounts(1, 1, 1, m); - } - - public void assertAfterScavenge (SessionHandler manager) - { - assertSessionCounts(1,1,1, manager); - } - - public void assertSessionCounts (int current, int max, int total, SessionHandler manager) - { - assertEquals(current, ((DefaultSessionCache)manager.getSessionCache()).getSessionsCurrent()); - assertEquals(max, ((DefaultSessionCache)manager.getSessionCache()).getSessionsMax()); - assertEquals(total, ((DefaultSessionCache)manager.getSessionCache()).getSessionsTotal()); - } - - public static class TestSessionListener implements HttpSessionListener - { - public Set _creates = new HashSet(); - public Set _destroys = new HashSet(); - - @Override - public void sessionDestroyed(HttpSessionEvent se) - { - _destroys.add(se.getSession().getId()); - } - - @Override - public void sessionCreated(HttpSessionEvent se) - { - _creates.add(se.getSession().getId()); - } - } - - - - public static class TestServlet extends HttpServlet - { - /** - * - */ - private static final long serialVersionUID = 1L; - - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException - { - String action = request.getParameter("action"); - if ("init".equals(action)) - { - HttpSession session = request.getSession(true); - session.setAttribute("test", "test"); - sendResult(session, httpServletResponse.getWriter()); - - } - else - { - HttpSession session = request.getSession(false); - - // if we node hopped we should get the session and test should already be present - sendResult(session, httpServletResponse.getWriter()); - - if (session!=null) - { - session.setAttribute("test", "test"); - } - } - } - - private void sendResult(HttpSession session, PrintWriter writer) - { - if (session != null) - { - writer.print(session.getAttribute("test")); - } - else - { - writer.print("null"); - } - } - } -} diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionMigrationTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionMigrationTest.java deleted file mode 100644 index da986252ed2..00000000000 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionMigrationTest.java +++ /dev/null @@ -1,148 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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 java.io.IOException; -import java.io.PrintWriter; - -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; - -/** - * AbstractClusteredSessionMigrationTest - * - * Check that a session that is active on node 1 can be accessed on node2. - */ -public abstract class AbstractClusteredSessionMigrationTest extends AbstractTestBase -{ - - - @Test - public void testSessionMigration() throws Exception - { - String contextPath = "/"; - String servletMapping = "/server"; - - DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); - cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); - SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); - ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(TestServer.DEFAULT_SCAVENGE_SEC); - - TestServer server1 = new TestServer(0, TestServer.DEFAULT_MAX_INACTIVE, TestServer.DEFAULT_SCAVENGE_SEC, - cacheFactory, storeFactory); - server1.addContext(contextPath).addServlet(TestServlet.class, servletMapping); - - try - { - server1.start(); - int port1=server1.getPort(); - - TestServer server2 = new TestServer(0, TestServer.DEFAULT_MAX_INACTIVE, TestServer.DEFAULT_SCAVENGE_SEC, - cacheFactory, storeFactory); - server2.addContext(contextPath).addServlet(TestServlet.class, servletMapping); - - try - { - server2.start(); - int port2=server2.getPort(); - - HttpClient client = new HttpClient(); - client.start(); - try - { - // Perform one request to server1 to create a session - int value = 1; - Request request1 = client.POST("http://localhost:" + port1 + contextPath + servletMapping.substring(1) + "?action=set&value=" + value); - ContentResponse response1 = request1.send(); - assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().get("Set-Cookie"); - assertTrue(sessionCookie != null); - // Mangle the cookie, replacing Path with $Path, etc. - sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); - - // Perform a request to server2 using the session cookie from the previous request - // This should migrate the session from server1 to server2. - Request request2 = client.newRequest("http://localhost:" + port2 + contextPath + servletMapping.substring(1) + "?action=get"); - request2.header("Cookie", sessionCookie); - ContentResponse response2 = request2.send(); - assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); - String response = response2.getContentAsString(); - assertEquals(response.trim(),String.valueOf(value)); } - finally - { - client.stop(); - } - } - finally - { - server2.stop(); - } - } - finally - { - server1.stop(); - } - } - - public static class TestServlet extends HttpServlet - { - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException - { - doPost(request, response); - } - - @Override - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException - { - HttpSession session = request.getSession(false); - - String action = request.getParameter("action"); - if ("set".equals(action)) - { - if (session == null) session = request.getSession(true); - int value = Integer.parseInt(request.getParameter("value")); - session.setAttribute("value", value); - PrintWriter writer = response.getWriter(); - writer.println(value); - writer.flush(); - } - else if ("get".equals(action)) - { - int value = (Integer)session.getAttribute("value"); - int x = session.getMaxInactiveInterval(); - assertTrue(x > 0); - 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/AbstractClusteredSessionScavengingTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionScavengingTest.java index 26f84a15fb9..e7b2089d4ec 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionScavengingTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractClusteredSessionScavengingTest.java @@ -19,10 +19,15 @@ package org.eclipse.jetty.server.session; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeUnit; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -34,195 +39,116 @@ import javax.servlet.http.HttpSessionListener; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.util.statistic.CounterStatistic; +import org.eclipse.jetty.servlet.ServletHolder; import org.junit.Test; /** * AbstractClusteredSessionScavengingTest + * + * Test that a session that was live on node1, but then more + * recently used on node2 does not expire over on node1. */ public abstract class AbstractClusteredSessionScavengingTest extends AbstractTestBase { - public void pause(int scavengePeriod) + public void pause(int secs) + throws InterruptedException { - try - { - Thread.sleep(scavengePeriod * 1000L); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } + Thread.sleep(TimeUnit.SECONDS.toMillis(secs)); } - - - public static class SessionListener implements HttpSessionListener - { - public CounterStatistic count = new CounterStatistic(); - /** - * @see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent) - */ - @Override - public void sessionCreated(HttpSessionEvent se) - { - count.increment(); - } - /** - * @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent) - */ - @Override - public void sessionDestroyed(HttpSessionEvent se) - { - count.decrement(); - } - } + + + @Test - public void testNoScavenging() throws Exception + public void testClusteredScavenge() throws Exception { String contextPath = "/"; String servletMapping = "/server"; - int inactivePeriod = 3; - int scavengePeriod = 0; - + int maxInactivePeriod = 5; //session will timeout after 5 seconds + int scavengePeriod = 1; //scavenging occurs every 1 seconds + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); - cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); - SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); - - - TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod, - cacheFactory, storeFactory); - ServletContextHandler context1 = server1.addContext(contextPath); - context1.addServlet(TestServlet.class, servletMapping); - SessionListener listener = new SessionListener(); - context1.getSessionHandler().addEventListener(listener); - - - try - { - server1.start(); - int port1 = server1.getPort(); - - HttpClient client = new HttpClient(); - client.start(); - try - { - String url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1); - - - // Create the session - ContentResponse response1 = client.GET(url + "?action=init"); - assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().get("Set-Cookie"); - assertTrue(sessionCookie != null); - SessionHandler m1 = context1.getSessionHandler(); - assertEquals(1, m1.getSessionsCreated()); - - - // Wait a while to ensure that the session should have expired, if the - //scavenger was running - pause(2*inactivePeriod); - - assertEquals(1, m1.getSessionsCreated()); - - - if (m1 instanceof TestSessionHandler) - { - ((TestSessionHandler)m1).assertCandidatesForExpiry(0); - } - - //check a session removed listener did not get called - assertEquals(1, listener.count.getCurrent()); - } - finally - { - client.stop(); - } - } - finally - { - server1.stop(); - } - } - - - @Test - public void testLocalSessionsScavenging() throws Exception - { - String contextPath = ""; - String servletMapping = "/server"; - int inactivePeriod = 4; - int scavengePeriod = 1; - - DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); - cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); //don't evict sessions SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod); + ((AbstractSessionDataStoreFactory)storeFactory).setSavePeriodSec(0); //always save when the session exits + + TestServer server1 = new TestServer(0, maxInactivePeriod, scavengePeriod, cacheFactory, storeFactory); + TestServlet servlet1 = new TestServlet(); + ServletHolder holder1 = new ServletHolder(servlet1); + ServletContextHandler context = server1.addContext(contextPath); + TestSessionListener listener1 = new TestSessionListener(); + context.getSessionHandler().addEventListener(listener1); + context.addServlet(holder1, servletMapping); + SessionHandler m1 = context.getSessionHandler(); - TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod, - cacheFactory, storeFactory); - ServletContextHandler context1 = server1.addContext(contextPath); - context1.addServlet(TestServlet.class, servletMapping); try { server1.start(); - int port1 = server1.getPort(); - TestServer server2 = new TestServer(0, inactivePeriod, scavengePeriod * 2, cacheFactory, storeFactory); + int port1=server1.getPort(); + + TestServer server2 = new TestServer(0, maxInactivePeriod, scavengePeriod, cacheFactory, storeFactory); ServletContextHandler context2 = server2.addContext(contextPath); context2.addServlet(TestServlet.class, servletMapping); + SessionHandler m2 = context2.getSessionHandler(); + try { server2.start(); - int port2 = server2.getPort(); + int port2=server2.getPort(); HttpClient client = new HttpClient(); client.start(); try { - String[] urls = new String[2]; - urls[0] = "http://localhost:" + port1 + contextPath + servletMapping; - urls[1] = "http://localhost:" + port2 + contextPath + servletMapping; - - // Create the session on node1 - ContentResponse response1 = client.GET(urls[0] + "?action=init"); - assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); + // Perform one request to server1 to create a session + ContentResponse response1 = client.GET("http://localhost:" + port1 + contextPath + servletMapping.substring(1) + "?action=init"); + assertEquals(HttpServletResponse.SC_OK, response1.getStatus()); + assertEquals("test", response1.getContentAsString()); String sessionCookie = response1.getHeaders().get("Set-Cookie"); - assertTrue(sessionCookie != null); + assertTrue( sessionCookie != null ); + assertEquals(1, ((DefaultSessionCache)m1.getSessionCache()).getSessionsCurrent()); + assertEquals(1, ((DefaultSessionCache)m1.getSessionCache()).getSessionsMax()); + assertEquals(1, ((DefaultSessionCache)m1.getSessionCache()).getSessionsTotal()); // Mangle the cookie, replacing Path with $Path, etc. - sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); - SessionHandler m1 = context1.getSessionHandler(); - assertEquals(1, m1.getSessionsCreated()); - - // Be sure the session is also present in node2 - org.eclipse.jetty.client.api.Request request = client.newRequest(urls[1] + "?action=test"); - request.header("Cookie", sessionCookie); - ContentResponse response2 = request.send(); - assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); - SessionHandler m2 = context2.getSessionHandler(); - - // Wait for the scavenger to run on node1 - pause(inactivePeriod+(2*scavengePeriod)); - - assertEquals(1, m1.getSessionsCreated()); - - // Check that node1 does not have any local session cached - request = client.newRequest(urls[0] + "?action=check"); - response1 = request.send(); - assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); + sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); + String id = TestServer.extractSessionId(sessionCookie); + Session s1 = ((DefaultSessionCache)m1.getSessionCache()).get(id); + assertNotNull(s1); + long expiry = s1.getSessionData().getExpiry(); - assertEquals(1, m1.getSessionsCreated()); - - // Wait for the scavenger to run on node2, waiting 3 times the scavenger period - // This ensures that the scavenger on node2 runs at least once. - pause(inactivePeriod+(2*scavengePeriod)); - // Check that node2 does not have any local session cached - request = client.newRequest(urls[1] + "?action=check"); - response2 = request.send(); - assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); + //Now do requests for the session to node2. This will update the expiry time on the session. + //Send requests for the next maxInactiveInterval, pausing a little between each request. + int requestInterval = 500; //ms pause between requests + long start = System.currentTimeMillis(); + long end = expiry; + long time = start; + while (time < end) + { + Request request = client.newRequest("http://localhost:" + port2 + contextPath + servletMapping.substring(1)); + request.header("Cookie", sessionCookie); //use existing session + ContentResponse response2 = request.send(); + assertEquals(HttpServletResponse.SC_OK , response2.getStatus()); + assertEquals("test", response2.getContentAsString()); + Thread.sleep(requestInterval); + assertSessionCounts(1,1,1, m2); + time = System.currentTimeMillis(); + } + + //session on node1 should be eligible for scavenge + //ensure scavenger has run on node1 + Thread.sleep(TimeUnit.SECONDS.toMillis(scavengePeriod)); // wait until just after the original expiry time has passed + + + //check that the session wasn't in fact scavenged because it was in use on node1 + assertFalse(listener1._destroys.contains(TestServer.extractSessionId(sessionCookie))); + assertAfterScavenge(m1); } finally { @@ -239,9 +165,51 @@ public abstract class AbstractClusteredSessionScavengingTest extends AbstractTes server1.stop(); } } + + + + public void assertAfterSessionCreated (SessionHandler m) + { + assertSessionCounts(1, 1, 1, m); + } + + public void assertAfterScavenge (SessionHandler manager) + { + assertSessionCounts(1,1,1, manager); + } + + public void assertSessionCounts (int current, int max, int total, SessionHandler manager) + { + assertEquals(current, ((DefaultSessionCache)manager.getSessionCache()).getSessionsCurrent()); + assertEquals(max, ((DefaultSessionCache)manager.getSessionCache()).getSessionsMax()); + assertEquals(total, ((DefaultSessionCache)manager.getSessionCache()).getSessionsTotal()); + } + + + public static class TestSessionListener implements HttpSessionListener + { + public Set _creates = new HashSet<>(); + public Set _destroys = new HashSet<>(); + + @Override + public void sessionDestroyed(HttpSessionEvent se) + { + _destroys.add(se.getSession().getId()); + } + + @Override + public void sessionCreated(HttpSessionEvent se) + { + _creates.add(se.getSession().getId()); + } + } + + public static class TestServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + @Override protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException { @@ -250,18 +218,34 @@ public abstract class AbstractClusteredSessionScavengingTest extends AbstractTes { HttpSession session = request.getSession(true); session.setAttribute("test", "test"); + sendResult(session, httpServletResponse.getWriter()); + } - else if ("test".equals(action)) + else { HttpSession session = request.getSession(false); - assertNotNull(session); - session.setAttribute("test", "test"); + + // if we node hopped we should get the session and test should already be present + sendResult(session, httpServletResponse.getWriter()); + + if (session!=null) + { + session.setAttribute("test", "test"); + } } - else if ("check".equals(action)) + } + + private void sendResult(HttpSession session, PrintWriter writer) + { + if (session != null) { - HttpSession session = request.getSession(false); - assertTrue(session == null); + writer.print(session.getAttribute("test")); + } + else + { + writer.print("null"); } } } + } diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractProxySerializationTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractProxySerializationTest.java deleted file mode 100644 index 080b1472538..00000000000 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractProxySerializationTest.java +++ /dev/null @@ -1,134 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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 java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.net.URL; -import java.net.URLClassLoader; - -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.eclipse.jetty.util.IO; -import org.junit.Test; - -/** - * AbstractProxySerializationTest - * - * For SessionDataStores that passivate with serialization. - */ -public abstract class AbstractProxySerializationTest extends AbstractTestBase -{ - - public abstract void customizeContext (ServletContextHandler c); - - - /** - * @param msec milliseconds to sleep - */ - public void pause(int msec) - { - try - { - Thread.sleep(msec); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - } - - @Test - public void testProxySerialization() throws Exception - { - String contextPath = "/"; - String servletMapping = "/server"; - int scavengePeriod = 10; - - DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); - cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); - SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); - ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod); - - TestServer server = new TestServer(0, 20, scavengePeriod, - cacheFactory, storeFactory); - ServletContextHandler context = server.addContext(contextPath); - - InputStream is = this.getClass().getClassLoader().getResourceAsStream("proxy-serialization.jar"); - - File testDir = MavenTestingUtils.getTargetTestingDir("proxy-serialization"); - testDir.mkdirs(); - - File extractedJar = new File (testDir, "proxy-serialization.jar"); - extractedJar.createNewFile(); - IO.copy(is, new FileOutputStream(extractedJar)); - - - URLClassLoader loader = new URLClassLoader(new URL[] {extractedJar.toURI().toURL()}, Thread.currentThread().getContextClassLoader()); - context.setClassLoader(loader); - context.addServlet("TestServlet", servletMapping); - customizeContext(context); - - try - { - server.start(); - int port=server.getPort(); - HttpClient client = new HttpClient(); - client.start(); - try - { - ContentResponse response = client.GET("http://localhost:" + port + contextPath + servletMapping.substring(1) + "?action=create"); - assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().get("Set-Cookie"); - assertTrue(sessionCookie != null); - - //stop the context to be sure the sesssion will be passivated - context.stop(); - - //restart the context - context.start(); - - // Make another request using the session id from before - Request request = client.newRequest("http://localhost:" + port + contextPath + servletMapping.substring(1) + "?action=test"); - response = request.send(); - assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - } - finally - { - client.stop(); - } - } - finally - { - server.stop(); - } - - } -} diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStoreTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStoreTest.java new file mode 100644 index 00000000000..4f02afe2a14 --- /dev/null +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionDataStoreTest.java @@ -0,0 +1,761 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.junit.Test; + +/** + * AbstractSessionDataStoreTest + * + * + */ +public abstract class AbstractSessionDataStoreTest +{ + public static final int GRACE_PERIOD_SEC = (int)TimeUnit.HOURS.toSeconds(2); + + /** + * A timestamp representing a time that was close to the epoch, and thus + * happened a long time ago. Used as expiry timestamp for to + * signify a session is expired. + */ + public static final long ANCIENT_TIMESTAMP = 100L; + public static final long RECENT_TIMESTAMP = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(3*GRACE_PERIOD_SEC); + + + + + public abstract SessionDataStoreFactory createSessionDataStoreFactory(); + + public abstract void persistSession(SessionData data) throws Exception; + + public abstract void persistUnreadableSession(SessionData data) throws Exception; + + public abstract boolean checkSessionExists (SessionData data) throws Exception; + + public abstract boolean checkSessionPersisted (SessionData data) throws Exception; + + + + /** + * Test that the store can persist a session. + * + * @throws Exception + */ + @Test + public void testStoreSession() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + store.start(); + + //create a session + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", 100, now, now-1, -1);//never expires + data.setAttribute("a", "b"); + data.setLastNode(sessionContext.getWorkerName()); + + store.store("1234", data); + + //check that the store contains all of the session data + assertTrue(checkSessionPersisted(data)); + } + + + /** + * Test that the store can update a pre-existing session. + * + * @throws Exception + */ + @Test + public void testUpdateSession() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + store.start(); + + //create a session + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", 100, 200, 199, -1);//never expires + data.setAttribute("a", "b"); + data.setLastNode(sessionContext.getWorkerName()); + data.setLastSaved(400); //make it look like it was previously saved by the store + + + //put it into the store + persistSession(data); + + //now test we can update the session + data.setLastAccessed(now-1); + data.setAccessed(now); + data.setMaxInactiveMs(TimeUnit.MINUTES.toMillis(2)); + data.setAttribute("a", "c"); + store.store("1234", data); + + assertTrue(checkSessionPersisted(data)); + } + + + /** + * Test that the store can persist a session that contains + * serializable objects in the attributes. + * + * @throws Exception + */ + @Test + public void testStoreObjectAttributes() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + store.start(); + + //create a session + SessionData data = store.newSessionData("1234", 100, 200, 199, -1);//never expires + TestFoo testFoo = new TestFoo(); + testFoo.setInt(33); + FooInvocationHandler handler = new FooInvocationHandler(testFoo); + Foo foo = (Foo)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] {Foo.class}, handler); + data.setAttribute("foo", foo); + data.setLastNode(sessionContext.getWorkerName()); + + //test that it can be persisted + store.store("1234", data); + checkSessionPersisted(data); + } + + /** + * Test that we can load a persisted session. + * + * @throws Exception + */ + @Test + public void testLoadSessionExists() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + //persist a session that is not expired + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", 100, now, now-1, -1);//never expires + data.setLastNode(sessionContext.getWorkerName()); + persistSession(data); + + store.start(); + + //test that we can retrieve it + SessionData loaded = store.load("1234"); + assertNotNull(loaded); + assertEquals("1234", loaded.getId()); + assertEquals(100, loaded.getCreated()); + assertEquals(now, loaded.getAccessed()); + assertEquals(now-1, loaded.getLastAccessed()); + assertEquals(0, loaded.getExpiry()); + } + + + /** + * Test that an expired session can be loaded. + * + * @throws Exception + */ + @Test + public void testLoadSessionExpired() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + + //persist a session that is expired + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("678", 100, now-20, now-30, 10);//10 sec max idle + data.setLastNode(sessionContext.getWorkerName()); + data.setExpiry(RECENT_TIMESTAMP); //make it expired recently + persistSession(data); + + store.start(); + + //test we can retrieve it + SessionData loaded = store.load("678"); + assertNotNull(loaded); + assertEquals("678", loaded.getId()); + assertEquals(100, loaded.getCreated()); + assertEquals(now-20, loaded.getAccessed()); + assertEquals(now-30, loaded.getLastAccessed()); + assertEquals(RECENT_TIMESTAMP, loaded.getExpiry()); + } + + + /** + * Test that a non-existent session cannot be loaded. + * @throws Exception + */ + @Test + public void testLoadSessionDoesNotExist() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + store.start(); + + //test we can't retrieve a non-existent session + SessionData loaded = store.load("111"); + assertNull(loaded); + } + + + /** + * Test that a session that cannot be loaded throws exception. + * @throws Exception + */ + @Test + public void testLoadSessionFails() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + + //persist a session that is damaged and cannot be read + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("222", 100, now, now-1, -1); + data.setLastNode(sessionContext.getWorkerName()); + persistUnreadableSession(data); + + store.start(); + + //test that we can retrieve it + try + { + store.load("222"); + fail("Session should be unreadable"); + } + catch (UnreadableSessionDataException e) + { + //expected exception + } + } + + + + /** + * Test that we can delete a persisted session. + * + * @throws Exception + */ + @Test + public void testDeleteSessionExists() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + //persist a session that is not expired + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", 100, now, now-1, -1); + data.setLastNode(sessionContext.getWorkerName()); + persistSession(data); + + store.start(); + + //delete the session via the store + store.delete("1234"); + + //check the session is no longer exists + assertFalse(checkSessionExists(data)); + } + + + /** + * Test deletion of non-existent session. + * @throws Exception + */ + @Test + public void testDeleteSessionDoesNotExist() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + store.initialize(new SessionContext("foo", context.getServletContext())); + store.start(); + + //delete the non-existent session via the store + store.delete("3333"); + } + + + /** + * Test SessionDataStore.getExpired. Tests the situation + * where the session candidates are also expired in the + * store. + * + * @throws Exception + */ + @Test + public void testGetExpiredPersistedAndExpired() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + //persist a session that is expired + SessionData data = store.newSessionData("1234", 100, 101, 101, 10); + data.setLastNode(sessionContext.getWorkerName()); + data.setExpiry(RECENT_TIMESTAMP); //make it expired recently so FileSessionDataStore doesn't eliminate it on startup + persistSession(data); + + //persist another session that is expired + SessionData data2 = store.newSessionData("5678", 100, 100, 101, 30); + data2.setLastNode(sessionContext.getWorkerName()); + data2.setExpiry(RECENT_TIMESTAMP); //make it expired recently so FileSessionDataStore doesn't eliminate it on startup + persistSession(data2); + + store.start(); + + Set candidates = new HashSet<>(Arrays.asList(new String[] {"1234", "5678"})); + Set expiredIds = store.getExpired(candidates); + assertEquals(2, expiredIds.size()); + assertTrue(expiredIds.contains("1234")); + assertTrue(expiredIds.contains("5678")); + } + + + /** + * Test SessionDataStore.getExpired: tests the situation where + * the session candidates are not expired in the store. + * @throws Exception + */ + @Test + public void testGetExpiredPersistedNotExpired() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + long now = System.currentTimeMillis(); + //persist a session that is not expired + SessionData data = store.newSessionData("1234", 100, now, now-1, TimeUnit.MINUTES.toMillis(60)); + data.setLastNode(sessionContext.getWorkerName()); + persistSession(data); + + //persist another session that is not expired + SessionData data2 = store.newSessionData("5678", 100, now, now-1, TimeUnit.MINUTES.toMillis(60)); + data2.setLastNode(sessionContext.getWorkerName()); + persistSession(data2); + + store.start(); + + Set candidates = new HashSet<>(Arrays.asList(new String[] {"1234", "5678"})); + Set expiredIds = store.getExpired(candidates); + assertEquals(0, expiredIds.size()); + } + + /** + * Test SessionDataStore.getExpired: tests the situation where + * the session candidates don't exist in the store. + * + * @throws Exception + */ + @Test + public void testGetExpiredNotPersisted() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + store.start(); + + Set candidates = new HashSet<>(Arrays.asList(new String[] {"1234", "5678"})); + Set expiredIds = store.getExpired(candidates); + assertEquals(2, expiredIds.size()); + assertTrue(expiredIds.contains("1234")); + assertTrue(expiredIds.contains("5678")); + } + + /** + * Test SessionDataStore.getExpired: tests the situation where + * there are more persisted expired sessions in the store than + * present in the candidate list. + * + * @throws Exception + */ + @Test + public void testGetExpiredPersistedAndExpiredOnly() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + //persist a session that is expired + SessionData data = store.newSessionData("1234", 100, 101, 100, TimeUnit.MINUTES.toMillis(60)); + data.setLastNode(sessionContext.getWorkerName()); + data.setExpiry(RECENT_TIMESTAMP); //must be recently expired, or FileSessionDataStore will eliminate it on startup + persistSession(data); + + //persist another session that is expired + SessionData data2 = store.newSessionData("5678", 100, 101, 100, TimeUnit.MINUTES.toMillis(60)); + data2.setLastNode(sessionContext.getWorkerName()); + data2.setExpiry(RECENT_TIMESTAMP); //must be recently expired, or FileSessionDataStore will eliminate it on startup + persistSession(data2); + + store.start(); + + Set candidates = new HashSet<>(); + Set expiredIds = store.getExpired(candidates); + assertEquals(2, expiredIds.size()); + assertTrue(expiredIds.contains("1234")); + assertTrue(expiredIds.contains("5678")); + } + + + /** + * Test SessionDataStore.getExpired: tests the situation where + * there are sessions that are not in use on the node, but have + * expired and are last used by another node. + * + * @throws Exception + */ + @Test + public void testGetExpiredDifferentNode() throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + //persist a session that is expired for a different node + SessionData data = store.newSessionData("1234", 100, 101, 100, TimeUnit.MINUTES.toMillis(60)); + data.setLastNode("other"); + data.setExpiry(RECENT_TIMESTAMP); //must be recently expired, or FileSessionDataStore will eliminate it on startup + persistSession(data); + + store.start(); + + Set candidates = new HashSet<>(); + Set expiredIds = store.getExpired(candidates); + assertEquals(1, expiredIds.size()); + assertTrue(expiredIds.contains("1234")); + } + + + + /** + * Test the exist() method with a session that does exist and is not expired + * + * @throws Exception + */ + @Test + public void testExistsNotExpired () throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + long now = System.currentTimeMillis(); + //persist a session that is not expired + SessionData data = store.newSessionData("1234", 100, now, now-1, TimeUnit.MINUTES.toMillis(60)); + data.setLastNode(sessionContext.getWorkerName()); + persistSession(data); + + store.start(); + + assertTrue(store.exists("1234")); + } + + /** + * Test the exist() method with a session that does exist and is expired + * + * @throws Exception + */ + @Test + public void testExistsIsExpired () throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + //persist a session that is expired + SessionData data = store.newSessionData("1234", 100, 101, 100, TimeUnit.MINUTES.toMillis(60)); + data.setLastNode(sessionContext.getWorkerName()); + data.setExpiry(RECENT_TIMESTAMP); + persistSession(data); + + store.start(); + + assertFalse(store.exists("1234")); + } + + /** + * Test the exist() method with a session that does not exist + * + * @throws Exception + */ + @Test + public void testExistsNotExists () throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + store.start(); + + assertFalse(store.exists("8888")); + } + + + @Test + public void testExistsDifferentContext () throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + + //persist a session for a different context + SessionData data = store.newSessionData("1234", 100, 101, 100, TimeUnit.MINUTES.toMillis(60)); + data.setContextPath("_other"); + data.setLastNode(sessionContext.getWorkerName()); + persistSession(data); + + store.start(); + + //check that session does not exist for this context + assertFalse(store.exists("1234")); + } + + + /** + * Test setting a save period to avoid writes when the attributes haven't changed. + * + * @throws Exception + */ + @Test + public void testSavePeriodOnUpdate () + throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + ((AbstractSessionDataStoreFactory)factory).setSavePeriodSec(20); //only save every 20sec + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + store.start(); + + long now = System.currentTimeMillis(); + + //persist a session that is not expired, and has been saved before + SessionData data = store.newSessionData("1234", 100, now-10, now-20, TimeUnit.MINUTES.toMillis(60)); + data.setLastNode(sessionContext.getWorkerName()); + data.setLastSaved(now-100); + persistSession(data); + + //update just the access and last access time + data.setLastAccessed(now-5); + data.setAccessed(now-1); + + //test that a save does not change the stored data + store.store("1234", data); + + //reset the times for a check + data.setLastAccessed(now-20); + data.setAccessed(now-10); + checkSessionPersisted(data); + } + + + /** + * Check that a session that has never previously been + * saved will be saved despite the savePeriod setting. + * + * @throws Exception + */ + @Test + public void testSavePeriodOnCreate () + throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + ((AbstractSessionDataStoreFactory)factory).setSavePeriodSec(20); //only save every 20sec + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + store.start(); + + long now = System.currentTimeMillis(); + //create a session that is not expired, and has never been saved before + SessionData data = store.newSessionData("1234", 100, now-10, now-20, TimeUnit.MINUTES.toMillis(60)); + data.setLastNode(sessionContext.getWorkerName()); + + store.store("1234", data); + + checkSessionPersisted(data); + } + + + /** + * Check that a session whose attributes have changed will always + * be saved despite the savePeriod + * + * @throws Exception + */ + @Test + public void testSavePeriodDirtySession () + throws Exception + { + //create the SessionDataStore + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + SessionDataStoreFactory factory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC); + ((AbstractSessionDataStoreFactory)factory).setSavePeriodSec(20); //only save every 20sec + SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler()); + SessionContext sessionContext = new SessionContext("foo", context.getServletContext()); + store.initialize(sessionContext); + store.start(); + + //persist a session that is not expired + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", 100, now-10, now-20, TimeUnit.MINUTES.toMillis(60)); + data.setLastNode(sessionContext.getWorkerName()); + data.setLastSaved(now-100); + data.setAttribute("wibble", "wobble"); + persistSession(data); + + //now change the attributes + data.setAttribute("wibble", "bobble"); + data.setLastAccessed(now-5); + data.setAccessed(now-1); + + store.store("1234", data); + + checkSessionPersisted(data); + } +} diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionExpiryTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionExpiryTest.java deleted file mode 100644 index bf3308f631a..00000000000 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionExpiryTest.java +++ /dev/null @@ -1,447 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2018 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.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -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 javax.servlet.http.HttpSessionEvent; -import javax.servlet.http.HttpSessionListener; - -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.client.api.Request; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.util.StringUtil; -import org.eclipse.jetty.util.log.Log; -import org.junit.Ignore; -import org.junit.Test; - -/** - * AbstractSessionExpiryTest - * - * Ensure session is not removed when server stops, and that a - * non-expired session can be loaded in after restart. - */ -public abstract class AbstractSessionExpiryTest extends AbstractTestBase -{ - - public void pause(int period) - { - try - { - Thread.sleep(period * 1000L); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - } - - public class TestHttpSessionListener implements HttpSessionListener - { - public List createdSessions = new ArrayList(); - public List destroyedSessions = new ArrayList(); - public boolean accessAttribute = false; - public Exception ex = null; - - public TestHttpSessionListener(boolean access) - { - accessAttribute = access; - } - - public TestHttpSessionListener() - { - accessAttribute = false; - } - - @Override - public void sessionDestroyed(HttpSessionEvent se) - { - destroyedSessions.add(se.getSession().getId()); - if (accessAttribute) - { - try - { - - se.getSession().getAttribute("anything"); - } - catch (Exception e) - { - ex = e; - } - } - } - - @Override - public void sessionCreated(HttpSessionEvent se) - { - createdSessions.add(se.getSession().getId()); - } - }; - - @Test - @Ignore // https://github.com/eclipse/jetty.project/issues/2214 - public void testSessionExpiresWithListener() throws Exception - { - String contextPath = "/"; - String servletMapping = "/server"; - int inactivePeriod = 3; - int scavengePeriod = 1; - - DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); - cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); - SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); - ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod); - - TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod, - cacheFactory, storeFactory); - TestServlet servlet = new TestServlet(); - ServletHolder holder = new ServletHolder(servlet); - ServletContextHandler context = server1.addContext(contextPath); - context.addServlet(holder, servletMapping); - TestHttpSessionListener listener = new TestHttpSessionListener(true); - - context.getSessionHandler().addEventListener(listener); - - server1.start(); - int port1 = server1.getPort(); - - try - { - HttpClient client = new HttpClient(); - client.start(); - String url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1); - - //make a request to set up a session on the server - ContentResponse response1 = client.GET(url + "?action=init"); - assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().get("Set-Cookie"); - assertTrue(sessionCookie != null); - - String sessionId = TestServer.extractSessionId(sessionCookie); - - verifySessionCreated(listener,sessionId); - - //and wait until the session should have expired - pause(inactivePeriod+(scavengePeriod*2)); - - verifySessionDestroyed (listener, sessionId); - assertNull(listener.ex); - } - finally - { - server1.stop(); - } - } - - /** - * Check session is preserved over stop/start - * @throws Exception - */ - @Test - public void testSessionNotExpired() throws Exception - { - String contextPath = "/"; - String servletMapping = "/server"; - int inactivePeriod = 20; - int scavengePeriod = 10; - - DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); - cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); - SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); - ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod); - - TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod, - cacheFactory, storeFactory); - TestServlet servlet = new TestServlet(); - ServletHolder holder = new ServletHolder(servlet); - server1.addContext(contextPath).addServlet(holder, servletMapping); - - HttpClient client = new HttpClient(); - - try - { - Log.getLogger(org.eclipse.jetty.util.thread.QueuedThreadPool.class).setDebugEnabled(true); - server1.start(); - int port1 = server1.getPort(); - - client.start(); - String url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1); - - //make a request to set up a session on the server - ContentResponse response = client.GET(url + "?action=init"); - assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().get("Set-Cookie"); - assertTrue(sessionCookie != null); - - //now stop the server - server1.stop(); - - - //start the server again, before the session times out - server1.start(); - port1 = server1.getPort(); - url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1); - - //make another request, the session should not have expired - Request request = client.newRequest(url + "?action=notexpired"); - ContentResponse response2 = request.send(); - assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); - - } - finally - { - Log.getLogger(org.eclipse.jetty.util.thread.QueuedThreadPool.class).setDebugEnabled(false); - client.stop(); - server1.stop(); - } - } - - - /** - * Check that a session that expires whilst the server is stopped will not be - * able to be used when the server restarts - * @throws Exception - */ - @Test - public void testSessionExpiry() throws Exception - { - - - String contextPath = "/"; - String servletMapping = "/server"; - int inactivePeriod = 4; - int scavengePeriod = 1; - - DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); - cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); - SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); - ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod); - - TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod, - cacheFactory, storeFactory); - TestServlet servlet = new TestServlet(); - ServletHolder holder = new ServletHolder(servlet); - ServletContextHandler context = server1.addContext(contextPath); - context.addServlet(holder, servletMapping); - TestHttpSessionListener listener = new TestHttpSessionListener(); - - context.getSessionHandler().addEventListener(listener); - - server1.start(); - int port1 = server1.getPort(); - - try - { - HttpClient client = new HttpClient(); - client.start(); - String url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1); - - //make a request to set up a session on the server - ContentResponse response1 = client.GET(url + "?action=init"); - assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); - String sessionCookie = response1.getHeaders().get("Set-Cookie"); - assertTrue(sessionCookie != null); - - String sessionId = TestServer.extractSessionId(sessionCookie); - - verifySessionCreated(listener,sessionId); - - //now stop the server - server1.stop(); - - //and wait until the session should have expired - pause(inactivePeriod); - - //restart the server - server1.start(); - - //and wait until the scavenger has run - pause(inactivePeriod+(scavengePeriod*2)); - - port1 = server1.getPort(); - url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1); - - //make another request, the session should have expired - Request request = client.newRequest(url + "?action=test"); - ContentResponse response2 = request.send(); - - assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); - String cookie2 = response2.getHeaders().get("Set-Cookie"); - assertTrue (!cookie2.equals(sessionCookie)); - verifySessionDestroyed (listener, sessionId); - } - finally - { - server1.stop(); - } - } - - - @Test - public void testRequestForSessionWithChangedTimeout () throws Exception - { - String contextPath = "/"; - String servletMapping = "/server"; - int inactivePeriod = 5; - int scavengePeriod = 1; - - DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); - cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); - SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); - ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod); - - TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod, - cacheFactory, storeFactory); - ChangeTimeoutServlet servlet = new ChangeTimeoutServlet(); - ServletHolder holder = new ServletHolder(servlet); - ServletContextHandler context = server1.addContext(contextPath); - context.addServlet(holder, servletMapping); - TestHttpSessionListener listener = new TestHttpSessionListener(); - - context.getSessionHandler().addEventListener(listener); - - server1.start(); - int port1 = server1.getPort(); - - try - { - HttpClient client = new HttpClient(); - client.start(); - String url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1); - - //make a request to set up a session on the server with the session manager's inactive timeout - ContentResponse response = client.GET(url + "?action=init"); - assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie = response.getHeaders().get("Set-Cookie"); - assertTrue(sessionCookie != null); - - //make another request to change the session timeout to a larger value - int newInactivePeriod = 100; - Request request = client.newRequest(url + "?action=change&val="+newInactivePeriod); - response = request.send(); - assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - - //stop and restart the session manager to ensure it needs to reload the session - context.stop(); - context.start(); - - //wait until the session manager timeout has passed and re-request the session - //which should still be valid - pause(inactivePeriod); - - request = client.newRequest(url + "?action=check"); - response = request.send(); - assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - String sessionCookie2 = response.getHeaders().get("Set-Cookie"); - assertNull(sessionCookie2); - - } - finally - { - server1.stop(); - } - } - - - - public void verifySessionCreated (TestHttpSessionListener listener, String sessionId) - { - assertTrue(listener.createdSessions.contains(sessionId)); - } - public void verifySessionDestroyed (TestHttpSessionListener listener, String sessionId) - { - assertTrue (listener.destroyedSessions.contains(sessionId)); - } - - - - public static class TestServlet extends HttpServlet - { - public String originalId = null; - - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException - { - String action = request.getParameter("action"); - if ("init".equals(action)) - { - HttpSession session = request.getSession(true); - session.setAttribute("test", "test"); - originalId = session.getId(); - } - else if ("test".equals(action)) - { - HttpSession session = request.getSession(true); - assertTrue(session != null); - assertTrue(!originalId.equals(session.getId())); - } - else if ("notexpired".equals(action)) - { - HttpSession session = request.getSession(false); - assertTrue(session != null); - assertTrue(originalId.equals(session.getId())); - } - - } - } - - - public static class ChangeTimeoutServlet extends HttpServlet - { - - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException - { - String action = request.getParameter("action"); - if ("init".equals(action)) - { - HttpSession session = request.getSession(true); - session.setAttribute("test", "test"); - } - else if ("change".equals(action)) - { - String tmp = request.getParameter("val"); - int val = (StringUtil.isBlank(tmp)?0:Integer.valueOf(tmp.trim())); - HttpSession session = request.getSession(false); - assertNotNull(session); - session.setMaxInactiveInterval(val); - } - else if ("check".equals(action)) - { - HttpSession session = request.getSession(false); - assertNotNull(session); - } - } - } - -} diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestHelper.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/Foo.java similarity index 82% rename from tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestHelper.java rename to tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/Foo.java index bb072ff7839..72819d75362 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestHelper.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/Foo.java @@ -19,15 +19,12 @@ package org.eclipse.jetty.server.session; /** - * HashTestHelper - * + * Foo + * + * */ -public class HashTestHelper +public interface Foo { - - public static SessionDataStoreFactory newSessionDataStoreFactory() - { - return new NullSessionDataStoreFactory(); - } - + public int getInt(); + public void setInt (int i); } diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/FooInvocationHandler.java similarity index 63% rename from tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java rename to tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/FooInvocationHandler.java index 33df753ef75..ef5f630f76f 100644 --- a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/FooInvocationHandler.java @@ -16,32 +16,34 @@ // ======================================================================== // - package org.eclipse.jetty.server.session; -import org.junit.After; +import java.io.Serializable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; /** - * ModifyMaxInactiveIntervalTest + * ProxiableSessionAttributeObjectInvocationHandler * * */ -public class ModifyMaxInactiveIntervalTest extends AbstractModifyMaxInactiveIntervalTest +public class FooInvocationHandler implements InvocationHandler, Serializable { - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() + private static final long serialVersionUID = -4009478822490178554L; + + private Foo foo; + + public FooInvocationHandler (Foo f) { - return JdbcTestHelper.newSessionDataStoreFactory(); + foo = f; } - @After - public void tearDown() throws Exception + + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - JdbcTestHelper.shutdown(null); + return method.invoke(foo, args); } - } diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateCreateScavengeTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestFoo.java similarity index 65% rename from tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateCreateScavengeTest.java rename to tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestFoo.java index 3ec2eb172b8..8b004fe99cb 100644 --- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateCreateScavengeTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestFoo.java @@ -18,23 +18,40 @@ package org.eclipse.jetty.server.session; -import org.junit.Test; +import java.io.Serializable; -public class SessionInvalidateCreateScavengeTest extends AbstractSessionInvalidateCreateScavengeTest +/** + * TestFoo + * + * + */ +public class TestFoo implements Foo, Serializable { - /** - * @see org.eclipse.jetty.server.session.AbstractTestBase#createSessionDataStoreFactory() - */ - @Override - public SessionDataStoreFactory createSessionDataStoreFactory() - { - return HashTestHelper.newSessionDataStoreFactory(); - } + private static final long serialVersionUID = 953717519120144555L; - @Test + private int i = -99; + @Override - public void testSessionScavenge() throws Exception + public int getInt() { - super.testSessionScavenge(); + return this.i; } + + @Override + public void setInt(int i) + { + this.i = i; + } + + + @Override + public boolean equals(Object obj) + { + if (obj == null) + return false; + + return (((Foo)obj).getInt() == getInt()); + } + + } diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestFooServlet.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestFooServlet.java new file mode 100644 index 00000000000..548a5498106 --- /dev/null +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestFooServlet.java @@ -0,0 +1,59 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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 java.io.IOException; +import java.lang.reflect.Proxy; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + + + +public class TestFooServlet extends HttpServlet +{ + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + String action = request.getParameter("action"); + + if ("create".equals(action)) + { + HttpSession session = request.getSession(true); + TestFoo testFoo = new TestFoo(); + testFoo.setInt(33); + FooInvocationHandler handler = new FooInvocationHandler(testFoo); + Foo foo = (Foo)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[] {Foo.class}, handler); + session.setAttribute("foo", foo); + } + else if ("test".equals(action)) + { + HttpSession session = request.getSession(false); + if (session == null) + response.sendError(500, "Session not activated"); + Foo foo = (Foo)session.getAttribute("foo"); + if (foo == null || foo.getInt() != 33) + response.sendError(500, "Foo not deserialized"); + } + + } +} diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpSessionListener.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpSessionListener.java new file mode 100644 index 00000000000..6e366458183 --- /dev/null +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestHttpSessionListener.java @@ -0,0 +1,71 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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 java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionListener; + +/** + * TestSessionListener + * + * + */ +public class TestHttpSessionListener implements HttpSessionListener +{ + public List createdSessions = new ArrayList<>(); + public List destroyedSessions = new ArrayList<>(); + public boolean accessAttribute = false; + public Exception ex = null; + + public TestHttpSessionListener(boolean access) + { + accessAttribute = access; + } + + public TestHttpSessionListener() + { + accessAttribute = false; + } + + public void sessionDestroyed(HttpSessionEvent se) + { + destroyedSessions.add(se.getSession().getId()); + if (accessAttribute) + { + try + { + se.getSession().getAttribute("anything"); + } + catch (Exception e) + { + ex = e; + } + } + } + + public void sessionCreated(HttpSessionEvent se) + { + createdSessions.add(se.getSession().getId()); + } + +} diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestSessionDataStore.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestSessionDataStore.java index 552f4a63cf4..51ac9b98be3 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestSessionDataStore.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/TestSessionDataStore.java @@ -27,35 +27,39 @@ import java.util.Set; /** * TestSessionDataStore * - * Make a fake session data store that creates a new SessionData object + * Make a fake session data store (non clustered!) that creates a new SessionData object * every time load(id) is called. */ public class TestSessionDataStore extends AbstractSessionDataStore { public Map _map = new HashMap<>(); + public boolean _passivating; + + public TestSessionDataStore () + { + _passivating = false; + } + + public TestSessionDataStore (boolean passivating) + { + _passivating = passivating; + } - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#isPassivating() - */ @Override public boolean isPassivating() { - return false; + return _passivating; } - /** - * @see org.eclipse.jetty.server.session.SessionDataStore#exists(java.lang.String) - */ + @Override public boolean exists(String id) throws Exception { return _map.containsKey(id); } - /** - * @see org.eclipse.jetty.server.session.SessionDataMap#load(java.lang.String) - */ + @Override public SessionData load(String id) throws Exception { @@ -67,27 +71,21 @@ public class TestSessionDataStore extends AbstractSessionDataStore return nsd; } - /** - * @see org.eclipse.jetty.server.session.SessionDataMap#delete(java.lang.String) - */ + @Override public boolean delete(String id) throws Exception { return (_map.remove(id) != null); } - /** - * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doStore(java.lang.String, org.eclipse.jetty.server.session.SessionData, long) - */ + @Override public void doStore(String id, SessionData data, long lastSaveTime) throws Exception { _map.put(id, data); } - /** - * @see org.eclipse.jetty.server.session.AbstractSessionDataStore#doGetExpired(java.util.Set) - */ + @Override public Set doGetExpired(Set candidates) { @@ -102,5 +100,4 @@ public class TestSessionDataStore extends AbstractSessionDataStore } return set; } - } diff --git a/tests/test-sessions/test-sessions-common/src/main/resources/proxy-serialization.jar b/tests/test-sessions/test-sessions-common/src/main/resources/proxy-serialization.jar deleted file mode 100644 index fe3f0402dd9..00000000000 Binary files a/tests/test-sessions/test-sessions-common/src/main/resources/proxy-serialization.jar and /dev/null differ diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java index f818c6f0188..381f7b46cd0 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ClientCrossContextSessionTest.java @@ -107,6 +107,7 @@ public class ClientCrossContextSessionTest public static class TestServletA extends HttpServlet { + private static final long serialVersionUID = 1L; public String sessionId; @Override @@ -130,6 +131,7 @@ public class ClientCrossContextSessionTest public static class TestServletB extends HttpServlet { + private static final long serialVersionUID = 1L; public String sessionId; @Override @@ -141,8 +143,6 @@ public class ClientCrossContextSessionTest sessionId = session.getId(); - - // Add something to the session session.setAttribute("B", "B"); @@ -151,6 +151,4 @@ public class ClientCrossContextSessionTest assertTrue(objectA == null); } } - - } diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/CreationTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/CreationTest.java index 4664be00432..f942c00f4b0 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/CreationTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/CreationTest.java @@ -335,6 +335,7 @@ public class CreationTest public static class TestServlet extends HttpServlet { + private static final long serialVersionUID = 1L; public String _id = null; public CountDownLatch _synchronizer; public SessionDataStore _store; @@ -421,6 +422,8 @@ public class CreationTest public static class TestServletB extends HttpServlet { + private static final long serialVersionUID = 1L; + @Override protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException { diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java new file mode 100644 index 00000000000..34e86b44dcd --- /dev/null +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DefaultSessionCacheTest.java @@ -0,0 +1,672 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 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.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import javax.servlet.http.HttpSessionActivationListener; +import javax.servlet.http.HttpSessionEvent; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.junit.Test; + +/** + * DefaultSessionCacheTest + * + * + */ +public class DefaultSessionCacheTest +{ + + public static class TestSessionActivationListener implements HttpSessionActivationListener + { + public int passivateCalls = 0; + public int activateCalls = 0; + + @Override + public void sessionWillPassivate(HttpSessionEvent se) + { + ++passivateCalls; + } + + @Override + public void sessionDidActivate(HttpSessionEvent se) + { + ++activateCalls; + } + + } + + + /** + * Test sessions are saved when shutdown with a store. + * + * @throws Exception + */ + @Test + public void testShutdownWithSessionStore() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(true);//fake passivation + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + + context.start(); + + //put a session in the cache and store + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + Session session = cache.newSession(data); + TestSessionActivationListener listener = new TestSessionActivationListener(); + cache.put("1234", session); + assertTrue(cache.contains("1234")); + session.setAttribute("aaa", listener); + cache.put("1234", session); + + assertTrue(store.exists("1234")); + assertTrue(cache.contains("1234")); + + context.stop(); //calls shutdown + + assertTrue(store.exists("1234")); + assertFalse(cache.contains("1234")); + assertEquals(2, listener.passivateCalls); + assertEquals(1, listener.activateCalls); + } + + + + + /** + * Test that a new Session object can be created from + * previously persisted data (SessionData). + * @throws Exception + */ + @Test + public void testNewSessionFromPersistedData() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(true);//fake passivation + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + + context.start(); + + long now = System.currentTimeMillis(); + //fake persisted data + SessionData data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + Session session = cache.newSession(data); + assertNotNull(session); + assertEquals("1234", session.getId()); + } + + /** + * Test that a session id can be renewed. + * + * @throws Exception + */ + @Test + public void testRenewSessionId() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(true);//fake passivation + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + + context.start(); + + //put a session in the cache and store + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + Session session = cache.newSession(data); + cache.put("1234", session); + assertTrue(cache.contains("1234")); + + cache.renewSessionId("1234", "5678"); + + assertTrue(cache.contains("5678")); + assertFalse(cache.contains("1234")); + + assertTrue(store.exists("5678")); + assertFalse(store.exists("1234")); + } + + + + /** + * Test that a session that is in the cache can be retrieved. + * + * @throws Exception + */ + @Test + public void testGetSessionInCache() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(); + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + context.start(); + + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + Session session = cache.newSession(data); + + //put the session in the cache + cache.put("1234", session); + + assertNotNull(cache.get("1234")); + } + + /** + * Test that the cache can load from the SessionDataStore + * @throws Exception + */ + @Test + public void testGetSessionNotInCache() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(); + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + context.start(); + + //put session data into the store + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + store.store("1234", data); + + assertFalse(cache.contains("1234")); + + Session session = cache.get("1234"); + assertNotNull(session); + assertEquals("1234", session.getId()); + assertEquals(now-20, session.getCreationTime()); + } + + @Test + public void testPutRequestsStillActive() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(); + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + context.start(); + + //make a session + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + data.setExpiry(now+TimeUnit.DAYS.toMillis(1)); + Session session = cache.newSession(data); + session.access(now); //simulate request still active + cache.put("1234", session); + assertTrue(session.isResident()); + assertTrue(cache.contains("1234")); + assertFalse(store.exists("1234")); + + } + + @Test + public void testPutLastRequest() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(); + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + context.start(); + + //make a session + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + data.setExpiry(now+TimeUnit.DAYS.toMillis(1)); + Session session = cache.newSession(data); + session.access(now); //simulate request still active + session.complete(); //simulate request exiting + cache.put("1234", session); + assertTrue(session.isResident()); + assertTrue(cache.contains("1234")); + assertTrue(store.exists("1234")); + + } + + /** + * Test contains method. + * + * @throws Exception + */ + @Test + public void testContains() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(); + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + context.start(); + + //test one that isn't contained + assertFalse(cache.contains("1234")); + + //test one that is contained + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + Session session = cache.newSession(data); + + //put the session in the cache + cache.put("1234", session); + assertTrue(cache.contains("1234")); + } + + /** + * Test the exist method. + * + * @throws Exception + */ + @Test + public void testExists() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(); + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + context.start(); + + //test one that doesn't exist at all + assertFalse(cache.exists("1234")); + + //test one that only exists in the store + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + store.store("1234", data); + assertTrue(cache.exists("1234")); + + //test one that exists in the cache also + Session session = cache.newSession(data); + cache.put("1234", session); + assertTrue(cache.exists("1234")); + } + + + /** + * Test the delete method. + * + * @throws Exception + */ + @Test + public void testDelete() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(); + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + context.start(); + + //test remove non-existant session + Session session = cache.delete("1234"); + assertNull(session); + + //test remove of existing session in store only + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + store.store("1234", data); + session = cache.delete("1234"); + assertNotNull(session); + assertFalse(store.exists("1234")); + assertFalse(cache.contains("1234")); + + //test remove of session in both store and cache + data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + session = cache.newSession(data); + cache.put("1234", session); + assertTrue(store.exists("1234")); + assertTrue(cache.contains("1234")); + session = cache.delete("1234"); + assertNotNull(session); + assertFalse(store.exists("1234")); + assertFalse(cache.contains("1234")); + } + + + + @Test + public void testExpiration() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(); + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + context.start(); + + //test no candidates, no data in store + Set result = cache.checkExpiration(Collections.emptySet()); + assertTrue(result.isEmpty()); + + //test candidates that are in the cache and NOT expired + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + data.setExpiry(now+TimeUnit.DAYS.toMillis(1)); + Session session = cache.newSession(data); + cache.put("1234", session); + assertTrue(cache.exists("1234")); + result = cache.checkExpiration(Collections.singleton("1234")); + assertTrue(result.isEmpty()); + + //test candidates that are in the cache AND expired + data.setExpiry(1); + cache.put("1234", session); + result = cache.checkExpiration(Collections.singleton("1234")); + assertEquals(1, result.size()); + assertEquals("1234", result.iterator().next()); + + //test candidates that are not in the cache + SessionData data2 = store.newSessionData("567", now-50, now-40, now-30, TimeUnit.MINUTES.toMillis(10)); + data2.setExpiry(1); + store.store("567", data2); + + result = cache.checkExpiration(Collections.emptySet()); + assertNotNull(result); + assertEquals(2, result.size()); + assertTrue(result.contains("1234")); + assertTrue(result.contains("567")); + } + + @Test + public void testCheckInactiveSession() + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(); + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + context.start(); + + //test NEVER EVICT + //test session that is not resident + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + data.setExpiry(now+TimeUnit.DAYS.toMillis(1)); + Session session = cache.newSession(data); + cache.checkInactiveSession(session); + assertFalse(store.exists("1234")); + assertFalse(cache.contains("1234")); + assertFalse(session.isResident()); + //ie nothing happens to the session + + //test session that is resident but not valid + cache.put("1234", session); + session._state = Session.State.INVALID; + cache.checkInactiveSession(session); + assertTrue(store.exists("1234")); + assertTrue(cache.contains("1234")); + assertTrue(session.isResident()); + assertFalse(session.isValid()); + //ie nothing happens to the session + + //test session that is resident, is valid, but NEVER_EVICT + session._state = Session.State.VALID; + cache.checkInactiveSession(session); + assertTrue(store.exists("1234")); + assertTrue(cache.contains("1234")); + assertTrue(session.isResident()); + assertTrue(session.isValid()); + //ie nothing happens to the session + + //test EVICT_ON_INACTIVITY, session has passed the inactivity time + cache.setEvictionPolicy(SessionCache.EVICT_ON_INACTIVITY); + data.setAccessed(now-TimeUnit.SECONDS.toMillis(30)); + cache.checkInactiveSession(session); + assertFalse(cache.contains("1234")); + assertFalse(session.isResident()); + + //test EVICT_ON_SESSION_EXIT with requests still active. + //this should not affect the session because it this is an idle test only + SessionData data2 = store.newSessionData("567", now, now-TimeUnit.SECONDS.toMillis(30), now-TimeUnit.SECONDS.toMillis(40), TimeUnit.MINUTES.toMillis(10)); + data2.setExpiry(now+TimeUnit.DAYS.toMillis(1));//not expired + Session session2 = cache.newSession(data2); + cache.put("567", session2);//ensure session is in cache + cache.setEvictionPolicy(SessionCache.EVICT_ON_SESSION_EXIT); + session2.access(System.currentTimeMillis());//simulate 1 request in session + assertTrue(cache.contains("567")); + cache.checkInactiveSession(session2); + assertTrue(cache.contains("567")); //not evicted + + + //test EVICT_ON_SESSION_EXIT - requests not active + //this should not affect the session because this is an idle test only + session2.complete(); //simulate last request leaving session + cache.checkInactiveSession(session2); + assertTrue(cache.contains("567")); + + } + + @Test + public void testSaveOnEviction () + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.EVICT_ON_INACTIVITY); //evict after 1 second inactivity + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(); + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + context.start(); + + //make a session + long now = System.currentTimeMillis(); + SessionData data = store.newSessionData("1234", now-20, now-10, now-20, TimeUnit.MINUTES.toMillis(10)); + data.setExpiry(now+TimeUnit.DAYS.toMillis(1)); + Session session = cache.newSession(data); + cache.put("1234", session); //make it resident + assertTrue(cache.contains("1234")); + long accessed = now-TimeUnit.SECONDS.toMillis(30); //make it idle + data.setAccessed(accessed); + cache.checkInactiveSession(session); + assertFalse(cache.contains("1234")); + assertFalse(session.isResident()); + SessionData retrieved = store.load("1234"); + assertEquals(accessed, retrieved.getAccessed()); //check that we persisted the session before we evicted + } + + @Test + public void testSaveOnCreateTrue () + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + cacheFactory.setSaveOnCreate(true); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(); + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + context.start(); + + long now = System.currentTimeMillis(); + cache.newSession(null, "1234", now, TimeUnit.MINUTES.toMillis(10)); + assertTrue(store.exists("1234")); + } + + + @Test + public void testSaveOnCreateFalse () + throws Exception + { + Server server = new Server(); + + ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); + context.setContextPath("/test"); + context.setServer(server); + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + cacheFactory.setSaveOnCreate(false); + DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler()); + + TestSessionDataStore store = new TestSessionDataStore(); + cache.setSessionDataStore(store); + context.getSessionHandler().setSessionCache(cache); + context.start(); + + long now = System.currentTimeMillis(); + cache.newSession(null, "1234", now, TimeUnit.MINUTES.toMillis(10)); + assertFalse(store.exists("1234")); + } + + +} diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DeleteUnloadableSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DeleteUnloadableSessionTest.java index e14893dc4cc..53922ca3b45 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DeleteUnloadableSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DeleteUnloadableSessionTest.java @@ -140,12 +140,14 @@ public class DeleteUnloadableSessionTest } /** - * TestServlet + * TestFooServlet * * */ public static class TestServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + @Override protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException { diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java index 414327c96f2..27301843c40 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/DirtyAttributeTest.java @@ -38,7 +38,6 @@ import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.servlet.ServletContextHandler; -import org.junit.After; import org.junit.Test; diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java index 659d5b71730..1354212d2e5 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.util.concurrent.TimeUnit; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -44,31 +45,18 @@ import org.junit.Test; /** * IdleSessionTest * - * Checks that a session can be idled and de-idled on the next request if it hasn't expired. - * - * - * + * Checks that a session can be passivated and re-activated on the next request if it hasn't expired. */ public class IdleSessionTest { protected TestServlet _servlet = new TestServlet(); protected TestServer _server1 = null; - - /** - * @param sec - */ - public void pause (int sec) + + public void pause (int sec)throws InterruptedException { - try - { - Thread.sleep(sec * 1000L); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } + Thread.sleep(TimeUnit.SECONDS.toMillis(sec)); } /** @@ -81,7 +69,7 @@ public class IdleSessionTest String servletMapping = "/server"; int inactivePeriod = 20; int scavengePeriod = 3; - int evictionSec = 5; + int evictionSec = 5; //evict from cache if idle for 5 sec DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); cacheFactory.setEvictionPolicy(evictionSec); @@ -106,32 +94,32 @@ public class IdleSessionTest String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); - //and wait until the session should be idled out - pause(evictionSec*3); + //and wait until the session should be passivated out + pause(evictionSec*2); //check that the session has been idled String id = TestServer.extractSessionId(sessionCookie); assertFalse(contextHandler.getSessionHandler().getSessionCache().contains(id)); assertTrue(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore().exists(id)); - //make another request to de-idle the session + //make another request to reactivate the session Request request = client.newRequest(url + "?action=test"); ContentResponse response2 = request.send(); assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); - //check session de-idled + //check session reactivated assertTrue(contextHandler.getSessionHandler().getSessionCache().contains(id)); - //wait again for the session to be idled - pause(evictionSec*3); + //wait again for the session to be passivated + pause(evictionSec*2); //check that it is assertFalse(contextHandler.getSessionHandler().getSessionCache().contains(id)); assertTrue(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore().exists(id)); - //While idle, take some action to ensure that a deidle won't work, like + //While passivated, take some action to ensure that a reactivate won't work, like //deleting the sessions in the store ((TestSessionDataStore)contextHandler.getSessionHandler().getSessionCache().getSessionDataStore())._map.clear(); @@ -140,7 +128,7 @@ public class IdleSessionTest response2 = request.send(); assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); - //Test trying to de-idle an expired session (ie before the scavenger can get to it) + //Test trying to reactivate an expired session (ie before the scavenger can get to it) //make a request to set up a session on the server response = client.GET(url + "?action=init"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); @@ -149,20 +137,20 @@ public class IdleSessionTest id = TestServer.extractSessionId(sessionCookie); //and wait until the session should be idled out - pause(evictionSec * 3); + pause(evictionSec * 2); //stop the scavenger if (_server1.getHouseKeeper() != null) _server1.getHouseKeeper().stop(); - //check that the session is idle + //check that the session is passivated assertFalse(contextHandler.getSessionHandler().getSessionCache().contains(id)); assertTrue(contextHandler.getSessionHandler().getSessionCache().getSessionDataStore().exists(id)); //wait until the session should be expired pause (inactivePeriod + (3*scavengePeriod)); - //make another request to de-idle the session + //make another request to reactivate the session request = client.newRequest(url + "?action=testfail"); response2 = request.send(); assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java index af20e84b78f..2bb42a84ac2 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ImmortalSessionTest.java @@ -19,8 +19,8 @@ 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 static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.PrintWriter; @@ -131,6 +131,8 @@ public class ImmortalSessionTest public static class TestServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractModifyMaxInactiveIntervalTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java similarity index 84% rename from tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractModifyMaxInactiveIntervalTest.java rename to tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java index 37a9b37a426..8c48d4cdece 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractModifyMaxInactiveIntervalTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java @@ -19,9 +19,11 @@ package org.eclipse.jetty.server.session; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.util.concurrent.TimeUnit; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -37,28 +39,81 @@ import org.junit.Test; /** - * AbstractModifyMaxInactiveIntervalTest + * ModifyMaxInactiveIntervalTest * * * */ -public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTestBase +public class ModifyMaxInactiveIntervalTest extends AbstractTestBase { - public static int newMaxInactive = 20; public static int __scavenge = 1; + + + /** + * Test that setting an integer overflow valued max inactive interval + * results in an immortal session (value -1). + * + * @throws Exception + */ + @Test + public void testHugeMaxInactiveInterval() throws Exception + { + int inactivePeriod = Integer.MAX_VALUE * 60; //integer overflow + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(TestServer.DEFAULT_SCAVENGE_SEC); + + TestServer server = new TestServer(0, inactivePeriod, __scavenge, cacheFactory, storeFactory); + ServletContextHandler ctxA = server.addContext("/mod"); + ctxA.addServlet(TestModServlet.class, "/test"); + + server.start(); + int port=server.getPort(); + try + { + HttpClient client = new HttpClient(); + client.start(); + try + { + // Perform a request to create a session + ContentResponse response = client.GET("http://localhost:" + port + "/mod/test?action=create"); + + assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + String sessionCookie = response.getHeaders().get("Set-Cookie"); + assertTrue(sessionCookie != null); + String id = TestServer.extractSessionId(sessionCookie); + + //check that the maxInactive is -1 + Session s = ctxA.getSessionHandler().getSession(id); + assertEquals(-1, s.getMaxInactiveInterval()); + + } + finally + { + client.stop(); + } + } + finally + { + server.stop(); + } + + } @Test public void testReduceMaxInactiveInterval() throws Exception { int oldMaxInactive = 30; int newMaxInactive = 1; + int scavengeSec = __scavenge; DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(TestServer.DEFAULT_SCAVENGE_SEC); - TestServer server = new TestServer(0, oldMaxInactive, 1, cacheFactory, storeFactory); + TestServer server = new TestServer(0, oldMaxInactive, scavengeSec, cacheFactory, storeFactory); ServletContextHandler ctxA = server.addContext("/mod"); ctxA.addServlet(TestModServlet.class, "/test"); @@ -83,7 +138,7 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest assertEquals(HttpServletResponse.SC_OK,response.getStatus()); // Wait for the session to expire - Thread.sleep(1500*newMaxInactive); + Thread.sleep(TimeUnit.SECONDS.toMillis(newMaxInactive+scavengeSec)); //do another request using the cookie to ensure the session is NOT there request= client.newRequest("http://localhost:" + port + "/mod/test?action=test&val="+newMaxInactive); @@ -108,13 +163,14 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest { int oldMaxInactive = 1; int newMaxInactive = 10; + int scavengeSec = __scavenge; DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(TestServer.DEFAULT_SCAVENGE_SEC); - TestServer server = new TestServer(0, oldMaxInactive, 1, cacheFactory, storeFactory); + TestServer server = new TestServer(0, oldMaxInactive, scavengeSec, cacheFactory, storeFactory); ServletContextHandler ctxA = server.addContext("/mod"); ctxA.addServlet(TestModServlet.class, "/test"); @@ -139,7 +195,7 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest assertEquals(HttpServletResponse.SC_OK,response.getStatus()); // wait until the old inactive interval should have expired - Thread.sleep(1100*oldMaxInactive); + Thread.sleep(TimeUnit.SECONDS.toMillis(scavengeSec+oldMaxInactive)); //do another request using the cookie to ensure the session is still there request= client.newRequest("http://localhost:" + port + "/mod/test?action=test&val="+newMaxInactive); @@ -166,13 +222,14 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest int newMaxInactive = 120; //2min int evict = 2; int sleep = evict; + int scavenge = __scavenge; DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); cacheFactory.setEvictionPolicy(evict); SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(TestServer.DEFAULT_SCAVENGE_SEC); - TestServer server = new TestServer(0, oldMaxInactive, 1, cacheFactory, storeFactory); + TestServer server = new TestServer(0, oldMaxInactive, scavenge, cacheFactory, storeFactory); ServletContextHandler ctxA = server.addContext("/mod"); ctxA.addServlet(TestModServlet.class, "/test"); @@ -221,13 +278,14 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest int newMaxInactive = 2; int evict = 4; int sleep = evict; + int scavenge = __scavenge; DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); cacheFactory.setEvictionPolicy(evict); SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(TestServer.DEFAULT_SCAVENGE_SEC); - TestServer server = new TestServer(0, oldMaxInactive, 1, cacheFactory, storeFactory); + TestServer server = new TestServer(0, oldMaxInactive, scavenge, cacheFactory, storeFactory); ServletContextHandler ctxA = server.addContext("/mod"); ctxA.addServlet(TestModServlet.class, "/test"); @@ -273,13 +331,14 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest { int oldMaxInactive = -1; int newMaxInactive = 120; + int scavenge = __scavenge; DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(TestServer.DEFAULT_SCAVENGE_SEC); - TestServer server = new TestServer(0, oldMaxInactive, 1, cacheFactory, storeFactory); + TestServer server = new TestServer(0, oldMaxInactive, scavenge, cacheFactory, storeFactory); ServletContextHandler ctxA = server.addContext("/mod"); ctxA.addServlet(TestModServlet.class, "/test"); @@ -324,15 +383,15 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest public void testNoExpireSessionInUse() throws Exception { int maxInactive = 3; - int sleep = maxInactive + (int)(maxInactive * 0.8); - + int scavenge = __scavenge; + int sleep = maxInactive + scavenge; DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(TestServer.DEFAULT_SCAVENGE_SEC); - TestServer server = new TestServer(0, maxInactive, 1, cacheFactory, storeFactory); + TestServer server = new TestServer(0, maxInactive, scavenge, cacheFactory, storeFactory); ServletContextHandler ctxA = server.addContext("/mod"); ctxA.addServlet(TestModServlet.class, "/test"); @@ -345,7 +404,6 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest try { // Perform a request to create a session - ContentResponse response = client.GET("http://localhost:" + port + "/mod/test?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); @@ -376,7 +434,7 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest { int oldMaxInactive = 4; int newMaxInactive = 20; - int sleep = oldMaxInactive+(int)(oldMaxInactive * 0.8); + int sleep = oldMaxInactive+__scavenge; DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); @@ -395,8 +453,7 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest client.start(); try { - // Perform a request to create a session - + // Perform a request to create a session ContentResponse response = client.GET("http://localhost:" + port + "/mod/test?action=create"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); @@ -410,7 +467,7 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest assertEquals(HttpServletResponse.SC_OK,response.getStatus()); //wait for longer than the old inactive interval - Thread.sleep(sleep*1000L); + Thread.sleep(TimeUnit.SECONDS.toMillis(sleep)); //do another request using the cookie to ensure the session is still there request= client.newRequest("http://localhost:" + port + "/mod/test?action=test&val="+newMaxInactive); @@ -488,6 +545,7 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest if ("create".equals(action)) { HttpSession session = request.getSession(true); + assertNotNull(session); return; } @@ -502,7 +560,7 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest int wait = (tmp==null?0:Integer.parseInt(tmp)); if (wait >0) { - try { Thread.sleep(wait*1000);}catch (Exception e) {throw new ServletException(e);} + try { Thread.sleep(TimeUnit.SECONDS.toMillis(wait));}catch (Exception e) {throw new ServletException(e);} } HttpSession session = request.getSession(false); if (session == null) @@ -531,7 +589,7 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest if (interval > 0) { - try{Thread.sleep(interval*1000);}catch (Exception e) {throw new ServletException(e);} + try{Thread.sleep(TimeUnit.SECONDS.toMillis(interval));}catch (Exception e) {throw new ServletException(e);} } session = request.getSession(false); @@ -558,5 +616,15 @@ public abstract class AbstractModifyMaxInactiveIntervalTest extends AbstractTest } } } + + + /** + * + */ + @Override + public SessionDataStoreFactory createSessionDataStoreFactory() + { + return new TestSessionDataStoreFactory(); + } } diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNonClusteredSessionScavengingTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java similarity index 67% rename from tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNonClusteredSessionScavengingTest.java rename to tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java index 3e2abd8e2cc..7e16dfdcb30 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractNonClusteredSessionScavengingTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/NonClusteredSessionScavengingTest.java @@ -20,11 +20,14 @@ package org.eclipse.jetty.server.session; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.IOException; +import java.util.concurrent.TimeUnit; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -39,31 +42,95 @@ import org.eclipse.jetty.servlet.ServletContextHandler; import org.junit.Test; /** - * AbstractNonClusteredSessionScavengingTest + * NonClusteredSessionScavengingTest * * Create a session, wait for it to be scavenged, re-present the cookie and check that a * new session is created. */ -public abstract class AbstractNonClusteredSessionScavengingTest extends AbstractTestBase +public class NonClusteredSessionScavengingTest extends AbstractTestBase { public SessionDataStore _dataStore; - - public abstract void assertSession (String id, boolean exists); - - public void pause(int scavenge) + + public void pause(int scavenge) throws InterruptedException { + Thread.sleep(TimeUnit.SECONDS.toMillis(scavenge)); + } + + + @Test + public void testNoScavenging() throws Exception + { + String contextPath = "/"; + String servletMapping = "/server"; + int inactivePeriod = 3; + int scavengePeriod = 0; //turn off scavenging + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); + + + TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod, + cacheFactory, storeFactory); + ServletContextHandler context1 = server1.addContext(contextPath); + context1.addServlet(TestServlet.class, servletMapping); + TestHttpSessionListener listener = new TestHttpSessionListener(); + context1.getSessionHandler().addEventListener(listener); + + try { - Thread.sleep(scavenge * 1000L); + server1.start(); + int port1 = server1.getPort(); + + HttpClient client = new HttpClient(); + client.start(); + try + { + String url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1); + + + // Create the session + ContentResponse response1 = client.GET(url + "?action=create"); + assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); + String sessionCookie = response1.getHeaders().get("Set-Cookie"); + assertTrue(sessionCookie != null); + SessionHandler m1 = context1.getSessionHandler(); + assertEquals(1, m1.getSessionsCreated()); + + + // Wait a while to ensure that the session should have expired, if the + //scavenger was running + pause(2*inactivePeriod); + + assertEquals(1, m1.getSessionsCreated()); + + + if (m1 instanceof TestSessionHandler) + { + ((TestSessionHandler)m1).assertCandidatesForExpiry(0); + } + + //check the session listener did not get called + assertTrue(listener.destroyedSessions.isEmpty()); + } + finally + { + client.stop(); + } } - catch (InterruptedException e) + finally { - e.printStackTrace(); + server1.stop(); } } + + + + @Test public void testNewSession() throws Exception { @@ -75,12 +142,12 @@ public abstract class AbstractNonClusteredSessionScavengingTest extends Abstract cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod); - + TestServer server = new TestServer(0, maxInactivePeriod, scavengePeriod, - cacheFactory, storeFactory); + cacheFactory, storeFactory); ServletContextHandler context = server.addContext("/"); _dataStore = context.getSessionHandler().getSessionCache().getSessionDataStore(); - + context.addServlet(TestServlet.class, servletMapping); String contextPath = "/"; @@ -100,13 +167,15 @@ public abstract class AbstractNonClusteredSessionScavengingTest extends Abstract // Let's wait for the scavenger to run pause(maxInactivePeriod + scavengePeriod); - assertSession (TestServer.extractSessionId(sessionCookie), false); + assertFalse(_dataStore.exists(TestServer.extractSessionId(sessionCookie))); // The session should not be there anymore, but we present an old cookie // The server should create a new session. Request request = client.newRequest("http://localhost:" + port + contextPath + servletMapping.substring(1) + "?action=old-create"); response = request.send(); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + String sessionCookie2 = response.getHeaders().get("Set-Cookie"); + assertNotEquals(TestServer.extractSessionId(sessionCookie), TestServer.extractSessionId(sessionCookie2)); } finally { @@ -123,7 +192,7 @@ public abstract class AbstractNonClusteredSessionScavengingTest extends Abstract public void testImmortalSession() throws Exception { String servletMapping = "/server"; - int scavengePeriod = 3; + int scavengePeriod = 1; int maxInactivePeriod = 0; DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); @@ -155,7 +224,7 @@ public abstract class AbstractNonClusteredSessionScavengingTest extends Abstract // Let's wait for the scavenger to run pause(2*scavengePeriod); - assertSession(TestServer.extractSessionId(sessionCookie), true); + assertTrue(_dataStore.exists(TestServer.extractSessionId(sessionCookie))); // Test that the session is still there Request request = client.newRequest("http://localhost:" + port + contextPath + servletMapping.substring(1) + "?action=old-test"); @@ -203,8 +272,17 @@ public abstract class AbstractNonClusteredSessionScavengingTest extends Abstract } else { - assertTrue(false); + fail("Unknown servlet action"); } } } + + /** + * + */ + @Override + public SessionDataStoreFactory createSessionDataStoreFactory() + { + return new TestSessionDataStoreFactory(); + } } diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/RedirectSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/RedirectSessionTest.java index 01cb1e63699..16049071210 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/RedirectSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/RedirectSessionTest.java @@ -42,8 +42,6 @@ import org.junit.Test; */ public class RedirectSessionTest { - - @Test public void testSessionRedirect() throws Exception @@ -58,9 +56,6 @@ public class RedirectSessionTest testServletContextHandler.addServlet(Servlet1.class, "/one"); testServletContextHandler.addServlet(Servlet2.class, "/two"); - - - try { testServer.start(); @@ -89,6 +84,8 @@ public class RedirectSessionTest public static class Servlet1 extends HttpServlet { + private static final long serialVersionUID = 1L; + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { @@ -102,6 +99,8 @@ public class RedirectSessionTest public static class Servlet2 extends HttpServlet { + private static final long serialVersionUID = 1L; + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { @@ -113,7 +112,4 @@ public class RedirectSessionTest } } - - - } diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java index a9cbf650945..f415fe1cb63 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/ReentrantRequestSessionTest.java @@ -94,6 +94,8 @@ public class ReentrantRequestSessionTest public static class TestServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { @@ -103,8 +105,6 @@ public class ReentrantRequestSessionTest @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - - String action = request.getParameter("action"); if ("create".equals(action)) { diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java index 7e1b47f1238..435f71ac038 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/RemoveSessionTest.java @@ -81,7 +81,7 @@ public class RemoveSessionTest String sessionCookie = response.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); - //ensure sessionCreated listener is called + //ensure sessionCreated bindingListener is called assertTrue (testListener.isCreated()); assertEquals(1, m.getSessionsCreated()); assertEquals(1, ((DefaultSessionCache)m.getSessionCache()).getSessionsMax()); @@ -91,7 +91,7 @@ public class RemoveSessionTest Request request = client.newRequest("http://localhost:" + port + contextPath + servletMapping + "?action=delete"); response = request.send(); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - //ensure sessionDestroyed listener is called + //ensure sessionDestroyed bindingListener is called assertTrue(testListener.isDestroyed()); assertEquals(0, ((DefaultSessionCache)m.getSessionCache()).getSessionsCurrent()); assertEquals(1, ((DefaultSessionCache)m.getSessionCache()).getSessionsMax()); @@ -121,7 +121,8 @@ public class RemoveSessionTest } public static class TestServlet extends HttpServlet { - @Override + private static final long serialVersionUID = 1L; + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String action = request.getParameter("action"); diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameContextForwardedSessionTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameContextForwardedSessionTest.java index f02d89c8ab2..6b68b026351 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameContextForwardedSessionTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameContextForwardedSessionTest.java @@ -64,8 +64,7 @@ public class SameContextForwardedSessionTest @Test public void testSessionCreateInForward() throws Exception - { - + { DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory(); @@ -77,8 +76,6 @@ public class SameContextForwardedSessionTest testServletContextHandler.addServlet(Servlet2.class, "/two"); testServletContextHandler.addServlet(Servlet3.class, "/three"); testServletContextHandler.addServlet(Servlet4.class, "/four"); - - try { @@ -122,6 +119,7 @@ public class SameContextForwardedSessionTest public static class Servlet1 extends HttpServlet { + private static final long serialVersionUID = 1L; CountDownLatch _synchronizer; public void setSynchronizer(CountDownLatch sync) @@ -151,6 +149,8 @@ public class SameContextForwardedSessionTest public static class Servlet2 extends HttpServlet { + private static final long serialVersionUID = 1L; + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { @@ -171,6 +171,8 @@ public class SameContextForwardedSessionTest public static class Servlet3 extends HttpServlet { + private static final long serialVersionUID = 1L; + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { @@ -189,6 +191,8 @@ public class SameContextForwardedSessionTest public static class Servlet4 extends HttpServlet { + private static final long serialVersionUID = 1L; + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java index ec13b65484c..f3f0b43ff36 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SameNodeLoadTest.java @@ -189,6 +189,8 @@ public class SameNodeLoadTest public static class TestServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + @Override protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SaveOptimizeTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SaveOptimizeTest.java index 4e51832572f..d2b5e064623 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SaveOptimizeTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SaveOptimizeTest.java @@ -53,12 +53,9 @@ import org.junit.Test; */ public class SaveOptimizeTest { - protected TestServlet _servlet; protected TestServer _server1 = null; - - /** * Create and then invalidate a session in the same request. @@ -488,6 +485,7 @@ public class SaveOptimizeTest public static class TestServlet extends HttpServlet { + private static final long serialVersionUID = 1L; public String _id = null; public SessionDataStore _store; public HttpSession _firstSession = null; diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionEvictionFailureTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionEvictionFailureTest.java index 440938adfaf..80c4dae9f34 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionEvictionFailureTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionEvictionFailureTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertNull; import java.io.IOException; import java.util.Set; +import java.util.concurrent.TimeUnit; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -153,7 +154,7 @@ public class SessionEvictionFailureTest /** - * TestServlet + * TestFooServlet * * */ @@ -179,23 +180,13 @@ public class SessionEvictionFailureTest } } } - - - /** - * @param sec - */ - public static void pause (int sec) + + + public static void pause (int sec) throws InterruptedException { - try - { - Thread.currentThread().sleep(sec*1000L); - } - catch (InterruptedException e) - { - //just return; - } + Thread.currentThread().sleep(TimeUnit.SECONDS.toMillis(sec)); } - + @Test diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateCreateScavengeTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateCreateScavengeTest.java similarity index 90% rename from tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateCreateScavengeTest.java rename to tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateCreateScavengeTest.java index 872e0e41349..eef8a67065e 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionInvalidateCreateScavengeTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionInvalidateCreateScavengeTest.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -46,46 +47,22 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.junit.Test; /** - * AbstractSessionInvalidateCreateScavengeTest + * SessionInvalidateCreateScavengeTest * * This test verifies that invalidating an existing session and creating * a new session within the scope of a single request will expire the * newly created session correctly (removed from the server and session listeners called). * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=377610 */ -public abstract class AbstractSessionInvalidateCreateScavengeTest extends AbstractTestBase +public class SessionInvalidateCreateScavengeTest extends AbstractTestBase { - public class MySessionListener implements HttpSessionListener + @Override + public SessionDataStoreFactory createSessionDataStoreFactory() { - List destroys = new ArrayList<>(); - - @Override - public void sessionCreated(HttpSessionEvent e) - { - - } - - @Override - public void sessionDestroyed(HttpSessionEvent e) - { - destroys.add(e.getSession().hashCode()); - } + return new TestSessionDataStoreFactory(); } - - public void pause(int scavengePeriod) - { - try - { - Thread.sleep(scavengePeriod * 1000L); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - } - @Test @SuppressWarnings("ReferenceEquality") public void testSessionScavenge() throws Exception @@ -93,22 +70,22 @@ public abstract class AbstractSessionInvalidateCreateScavengeTest extends Abstra String contextPath = "/"; String servletMapping = "/server"; int inactivePeriod = 6; - int scavengePeriod = 3; - + int scavengePeriod = 1; + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); SessionDataStoreFactory storeFactory = createSessionDataStoreFactory(); ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod); - + TestServer server = new TestServer(0, inactivePeriod, scavengePeriod, - cacheFactory, storeFactory); + cacheFactory, storeFactory); ServletContextHandler context = server.addContext(contextPath); TestServlet servlet = new TestServlet(); ServletHolder holder = new ServletHolder(servlet); context.addServlet(holder, servletMapping); MySessionListener listener = new MySessionListener(); context.getSessionHandler().addEventListener(listener); - + try { server.start(); @@ -126,14 +103,14 @@ public abstract class AbstractSessionInvalidateCreateScavengeTest extends Abstra assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); String sessionCookie = response1.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); - + // Make a request which will invalidate the existing session and create a new one Request request2 = client.newRequest(url + "?action=test"); ContentResponse response2 = request2.send(); assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); // Wait for the scavenger to run - pause(inactivePeriod+(2*scavengePeriod)); + Thread.currentThread().sleep(TimeUnit.SECONDS.toMillis(inactivePeriod+scavengePeriod)); //test that the session created in the last test is scavenged: //the HttpSessionListener should have been called when session1 was invalidated and session2 was scavenged @@ -153,15 +130,24 @@ public abstract class AbstractSessionInvalidateCreateScavengeTest extends Abstra } } - public static class Foo implements Serializable + public class MySessionListener implements HttpSessionListener { - public boolean bar = false; - - public boolean getBar() { return bar;}; + List destroys = new ArrayList<>(); + + public void sessionCreated(HttpSessionEvent e) + { + + } + + public void sessionDestroyed(HttpSessionEvent e) + { + destroys.add(e.getSession().hashCode()); + } } public static class MySessionBindingListener implements HttpSessionBindingListener, Serializable { + private static final long serialVersionUID = 1L; private boolean unbound = false; @Override @@ -179,6 +165,7 @@ public abstract class AbstractSessionInvalidateCreateScavengeTest extends Abstra public static class TestServlet extends HttpServlet { + private static final long serialVersionUID = 1L; public MySessionBindingListener listener = new MySessionBindingListener(); @@ -220,11 +207,12 @@ public abstract class AbstractSessionInvalidateCreateScavengeTest extends Abstra assertTrue(!newId.equals(oldId)); assertTrue (session.getAttribute("identity")==null); session.setAttribute("identity", "session2"); - session.setAttribute("listener", listener); + session.setAttribute("bindingListener", listener); } else fail("Session already missing"); } } } + } diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionListenerTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionListenerTest.java index 21352f10651..7a034922e99 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionListenerTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionListenerTest.java @@ -19,11 +19,15 @@ package org.eclipse.jetty.server.session; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.Serializable; +import java.net.HttpCookie; +import java.util.concurrent.TimeUnit; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -43,39 +47,17 @@ import org.junit.Test; /** * SessionListenerTest * - * Test that the HttpSessionBindingListeners are called. + * Test that session listeners are called. */ public class SessionListenerTest { - public static class MySessionBindingListener implements HttpSessionBindingListener, Serializable - { - boolean unbound = false; - boolean bound = false; - - @Override - public void valueUnbound(HttpSessionBindingEvent event) - { - unbound = true; - } - - @Override - public void valueBound(HttpSessionBindingEvent event) - { - bound = true; - } - } - - public static class Foo implements Serializable - { - public boolean bar = false; - - public boolean getBar() { return bar;}; - } - - - + /** + * Test that listeners are called when a session is deliberately invalidated. + * + * @throws Exception + */ @Test - public void testListener() throws Exception + public void testListenerWithInvalidation() throws Exception { String contextPath = ""; String servletMapping = "/server"; @@ -90,6 +72,8 @@ public class SessionListenerTest TestServer server = new TestServer(0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory); ServletContextHandler context = server.addContext(contextPath); + TestHttpSessionListener listener = new TestHttpSessionListener(true); + context.getSessionHandler().addEventListener(listener); TestServlet servlet = new TestServlet(); ServletHolder holder = new ServletHolder(servlet); context.addServlet(holder, servletMapping); @@ -104,22 +88,23 @@ public class SessionListenerTest try { String url = "http://localhost:" + port1 + contextPath + servletMapping; - - // Create the session ContentResponse response1 = client.GET(url + "?action=init"); assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); String sessionCookie = response1.getHeaders().get("Set-Cookie"); assertTrue(sessionCookie != null); - assertTrue (servlet.listener.bound); + assertTrue (TestServlet.bindingListener.bound); + String sessionId = TestServer.extractSessionId(sessionCookie); + assertTrue(listener.createdSessions.contains(sessionId)); // Make a request which will invalidate the existing session Request request2 = client.newRequest(url + "?action=test"); ContentResponse response2 = request2.send(); assertEquals(HttpServletResponse.SC_OK,response2.getStatus()); - assertTrue (servlet.listener.unbound); + assertTrue (TestServlet.bindingListener.unbound); + assertTrue (listener.destroyedSessions.contains(sessionId)); } finally { @@ -131,10 +116,158 @@ public class SessionListenerTest server.stop(); } } + + + /** + * Test that listeners are called when a session expires. + * + * @throws Exception + */ + @Test + public void testSessionExpiresWithListener() throws Exception + { + String contextPath = "/"; + String servletMapping = "/server"; + int inactivePeriod = 3; + int scavengePeriod = 1; + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod); + + TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod, + cacheFactory, storeFactory); + TestServlet servlet = new TestServlet(); + ServletHolder holder = new ServletHolder(servlet); + ServletContextHandler context = server1.addContext(contextPath); + context.addServlet(holder, servletMapping); + TestHttpSessionListener listener = new TestHttpSessionListener(true); + context.getSessionHandler().addEventListener(listener); + + server1.start(); + int port1 = server1.getPort(); + + try + { + HttpClient client = new HttpClient(); + client.start(); + String url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1); + + //make a request to set up a session on the server + ContentResponse response1 = client.GET(url + "?action=init"); + assertEquals(HttpServletResponse.SC_OK,response1.getStatus()); + String sessionCookie = response1.getHeaders().get("Set-Cookie"); + assertTrue(sessionCookie != null); + + String sessionId = TestServer.extractSessionId(sessionCookie); + + assertTrue(listener.createdSessions.contains(sessionId)); + + //and wait until the session should have expired + Thread.currentThread().sleep(TimeUnit.SECONDS.toMillis(inactivePeriod+(scavengePeriod))); + + assertTrue (listener.destroyedSessions.contains(sessionId)); + + assertNull(listener.ex); + } + finally + { + server1.stop(); + } + } + + /** + * Check that a session that is expired cannot be reused, and expiry listeners are called for it + * + * @throws Exception + */ + @Test + public void testExpiredSession() throws Exception + { + String contextPath = "/"; + String servletMapping = "/server"; + int inactivePeriod = 4; + int scavengePeriod = 1; + + DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory(); + cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT); + SessionDataStoreFactory storeFactory = new TestSessionDataStoreFactory(); + ((AbstractSessionDataStoreFactory)storeFactory).setGracePeriodSec(scavengePeriod); + + TestServer server1 = new TestServer(0, inactivePeriod, scavengePeriod, + cacheFactory, storeFactory); + SimpleTestServlet servlet = new SimpleTestServlet(); + ServletHolder holder = new ServletHolder(servlet); + ServletContextHandler context = server1.addContext(contextPath); + context.addServlet(holder, servletMapping); + TestHttpSessionListener listener = new TestHttpSessionListener(); + + context.getSessionHandler().addEventListener(listener); + + server1.start(); + int port1 = server1.getPort(); + + try + { + //save a session that has already expired + long now = System.currentTimeMillis(); + SessionData data = context.getSessionHandler().getSessionCache().getSessionDataStore().newSessionData("1234", now-10, now-5, now-10, 30000); + data.setExpiry(100); //make it expired a long time ago + context.getSessionHandler().getSessionCache().getSessionDataStore().store("1234", data); + + HttpClient client = new HttpClient(); + client.start(); + + port1 = server1.getPort(); + String url = "http://localhost:" + port1 + contextPath + servletMapping.substring(1); + + //make another request using the id of the expired session + Request request = client.newRequest(url + "?action=test"); + request.cookie(new HttpCookie("JSESSIONID", "1234")); + ContentResponse response = request.send(); + assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + + //should be a new session id + String cookie2 = response.getHeaders().get("Set-Cookie"); + assertNotEquals("1234", TestServer.extractSessionId(cookie2)); + + assertTrue (listener.destroyedSessions.contains("1234")); + + assertNull(listener.ex); + + } + finally + { + server1.stop(); + } + } + + + + public static class MySessionBindingListener implements HttpSessionBindingListener, Serializable + { + private static final long serialVersionUID = 1L; + boolean unbound = false; + boolean bound = false; + + public void valueUnbound(HttpSessionBindingEvent event) + { + unbound = true; + } + + public void valueBound(HttpSessionBindingEvent event) + { + bound = true; + } + } + + public static class TestServlet extends HttpServlet { - public static final MySessionBindingListener listener = new MySessionBindingListener(); + private static final long serialVersionUID = 1L; + public static final MySessionBindingListener bindingListener = new MySessionBindingListener(); @Override @@ -145,7 +278,7 @@ public class SessionListenerTest if ("init".equals(action)) { HttpSession session = request.getSession(true); - session.setAttribute("foo", listener); + session.setAttribute("foo", bindingListener); assertNotNull(session); } @@ -159,4 +292,20 @@ public class SessionListenerTest } } } + + public static class SimpleTestServlet extends HttpServlet + { + private static final long serialVersionUID = 1L; + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException + { + String action = request.getParameter("action"); + if ("test".equals(action)) + { + HttpSession session = request.getSession(true); + assertTrue(session != null); + } + } + } } diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java index b07ecacf338..d7d5092e918 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionRenewTest.java @@ -197,7 +197,8 @@ public class SessionRenewTest public static class TestServlet extends HttpServlet { - + private static final long serialVersionUID = 1L; + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {