You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by th...@apache.org on 2020/09/14 16:38:21 UTC

[lucene-solr] 03/39: LUCENE-9465: 'beast' task from within gradle (#1757)

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

thelabdude pushed a commit to branch reference_impl_gradle_updates
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit 17d664ff89800015966dd4cdfb30b53321018610
Author: Dawid Weiss <dw...@apache.org>
AuthorDate: Tue Aug 18 09:28:50 2020 +0200

    LUCENE-9465: 'beast' task from within gradle (#1757)
---
 build.gradle                           |  1 +
 gradle/testing/beasting.gradle         | 82 ++++++++++++++++++++++++++++++++++
 gradle/testing/defaults-tests.gradle   |  3 +-
 gradle/testing/fail-on-no-tests.gradle |  2 +-
 gradle/testing/randomization.gradle    |  8 ++--
 help/tests.txt                         | 15 +++++++
 6 files changed, 106 insertions(+), 5 deletions(-)

diff --git a/build.gradle b/build.gradle
index 288a6a7..f5ad04a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -132,6 +132,7 @@ apply from: file('gradle/testing/per-project-summary.gradle')
 apply from: file('gradle/testing/slowest-tests-at-end.gradle')
 apply from: file('gradle/testing/failed-tests-at-end.gradle')
 apply from: file('gradle/testing/profiling.gradle')
+apply from: file('gradle/testing/beasting.gradle')
 apply from: file('gradle/help.gradle')
 
 // Ant-compatibility layer. ALL OF THESE SHOULD BE GONE at some point. They are
diff --git a/gradle/testing/beasting.gradle b/gradle/testing/beasting.gradle
new file mode 100644
index 0000000..1604cdb
--- /dev/null
+++ b/gradle/testing/beasting.gradle
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+// This adds 'beast' task which clones tests a given number of times (preferably
+// constrained with a filtering pattern passed via '--tests').
+
+// TODO: subtasks are not run in parallel (sigh, gradle removed this capability for intra-project tasks).
+// TODO: maybe it would be better to take a deeper approach and just feed the task
+//       runner duplicated suite names (much like https://github.com/gradle/test-retry-gradle-plugin)
+// TODO: this is a somewhat related issue: https://github.com/gradle/test-retry-gradle-plugin/issues/29
+
+def beastingMode = gradle.startParameter.taskNames.contains("beast");
+
+if (beastingMode) {
+  if (rootProject.rootSeedUserProvided) {
+    logger.warn("Root randomization seed is externally provided, all duplicated runs will use the same starting seed.")
+  }
+
+  allprojects {
+    plugins.withType(JavaPlugin) {
+      task beast(type: BeastTask) {
+        description "Run a test suite (or a set of tests) many times over (duplicate 'test' task)."
+        group "Verification"
+      }
+
+      def dups = Integer.parseInt(propertyOrDefault("tests.dups", "0"))
+      if (dups <= 0) {
+        throw new GradleException("Specify -Ptests.dups=[count] for beast task.")
+      }
+
+      // generate N test tasks and attach them to the beasting task for this project;
+      // the test filter will be applied by the beast task once it is received from
+      // command line.
+      def subtasks = (1..dups).collect { value ->
+        return tasks.create(name: "test_${value}", type: Test, {
+          failFast = true
+          doFirst {
+            // If there is a global root seed, use it (all duplicated tasks will run
+            // from the same starting seed). Otherwise pick a sequential derivative.
+            if (!rootProject.rootSeedUserProvided) {
+              systemProperty("tests.seed",
+                  String.format("%08X", new Random(rootProject.rootSeedLong + value).nextLong()))
+            }
+          }
+        })
+      }
+
+      beast.dependsOn subtasks
+    }
+  }
+}
+
+/**
+ * We have to declare a dummy task here to be able to reuse the same syntax for 'test' task
+ * filter option.
+ */
+class BeastTask extends DefaultTask {
+  @Option(option = "tests", description = "Sets test class or method name to be included, '*' is supported.")
+  public void setTestNamePatterns(List<String> patterns) {
+    taskDependencies.getDependencies(this).each { subtask ->
+      subtask.filter.setCommandLineIncludePatterns(patterns)
+    }
+  }
+
+  @TaskAction
+  void run() {
+  }
+}
\ No newline at end of file
diff --git a/gradle/testing/defaults-tests.gradle b/gradle/testing/defaults-tests.gradle
index e59c5c9..9bca17b 100644
--- a/gradle/testing/defaults-tests.gradle
+++ b/gradle/testing/defaults-tests.gradle
@@ -50,8 +50,9 @@ allprojects {
       }
     }
 
-    test {
+    tasks.withType(Test) {
       reports.junitXml.destination file(propertyOrDefault("reports.dest", "${reports.junitXml.destination.toString()}"))
+
       ext {
         testOutputsDir = file("${reports.junitXml.destination}/outputs")
       }
diff --git a/gradle/testing/fail-on-no-tests.gradle b/gradle/testing/fail-on-no-tests.gradle
index 4851b47..db763d8 100644
--- a/gradle/testing/fail-on-no-tests.gradle
+++ b/gradle/testing/fail-on-no-tests.gradle
@@ -19,7 +19,7 @@
 
 configure(allprojects) {
   plugins.withType(JavaPlugin) {
-    test {
+    tasks.withType(Test) {
       filter {
         failOnNoMatchingTests = false
       }
diff --git a/gradle/testing/randomization.gradle b/gradle/testing/randomization.gradle
index 0f36bae..f1d57d0 100644
--- a/gradle/testing/randomization.gradle
+++ b/gradle/testing/randomization.gradle
@@ -37,6 +37,7 @@ buildscript {
 configure(rootProject) {
   ext {
     rootSeed = propertyOrDefault('tests.seed', String.format("%08X", new Random().nextLong()))
+    rootSeedUserProvided = (propertyOrDefault('tests.seed', null) != null)
     rootSeedLong = SeedUtils.parseSeedChain(rootSeed)[0]
     projectSeedLong = rootSeedLong ^ project.path.hashCode()
   }
@@ -62,7 +63,7 @@ allprojects {
       testOptions = [
           // seed, repetition and amplification.
           [propName: 'tests.seed', value: "random", description: "Sets the master randomization seed."],
-          [propName: 'tests.iters', value: null, description: "Duplicate (re-run) each test N times."],
+          [propName: 'tests.iters', value: null, description: "Duplicate (re-run) each test case N times."],
           [propName: 'tests.multiplier', value: 1, description: "Value multiplier for randomized tests."],
           [propName: 'tests.maxfailures', value: null, description: "Skip tests after a given number of failures."],
           [propName: 'tests.timeoutSuite', value: null, description: "Timeout (in millis) for an entire suite."],
@@ -157,7 +158,7 @@ allprojects {
       }
 
       // Append resolved test properties to the test task.
-      test {
+      tasks.withType(Test) { task ->
         // TODO: we could remove opts with "buildOnly: true" (?)
         systemProperties testOptionsResolved
 
@@ -237,9 +238,10 @@ if (vmName =~ /(?i)(hotspot|openjdk|jrockit)/ &&
   logger.debug("Enabling HashMap assertions.")
   allprojects {
     plugins.withType(JavaPlugin) {
-      test {
+      tasks.withType(Test) { task ->  
         jvmArgs("-da:java.util.HashMap")
       }
     }
   }
 }
+
diff --git a/help/tests.txt b/help/tests.txt
index 30b1f4a..5054c0e 100644
--- a/help/tests.txt
+++ b/help/tests.txt
@@ -101,6 +101,21 @@ cleanTest task:
 
 gradlew -p lucene/core cleanTest test -Ptests.seed=deadbeef
 
+The 'tests.iters' option should be sufficient for individual test cases
+and is *much* faster than trying to duplicate re-runs of the entire
+test suites. When it is absolutely needed to re-run an entire suite (because
+of randomization in the static initialization, for example), you can do it
+by running the 'beast' task with 'tests.dups' option:
+
+gradlew -p lucene/core beast -Ptests.dups=10 --tests TestPerFieldDocValuesFormat
+
+Note the filter (--tests) used to narrow down test reiterations to a particular
+class. You can use any filter, including no filter at all, but it rarely makes
+sense (will take ages). By default the test tasks generated by the 'beast' mode
+use a random starting seed for randomization. If you pass an explicit seed, this
+won't be the case (all tasks will use exactly the same starting seed):
+
+gradlew -p lucene/core beast -Ptests.dups=10 --tests TestPerFieldDocValuesFormat -Dtests.seed=deadbeef
 
 Verbose mode and debugging
 --------------------------