GEODE-8637: Give each test worker a unique working dir (#5649)
* Give each test worker a unique working dir
Before running a test task, wrap its TestFramework in a wrapper that
creates a unique working dir for each new test worker.
diff --git a/buildSrc/src/main/java/org/apache/geode/gradle/RunInSubdirectoryTestFramework.java b/buildSrc/src/main/java/org/apache/geode/gradle/RunInSubdirectoryTestFramework.java
new file mode 100644
index 0000000..546ae1e
--- /dev/null
+++ b/buildSrc/src/main/java/org/apache/geode/gradle/RunInSubdirectoryTestFramework.java
@@ -0,0 +1,102 @@
+/*
+ * 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 static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.gradle.api.Action;
+import org.gradle.api.internal.tasks.testing.TestFramework;
+import org.gradle.api.internal.tasks.testing.WorkerTestClassProcessorFactory;
+import org.gradle.api.internal.tasks.testing.detection.TestFrameworkDetector;
+import org.gradle.api.tasks.testing.TestFrameworkOptions;
+import org.gradle.process.internal.JavaExecHandleBuilder;
+import org.gradle.process.internal.worker.WorkerProcessBuilder;
+
+/**
+ * Wraps a test framework to run each test worker in a separate working directory.
+ */
+public class RunInSubdirectoryTestFramework implements TestFramework {
+ private static final String GEMFIRE_PROPERTIES = "gemfire.properties";
+ private final AtomicLong workerId = new AtomicLong();
+ private final TestFramework delegate;
+
+ public RunInSubdirectoryTestFramework(TestFramework delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public TestFrameworkDetector getDetector() {
+ return delegate.getDetector();
+ }
+
+ @Override
+ public TestFrameworkOptions getOptions() {
+ return delegate.getOptions();
+ }
+
+ @Override
+ public WorkerTestClassProcessorFactory getProcessorFactory() {
+ return delegate.getProcessorFactory();
+ }
+
+ /**
+ * Return an action that configures the test worker builder to run the test worker in a unique
+ * subdirectory of the task's working directory.
+ */
+ @Override
+ public Action<WorkerProcessBuilder> getWorkerConfigurationAction() {
+ return workerProcessBuilder -> {
+ delegate.getWorkerConfigurationAction().execute(workerProcessBuilder);
+ JavaExecHandleBuilder javaCommand = workerProcessBuilder.getJavaCommand();
+
+ Path taskWorkingDir = javaCommand.getWorkingDir().toPath();
+ String workerWorkingDirName = String.format("test-worker-%06d", workerId.incrementAndGet());
+ Path workerWorkingDir = taskWorkingDir.resolve(workerWorkingDirName);
+
+ createWorkingDir(workerWorkingDir);
+ copyGemFirePropertiesFile(taskWorkingDir, workerWorkingDir);
+
+ javaCommand.setWorkingDir(workerWorkingDir);
+ };
+ }
+
+ private void copyGemFirePropertiesFile(Path taskWorkingDir, Path workerWorkingDir) {
+ Path taskPropertiesFile = taskWorkingDir.resolve(GEMFIRE_PROPERTIES);
+ if (!Files.exists(taskPropertiesFile)) {
+ return;
+ }
+ Path workerPropertiesFile = workerWorkingDir.resolve(taskPropertiesFile.getFileName());
+ try {
+ Files.copy(taskPropertiesFile, workerPropertiesFile, COPY_ATTRIBUTES);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ private void createWorkingDir(Path workerWorkingDir) {
+ try {
+ Files.createDirectories(workerWorkingDir);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+}
diff --git a/extensions/geode-modules-test/src/main/java/org/apache/geode/modules/session/AbstractSessionsTest.java b/extensions/geode-modules-test/src/main/java/org/apache/geode/modules/session/AbstractSessionsTest.java
index e30a15d..95250d3 100644
--- a/extensions/geode-modules-test/src/main/java/org/apache/geode/modules/session/AbstractSessionsTest.java
+++ b/extensions/geode-modules-test/src/main/java/org/apache/geode/modules/session/AbstractSessionsTest.java
@@ -54,7 +54,8 @@
// Set up the servers we need
protected static void setupServer(final DeltaSessionManager manager) throws Exception {
- FileUtils.copyDirectory(Paths.get("..", "resources", "integrationTest", "tomcat").toFile(),
+ FileUtils.copyDirectory(
+ Paths.get("..", "..", "resources", "integrationTest", "tomcat").toFile(),
new File("./tomcat"));
port = SocketUtils.findAvailableTcpPort();
server = new EmbeddedTomcat(port, "JVM-1");
diff --git a/gradle/test.gradle b/gradle/test.gradle
index 15d0e5b..e12c3e1 100644
--- a/gradle/test.gradle
+++ b/gradle/test.gradle
@@ -1,6 +1,7 @@
import org.apache.geode.gradle.TestPropertiesWriter
import org.apache.geode.gradle.RepeatTest
import org.apache.geode.gradle.plugins.DependencyConstraints
+import org.apache.geode.gradle.RunInSubdirectoryTestFramework
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
@@ -161,6 +162,17 @@
}
}
+configure([acceptanceTest, distributedTest, integrationTest, uiTest, upgradeTest, repeatAcceptanceTest, repeatDistributedTest, repeatIntegrationTest, repeatUnitTest, repeatUpgradeTest]) {
+ doFirst {
+ // Wrap the task's test framework in a wrapper that runs each test worker JVM in a unique
+ // subdirectory.
+ def subdirFramework = new RunInSubdirectoryTestFramework(testFramework)
+ // This call works for now, but the Test class declares useTestFramework() as protected, so
+ // this could become troublesome in a future version of Gradle/Groovy.
+ useTestFramework subdirFramework
+ }
+}
+
configure([repeatDistributedTest, repeatIntegrationTest, repeatUpgradeTest, repeatUnitTest, repeatAcceptanceTest]) {
times = Integer.parseInt(repeat)
useJUnit {}