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/08/08 23:12:53 UTC

(maven-surefire) branch master updated: [SUREFIRE-862, SUREFIRE-3178] Handle missing Failsafe summary files (#3417)

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 8027cc1ee [SUREFIRE-862, SUREFIRE-3178] Handle missing Failsafe summary files (#3417)
8027cc1ee is described below

commit 8027cc1ee067f7f6afb09a77915692a1463d56ff
Author: Václav Haisman <vh...@gmail.com>
AuthorDate: Sun Aug 9 01:12:47 2026 +0200

    [SUREFIRE-862, SUREFIRE-3178] Handle missing Failsafe summary files (#3417)
    
    * Ignore missing Failsafe summary files
    
    Skip configured summary files that were not created because no integration tests ran. Log each missing path at debug level and cover all-missing and mixed-summary cases.
    
    Fixes #862.
    
    * Honor failIfNoTests without Failsafe summary
    
    Let VerifyMojo report a no-tests result when failIfNoTests is enabled even if integration-test did not write a summary file. Cover the empty test class regression with unit and integration tests.
    
    Fixes #3178.
---
 .../apache/maven/plugin/failsafe/VerifyMojo.java   | 32 +++++++++---
 .../maven/plugin/failsafe/VerifyMojoTest.java      | 35 +++++++++++++
 .../its/jiras/Surefire3178FailIfNoTestsIT.java     | 33 ++++++++++++
 .../jiras/Surefire862MissingSummaryFilesIT.java    | 32 ++++++++++++
 .../surefire-3178-fail-if-no-tests/pom.xml         | 55 ++++++++++++++++++++
 .../src/test/java/EmptyIT.java                     | 19 +++++++
 .../surefire-862-missing-summary-files/pom.xml     | 60 ++++++++++++++++++++++
 7 files changed, 260 insertions(+), 6 deletions(-)

diff --git a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java
index 92a0a329f..e6262d1a7 100644
--- a/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java
+++ b/maven-failsafe-plugin/src/main/java/org/apache/maven/plugin/failsafe/VerifyMojo.java
@@ -181,11 +181,13 @@ public void execute() throws MojoExecutionException, MojoFailureException {
                     capitalizeFirstLetter(getPluginName()) + " report directory: " + getReportsDirectory());
 
             try {
-                RunResult summary = existsSummaryFile() ? readSummary(summaryFile) : noTestsRun();
+                RunResult summary = isSummaryFile(summaryFile) ? readSummary(summaryFile) : noTestsRun();
 
-                if (existsSummaryFiles()) {
+                if (summaryFiles != null) {
                     for (final File summaryFile : summaryFiles) {
-                        summary = summary.aggregate(readSummary(summaryFile));
+                        if (isSummaryFile(summaryFile)) {
+                            summary = summary.aggregate(readSummary(summaryFile));
+                        }
                     }
                 }
                 reportExecution(this, summary, getConsoleLogger(), getBooterForkException(summary));
@@ -233,7 +235,7 @@ protected boolean verifyParameters() throws MojoFailureException {
 
         if (!existsSummary()) {
             getConsoleLogger().info("No tests to run.");
-            return false;
+            return getFailIfNoTests();
         }
 
         if (failOnFlakeCount < 0) {
@@ -368,11 +370,29 @@ public void setSession(MavenSession session) {
     }
 
     private boolean existsSummaryFile() {
-        return summaryFile != null && summaryFile.isFile();
+        return existsSummaryFile(summaryFile);
     }
 
     private boolean existsSummaryFiles() {
-        return summaryFiles != null && summaryFiles.length != 0;
+        boolean exists = false;
+        if (summaryFiles != null) {
+            for (File summaryFile : summaryFiles) {
+                exists |= existsSummaryFile(summaryFile);
+            }
+        }
+        return exists;
+    }
+
+    private boolean existsSummaryFile(File summaryFile) {
+        boolean exists = isSummaryFile(summaryFile);
+        if (!exists && summaryFile != null) {
+            getConsoleLogger().debug("Failsafe summary file does not exist: " + summaryFile);
+        }
+        return exists;
+    }
+
+    private static boolean isSummaryFile(File summaryFile) {
+        return summaryFile != null && summaryFile.isFile();
     }
 
     private boolean existsSummary() {
diff --git a/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/VerifyMojoTest.java b/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/VerifyMojoTest.java
index 7f042127f..863384869 100644
--- a/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/VerifyMojoTest.java
+++ b/maven-failsafe-plugin/src/test/java/org/apache/maven/plugin/failsafe/VerifyMojoTest.java
@@ -20,6 +20,7 @@
 
 import java.io.File;
 import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Field;
 import java.net.URL;
 import java.net.URLDecoder;
 
@@ -94,4 +95,38 @@ void executeForPassingTests() throws MojoExecutionException, MojoFailureExceptio
         mojo.setSummaryFile(new File(getTestBaseDir(), "failsafe-summary-success.xml"));
         mojo.execute();
     }
+
+    @Test
+    void executeWithMissingAdditionalSummaryFiles() throws Exception {
+        setupExecuteMocks();
+        setSummaryFiles(new File(tempFolder, "missing-summary.xml"));
+
+        assertThatCode(mojo::execute).doesNotThrowAnyException();
+    }
+
+    @Test
+    void executeWithMissingSummaryAndFailIfNoTests() {
+        setupExecuteMocks();
+        mojo.setFailIfNoTests(true);
+
+        assertThatCode(mojo::execute)
+                .isExactlyInstanceOf(MojoFailureException.class)
+                .hasMessage("No tests were executed!  (Set -DfailIfNoTests=false to ignore this error.)");
+    }
+
+    @Test
+    void executeWithExistingAndMissingAdditionalSummaryFiles() throws Exception {
+        setupExecuteMocks();
+        setSummaryFiles(
+                new File(getTestBaseDir(), "failsafe-summary-success.xml"),
+                new File(tempFolder, "missing-summary.xml"));
+
+        assertThatCode(mojo::execute).doesNotThrowAnyException();
+    }
+
+    private void setSummaryFiles(File... summaryFiles) throws ReflectiveOperationException {
+        Field field = VerifyMojo.class.getDeclaredField("summaryFiles");
+        field.setAccessible(true);
+        field.set(mojo, summaryFiles);
+    }
 }
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire3178FailIfNoTestsIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire3178FailIfNoTestsIT.java
new file mode 100644
index 000000000..3021631b3
--- /dev/null
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire3178FailIfNoTestsIT.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.surefire.its.jiras;
+
+import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
+import org.junit.jupiter.api.Test;
+
+public class Surefire3178FailIfNoTestsIT extends SurefireJUnit4IntegrationTestCase {
+    @Test
+    public void emptyTestClassFailsVerification() {
+        unpack("surefire-3178-fail-if-no-tests")
+                .maven()
+                .withFailure()
+                .executeVerify()
+                .verifyTextInLog("No tests were executed!");
+    }
+}
diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire862MissingSummaryFilesIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire862MissingSummaryFilesIT.java
new file mode 100644
index 000000000..3be35f50f
--- /dev/null
+++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire862MissingSummaryFilesIT.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.surefire.its.jiras;
+
+import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase;
+import org.junit.jupiter.api.Test;
+
+public class Surefire862MissingSummaryFilesIT extends SurefireJUnit4IntegrationTestCase {
+    @Test
+    public void missingSummaryFilesAreIgnored() {
+        unpack("surefire-862-missing-summary-files")
+                .debugLogging()
+                .executeVerify()
+                .verifyTextInLog("Failsafe summary file does not exist:");
+    }
+}
diff --git a/surefire-its/src/test/resources/surefire-3178-fail-if-no-tests/pom.xml b/surefire-its/src/test/resources/surefire-3178-fail-if-no-tests/pom.xml
new file mode 100644
index 000000000..cfb1c6277
--- /dev/null
+++ b/surefire-its/src/test/resources/surefire-3178-fail-if-no-tests/pom.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.plugins.surefire</groupId>
+  <artifactId>surefire-3178-fail-if-no-tests</artifactId>
+  <version>1.0-SNAPSHOT</version>
+
+  <properties>
+    <maven.compiler.source>1.8</maven.compiler.source>
+    <maven.compiler.target>1.8</maven.compiler.target>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+        <version>${surefire.version}</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>integration-test</goal>
+              <goal>verify</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <failIfNoTests>true</failIfNoTests>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/surefire-its/src/test/resources/surefire-3178-fail-if-no-tests/src/test/java/EmptyIT.java b/surefire-its/src/test/resources/surefire-3178-fail-if-no-tests/src/test/java/EmptyIT.java
new file mode 100644
index 000000000..12a0874d5
--- /dev/null
+++ b/surefire-its/src/test/resources/surefire-3178-fail-if-no-tests/src/test/java/EmptyIT.java
@@ -0,0 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+public class EmptyIT {}
diff --git a/surefire-its/src/test/resources/surefire-862-missing-summary-files/pom.xml b/surefire-its/src/test/resources/surefire-862-missing-summary-files/pom.xml
new file mode 100644
index 000000000..9c6bfe9a5
--- /dev/null
+++ b/surefire-its/src/test/resources/surefire-862-missing-summary-files/pom.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>localhost</groupId>
+  <artifactId>surefire-862-missing-summary-files</artifactId>
+  <version>1.0</version>
+  <packaging>pom</packaging>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-failsafe-plugin</artifactId>
+        <version>${surefire.version}</version>
+        <executions>
+          <execution>
+            <id>integration-test</id>
+            <goals>
+              <goal>integration-test</goal>
+            </goals>
+            <configuration>
+              <summaryFile>${project.build.directory}/failsafe-summary-itest.xml</summaryFile>
+            </configuration>
+          </execution>
+          <execution>
+            <id>verify</id>
+            <goals>
+              <goal>verify</goal>
+            </goals>
+            <configuration>
+              <summaryFiles>
+                <summaryFile>${project.build.directory}/failsafe-summary-itest.xml</summaryFile>
+              </summaryFiles>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>