You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ol...@apache.org on 2026/09/06 11:58:43 UTC

(maven-surefire) branch master updated: Fix inverted filter predicate in ForkStarter#readTestClassNames (#3453)

This is an automated email from the ASF dual-hosted git repository.

olamy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-surefire.git


The following commit(s) were added to refs/heads/master by this push:
     new 0b4656cee Fix inverted filter predicate in ForkStarter#readTestClassNames (#3453)
0b4656cee is described below

commit 0b4656cee86a39dd577f24b59665f056803c6f81
Author: Sylwester Lachiewicz <sl...@apache.org>
AuthorDate: Sun Sep 6 13:58:38 2026 +0200

    Fix inverted filter predicate in ForkStarter#readTestClassNames (#3453)
    
    * Fix inverted filter predicate in ForkStarter#readTestClassNames
    
    ForkStarter#readTestClassNames used String::isEmpty instead of !isEmpty(),
    causing discovered test classes to be filtered out instead of retained
    when running multi-fork or toolchain configurations.
    
    * Configure GHA to reproduce #3453
    
    Signed-off-by: Olivier Lamy <ol...@apache.org>
    
    ---------
    
    Signed-off-by: Olivier Lamy <ol...@apache.org>
    Co-authored-by: Olivier Lamy <ol...@apache.org>
---
 .github/workflows/maven-verify.yml                       | 12 +++++++++++-
 .../maven/plugin/surefire/booterclient/ForkStarter.java  |  9 +++++++--
 .../plugin/surefire/booterclient/ForkStarterTest.java    | 16 ++++++++++++++++
 3 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/maven-verify.yml b/.github/workflows/maven-verify.yml
index 991e799a8..4c33a5281 100644
--- a/.github/workflows/maven-verify.yml
+++ b/.github/workflows/maven-verify.yml
@@ -30,7 +30,17 @@ jobs:
       ff-jdk: '21'
       ff-goal: 'clean install site site:stage -P reporting -nsu'
       ff-site-goal: '-v'
-      verify-goal: 'clean install -nsu -P run-its'
+      # setup-java installs these and exports JAVA_HOME_<version>_<arch> for each one.
+      # 25 is newer than anything in jdk-matrix, so it can act as the toolchain JDK.
+      jdk-toolchain: |
+        11
+        17
+        21
+        25
+      # Gives Surefire2151ToolchainForkDiscoveryIT a toolchain JDK that really differs from
+      # the JVM running Maven. Without it the test never gets to the fork it is about.
+      # Only the x64 bash runners expand this; elsewhere it is empty and the test skips.
+      verify-goal: 'clean install -nsu -P run-its "-Dsurefire.test.toolchain.jdkHome=$JAVA_HOME_25_X64"'
       verify-fail-fast: false
       # Investigation reasons: Some tests generate custom files, standard reports and logs.
       # Remove the line with `*-jvmRun*-events.bin` pattern if large streams should be investigated.
diff --git a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
index 5d0fe344d..cd97c7673 100644
--- a/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
+++ b/maven-surefire-common/src/main/java/org/apache/maven/plugin/surefire/booterclient/ForkStarter.java
@@ -849,7 +849,12 @@ private List<String> discoverTestClassNames(SurefireProperties effectiveSystemPr
                         false,
                         discoveryFile.getAbsolutePath());
             }
-            return readTestClassNames(discoveryFile);
+            List<String> testClassNames = readTestClassNames(discoveryFile);
+            if (testClassNames.isEmpty()) {
+                log.warning("The test-listing fork did not discover any test class (see " + discoveryFile
+                        + "). No tests will run.");
+            }
+            return testClassNames;
         } finally {
             returnNumber(forkNumber);
             removeShutdownHook(shutdown);
@@ -868,7 +873,7 @@ private static List<String> readTestClassNames(File discoveryFile) throws Surefi
         try {
             return Files.readAllLines(discoveryFile.toPath(), UTF_8).stream()
                     .map(String::trim)
-                    .filter(String::isEmpty)
+                    .filter(line -> !line.isEmpty())
                     .collect(toList());
         } catch (IOException e) {
             throw new SurefireBooterForkException("Cannot read discovered tests from " + discoveryFile, e);
diff --git a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java
index d0c5b9f88..7a45e8acd 100644
--- a/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java
+++ b/maven-surefire-common/src/test/java/org/apache/maven/plugin/surefire/booterclient/ForkStarterTest.java
@@ -27,6 +27,7 @@
 import java.nio.file.Paths;
 import java.util.ArrayDeque;
 import java.util.Collections;
+import java.util.List;
 import java.util.jar.Manifest;
 import java.util.zip.Deflater;
 
@@ -62,6 +63,8 @@
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Arrays.asList;
 import static org.apache.commons.io.FileUtils.deleteQuietly;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -290,6 +293,19 @@ public void processShouldWaitForAck() throws Exception {
         testLessInputStream.close();
     }
 
+    @Test
+    public void readTestClassNamesShouldKeepDiscoveredClassesAndDropBlankLines() throws Exception {
+        File discoveryFile = new File(tmp, "surefire-discovered-tests.txt");
+        Files.write(discoveryFile.toPath(), asList("com.example.FooTest", "", "  com.example.BarTest  ", "   "), UTF_8);
+
+        Method method = ForkStarter.class.getDeclaredMethod("readTestClassNames", File.class);
+        method.setAccessible(true);
+        @SuppressWarnings("unchecked")
+        List<String> testClassNames = (List<String>) method.invoke(null, discoveryFile);
+
+        assertThat(testClassNames).containsExactly("com.example.FooTest", "com.example.BarTest");
+    }
+
     @SuppressWarnings("unchecked")
     private static <T> T invokeMethod(Object target, String methodName, Class<?>[] paramTypes, Object... args)
             throws Exception {