diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/console/ConsoleHelper.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/console/ConsoleHelper.java index 6f57065e1ef88..449628c6a28f8 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/console/ConsoleHelper.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/console/ConsoleHelper.java @@ -6,7 +6,7 @@ import org.aesh.readline.tty.terminal.TerminalConnection; import org.aesh.terminal.Connection; -import io.quarkus.deployment.TestConfig; +import io.quarkus.deployment.dev.testing.TestConfig; import io.quarkus.dev.console.BasicConsole; import io.quarkus.dev.console.QuarkusConsole; diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java index c9be56b34004b..d7c5d4c3a3aa2 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/JunitTestRunner.java @@ -107,6 +107,7 @@ public class JunitTestRunner { private final Pattern exclude; private final boolean displayInConsole; private final boolean failingTestsOnly; + private final TestType testType; private volatile boolean testsRunning = false; private volatile boolean aborted; @@ -127,6 +128,7 @@ public JunitTestRunner(Builder builder) { this.exclude = builder.exclude; this.displayInConsole = builder.displayInConsole; this.failingTestsOnly = builder.failingTestsOnly; + this.testType = builder.testType; } public void runTests() { @@ -472,15 +474,16 @@ private DiscoveryResult discoverTestClasses(DevModeContext devModeContext) { unitTestClasses.add(name); } - List> qtClasses = new ArrayList<>(); + List> itClasses = new ArrayList<>(); + List> utClasses = new ArrayList<>(); for (String i : quarkusTestClasses) { try { - qtClasses.add(Thread.currentThread().getContextClassLoader().loadClass(i)); + itClasses.add(Thread.currentThread().getContextClassLoader().loadClass(i)); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } - qtClasses.sort(Comparator.comparing(new Function, String>() { + itClasses.sort(Comparator.comparing(new Function, String>() { @Override public String apply(Class aClass) { ClassInfo def = index.getClassByName(DotName.createSimple(aClass.getName())); @@ -516,14 +519,26 @@ public String apply(Class aClass) { cl = testApplication.createRuntimeClassLoader(Collections.emptyMap(), transformedClasses); for (String i : unitTestClasses) { try { - qtClasses.add(cl.loadClass(i)); + utClasses.add(cl.loadClass(i)); } catch (ClassNotFoundException exception) { throw new RuntimeException(exception); } } } - return new DiscoveryResult(cl, qtClasses); + if (testType == TestType.ALL) { + //run unit style tests first + //before the quarkus tests have started + //which stops quarkus interfering with WireMock + List> ret = new ArrayList<>(utClasses.size() + itClasses.size()); + ret.addAll(utClasses); + ret.addAll(itClasses); + return new DiscoveryResult(cl, ret); + } else if (testType == TestType.UNIT) { + return new DiscoveryResult(cl, utClasses); + } else { + return new DiscoveryResult(cl, itClasses); + } } private static Set collectTestAnnotations(Index index) { @@ -602,6 +617,7 @@ public boolean test(String logRecord) { } static class Builder { + private TestType testType = TestType.ALL; private TestState testState; private long runId = -1; private DevModeContext devModeContext; @@ -622,6 +638,11 @@ public Builder setRunId(long runId) { return this; } + public Builder setTestType(TestType testType) { + this.testType = testType; + return this; + } + public Builder setDevModeContext(DevModeContext devModeContext) { this.devModeContext = devModeContext; return this; diff --git a/core/deployment/src/main/java/io/quarkus/deployment/TestConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java similarity index 92% rename from core/deployment/src/main/java/io/quarkus/deployment/TestConfig.java rename to core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java index 97e581e8ea62d..b9af4c361f98e 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/TestConfig.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestConfig.java @@ -1,4 +1,4 @@ -package io.quarkus.deployment; +package io.quarkus.deployment.dev.testing; import java.time.Duration; import java.util.List; @@ -134,6 +134,17 @@ public class TestConfig { @ConfigItem(defaultValue = "10m") Duration hangDetectionTimeout; + /** + * The type of test to run, this can be either: + * + * quarkus-test: Only runs {@code @QuarkusTest} annotated test classes + * unit: Only runs classes that are not annotated with {@code @QuarkusTest} + * all: Runs both, running the unit tests first + * + */ + @ConfigItem(defaultValue = "all") + TestType testType; + @ConfigGroup public static class Profile { @@ -157,6 +168,5 @@ public enum Mode { PAUSED, ENABLED, DISABLED - } } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunner.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunner.java index 4b47e741d0473..62edea579cf5e 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunner.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunner.java @@ -25,6 +25,7 @@ import io.quarkus.bootstrap.app.CuratedApplication; import io.quarkus.deployment.dev.ClassScanResult; import io.quarkus.deployment.dev.DevModeContext; +import io.quarkus.runtime.configuration.HyphenateEnumConverter; public class TestRunner { @@ -55,6 +56,7 @@ public class TestRunner { String appPropertiesExcludeTags; String appPropertiesIncludePattern; String appPropertiesExcludePattern; + String appPropertiesTestType; public TestRunner(TestSupport testSupport, DevModeContext devModeContext, CuratedApplication testApplication) { this.testSupport = testSupport; @@ -85,9 +87,6 @@ private void runTests(ClassScanResult classScanResult, boolean reRunFailures) { if (compileProblem != null) { return; } - if (testApplication == null) { - return; - } if (disabled) { return; } @@ -207,6 +206,7 @@ private void runInternal(ClassScanResult classScanResult, boolean reRunFailures) .setExcludeTags(testSupport.excludeTags) .setInclude(testSupport.include) .setExclude(testSupport.exclude) + .setTestType(testSupport.testType) .setFailingTestsOnly(testSupport.failingTestsOnly); if (reRunFailures) { Set ids = new HashSet<>(); @@ -277,6 +277,7 @@ private void handleApplicationPropertiesChange() { String excludeTags = p.getProperty("quarkus.test.exclude-tags"); String includePattern = p.getProperty("quarkus.test.include-pattern"); String excludePattern = p.getProperty("quarkus.test.exclude-pattern"); + String testType = p.getProperty("quarkus.test.test-type"); if (!firstRun) { if (!Objects.equals(includeTags, appPropertiesIncludeTags)) { if (includeTags == null) { @@ -308,11 +309,26 @@ private void handleApplicationPropertiesChange() { testSupport.exclude = Pattern.compile(excludePattern); } } + if (!Objects.equals(excludePattern, appPropertiesExcludePattern)) { + if (excludePattern == null) { + testSupport.exclude = null; + } else { + testSupport.exclude = Pattern.compile(excludePattern); + } + } + if (!Objects.equals(testType, appPropertiesTestType)) { + if (testType == null) { + testSupport.testType = TestType.ALL; + } else { + testSupport.testType = new HyphenateEnumConverter<>(TestType.class).convert(testType); + } + } } appPropertiesIncludeTags = includeTags; appPropertiesExcludeTags = excludeTags; appPropertiesIncludePattern = includePattern; appPropertiesExcludePattern = excludePattern; + appPropertiesTestType = testType; break; } } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSupport.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSupport.java index e2bfb2dd5a488..40f8ce2bcc3b3 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSupport.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestSupport.java @@ -39,6 +39,7 @@ public class TestSupport implements TestController { volatile boolean displayTestOutput; volatile Boolean explicitDisplayTestOutput; volatile boolean failingTestsOnly; + volatile TestType testType = TestType.ALL; public TestSupport(CuratedApplication curatedApplication, List compilationProviders, DevModeContext context) { @@ -142,7 +143,6 @@ public synchronized void stop() { } } if (testRunner != null) { - testRunner.disable(); } } @@ -216,6 +216,11 @@ public TestSupport setConfiguredDisplayTestOutput(boolean displayTestOutput) { return this; } + public TestSupport setTestType(TestType testType) { + this.testType = testType; + return this; + } + @Override public TestState currentState() { return testState; diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java index 75d68dfbd7e18..e6c39814292d4 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestTracingProcessor.java @@ -14,7 +14,6 @@ import io.quarkus.deployment.IsDevelopment; import io.quarkus.deployment.IsNormal; import io.quarkus.deployment.IsTest; -import io.quarkus.deployment.TestConfig; import io.quarkus.deployment.annotations.BuildProducer; import io.quarkus.deployment.annotations.BuildStep; import io.quarkus.deployment.annotations.Produce; @@ -82,11 +81,11 @@ ServiceStartBuildItem startTesting(TestConfig config, LiveReloadBuildItem liveRe testSupport.setPatterns(config.includePattern.orElse(null), config.excludePattern.orElse(null)); testSupport.setConfiguredDisplayTestOutput(config.displayTestOutput); + testSupport.setTestType(config.testType); if (!liveReloadBuildItem.isLiveReload()) { if (config.continuousTesting == TestConfig.Mode.ENABLED) { testSupport.start(); } else if (config.continuousTesting == TestConfig.Mode.PAUSED) { - testSupport.init(); testSupport.stop(); } } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestType.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestType.java new file mode 100644 index 0000000000000..174e1e6b0a822 --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestType.java @@ -0,0 +1,7 @@ +package io.quarkus.deployment.dev.testing; + +public enum TestType { + UNIT, + QUARKUS_TEST, + ALL +} diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/QuarkusTestTypeTestCase.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/QuarkusTestTypeTestCase.java new file mode 100644 index 0000000000000..b473a266fbcd9 --- /dev/null +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/QuarkusTestTypeTestCase.java @@ -0,0 +1,43 @@ +package io.quarkus.vertx.http.testrunner; + +import java.util.function.Supplier; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusDevModeTest; +import io.quarkus.vertx.http.deployment.devmode.tests.TestStatus; + +public class QuarkusTestTypeTestCase { + + @RegisterExtension + static QuarkusDevModeTest test = new QuarkusDevModeTest() + .setArchiveProducer(new Supplier() { + @Override + public JavaArchive get() { + return ShrinkWrap.create(JavaArchive.class).addClass(HelloResource.class) + .add(new StringAsset(TestRunnerTestUtils.appProperties("quarkus.test.test-type=quarkus-test")), + "application.properties"); + } + }) + .setTestArchiveProducer(new Supplier() { + @Override + public JavaArchive get() { + return ShrinkWrap.create(JavaArchive.class).addClasses(SimpleET.class, UnitET.class); + } + }); + + @Test + public void testQuarkusTestMode() throws InterruptedException { + TestStatus ts = TestRunnerTestUtils.waitForFirstRunToComplete(); + Assertions.assertEquals(1L, ts.getLastRun()); + Assertions.assertEquals(1L, ts.getTestsFailed()); + Assertions.assertEquals(1L, ts.getTestsPassed()); + Assertions.assertEquals(0L, ts.getTestsSkipped()); + Assertions.assertEquals(-1L, ts.getRunning()); + } +} diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestRunnerTestUtils.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestRunnerTestUtils.java index 4a7a5774ba665..a16785bddbeb3 100644 --- a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestRunnerTestUtils.java +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/TestRunnerTestUtils.java @@ -40,7 +40,7 @@ public Boolean call() throws Exception { } public static String appProperties(String... props) { - return "quarkus.test.continuous-testing=enabled\nquarkus.test.console=false\nquarkus.test.display-test-output=true\n" + return "quarkus.test.continuous-testing=enabled\nquarkus.test.display-test-output=true\nquarkus.test.basic-console=true\n" + String.join("\n", Arrays.asList(props)); } } diff --git a/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/UnitTestTypeTestCase.java b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/UnitTestTypeTestCase.java new file mode 100644 index 0000000000000..1d49d0bf15da8 --- /dev/null +++ b/extensions/vertx-http/deployment/src/test/java/io/quarkus/vertx/http/testrunner/UnitTestTypeTestCase.java @@ -0,0 +1,44 @@ +package io.quarkus.vertx.http.testrunner; + +import java.util.function.Supplier; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.StringAsset; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusDevModeTest; +import io.quarkus.vertx.http.deployment.devmode.tests.TestStatus; + +public class UnitTestTypeTestCase { + + @RegisterExtension + static QuarkusDevModeTest test = new QuarkusDevModeTest() + .setArchiveProducer(new Supplier() { + @Override + public JavaArchive get() { + return ShrinkWrap.create(JavaArchive.class).addClass(HelloResource.class) + .add(new StringAsset(TestRunnerTestUtils.appProperties("quarkus.test.test-type=unit")), + "application.properties"); + } + }) + .setTestArchiveProducer(new Supplier() { + @Override + public JavaArchive get() { + return ShrinkWrap.create(JavaArchive.class).addClasses(SimpleET.class, UnitET.class); + } + }); + + @Test + public void testUnitMode() throws InterruptedException { + TestStatus ts = TestRunnerTestUtils.waitForFirstRunToComplete(); + Assertions.assertEquals(1L, ts.getLastRun()); + Assertions.assertEquals(1L, ts.getTestsFailed()); + Assertions.assertEquals(0L, ts.getTestsPassed()); + Assertions.assertEquals(0L, ts.getTestsSkipped()); + Assertions.assertEquals(-1L, ts.getRunning()); + + } +}