From ec11fccb90114a55b6b948df937be2cf02ed9f35 Mon Sep 17 00:00:00 2001 From: Baekgyu Date: Wed, 21 Oct 2026 22:07:31 +0900 Subject: [PATCH] Allow custom task queues in TestWorkflowExtension --- CHANGELOG.md | 2 + .../testing/TestWorkflowExtension.java | 28 ++++++- .../TestWorkflowExtensionTaskQueueTest.java | 79 +++++++++++++++++++ .../junit5/TestWorkflowExtensionTest.java | 3 +- 4 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 temporal-testing/src/test/java/io/temporal/testing/junit5/TestWorkflowExtensionTaskQueueTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index dbc9d1e623..5908c9a7d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ to docs, or any other relevant information. `WorkflowOutboundCallsInterceptorBase` need to add them, and Base subclasses override them to see calls with options. ### Added +- `TestWorkflowExtension.Builder.setWorkerTaskQueue` lets tests specify a custom worker task queue. + When unset or `null`, the extension continues to generate a task queue name for each test. - Applications can use the experimental `@TransferTypeConvertible` annotation and `TransferTypeConverter` interface to convert top-level model values to transfer types. The SDK applies this conversion to workflow, activity, Nexus, and schedule payloads, including failure diff --git a/temporal-testing/src/main/java/io/temporal/testing/TestWorkflowExtension.java b/temporal-testing/src/main/java/io/temporal/testing/TestWorkflowExtension.java index c06edaabb6..5e4465de60 100644 --- a/temporal-testing/src/main/java/io/temporal/testing/TestWorkflowExtension.java +++ b/temporal-testing/src/main/java/io/temporal/testing/TestWorkflowExtension.java @@ -23,6 +23,7 @@ import java.time.Instant; import java.util.*; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.junit.jupiter.api.extension.AfterEachCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; @@ -79,6 +80,7 @@ private enum ServiceType { private static final String NEXUS_ENDPOINT_KEY = "nexusEndpoint"; private final WorkerOptions workerOptions; + private final String workerTaskQueue; private final WorkflowClientOptions workflowClientOptions; private final ActivityClientOptions activityClientOptions; private final WorkerFactoryOptions workerFactoryOptions; @@ -100,6 +102,7 @@ private enum ServiceType { private TestWorkflowExtension(Builder builder) { workerOptions = builder.workerOptions; + workerTaskQueue = builder.workerTaskQueue; if (builder.workflowClientOptions != null) { workflowClientOptions = builder.workflowClientOptions; } else { @@ -214,7 +217,10 @@ public void beforeEach(ExtensionContext context) { try { String taskQueue = - String.format("WorkflowTest-%s-%s", context.getDisplayName(), context.getUniqueId()); + workerTaskQueue != null + ? workerTaskQueue + : String.format( + "WorkflowTest-%s-%s", context.getDisplayName(), context.getUniqueId()); String nexusEndpointName = String.format("WorkflowTestNexusEndpoint-%s", UUID.randomUUID()); boolean createNexusEndpoint = !doNotSetupNexusEndpoint && nexusServiceImplementations.length > 0; @@ -327,6 +333,7 @@ public static class Builder { private static final Object[] NO_NEXUS_SERVICES = new Object[0]; private WorkerOptions workerOptions = WorkerOptions.getDefaultInstance(); + private String workerTaskQueue; private WorkflowClientOptions workflowClientOptions; private ActivityClientOptions activityClientOptions; private WorkerFactoryOptions workerFactoryOptions; @@ -357,6 +364,25 @@ public Builder setWorkerOptions(WorkerOptions options) { return this; } + /** + * Sets the task queue used by the worker, injected workflow stubs and {@link WorkflowOptions}, + * and any automatically created Nexus endpoint. If unset or {@code null}, a task queue name is + * generated for each test. + * + *

When using an external service, avoid sharing the same task queue across parallel tests in + * the same namespace, as their workers may process each other's tasks. + * + * @param workerTaskQueue task queue name, or {@code null} to use a generated name. + * @throws IllegalArgumentException if the task queue name is empty. + */ + public Builder setWorkerTaskQueue(@Nullable String workerTaskQueue) { + if (workerTaskQueue != null && workerTaskQueue.isEmpty()) { + throw new IllegalArgumentException("workerTaskQueue should not be an empty string"); + } + this.workerTaskQueue = workerTaskQueue; + return this; + } + /** * Override {@link WorkflowClientOptions} for test environment. If set, takes precedence over * {@link #setNamespace(String) namespace}. diff --git a/temporal-testing/src/test/java/io/temporal/testing/junit5/TestWorkflowExtensionTaskQueueTest.java b/temporal-testing/src/test/java/io/temporal/testing/junit5/TestWorkflowExtensionTaskQueueTest.java new file mode 100644 index 0000000000..1e3320c986 --- /dev/null +++ b/temporal-testing/src/test/java/io/temporal/testing/junit5/TestWorkflowExtensionTaskQueueTest.java @@ -0,0 +1,79 @@ +package io.temporal.testing.junit5; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.testing.junit5.TestWorkflowExtensionTest.HelloActivityImpl; +import io.temporal.testing.junit5.TestWorkflowExtensionTest.HelloWorkflow; +import io.temporal.testing.junit5.TestWorkflowExtensionTest.HelloWorkflowImpl; +import io.temporal.testing.junit5.TestWorkflowExtensionTest.TestNexusServiceImpl; +import io.temporal.worker.Worker; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.api.extension.RegisterExtension; + +@Timeout(value = 30, unit = TimeUnit.SECONDS) +public class TestWorkflowExtensionTaskQueueTest { + + @Test + public void rejectsEmptyTaskQueue() { + assertThrows( + IllegalArgumentException.class, + () -> TestWorkflowExtension.newBuilder().setWorkerTaskQueue("")); + } + + @Nested + class CustomTaskQueue { + @RegisterExtension + final TestWorkflowExtension extension = + TestWorkflowExtension.newBuilder() + .setWorkerTaskQueue("expense-category") + .registerWorkflowImplementationTypes(HelloWorkflowImpl.class) + .setActivityImplementations(new HelloActivityImpl()) + .setNexusServiceImplementation(new TestNexusServiceImpl()) + .build(); + + @Test + void usesCustomTaskQueue( + Worker worker, + WorkflowOptions options, + WorkflowClient client, + HelloWorkflow injectedWorkflow) { + assertEquals("expense-category", worker.getTaskQueue()); + assertEquals("expense-category", options.getTaskQueue()); + assertEquals( + "Hello Injected from activity BuildGreeting and workflow HelloWorkflow", + injectedWorkflow.sayHello("Injected")); + + HelloWorkflow workflow = + client.newWorkflowStub( + HelloWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue("expense-category").build()); + assertEquals( + "Hello Client from activity BuildGreeting and workflow HelloWorkflow", + workflow.sayHello("Client")); + } + } + + @Nested + class NullTaskQueue { + @RegisterExtension + final TestWorkflowExtension extension = + TestWorkflowExtension.newBuilder() + .setWorkerTaskQueue("expense-category") + .setWorkerTaskQueue(null) + .build(); + + @Test + void restoresGeneratedTaskQueue(Worker worker, WorkflowOptions options) { + assertTrue(worker.getTaskQueue().startsWith("WorkflowTest-")); + assertEquals(worker.getTaskQueue(), options.getTaskQueue()); + } + } +} diff --git a/temporal-testing/src/test/java/io/temporal/testing/junit5/TestWorkflowExtensionTest.java b/temporal-testing/src/test/java/io/temporal/testing/junit5/TestWorkflowExtensionTest.java index 9da6156bb9..336d9fd2ca 100644 --- a/temporal-testing/src/test/java/io/temporal/testing/junit5/TestWorkflowExtensionTest.java +++ b/temporal-testing/src/test/java/io/temporal/testing/junit5/TestWorkflowExtensionTest.java @@ -120,7 +120,8 @@ public void extensionShouldLaunchTestEnvironmentAndResolveParameters( () -> assertTrue(testEnv.isStarted()), () -> assertNotNull(workflowClient), () -> assertNotNull(activityClient), - () -> assertNotNull(workflowOptions.getTaskQueue()), + () -> assertTrue(workflowOptions.getTaskQueue().startsWith("WorkflowTest-")), + () -> assertEquals(worker.getTaskQueue(), workflowOptions.getTaskQueue()), () -> assertNotNull(worker), () -> assertEquals(