diff --git a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod index 4174d473581..40e322c1672 100644 --- a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod +++ b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod @@ -14,7 +14,6 @@ sessions [files] maven://com.hazelcast/hazelcast/${hazelcast.version}|lib/hazelcast/hazelcast-${hazelcast.version}.jar -maven://com.hazelcast/hazelcast-client/${hazelcast.version}|lib/hazelcast/hazelcast-client-${hazelcast.version}.jar [xml] etc/sessions/hazelcast/remote.xml @@ -22,7 +21,6 @@ etc/sessions/hazelcast/remote.xml [lib] lib/jetty-hazelcast-${jetty.version}.jar lib/hazelcast/hazelcast-${hazelcast.version}.jar -lib/hazelcast/hazelcast-client-${hazelcast.version}.jar [ini] hazelcast.version?=4.1 diff --git a/tests/test-distribution/pom.xml b/tests/test-distribution/pom.xml index 2b81d3afa88..107ba0f26e5 100644 --- a/tests/test-distribution/pom.xml +++ b/tests/test-distribution/pom.xml @@ -11,6 +11,7 @@ ${project.groupId}.tests.distribution + -1 @@ -94,6 +95,13 @@ war test + + org.eclipse.jetty.tests + test-simple-session-webapp + ${project.version} + war + test + org.eclipse.jetty.tests test-weld-cdi-webapp @@ -167,6 +175,11 @@ test war + + org.testcontainers + testcontainers + test + @@ -178,6 +191,8 @@ ${settings.localRepository} ${project.version} + ${hazelcast.version} + $(distribution.debug.port} diff --git a/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/JettyHomeTester.java b/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/JettyHomeTester.java index 486a1543d97..ebbb5b43d0e 100644 --- a/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/JettyHomeTester.java +++ b/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/JettyHomeTester.java @@ -149,6 +149,12 @@ public class JettyHomeTester commands.add(getJavaExecutable()); commands.addAll(config.getJVMArgs()); commands.add("-Djava.io.tmpdir=" + workDir.toAbsolutePath().toString()); + int debugPort = Integer.getInteger("distribution.debug.port", 0); + if (debugPort > 0) + { + commands.add("-Xdebug"); + commands.add("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=" + debugPort); + } commands.add("-jar"); commands.add(config.jettyHome.toAbsolutePath() + "/start.jar"); diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HazelcastSessionDistributionTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HazelcastSessionDistributionTests.java new file mode 100644 index 00000000000..6fe937dd474 --- /dev/null +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HazelcastSessionDistributionTests.java @@ -0,0 +1,254 @@ +// +// ======================================================================== +// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.tests.distribution; + +import java.io.File; +import java.io.OutputStream; +import java.net.InetAddress; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.http.HttpStatus; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.BindMode; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.output.Slf4jLogConsumer; +import org.testcontainers.containers.wait.strategy.Wait; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class HazelcastSessionDistributionTests extends AbstractJettyHomeTest +{ + private static final Logger HAZELCAST_LOG = LoggerFactory.getLogger("org.eclipse.jetty.tests.distribution.HazelcastLogs"); + + private static final Logger LOGGER = LoggerFactory.getLogger(HazelcastSessionDistributionTests.class); + + + /** + * This simulate the onlyClient option which means the JVM running Jetty is only an Hazelcast client and not part + * of the cluster + */ + @Test + public void testHazelcastRemoteOnlyClient() throws Exception + { + try (GenericContainer hazelcast = + new GenericContainer("hazelcast/hazelcast:" + System.getProperty("hazelcast.version", "4.1")) + .withExposedPorts(5701) + .waitingFor(Wait.forListeningPort()) + .withLogConsumer(new Slf4jLogConsumer(HAZELCAST_LOG))) + { + hazelcast.start(); + String hazelcastHost = hazelcast.getContainerIpAddress(); + int hazelcastPort = hazelcast.getMappedPort(5701); + + LOGGER.info("hazelcast started on {}:{}", hazelcastHost, hazelcastPort); + + Map tokenValues = new HashMap<>(); + tokenValues.put("hazelcast_ip", hazelcastHost); + tokenValues.put("hazelcast_port", Integer.toString(hazelcastPort)); + Path hazelcastJettyPath = Paths.get("target/hazelcast-client.xml"); + transformFileWithHostAndPort(Paths.get("src/test/resources/hazelcast-client.xml"), + hazelcastJettyPath, + tokenValues); + + String jettyVersion = System.getProperty("jettyVersion"); + JettyHomeTester distribution = JettyHomeTester.Builder.newInstance() + .jettyVersion(jettyVersion) + .mavenLocalRepository(System.getProperty("mavenRepoPath")) + .build(); + + String[] args1 = { + "--create-startd", + "--approve-all-licenses", + "--add-to-start=resources,server,http,webapp,deploy,jmx,servlet,servlets,session-store-hazelcast-remote" + }; + try (JettyHomeTester.Run run1 = distribution.start(args1)) + { + assertTrue(run1.awaitFor(5, TimeUnit.SECONDS)); + assertEquals(0, run1.getExitValue()); + + File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-simple-session-webapp:war:" + jettyVersion); + distribution.installWarFile(war, "test"); + + int port = distribution.freePort(); + String[] argsStart = { + "jetty.http.port=" + port, + "jetty.session.hazelcast.configurationLocation=" + hazelcastJettyPath.toAbsolutePath(), + "jetty.session.hazelcast.onlyClient=true" + }; + try (JettyHomeTester.Run run2 = distribution.start(argsStart)) + { + assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS)); + + startHttpClient(); + ContentResponse response = client.GET("http://localhost:" + port + "/test/session?action=CREATE"); + assertEquals(HttpStatus.OK_200, response.getStatus()); + assertThat(response.getContentAsString(), containsString("SESSION CREATED")); + + response = client.GET("http://localhost:" + port + "/test/session?action=READ"); + assertEquals(HttpStatus.OK_200, response.getStatus()); + assertThat(response.getContentAsString(), containsString("SESSION READ CHOCOLATE THE BEST:FRENCH")); + } + + try (JettyHomeTester.Run run2 = distribution.start(argsStart)) + { + assertTrue(run2.awaitConsoleLogsFor("Started Server@", 10, TimeUnit.SECONDS)); + + ContentResponse response = client.GET("http://localhost:" + port + "/test/session?action=READ"); + assertEquals(HttpStatus.OK_200, response.getStatus()); + assertThat(response.getContentAsString(), containsString("SESSION READ CHOCOLATE THE BEST:FRENCH")); + } + } + + } + } + + @Disabled("not working see https://github.com/hazelcast/hazelcast/issues/18508") + /** + * This test simulate Hazelcast instance within Jetty a cluster member with an external Hazelcast instance + */ + public void testHazelcastRemoteAndPartOfCluster() throws Exception + { + + Map env = new HashMap<>(); + // -Dhazelcast.local.publicAddress=127.0.0.1:5701 + env.put("JAVA_OPTS", "-Dhazelcast.config=/opt/hazelcast/config_ext/hazelcast.xml"); + try (GenericContainer hazelcast = + new GenericContainer("hazelcast/hazelcast:" + System.getProperty("hazelcast.version", "4.1")) + .withExposedPorts(5701, 5705) + .withEnv(env) + .waitingFor(Wait.forLogMessage(".*is STARTED.*", 1)) + //.withNetworkMode("host") + //.waitingFor(Wait.forListeningPort()) + .withClasspathResourceMapping("hazelcast-server.xml", + "/opt/hazelcast/config_ext/hazelcast.xml", + BindMode.READ_ONLY) + .withLogConsumer(new Slf4jLogConsumer(HAZELCAST_LOG))) + { + hazelcast.start(); + String hazelcastHost = InetAddress.getByName(hazelcast.getContainerIpAddress()).getHostAddress(); // hazelcast.getContainerIpAddress(); + int hazelcastPort = hazelcast.getMappedPort(5701); +// int hazelcastMultiCastPort = hazelcast.getMappedPort(54327); + + LOGGER.info("hazelcast started on {}:{}", hazelcastHost, hazelcastPort); + + Map tokenValues = new HashMap<>(); + tokenValues.put("hazelcast_ip", hazelcastHost); + tokenValues.put("hazelcast_port", Integer.toString(hazelcastPort)); +// tokenValues.put("hazelcast_multicast_port", Integer.toString(hazelcastMultiCastPort)); + Path hazelcastJettyPath = Paths.get("target/hazelcast-jetty.xml"); + transformFileWithHostAndPort(Paths.get("src/test/resources/hazelcast-jetty.xml"), + hazelcastJettyPath, + tokenValues); + + String jettyVersion = System.getProperty("jettyVersion"); + JettyHomeTester distribution = JettyHomeTester.Builder.newInstance() + .jettyVersion(jettyVersion) + .mavenLocalRepository(System.getProperty("mavenRepoPath")) + .build(); + + String[] args1 = { + "--create-startd", + "--approve-all-licenses", + "--add-to-start=resources,server,http,webapp,deploy,jmx,servlet,servlets,session-store-hazelcast-remote" + }; + try (JettyHomeTester.Run run1 = distribution.start(args1)) + { + assertTrue(run1.awaitFor(10, TimeUnit.SECONDS)); + assertEquals(0, run1.getExitValue()); + + File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-simple-session-webapp:war:" + jettyVersion); + distribution.installWarFile(war, "test"); + + int port = distribution.freePort(); + List argsStart = Arrays.asList( + "jetty.http.port=" + port, + "jetty.session.hazelcast.onlyClient=false", + "jetty.session.hazelcast.configurationLocation=" + hazelcastJettyPath.toAbsolutePath() + ); + + try (JettyHomeTester.Run run2 = distribution.start(argsStart)) + { + assertTrue(run2.awaitConsoleLogsFor("Started @", 60, TimeUnit.SECONDS)); + + startHttpClient(); + ContentResponse response = client.GET("http://localhost:" + port + "/test/session?action=CREATE"); + assertEquals(HttpStatus.OK_200, response.getStatus()); + assertThat(response.getContentAsString(), containsString("SESSION CREATED")); + + response = client.GET("http://localhost:" + port + "/test/session?action=READ"); + assertEquals(HttpStatus.OK_200, response.getStatus()); + assertThat(response.getContentAsString(), containsString("SESSION READ CHOCOLATE THE BEST:FRENCH")); + } + + LOGGER.info("restarting Jetty"); + + try (JettyHomeTester.Run run2 = distribution.start(argsStart)) + { + assertTrue(run2.awaitConsoleLogsFor("Started @", 15, TimeUnit.SECONDS)); + + ContentResponse response = client.GET("http://localhost:" + port + "/test/session?action=READ"); + assertEquals(HttpStatus.OK_200, response.getStatus()); + assertThat(response.getContentAsString(), containsString("SESSION READ CHOCOLATE THE BEST:FRENCH")); + } + } + + } + } + + /** + * @param input input file to interpolate + * @param output output file of interpolation + * @param tokensValues key token to replace, value the value + */ + private void transformFileWithHostAndPort(Path input, Path output, Map tokensValues) throws Exception + { + StringBuilder fileContent = new StringBuilder(); + Files.deleteIfExists(output); + Files.createFile(output); + try (OutputStream outputStream = Files.newOutputStream(output)) + { + Files.readAllLines(input).forEach(line -> + { + StringBuilder newLine = new StringBuilder(line); + tokensValues.forEach((key, value) -> + { + String interpolated = newLine.toString().replace(key, value); + newLine.setLength(0); + newLine.append(interpolated); + }); + fileContent.append(newLine.toString()); + fileContent.append(System.lineSeparator()); + }); + + + outputStream.write(fileContent.toString().getBytes(StandardCharsets.UTF_8)); + } + } + +} diff --git a/tests/test-distribution/src/test/resources/hazelcast-client.xml b/tests/test-distribution/src/test/resources/hazelcast-client.xml new file mode 100644 index 00000000000..7b09cd433fa --- /dev/null +++ b/tests/test-distribution/src/test/resources/hazelcast-client.xml @@ -0,0 +1,20 @@ + + + + + + + +
hazelcast_ip:hazelcast_port
+
+
+ + + + + +
diff --git a/tests/test-distribution/src/test/resources/hazelcast-jetty.xml b/tests/test-distribution/src/test/resources/hazelcast-jetty.xml new file mode 100644 index 00000000000..e1122fb30e6 --- /dev/null +++ b/tests/test-distribution/src/test/resources/hazelcast-jetty.xml @@ -0,0 +1,50 @@ + + + + + + + 5705 + + + + + + hazelcast_ip:hazelcast_port + + + + + + + true + + + + + + + + + diff --git a/tests/test-distribution/src/test/resources/hazelcast-server.xml b/tests/test-distribution/src/test/resources/hazelcast-server.xml new file mode 100644 index 00000000000..9a0d70d97a1 --- /dev/null +++ b/tests/test-distribution/src/test/resources/hazelcast-server.xml @@ -0,0 +1,52 @@ + + + + + + + + true + 5701 + + + + + + + + + + + + + true + + + + + + + + + diff --git a/tests/test-distribution/src/test/resources/jetty-logging.properties b/tests/test-distribution/src/test/resources/jetty-logging.properties index 6c7059f135c..cb96a22a250 100644 --- a/tests/test-distribution/src/test/resources/jetty-logging.properties +++ b/tests/test-distribution/src/test/resources/jetty-logging.properties @@ -1,3 +1,5 @@ # Jetty Logging using jetty-slf4j-impl org.eclipse.jetty.logging.appender.MESSAGE_ESCAPE=false #org.eclipse.jetty.LEVEL=DEBUG + +#org.eclipse.jetty.tests.distribution.LEVEL=DEBUG diff --git a/tests/test-webapps/pom.xml b/tests/test-webapps/pom.xml index 5aea6c9e1bc..59c82a85d44 100644 --- a/tests/test-webapps/pom.xml +++ b/tests/test-webapps/pom.xml @@ -32,6 +32,7 @@ test-webapp-rfc2616 test-http2-webapp + test-simple-session-webapp test-felix-webapp test-cdi-common-webapp test-weld-cdi-webapp diff --git a/tests/test-webapps/test-simple-session-webapp/pom.xml b/tests/test-webapps/test-simple-session-webapp/pom.xml new file mode 100644 index 00000000000..9a930d48e9a --- /dev/null +++ b/tests/test-webapps/test-simple-session-webapp/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + org.eclipse.jetty.tests + test-webapps-parent + 10.0.7-SNAPSHOT + + + test-simple-session-webapp + + war + + Test :: Jetty Test Simple Session Webapp + + + + org.eclipse.jetty.toolchain + jetty-servlet-api + provided + + + + diff --git a/tests/test-webapps/test-simple-session-webapp/src/main/java/org/eclipse/jetty/test/session/Chocolate.java b/tests/test-webapps/test-simple-session-webapp/src/main/java/org/eclipse/jetty/test/session/Chocolate.java new file mode 100644 index 00000000000..934751f9ed7 --- /dev/null +++ b/tests/test-webapps/test-simple-session-webapp/src/main/java/org/eclipse/jetty/test/session/Chocolate.java @@ -0,0 +1,30 @@ +// +// ======================================================================== +// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.test.session; + +import java.io.Serializable; + +public class Chocolate implements Serializable +{ + private static final long serialVersionUID = 1L; + + private static final String THE_BEST_EVER = "FRENCH"; + + private String theBest = THE_BEST_EVER; + + public String getTheBest() + { + return this.theBest; + } +} diff --git a/tests/test-webapps/test-simple-session-webapp/src/main/java/org/eclipse/jetty/test/session/SessionTest.java b/tests/test-webapps/test-simple-session-webapp/src/main/java/org/eclipse/jetty/test/session/SessionTest.java new file mode 100644 index 00000000000..edf928a174b --- /dev/null +++ b/tests/test-webapps/test-simple-session-webapp/src/main/java/org/eclipse/jetty/test/session/SessionTest.java @@ -0,0 +1,44 @@ +// +// ======================================================================== +// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.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.test.session; + +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; + +public class SessionTest extends HttpServlet +{ + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + String action = req.getParameter("action"); + if ("CREATE".equals(action)) + { + HttpSession session = req.getSession(true); + session.setAttribute("CHOCOLATE", new Chocolate()); + resp.getOutputStream().println("SESSION CREATED"); + } + else + { + HttpSession session = req.getSession(false); + Chocolate yummi = (Chocolate)session.getAttribute("CHOCOLATE"); + resp.getOutputStream().println("SESSION READ CHOCOLATE THE BEST:" + yummi.getTheBest()); + } + } +} diff --git a/tests/test-webapps/test-simple-session-webapp/src/main/webapp/WEB-INF/web.xml b/tests/test-webapps/test-simple-session-webapp/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..6da5135a1db --- /dev/null +++ b/tests/test-webapps/test-simple-session-webapp/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,21 @@ + + + + Very Simple Web Application + + + SessionTest + org.eclipse.jetty.test.session.SessionTest + + + + SessionTest + /session + + +