From 3b30307ea4f40a24ee9c45e5ec4194c4a04d7ab8 Mon Sep 17 00:00:00 2001 From: Dan Plyukhin Date: Tue, 5 May 2026 16:50:19 -0500 Subject: [PATCH 1/4] Improve instructions in CONTRIBUTING.md Add missing gradle toolchain dependencies to the list of Java version requirements, both in CONTRIBUTING.md and mise.toml. Fix test instructions in CONTRIBUTING.md, which incorrectly state that a temporal server needs to be running during tests. Explain how to run the tests that *do* require a temporal server. --- CONTRIBUTING.md | 26 +++++++++++++++----------- mise.toml | 15 +-------------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5b0c1a0fd..44dba882d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,8 +8,14 @@ before we can merge in any of your changes ## Development Environment -- Java 23+ -- Docker to run Temporal Server +- **Java 23+** is required to run Gradle and to compile the project. +- Some tests assume you also have **Java 17 and 21** installed. +- Some optional tests also require the [Temporal CLI](https://docs.temporal.io/cli#installation). + +You can install the Java dependencies all in one go with [mise](https://mise.jdx.dev/), which reads from [mise.toml](./mise.toml). If you're using mise and Gradle isn't automatically picking up the older JDKs as toolchains, try [this workaround](https://mise.jdx.dev/lang/java.html#gradle-toolchains-detection). + +If you're using Apple Silicon, see the [note on Rosetta](#note-on-rosetta). + ## Build @@ -41,26 +47,24 @@ fatal: No names found, cannot describe anything. This can be done resolved by running `git fetch --tags` on your branch. Note, make sure your fork has tags copied from the main repo. -## Test and Build +## Testing -Run a local temporal server with the [temporal CLI](https://docs.temporal.io/cli#installation): +Some tests assume you have the temporal server running, and others don't. By default, Gradle only runs the tests that don't require a server: ```bash -temporal server start-dev +./gradlew test ``` -(If this does not work, see instructions for running the Temporal Server at https://github.com/temporalio/temporal/blob/master/README.md.) - -Then run all the tests with: +You can run a local temporal server with the [temporal CLI](https://docs.temporal.io/cli#installation): ```bash -./gradlew test +temporal server start-dev ``` -Build with: +Run the tests that require a temporal server: ```bash -./gradlew build +USE_DOCKER_SERVICE=true ./gradlew test ``` ## Note on Rosetta diff --git a/mise.toml b/mise.toml index dbdf2a1eb..8bcc92786 100644 --- a/mise.toml +++ b/mise.toml @@ -1,15 +1,2 @@ -# TIP -# -# For the best SDK development experience, make to hava all of the following -# JDKs installed on your machine (`mise install java@[version]`): -# - `java@temurin-11` -# - `java@temurin-17` -# - `java@temurin-23` -# -# Java 21+ is required for anything that requires gradle. -# -# If you find out that gradle isn't automatically picking it up older JDKs as -# toolchains, see https://mise.jdx.dev/lang/java.html#gradle-toolchains-detection. - [tools] -java = "temurin-23" +java = ["temurin-23", "temurin-21", "temurin-17"] From 9a9b020f912ca287e47060e6b15f2025d80d51f3 Mon Sep 17 00:00:00 2001 From: Dan Plyukhin Date: Thu, 7 May 2026 14:41:26 -0500 Subject: [PATCH 2/4] Rephrase misleading advice about testing --- CONTRIBUTING.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 44dba882d..7c28aad7c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,19 +49,26 @@ the main repo. ## Testing -Some tests assume you have the temporal server running, and others don't. By default, Gradle only runs the tests that don't require a server: +Run tests: ```bash ./gradlew test ``` -You can run a local temporal server with the [temporal CLI](https://docs.temporal.io/cli#installation): +Run a single test or group of tests: + +```bash +./gradlew :temporal-sdk:test --offline --tests "io.temporal.activity.ActivityPauseTest" +./gradlew :temporal-sdk:test --offline --tests "io.temporal.workflow.*" +``` + +By default, tests run against an built-in test server that starts automatically. But some tests require a real temporal server and will be skipped. You can run an external server locally with the [temporal CLI](https://docs.temporal.io/cli#installation): ```bash temporal server start-dev ``` -Run the tests that require a temporal server: +Run the tests that require an external server: ```bash USE_DOCKER_SERVICE=true ./gradlew test From 83ca84422160d4251544d8518ef5163b1828b226 Mon Sep 17 00:00:00 2001 From: Dan Plyukhin Date: Thu, 7 May 2026 15:33:47 -0500 Subject: [PATCH 3/4] Renamed USE_DOCKER_SERVICE to USE_EXTERNAL_SERVICE --- .github/workflows/ci.yml | 14 ++++++------ CONTRIBUTING.md | 2 +- .../temporal/activity/ActivityPauseTest.java | 1 + .../io/temporal/worker/StickyWorkerTest.java | 22 ++----------------- .../workerFactory/WorkerFactoryTests.java | 6 ++--- .../autoconfigure/WorkerVersioningTest.java | 8 +++---- .../docker/RegisterTestNamespace.java | 6 ++--- .../ExternalServiceTestConfigurator.java | 12 +++++----- .../testing/internal/SDKTestWorkflowRule.java | 2 +- 9 files changed, 28 insertions(+), 45 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0d581a6f..87299800f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,25 +32,25 @@ jobs: - name: Run unit tests (Java 23) env: USER: unittest - USE_DOCKER_SERVICE: false + USE_EXTERNAL_SERVICE: false run: ./gradlew --no-daemon test -x spotlessCheck -x spotlessApply -x spotlessJava -P edgeDepsTest -PtestJavaVersion=23 - name: Run independent resource tuner test env: USER: unittest - USE_DOCKER_SERVICE: false + USE_EXTERNAL_SERVICE: false run: ./gradlew --no-daemon temporal-sdk:testResourceIndependent -x spotlessCheck -x spotlessApply -x spotlessJava -P edgeDepsTest -PtestJavaVersion=23 - name: Run Spring Boot 3 compatibility tests env: USER: unittest - USE_DOCKER_SERVICE: false + USE_EXTERNAL_SERVICE: false run: ./gradlew --no-daemon :temporal-spring-boot-autoconfigure:test -x spotlessCheck -x spotlessApply -x spotlessJava -P edgeDepsTest -P springBoot3Test -PtestJavaVersion=23 - name: Run Spring Boot 4 compatibility tests env: USER: unittest - USE_DOCKER_SERVICE: false + USE_EXTERNAL_SERVICE: false run: ./gradlew --no-daemon :temporal-spring-boot-autoconfigure:test -x spotlessCheck -x spotlessApply -x spotlessJava -P edgeDepsTest -P springBoot4Test -PtestJavaVersion=23 - name: Publish Test Report @@ -125,20 +125,20 @@ jobs: env: USER: unittest TEMPORAL_SERVICE_ADDRESS: localhost:7233 - USE_DOCKER_SERVICE: true + USE_EXTERNAL_SERVICE: true run: ./gradlew --no-daemon test -x spotlessCheck -x spotlessApply -x spotlessJava -PtestJavaVersion=11 - name: Run Jackson 3 converter tests (Java 17) env: USER: unittest - USE_DOCKER_SERVICE: false + USE_EXTERNAL_SERVICE: false run: ./gradlew --no-daemon :temporal-sdk:jackson3Tests -x spotlessCheck -x spotlessApply -x spotlessJava -PtestJavaVersion=17 - name: Run virtual thread tests (Java 21) env: USER: unittest TEMPORAL_SERVICE_ADDRESS: localhost:7233 - USE_DOCKER_SERVICE: true + USE_EXTERNAL_SERVICE: true run: ./gradlew --no-daemon :temporal-sdk:virtualThreadTests -x spotlessCheck -x spotlessApply -x spotlessJava -PtestJavaVersion=21 - name: Publish Test Report diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7c28aad7c..6fb0ea454 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -71,7 +71,7 @@ temporal server start-dev Run the tests that require an external server: ```bash -USE_DOCKER_SERVICE=true ./gradlew test +USE_EXTERNAL_SERVICE=true ./gradlew test ``` ## Note on Rosetta diff --git a/temporal-sdk/src/test/java/io/temporal/activity/ActivityPauseTest.java b/temporal-sdk/src/test/java/io/temporal/activity/ActivityPauseTest.java index fbab79d2c..862b96430 100644 --- a/temporal-sdk/src/test/java/io/temporal/activity/ActivityPauseTest.java +++ b/temporal-sdk/src/test/java/io/temporal/activity/ActivityPauseTest.java @@ -62,6 +62,7 @@ public String execute() { } public static class HeartBeatingActivityImpl implements TestActivities.TestActivity1 { + @Override public String execute(String arg) { ActivityInfo info = Activity.getExecutionContext().getInfo(); diff --git a/temporal-sdk/src/test/java/io/temporal/worker/StickyWorkerTest.java b/temporal-sdk/src/test/java/io/temporal/worker/StickyWorkerTest.java index 508ab585b..f14a207aa 100644 --- a/temporal-sdk/src/test/java/io/temporal/worker/StickyWorkerTest.java +++ b/temporal-sdk/src/test/java/io/temporal/worker/StickyWorkerTest.java @@ -46,32 +46,15 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestName; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@RunWith(Parameterized.class) public class StickyWorkerTest { - private static final boolean useDockerService = - Boolean.parseBoolean(System.getenv("USE_DOCKER_SERVICE")); + private static final boolean useExternalService = + Boolean.parseBoolean(System.getenv("USE_EXTERNAL_SERVICE")); private static final String serviceAddress = System.getenv("TEMPORAL_SERVICE_ADDRESS"); - @Parameterized.Parameter public boolean useExternalService; - - @Parameterized.Parameters(name = "{1}") - public static Object[] data() { - if (!useDockerService) { - return new Object[][] {{false, "TestService"}}; - } else { - return new Object[][] {{true, "Docker"}}; - } - } - - @Parameterized.Parameter(1) - public String testType; - @Rule public TestName testName = new TestName(); private Scope metricsScope; @@ -536,7 +519,6 @@ public TestEnvironmentWrapper(WorkerFactoryOptions options) { .setMetricsScope(metricsScope) .setWorkflowClientOptions(clientOptions) .setWorkerFactoryOptions(options) - .setUseExternalService(useExternalService) .setTarget(serviceAddress) .build(); testEnv = TestWorkflowEnvironment.newInstance(testOptions); diff --git a/temporal-sdk/src/test/java/io/temporal/workerFactory/WorkerFactoryTests.java b/temporal-sdk/src/test/java/io/temporal/workerFactory/WorkerFactoryTests.java index 856ba8dcc..3b7974d45 100644 --- a/temporal-sdk/src/test/java/io/temporal/workerFactory/WorkerFactoryTests.java +++ b/temporal-sdk/src/test/java/io/temporal/workerFactory/WorkerFactoryTests.java @@ -21,13 +21,13 @@ public class WorkerFactoryTests { - private static final boolean useDockerService = - Boolean.parseBoolean(System.getenv("USE_DOCKER_SERVICE")); + private static final boolean useExternalService = + Boolean.parseBoolean(System.getenv("USE_EXTERNAL_SERVICE")); private static final String serviceAddress = System.getenv("TEMPORAL_SERVICE_ADDRESS"); @BeforeClass public static void beforeClass() { - Assume.assumeTrue(useDockerService); + Assume.assumeTrue(useExternalService); } private WorkflowServiceStubs service; diff --git a/temporal-spring-boot-autoconfigure/src/test/java/io/temporal/spring/boot/autoconfigure/WorkerVersioningTest.java b/temporal-spring-boot-autoconfigure/src/test/java/io/temporal/spring/boot/autoconfigure/WorkerVersioningTest.java index 5c0481b4a..70cc4076b 100644 --- a/temporal-spring-boot-autoconfigure/src/test/java/io/temporal/spring/boot/autoconfigure/WorkerVersioningTest.java +++ b/temporal-spring-boot-autoconfigure/src/test/java/io/temporal/spring/boot/autoconfigure/WorkerVersioningTest.java @@ -36,11 +36,11 @@ public class WorkerVersioningTest { @Autowired WorkflowClient workflowClient; @BeforeAll - static void checkDockerService() { - String useDocker = System.getenv("USE_DOCKER_SERVICE"); + static void checkExternalService() { + String useExternal = System.getenv("USE_EXTERNAL_SERVICE"); Assumptions.assumeTrue( - useDocker != null && useDocker.equalsIgnoreCase("true"), - "Skipping tests because USE_DOCKER_SERVICE is not set"); + useExternal != null && useExternal.equalsIgnoreCase("true"), + "Skipping tests because USE_EXTERNAL_SERVICE is not set"); } @BeforeEach diff --git a/temporal-testing/src/main/java/io/temporal/internal/docker/RegisterTestNamespace.java b/temporal-testing/src/main/java/io/temporal/internal/docker/RegisterTestNamespace.java index c58f2e35b..c840adf55 100644 --- a/temporal-testing/src/main/java/io/temporal/internal/docker/RegisterTestNamespace.java +++ b/temporal-testing/src/main/java/io/temporal/internal/docker/RegisterTestNamespace.java @@ -13,12 +13,12 @@ /** Waits for local service to become available and registers UnitTest namespace. */ public class RegisterTestNamespace { public static final String NAMESPACE = "UnitTest"; - private static final boolean useDockerService = - Boolean.parseBoolean(System.getenv("USE_DOCKER_SERVICE")); + private static final boolean useExternalService = + Boolean.parseBoolean(System.getenv("USE_EXTERNAL_SERVICE")); private static final String serviceAddress = System.getenv("TEMPORAL_SERVICE_ADDRESS"); public static void main(String[] args) throws InterruptedException { - if (!useDockerService) { + if (!useExternalService) { return; } diff --git a/temporal-testing/src/main/java/io/temporal/testing/internal/ExternalServiceTestConfigurator.java b/temporal-testing/src/main/java/io/temporal/testing/internal/ExternalServiceTestConfigurator.java index fdcc32235..b81a9d363 100644 --- a/temporal-testing/src/main/java/io/temporal/testing/internal/ExternalServiceTestConfigurator.java +++ b/temporal-testing/src/main/java/io/temporal/testing/internal/ExternalServiceTestConfigurator.java @@ -5,15 +5,15 @@ import io.temporal.testing.TestWorkflowRule; public class ExternalServiceTestConfigurator { - private static boolean USE_DOCKER_SERVICE = - EnvironmentVariableUtils.readBooleanFlag("USE_DOCKER_SERVICE"); + private static boolean USE_EXTERNAL_SERVICE = + EnvironmentVariableUtils.readBooleanFlag("USE_EXTERNAL_SERVICE"); private static String TEMPORAL_SERVICE_ADDRESS = EnvironmentVariableUtils.readString("TEMPORAL_SERVICE_ADDRESS"); private static boolean USE_VIRTUAL_THREADS = EnvironmentVariableUtils.readBooleanFlag("USE_VIRTUAL_THREADS"); public static boolean isUseExternalService() { - return USE_DOCKER_SERVICE; + return USE_EXTERNAL_SERVICE; } public static boolean isUseVirtualThreads() { @@ -21,13 +21,13 @@ public static boolean isUseVirtualThreads() { } public static String getTemporalServiceAddress() { - return USE_DOCKER_SERVICE + return USE_EXTERNAL_SERVICE ? (TEMPORAL_SERVICE_ADDRESS != null ? TEMPORAL_SERVICE_ADDRESS : "127.0.0.1:7233") : null; } public static TestWorkflowRule.Builder configure(TestWorkflowRule.Builder testWorkflowRule) { - if (USE_DOCKER_SERVICE) { + if (USE_EXTERNAL_SERVICE) { testWorkflowRule.setUseExternalService(true); if (TEMPORAL_SERVICE_ADDRESS != null) { testWorkflowRule.setTarget(TEMPORAL_SERVICE_ADDRESS); @@ -38,7 +38,7 @@ public static TestWorkflowRule.Builder configure(TestWorkflowRule.Builder testWo public static TestEnvironmentOptions.Builder configure( TestEnvironmentOptions.Builder testEnvironmentOptions) { - if (USE_DOCKER_SERVICE) { + if (USE_EXTERNAL_SERVICE) { testEnvironmentOptions.setUseExternalService(true); if (TEMPORAL_SERVICE_ADDRESS != null) { testEnvironmentOptions.setTarget(TEMPORAL_SERVICE_ADDRESS); diff --git a/temporal-testing/src/main/java/io/temporal/testing/internal/SDKTestWorkflowRule.java b/temporal-testing/src/main/java/io/temporal/testing/internal/SDKTestWorkflowRule.java index 48a00afc4..e88a7ec3d 100644 --- a/temporal-testing/src/main/java/io/temporal/testing/internal/SDKTestWorkflowRule.java +++ b/temporal-testing/src/main/java/io/temporal/testing/internal/SDKTestWorkflowRule.java @@ -64,7 +64,7 @@ public class SDKTestWorkflowRule implements TestRule { "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; // Enable to regenerate JsonFiles used for replay testing. public static final boolean REGENERATE_JSON_FILES = false; - // Only enable when USE_DOCKER_SERVICE is true + // Only enable when USE_EXTERNAL_SERVICE is true public static final boolean useExternalService = ExternalServiceTestConfigurator.isUseExternalService(); public static final boolean USE_VIRTUAL_THREADS = From 06e992ed33083dc000eaaf457b0b46533d4c5fd1 Mon Sep 17 00:00:00 2001 From: Dan Plyukhin Date: Fri, 8 May 2026 10:49:12 -0500 Subject: [PATCH 4/4] Use Quinn's suggestion to clarify CONTRIBUTING.md --- CONTRIBUTING.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6fb0ea454..f3e646ac3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,14 +62,15 @@ Run a single test or group of tests: ./gradlew :temporal-sdk:test --offline --tests "io.temporal.workflow.*" ``` -By default, tests run against an built-in test server that starts automatically. But some tests require a real temporal server and will be skipped. You can run an external server locally with the [temporal CLI](https://docs.temporal.io/cli#installation): +By default, integration tests run against the built-in time-skipping test server. Some tests require features that the built-in server doesn't support; those tests will be skipped. To run the skipped tests: +1. Install the [temporal CLI](https://docs.temporal.io/cli#installation), which comes with a built-in dev server. +2. Find the flags that the dev server will need to run the tests by grepping for `temporal server` in [./github/workflows/ci.yml](./github/workflows/ci.yml). +3. Start the server: ```bash -temporal server start-dev +temporal server start-dev --YOUR-FLAGS-HERE ``` - -Run the tests that require an external server: - +4. Set the `USE_EXTERNAL_SERVICE` environment variable and run the tests: ```bash USE_EXTERNAL_SERVICE=true ./gradlew test ```