From da46d00678b700a9db7548104feb24873c81efb6 Mon Sep 17 00:00:00 2001 From: Stuart Douglas Date: Tue, 13 Apr 2021 11:33:33 +1000 Subject: [PATCH] Refactor --- .../io/quarkus/deployment/TestConfig.java | 8 + .../deployment/dev/IsolatedDevModeMain.java | 1 + .../dev/RuntimeUpdatesProcessor.java | 10 +- .../dev/testing/TestController.java | 11 ++ .../deployment/dev/testing/TestListener.java | 21 +++ .../dev/testing/TestRunListener.java | 26 +++ .../deployment/dev/testing/TestSupport.java | 39 ++-- .../dev/testing/runner/JunitTestRunner.java | 48 +++-- .../testing/runner/TestConsoleHandler.java | 175 ++++++++++++++++++ .../dev/testing/runner/TestRunner.java | 131 +------------ .../testing/runner/TestTracingProcessor.java | 12 +- 11 files changed, 316 insertions(+), 166 deletions(-) create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestController.java create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestListener.java create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunListener.java create mode 100644 core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/TestConsoleHandler.java diff --git a/core/deployment/src/main/java/io/quarkus/deployment/TestConfig.java b/core/deployment/src/main/java/io/quarkus/deployment/TestConfig.java index 3a3406eb318705..f648b8b3c123c9 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/TestConfig.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/TestConfig.java @@ -75,6 +75,14 @@ public class TestConfig { @ConfigItem(defaultValue = "false") public boolean disableColor; + /** + * If test results and status should be displayed in the console. + * + * If this is false results can still be viewed in the dev console. + */ + @ConfigItem(defaultValue = "true") + public boolean console; + /** * Duration to wait for the native image to built during testing */ diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedDevModeMain.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedDevModeMain.java index 87a7fac75c51a9..7a58176da004f7 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedDevModeMain.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/IsolatedDevModeMain.java @@ -237,6 +237,7 @@ private RuntimeUpdatesProcessor setupRuntimeCompilation(DevModeContext context, } QuarkusCompiler compiler = new QuarkusCompiler(curatedApplication, compilationProviders, context); TestSupport testSupport = new TestSupport(curatedApplication, compilationProviders, context); + RuntimeUpdatesProcessor processor = new RuntimeUpdatesProcessor(appRoot, context, compiler, devModeType, this::restartCallback, null, new BiFunction() { @Override diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java index 5d6e7d5dd45db5..8b1ddda9172090 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/RuntimeUpdatesProcessor.java @@ -52,6 +52,7 @@ import io.quarkus.bootstrap.runner.Timing; import io.quarkus.changeagent.ClassChangeAgent; +import io.quarkus.deployment.dev.testing.TestListener; import io.quarkus.deployment.dev.testing.TestSupport; import io.quarkus.deployment.dev.testing.runner.TestRunner; import io.quarkus.deployment.util.FSWatchUtil; @@ -125,19 +126,18 @@ public RuntimeUpdatesProcessor(Path applicationRoot, DevModeContext context, Qua this.copyResourceNotification = copyResourceNotification; this.classTransformers = classTransformers; this.testSupport = testSupport; - testSupport.addStartListener(new Runnable() { + testSupport.addListener(new TestListener() { @Override - public void run() { + public void testsEnabled() { if (!firstTestScanComplete) { checkForChangedTestClasses(true); firstTestScanComplete = true; } startTestScanningTimer(); } - }); - testSupport.addStopListener(new Runnable() { + @Override - public void run() { + public void testsDisabled() { synchronized (RuntimeUpdatesProcessor.this) { if (timer != null) { timer.cancel(); diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestController.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestController.java new file mode 100644 index 00000000000000..6815c6b3ae7cdf --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestController.java @@ -0,0 +1,11 @@ +package io.quarkus.deployment.dev.testing; + +import io.quarkus.deployment.dev.testing.runner.TestState; + +public interface TestController { + + TestState currentState(); + + void runAllTests(); + +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestListener.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestListener.java new file mode 100644 index 00000000000000..a4bc1c3d68d31d --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestListener.java @@ -0,0 +1,21 @@ +package io.quarkus.deployment.dev.testing; + +import java.util.function.Consumer; + +public interface TestListener { + + default void listenerRegistered(TestController testController) { + + } + + default void testsEnabled() { + } + + default void testsDisabled() { + + } + + default void testRunStarted(Consumer listenerConsumer) { + + } +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunListener.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunListener.java new file mode 100644 index 00000000000000..0d8f959de484d4 --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/TestRunListener.java @@ -0,0 +1,26 @@ +package io.quarkus.deployment.dev.testing; + +import org.junit.platform.launcher.TestIdentifier; + +public interface TestRunListener { + + default void runStarted(long toRun) { + + } + + default void testComplete(TestResult result) { + + } + + default void runComplete(TestRunResults results) { + + } + + default void runAborted() { + + } + + default void testStarted(TestIdentifier testIdentifier, String className) { + + } +} 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 6d04eea5478ee9..2728108b2fdce8 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 @@ -19,15 +19,14 @@ import io.quarkus.deployment.dev.testing.runner.TestState; import io.quarkus.dev.testing.ContinuousTestingWebsocketListener; -public class TestSupport { +public class TestSupport implements TestController { private static final Logger log = Logger.getLogger(TestSupport.class); final CuratedApplication curatedApplication; final List compilationProviders; final DevModeContext context; - final List startListeners = new ArrayList<>(); - final List stopListeners = new ArrayList<>(); + final List testListeners = new ArrayList<>(); final TestState testState = new TestState(); volatile CuratedApplication testCuratedApplication; @@ -55,6 +54,10 @@ public boolean isRunning() { return testRunner.isRunning(); } + public List getTestListeners() { + return testListeners; + } + /** * Gets the results for an already completed test run, whoes ID is equal to or larger than the provided id. */ @@ -129,8 +132,8 @@ public void start() { if (context.getApplicationRoot().getTest().isPresent()) { started = true; init(); - for (Runnable i : startListeners) { - i.run(); + for (TestListener i : testListeners) { + i.testsEnabled(); } testRunner.enable(); } @@ -191,8 +194,8 @@ public void accept(TestRunResults testRunResults) { public synchronized void stop() { if (started) { started = false; - for (Runnable i : stopListeners) { - i.run(); + for (TestListener i : testListeners) { + i.testsDisabled(); } } if (testRunner != null) { @@ -201,24 +204,21 @@ public synchronized void stop() { } } - public void addStartListener(Runnable runnable) { + public void addListener(TestListener listener) { boolean run = false; synchronized (this) { - startListeners.add(runnable); + testListeners.add(listener); if (started) { run = true; } } + listener.listenerRegistered(this); if (run) { //run outside lock - runnable.run(); + listener.testsEnabled(); } } - public synchronized void addStopListener(Runnable runnable) { - stopListeners.add(runnable); - } - public boolean isStarted() { return started; } @@ -269,6 +269,16 @@ public void setPatterns(String include, String exclude) { testRunner.setPatterns(include, exclude); } + @Override + public TestState currentState() { + return getTestRunner().getResults(); + } + + @Override + public void runAllTests() { + getTestRunner().runTests(); + } + public static class RunStatus { final long lastRun; @@ -287,4 +297,5 @@ public long getRunning() { return running; } } + } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/JunitTestRunner.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/JunitTestRunner.java index ecfef3b7aa5319..e60185c5c14317 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/JunitTestRunner.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/JunitTestRunner.java @@ -65,6 +65,7 @@ import io.quarkus.deployment.dev.DevModeContext; import io.quarkus.deployment.dev.testing.TestClassResult; import io.quarkus.deployment.dev.testing.TestResult; +import io.quarkus.deployment.dev.testing.TestRunListener; import io.quarkus.deployment.dev.testing.TestRunResults; import io.quarkus.dev.testing.ContinuousTestingLogHandler; import io.quarkus.dev.testing.TracingHandler; @@ -81,7 +82,7 @@ public class JunitTestRunner { private final ClassScanResult classScanResult; private final TestClassUsages testClassUsages; private final TestState testState; - private final TestListener listener; + private final List listeners; private final Set includeTags; private final Set excludeTags; private final Pattern include; @@ -97,7 +98,7 @@ public JunitTestRunner(Builder builder) { this.testApplication = builder.testApplication; this.classScanResult = builder.classScanResult; this.testClassUsages = builder.testClassUsages; - this.listener = builder.listener; + this.listeners = builder.listeners; this.testState = builder.testState; this.includeTags = new HashSet<>(builder.includeTags); this.excludeTags = new HashSet<>(builder.excludeTags); @@ -140,7 +141,9 @@ public void runTests() { return; } long toRun = testPlan.countTestIdentifiers(TestIdentifier::isTest); - listener.runStarted(toRun); + for (TestRunListener listener : listeners) { + listener.runStarted(toRun); + } log.debug("Starting test run with " + quarkusTestClasses.size() + " test cases"); TestLogCapturingHandler logHandler = new TestLogCapturingHandler(); ContinuousTestingLogHandler.setLogHandler(logHandler); @@ -176,7 +179,9 @@ public void executionStarted(TestIdentifier testIdentifier) { className = ((ClassSource) testIdentifier.getSource().get()).getClassName(); } } - listener.testStarted(testIdentifier, className); + for (TestRunListener listener : listeners) { + listener.testStarted(testIdentifier, className); + } waitTillResumed(); touchedClasses.push(Collections.synchronizedSet(new HashSet<>())); } @@ -232,7 +237,9 @@ public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult logHandler.captureOutput(), testIdentifier.isTest(), runId); results.put(id, result); if (result.isTest()) { - listener.testComplete(result); + for (TestRunListener listener : listeners) { + listener.testComplete(result); + } } } if (testExecutionResult.getStatus() == TestExecutionResult.Status.FAILED) { @@ -281,8 +288,11 @@ public void reportingEntryPublished(TestIdentifier testIdentifier, ReportEntry e ContinuousTestingLogHandler.setLogHandler(null); List historicFailures = testState.getHistoricFailures(resultsByClass); - listener.runComplete(new TestRunResults(runId, classScanResult, classScanResult == null, start, - System.currentTimeMillis(), toResultsMap(historicFailures, resultsByClass))); + + for (TestRunListener listener : listeners) { + listener.runComplete(new TestRunResults(runId, classScanResult, classScanResult == null, start, + System.currentTimeMillis(), toResultsMap(historicFailures, resultsByClass))); + } } catch (Exception e) { throw new RuntimeException(e); } finally { @@ -292,7 +302,9 @@ public void reportingEntryPublished(TestIdentifier testIdentifier, ReportEntry e } public synchronized void abort() { - listener.runAborted(); + for (TestRunListener listener : listeners) { + listener.runAborted(); + } aborted = true; notifyAll(); } @@ -422,19 +434,6 @@ public boolean isRunning() { return testsRunning; } - public interface TestListener { - - void runStarted(long toRun); - - void testComplete(TestResult result); - - void runComplete(TestRunResults results); - - void runAborted(); - - void testStarted(TestIdentifier testIdentifier, String className); - } - private class TestLogCapturingHandler implements Predicate { private final List logOutput; @@ -489,7 +488,7 @@ static class Builder { private CuratedApplication testApplication; private ClassScanResult classScanResult; private TestClassUsages testClassUsages; - private TestListener listener; + private List listeners = new ArrayList<>(); private List includeTags = Collections.emptyList(); private List excludeTags = Collections.emptyList(); private Pattern include; @@ -530,8 +529,8 @@ public Builder setTestClassUsages(TestClassUsages testClassUsages) { return this; } - public Builder setListener(TestListener listener) { - this.listener = listener; + public Builder addListener(TestRunListener listener) { + this.listeners.add(listener); return this; } @@ -555,7 +554,6 @@ public JunitTestRunner build() { Objects.requireNonNull(testClassUsages, "testClassUsages"); Objects.requireNonNull(testApplication, "testApplication"); Objects.requireNonNull(testState, "testState"); - Objects.requireNonNull(listener, "listener"); return new JunitTestRunner(this); } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/TestConsoleHandler.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/TestConsoleHandler.java new file mode 100644 index 00000000000000..8f3114959a54d6 --- /dev/null +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/TestConsoleHandler.java @@ -0,0 +1,175 @@ +package io.quarkus.deployment.dev.testing.runner; + +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; + +import org.jboss.logging.Logger; +import org.junit.platform.engine.TestExecutionResult; +import org.junit.platform.launcher.TestIdentifier; + +import io.quarkus.deployment.dev.console.InputHandler; +import io.quarkus.deployment.dev.console.QuarkusConsole; +import io.quarkus.deployment.dev.testing.TestClassResult; +import io.quarkus.deployment.dev.testing.TestController; +import io.quarkus.deployment.dev.testing.TestListener; +import io.quarkus.deployment.dev.testing.TestResult; +import io.quarkus.deployment.dev.testing.TestRunListener; +import io.quarkus.deployment.dev.testing.TestRunResults; +import io.quarkus.deployment.dev.testing.TestSupport; + +public class TestConsoleHandler implements TestListener { + + private static final Logger log = Logger.getLogger("io.quarkus.test"); + + public static final String DISABLED_PROMPT = "\u001b[33mTests Disabled, press [e] to enable\u001b[0m"; + public static final String FIRST_RUN_PROMPT = "\u001b[33mRunning Tests for the first time\u001b[0m"; + public static final String RUNNING_PROMPT = "Press [r] to re-run, [v] to view full results, [d] to disable, [?] for more options>"; + + boolean firstRun = true; + boolean disabled = true; + volatile InputHandler.ConsoleStatus promptHandler; + volatile TestController testController; + private String lastStatus; + + public void install() { + QuarkusConsole.INSTANCE.pushInputHandler(inputHandler); + } + + private final InputHandler inputHandler = new InputHandler() { + + @Override + public void handleInput(int[] keys) { + if (disabled) { + for (int i : keys) { + if (i == 'e') { + TestSupport.instance().start(); + } + } + } else if (!firstRun) { + for (int k : keys) { + if (k == 'r') { + testController.runAllTests(); + } else if (k == 'v') { + printFullResults(); + } else if (k == 'd') { + TestSupport.instance().stop(); + } + } + } + } + + @Override + public void promptHandler(InputHandler.ConsoleStatus promptHandler) { + TestConsoleHandler.this.promptHandler = promptHandler; + } + }; + + @Override + public void listenerRegistered(TestController testController) { + this.testController = testController; + promptHandler.setStatus(DISABLED_PROMPT); + } + + private void printFullResults() { + for (TestClassResult i : testController.currentState().getFailingClasses()) { + for (TestResult failed : i.getFailing()) { + log.error( + "Test " + failed.getDisplayName() + " failed " + + failed.getTestExecutionResult().getStatus() + + "\n", + failed.getTestExecutionResult().getThrowable().get()); + } + } + + } + + @Override + public void testsEnabled() { + disabled = false; + if (firstRun) { + promptHandler.setStatus(null); + promptHandler.setPrompt(FIRST_RUN_PROMPT); + } else { + promptHandler.setPrompt(RUNNING_PROMPT); + promptHandler.setStatus(lastStatus); + } + } + + @Override + public void testsDisabled() { + disabled = true; + promptHandler.setPrompt(DISABLED_PROMPT); + promptHandler.setStatus(null); + } + + @Override + public void testRunStarted(Consumer listenerConsumer) { + + AtomicLong totalNoTests = new AtomicLong(); + AtomicLong skipped = new AtomicLong(); + AtomicLong methodCount = new AtomicLong(); + AtomicLong failureCount = new AtomicLong(); + listenerConsumer.accept(new TestRunListener() { + @Override + public void runStarted(long toRun) { + totalNoTests.set(toRun); + promptHandler.setStatus("Running 0/" + toRun + "."); + } + + @Override + public void testComplete(TestResult result) { + + if (result.getTestExecutionResult().getStatus() == TestExecutionResult.Status.FAILED) { + failureCount.incrementAndGet(); + } else if (result.getTestExecutionResult().getStatus() == TestExecutionResult.Status.ABORTED) { + skipped.incrementAndGet(); + } + methodCount.incrementAndGet(); + } + + @Override + public void runComplete(TestRunResults results) { + if (results.getCurrentFailing().isEmpty()) { + lastStatus = "\u001B[32mTests all passed, " + methodCount.get() + " tests were run, " + skipped.get() + + " were skipped. Tests took " + (results.getTotalTime()) + + "ms." + "\u001b[0m"; + } else { + StringBuilder sb = new StringBuilder( + "\u001B[91mTest run failed, " + methodCount.get() + " tests were run, " + + results.getCurrentFailing().size() + + " failed, " + + skipped.get() + + " were skipped. Tests took " + results.getTotalTime() + "ms"); + for (Map.Entry classEntry : results.getCurrentFailing().entrySet()) { + for (TestResult test : classEntry.getValue().getFailing()) { + log.error( + "Test " + test.getDisplayName() + " failed \n", + test.getTestExecutionResult().getThrowable().get()); + } + } + lastStatus = sb.toString() + "\u001b[0m"; + } + //this will re-print when using the basic console + promptHandler.setPrompt(RUNNING_PROMPT); + promptHandler.setStatus(lastStatus); + } + + @Override + public void runAborted() { + promptHandler.setStatus("Test run aborted."); + } + + @Override + public void testStarted(TestIdentifier testIdentifier, String className) { + promptHandler.setStatus("Running " + methodCount.get() + "/" + totalNoTests + + (failureCount.get() == 0 ? "." + : ". " + failureCount + " failures so far.") + + " Running: " + + className + "#" + testIdentifier.getDisplayName()); + } + }); + + } + +} diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/TestRunner.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/TestRunner.java index 8c640e2cbbe5ee..7f8ec9360573e5 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/TestRunner.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/TestRunner.java @@ -2,24 +2,19 @@ import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.regex.Pattern; import org.jboss.logging.Logger; -import org.junit.platform.engine.TestExecutionResult; -import org.junit.platform.launcher.TestIdentifier; import org.opentest4j.TestAbortedException; import io.quarkus.bootstrap.app.CuratedApplication; import io.quarkus.deployment.dev.ClassScanResult; import io.quarkus.deployment.dev.DevModeContext; -import io.quarkus.deployment.dev.console.InputHandler; -import io.quarkus.deployment.dev.console.QuarkusConsole; -import io.quarkus.deployment.dev.testing.TestClassResult; -import io.quarkus.deployment.dev.testing.TestResult; +import io.quarkus.deployment.dev.testing.TestListener; +import io.quarkus.deployment.dev.testing.TestRunListener; import io.quarkus.deployment.dev.testing.TestRunResults; import io.quarkus.deployment.dev.testing.TestSupport; import io.quarkus.dev.testing.ContinuousTestingWebsocketListener; @@ -28,9 +23,6 @@ public class TestRunner { private static final Logger log = Logger.getLogger(TestRunner.class); private static final AtomicLong COUNTER = new AtomicLong(); - public static final String DISABLED_PROMPT = "\u001b[33mTests Disabled, press [e] to enable\u001b[0m"; - public static final String FIRST_RUN_PROMPT = "\u001b[33mRunning Tests for the first time\u001b[0m"; - public static final String RUNNING_PROMPT = "Press [r] to re-run, [v] to view full results, [d] to disable, [?] for more options>"; private final DevModeContext devModeContext; private final CuratedApplication testApplication; @@ -54,38 +46,7 @@ public class TestRunner { volatile List excludeTags = Collections.emptyList(); volatile Pattern include = null; volatile Pattern exclude = null; - volatile InputHandler.ConsoleStatus promptHandler; private JunitTestRunner runner; - private String lastStatus; - - private final InputHandler inputHandler = new InputHandler() { - - @Override - public void handleInput(int[] keys) { - if (disabled) { - for (int i : keys) { - if (i == 'e') { - TestSupport.instance().start(); - } - } - } else if (!firstRun) { - for (int k : keys) { - if (k == 'r') { - runTests(); - } else if (k == 'v') { - printFullResults(); - } else if (k == 'd') { - TestSupport.instance().stop(); - } - } - } - } - - @Override - public void promptHandler(InputHandler.ConsoleStatus promptHandler) { - TestRunner.this.promptHandler = promptHandler; - } - }; public TestRunner(DevModeContext devModeContext, CuratedApplication testApplication, Consumer resultHandler, TestState testState) { @@ -93,7 +54,6 @@ public TestRunner(DevModeContext devModeContext, CuratedApplication testApplicat this.testApplication = testApplication; this.resultHandler = resultHandler; this.testState = testState; - QuarkusConsole.INSTANCE.pushInputHandler(inputHandler); } public void runTests() { @@ -182,8 +142,6 @@ public synchronized void resume() { } public synchronized void disable() { - promptHandler.setPrompt(DISABLED_PROMPT); - promptHandler.setStatus(null); ContinuousTestingWebsocketListener.setRunning(false); disabled = true; notifyAll(); @@ -198,23 +156,14 @@ public synchronized void enable() { } disabled = false; if (firstRun) { - promptHandler.setStatus(null); - promptHandler.setPrompt(FIRST_RUN_PROMPT); ContinuousTestingWebsocketListener.setRunning(true); runTests(); - } else { - promptHandler.setPrompt(RUNNING_PROMPT); - promptHandler.setStatus(lastStatus); } } private void runInternal(ClassScanResult classScanResult) { final long runId = COUNTER.incrementAndGet(); - AtomicLong totalNoTests = new AtomicLong(); - AtomicLong skipped = new AtomicLong(); - AtomicLong methodCount = new AtomicLong(); - AtomicLong failureCount = new AtomicLong(); AtomicReference resultsRef = new AtomicReference<>(); synchronized (this) { if (runner != null) { @@ -223,7 +172,7 @@ private void runInternal(ClassScanResult classScanResult) { if (disabled) { return; } - runner = new JunitTestRunner.Builder() + JunitTestRunner.Builder builder = new JunitTestRunner.Builder() .setClassScanResult(classScanResult) .setDevModeContext(devModeContext) .setRunId(runId) @@ -234,41 +183,17 @@ private void runInternal(ClassScanResult classScanResult) { .setExcludeTags(excludeTags) .setInclude(include) .setExclude(exclude) - .setListener(new JunitTestRunner.TestListener() { - @Override - public void runStarted(long toRun) { - totalNoTests.set(toRun); - promptHandler.setStatus("Running 0/" + toRun + "."); - } - - @Override - public void testComplete(TestResult result) { - if (result.getTestExecutionResult().getStatus() == TestExecutionResult.Status.FAILED) { - failureCount.incrementAndGet(); - } else if (result.getTestExecutionResult().getStatus() == TestExecutionResult.Status.ABORTED) { - skipped.incrementAndGet(); - } - methodCount.incrementAndGet(); - } - + .addListener(new TestRunListener() { @Override public void runComplete(TestRunResults results) { - resultsRef.set(results); - } - - @Override - public void runAborted() { + resultHandler.accept(results); } - @Override - public void testStarted(TestIdentifier testIdentifier, String className) { - promptHandler.setStatus("Running " + methodCount.get() + "/" + totalNoTests - + (failureCount.get() == 0 ? "." - : ". " + failureCount + " failures so far.") - + " Running: " - + className + "#" + testIdentifier.getDisplayName()); - } - }) + }); + for (TestListener i : TestSupport.instance().getTestListeners()) { + i.testRunStarted(builder::addListener); + } + runner = builder .build(); if (paused) { runner.pause(); @@ -282,48 +207,12 @@ public void testStarted(TestIdentifier testIdentifier, String className) { if (disabled || results == null) { return; } - resultHandler.accept(results); - if (results.getCurrentFailing().isEmpty()) { - lastStatus = "\u001B[32mTests all passed, " + methodCount.get() + " tests were run, " + skipped.get() - + " were skipped. Tests took " + (results.getTotalTime()) - + "ms." + "\u001b[0m"; - } else { - StringBuilder sb = new StringBuilder( - "\u001B[91mTest run failed, " + methodCount.get() + " tests were run, " + results.getCurrentFailing().size() - + " failed, " - + skipped.get() - + " were skipped. Tests took " + results.getTotalTime() + "ms"); - for (Map.Entry classEntry : results.getCurrentFailing().entrySet()) { - for (TestResult test : classEntry.getValue().getFailing()) { - log.error( - "Test " + test.getDisplayName() + " failed \n", - test.getTestExecutionResult().getThrowable().get()); - } - } - lastStatus = sb.toString() + "\u001b[0m"; - } - //this will re-print when using the basic console - promptHandler.setPrompt(RUNNING_PROMPT); - promptHandler.setStatus(lastStatus); if (firstRun) { firstRun = false; } } - private void printFullResults() { - for (TestClassResult i : testState.getFailingClasses()) { - for (TestResult failed : i.getFailing()) { - log.error( - "Test " + failed.getDisplayName() + " failed " - + failed.getTestExecutionResult().getStatus() - + "\n", - failed.getTestExecutionResult().getThrowable().get()); - } - } - - } - public void waitTillResumed() { synchronized (TestRunner.this) { while (paused && !disabled) { diff --git a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/TestTracingProcessor.java b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/TestTracingProcessor.java index fca405c4387a1f..79730a16cf0e30 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/TestTracingProcessor.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/dev/testing/runner/TestTracingProcessor.java @@ -25,6 +25,7 @@ import io.quarkus.deployment.builditem.ServiceStartBuildItem; import io.quarkus.deployment.dev.RuntimeUpdatesProcessor; import io.quarkus.deployment.dev.console.QuarkusConsole; +import io.quarkus.deployment.dev.testing.TestSupport; import io.quarkus.deployment.logging.LogCleanupFilterBuildItem; import io.quarkus.dev.testing.TracingHandler; @@ -36,6 +37,7 @@ public class TestTracingProcessor { private static TestConfig.Mode lastEnabledValue; + private static boolean consoleInstalled = false; @BuildStep(onlyIfNot = IsNormal.class) LogCleanupFilterBuildItem handle() { @@ -47,7 +49,15 @@ ServiceStartBuildItem setupConsole(TestConfig config) { if (RuntimeUpdatesProcessor.INSTANCE == null || config.continuousTesting == TestConfig.Mode.DISABLED) { return null; } - QuarkusConsole.installConsole(config); + if (consoleInstalled) { + return null; + } + if (config.console) { + QuarkusConsole.installConsole(config); + TestConsoleHandler consoleHandler = new TestConsoleHandler(); + consoleHandler.install(); + TestSupport.instance().addListener(consoleHandler); + } return null; }