Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
*
* <p>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}.
Expand Down
Original file line number Diff line number Diff line change
@@ -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());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading