You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by dw...@apache.org on 2025/06/25 21:17:39 UTC

(lucene) branch main updated: Correct tests.seed to be reported on failures (#14848)

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

dweiss pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/lucene.git


The following commit(s) were added to refs/heads/main by this push:
     new 4b47fb1a311 Correct tests.seed to be reported on failures (#14848)
4b47fb1a311 is described below

commit 4b47fb1a3113d22bca6cd8c1664529ef2d7f4877
Author: Dawid Weiss <da...@carrotsearch.com>
AuthorDate: Wed Jun 25 23:17:33 2025 +0200

    Correct tests.seed to be reported on failures (#14848)
---
 .../lucene.java.show-failed-tests-at-end.gradle    | 31 ++++++++++++++++++----
 .../lucene.java.tests-and-randomization.gradle     |  8 ++++++
 .../lucene/gradle/ErrorReportingTestListener.java  | 16 ++++++++---
 3 files changed, 46 insertions(+), 9 deletions(-)

diff --git a/build-tools/build-infra/src/main/groovy/lucene.java.show-failed-tests-at-end.gradle b/build-tools/build-infra/src/main/groovy/lucene.java.show-failed-tests-at-end.gradle
index 5c76ca592ac..9e3fcbd3fc0 100644
--- a/build-tools/build-infra/src/main/groovy/lucene.java.show-failed-tests-at-end.gradle
+++ b/build-tools/build-infra/src/main/groovy/lucene.java.show-failed-tests-at-end.gradle
@@ -15,6 +15,7 @@
  * limitations under the License.
  */
 
+import java.util.regex.Pattern
 import org.apache.lucene.gradle.ErrorReportingTestListener
 
 // Display all failed tests at the end of the build.
@@ -33,11 +34,28 @@ allprojects {
 
       afterTest { desc, result ->
         if (result.resultType == TestResult.ResultType.FAILURE) {
+          // check if it's a constructor or a before/after class hook that failed.
+          def qTestName
+          if (desc.name == "classMethod") {
+            qTestName = desc.className
+          } else {
+            qTestName = "${desc.className}.${desc.name}"
+          }
+
+          def randomizationParameters = ""
+          def p = Pattern.compile(/.+ (?<params>[{].*[}])$/)
+          def matcher = p.matcher(qTestName)
+          if (matcher.matches()) {
+            randomizationParameters = matcher.group("params")
+            qTestName = qTestName.replace(randomizationParameters, "").trim()
+          }
+
           failedTests << [
-            "name"     : "${desc.className}.${desc.name}",
+            "name"     : qTestName,
+            "randomizationParameters": randomizationParameters,
             "project"  : "${test.project.path}",
             "output"   : file("${testOutputsDir}/${ErrorReportingTestListener.getOutputLogName(desc.parent)}"),
-            "reproduce": "gradlew ${project.path}:test --tests \"${desc.className}.${desc.name}\" ${reproLine}"
+            "reproduce": "gradlew ${project.path}:test --tests \"${qTestName}\" ${reproLine}"
           ]
         }
       }
@@ -62,11 +80,14 @@ gradle.buildFinished { result ->
         .sort { a, b -> b.project.compareTo(a.project) }
         .collect { e ->
           String.format(Locale.ROOT,
-              "  - %s (%s)\n    Test output: %s\n    Reproduce with: %s\n",
-              e.name, e.project, e.output, e.reproduce)
+              "  - %s (%s)%s\n    Test output: %s\n    Reproduce with: %s\n",
+              e.name, e.project,
+              e.containsKey("randomizationParameters") &&
+              !e.randomizationParameters.isBlank() ? "\n    Context parameters: ${e.randomizationParameters}" : "",
+              e.output, e.reproduce)
         }
         .join("\n")
 
-    logger.error("\nERROR: The following test(s) have failed:\n${formatted}")
+    logger.error("\nERROR: The following {} failed:\n\n{}", failedTests.size() == 1 ? "test has" : "tests have", formatted)
   }
 }
diff --git a/build-tools/build-infra/src/main/groovy/lucene.java.tests-and-randomization.gradle b/build-tools/build-infra/src/main/groovy/lucene.java.tests-and-randomization.gradle
index 670a1591407..cfddde2db78 100644
--- a/build-tools/build-infra/src/main/groovy/lucene.java.tests-and-randomization.gradle
+++ b/build-tools/build-infra/src/main/groovy/lucene.java.tests-and-randomization.gradle
@@ -20,6 +20,7 @@ import org.apache.tools.ant.types.Commandline
 import org.gradle.api.tasks.testing.logging.*
 import com.carrotsearch.randomizedtesting.generators.RandomPicks
 import org.apache.lucene.gradle.ErrorReportingTestListener
+import com.carrotsearch.gradle.buildinfra.buildoptions.BuildOptionsExtension
 
 def loggingConfigFile = rootProject.layout.projectDirectory.file("gradle/testing/logging.properties")
 def verboseModeHookInstalled = false
@@ -82,6 +83,13 @@ Provider<Integer> upperJavaFeatureVersionOption = buildOptions.addIntOption(
     "tests.upperJavaFeatureVersion", "Min JDK feature version to configure the Panama Vectorization provider")
 
 // Test reiteration, filtering and component randomization options.
+
+// Propagate root seed so that it is visible and reported as an option in subprojects.
+if (project != project.rootProject) {
+  buildOptions.addOption("tests.seed", "The \"root\" randomization seed for options and test parameters.",
+      rootProject.getExtensions().getByType(BuildOptionsExtension).getOption("tests.seed").asStringProvider())
+}
+
 buildOptions.addIntOption("tests.iters", "Duplicate (re-run) each test case N times.")
 optionsInheritedAsProperties += ["tests.iters"]
 
diff --git a/build-tools/build-infra/src/main/java/org/apache/lucene/gradle/ErrorReportingTestListener.java b/build-tools/build-infra/src/main/java/org/apache/lucene/gradle/ErrorReportingTestListener.java
index a58038ff710..a6dc738a645 100644
--- a/build-tools/build-infra/src/main/java/org/apache/lucene/gradle/ErrorReportingTestListener.java
+++ b/build-tools/build-infra/src/main/java/org/apache/lucene/gradle/ErrorReportingTestListener.java
@@ -173,11 +173,19 @@ public class ErrorReportingTestListener implements TestOutputListener, TestListe
             })
         .filter(
             option -> {
+              // if the option is not present, ignore it in repro line.
+              if (!option.isPresent()) {
+                return false;
+              }
+
               // we only care about options that have non-default values or options
-              // where values are computed are runtime (possibly randomized).
-              return option.isPresent()
-                  && (option.getSource() == BuildOptionValueSource.COMPUTED_VALUE
-                      || !option.isEqualToDefaultValue());
+              // where values are computed at runtime (possibly randomized).
+              if (option.getSource() == BuildOptionValueSource.COMPUTED_VALUE) {
+                return true;
+              }
+
+              // filter out all non-computed options with default values.
+              return !option.isEqualToDefaultValue();
             })
         .map(
             option -> {