From fff257808635c33e6053288dd237bff82d93ec88 Mon Sep 17 00:00:00 2001 From: Jose Date: Tue, 16 Feb 2021 08:22:32 +0100 Subject: [PATCH] Add QuarkusProdModeTest start/stop methods and fix restassured integration when random ports --- .../io/quarkus/test/QuarkusProdModeTest.java | 92 ++++++++++++++----- .../quarkus/test/QuarkusProdModeTestTest.java | 42 +++++++++ 2 files changed, 109 insertions(+), 25 deletions(-) create mode 100644 test-framework/junit5-internal/src/test/java/io/quarkus/test/QuarkusProdModeTestTest.java diff --git a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusProdModeTest.java b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusProdModeTest.java index cdfcadf74a3d2..34edf10062bc6 100644 --- a/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusProdModeTest.java +++ b/test-framework/junit5-internal/src/main/java/io/quarkus/test/QuarkusProdModeTest.java @@ -106,6 +106,7 @@ public class QuarkusProdModeTest private Process process; + private Path builtResultArtifact; private ProdModeTestResults prodModeTestResults; private Optional prodModeTestResultsField = Optional.empty(); private Path logfilePath; @@ -114,7 +115,7 @@ public class QuarkusProdModeTest private InMemoryLogHandler inMemoryLogHandler = new InMemoryLogHandler((r) -> false); private boolean expectExit; private String startupConsoleOutput; - private int exitCode; + private Integer exitCode; private Consumer assertBuildException; private String[] commandLineParameters = new String[0]; @@ -259,9 +260,10 @@ public String getStartupConsoleOutput() { } /** - * Returns the process exit code, this can only be used if {@link #expectExit} is true + * Returns the process exit code, this can only be used if {@link #expectExit} is true. + * Null if the app is running. */ - public int getExitCode() { + public Integer getExitCode() { return exitCode; } @@ -401,14 +403,10 @@ public void close() throws Throwable { curatedApplication.close(); } - Path builtResultArtifact = setupProdModeResults(testClass, buildDir, result); + builtResultArtifact = setupProdModeResults(testClass, buildDir, result); if (run) { - startBuiltResult(builtResultArtifact); - RestAssuredURLManager.setURL(false, - runtimeProperties.get(QUARKUS_HTTP_PORT_PROPERTY) != null - ? Integer.parseInt(runtimeProperties.get(QUARKUS_HTTP_PORT_PROPERTY)) - : DEFAULT_HTTP_PORT_INT); + start(); if (logfilePath != null) { logfileField = Arrays.stream(testClass.getDeclaredFields()).filter( @@ -465,8 +463,20 @@ private Path setupProdModeResults(Class testClass, Path buildDir, AugmentResu return builtResultArtifact; } - private void startBuiltResult(Path builtResultArtifact) throws IOException { - Path builtResultArtifactParentDir = builtResultArtifact.getParent(); + /** + * Start the Quarkus application. If the application is already started, it raises an {@link IllegalStateException} + * exception. + * + * @throws RuntimeException when application errors at startup. + * @throws IllegalStateException if the application is already started. + */ + public void start() { + if (process != null && process.isAlive()) { + throw new IllegalStateException("Quarkus application is already started. "); + } + + exitCode = null; + Path builtResultArtifactParent = builtResultArtifact.getParent(); if (runtimeProperties == null) { runtimeProperties = new HashMap<>(); @@ -476,7 +486,7 @@ private void startBuiltResult(Path builtResultArtifact) throws IOException { } runtimeProperties.putIfAbsent(QUARKUS_HTTP_PORT_PROPERTY, DEFAULT_HTTP_PORT); if (logFileName != null) { - logfilePath = builtResultArtifactParentDir.resolve(logFileName); + logfilePath = builtResultArtifactParent.resolve(logFileName); runtimeProperties.put("quarkus.log.file.path", logfilePath.toAbsolutePath().toString()); runtimeProperties.put("quarkus.log.file.enable", "true"); } @@ -505,11 +515,46 @@ private void startBuiltResult(Path builtResultArtifact) throws IOException { } command.addAll(Arrays.asList(commandLineParameters)); - process = new ProcessBuilder(command) - .redirectErrorStream(true) - .directory(builtResultArtifactParentDir.toFile()) - .start(); - ensureApplicationStartupOrFailure(); + + try { + process = new ProcessBuilder(command) + .redirectErrorStream(true) + .directory(builtResultArtifactParent.toFile()) + .start(); + ensureApplicationStartupOrFailure(); + setupRestAssured(); + } catch (IOException ex) { + throw new RuntimeException("The produced jar could not be launched. ", ex); + } + } + + /** + * Stop the Quarkus application. + */ + public void stop() { + try { + if (process != null) { + process.destroy(); + process.waitFor(); + exitCode = process.exitValue(); + } + } catch (InterruptedException ignored) { + + } + } + + private void setupRestAssured() { + Integer httpPort = Optional.ofNullable(runtimeProperties.get(QUARKUS_HTTP_PORT_PROPERTY)) + .map(Integer::parseInt) + .orElse(DEFAULT_HTTP_PORT_INT); + + // If http port is 0, then we need to set the port to null in order to use the `quarkus.https.test-port` property + // which is done in `RestAssuredURLManager.setURL`. + if (httpPort == 0) { + httpPort = null; + } + + RestAssuredURLManager.setURL(false, httpPort); } private void ensureApplicationStartupOrFailure() throws IOException { @@ -586,14 +631,7 @@ public void afterAll(ExtensionContext extensionContext) throws Exception { RestAssuredURLManager.clearURL(); } - try { - if (process != null) { - process.destroy(); - process.waitFor(); - } - } catch (InterruptedException ignored) { - - } + stop(); try { if (curatedApplication != null) { @@ -611,6 +649,10 @@ public void afterAll(ExtensionContext extensionContext) throws Exception { @Override public void beforeEach(ExtensionContext context) { + if (run && (process == null || !process.isAlive())) { + start(); + } + prodModeTestResultsField.ifPresent(f -> { try { f.set(context.getRequiredTestInstance(), prodModeTestResults); diff --git a/test-framework/junit5-internal/src/test/java/io/quarkus/test/QuarkusProdModeTestTest.java b/test-framework/junit5-internal/src/test/java/io/quarkus/test/QuarkusProdModeTestTest.java new file mode 100644 index 0000000000000..f8dbece2c0cb7 --- /dev/null +++ b/test-framework/junit5-internal/src/test/java/io/quarkus/test/QuarkusProdModeTestTest.java @@ -0,0 +1,42 @@ +package io.quarkus.test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +public class QuarkusProdModeTestTest { + @RegisterExtension + static final QuarkusProdModeTest simpleApp = new QuarkusProdModeTest() + .setApplicationName("simple-app") + .setApplicationVersion("0.1-SNAPSHOT") + .setRun(true); + + @Test + public void shouldStartAndStopInnerProcess() { + thenAppIsRunning(); + + whenStopApp(); + thenAppIsNotRunning(); + + whenStartApp(); + thenAppIsRunning(); + } + + private void whenStopApp() { + simpleApp.stop(); + } + + private void whenStartApp() { + simpleApp.start(); + } + + private void thenAppIsNotRunning() { + assertNotNull(simpleApp.getExitCode(), "App is running"); + } + + private void thenAppIsRunning() { + assertNull(simpleApp.getExitCode(), "App is not running"); + } +}