-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #30281 from holly-cummins/enable-quarkus-test-testing
- Loading branch information
Showing
6 changed files
with
264 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
73 changes: 73 additions & 0 deletions
73
integration-tests/maven/src/test/java/io/quarkus/maven/it/LaunchMojoTestBase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package io.quarkus.maven.it; | ||
|
||
import static org.awaitility.Awaitility.await; | ||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.fail; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.util.Collections; | ||
import java.util.UUID; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
import org.apache.maven.shared.invoker.MavenInvocationException; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import io.quarkus.maven.it.continuoustesting.ContinuousTestingMavenTestUtils; | ||
|
||
/** | ||
* Contains tests that we expect to pass with both quarkus:dev and quarkus:test | ||
*/ | ||
@DisableForNative | ||
public abstract class LaunchMojoTestBase extends RunAndCheckMojoTestBase { | ||
|
||
protected abstract ContinuousTestingMavenTestUtils getTestingTestUtils(); | ||
|
||
@Test | ||
public void testThatTheTestsAreReRunMultiModule() | ||
throws MavenInvocationException, IOException { | ||
//we also check continuous testing | ||
testDir = initProject("projects/multimodule", "projects/multimodule-with-deps"); | ||
runAndCheck(); | ||
|
||
ContinuousTestingMavenTestUtils testingTestUtils = getTestingTestUtils(); | ||
ContinuousTestingMavenTestUtils.TestStatus results = testingTestUtils.waitForNextCompletion(); | ||
|
||
//check that the tests in both modules run | ||
assertEquals(2, results.getTestsPassed()); | ||
|
||
// Edit the "Hello" message. | ||
File source = new File(testDir, "rest/src/main/java/org/acme/HelloResource.java"); | ||
final String uuid = UUID.randomUUID().toString(); | ||
filter(source, Collections.singletonMap("return \"hello\";", "return \"" + uuid + "\";")); | ||
|
||
// Wait until we get "uuid" | ||
// We can't poll, so just pause | ||
try { | ||
Thread.sleep(2 * 1000); | ||
} catch (InterruptedException e) { | ||
fail(e); | ||
} | ||
await() | ||
.pollDelay(100, TimeUnit.MILLISECONDS) | ||
.pollInterval(1, TimeUnit.SECONDS) | ||
.until(source::isFile); | ||
|
||
results = testingTestUtils.waitForNextCompletion(); | ||
|
||
//make sure the test is failing now | ||
assertEquals(1, results.getTestsFailed()); | ||
//now modify the passing test | ||
var testSource = new File(testDir, "rest/src/test/java/org/acme/test/SimpleTest.java"); | ||
filter(testSource, Collections.singletonMap("Assertions.assertTrue(true);", "Assertions.assertTrue(false);")); | ||
results = testingTestUtils.waitForNextCompletion(); | ||
assertEquals(2, results.getTotalTestsFailed()); | ||
//fix it again | ||
filter(testSource, Collections.singletonMap("Assertions.assertTrue(false);", "Assertions.assertTrue(true);")); | ||
results = testingTestUtils.waitForNextCompletion(); | ||
assertEquals(1, results.getTotalTestsFailed(), "Failed, actual results " + results); | ||
assertEquals(1, results.getTotalTestsPassed(), "Failed, actual results " + results); | ||
|
||
} | ||
|
||
} |
54 changes: 54 additions & 0 deletions
54
integration-tests/maven/src/test/java/io/quarkus/maven/it/TestMojoIT.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package io.quarkus.maven.it; | ||
|
||
import java.io.FileNotFoundException; | ||
|
||
import org.apache.maven.shared.invoker.MavenInvocationException; | ||
|
||
import io.quarkus.maven.it.continuoustesting.ContinuousTestingMavenTestUtils; | ||
import io.quarkus.maven.it.continuoustesting.TestModeContinuousTestingMavenTestUtils; | ||
import io.quarkus.runtime.LaunchMode; | ||
|
||
/** | ||
* Tests the quarkus:test mojo. Most of the behaviour of quarkus:test is expected to also work with quarkus:test, so tests are | ||
* in a superclass. | ||
* <p> | ||
* NOTE to anyone diagnosing failures in this test, to run a single method use: | ||
* <p> | ||
* mvn install -Dit.test=TestMojoIT#methodName | ||
*/ | ||
@DisableForNative | ||
public class TestMojoIT extends LaunchMojoTestBase { | ||
|
||
@Override | ||
protected LaunchMode getDefaultLaunchMode() { | ||
return LaunchMode.TEST; | ||
} | ||
|
||
@Override | ||
protected ContinuousTestingMavenTestUtils getTestingTestUtils() { | ||
return new TestModeContinuousTestingMavenTestUtils(running); | ||
} | ||
|
||
@Override | ||
public void shutdownTheApp() { | ||
if (running != null) { | ||
running.stop(); | ||
} | ||
|
||
// There's no http server, so there's nothing to check to make sure we're stopped, except by the maven invoker itself, or the logs | ||
} | ||
|
||
/** | ||
* This is actually more like runAndDoNotCheck, because | ||
* we can't really check anything via a HTTP get, because this is a test mode application | ||
*/ | ||
@Override | ||
protected void runAndCheck(boolean performCompile, LaunchMode mode, String... options) | ||
throws FileNotFoundException, MavenInvocationException { | ||
run(performCompile, mode, options); | ||
|
||
// We don't need to try and pause, because the continuous testing utils will wait for tests to finish | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
...n/java/io/quarkus/maven/it/continuoustesting/TestModeContinuousTestingMavenTestUtils.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package io.quarkus.maven.it.continuoustesting; | ||
|
||
import static org.awaitility.Awaitility.await; | ||
import static org.junit.jupiter.api.Assertions.fail; | ||
|
||
import java.io.IOException; | ||
import java.util.concurrent.TimeUnit; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
import io.quarkus.maven.it.verifier.RunningInvoker; | ||
|
||
/** | ||
* Utilities for testing behaviour with `mvn quarkus:test`. This is harder than dev mode, since | ||
* we don't have an http endpoint to query for test status, but we can do our best effort. | ||
*/ | ||
public class TestModeContinuousTestingMavenTestUtils extends ContinuousTestingMavenTestUtils { | ||
// Example output we look for | ||
// 1 test failed (1 passing, 0 skipped), 1 test was run in 217ms. Tests completed at 21:22:34 due to changes to HelloResource$Blah.class and 1 other files. | ||
// All 2 tests are passing (0 skipped), 2 tests were run in 1413ms. Tests completed at 21:22:33. | ||
private static final Pattern ALL_PASSING = Pattern.compile("All (\\d\\d*) tests are passing \\((\\d\\d*) skipped\\)", | ||
Pattern.MULTILINE); | ||
private static final Pattern SOME_PASSING = Pattern | ||
.compile("(\\d\\d*) tests? failed \\((\\d\\d*) passing, (\\d\\d*) skipped\\)", Pattern.MULTILINE); | ||
private static final String TESTS_COMPLETED = "Tests completed at"; | ||
private final RunningInvoker running; | ||
private int startPosition = 0; | ||
|
||
public TestModeContinuousTestingMavenTestUtils(RunningInvoker running) { | ||
this.running = running; | ||
} | ||
|
||
@Override | ||
public TestStatus waitForNextCompletion() { | ||
|
||
// We have to scrape test status, because in test mode we do not have an API | ||
await() | ||
.pollDelay(1, TimeUnit.SECONDS) | ||
.atMost(3, TimeUnit.MINUTES).until(() -> getLogSinceLastRun().contains(TESTS_COMPLETED)); | ||
TestStatus testStatus = new TestStatus(); | ||
try { | ||
String log = getLogSinceLastRun(); | ||
|
||
Matcher matcher = ALL_PASSING.matcher(log); | ||
int failCount; | ||
int passCount; | ||
int skipCount; | ||
if (matcher.find()) { | ||
passCount = Integer.parseInt(matcher.group(1)); | ||
skipCount = Integer.parseInt(matcher.group(2)); | ||
failCount = 0; | ||
} else { | ||
matcher = SOME_PASSING.matcher(log); | ||
if (!matcher.find()) { | ||
fail("Tests were run, but the log is not parseable with the patterns we know. This is the log\n: " + log); | ||
} | ||
failCount = Integer.parseInt(matcher.group(1)); | ||
passCount = Integer.parseInt(matcher.group(2)); | ||
skipCount = Integer.parseInt(matcher.group(3)); | ||
} | ||
testStatus.setTestsFailed(failCount); | ||
testStatus.setTestsPassed(passCount); | ||
testStatus.setTestsSkipped(skipCount); | ||
|
||
// Note: slight fudging of total counts! | ||
// io.quarkus.test.ContinuousTestingTestUtils treats the total counts the same as the current counts, | ||
// so we will do the same. | ||
// it's not ideal, so if it causes problems we may want to invest in more elaborate parsing | ||
testStatus.setTotalTestsFailed(failCount); | ||
testStatus.setTotalTestsPassed(passCount); | ||
testStatus.setTotalTestsSkipped(skipCount); | ||
|
||
setHighWaterMark(); | ||
} catch (IOException e) { | ||
fail(e); | ||
} | ||
return testStatus; | ||
|
||
} | ||
|
||
private void setHighWaterMark() throws IOException { | ||
// We only want to check the logs in the section which was updated after the last completion, | ||
// so make a note of what the position was | ||
startPosition = startPosition + getLogSinceLastRun().indexOf(TESTS_COMPLETED) + TESTS_COMPLETED.length(); | ||
} | ||
|
||
private String getLogSinceLastRun() throws IOException { | ||
String log = running.log(); | ||
return log.substring(startPosition); | ||
|
||
} | ||
} |