Merge branch 'jetty-9.4.x' into jetty-10.0.x

This commit is contained in:
olivier lamy 2020-05-08 10:21:41 +10:00
commit 972cd95ec0
11 changed files with 545 additions and 111 deletions

101
Jenkinsfile vendored
View File

@ -3,51 +3,47 @@
pipeline { pipeline {
agent any agent any
// save some io during the build // save some io during the build
options { durabilityHint('PERFORMANCE_OPTIMIZED') } options { durabilityHint( 'PERFORMANCE_OPTIMIZED' ) }
stages { stages {
stage("Parallel Stage") { stage( "Parallel Stage" ) {
parallel { parallel {
stage("Build / Test - JDK11") { stage( "Build / Test - JDK11" ) {
agent { agent {
node { label 'linux' } node { label 'linux' }
} }
options { timeout(time: 120, unit: 'MINUTES') } options { timeout( time: 120, unit: 'MINUTES' ) }
steps { steps {
container('jetty-build') { container('jetty-build') {
mavenBuild("jdk11", "-T3 -Pmongodb clean install", "maven3", true) // -Pautobahn timeout( time: 120, unit: 'MINUTES' ) {
// Collect up the jacoco execution results (only on main build) mavenBuild( "jdk11", "-T3 -Pmongodb clean install", "maven3", true ) // -Pautobahn
jacoco inclusionPattern: '**/org/eclipse/jetty/**/*.class', // Collect up the jacoco execution results (only on main build)
exclusionPattern: '' + jacoco inclusionPattern: '**/org/eclipse/jetty/**/*.class',
// build tools exclusionPattern: '' +
'**/org/eclipse/jetty/ant/**' + // build tools
',**/org/eclipse/jetty/maven/**' + '**/org/eclipse/jetty/ant/**' + ',**/org/eclipse/jetty/maven/**' +
',**/org/eclipse/jetty/jspc/**' + ',**/org/eclipse/jetty/jspc/**' +
// example code / documentation // example code / documentation
',**/org/eclipse/jetty/embedded/**' + ',**/org/eclipse/jetty/embedded/**' + ',**/org/eclipse/jetty/asyncrest/**' +
',**/org/eclipse/jetty/asyncrest/**' + ',**/org/eclipse/jetty/demo/**' +
',**/org/eclipse/jetty/demo/**' + // special environments / late integrations
// special environments / late integrations ',**/org/eclipse/jetty/gcloud/**' + ',**/org/eclipse/jetty/infinispan/**' +
',**/org/eclipse/jetty/gcloud/**' + ',**/org/eclipse/jetty/osgi/**' + ',**/org/eclipse/jetty/spring/**' +
',**/org/eclipse/jetty/infinispan/**' + ',**/org/eclipse/jetty/http/spi/**' +
',**/org/eclipse/jetty/osgi/**' + // test classes
',**/org/eclipse/jetty/spring/**' + ',**/org/eclipse/jetty/tests/**' + ',**/org/eclipse/jetty/test/**',
',**/org/eclipse/jetty/http/spi/**' + execPattern: '**/target/jacoco.exec',
// test classes classPattern: '**/target/classes',
',**/org/eclipse/jetty/tests/**' + sourcePattern: '**/src/main/java'
',**/org/eclipse/jetty/test/**', warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']]
execPattern: '**/target/jacoco.exec', junit testResults: '**/target/surefire-reports/*.xml,**/target/invoker-reports/TEST*.xml,**/target/autobahntestsuite-reports/*.xml'
classPattern: '**/target/classes', }
sourcePattern: '**/src/main/java'
warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']]
junit testResults: '**/target/surefire-reports/*.xml,**/target/invoker-reports/TEST*.xml,**/target/autobahntestsuite-reports/*.xml'
} }
} }
} }
stage( "Build / Test - JDK14" ) {
stage("Build / Test - JDK14") {
agent { node { label 'linux' } } agent { node { label 'linux' } }
steps { steps {
container('jetty-build') { container( 'jetty-build' ) {
timeout( time: 120, unit: 'MINUTES' ) { timeout( time: 120, unit: 'MINUTES' ) {
mavenBuild( "jdk14", "-T3 -Pmongodb clean install", "maven3", true ) mavenBuild( "jdk14", "-T3 -Pmongodb clean install", "maven3", true )
warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']] warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']]
@ -57,7 +53,7 @@ pipeline {
} }
} }
stage("Build Javadoc") { stage( "Build Javadoc" ) {
agent { node { label 'linux' } } agent { node { label 'linux' } }
steps { steps {
container('jetty-build') { container('jetty-build') {
@ -69,23 +65,34 @@ pipeline {
} }
} }
} }
stage( "Build Compact3" ) {
agent { node { label 'linux' } }
steps {
container('jetty-build') {
timeout( time: 30, unit: 'MINUTES' ) {
mavenBuild( "jdk8", "-T3 -Pcompact3 clean install -DskipTests", "maven3", true )
warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']]
}
}
}
}
} }
} }
} }
} post {
post { failure {
failure { slackNotif()
slackNotif() }
} unstable {
unstable { slackNotif()
slackNotif() }
} fixed {
fixed { slackNotif()
slackNotif() }
} }
} }
} }
def slackNotif() { def slackNotif() {
script { script {
try { try {
@ -116,7 +123,7 @@ def slackNotif() {
*/ */
def mavenBuild(jdk, cmdline, mvnName, junitPublishDisabled) { def mavenBuild(jdk, cmdline, mvnName, junitPublishDisabled) {
def localRepo = ".repository" def localRepo = ".repository"
def mavenOpts = '-Xms1g -Xmx4g -Djava.awt.headless=true' def mavenOpts = '-Xms1g -Xmx6g -Djava.awt.headless=true'
withMaven( withMaven(
maven: mvnName, maven: mvnName,
@ -126,7 +133,7 @@ def mavenBuild(jdk, cmdline, mvnName, junitPublishDisabled) {
mavenOpts: mavenOpts, mavenOpts: mavenOpts,
mavenLocalRepo: localRepo) { mavenLocalRepo: localRepo) {
// Some common Maven command line + provided command line // Some common Maven command line + provided command line
sh "mvn -Pci -V -B -e -fae -Dmaven.test.failure.ignore=true -Djetty.testtracker.log=true $cmdline -Dunix.socket.tmp=" + env.JENKINS_HOME sh "mvn -Premote-session-tests -Pci -V -B -e -fae -Dmaven.test.failure.ignore=true -Djetty.testtracker.log=true $cmdline -Dunix.socket.tmp=" + env.JENKINS_HOME
} }
} }

View File

@ -641,6 +641,10 @@ public class ProxyConnectionFactory extends DetectorConnectionFactory
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Proxy v2 {} {}", getEndPoint(), proxyEndPoint.toString()); LOG.debug("Proxy v2 {} {}", getEndPoint(), proxyEndPoint.toString());
} }
else
{
_buffer.position(_buffer.position() + _length);
}
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Proxy v2 parsing dynamic packet part is now done, upgrading to {}", _nextProtocol); LOG.debug("Proxy v2 parsing dynamic packet part is now done, upgrading to {}", _nextProtocol);
@ -777,7 +781,7 @@ public class ProxyConnectionFactory extends DetectorConnectionFactory
{ {
return _tlvs != null ? _tlvs.get(type) : null; return _tlvs != null ? _tlvs.get(type) : null;
} }
@Override @Override
public void close(Throwable cause) public void close(Throwable cause)
{ {

View File

@ -0,0 +1,108 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.server;
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.ServletRequest;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.Attributes;
/**
* <p>Customizer that extracts the real local and remote address:port pairs from a {@link ProxyConnectionFactory}
* and sets them on the request with {@link ServletRequest#setAttribute(String, Object)}.
*/
public class ProxyCustomizer implements HttpConfiguration.Customizer
{
/**
* The remote address attribute name.
*/
public static final String REMOTE_ADDRESS_ATTRIBUTE_NAME = "org.eclipse.jetty.proxy.remote.address";
/**
* The remote port attribute name.
*/
public static final String REMOTE_PORT_ATTRIBUTE_NAME = "org.eclipse.jetty.proxy.remote.port";
/**
* The local address attribute name.
*/
public static final String LOCAL_ADDRESS_ATTRIBUTE_NAME = "org.eclipse.jetty.proxy.local.address";
/**
* The local port attribute name.
*/
public static final String LOCAL_PORT_ATTRIBUTE_NAME = "org.eclipse.jetty.proxy.local.port";
@Override
public void customize(Connector connector, HttpConfiguration channelConfig, Request request)
{
EndPoint endPoint = request.getHttpChannel().getEndPoint();
if (endPoint instanceof ProxyConnectionFactory.ProxyEndPoint)
{
EndPoint underlyingEndpoint = ((ProxyConnectionFactory.ProxyEndPoint)endPoint).unwrap();
request.setAttributes(new ProxyAttributes(underlyingEndpoint.getRemoteAddress(), underlyingEndpoint.getLocalAddress(), request.getAttributes()));
}
}
private static class ProxyAttributes extends Attributes.Wrapper
{
private final InetSocketAddress remoteAddress;
private final InetSocketAddress localAddress;
private ProxyAttributes(InetSocketAddress remoteAddress, InetSocketAddress localAddress, Attributes attributes)
{
super(attributes);
this.remoteAddress = remoteAddress;
this.localAddress = localAddress;
}
@Override
public Object getAttribute(String name)
{
switch (name)
{
case REMOTE_ADDRESS_ATTRIBUTE_NAME:
return remoteAddress.getAddress().getHostAddress();
case REMOTE_PORT_ATTRIBUTE_NAME:
return remoteAddress.getPort();
case LOCAL_ADDRESS_ATTRIBUTE_NAME:
return localAddress.getAddress().getHostAddress();
case LOCAL_PORT_ATTRIBUTE_NAME:
return localAddress.getPort();
default:
return super.getAttribute(name);
}
}
@Override
public Set<String> getAttributeNameSet()
{
Set<String> names = new HashSet<>(_attributes.getAttributeNameSet());
names.add(REMOTE_ADDRESS_ATTRIBUTE_NAME);
names.add(REMOTE_PORT_ATTRIBUTE_NAME);
names.add(LOCAL_ADDRESS_ATTRIBUTE_NAME);
names.add(LOCAL_PORT_ATTRIBUTE_NAME);
return names;
}
}
}

View File

@ -151,6 +151,39 @@ public class ProxyConnectionTest
assertThat(response, Matchers.containsString("remote=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:12345")); assertThat(response, Matchers.containsString("remote=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:12345"));
} }
@ParameterizedTest
@MethodSource("requestProcessors")
public void testLocalV2(RequestProcessor p) throws Exception
{
String proxy =
// Preamble
"0D0A0D0A000D0A515549540A" +
// V2, LOCAL
"20" +
// 0x1 : AF_INET 0x1 : STREAM.
"11" +
// Address length is 16.
"0010" +
// gibberish
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
;
String http = "GET /path HTTP/1.1\n" +
"Host: server:80\n" +
"Connection: close\n" +
"\n";
String response = p.sendRequestWaitingForResponse(TypeUtil.fromHexString(proxy), http.getBytes(StandardCharsets.US_ASCII));
assertThat(response, Matchers.containsString("HTTP/1.1 200"));
assertThat(response, Matchers.containsString("pathInfo=/path"));
assertThat(response, Matchers.containsString("local=0.0.0.0:0"));
assertThat(response, Matchers.containsString("remote=0.0.0.0:0"));
}
@ParameterizedTest @ParameterizedTest
@MethodSource("requestProcessors") @MethodSource("requestProcessors")
public void testMissingField(RequestProcessor p) throws Exception public void testMissingField(RequestProcessor p) throws Exception

View File

@ -0,0 +1,178 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.TypeUtil;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
public class ProxyCustomizerTest
{
private Server server;
private ProxyResponse sendProxyRequest(String proxyAsHexString, String rawHttp) throws IOException
{
try (Socket socket = new Socket(server.getURI().getHost(), server.getURI().getPort()))
{
OutputStream output = socket.getOutputStream();
output.write(TypeUtil.fromHexString(proxyAsHexString));
output.write(rawHttp.getBytes(StandardCharsets.UTF_8));
output.flush();
socket.shutdownOutput();
StringBuilder sb = new StringBuilder();
InputStream input = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
while (true)
{
String line = reader.readLine();
if (line == null)
break;
sb.append(line).append("\r\n");
}
return new ProxyResponse((InetSocketAddress)socket.getLocalSocketAddress(), (InetSocketAddress)socket.getRemoteSocketAddress(), sb.toString());
}
}
private static class ProxyResponse
{
private final InetSocketAddress localSocketAddress;
private final InetSocketAddress remoteSocketAddress;
private final String httpResponse;
public ProxyResponse(InetSocketAddress localSocketAddress, InetSocketAddress remoteSocketAddress, String httpResponse)
{
this.localSocketAddress = localSocketAddress;
this.remoteSocketAddress = remoteSocketAddress;
this.httpResponse = httpResponse;
}
}
@BeforeEach
void setUp() throws Exception
{
Handler handler = new AbstractHandler()
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
{
response.addHeader("preexisting.attribute", request.getAttribute("some.attribute").toString());
ArrayList<String> attributeNames = Collections.list(request.getAttributeNames());
Collections.sort(attributeNames);
response.addHeader("attributeNames", String.join(",", attributeNames));
response.addHeader("localAddress", request.getLocalAddr() + ":" + request.getLocalPort());
response.addHeader("remoteAddress", request.getRemoteAddr() + ":" + request.getRemotePort());
Object localAddress = request.getAttribute(ProxyCustomizer.LOCAL_ADDRESS_ATTRIBUTE_NAME);
if (localAddress != null)
response.addHeader("proxyLocalAddress", localAddress.toString() + ":" + request.getAttribute(ProxyCustomizer.LOCAL_PORT_ATTRIBUTE_NAME));
Object remoteAddress = request.getAttribute(ProxyCustomizer.REMOTE_ADDRESS_ATTRIBUTE_NAME);
if (remoteAddress != null)
response.addHeader("proxyRemoteAddress", remoteAddress.toString() + ":" + request.getAttribute(ProxyCustomizer.REMOTE_PORT_ATTRIBUTE_NAME));
baseRequest.setHandled(true);
}
};
server = new Server();
HttpConfiguration httpConfiguration = new HttpConfiguration();
httpConfiguration.addCustomizer((connector, channelConfig, request) -> request.setAttribute("some.attribute", "some value"));
httpConfiguration.addCustomizer(new ProxyCustomizer());
ServerConnector connector = new ServerConnector(server, new ProxyConnectionFactory(), new HttpConnectionFactory(httpConfiguration));
server.addConnector(connector);
server.setHandler(handler);
server.start();
}
@AfterEach
void tearDown() throws Exception
{
server.stop();
server = null;
}
@Test
void testProxyCustomizerWithProxyData() throws Exception
{
String proxy =
// Preamble
"0D0A0D0A000D0A515549540A" +
// V2, PROXY
"21" +
// 0x1 : AF_INET 0x1 : STREAM. Address length is 2*4 + 2*2 = 12 bytes.
"11" +
// length of remaining header (4+4+2+2 = 12)
"000C" +
// uint32_t src_addr; uint32_t dst_addr; uint16_t src_port; uint16_t dst_port;
"01010001" +
"010100FE" +
"3039" +
"1F90";
String http = "GET /1 HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n";
ProxyResponse response = sendProxyRequest(proxy, http);
assertThat(response.httpResponse, Matchers.containsString("localAddress: 1.1.0.254:8080"));
assertThat(response.httpResponse, Matchers.containsString("remoteAddress: 1.1.0.1:12345"));
assertThat(response.httpResponse, Matchers.containsString("proxyLocalAddress: " + response.remoteSocketAddress.getAddress().getHostAddress() + ":" + response.remoteSocketAddress.getPort()));
assertThat(response.httpResponse, Matchers.containsString("proxyRemoteAddress: " + response.localSocketAddress.getAddress().getHostAddress() + ":" + response.localSocketAddress.getPort()));
assertThat(response.httpResponse, Matchers.containsString("preexisting.attribute: some value"));
assertThat(response.httpResponse, Matchers.containsString("attributeNames: org.eclipse.jetty.proxy.local.address,org.eclipse.jetty.proxy.local.port,org.eclipse.jetty.proxy.remote.address,org.eclipse.jetty.proxy.remote.port,some.attribute"));
}
@Test
void testProxyCustomizerWithoutProxyData() throws Exception
{
String proxy = "";
String http = "GET /1 HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n";
ProxyResponse response = sendProxyRequest(proxy, http);
assertThat(response.httpResponse, Matchers.containsString("localAddress: " + response.remoteSocketAddress.getAddress().getHostAddress() + ":" + response.remoteSocketAddress.getPort()));
assertThat(response.httpResponse, Matchers.containsString("remoteAddress: " + response.localSocketAddress.getAddress().getHostAddress() + ":" + response.localSocketAddress.getPort()));
assertThat(response.httpResponse, Matchers.not(Matchers.containsString("proxyLocalAddress: ")));
assertThat(response.httpResponse, Matchers.not(Matchers.containsString("proxyRemoteAddress: ")));
assertThat(response.httpResponse, Matchers.containsString("preexisting.attribute: some value"));
assertThat(response.httpResponse, Matchers.containsString("attributeNames: some.attribute"));
}
}

View File

@ -216,5 +216,81 @@ public class ProxyProtocolTest
} }
} }
} }
@Test
public void testProxyProtocolV2Local() throws Exception
{
start(new AbstractHandler()
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
}
});
try (Socket socket = new Socket("localhost", connector.getLocalPort()))
{
String proxy =
// Preamble
"0D0A0D0A000D0A515549540A" +
// V2, LOCAL
"20" +
// 0x1 : AF_INET 0x1 : STREAM. Address length is 2*4 + 2*2 = 12 bytes.
"11" +
// length of remaining header (4+4+2+2+6+3 = 21)
"0015" +
// uint32_t src_addr; uint32_t dst_addr; uint16_t src_port; uint16_t dst_port;
"C0A80001" +
"7f000001" +
"3039" +
"1F90" +
// NOOP value 0
"040000" +
// NOOP value ABCDEF
"040003ABCDEF";
String request1 =
"GET /1 HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n";
OutputStream output = socket.getOutputStream();
output.write(TypeUtil.fromHexString(proxy));
output.write(request1.getBytes(StandardCharsets.UTF_8));
output.flush();
InputStream input = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
String response1 = reader.readLine();
assertTrue(response1.startsWith("HTTP/1.1 200 "));
while (true)
{
if (reader.readLine().isEmpty())
break;
}
// Send a second request to verify that the proxied IP is retained.
String request2 =
"GET /2 HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"Connection: close\r\n" +
"\r\n";
output.write(request2.getBytes(StandardCharsets.UTF_8));
output.flush();
String response2 = reader.readLine();
assertTrue(response2.startsWith("HTTP/1.1 200 "));
while (true)
{
if (reader.readLine() == null)
break;
}
}
}
} }

12
pom.xml
View File

@ -33,7 +33,7 @@
<jmh.version>1.21</jmh.version> <jmh.version>1.21</jmh.version>
<jmhjar.name>benchmarks</jmhjar.name> <jmhjar.name>benchmarks</jmhjar.name>
<tycho-version>1.4.0</tycho-version> <tycho-version>1.4.0</tycho-version>
<junit.version>5.5.1</junit.version> <junit.version>5.6.2</junit.version>
<maven.version>3.6.0</maven.version> <maven.version>3.6.0</maven.version>
<maven.resolver.version>1.3.1</maven.resolver.version> <maven.resolver.version>1.3.1</maven.resolver.version>
<weld.version>3.1.2.Final</weld.version> <weld.version>3.1.2.Final</weld.version>
@ -1063,6 +1063,16 @@
<artifactId>junit-jupiter</artifactId> <artifactId>junit-jupiter</artifactId>
<version>${junit.version}</version> <version>${junit.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.14.1</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.14.1</version>
</dependency>
<!-- Old Deps --> <!-- Old Deps -->
<dependency> <dependency>
<groupId>org.eclipse.jetty.toolchain</groupId> <groupId>org.eclipse.jetty.toolchain</groupId>

View File

@ -12,6 +12,8 @@
<properties> <properties>
<bundle-symbolic-name>${project.groupId}.sessions.mongo</bundle-symbolic-name> <bundle-symbolic-name>${project.groupId}.sessions.mongo</bundle-symbolic-name>
<embedmongo.host>localhost</embedmongo.host> <embedmongo.host>localhost</embedmongo.host>
<!-- if changing this version please update default in MongoTestHelper you will get thanks from Eclipse IDE users -->
<mongo.docker.version>2.2.7</mongo.docker.version>
</properties> </properties>
<build> <build>
<plugins> <plugins>
@ -111,13 +113,28 @@
<artifactId>jetty-test-helper</artifactId> <artifactId>jetty-test-helper</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<profiles> <profiles>
<profile> <profile>
<id>mongodb</id> <id>remote-session-tests</id>
<activation> <activation>
<property> <property>
<name>mongodb.enabled</name> <name>mongo.enabled</name>
<value>true</value> <value>true</value>
</property> </property>
</activation> </activation>
@ -128,51 +145,11 @@
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<configuration> <configuration>
<systemPropertyVariables> <systemPropertyVariables>
<embedmongoPort>${embedmongo.port}</embedmongoPort> <mongo.docker.version>${mongo.docker.version}</mongo.docker.version>
<embedmongoHost>${embedmongo.host}</embedmongoHost>
</systemPropertyVariables> </systemPropertyVariables>
<skipTests>false</skipTests> <skipTests>false</skipTests>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>com.github.joelittlejohn.embedmongo</groupId>
<artifactId>embedmongo-maven-plugin</artifactId>
<version>0.4.1</version>
<configuration>
<!--port>37017</port-->
<!-- allocates a random port and overrides embedmongo.port -->
<randomPort>true</randomPort>
<databaseDirectory>${project.build.directory}/mongotest</databaseDirectory>
<!-- optional (file|console|none), default console -->
<logging>file</logging>
<!-- optional, can be used when logging=file, default is ./embedmongo.log -->
<logFile>${project.build.directory}/embedmongo.log</logFile>
<!--optional, one of wiredTiger or mmapv1 (default is mmapv1) -->
<!--storageEngine>wiredTiger</storageEngine-->
<!-- optional, skips this plugin entirely, use on the command line like -Dembedmongo.skip -->
<skip>false</skip>
<downloadPath>https://jenkins.webtide.net/userContent/</downloadPath>
<version>2.2.1</version>
</configuration>
<executions>
<execution>
<id>start</id>
<phase>process-test-classes</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop</id>
<phase>test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>
</profile> </profile>

View File

@ -42,15 +42,16 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
*/ */
public class MongoSessionDataStoreTest extends AbstractSessionDataStoreTest public class MongoSessionDataStoreTest extends AbstractSessionDataStoreTest
{ {
@BeforeEach @BeforeEach
public void beforeClass() throws Exception public void beforeEach() throws Exception
{ {
MongoTestHelper.dropCollection(); MongoTestHelper.dropCollection();
MongoTestHelper.createCollection(); MongoTestHelper.createCollection();
} }
@AfterEach @AfterEach
public void afterClass() throws Exception public void afterEach() throws Exception
{ {
MongoTestHelper.dropCollection(); MongoTestHelper.dropCollection();
} }

View File

@ -35,6 +35,9 @@ import org.eclipse.jetty.util.ClassLoadingObjectInputStream;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.output.Slf4jLogConsumer;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
@ -45,37 +48,71 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class MongoTestHelper public class MongoTestHelper
{ {
private static final Logger LOG = LoggerFactory.getLogger(MongoTestHelper.class); private static final Logger LOG = LoggerFactory.getLogger(MongoTestHelper.class);
private static final Logger MONGO_LOG = LoggerFactory.getLogger("org.eclipse.jetty.nosql.mongodb.MongoLogs");
public static final String DB_NAME = "HttpSessions"; public static final String DB_NAME = "HttpSessions";
public static final String COLLECTION_NAME = "testsessions"; public static final String COLLECTION_NAME = "testsessions";
static MongoClient _mongoClient; static GenericContainer mongo =
new GenericContainer("mongo:" + System.getProperty("mongo.docker.version", "2.2.7"))
.withLogConsumer(new Slf4jLogConsumer(MONGO_LOG));
static static MongoClient mongoClient;
public static void startMongo()
{ {
try try
{ {
_mongoClient = long start = System.currentTimeMillis();
new MongoClient(System.getProperty("embedmongo.host"), Integer.getInteger("embedmongoPort")); mongo.start();
String containerIpAddress = mongo.getContainerIpAddress();
int mongoPort = mongo.getMappedPort(27017);
LOG.info("Mongo container started for {}:{} - {}ms", containerIpAddress, mongoPort,
System.currentTimeMillis() - start);
System.setProperty("embedmongoHost", containerIpAddress);
System.setProperty("embedmongoPort", Integer.toString(mongoPort));
} }
catch (UnknownHostException e) catch (Exception e)
{ {
e.printStackTrace(); LOG.error(e.getMessage(), e);
throw new RuntimeException(e);
} }
} }
public static void dropCollection() throws MongoException, UnknownHostException public static void stopMongo()
{ {
_mongoClient.getDB(DB_NAME).getCollection(COLLECTION_NAME).drop(); mongo.stop();
mongoClient = null;
}
public static MongoClient getMongoClient() throws UnknownHostException
{
boolean restart = false;
if (mongo == null || !mongo.isRunning())
{
startMongo();
restart = true;
}
if (mongoClient == null || restart)
{
mongoClient = new MongoClient(System.getProperty("embedmongoHost"), Integer.getInteger("embedmongoPort"));
}
return mongoClient;
}
public static void dropCollection() throws Exception
{
getMongoClient().getDB(DB_NAME).getCollection(COLLECTION_NAME).drop();
} }
public static void createCollection() throws UnknownHostException, MongoException public static void createCollection() throws UnknownHostException, MongoException
{ {
_mongoClient.getDB(DB_NAME).createCollection(COLLECTION_NAME, null); getMongoClient().getDB(DB_NAME).createCollection(COLLECTION_NAME, null);
} }
public static DBCollection getCollection() throws UnknownHostException, MongoException public static DBCollection getCollection() throws UnknownHostException, MongoException
{ {
return _mongoClient.getDB(DB_NAME).getCollection(COLLECTION_NAME); return getMongoClient().getDB(DB_NAME).getCollection(COLLECTION_NAME);
} }
public static MongoSessionDataStoreFactory newSessionDataStoreFactory() public static MongoSessionDataStoreFactory newSessionDataStoreFactory()
@ -91,7 +128,7 @@ public class MongoTestHelper
public static boolean checkSessionExists(String id) public static boolean checkSessionExists(String id)
throws Exception throws Exception
{ {
DBCollection collection = _mongoClient.getDB(DB_NAME).getCollection(COLLECTION_NAME); DBCollection collection = getMongoClient().getDB(DB_NAME).getCollection(COLLECTION_NAME);
DBObject fields = new BasicDBObject(); DBObject fields = new BasicDBObject();
fields.put(MongoSessionDataStore.__EXPIRY, 1); fields.put(MongoSessionDataStore.__EXPIRY, 1);
@ -108,7 +145,7 @@ public class MongoTestHelper
public static boolean checkSessionPersisted(SessionData data) public static boolean checkSessionPersisted(SessionData data)
throws Exception throws Exception
{ {
DBCollection collection = _mongoClient.getDB(DB_NAME).getCollection(COLLECTION_NAME); DBCollection collection = getMongoClient().getDB(DB_NAME).getCollection(COLLECTION_NAME);
DBObject fields = new BasicDBObject(); DBObject fields = new BasicDBObject();
@ -116,7 +153,7 @@ public class MongoTestHelper
if (sessionDocument == null) if (sessionDocument == null)
return false; //doesn't exist return false; //doesn't exist
LOG.info("{}", sessionDocument); LOG.debug("{}", sessionDocument);
Boolean valid = (Boolean)sessionDocument.get(MongoSessionDataStore.__VALID); Boolean valid = (Boolean)sessionDocument.get(MongoSessionDataStore.__VALID);
@ -182,7 +219,7 @@ public class MongoTestHelper
Map<String, Object> attributes) Map<String, Object> attributes)
throws Exception throws Exception
{ {
DBCollection collection = _mongoClient.getDB(DB_NAME).getCollection(COLLECTION_NAME); DBCollection collection = getMongoClient().getDB(DB_NAME).getCollection(COLLECTION_NAME);
// Form query for upsert // Form query for upsert
BasicDBObject key = new BasicDBObject(MongoSessionDataStore.__ID, id); BasicDBObject key = new BasicDBObject(MongoSessionDataStore.__ID, id);
@ -231,7 +268,7 @@ public class MongoTestHelper
throws Exception throws Exception
{ {
DBCollection collection = _mongoClient.getDB(DB_NAME).getCollection(COLLECTION_NAME); DBCollection collection = getMongoClient().getDB(DB_NAME).getCollection(COLLECTION_NAME);
// Form query for upsert // Form query for upsert
BasicDBObject key = new BasicDBObject(MongoSessionDataStore.__ID, id); BasicDBObject key = new BasicDBObject(MongoSessionDataStore.__ID, id);
@ -277,7 +314,7 @@ public class MongoTestHelper
throws Exception throws Exception
{ {
//make old-style session to test if we can retrieve it //make old-style session to test if we can retrieve it
DBCollection collection = _mongoClient.getDB(DB_NAME).getCollection(COLLECTION_NAME); DBCollection collection = getMongoClient().getDB(DB_NAME).getCollection(COLLECTION_NAME);
// Form query for upsert // Form query for upsert
BasicDBObject key = new BasicDBObject(MongoSessionDataStore.__ID, id); BasicDBObject key = new BasicDBObject(MongoSessionDataStore.__ID, id);

View File

@ -0,0 +1,3 @@
org.slf4j.simpleLogger.defaultLogLevel=info
org.slf4j.simpleLogger.log.org.eclipse.jetty.nosql.mongodb.MongoLogs=error
org.slf4j.simpleLogger.log.org.eclipse.jetty.nosql.mongodb.MongoTestHelper=info