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 <[email protected]>
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}
}