diff --git a/jetty-websocket/websocket-core-tests/src/test/java/org/eclipse/jetty/websocket/core/autobahn/AutobahnTests.java b/jetty-websocket/websocket-core-tests/src/test/java/org/eclipse/jetty/websocket/core/autobahn/AutobahnTests.java index 117f040d5ae..667ab93a01c 100644 --- a/jetty-websocket/websocket-core-tests/src/test/java/org/eclipse/jetty/websocket/core/autobahn/AutobahnTests.java +++ b/jetty-websocket/websocket-core-tests/src/test/java/org/eclipse/jetty/websocket/core/autobahn/AutobahnTests.java @@ -19,9 +19,7 @@ package org.eclipse.jetty.websocket.core.autobahn; import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.io.FileNotFoundException; import java.io.Reader; import java.nio.file.Files; import java.nio.file.Path; @@ -32,21 +30,22 @@ import java.util.List; import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.exception.NotFoundException; +import org.apache.commons.compress.archivers.ArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; 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.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; 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.startupcheck.OneShotStartupCheckStrategy; import org.testcontainers.containers.startupcheck.StartupCheckStrategy; import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerStatus; import org.testcontainers.utility.TestcontainersConfiguration; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -54,7 +53,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; @Testcontainers public class AutobahnTests { - static { TestcontainersConfiguration.getInstance().getProperties().setProperty("transport.type", "httpclient5"); @@ -62,76 +60,52 @@ 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 static final String CHOWN_REPORTS_CMD = "[ -d /target/reports ] && chown -R `stat -c '%u' /target/reports` /target/reports/* && touch done.txt"; - private Path reportDir; - private Path fuzzingServer; - private Path fuzzingClient; + private static Path reportDir; + private static Path fuzzingServer; + private static Path fuzzingClient; - Path baseDir; - - @BeforeEach - public void before() throws Exception + @BeforeAll + public static void before() throws Exception { String workspace; workspace = System.getenv().get("WORKSPACE"); LOG.info("Workspace: {}", workspace); LOG.info("User Dir: {}", USER_DIR); - baseDir = USER_DIR;//(workspace != null) ? Paths.get(workspace) : USER_DIR; - LOG.info("Base Dir: {}", baseDir); - fuzzingServer = baseDir.resolve("fuzzingserver.json"); + fuzzingServer = USER_DIR.resolve("fuzzingserver.json"); assertTrue(Files.exists(fuzzingServer), fuzzingServer + " not exists"); - fuzzingClient = baseDir.resolve("fuzzingclient.json"); - assertTrue(Files.exists(fuzzingClient), fuzzingClient + " not exists"); + fuzzingClient = USER_DIR.resolve("fuzzingclient.json"); + assertTrue(Files.exists(fuzzingClient), fuzzingClient + " not exists"); - reportDir = baseDir.resolve("target/reports"); - if (!Files.exists(reportDir)) - Files.createDirectory(reportDir); + reportDir = USER_DIR.resolve("target/reports"); + IO.delete(reportDir.toFile()); + Files.createDirectory(reportDir); } @Test public void testClient() throws Exception { - // We need to chown the generated test results so host has permissions to delete files generated by container. - try (GenericContainer container = new GenericContainer<>("crossbario/autobahn-testsuite:latest") - .withCommand("/bin/bash", "-c", "wstest -m fuzzingserver -s /config/fuzzingserver.json ; " + CHOWN_REPORTS_CMD) + GenericContainer container = new GenericContainer<>("crossbario/autobahn-testsuite:latest") + .withCommand("/bin/bash", "-c", "wstest -m fuzzingserver -s /config/fuzzingserver.json") .withExposedPorts(9001) - .withLogConsumer(new Slf4jLogConsumer(LOG))) + .withLogConsumer(new Slf4jLogConsumer(LOG)); + container.addFileSystemBind(fuzzingServer.toString(), "/config/fuzzingserver.json", BindMode.READ_ONLY); + + try { - container.addFileSystemBind(fuzzingServer.toString(), "/config/fuzzingserver.json", BindMode.READ_ONLY); - container.addFileSystemBind(reportDir.toString(), "/target/reports", BindMode.READ_WRITE); - // we simply declare it as started once we get the file - File indexJson = new File(reportDir.toFile(), "index.json"); - container.withStartupCheckStrategy(new StartupCheckStrategy() - { - @Override - public StartupStatus checkStartupState(DockerClient dockerClient, String containerId ) - { - try(InputStream done = dockerClient.copyArchiveFromContainerCmd( containerId, "done.txt" ).exec(); - InputStream inputStream = - dockerClient.copyArchiveFromContainerCmd( containerId, "/target/reports/clients/index.json" ).exec(); - TarArchiveInputStream tarInputStream = new TarArchiveInputStream( inputStream)) - { - tarInputStream.getNextEntry(); - Files.copy(tarInputStream, indexJson.toPath()); - return StartupStatus.SUCCESSFUL; - } catch (NotFoundException e){ - // ignore as file not ready yet - } - catch ( Exception e ) - { - throw new RuntimeException(e.getMessage(),e); - } - // still no file so we declare this not ready yet - return StartupStatus.NOT_YET_KNOWN; - } - }); container.start(); Integer mappedPort = container.getMappedPort(9001); CoreAutobahnClient.main(new String[]{"localhost", mappedPort.toString()}); - IO.copy(reportDir.toFile(), baseDir.resolve("target/reports-client").toFile()); + + DockerClient dockerClient = container.getDockerClient(); + String containerId = container.getContainerId(); + copyFromContainer(dockerClient, containerId, reportDir, Paths.get("/target/reports/clients")); + } + finally + { + container.stop(); } LOG.info("Test Result Overview {}", reportDir.resolve("clients/index.html").toUri()); @@ -144,16 +118,15 @@ public class AutobahnTests final int port = 9001; org.testcontainers.Testcontainers.exposeHostPorts(port); Server server = CoreAutobahnServer.startAutobahnServer(port); - // We need to chown the generated test results so host has permissions to delete files generated by container. + + FileSignalWaitStrategy strategy = new FileSignalWaitStrategy(reportDir, Paths.get("/target/reports/servers")); try (GenericContainer container = new GenericContainer<>("crossbario/autobahn-testsuite:latest") - .withCommand("/bin/bash", "-c", "wstest -m fuzzingclient -s /config/fuzzingclient.json ; " + CHOWN_REPORTS_CMD) + .withCommand("/bin/bash", "-c", "wstest -m fuzzingclient -s /config/fuzzingclient.json" + FileSignalWaitStrategy.END_COMMAND) .withLogConsumer(new Slf4jLogConsumer(LOG)) - .withStartupCheckStrategy(new OneShotStartupCheckStrategy().withTimeout(Duration.ofHours(1)))) + .withStartupCheckStrategy(strategy)) { container.addFileSystemBind(fuzzingClient.toString(), "/config/fuzzingclient.json", BindMode.READ_ONLY); - container.addFileSystemBind(reportDir.toString(), "/target/reports", BindMode.READ_WRITE); container.start(); - IO.copy(reportDir.toFile(), baseDir.resolve("target/reports-server").toFile()); } finally { @@ -163,6 +136,75 @@ public class AutobahnTests LOG.info("Test Result Overview {}", reportDir.resolve("servers/index.html").toUri()); } + private static class FileSignalWaitStrategy extends StartupCheckStrategy + { + public static final String SIGNAL_FILE = "/signalComplete"; + public static final String END_COMMAND = " && touch " + SIGNAL_FILE + " && sleep infinity"; + + Path _localDir; + Path _containerDir; + + public FileSignalWaitStrategy(Path localDir, Path containerDir) + { + _localDir = localDir; + _containerDir = containerDir; + withTimeout(Duration.ofHours(2)); + } + + @Override + public StartupCheckStrategy.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))) + return StartupStatus.FAILED; + + try + { + dockerClient.copyArchiveFromContainerCmd(containerId, SIGNAL_FILE).exec().close(); + } + catch (FileNotFoundException | NotFoundException e) + { + return StartupStatus.NOT_YET_KNOWN; + } + catch (Throwable t) + { + LOG.warn("Unknown Error", t); + return StartupStatus.FAILED; + } + + try + { + copyFromContainer(dockerClient, containerId, _localDir, _containerDir); + return StartupStatus.SUCCESSFUL; + } + catch (Throwable t) + { + LOG.warn("Error copying reports", t); + return StartupStatus.FAILED; + } + } + } + + private static void copyFromContainer(DockerClient dockerClient, String containerId, Path target, Path source) throws Exception + { + try (TarArchiveInputStream tarArchiveInputStream = new TarArchiveInputStream(dockerClient + .copyArchiveFromContainerCmd(containerId, source.toString()) + .exec())) + { + ArchiveEntry archiveEntry; + while ((archiveEntry = tarArchiveInputStream.getNextEntry()) != null) + { + Path filePath = target.resolve(archiveEntry.getName()); + if (archiveEntry.isDirectory()) + { + if (!Files.exists(filePath)) + Files.createDirectory(filePath); + continue; + } + Files.copy(tarArchiveInputStream, filePath); + } + } + } private static List parseResults( String agentString, Path jsonPath) throws Exception { List results = new ArrayList<>(); diff --git a/jetty-websocket/websocket-core-tests/src/test/java/org/eclipse/jetty/websocket/core/autobahn/CoreAutobahnClient.java b/jetty-websocket/websocket-core-tests/src/test/java/org/eclipse/jetty/websocket/core/autobahn/CoreAutobahnClient.java index 0de91eca80b..51e33942388 100644 --- a/jetty-websocket/websocket-core-tests/src/test/java/org/eclipse/jetty/websocket/core/autobahn/CoreAutobahnClient.java +++ b/jetty-websocket/websocket-core-tests/src/test/java/org/eclipse/jetty/websocket/core/autobahn/CoreAutobahnClient.java @@ -74,7 +74,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; */ public class CoreAutobahnClient { - public static void main(String[] args) + public static void main(String[] args) throws Exception { String hostname = "localhost"; int port = 9001; @@ -131,6 +131,7 @@ public class CoreAutobahnClient catch (Throwable t) { LOG.warn("Test Failed", t); + throw t; } finally {