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

upthewaterspout pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new 082f1d5  GEODE-5388: Adding a gradle task to repeat a test
082f1d5 is described below

commit 082f1d5619acf5fab93017cc200d58162c7c3021
Author: Dan Smith <upthewatersp...@apache.org>
AuthorDate: Mon Jul 9 13:21:56 2018 -0700

    GEODE-5388: Adding a gradle task to repeat a test
    
    Example
    ./gradlew repeatTest --tests
    PartitionedRegionHADUnitTest.testBucketFailOverDuringCacheClose
    -Prepeat=100
---
 .../org/apache/geode/gradle/RepeatTest.groovy      |  70 +++++++++++
 .../geode/gradle/OverriddenTestExecutor.java       | 134 +++++++++++++++++++++
 gradle.properties                                  |   3 +
 gradle/docker.gradle                               |   1 +
 gradle/test.gradle                                 |  13 +-
 5 files changed, 219 insertions(+), 2 deletions(-)

diff --git a/buildSrc/src/main/groovy/org/apache/geode/gradle/RepeatTest.groovy 
b/buildSrc/src/main/groovy/org/apache/geode/gradle/RepeatTest.groovy
new file mode 100644
index 0000000..9109f96
--- /dev/null
+++ b/buildSrc/src/main/groovy/org/apache/geode/gradle/RepeatTest.groovy
@@ -0,0 +1,70 @@
+/*
+ * 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.geode.gradle;
+
+import org.gradle.StartParameter;
+import org.gradle.api.file.FileTree;
+import org.gradle.api.internal.DocumentationRegistry;
+import org.gradle.api.internal.tasks.testing.JvmTestExecutionSpec;
+import org.gradle.api.internal.tasks.testing.TestExecuter
+import org.gradle.api.internal.tasks.testing.detection.DefaultTestExecuter;
+import org.gradle.api.internal.tasks.testing.filter.DefaultTestFilter;
+import org.gradle.api.tasks.testing.Test;
+import org.gradle.internal.operations.BuildOperationExecutor;
+import org.gradle.internal.time.Clock;
+import org.gradle.internal.work.WorkerLeaseRegistry
+import org.gradle.process.internal.worker.WorkerProcessFactory;
+
+class RepeatTest extends Test {
+  int times = 1;
+
+  @Override
+  FileTree getCandidateClassFiles() {
+    FileTree candidates = super.getCandidateClassFiles();
+    for (int i = 0; i < times; i++) {
+      candidates = candidates.plus(super.getCandidateClassFiles());
+    }
+
+    return candidates;
+  }
+
+  /*
+   * We have to override gradles default test executor, because that uses 
{@link RunPreviousFailedFirstTestClassProcessor}
+   * Which deduplicates the test specs we're passing in
+   */
+  @Override
+  protected TestExecuter<JvmTestExecutionSpec> createTestExecuter() {
+    def oldExecutor = super.createTestExecuter()
+
+    def workerProcessFactory = getProcessBuilderFactory()
+
+    //Use the previously set worker process factory. If the test is
+    //being run using the parallel docker plugin, this will be a docker
+    //process factory
+    if(oldExecutor instanceof DefaultTestExecuter) {
+      workerProcessFactory = oldExecutor.workerFactory
+    }
+
+    return new OverriddenTestExecutor(workerProcessFactory, getActorFactory(),
+        getModuleRegistry(),
+        getServices().get(WorkerLeaseRegistry.class),
+        getServices().get(BuildOperationExecutor.class),
+        getServices().get(StartParameter.class).getMaxWorkerCount(),
+        getServices().get(Clock.class),
+        getServices().get(DocumentationRegistry.class),
+        (DefaultTestFilter) getFilter());
+  }
+
+}
diff --git 
a/buildSrc/src/main/java/org/apache/geode/gradle/OverriddenTestExecutor.java 
b/buildSrc/src/main/java/org/apache/geode/gradle/OverriddenTestExecutor.java
new file mode 100644
index 0000000..4984bb4
--- /dev/null
+++ b/buildSrc/src/main/java/org/apache/geode/gradle/OverriddenTestExecutor.java
@@ -0,0 +1,134 @@
+/*
+ * 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.geode.gradle;
+
+import java.io.File;
+import java.util.Set;
+
+import com.google.common.collect.ImmutableSet;
+import org.gradle.api.file.FileTree;
+import org.gradle.api.internal.DocumentationRegistry;
+import org.gradle.api.internal.classpath.ModuleRegistry;
+import org.gradle.api.internal.tasks.testing.JvmTestExecutionSpec;
+import org.gradle.api.internal.tasks.testing.TestClassProcessor;
+import org.gradle.api.internal.tasks.testing.TestExecuter;
+import org.gradle.api.internal.tasks.testing.TestFramework;
+import org.gradle.api.internal.tasks.testing.TestResultProcessor;
+import org.gradle.api.internal.tasks.testing.WorkerTestClassProcessorFactory;
+import org.gradle.api.internal.tasks.testing.detection.DefaultTestClassScanner;
+import org.gradle.api.internal.tasks.testing.detection.TestFrameworkDetector;
+import org.gradle.api.internal.tasks.testing.filter.DefaultTestFilter;
+import 
org.gradle.api.internal.tasks.testing.processors.MaxNParallelTestClassProcessor;
+import 
org.gradle.api.internal.tasks.testing.processors.PatternMatchTestClassProcessor;
+import 
org.gradle.api.internal.tasks.testing.processors.RestartEveryNTestClassProcessor;
+import 
org.gradle.api.internal.tasks.testing.processors.RunPreviousFailedFirstTestClassProcessor;
+import org.gradle.api.internal.tasks.testing.processors.TestMainAction;
+import org.gradle.api.internal.tasks.testing.worker.ForkingTestClassProcessor;
+import org.gradle.api.logging.Logger;
+import org.gradle.api.logging.Logging;
+import org.gradle.internal.Factory;
+import org.gradle.internal.actor.ActorFactory;
+import org.gradle.internal.operations.BuildOperationExecutor;
+import org.gradle.internal.time.Clock;
+import org.gradle.internal.work.WorkerLeaseRegistry;
+import org.gradle.process.internal.worker.WorkerProcessFactory;
+
+/**
+ * Test executor that is used to replace gradles DefaultTestExecutor and does
+ * not include a {@link RunPreviousFailedFirstTestClassProcessor} in the 
processor
+ * chain.  This is used by the RepeatTest task.
+ */
+class OverriddenTestExecutor implements TestExecuter<JvmTestExecutionSpec> {
+  private static final Logger LOGGER = 
Logging.getLogger(OverriddenTestExecutor.class);
+
+  private final WorkerProcessFactory workerFactory;
+  private final ActorFactory actorFactory;
+  private final ModuleRegistry moduleRegistry;
+  private final WorkerLeaseRegistry workerLeaseRegistry;
+  private final BuildOperationExecutor buildOperationExecutor;
+  private final int maxWorkerCount;
+  private final Clock clock;
+  private final DocumentationRegistry documentationRegistry;
+  private final DefaultTestFilter testFilter;
+  private TestClassProcessor processor;
+
+  public OverriddenTestExecutor(WorkerProcessFactory workerFactory, 
ActorFactory actorFactory, ModuleRegistry moduleRegistry,
+                                WorkerLeaseRegistry workerLeaseRegistry, 
BuildOperationExecutor buildOperationExecutor, int maxWorkerCount,
+                                Clock clock, DocumentationRegistry 
documentationRegistry, DefaultTestFilter testFilter) {
+    this.workerFactory = workerFactory;
+    this.actorFactory = actorFactory;
+    this.moduleRegistry = moduleRegistry;
+    this.workerLeaseRegistry = workerLeaseRegistry;
+    this.buildOperationExecutor = buildOperationExecutor;
+    this.maxWorkerCount = maxWorkerCount;
+    this.clock = clock;
+    this.documentationRegistry = documentationRegistry;
+    this.testFilter = testFilter;
+  }
+
+  @Override
+  public void execute(final JvmTestExecutionSpec testExecutionSpec, 
TestResultProcessor testResultProcessor) {
+    final TestFramework testFramework = testExecutionSpec.getTestFramework();
+    final WorkerTestClassProcessorFactory testInstanceFactory = 
testFramework.getProcessorFactory();
+    final WorkerLeaseRegistry.WorkerLease currentWorkerLease = 
workerLeaseRegistry.getCurrentWorkerLease();
+    final Set<File> classpath = 
ImmutableSet.copyOf(testExecutionSpec.getClasspath());
+    final Factory<TestClassProcessor> forkingProcessorFactory = new 
Factory<TestClassProcessor>() {
+      public TestClassProcessor create() {
+        return new ForkingTestClassProcessor(currentWorkerLease, 
workerFactory, testInstanceFactory, testExecutionSpec.getJavaForkOptions(),
+            classpath, testFramework.getWorkerConfigurationAction(), 
moduleRegistry, documentationRegistry);
+      }
+    };
+    final Factory<TestClassProcessor> reforkingProcessorFactory = new 
Factory<TestClassProcessor>() {
+      public TestClassProcessor create() {
+        return new RestartEveryNTestClassProcessor(forkingProcessorFactory, 
testExecutionSpec.getForkEvery());
+      }
+    };
+    processor =
+        new PatternMatchTestClassProcessor(testFilter,
+                new 
MaxNParallelTestClassProcessor(getMaxParallelForks(testExecutionSpec), 
reforkingProcessorFactory, actorFactory));
+
+    final FileTree testClassFiles = testExecutionSpec.getCandidateClassFiles();
+
+    Runnable detector;
+    if (testExecutionSpec.isScanForTestClasses() && 
testFramework.getDetector() != null) {
+      TestFrameworkDetector testFrameworkDetector = 
testFramework.getDetector();
+      
testFrameworkDetector.setTestClasses(testExecutionSpec.getTestClassesDirs().getFiles());
+      testFrameworkDetector.setTestClasspath(classpath);
+      detector = new DefaultTestClassScanner(testClassFiles, 
testFrameworkDetector, processor);
+    } else {
+      detector = new DefaultTestClassScanner(testClassFiles, null, processor);
+    }
+
+    final Object testTaskOperationId = 
buildOperationExecutor.getCurrentOperation().getParentId();
+
+    new TestMainAction(detector, processor, testResultProcessor, clock, 
testTaskOperationId, testExecutionSpec.getPath(), "Gradle Test Run " + 
testExecutionSpec.getIdentityPath()).run();
+  }
+
+  @Override
+  public void stopNow() {
+    if (processor != null) {
+      processor.stopNow();
+    }
+  }
+
+  private int getMaxParallelForks(JvmTestExecutionSpec testExecutionSpec) {
+    int maxParallelForks = testExecutionSpec.getMaxParallelForks();
+    if (maxParallelForks > maxWorkerCount) {
+      LOGGER.info("{}.maxParallelForks ({}) is larger than max-workers ({}), 
forcing it to {}", testExecutionSpec.getPath(), maxParallelForks, 
maxWorkerCount, maxWorkerCount);
+      maxParallelForks = maxWorkerCount;
+    }
+    return maxParallelForks;
+  }
+}
diff --git a/gradle.properties b/gradle.properties
index f449867..dc7e5c0 100755
--- a/gradle.properties
+++ b/gradle.properties
@@ -60,6 +60,9 @@ dunitDockerUser = root
 #JVM to be used by tests
 testJVM=
 
+repeat = 100
+
 org.gradle.caching = true
 org.gradle.parallel = false
 org.gradle.configureondemand = false
+
diff --git a/gradle/docker.gradle b/gradle/docker.gradle
index 96de69d..4cafbf2 100644
--- a/gradle/docker.gradle
+++ b/gradle/docker.gradle
@@ -108,5 +108,6 @@ subprojects {
 
   if (project.hasProperty('parallelDunit')) {
     distributedTest.configure(dockerConfig)
+    repeatTest.configure(dockerConfig)
   }
 }
diff --git a/gradle/test.gradle b/gradle/test.gradle
index 18ce11b..0987c02 100644
--- a/gradle/test.gradle
+++ b/gradle/test.gradle
@@ -1,4 +1,5 @@
 import org.apache.geode.gradle.TestPropertiesWriter
+import org.apache.geode.gradle.RepeatTest
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -133,6 +134,14 @@ subprojects {
     outputs.upToDateWhen{false}
   }
 
+  task repeatTest(type:RepeatTest) {
+    times= Integer.parseInt(repeat)
+
+    useJUnit {}
+
+    outputs.upToDateWhen{false}
+  }
+
   task flakyTest(type:Test) {
     useJUnit {
       includeCategories 'org.apache.geode.test.junit.categories.FlakyTest'
@@ -417,6 +426,6 @@ subprojects {
 
   check.dependsOn checkMissedTests
 
-  combineReports.mustRunAfter check, test, integrationTest, distributedTest, 
flakyTest, checkMissedTests, acceptanceTest
-  [build, check, test, integrationTest, distributedTest, flakyTest, 
checkMissedTests, acceptanceTest].each {it.finalizedBy combineReports}
+  combineReports.mustRunAfter check, test, integrationTest, distributedTest, 
flakyTest, checkMissedTests, acceptanceTest, repeatTest
+  [build, check, test, integrationTest, distributedTest, flakyTest, 
checkMissedTests, acceptanceTest, repeatTest].each {it.finalizedBy 
combineReports}
 }

Reply via email to