Run WebSocket Autobahn test for all Jetty, Javax and Core APIs (#7430)

* Run WebSocket Autobahn test for all Jetty, Javax and Core APIs

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>

Signed-off-by: Olivier Lamy <oliver.lamy@gmail.com>
This commit is contained in:
Lachlan 2022-01-31 16:29:41 +11:00 committed by GitHub
parent 53762fbda4
commit b0e334f14a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 1053 additions and 413 deletions

View File

@ -10,8 +10,17 @@ pipeline {
// save some io during the build
durabilityHint( 'PERFORMANCE_OPTIMIZED' )
}
parameters {
string( defaultValue: 'jetty-10.0.x', description: 'GIT branch name to build (jetty-10.0.x/jetty-11.0.x/etc.)',
name: 'JETTY_BRANCH' )
}
stages {
stage("Checkout Jetty Branch") {
steps {
git url: 'https://github.com/eclipse/jetty.project/', branch: '${JETTY_BRANCH}'
}
}
stage( "Build / Test - JDK11" ) {
agent {
node { label 'linux' }
@ -19,8 +28,14 @@ pipeline {
steps {
container( 'jetty-build' ) {
timeout( time: 120, unit: 'MINUTES' ) {
mavenBuild( "jdk11", "-T3 clean install -Djacoco.skip=true -Pautobahn", "maven3", true ) //
mavenBuild( "jdk11", "-T3 clean install -Djacoco.skip=true -pl :test-websocket-autobahn -am -Pautobahn -Dtest=AutobahnTests", "maven3" ) //
junit testResults: '**/target/surefire-reports/*.xml,**/target/invoker-reports/TEST*.xml,**/target/autobahntestsuite-reports/*.xml'
publishHTML([allowMissing: true, alwaysLinkToLastBuild: true, keepAll: true, reportDir: "${env.WORKSPACE}/tests/test-websocket-autobahn/target/reports/core/servers", reportFiles: 'index.html', reportName: 'Autobahn Report Core Server', reportTitles: ''])
publishHTML([allowMissing: true, alwaysLinkToLastBuild: true, keepAll: true, reportDir: "${env.WORKSPACE}/tests/test-websocket-autobahn/target/reports/core/clients", reportFiles: 'index.html', reportName: 'Autobahn Report Core Client', reportTitles: ''])
publishHTML([allowMissing: true, alwaysLinkToLastBuild: true, keepAll: true, reportDir: "${env.WORKSPACE}/tests/test-websocket-autobahn/target/reports/javax/servers", reportFiles: 'index.html', reportName: 'Autobahn Report Javax Server', reportTitles: ''])
publishHTML([allowMissing: true, alwaysLinkToLastBuild: true, keepAll: true, reportDir: "${env.WORKSPACE}/tests/test-websocket-autobahn/target/reports/javax/clients", reportFiles: 'index.html', reportName: 'Autobahn Report Javax Client', reportTitles: ''])
publishHTML([allowMissing: true, alwaysLinkToLastBuild: true, keepAll: true, reportDir: "${env.WORKSPACE}/tests/test-websocket-autobahn/target/reports/jetty/servers", reportFiles: 'index.html', reportName: 'Autobahn Report Jetty Server', reportTitles: ''])
publishHTML([allowMissing: true, alwaysLinkToLastBuild: true, keepAll: true, reportDir: "${env.WORKSPACE}/tests/test-websocket-autobahn/target/reports/jetty/clients", reportFiles: 'index.html', reportName: 'Autobahn Report Jetty Client', reportTitles: ''])
}
}
}
@ -68,19 +83,16 @@ def slackNotif() {
* @paran mvnName maven installation to use
* @return the Jenkinsfile step representing a maven build
*/
def mavenBuild(jdk, cmdline, mvnName, junitPublishDisabled) {
def localRepo = ".repository"
def mavenOpts = '-Xms1g -Xmx4g -Djava.awt.headless=true'
withMaven(
maven: mvnName,
jdk: "$jdk",
publisherStrategy: 'EXPLICIT',
options: [junitPublisher(disabled: junitPublishDisabled), mavenLinkerPublisher(disabled: false), pipelineGraphPublisher(disabled: false)],
mavenOpts: mavenOpts,
mavenLocalRepo: localRepo) {
// 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"
def mavenBuild(jdk, cmdline, mvnName) {
script {
withEnv(["JAVA_HOME=${ tool "$jdk" }",
"PATH+MAVEN=${ tool "$jdk" }/bin:${tool "$mvnName"}/bin",
"MAVEN_OPTS=-Xms2g -Xmx8g -Djava.awt.headless=true"]) {
configFileProvider(
[configFile(fileId: 'oss-settings.xml', variable: 'GLOBAL_MVN_SETTINGS')]) {
sh "mvn -Denforcer.skip=true -Dlicense.skip=true -Dspotbugs.skip=true -Dcheckstyle.skip=true --no-transfer-progress -s $GLOBAL_MVN_SETTINGS -Dmaven.repo.local=.repository -Pci -V -B -e -Djetty.testtracker.log=true $cmdline"
}
}
}
}

View File

@ -37,42 +37,9 @@
<artifactId>jetty-slf4j-impl</artifactId>
<scope>test</scope>
</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>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/AutobahnTests**</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -92,30 +59,4 @@
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>autobahn</id>
<activation>
<property>
<name>autobahn</name>
<value>true</value>
</property>
</activation>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>none</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>
</project>

View File

@ -1,18 +0,0 @@
{
"options": {
"failByDrop": false
},
"outdir": "./target/reports/servers",
"servers": [
{
"agent": "Jetty-10.0.0-SNAPSHOT",
"url": "ws://127.0.0.1:9001",
"options": {
"version": 18
}
}
],
"cases": ["*"],
"exclude-cases": [],
"exclude-agent-cases": {}
}

View File

@ -1,10 +0,0 @@
{
"options": {
"failByDrop": false
},
"url": "ws://127.0.0.1:9001",
"outdir": "./target/reports/clients",
"cases": ["*"],
"exclude-cases": [],
"exclude-agent-cases": {}
}

View File

@ -1,18 +0,0 @@
{
"options": {
"failByDrop": false
},
"outdir": "./target/reports/servers",
"servers": [
{
"agent": "Jetty-10.0.0-SNAPSHOT",
"url": "ws://127.0.0.1:9001",
"options": {
"version": 18
}
}
],
"cases": ["*"],
"exclude-cases": [],
"exclude-agent-cases": {}
}

View File

@ -1,10 +0,0 @@
{
"options": {
"failByDrop": false
},
"url": "ws://127.0.0.1:9001",
"outdir": "./target/reports/clients",
"cases": ["*"],
"exclude-cases": [],
"exclude-agent-cases": {}
}

View File

@ -57,5 +57,7 @@
<module>test-distribution</module>
<module>test-cdi</module>
<module>test-jpms</module>
<module>test-websocket-autobahn</module>
</modules>
</project>

View File

@ -7,6 +7,7 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>test-distribution</artifactId>
<name>Jetty Tests :: Distribution Tests</name>
<packaging>jar</packaging>
<properties>

View File

@ -8,7 +8,7 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>test-jpms</artifactId>
<packaging>pom</packaging>
<name>Jetty Tests :: JPMS Parent</name>
<name>Jetty Tests :: JPMS</name>
<modules>
<module>test-jpms-websocket-core</module>
</modules>

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>tests-parent</artifactId>
<version>10.0.8-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>test-websocket-autobahn</artifactId>
<name>Jetty Tests :: WebSocket Autobahn Tests</name>
<description>Run of Autobahn Testsuite for Jetty</description>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-jetty-client</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-javax-client</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-javax-server</artifactId>
</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.codehaus.plexus</groupId>
<artifactId>plexus-utils</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/AutobahnTests**</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Bundle-Description>jetty.websocket Autobahn Tests</Bundle-Description>
<Export-Package>
org.eclipse.jetty.websocket.jetty.tests.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
</instructions>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>autobahn</id>
<activation>
<property>
<name>autobahn</name>
<value>true</value>
</property>
</activation>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkedProcessTimeoutInSeconds>10800</forkedProcessTimeoutInSeconds>
<excludes>
<exclude>none</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,19 @@
//
// ========================================================================
// Copyright (c) 1995-2022 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.websocket.tests;
public interface AutobahnClient
{
void runAutobahnClient(String hostname, int port, int[] caseNumbers);
}

View File

@ -0,0 +1,21 @@
//
// ========================================================================
// Copyright (c) 1995-2022 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.websocket.tests;
public interface AutobahnServer
{
void startAutobahnServer(int port) throws Exception;
void stopAutobahnServer() throws Exception;
}

View File

@ -0,0 +1,160 @@
//
// ========================================================================
// Copyright (c) 1995-2022 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.websocket.tests;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.List;
import com.github.dockerjava.api.DockerClient;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.websocket.tests.core.CoreAutobahnClient;
import org.eclipse.jetty.websocket.tests.core.CoreAutobahnServer;
import org.eclipse.jetty.websocket.tests.javax.JavaxAutobahnClient;
import org.eclipse.jetty.websocket.tests.javax.JavaxAutobahnServer;
import org.eclipse.jetty.websocket.tests.jetty.JettyAutobahnClient;
import org.eclipse.jetty.websocket.tests.jetty.JettyAutobahnServer;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.MountableFile;
import static org.eclipse.jetty.websocket.tests.AutobahnUtils.copyFromContainer;
import static org.eclipse.jetty.websocket.tests.AutobahnUtils.parseResults;
import static org.eclipse.jetty.websocket.tests.AutobahnUtils.throwIfFailed;
import static org.eclipse.jetty.websocket.tests.AutobahnUtils.writeJUnitXmlReport;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Testcontainers(disabledWithoutDocker = true)
public class AutobahnTests
{
private static final Logger LOG = LoggerFactory.getLogger(AutobahnTests.class);
private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
private Path reportDir;
private Path fuzzingServer;
private Path fuzzingClient;
private AutobahnServer server;
private AutobahnClient client;
@BeforeAll
public static void clean()
{
Path reportDir = USER_DIR.resolve("target/reports");
IO.delete(reportDir.toFile());
}
public void setup(String version) throws Exception
{
fuzzingServer = USER_DIR.resolve("fuzzingserver.json");
assertTrue(Files.exists(fuzzingServer), fuzzingServer + " not exists");
fuzzingClient = USER_DIR.resolve("fuzzingclient.json");
assertTrue(Files.exists(fuzzingClient), fuzzingClient + " not exists");
reportDir = USER_DIR.resolve("target/reports/" + version);
if (!Files.exists(reportDir))
Files.createDirectories(reportDir);
switch (version)
{
case "jetty":
server = new JettyAutobahnServer();
client = new JettyAutobahnClient();
break;
case "javax":
server = new JavaxAutobahnServer();
client = new JavaxAutobahnClient();
break;
case "core":
server = new CoreAutobahnServer();
client = new CoreAutobahnClient();
break;
default:
throw new IllegalStateException(version);
}
}
@ParameterizedTest
@ValueSource(strings = {"core", "jetty", "javax"})
public void testClient(String version) throws Exception
{
setup(version);
try (GenericContainer<?> container = new GenericContainer<>(DockerImageName.parse("jettyproject/autobahn-testsuite:latest"))
.withCommand("/bin/bash", "-c", "wstest -m fuzzingserver -s /config/fuzzingserver.json")
.withExposedPorts(9001)
.withCopyFileToContainer(MountableFile.forHostPath(fuzzingServer), "/config/fuzzingserver.json")
.withLogConsumer(new Slf4jLogConsumer(LOG))
.withStartupTimeout(Duration.ofHours(2)))
{
container.start();
Integer mappedPort = container.getMappedPort(9001);
client.runAutobahnClient(container.getContainerIpAddress(), mappedPort, null);
DockerClient dockerClient = container.getDockerClient();
String containerId = container.getContainerId();
copyFromContainer(dockerClient, containerId, reportDir, Paths.get("/target/reports/clients"));
}
LOG.info("Test Result Overview {}", reportDir.resolve("clients/index.html").toUri());
List<AutobahnUtils.AutobahnCaseResult> results = parseResults(reportDir.resolve("clients/index.json"));
String className = getClass().getName();
writeJUnitXmlReport(results, version + "-autobahn-client", className + ".client");
throwIfFailed(results);
}
@ParameterizedTest
@ValueSource(strings = {"core", "jetty", "javax"})
public void testServer(String version) throws Exception
{
setup(version);
// We need to expose the host port of the server to the Autobahn Client in docker container.
final int port = 9001;
org.testcontainers.Testcontainers.exposeHostPorts(port);
server.startAutobahnServer(port);
AutobahnUtils.FileSignalWaitStrategy strategy = new AutobahnUtils.FileSignalWaitStrategy(reportDir, Paths.get("/target/reports/servers"));
try (GenericContainer<?> container = new GenericContainer<>(DockerImageName.parse("jettyproject/autobahn-testsuite:latest"))
.withCommand("/bin/bash", "-c", "wstest -m fuzzingclient -s /config/fuzzingclient.json" + AutobahnUtils.FileSignalWaitStrategy.END_COMMAND)
.withLogConsumer(new Slf4jLogConsumer(LOG))
.withCopyFileToContainer(MountableFile.forHostPath(fuzzingClient), "/config/fuzzingclient.json")
.withStartupCheckStrategy(strategy)
.withStartupTimeout(Duration.ofHours(2)))
{
container.start();
}
finally
{
server.stopAutobahnServer();
}
LOG.info("Test Result Overview {}", reportDir.resolve("servers/index.html").toUri());
List<AutobahnUtils.AutobahnCaseResult> results = parseResults(reportDir.resolve("servers/index.json"));
String className = getClass().getName();
writeJUnitXmlReport(results, version + "-autobahn-server", className + ".server");
throwIfFailed(results);
}
}

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.websocket.core.autobahn;
package org.eclipse.jetty.websocket.tests;
import java.io.File;
import java.io.FileNotFoundException;
@ -31,110 +31,19 @@ import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.codehaus.plexus.util.xml.Xpp3DomWriter;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.IO;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.containers.startupcheck.StartupCheckStrategy;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.DockerStatus;
import org.testcontainers.utility.MountableFile;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Disabled("Disable this test so it doesn't run locally as it takes 1h+ to run.")
@Testcontainers
public class AutobahnTests
public class AutobahnUtils
{
private static final Logger LOG = LoggerFactory.getLogger(AutobahnTests.class);
private static final Path USER_DIR = Paths.get(System.getProperty("user.dir"));
private static final Logger LOG = LoggerFactory.getLogger(AutobahnUtils.class);
private static Path reportDir;
private static Path fuzzingServer;
private static Path fuzzingClient;
@BeforeAll
public static void before() throws Exception
{
fuzzingServer = USER_DIR.resolve("fuzzingserver.json");
assertTrue(Files.exists(fuzzingServer), fuzzingServer + " not exists");
fuzzingClient = USER_DIR.resolve("fuzzingclient.json");
assertTrue(Files.exists(fuzzingClient), fuzzingClient + " not exists");
reportDir = USER_DIR.resolve("target/reports");
IO.delete(reportDir.toFile());
Files.createDirectory(reportDir);
}
@Test
public void testClient() throws Exception
{
try (GenericContainer<?> container = new GenericContainer<>(DockerImageName.parse("jettyproject/autobahn-testsuite:latest"))
.withCommand("/bin/bash", "-c", "wstest -m fuzzingserver -s /config/fuzzingserver.json")
.withExposedPorts(9001)
.withCopyFileToContainer(MountableFile.forHostPath(fuzzingServer), "/config/fuzzingserver.json")
.withLogConsumer(new Slf4jLogConsumer(LOG))
.withStartupTimeout(Duration.ofHours(2)))
{
container.start();
Integer mappedPort = container.getMappedPort(9001);
CoreAutobahnClient.main(new String[]{container.getContainerIpAddress(), mappedPort.toString()});
DockerClient dockerClient = container.getDockerClient();
String containerId = container.getContainerId();
copyFromContainer(dockerClient, containerId, reportDir, Paths.get("/target/reports/clients"));
}
LOG.info("Test Result Overview {}", reportDir.resolve("clients/index.html").toUri());
List<AutobahnCaseResult> results = parseResults(Paths.get("target/reports/clients/index.json"));
String className = getClass().getName();
writeJUnitXmlReport(results, "autobahn-client", className + ".client");
throwIfFailed(results);
}
@Test
public void testServer() throws Exception
{
// We need to expose the host port of the server to the Autobahn Client in docker container.
final int port = 9001;
org.testcontainers.Testcontainers.exposeHostPorts(port);
Server server = CoreAutobahnServer.startAutobahnServer(port);
FileSignalWaitStrategy strategy = new FileSignalWaitStrategy(reportDir, Paths.get("/target/reports/servers"));
try (GenericContainer<?> container = new GenericContainer<>(DockerImageName.parse("jettyproject/autobahn-testsuite:latest"))
.withCommand("/bin/bash", "-c", "wstest -m fuzzingclient -s /config/fuzzingclient.json" + FileSignalWaitStrategy.END_COMMAND)
.withLogConsumer(new Slf4jLogConsumer(LOG))
.withCopyFileToContainer(MountableFile.forHostPath(fuzzingClient), "/config/fuzzingclient.json")
.withStartupCheckStrategy(strategy)
.withStartupTimeout(Duration.ofHours(2)))
{
container.start();
}
finally
{
server.stop();
}
LOG.info("Test Result Overview {}", reportDir.resolve("servers/index.html").toUri());
List<AutobahnCaseResult> results = parseResults(Paths.get("target/reports/servers/index.json"));
String className = getClass().getName();
writeJUnitXmlReport(results, "autobahn-server", className + ".server");
throwIfFailed(results);
}
private void throwIfFailed(List<AutobahnCaseResult> results) throws Exception
public static void throwIfFailed(List<AutobahnCaseResult> results) throws Exception
{
StringBuilder message = new StringBuilder();
for (AutobahnCaseResult result : results)
@ -147,7 +56,7 @@ public class AutobahnTests
throw new Exception("Failed Test Cases: " + message);
}
private static class FileSignalWaitStrategy extends StartupCheckStrategy
public static class FileSignalWaitStrategy extends StartupCheckStrategy
{
public static final String SIGNAL_FILE = "/signalComplete";
public static final String END_COMMAND = " && touch " + SIGNAL_FILE + " && sleep infinity";
@ -163,7 +72,7 @@ public class AutobahnTests
}
@Override
public StartupCheckStrategy.StartupStatus checkStartupState(DockerClient dockerClient, String containerId)
public StartupStatus checkStartupState(DockerClient dockerClient, String containerId)
{
// If the container was stopped then we have failed to copy out the file.
if (DockerStatus.isContainerStopped(getCurrentState(dockerClient, containerId)))
@ -196,7 +105,7 @@ public class AutobahnTests
}
}
private static void copyFromContainer(DockerClient dockerClient, String containerId, Path target, Path source) throws Exception
public static void copyFromContainer(DockerClient dockerClient, String containerId, Path target, Path source) throws Exception
{
try (TarArchiveInputStream tarArchiveInputStream = new TarArchiveInputStream(dockerClient
.copyArchiveFromContainerCmd(containerId, source.toString())
@ -217,8 +126,7 @@ public class AutobahnTests
}
}
private void writeJUnitXmlReport(List<AutobahnCaseResult> results, String surefireFileName, String testName)
throws Exception
public static void writeJUnitXmlReport(List<AutobahnCaseResult> results, String surefireFileName, String testName) throws Exception
{
int failures = 0;
long suiteDuration = 0;
@ -259,8 +167,7 @@ public class AutobahnTests
}
}
private void addFailure(Xpp3Dom testCase, AutobahnCaseResult result) throws IOException,
ParseException
public static void addFailure(Xpp3Dom testCase, AutobahnCaseResult result) throws IOException, ParseException
{
JSONParser parser = new JSONParser();
@ -292,7 +199,7 @@ public class AutobahnTests
}
}
private static List<AutobahnCaseResult> parseResults(Path jsonPath) throws Exception
public static List<AutobahnCaseResult> parseResults(Path jsonPath) throws Exception
{
List<AutobahnCaseResult> results = new ArrayList<>();
JSONParser parser = new JSONParser();

View File

@ -11,14 +11,13 @@
// ========================================================================
//
package org.eclipse.jetty.websocket.core.autobahn;
package org.eclipse.jetty.websocket.tests.core;
import java.nio.ByteBuffer;
import java.time.Duration;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.TestMessageHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.websocket.core.autobahn;
package org.eclipse.jetty.websocket.tests.core;
import java.net.URI;
import java.util.concurrent.Future;
@ -23,15 +23,15 @@ import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.UrlEncoded;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.TestMessageHandler;
import org.eclipse.jetty.websocket.core.client.CoreClientUpgradeRequest;
import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
import org.eclipse.jetty.websocket.core.internal.MessageHandler;
import org.eclipse.jetty.websocket.tests.AutobahnClient;
import org.junit.jupiter.api.Assertions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* WebSocket Client for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
@ -67,9 +67,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
* $ ls target/reports/clients/
* </pre>
*/
public class CoreAutobahnClient
public class CoreAutobahnClient implements AutobahnClient
{
public static void main(String[] args) throws Exception
public static void main(String[] args)
{
String hostname = "localhost";
int port = 9001;
@ -92,11 +92,25 @@ public class CoreAutobahnClient
}
}
CoreAutobahnClient client = null;
CoreAutobahnClient client = new CoreAutobahnClient();
client.runAutobahnClient(hostname, port, caseNumbers);
}
private static final Logger LOG = LoggerFactory.getLogger(CoreAutobahnClient.class);
private URI baseWebsocketUri;
private WebSocketCoreClient client;
private String userAgent;
@Override
public void runAutobahnClient(String hostname, int port, int[] caseNumbers)
{
try
{
String userAgent = "JettyWebsocketClient/" + Jetty.VERSION;
client = new CoreAutobahnClient(hostname, port, userAgent);
String userAgent = "CoreWebsocketClient/" + Jetty.VERSION;
this.userAgent = userAgent;
this.baseWebsocketUri = new URI("ws://" + hostname + ":" + port);
this.client = new WebSocketCoreClient();
this.client.start();
LOG.info("Running test suite...");
LOG.info("Using Fuzzing Server: {}:{}", hostname, port);
@ -104,12 +118,12 @@ public class CoreAutobahnClient
if (caseNumbers == null)
{
int caseCount = client.getCaseCount();
int caseCount = getCaseCount();
LOG.info("Will run all {} cases ...", caseCount);
for (int caseNum = 1; caseNum <= caseCount; caseNum++)
{
LOG.info("Running case {} (of {}) ...", caseNum, caseCount);
client.runCaseByNumber(caseNum);
runCaseByNumber(caseNum);
}
}
else
@ -117,48 +131,34 @@ public class CoreAutobahnClient
LOG.info("Will run {} cases ...", caseNumbers.length);
for (int caseNum : caseNumbers)
{
client.runCaseByNumber(caseNum);
runCaseByNumber(caseNum);
}
}
LOG.info("All test cases executed.");
client.updateReports();
updateReports();
}
catch (Throwable t)
{
LOG.warn("Test Failed", t);
throw t;
}
finally
{
if (client != null)
client.shutdown();
shutdown();
}
}
private static final Logger LOG = LoggerFactory.getLogger(CoreAutobahnClient.class);
private final URI baseWebsocketUri;
private final WebSocketCoreClient client;
private final String userAgent;
public CoreAutobahnClient(String hostname, int port, String userAgent) throws Exception
{
this.userAgent = userAgent;
this.baseWebsocketUri = new URI("ws://" + hostname + ":" + port);
this.client = new WebSocketCoreClient();
this.client.start();
}
public int getCaseCount() throws Exception
{
URI wsUri = baseWebsocketUri.resolve("/getCaseCount");
TestMessageHandler onCaseCount = new TestMessageHandler();
CoreSession session = upgrade(onCaseCount, wsUri).get(5, TimeUnit.SECONDS);
assertTrue(onCaseCount.openLatch.await(5, TimeUnit.SECONDS));
Assertions.assertTrue(onCaseCount.openLatch.await(5, TimeUnit.SECONDS));
String msg = onCaseCount.textMessages.poll(5, TimeUnit.SECONDS);
// Close the connection.
session.close(Callback.NOOP);
assertTrue(onCaseCount.closeLatch.await(5, TimeUnit.SECONDS));
Assertions.assertTrue(onCaseCount.closeLatch.await(5, TimeUnit.SECONDS));
assertNotNull(msg);
return Integer.decode(msg);
@ -208,7 +208,7 @@ public class CoreAutobahnClient
TestMessageHandler onUpdateReports = new TestMessageHandler();
Future<CoreSession> response = upgrade(onUpdateReports, wsUri);
response.get(5, TimeUnit.SECONDS);
assertTrue(onUpdateReports.closeLatch.await(15, TimeUnit.SECONDS));
Assertions.assertTrue(onUpdateReports.closeLatch.await(15, TimeUnit.SECONDS));
LOG.info("Reports updated.");
LOG.info("Test suite finished!");
}

View File

@ -11,14 +11,13 @@
// ========================================================================
//
package org.eclipse.jetty.websocket.core.autobahn;
package org.eclipse.jetty.websocket.tests.core;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.websocket.core.TestWebSocketNegotiator;
import org.eclipse.jetty.websocket.core.WebSocketComponents;
import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
import org.eclipse.jetty.websocket.tests.AutobahnServer;
/**
* WebSocket Server for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
@ -54,7 +53,7 @@ import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
* $ ls target/reports/servers/
* </pre>
*/
public class CoreAutobahnServer
public class CoreAutobahnServer implements AutobahnServer
{
public static void main(String[] args) throws Exception
{
@ -62,25 +61,36 @@ public class CoreAutobahnServer
if (args != null && args.length > 0)
port = Integer.parseInt(args[0]);
Server server = startAutobahnServer(port);
CoreAutobahnServer server = new CoreAutobahnServer();
server.startAutobahnServer(port);
server.join();
}
public static Server startAutobahnServer(int port) throws Exception
private Server _server;
public void startAutobahnServer(int port) throws Exception
{
Server server = new Server(port);
ServerConnector connector = new ServerConnector(server);
connector.setIdleTimeout(10000);
server.addConnector(connector);
ContextHandler context = new ContextHandler("/");
server.setHandler(context);
_server = new Server();
ServerConnector connector = new ServerConnector(_server);
connector.setPort(port);
_server.addConnector(connector);
WebSocketComponents components = new WebSocketComponents();
WebSocketUpgradeHandler handler = new WebSocketUpgradeHandler(components);
handler.addMapping("/*", new TestWebSocketNegotiator(new AutobahnFrameHandler()));
_server.setHandler(handler);
context.setHandler(handler);
server.start();
return server;
_server.start();
}
@Override
public void stopAutobahnServer() throws Exception
{
_server.stop();
}
public void join() throws InterruptedException
{
_server.join();
}
}

View File

@ -0,0 +1,82 @@
//
// ========================================================================
// Copyright (c) 1995-2022 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.websocket.tests.core;
import java.nio.ByteBuffer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.websocket.core.CloseStatus;
import org.eclipse.jetty.websocket.core.CoreSession;
import org.eclipse.jetty.websocket.core.internal.MessageHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestMessageHandler extends MessageHandler
{
protected static final Logger LOG = LoggerFactory.getLogger(TestMessageHandler.class);
public CoreSession coreSession;
public BlockingQueue<String> textMessages = new BlockingArrayQueue<>();
public BlockingQueue<ByteBuffer> binaryMessages = new BlockingArrayQueue<>();
public CloseStatus closeStatus;
public volatile Throwable error;
public CountDownLatch openLatch = new CountDownLatch(1);
public CountDownLatch errorLatch = new CountDownLatch(1);
public CountDownLatch closeLatch = new CountDownLatch(1);
@Override
public void onOpen(CoreSession coreSession, Callback callback)
{
super.onOpen(coreSession, callback);
this.coreSession = coreSession;
openLatch.countDown();
}
@Override
public void onError(Throwable cause, Callback callback)
{
super.onError(cause, callback);
error = cause;
errorLatch.countDown();
}
@Override
public void onClosed(CloseStatus closeStatus, Callback callback)
{
super.onClosed(closeStatus, callback);
this.closeStatus = closeStatus;
closeLatch.countDown();
}
@Override
protected void onText(String message, Callback callback)
{
if (LOG.isDebugEnabled())
LOG.debug("onText {}", message);
textMessages.offer(message);
callback.succeeded();
}
@Override
protected void onBinary(ByteBuffer message, Callback callback)
{
if (LOG.isDebugEnabled())
LOG.debug("onBinary {}", message);
binaryMessages.offer(message);
callback.succeeded();
}
}

View File

@ -0,0 +1,47 @@
//
// ========================================================================
// Copyright (c) 1995-2022 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.websocket.tests.core;
import java.io.IOException;
import java.util.List;
import org.eclipse.jetty.websocket.core.FrameHandler;
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiation;
import org.eclipse.jetty.websocket.core.server.WebSocketNegotiator;
public class TestWebSocketNegotiator extends WebSocketNegotiator.AbstractNegotiator
{
private final FrameHandler frameHandler;
public TestWebSocketNegotiator(FrameHandler frameHandler)
{
this(frameHandler, null);
}
public TestWebSocketNegotiator(FrameHandler frameHandler, Customizer customizer)
{
super(customizer);
this.frameHandler = frameHandler;
}
@Override
public FrameHandler negotiate(WebSocketNegotiation negotiation) throws IOException
{
List<String> offeredSubprotocols = negotiation.getOfferedSubprotocols();
if (!offeredSubprotocols.isEmpty())
negotiation.setSubprotocol(offeredSubprotocols.get(0));
return frameHandler;
}
}

View File

@ -0,0 +1,38 @@
//
// ========================================================================
// Copyright (c) 1995-2022 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.websocket.tests.javax;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.websocket.ClientEndpoint;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/")
@ClientEndpoint(configurator = HostConfigurator.class)
public class EchoSocket extends EventSocket
{
@Override
public void onMessage(String message) throws IOException
{
super.onMessage(message);
session.getBasicRemote().sendText(message);
}
@Override
public void onMessage(ByteBuffer message) throws IOException
{
super.onMessage(message);
session.getBasicRemote().sendBinary(message);
}
}

View File

@ -0,0 +1,96 @@
//
// ========================================================================
// Copyright (c) 1995-2022 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.websocket.tests.javax;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ServerEndpoint("/")
@ClientEndpoint(configurator = HostConfigurator.class)
public class EventSocket
{
private static final Logger LOG = LoggerFactory.getLogger(EventSocket.class);
public Session session;
public EndpointConfig endpointConfig;
public BlockingQueue<String> textMessages = new BlockingArrayQueue<>();
public BlockingQueue<ByteBuffer> binaryMessages = new BlockingArrayQueue<>();
public volatile Throwable error = null;
public volatile CloseReason closeReason = null;
public CountDownLatch openLatch = new CountDownLatch(1);
public CountDownLatch closeLatch = new CountDownLatch(1);
public CountDownLatch errorLatch = new CountDownLatch(1);
@OnOpen
public void onOpen(Session session, EndpointConfig endpointConfig)
{
this.session = session;
this.endpointConfig = endpointConfig;
if (LOG.isDebugEnabled())
LOG.debug("{} onOpen(): {}", toString(), session);
openLatch.countDown();
}
@OnMessage
public void onMessage(String message) throws IOException
{
if (LOG.isDebugEnabled())
LOG.debug("{} onMessage(): {}", toString(), message);
textMessages.offer(message);
}
@OnMessage
public void onMessage(ByteBuffer message) throws IOException
{
if (LOG.isDebugEnabled())
LOG.debug("{} onMessage(): {}", toString(), message);
binaryMessages.offer(message);
}
@OnClose
public void onClose(CloseReason reason)
{
if (LOG.isDebugEnabled())
LOG.debug("{} onClose(): {}", toString(), reason);
closeReason = reason;
closeLatch.countDown();
}
@OnError
public void onError(Throwable cause)
{
if (LOG.isDebugEnabled())
LOG.debug("{} onError(): {}", toString(), cause);
error = cause;
errorLatch.countDown();
}
}

View File

@ -0,0 +1,30 @@
//
// ========================================================================
// Copyright (c) 1995-2022 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.websocket.tests.javax;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.websocket.ClientEndpointConfig;
import org.eclipse.jetty.http.HttpHeader;
public class HostConfigurator extends ClientEndpointConfig.Configurator
{
@Override
public void beforeRequest(Map<String, List<String>> headers)
{
headers.put(HttpHeader.HOST.asString(), Collections.singletonList("localhost:9001"));
}
}

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.websocket.javax.tests.autobahn;
package org.eclipse.jetty.websocket.tests.javax;
import java.net.URI;
import java.util.concurrent.TimeUnit;
@ -21,7 +21,8 @@ import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.UrlEncoded;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.websocket.javax.client.internal.JavaxWebSocketClientContainer;
import org.eclipse.jetty.websocket.javax.tests.EventSocket;
import org.eclipse.jetty.websocket.tests.AutobahnClient;
import org.eclipse.jetty.websocket.tests.jetty.JettyAutobahnClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -62,7 +63,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
* $ ls target/reports/clients/
* </pre>
*/
public class JavaxAutobahnClient
public class JavaxAutobahnClient implements AutobahnClient
{
public static void main(String[] args)
{
@ -87,46 +88,8 @@ public class JavaxAutobahnClient
}
}
JavaxAutobahnClient client = null;
try
{
String userAgent = "JettyWebsocketClient/" + Jetty.VERSION;
client = new JavaxAutobahnClient(hostname, port, userAgent);
LOG.info("Running test suite...");
LOG.info("Using Fuzzing Server: {}:{}", hostname, port);
LOG.info("User Agent: {}", userAgent);
if (caseNumbers == null)
{
int caseCount = client.getCaseCount();
LOG.info("Will run all {} cases ...", caseCount);
for (int caseNum = 1; caseNum <= caseCount; caseNum++)
{
LOG.info("Running case {} (of {}) ...", caseNum, caseCount);
client.runCaseByNumber(caseNum);
}
}
else
{
LOG.info("Will run {} cases ...", caseNumbers.length);
for (int caseNum : caseNumbers)
{
client.runCaseByNumber(caseNum);
}
}
LOG.info("All test cases executed.");
client.updateReports();
}
catch (Throwable t)
{
LOG.warn("Test Failed", t);
}
finally
{
if (client != null)
client.stop();
}
JettyAutobahnClient client = new JettyAutobahnClient();
client.runAutobahnClient(hostname, port, caseNumbers);
}
private static final Logger LOG = LoggerFactory.getLogger(JavaxAutobahnClient.class);
@ -134,15 +97,53 @@ public class JavaxAutobahnClient
private JavaxWebSocketClientContainer clientContainer;
private String userAgent;
public JavaxAutobahnClient(String hostname, int port, String userAgent) throws Exception
@Override
public void runAutobahnClient(String hostname, int port, int[] caseNumbers)
{
this.userAgent = userAgent;
this.baseWebsocketUri = new URI("ws://" + hostname + ":" + port);
this.clientContainer = new JavaxWebSocketClientContainer();
clientContainer.start();
try
{
String userAgent = "JavaxWebsocketClient/" + Jetty.VERSION;
this.userAgent = userAgent;
this.baseWebsocketUri = new URI("ws://" + hostname + ":" + port);
this.clientContainer = new JavaxWebSocketClientContainer();
clientContainer.start();
LOG.info("Running test suite...");
LOG.info("Using Fuzzing Server: {}:{}", hostname, port);
LOG.info("User Agent: {}", userAgent);
if (caseNumbers == null)
{
int caseCount = getCaseCount();
LOG.info("Will run all {} cases ...", caseCount);
for (int caseNum = 1; caseNum <= caseCount; caseNum++)
{
LOG.info("Running case {} (of {}) ...", caseNum, caseCount);
runCaseByNumber(caseNum);
}
}
else
{
LOG.info("Will run {} cases ...", caseNumbers.length);
for (int caseNum : caseNumbers)
{
runCaseByNumber(caseNum);
}
}
LOG.info("All test cases executed.");
updateReports();
}
catch (Throwable t)
{
LOG.warn("Test Failed", t);
}
finally
{
shutdown();
}
}
public void stop()
public void shutdown()
{
LifeCycle.stop(clientContainer);
}

View File

@ -11,12 +11,13 @@
// ========================================================================
//
package org.eclipse.jetty.websocket.javax.tests.autobahn;
package org.eclipse.jetty.websocket.tests.javax;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
import org.eclipse.jetty.websocket.tests.AutobahnServer;
/**
* WebSocket Server for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
@ -52,7 +53,7 @@ import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletCont
* $ ls target/reports/servers/
* </pre>
*/
public class JavaxAutobahnServer
public class JavaxAutobahnServer implements AutobahnServer
{
public static void main(String[] args) throws Exception
{
@ -60,18 +61,38 @@ public class JavaxAutobahnServer
if (args != null && args.length > 0)
port = Integer.parseInt(args[0]);
Server server = new Server(port);
ServerConnector connector = new ServerConnector(server);
connector.setIdleTimeout(10000);
server.addConnector(connector);
JavaxAutobahnServer server = new JavaxAutobahnServer();
server.startAutobahnServer(port);
server.join();
}
private Server _server;
public void startAutobahnServer(int port) throws Exception
{
_server = new Server();
ServerConnector connector = new ServerConnector(_server);
connector.setPort(port);
_server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
_server.setHandler(context);
JavaxWebSocketServletContainerInitializer.configure(context, (servletContext, container) ->
container.addEndpoint(JavaxAutobahnSocket.class));
server.start();
server.join();
_server.start();
}
@Override
public void stopAutobahnServer() throws Exception
{
_server.stop();
}
public void join() throws InterruptedException
{
_server.join();
}
}

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.websocket.javax.tests.autobahn;
package org.eclipse.jetty.websocket.tests.javax;
import java.io.IOException;
import java.nio.ByteBuffer;
@ -27,7 +27,7 @@ import javax.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ClientEndpoint
@ClientEndpoint(configurator = HostConfigurator.class)
@ServerEndpoint("/")
public class JavaxAutobahnSocket
{

View File

@ -0,0 +1,37 @@
//
// ========================================================================
// Copyright (c) 1995-2022 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.websocket.tests.jetty;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
@WebSocket
public class EchoSocket extends EventSocket
{
@Override
public void onMessage(String message) throws IOException
{
super.onMessage(message);
session.getRemote().sendString(message);
}
@Override
public void onMessage(byte[] buf, int offset, int len) throws IOException
{
super.onMessage(buf, offset, len);
session.getRemote().sendBytes(ByteBuffer.wrap(buf, offset, len));
}
}

View File

@ -0,0 +1,101 @@
//
// ========================================================================
// Copyright (c) 1995-2022 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.websocket.tests.jetty;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@WebSocket
public class EventSocket
{
private static final Logger LOG = LoggerFactory.getLogger(EventSocket.class);
public Session session;
private String behavior;
public BlockingQueue<String> textMessages = new BlockingArrayQueue<>();
public BlockingQueue<ByteBuffer> binaryMessages = new BlockingArrayQueue<>();
public volatile int closeCode = StatusCode.UNDEFINED;
public volatile String closeReason;
public volatile Throwable error = null;
public CountDownLatch openLatch = new CountDownLatch(1);
public CountDownLatch errorLatch = new CountDownLatch(1);
public CountDownLatch closeLatch = new CountDownLatch(1);
@OnWebSocketConnect
public void onOpen(Session session)
{
this.session = session;
behavior = session.getPolicy().getBehavior().name();
if (LOG.isDebugEnabled())
LOG.debug("{} onOpen(): {}", toString(), session);
openLatch.countDown();
}
@OnWebSocketMessage
public void onMessage(String message) throws IOException
{
if (LOG.isDebugEnabled())
LOG.debug("{} onMessage(): {}", toString(), message);
textMessages.offer(message);
}
@OnWebSocketMessage
public void onMessage(byte[] buf, int offset, int len) throws IOException
{
ByteBuffer message = ByteBuffer.wrap(buf, offset, len);
if (LOG.isDebugEnabled())
LOG.debug("{} onMessage(): {}", toString(), message);
binaryMessages.offer(message);
}
@OnWebSocketClose
public void onClose(int statusCode, String reason)
{
if (LOG.isDebugEnabled())
LOG.debug("{} onClose(): {}:{}", toString(), statusCode, reason);
this.closeCode = statusCode;
this.closeReason = reason;
closeLatch.countDown();
}
@OnWebSocketError
public void onError(Throwable cause)
{
if (LOG.isDebugEnabled())
LOG.debug("{} onError(): {}", toString(), cause);
error = cause;
errorLatch.countDown();
}
@Override
public String toString()
{
return String.format("[%s@%s]", behavior, Integer.toHexString(hashCode()));
}
}

View File

@ -11,28 +11,25 @@
// ========================================================================
//
package org.eclipse.jetty.websocket.tests.autobahn;
package org.eclipse.jetty.websocket.tests.jetty;
import java.io.IOException;
import java.net.URI;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.UrlEncoded;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.tests.EchoSocket;
import org.eclipse.jetty.websocket.tests.EventSocket;
import org.eclipse.jetty.websocket.tests.AutobahnClient;
import org.junit.jupiter.api.Assertions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* WebSocket Client for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
@ -68,7 +65,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
* $ ls target/reports/clients/
* </pre>
*/
public class JettyAutobahnClient
public class JettyAutobahnClient implements AutobahnClient
{
public static void main(String[] args)
{
@ -93,46 +90,8 @@ public class JettyAutobahnClient
}
}
JettyAutobahnClient client = null;
try
{
String userAgent = "JettyWebsocketClient/" + Jetty.VERSION;
client = new JettyAutobahnClient(hostname, port, userAgent);
LOG.info("Running test suite...");
LOG.info("Using Fuzzing Server: {}:{}", hostname, port);
LOG.info("User Agent: {}", userAgent);
if (caseNumbers == null)
{
int caseCount = client.getCaseCount();
LOG.info("Will run all {} cases ...", caseCount);
for (int caseNum = 1; caseNum <= caseCount; caseNum++)
{
LOG.info("Running case {} (of {}) ...", caseNum, caseCount);
client.runCaseByNumber(caseNum);
}
}
else
{
LOG.info("Will run {} cases ...", caseNumbers.length);
for (int caseNum : caseNumbers)
{
client.runCaseByNumber(caseNum);
}
}
LOG.info("All test cases executed.");
client.updateReports();
}
catch (Throwable t)
{
LOG.warn("Test Failed", t);
}
finally
{
if (client != null)
client.shutdown();
}
JettyAutobahnClient client = new JettyAutobahnClient();
client.runAutobahnClient(hostname, port, caseNumbers);
}
private static final Logger LOG = LoggerFactory.getLogger(JettyAutobahnClient.class);
@ -140,38 +99,76 @@ public class JettyAutobahnClient
private WebSocketClient client;
private String userAgent;
public JettyAutobahnClient(String hostname, int port, String userAgent) throws Exception
@Override
public void runAutobahnClient(String hostname, int port, int[] caseNumbers)
{
this.userAgent = userAgent;
this.baseWebsocketUri = new URI("ws://" + hostname + ":" + port);
this.client = new WebSocketClient();
this.client.start();
try
{
String userAgent = "JettyWebsocketClient/" + Jetty.VERSION;
this.userAgent = userAgent;
this.baseWebsocketUri = new URI("ws://" + hostname + ":" + port);
this.client = new WebSocketClient();
this.client.start();
LOG.info("Running test suite...");
LOG.info("Using Fuzzing Server: {}:{}", hostname, port);
LOG.info("User Agent: {}", userAgent);
if (caseNumbers == null)
{
int caseCount = getCaseCount();
LOG.info("Will run all {} cases ...", caseCount);
for (int caseNum = 1; caseNum <= caseCount; caseNum++)
{
LOG.info("Running case {} (of {}) ...", caseNum, caseCount);
runCaseByNumber(caseNum);
}
}
else
{
LOG.info("Will run {} cases ...", caseNumbers.length);
for (int caseNum : caseNumbers)
{
runCaseByNumber(caseNum);
}
}
LOG.info("All test cases executed.");
updateReports();
}
catch (Throwable t)
{
LOG.warn("Test Failed", t);
}
finally
{
shutdown();
}
}
public int getCaseCount() throws IOException, InterruptedException
public int getCaseCount() throws Exception
{
URI wsUri = baseWebsocketUri.resolve("/getCaseCount");
EventSocket onCaseCount = new EventSocket();
CompletableFuture<Session> response = client.connect(onCaseCount, wsUri);
Future<Session> response = upgrade(onCaseCount, wsUri);
if (waitForUpgrade(wsUri, response))
{
String msg = onCaseCount.textMessages.poll(10, TimeUnit.SECONDS);
onCaseCount.session.close(StatusCode.SHUTDOWN, null);
assertTrue(onCaseCount.closeLatch.await(2, TimeUnit.SECONDS));
Assertions.assertTrue(onCaseCount.closeLatch.await(2, TimeUnit.SECONDS));
assertNotNull(msg);
return Integer.decode(msg);
}
throw new IllegalStateException("Unable to get Case Count");
}
public void runCaseByNumber(int caseNumber) throws IOException, InterruptedException
public void runCaseByNumber(int caseNumber) throws Exception
{
URI wsUri = baseWebsocketUri.resolve("/runCase?case=" + caseNumber + "&agent=" + UrlEncoded.encodeString(userAgent));
LOG.info("test uri: {}", wsUri);
EchoSocket echoHandler = new JettyAutobahnSocket();
Future<Session> response = client.connect(echoHandler, wsUri);
Future<Session> response = upgrade(echoHandler, wsUri);
if (waitForUpgrade(wsUri, response))
{
// Wait up to 5 min as some of the tests can take a while
@ -195,13 +192,21 @@ public class JettyAutobahnClient
}
}
public void updateReports() throws IOException, InterruptedException, ExecutionException, TimeoutException
public Future<Session> upgrade(Object handler, URI uri) throws Exception
{
// We manually set the port as we run the server in docker container.
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
upgradeRequest.setHeader(HttpHeader.HOST.asString(), "localhost:9001");
return client.connect(handler, uri, upgradeRequest);
}
public void updateReports() throws Exception
{
URI wsUri = baseWebsocketUri.resolve("/updateReports?agent=" + UrlEncoded.encodeString(userAgent));
EventSocket onUpdateReports = new EventSocket();
Future<Session> response = client.connect(onUpdateReports, wsUri);
Future<Session> response = upgrade(onUpdateReports, wsUri);
response.get(5, TimeUnit.SECONDS);
assertTrue(onUpdateReports.closeLatch.await(15, TimeUnit.SECONDS));
Assertions.assertTrue(onUpdateReports.closeLatch.await(15, TimeUnit.SECONDS));
LOG.info("Reports updated.");
LOG.info("Test suite finished!");
}

View File

@ -11,12 +11,13 @@
// ========================================================================
//
package org.eclipse.jetty.websocket.tests.autobahn;
package org.eclipse.jetty.websocket.tests.jetty;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
import org.eclipse.jetty.websocket.tests.AutobahnServer;
/**
* WebSocket Server for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
@ -52,7 +53,7 @@ import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerI
* $ ls target/reports/servers/
* </pre>
*/
public class JettyAutobahnServer
public class JettyAutobahnServer implements AutobahnServer
{
public static void main(String[] args) throws Exception
{
@ -60,18 +61,39 @@ public class JettyAutobahnServer
if (args != null && args.length > 0)
port = Integer.parseInt(args[0]);
Server server = new Server(port);
ServerConnector connector = new ServerConnector(server);
connector.setIdleTimeout(10000);
server.addConnector(connector);
JettyAutobahnServer server = new JettyAutobahnServer();
server.startAutobahnServer(port);
server.join();
}
private Server _server;
@Override
public void startAutobahnServer(int port) throws Exception
{
_server = new Server();
ServerConnector connector = new ServerConnector(_server);
connector.setPort(port);
_server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
_server.setHandler(context);
JettyWebSocketServletContainerInitializer.configure(context, (servletContext, container) ->
container.addMapping("/", (req, resp) -> new JettyAutobahnSocket()));
server.start();
server.join();
_server.start();
}
@Override
public void stopAutobahnServer() throws Exception
{
_server.stop();
}
public void join() throws InterruptedException
{
_server.join();
}
}

View File

@ -11,12 +11,11 @@
// ========================================================================
//
package org.eclipse.jetty.websocket.tests.autobahn;
package org.eclipse.jetty.websocket.tests.jetty;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.core.WebSocketConstants;
import org.eclipse.jetty.websocket.tests.EchoSocket;
@WebSocket
public class JettyAutobahnSocket extends EchoSocket

View File

@ -0,0 +1,4 @@
org.slf4j.simpleLogger.defaultLogLevel=info
org.slf4j.simpleLogger.showDateTime=true
org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss
org.slf4j.simpleLogger.log.org.eclipse.jetty.websocket.tests=info