diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6eac7d64b..e3a085782 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,8 +8,8 @@ jobs: name: "Gradle wrapper validation" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: gradle/wrapper-validation-action@v3 + - uses: actions/checkout@v6 + - uses: gradle/actions/wrapper-validation@v5 unittest: name: Unit Tests diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java index be1cc788e..f207d64cf 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/CallerStarter.java @@ -4,7 +4,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.samples.nexus.options.ClientOptions; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,11 +26,12 @@ public static void main(String[] args) { logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo πŸ‘‹")); HelloCallerWorkflow helloWorkflow = client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions); - execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", NexusService.Language.EN); + execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", SampleNexusService.Language.EN); logger.info( "Started HelloCallerWorkflow workflowId: {} runId: {}", execution.getWorkflowId(), execution.getRunId()); - logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES)); + logger.info( + "Workflow result: {}", helloWorkflow.hello("Nexus", SampleNexusService.Language.ES)); } } diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java index 55186489e..5480917ba 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/CallerWorker.java @@ -21,7 +21,7 @@ public static void main(String[] args) { WorkflowImplementationOptions.newBuilder() .setNexusServiceOptions( Collections.singletonMap( - "NexusService", + "SampleNexusService", NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build())) .build(), EchoCallerWorkflowImpl.class, diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java index 948008772..f76edbfe4 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/EchoCallerWorkflowImpl.java @@ -1,15 +1,15 @@ package io.temporal.samples.nexus.caller; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.NexusOperationOptions; import io.temporal.workflow.NexusServiceOptions; import io.temporal.workflow.Workflow; import java.time.Duration; public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { - NexusService nexusService = + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -19,6 +19,6 @@ public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { @Override public String echo(String message) { - return nexusService.echo(new NexusService.EchoInput(message)).getMessage(); + return sampleNexusService.echo(new SampleNexusService.EchoInput(message)).getMessage(); } } diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java index 173c0be8b..1f78e9c02 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflow.java @@ -1,11 +1,11 @@ package io.temporal.samples.nexus.caller; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; @WorkflowInterface public interface HelloCallerWorkflow { @WorkflowMethod - String hello(String message, NexusService.Language language); + String hello(String message, SampleNexusService.Language language); } diff --git a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java index f1612e359..6a6fe8dce 100644 --- a/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/caller/HelloCallerWorkflowImpl.java @@ -1,6 +1,6 @@ package io.temporal.samples.nexus.caller; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.NexusOperationHandle; import io.temporal.workflow.NexusOperationOptions; import io.temporal.workflow.NexusServiceOptions; @@ -8,9 +8,9 @@ import java.time.Duration; public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { - NexusService nexusService = + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -19,10 +19,10 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { .build()); @Override - public String hello(String message, NexusService.Language language) { - NexusOperationHandle handle = + public String hello(String message, SampleNexusService.Language language) { + NexusOperationHandle handle = Workflow.startNexusOperation( - nexusService::hello, new NexusService.HelloInput(message, language)); + sampleNexusService::hello, new SampleNexusService.HelloInput(message, language)); // Optionally wait for the operation to be started. NexusOperationExecution will contain the // operation token in case this operation is asynchronous. handle.getExecution().get(); diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/EchoClient.java b/core/src/main/java/io/temporal/samples/nexus/handler/EchoClient.java new file mode 100644 index 000000000..74b6f6c69 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/handler/EchoClient.java @@ -0,0 +1,7 @@ +package io.temporal.samples.nexus.handler; + +import io.temporal.samples.nexus.service.SampleNexusService; + +public interface EchoClient { + SampleNexusService.EchoOutput echo(SampleNexusService.EchoInput input); +} diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/EchoClientImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/EchoClientImpl.java new file mode 100644 index 000000000..1c9a2e524 --- /dev/null +++ b/core/src/main/java/io/temporal/samples/nexus/handler/EchoClientImpl.java @@ -0,0 +1,12 @@ +package io.temporal.samples.nexus.handler; + +import io.temporal.samples.nexus.service.SampleNexusService; + +// Note that this is a class, not a Temporal worker. This is to demonstrate that Nexus services can +// simply call a class instead of a worker for fast operations that don't need retry handling. +public class EchoClientImpl implements EchoClient { + @Override + public SampleNexusService.EchoOutput echo(SampleNexusService.EchoInput input) { + return new SampleNexusService.EchoOutput(input.getMessage()); + } +} diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java index 3d8afa3d7..656b18c65 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/HandlerWorker.java @@ -15,7 +15,7 @@ public static void main(String[] args) { Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class); - worker.registerNexusServiceImplementation(new NexusServiceImpl()); + worker.registerNexusServiceImplementation(new SampleNexusServiceImpl()); factory.start(); } diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java index 3cae13b31..2c85d0792 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflow.java @@ -1,11 +1,11 @@ package io.temporal.samples.nexus.handler; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; @WorkflowInterface public interface HelloHandlerWorkflow { @WorkflowMethod - NexusService.HelloOutput hello(NexusService.HelloInput input); + SampleNexusService.HelloOutput hello(SampleNexusService.HelloInput input); } diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java index c897a5181..b896ab523 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/HelloHandlerWorkflowImpl.java @@ -1,22 +1,22 @@ package io.temporal.samples.nexus.handler; import io.temporal.failure.ApplicationFailure; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow { @Override - public NexusService.HelloOutput hello(NexusService.HelloInput input) { + public SampleNexusService.HelloOutput hello(SampleNexusService.HelloInput input) { switch (input.getLanguage()) { case EN: - return new NexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); case FR: - return new NexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); case DE: - return new NexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); case ES: - return new NexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); case TR: - return new NexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); } throw ApplicationFailure.newFailure( "Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE"); diff --git a/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexus/handler/SampleNexusServiceImpl.java similarity index 62% rename from core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java rename to core/src/main/java/io/temporal/samples/nexus/handler/SampleNexusServiceImpl.java index 2344f27ec..42952b72b 100644 --- a/core/src/main/java/io/temporal/samples/nexus/handler/NexusServiceImpl.java +++ b/core/src/main/java/io/temporal/samples/nexus/handler/SampleNexusServiceImpl.java @@ -6,27 +6,43 @@ import io.temporal.client.WorkflowOptions; import io.temporal.nexus.Nexus; import io.temporal.nexus.WorkflowRunOperation; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; // To create a service implementation, annotate the class with @ServiceImpl and provide the // interface that the service implements. The service implementation class should have methods that // return OperationHandler that correspond to the operations defined in the service interface. -@ServiceImpl(service = NexusService.class) -public class NexusServiceImpl { +@ServiceImpl(service = SampleNexusService.class) +public class SampleNexusServiceImpl { + private final EchoClient echoClient; + + // The injected EchoClient makes this class unit-testable. + // The no-arg constructor provides a default; the second allows tests to inject a mock. + // If you are not using the sync call or do not need to mock a handler, then you will not + // need this constructor pairing. + public SampleNexusServiceImpl() { + this(new EchoClientImpl()); + } + + public SampleNexusServiceImpl(EchoClient echoClient) { + this.echoClient = echoClient; + } + + // The Echo Nexus Service exemplifies making a synchronous call using OperationHandler.sync. + // In this case, it is calling the EchoClient class - not a workflow - and simply returning the + // result. @OperationImpl - public OperationHandler echo() { - // OperationHandler.sync is a meant for exposing simple RPC handlers. + public OperationHandler echo() { return OperationHandler.sync( // The method is for making arbitrary short calls to other services or databases, or // perform simple computations such as this one. Users can also access a workflow client by // calling // Nexus.getOperationContext().getWorkflowClient(ctx) to make arbitrary calls such as // signaling, querying, or listing workflows. - (ctx, details, input) -> new NexusService.EchoOutput(input.getMessage())); + (ctx, details, input) -> echoClient.echo(input)); } @OperationImpl - public OperationHandler hello() { + public OperationHandler hello() { // Use the WorkflowRunOperation.fromWorkflowMethod constructor, which is the easiest // way to expose a workflow as an operation. To expose a workflow with a different input // parameters then the operation or from an untyped stub, use the @@ -39,10 +55,8 @@ public OperationHandler hello .newWorkflowStub( HelloHandlerWorkflow.class, // Workflow IDs should typically be business meaningful IDs and are used to - // dedupe workflow starts. - // For this example, we're using the request ID allocated by Temporal when - // the - // caller workflow schedules + // dedupe workflow starts. For this example, we're using the request ID + // allocated by Temporal when the caller workflow schedules // the operation, this ID is guaranteed to be stable across retries of this // operation. // diff --git a/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java b/core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java similarity index 97% rename from core/src/main/java/io/temporal/samples/nexus/service/NexusService.java rename to core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java index ad65b1b33..180f9ec28 100644 --- a/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java +++ b/core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java @@ -6,7 +6,7 @@ import io.nexusrpc.Service; @Service -public interface NexusService { +public interface SampleNexusService { enum Language { EN, FR, diff --git a/core/src/main/java/io/temporal/samples/nexus/service/description.md b/core/src/main/java/io/temporal/samples/nexus/service/description.md index d79e151cd..b1cafb3a2 100644 --- a/core/src/main/java/io/temporal/samples/nexus/service/description.md +++ b/core/src/main/java/io/temporal/samples/nexus/service/description.md @@ -1,6 +1,6 @@ -## Service: [NexusService](https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java) +## Service: [SampleNexusService](https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java) - operation: `echo` - operation: `hello` -See https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/NexusService.java for Input / Output types. +See https://github.com/temporalio/samples-java/blob/main/core/src/main/java/io/temporal/samples/nexus/service/SampleNexusService.java for Input / Output types. diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java index cb05189cf..811cecde8 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/CallerWorker.java @@ -2,7 +2,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.samples.nexus.options.ClientOptions; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; import io.temporal.worker.WorkflowImplementationOptions; @@ -22,7 +22,7 @@ public static void main(String[] args) { WorkflowImplementationOptions.newBuilder() .setNexusServiceOptions( Collections.singletonMap( - NexusService.class.getSimpleName(), + SampleNexusService.class.getSimpleName(), NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build())) .build(), HelloCallerWorkflowImpl.class); diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java index 1bea801c8..6072906b4 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/caller/HelloCallerWorkflowImpl.java @@ -1,10 +1,10 @@ package io.temporal.samples.nexuscancellation.caller; -import static io.temporal.samples.nexus.service.NexusService.Language.*; +import static io.temporal.samples.nexus.service.SampleNexusService.Language.*; import io.temporal.failure.CanceledFailure; import io.temporal.failure.NexusOperationFailure; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.*; import java.time.Duration; import java.util.ArrayList; @@ -13,11 +13,11 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { public static final Logger log = Workflow.getLogger(HelloCallerWorkflowImpl.class); - private static final NexusService.Language[] languages = - new NexusService.Language[] {EN, FR, DE, ES, TR}; - NexusService nexusService = + private static final SampleNexusService.Language[] languages = + new SampleNexusService.Language[] {EN, FR, DE, ES, TR}; + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -33,7 +33,7 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { @Override public String hello(String message) { - List> results = new ArrayList<>(languages.length); + List> results = new ArrayList<>(languages.length); /* * Create our CancellationScope. Within this scope we call the nexus operation asynchronously @@ -42,10 +42,11 @@ public String hello(String message) { CancellationScope scope = Workflow.newCancellationScope( () -> { - for (NexusService.Language language : languages) { + for (SampleNexusService.Language language : languages) { results.add( Async.function( - nexusService::hello, new NexusService.HelloInput(message, language))); + sampleNexusService::hello, + new SampleNexusService.HelloInput(message, language))); } }); @@ -56,7 +57,7 @@ public String hello(String message) { scope.run(); // We use "anyOf" here to wait for one of the nexus operation invocations to return - NexusService.HelloOutput result = Promise.anyOf(results).get(); + SampleNexusService.HelloOutput result = Promise.anyOf(results).get(); // Trigger cancellation of all uncompleted nexus operations invocations within the cancellation // scope @@ -67,7 +68,7 @@ public String hello(String message) { // Note: Once the workflow completes any pending cancellation requests are dropped by the // server. In general, it is a good practice to wait for all cancellation requests to be // processed before completing the workflow. - for (Promise promise : results) { + for (Promise promise : results) { try { promise.get(); } catch (NexusOperationFailure e) { diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java index 8b8949a70..f7d0f6940 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HandlerWorker.java @@ -1,7 +1,7 @@ package io.temporal.samples.nexuscancellation.handler; import io.temporal.client.WorkflowClient; -import io.temporal.samples.nexus.handler.NexusServiceImpl; +import io.temporal.samples.nexus.handler.SampleNexusServiceImpl; import io.temporal.samples.nexus.options.ClientOptions; import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactory; @@ -16,7 +16,7 @@ public static void main(String[] args) { Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class); - worker.registerNexusServiceImplementation(new NexusServiceImpl()); + worker.registerNexusServiceImplementation(new SampleNexusServiceImpl()); factory.start(); } diff --git a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java index ca6510f60..de8b93557 100644 --- a/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscancellation/handler/HelloHandlerWorkflowImpl.java @@ -3,7 +3,7 @@ import io.temporal.failure.ApplicationFailure; import io.temporal.failure.CanceledFailure; import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.Workflow; import java.time.Duration; import org.slf4j.Logger; @@ -12,21 +12,21 @@ public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow { public static final Logger log = Workflow.getLogger(HelloHandlerWorkflowImpl.class); @Override - public NexusService.HelloOutput hello(NexusService.HelloInput input) { + public SampleNexusService.HelloOutput hello(SampleNexusService.HelloInput input) { // Sleep for a random duration to simulate some work try { Workflow.sleep(Duration.ofSeconds(Workflow.newRandom().nextInt(5))); switch (input.getLanguage()) { case EN: - return new NexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); case FR: - return new NexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); case DE: - return new NexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); case ES: - return new NexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); case TR: - return new NexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); } throw ApplicationFailure.newFailure( "Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE"); diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD index 79453cc4d..54e2bc4f9 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/README.MD @@ -40,6 +40,6 @@ INFO i.t.s.n.caller.CallerStarter - Workflow result: Hello Nexus πŸ‘‹ And this on the handler side: ``` -INFO i.t.s.n.handler.NexusServiceImpl - Echo called from a workflow with ID : 7ac97cb9-b457-4052-af94-d82478c35c5e +INFO i.t.s.n.handler.SampleNexusServiceImpl - Echo called from a workflow with ID : 7ac97cb9-b457-4052-af94-d82478c35c5e INFO i.t.s.n.h.HelloHandlerWorkflowImpl - HelloHandlerWorkflow called from a workflow with ID : 9e0bc89c-5709-4742-b7c0-868464c2fccf ``` diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java index f0896221a..cfcc739de 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerStarter.java @@ -7,7 +7,7 @@ import io.temporal.samples.nexus.caller.EchoCallerWorkflow; import io.temporal.samples.nexus.caller.HelloCallerWorkflow; import io.temporal.samples.nexus.options.ClientOptions; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.samples.nexuscontextpropagation.propagation.MDCContextPropagator; import java.util.Collections; import org.slf4j.Logger; @@ -35,11 +35,12 @@ public static void main(String[] args) { logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo πŸ‘‹")); HelloCallerWorkflow helloWorkflow = client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions); - execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", NexusService.Language.EN); + execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", SampleNexusService.Language.EN); logger.info( "Started HelloCallerWorkflow workflowId: {} runId: {}", execution.getWorkflowId(), execution.getRunId()); - logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES)); + logger.info( + "Workflow result: {}", helloWorkflow.hello("Nexus", SampleNexusService.Language.ES)); } } diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java index 13e568822..db3f1cfb9 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/CallerWorker.java @@ -28,7 +28,7 @@ public static void main(String[] args) { WorkflowImplementationOptions.newBuilder() .setNexusServiceOptions( Collections.singletonMap( - "NexusService", + "SampleNexusService", NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build())) .build(), EchoCallerWorkflowImpl.class, diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java index 14e998629..3de27350d 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/EchoCallerWorkflowImpl.java @@ -1,7 +1,7 @@ package io.temporal.samples.nexuscontextpropagation.caller; import io.temporal.samples.nexus.caller.EchoCallerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.NexusOperationOptions; import io.temporal.workflow.NexusServiceOptions; import io.temporal.workflow.Workflow; @@ -9,9 +9,9 @@ import org.slf4j.MDC; public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { - NexusService nexusService = + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -22,6 +22,6 @@ public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { @Override public String echo(String message) { MDC.put("x-nexus-caller-workflow-id", Workflow.getInfo().getWorkflowId()); - return nexusService.echo(new NexusService.EchoInput(message)).getMessage(); + return sampleNexusService.echo(new SampleNexusService.EchoInput(message)).getMessage(); } } diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java index fedefbc34..b817179a4 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/caller/HelloCallerWorkflowImpl.java @@ -1,7 +1,7 @@ package io.temporal.samples.nexuscontextpropagation.caller; import io.temporal.samples.nexus.caller.HelloCallerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.NexusOperationHandle; import io.temporal.workflow.NexusOperationOptions; import io.temporal.workflow.NexusServiceOptions; @@ -10,9 +10,9 @@ import org.slf4j.MDC; public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { - NexusService nexusService = + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -21,11 +21,11 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { .build()); @Override - public String hello(String message, NexusService.Language language) { + public String hello(String message, SampleNexusService.Language language) { MDC.put("x-nexus-caller-workflow-id", Workflow.getInfo().getWorkflowId()); - NexusOperationHandle handle = + NexusOperationHandle handle = Workflow.startNexusOperation( - nexusService::hello, new NexusService.HelloInput(message, language)); + sampleNexusService::hello, new SampleNexusService.HelloInput(message, language)); // Optionally wait for the operation to be started. NexusOperationExecution will contain the // operation token in case this operation is asynchronous. handle.getExecution().get(); diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java index c4f9ef54c..31b665a8a 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HandlerWorker.java @@ -29,7 +29,7 @@ public static void main(String[] args) { Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class); - worker.registerNexusServiceImplementation(new NexusServiceImpl()); + worker.registerNexusServiceImplementation(new SampleNexusServiceImpl()); factory.start(); } diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java index a2db3cb0e..324ad34c1 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/HelloHandlerWorkflowImpl.java @@ -2,7 +2,7 @@ import io.temporal.failure.ApplicationFailure; import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.Workflow; import org.slf4j.Logger; import org.slf4j.MDC; @@ -11,7 +11,7 @@ public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow { public static final Logger log = Workflow.getLogger(HelloHandlerWorkflowImpl.class); @Override - public NexusService.HelloOutput hello(NexusService.HelloInput input) { + public SampleNexusService.HelloOutput hello(SampleNexusService.HelloInput input) { if (MDC.get("x-nexus-caller-workflow-id") != null) { log.info( "HelloHandlerWorkflow called from a workflow with ID : {}", @@ -19,15 +19,15 @@ public NexusService.HelloOutput hello(NexusService.HelloInput input) { } switch (input.getLanguage()) { case EN: - return new NexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hello " + input.getName() + " πŸ‘‹"); case FR: - return new NexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Bonjour " + input.getName() + " πŸ‘‹"); case DE: - return new NexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hallo " + input.getName() + " πŸ‘‹"); case ES: - return new NexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Β‘Hola! " + input.getName() + " πŸ‘‹"); case TR: - return new NexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Merhaba " + input.getName() + " πŸ‘‹"); } throw ApplicationFailure.newFailure( "Unsupported language: " + input.getLanguage(), "UNSUPPORTED_LANGUAGE"); diff --git a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/SampleNexusServiceImpl.java similarity index 84% rename from core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java rename to core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/SampleNexusServiceImpl.java index 4977ff0c0..fc69e756b 100644 --- a/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/NexusServiceImpl.java +++ b/core/src/main/java/io/temporal/samples/nexuscontextpropagation/handler/SampleNexusServiceImpl.java @@ -7,7 +7,7 @@ import io.temporal.nexus.Nexus; import io.temporal.nexus.WorkflowRunOperation; import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; @@ -15,12 +15,12 @@ // To create a service implementation, annotate the class with @ServiceImpl and provide the // interface that the service implements. The service implementation class should have methods that // return OperationHandler that correspond to the operations defined in the service interface. -@ServiceImpl(service = NexusService.class) -public class NexusServiceImpl { - private static final Logger logger = LoggerFactory.getLogger(NexusServiceImpl.class); +@ServiceImpl(service = SampleNexusService.class) +public class SampleNexusServiceImpl { + private static final Logger logger = LoggerFactory.getLogger(SampleNexusServiceImpl.class); @OperationImpl - public OperationHandler echo() { + public OperationHandler echo() { // OperationHandler.sync is a meant for exposing simple RPC handlers. return OperationHandler.sync( // The method is for making arbitrary short calls to other services or databases, or @@ -33,12 +33,12 @@ public OperationHandler echo() logger.info( "Echo called from a workflow with ID : {}", MDC.get("x-nexus-caller-workflow-id")); } - return new NexusService.EchoOutput(input.getMessage()); + return new SampleNexusService.EchoOutput(input.getMessage()); }); } @OperationImpl - public OperationHandler hello() { + public OperationHandler hello() { // Use the WorkflowRunOperation.fromWorkflowMethod constructor, which is the easiest // way to expose a workflow as an operation. To expose a workflow with a different input // parameters then the operation or from an untyped stub, use the diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java index beebdf406..4d3e7cff5 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerStarter.java @@ -7,7 +7,7 @@ import io.temporal.samples.nexus.caller.EchoCallerWorkflow; import io.temporal.samples.nexus.caller.HelloCallerWorkflow; import io.temporal.samples.nexus.options.ClientOptions; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,11 +29,12 @@ public static void main(String[] args) { logger.info("Workflow result: {}", echoWorkflow.echo("Nexus Echo πŸ‘‹")); HelloCallerWorkflow helloWorkflow = client.newWorkflowStub(HelloCallerWorkflow.class, workflowOptions); - execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", NexusService.Language.EN); + execution = WorkflowClient.start(helloWorkflow::hello, "Nexus", SampleNexusService.Language.EN); logger.info( "Started HelloCallerWorkflow workflowId: {} runId: {}", execution.getWorkflowId(), execution.getRunId()); - logger.info("Workflow result: {}", helloWorkflow.hello("Nexus", NexusService.Language.ES)); + logger.info( + "Workflow result: {}", helloWorkflow.hello("Nexus", SampleNexusService.Language.ES)); } } diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java index 1db03a677..64272e6a2 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/CallerWorker.java @@ -21,7 +21,7 @@ public static void main(String[] args) { WorkflowImplementationOptions.newBuilder() .setNexusServiceOptions( Collections.singletonMap( - "NexusService", + "SampleNexusService", NexusServiceOptions.newBuilder().setEndpoint("my-nexus-endpoint-name").build())) .build(), EchoCallerWorkflowImpl.class, diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java index ea9aaabb0..20d875ddb 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/EchoCallerWorkflowImpl.java @@ -1,16 +1,16 @@ package io.temporal.samples.nexusmultipleargs.caller; import io.temporal.samples.nexus.caller.EchoCallerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.NexusOperationOptions; import io.temporal.workflow.NexusServiceOptions; import io.temporal.workflow.Workflow; import java.time.Duration; public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { - NexusService nexusService = + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -20,6 +20,6 @@ public class EchoCallerWorkflowImpl implements EchoCallerWorkflow { @Override public String echo(String message) { - return nexusService.echo(new NexusService.EchoInput(message)).getMessage(); + return sampleNexusService.echo(new SampleNexusService.EchoInput(message)).getMessage(); } } diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java index aeb7a13db..03a8635ed 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflow.java @@ -1,11 +1,11 @@ package io.temporal.samples.nexusmultipleargs.caller; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; @WorkflowInterface public interface HelloCallerWorkflow { @WorkflowMethod - String hello(String message, NexusService.Language language); + String hello(String message, SampleNexusService.Language language); } diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java index 94f4c3fc5..5d3c0824b 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/caller/HelloCallerWorkflowImpl.java @@ -1,7 +1,7 @@ package io.temporal.samples.nexusmultipleargs.caller; import io.temporal.samples.nexus.caller.HelloCallerWorkflow; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.NexusOperationHandle; import io.temporal.workflow.NexusOperationOptions; import io.temporal.workflow.NexusServiceOptions; @@ -9,9 +9,9 @@ import java.time.Duration; public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { - NexusService nexusService = + SampleNexusService sampleNexusService = Workflow.newNexusServiceStub( - NexusService.class, + SampleNexusService.class, NexusServiceOptions.newBuilder() .setOperationOptions( NexusOperationOptions.newBuilder() @@ -20,10 +20,10 @@ public class HelloCallerWorkflowImpl implements HelloCallerWorkflow { .build()); @Override - public String hello(String message, NexusService.Language language) { - NexusOperationHandle handle = + public String hello(String message, SampleNexusService.Language language) { + NexusOperationHandle handle = Workflow.startNexusOperation( - nexusService::hello, new NexusService.HelloInput(message, language)); + sampleNexusService::hello, new SampleNexusService.HelloInput(message, language)); // Optionally wait for the operation to be started. NexusOperationExecution will contain the // operation token in case this operation is asynchronous. handle.getExecution().get(); diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java index 0ec77889c..c3fd95e9f 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HandlerWorker.java @@ -15,7 +15,7 @@ public static void main(String[] args) { Worker worker = factory.newWorker(DEFAULT_TASK_QUEUE_NAME); worker.registerWorkflowImplementationTypes(HelloHandlerWorkflowImpl.class); - worker.registerNexusServiceImplementation(new NexusServiceImpl()); + worker.registerNexusServiceImplementation(new SampleNexusServiceImpl()); factory.start(); } diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java index 0a443d468..d13906496 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflow.java @@ -1,11 +1,11 @@ package io.temporal.samples.nexusmultipleargs.handler; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; @WorkflowInterface public interface HelloHandlerWorkflow { @WorkflowMethod - NexusService.HelloOutput hello(String name, NexusService.Language language); + SampleNexusService.HelloOutput hello(String name, SampleNexusService.Language language); } diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java index b802cee34..9d9cc3733 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/HelloHandlerWorkflowImpl.java @@ -1,22 +1,22 @@ package io.temporal.samples.nexusmultipleargs.handler; import io.temporal.failure.ApplicationFailure; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; public class HelloHandlerWorkflowImpl implements HelloHandlerWorkflow { @Override - public NexusService.HelloOutput hello(String name, NexusService.Language language) { + public SampleNexusService.HelloOutput hello(String name, SampleNexusService.Language language) { switch (language) { case EN: - return new NexusService.HelloOutput("Hello " + name + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hello " + name + " πŸ‘‹"); case FR: - return new NexusService.HelloOutput("Bonjour " + name + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Bonjour " + name + " πŸ‘‹"); case DE: - return new NexusService.HelloOutput("Hallo " + name + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Hallo " + name + " πŸ‘‹"); case ES: - return new NexusService.HelloOutput("Β‘Hola! " + name + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Β‘Hola! " + name + " πŸ‘‹"); case TR: - return new NexusService.HelloOutput("Merhaba " + name + " πŸ‘‹"); + return new SampleNexusService.HelloOutput("Merhaba " + name + " πŸ‘‹"); } throw ApplicationFailure.newFailure( "Unsupported language: " + language, "UNSUPPORTED_LANGUAGE"); diff --git a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/NexusServiceImpl.java b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/SampleNexusServiceImpl.java similarity index 86% rename from core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/NexusServiceImpl.java rename to core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/SampleNexusServiceImpl.java index 20d55fed8..b5d819267 100644 --- a/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/NexusServiceImpl.java +++ b/core/src/main/java/io/temporal/samples/nexusmultipleargs/handler/SampleNexusServiceImpl.java @@ -7,15 +7,15 @@ import io.temporal.nexus.Nexus; import io.temporal.nexus.WorkflowHandle; import io.temporal.nexus.WorkflowRunOperation; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.service.SampleNexusService; // To create a service implementation, annotate the class with @ServiceImpl and provide the // interface that the service implements. The service implementation class should have methods that // return OperationHandler that correspond to the operations defined in the service interface. -@ServiceImpl(service = NexusService.class) -public class NexusServiceImpl { +@ServiceImpl(service = SampleNexusService.class) +public class SampleNexusServiceImpl { @OperationImpl - public OperationHandler echo() { + public OperationHandler echo() { // OperationHandler.sync is a meant for exposing simple RPC handlers. return OperationHandler.sync( // The method is for making arbitrary short calls to other services or databases, or @@ -23,11 +23,11 @@ public OperationHandler echo() // calling // Nexus.getOperationContext().getWorkflowClient(ctx) to make arbitrary calls such as // signaling, querying, or listing workflows. - (ctx, details, input) -> new NexusService.EchoOutput(input.getMessage())); + (ctx, details, input) -> new SampleNexusService.EchoOutput(input.getMessage())); } @OperationImpl - public OperationHandler hello() { + public OperationHandler hello() { // If the operation input parameters are different from the workflow input parameters, // use the WorkflowRunOperation.fromWorkflowHandler constructor and the appropriate constructor // method on WorkflowHandle to map the Nexus input to the workflow parameters. diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java new file mode 100644 index 000000000..ca038ee0e --- /dev/null +++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5MockTest.java @@ -0,0 +1,79 @@ +package io.temporal.samples.nexus.caller; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +import io.temporal.samples.nexus.handler.EchoClient; +import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; +import io.temporal.samples.nexus.handler.SampleNexusServiceImpl; +import io.temporal.samples.nexus.service.SampleNexusService; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.worker.Worker; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +// This is an example of how to unit test Nexus services in JUnit5. The handlers are mocked, +// so that the caller classes interact with the mocks and not the handler classes themselves. + +public class CallerWorkflowJunit5MockTest { + + // Sync Nexus operations run inline in the handler thread β€” there is no backing workflow to + // register a factory for. To mock one, inject a mock dependency into the service implementation. + private static final EchoClient mockEchoClient = mock(EchoClient.class); + + @RegisterExtension + public static final TestWorkflowExtension testWorkflowExtension = + TestWorkflowExtension.newBuilder() + // If a Nexus service is registered as part of the test as in the following line of code, + // the TestWorkflowExtension will, by default, automatically create a Nexus service + // endpoint and workflows registered as part of the TestWorkflowExtension will + // automatically inherit the endpoint if none is set. + .setNexusServiceImplementation(new SampleNexusServiceImpl(mockEchoClient)) + // The Echo Nexus handler service just makes a call to a class, so no extra setup is + // needed. But the Hello Nexus service needs a worker for both the caller and handler + // in order to run, and the Echo Nexus caller service needs a worker. + // + // registerWorkflowImplementationTypes will take the classes given and create workers for + // them, enabling workflows to run. + .registerWorkflowImplementationTypes( + HelloCallerWorkflowImpl.class, EchoCallerWorkflowImpl.class) + .setDoNotStart(true) + .build(); + + @Test + public void testHelloWorkflow( + TestWorkflowEnvironment testEnv, Worker worker, HelloCallerWorkflow workflow) { + // Workflows started by a Nexus service can be mocked just like any other workflow + worker.registerWorkflowImplementationFactory( + HelloHandlerWorkflow.class, + () -> { + HelloHandlerWorkflow mockHandler = mock(HelloHandlerWorkflow.class); + when(mockHandler.hello(any())) + .thenReturn(new SampleNexusService.HelloOutput("Hello Mock World πŸ‘‹")); + return mockHandler; + }); + testEnv.start(); + + // Execute a workflow waiting for it to complete. + String greeting = workflow.hello("World", SampleNexusService.Language.EN); + assertEquals("Hello Mock World πŸ‘‹", greeting); + + testEnv.shutdown(); + } + + @Test + public void testEchoWorkflow( + TestWorkflowEnvironment testEnv, Worker worker, EchoCallerWorkflow workflow) { + // Sync Nexus operations run inline in the handler thread β€” there is no backing workflow to + // register a factory for. Instead, stub the injected EchoClient dependency directly. + when(mockEchoClient.echo(any())).thenReturn(new SampleNexusService.EchoOutput("mocked echo")); + testEnv.start(); + + // Execute a workflow waiting for it to complete. + String greeting = workflow.echo("Hello"); + assertEquals("mocked echo", greeting); + + testEnv.shutdown(); + } +} diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5Test.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5Test.java new file mode 100644 index 000000000..3da730c14 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowJunit5Test.java @@ -0,0 +1,58 @@ +package io.temporal.samples.nexus.caller; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.temporal.samples.nexus.handler.HelloHandlerWorkflowImpl; +import io.temporal.samples.nexus.handler.SampleNexusServiceImpl; +import io.temporal.samples.nexus.service.SampleNexusService; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.worker.Worker; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +// This is an example of how to unit test Nexus services in JUnit5. The handlers are not mocked, +// but are actually called by the testing framework by the caller classes. + +public class CallerWorkflowJunit5Test { + + @RegisterExtension + public static final TestWorkflowExtension testWorkflowExtension = + TestWorkflowExtension.newBuilder() + // If a Nexus service is registered as part of the test as in the following line of code, + // the TestWorkflowExtension will, by default, automatically create a Nexus service + // endpoint and workflows registered as part of the TestWorkflowExtension will + // automatically inherit the endpoint if none is set. + .setNexusServiceImplementation(new SampleNexusServiceImpl()) + // The Echo Nexus handler service just makes a call to a class, so no extra setup is + // needed. But the Hello Nexus service needs a worker for both the caller and handler + // in order to run, and the Echo Nexus caller service needs a worker. + // + // registerWorkflowImplementationTypes will take the classes given and create workers for + // them, enabling workflows to run. + .registerWorkflowImplementationTypes( + HelloCallerWorkflowImpl.class, + HelloHandlerWorkflowImpl.class, + EchoCallerWorkflowImpl.class) + // The workflow will start before each test, and will shut down after each test. + // See CallerWorkflowTest for an example of how to control this differently if needed. + .build(); + + // The TestWorkflowExtension extension in the Temporal testing library creates the + // arguments to the test cases and initializes them from the extension setup call above. + @Test + public void testHelloWorkflow( + TestWorkflowEnvironment testEnv, Worker worker, HelloCallerWorkflow workflow) { + // Execute a workflow waiting for it to complete. + String greeting = workflow.hello("World", SampleNexusService.Language.EN); + assertEquals("Hello World πŸ‘‹", greeting); + } + + @Test + public void testEchoWorkflow( + TestWorkflowEnvironment testEnv, Worker worker, EchoCallerWorkflow workflow) { + // Execute a workflow waiting for it to complete. + String greeting = workflow.echo("Hello"); + assertEquals("Hello", greeting); + } +} diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java new file mode 100644 index 000000000..c899713a2 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowMockTest.java @@ -0,0 +1,92 @@ +package io.temporal.samples.nexus.caller; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.nexus.handler.EchoClient; +import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; +import io.temporal.samples.nexus.handler.SampleNexusServiceImpl; +import io.temporal.samples.nexus.service.SampleNexusService; +import io.temporal.testing.TestWorkflowRule; +import org.junit.Rule; +import org.junit.Test; + +// This is an example of how to unit test Nexus services in JUnit4. The handlers are mocked, +// so that the caller classes interact with the mocks and not the handler classes themselves. + +public class CallerWorkflowMockTest { + + // Inject a mock EchoClient so sync Nexus operations can be stubbed per test. + // JUnit 4 creates a new test class instance per test method, so this mock is fresh each time. + private final EchoClient mockEchoClient = mock(EchoClient.class); + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + // If a Nexus service is registered as part of the test as in the following line of code, + // the TestWorkflowRule will, by default, automatically create a Nexus service endpoint + // and workflows registered as part of the TestWorkflowRule + // will automatically inherit the endpoint if none is set. + .setNexusServiceImplementation(new SampleNexusServiceImpl(mockEchoClient)) + // The Echo Nexus handler service just makes a call to a class, so no extra setup is + // needed. But the Hello Nexus service needs a worker for both the caller and handler + // in order to run. + // setWorkflowTypes will take the classes given and create workers for them, enabling + // workflows to run. This creates caller workflows, the handler workflows + // will be mocked in the test methods. + .setWorkflowTypes(HelloCallerWorkflowImpl.class, EchoCallerWorkflowImpl.class) + // Disable automatic worker startup as we are going to register some workflows manually + // per test + .setDoNotStart(true) + .build(); + + @Test + public void testHelloWorkflow() { + testWorkflowRule + .getWorker() + // Workflows started by a Nexus service can be mocked just like any other workflow + .registerWorkflowImplementationFactory( + HelloHandlerWorkflow.class, + () -> { + HelloHandlerWorkflow wf = mock(HelloHandlerWorkflow.class); + when(wf.hello(any())) + .thenReturn(new SampleNexusService.HelloOutput("Hello Mock World πŸ‘‹")); + return wf; + }); + testWorkflowRule.getTestEnvironment().start(); + + // Now create the caller workflow + HelloCallerWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloCallerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + String greeting = workflow.hello("World", SampleNexusService.Language.EN); + assertEquals("Hello Mock World πŸ‘‹", greeting); + + testWorkflowRule.getTestEnvironment().shutdown(); + } + + @Test + public void testEchoWorkflow() { + // Sync Nexus operations run inline in the handler thread β€” there is no backing workflow to + // register a factory for. Instead, stub the injected EchoCient dependency directly. + when(mockEchoClient.echo(any())).thenReturn(new SampleNexusService.EchoOutput("mocked echo")); + testWorkflowRule.getTestEnvironment().start(); + + EchoCallerWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + EchoCallerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + String greeting = workflow.echo("Hello"); + assertEquals("mocked echo", greeting); + + testWorkflowRule.getTestEnvironment().shutdown(); + } +} diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java index 2d3a6e42a..682995e61 100644 --- a/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java +++ b/core/src/test/java/io/temporal/samples/nexus/caller/CallerWorkflowTest.java @@ -1,14 +1,11 @@ package io.temporal.samples.nexus.caller; import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import io.temporal.client.WorkflowOptions; -import io.temporal.samples.nexus.handler.HelloHandlerWorkflow; -import io.temporal.samples.nexus.handler.NexusServiceImpl; -import io.temporal.samples.nexus.service.NexusService; +import io.temporal.samples.nexus.handler.HelloHandlerWorkflowImpl; +import io.temporal.samples.nexus.handler.SampleNexusServiceImpl; +import io.temporal.samples.nexus.service.SampleNexusService; import io.temporal.testing.TestWorkflowRule; import io.temporal.worker.WorkflowImplementationOptions; import io.temporal.workflow.NexusServiceOptions; @@ -16,16 +13,27 @@ import org.junit.Rule; import org.junit.Test; +// This is an example of how to unit test Nexus services in JUnit4. The handlers are not mocked, +// but are actually called by the testing framework by the caller classes. + public class CallerWorkflowTest { @Rule public TestWorkflowRule testWorkflowRule = TestWorkflowRule.newBuilder() - // If a Nexus service is registered as part of the test, the TestWorkflowRule will ,by - // default, automatically create a Nexus service endpoint and workflows registered as part - // of the TestWorkflowRule will automatically inherit the endpoint if none is set. - .setNexusServiceImplementation(new NexusServiceImpl()) - .setWorkflowTypes(HelloCallerWorkflowImpl.class) + // If a Nexus service is registered as part of the test as in the following line of code, + // the TestWorkflowRule will, by default, automatically create a Nexus service endpoint + // and workflows registered as part of the TestWorkflowRule + // will automatically inherit the endpoint if none is set. + .setNexusServiceImplementation(new SampleNexusServiceImpl()) + // The Echo Nexus handler service just makes a call to a class, so no extra setup is + // needed. But the Hello Nexus service needs a worker for both the caller and handler + // in order to run. + // setWorkflowTypes will take the classes given and create workers for them, enabling + // workflows to run. This is not adding an EchoCallerWorkflow though - + // see the testEchoWorkflow test method below for an example of an alternate way + // to supply a worker that gives you more flexibility if needed. + .setWorkflowTypes(HelloCallerWorkflowImpl.class, HelloHandlerWorkflowImpl.class) // Disable automatic worker startup as we are going to register some workflows manually // per test .setDoNotStart(true) @@ -33,16 +41,6 @@ public class CallerWorkflowTest { @Test public void testHelloWorkflow() { - testWorkflowRule - .getWorker() - // Workflows started by a Nexus service can be mocked just like any other workflow - .registerWorkflowImplementationFactory( - HelloHandlerWorkflow.class, - () -> { - HelloHandlerWorkflow wf = mock(HelloHandlerWorkflow.class); - when(wf.hello(any())).thenReturn(new NexusService.HelloOutput("Hello World πŸ‘‹")); - return wf; - }); testWorkflowRule.getTestEnvironment().start(); HelloCallerWorkflow workflow = @@ -51,7 +49,7 @@ public void testHelloWorkflow() { .newWorkflowStub( HelloCallerWorkflow.class, WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); - String greeting = workflow.hello("World", NexusService.Language.EN); + String greeting = workflow.hello("World", SampleNexusService.Language.EN); assertEquals("Hello World πŸ‘‹", greeting); testWorkflowRule.getTestEnvironment().shutdown(); @@ -61,15 +59,20 @@ public void testHelloWorkflow() { public void testEchoWorkflow() { // If Workflows are registered later than the endpoint can be set manually // either by setting the endpoint in the NexusServiceOptions in the Workflow implementation or - // by setting the NexusServiceOptions on the WorkflowImplementationOptions when registering the - // Workflow. + // by setting the NexusServiceOptions on the WorkflowImplementationOptions when registering + // the Workflow. To demonstrate, this is creating the Nexus service for Echo, + // and registering a EchoCallerWorkflowImpl worker. + // + // It is much simpler to use the setWorkflowTypes in the rule definition above - and as + // this isn't easily do-able in JUnit5 (the nexus endpoint isn't exposed) should be + // used with caution. testWorkflowRule .getWorker() .registerWorkflowImplementationTypes( WorkflowImplementationOptions.newBuilder() .setNexusServiceOptions( Collections.singletonMap( - "NexusService", + "SampleNexusService", NexusServiceOptions.newBuilder() .setEndpoint(testWorkflowRule.getNexusEndpoint().getSpec().getName()) .build())) diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java new file mode 100644 index 000000000..c5fd578c0 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceJunit5Test.java @@ -0,0 +1,105 @@ +package io.temporal.samples.nexus.caller; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import io.nexusrpc.handler.OperationHandler; +import io.nexusrpc.handler.OperationImpl; +import io.nexusrpc.handler.ServiceImpl; +import io.temporal.samples.nexus.service.SampleNexusService; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.worker.Worker; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +// This unit test example shows how to mock the Nexus service itself in JUnit4. +// This is the path to take when you don't have access to the service implementation so +// cannot mock it. Since the SampleNexusService itself is mocked, +// no handlers need to be set up or mocked. +public class NexusServiceJunit5Test { + + private final SampleNexusService mockNexusService = mock(SampleNexusService.class); + + /** + * A test-only Nexus service implementation that delegates to the Mockito mock defined above. Both + * operations are implemented as synchronous handlers that forward calls to the mock, allowing + * full control over return values and verification of inputs. + */ + @ServiceImpl(service = SampleNexusService.class) + public class TestNexusServiceImpl { + @OperationImpl + @SuppressWarnings("DirectInvocationOnMock") + public OperationHandler echo() { + return OperationHandler.sync((ctx, details, input) -> mockNexusService.echo(input)); + } + + @OperationImpl + @SuppressWarnings("DirectInvocationOnMock") + public OperationHandler hello() { + return OperationHandler.sync((ctx, details, input) -> mockNexusService.hello(input)); + } + } + + // Using OperationHandler.sync for both operations bypasses the need for a backing workflow, + // returning results inline just like a synchronous call. + // + // Note that the Mocks need to be done before the extension + // is defined, as creating the rule will fail if either call is still null. + + @RegisterExtension + public final TestWorkflowExtension testWorkflowExtension = + TestWorkflowExtension.newBuilder() + // If a Nexus service is registered as part of the test as in the following line of code, + // the TestWorkflowExtension will, by default, automatically create a Nexus service + // endpoint and workflows registered as part of the TestWorkflowExtension will + // automatically inherit the endpoint if none is set. + .setNexusServiceImplementation(new TestNexusServiceImpl()) + // The Echo Nexus handler service just makes a call to a class, so no extra setup is + // needed. But the Hello Nexus service needs a worker for both the caller and handler + // in order to run, and the Echo Nexus caller service needs a worker. + // + // registerWorkflowImplementationTypes will take the classes given and create workers for + // them, enabling workflows to run. + // Since both operations are mocked with OperationHandler.sync, no backing workflow is + // needed for hello β€” only the caller workflow types need to be registered. + .registerWorkflowImplementationTypes( + HelloCallerWorkflowImpl.class, EchoCallerWorkflowImpl.class) + // The workflow will start before each test, and will shut down after each test. + // See CallerWorkflowTest for an example of how to control this differently if needed. + .build(); + + // The TestWorkflowExtension extension in the Temporal testing library creates the + // arguments to the test cases and initializes them from the extension setup call above. + @Test + public void testHelloWorkflow( + TestWorkflowEnvironment testEnv, Worker worker, HelloCallerWorkflow workflow) { + + // Set the mock value to return + when(mockNexusService.hello(any())) + .thenReturn(new SampleNexusService.HelloOutput("Hello Mock World πŸ‘‹")); + + // Execute a workflow waiting for it to complete. + String greeting = workflow.hello("World", SampleNexusService.Language.EN); + assertEquals("Hello Mock World πŸ‘‹", greeting); + } + + @Test + public void testEchoWorkflow( + TestWorkflowEnvironment testEnv, Worker worker, EchoCallerWorkflow workflow) { + when(mockNexusService.echo(any())) + .thenReturn(new SampleNexusService.EchoOutput("echo response")); + + // Execute a workflow waiting for it to complete. + String greeting = workflow.echo("echo input"); + assertEquals("echo response", greeting); + + // Verify the echo operation was called exactly once and no other operations were invoked + verify(mockNexusService, times(1)).echo(any()); + // Verify the Nexus service was called with the correct input + verify(mockNexusService).echo(argThat(input -> "echo input".equals(input.getMessage()))); + + verifyNoMoreInteractions(mockNexusService); + } +} diff --git a/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java new file mode 100644 index 000000000..c2264ec65 --- /dev/null +++ b/core/src/test/java/io/temporal/samples/nexus/caller/NexusServiceMockTest.java @@ -0,0 +1,104 @@ +package io.temporal.samples.nexus.caller; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import io.nexusrpc.handler.OperationHandler; +import io.nexusrpc.handler.OperationImpl; +import io.nexusrpc.handler.ServiceImpl; +import io.temporal.client.WorkflowOptions; +import io.temporal.samples.nexus.service.SampleNexusService; +import io.temporal.testing.TestWorkflowRule; +import org.junit.Rule; +import org.junit.Test; + +// This unit test example shows how to mock the Nexus service itself in JUnit4. +// This is the path to take when you don't have access to the service implementation so +// cannot mock it. Since the SampleNexusService itself is mocked, +// no handlers need to be set up or mocked. +public class NexusServiceMockTest { + + private final SampleNexusService mockNexusService = mock(SampleNexusService.class); + + /** + * A test-only Nexus service implementation that delegates to the Mockito mock defined above. Both + * operations are implemented as synchronous handlers that forward calls to the mock, allowing + * full control over return values and verification of inputs. + */ + @ServiceImpl(service = SampleNexusService.class) + public class TestNexusServiceImpl { + @OperationImpl + @SuppressWarnings("DirectInvocationOnMock") + public OperationHandler echo() { + return OperationHandler.sync((ctx, details, input) -> mockNexusService.echo(input)); + } + + @OperationImpl + @SuppressWarnings("DirectInvocationOnMock") + public OperationHandler hello() { + return OperationHandler.sync((ctx, details, input) -> mockNexusService.hello(input)); + } + } + + // Using OperationHandler.sync for both operations bypasses the need for a backing workflow, + // returning results inline just like a synchronous call. + // + // Note that the Mocks need to be done before the rule + // is defined, as creating the rule will fail if either call is still null. + + @Rule + public TestWorkflowRule testWorkflowRule = + TestWorkflowRule.newBuilder() + .setNexusServiceImplementation(new TestNexusServiceImpl()) + .setWorkflowTypes(EchoCallerWorkflowImpl.class, HelloCallerWorkflowImpl.class) + .build(); + + @Test + public void testHelloCallerWithMockedService() { + when(mockNexusService.hello(any())) + .thenReturn(new SampleNexusService.HelloOutput("Bonjour World")); + + HelloCallerWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + HelloCallerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + + String result = workflow.hello("World", SampleNexusService.Language.FR); + assertEquals("Bonjour World", result); + + // Verify the Nexus service was called with the correct name and language + verify(mockNexusService) + .hello( + argThat( + input -> + "World".equals(input.getName()) + && SampleNexusService.Language.FR == input.getLanguage())); + } + + @Test + public void testEchoCallerWithMockedService() { + when(mockNexusService.echo(any())) + .thenReturn(new SampleNexusService.EchoOutput("echo response")); + + EchoCallerWorkflow workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + EchoCallerWorkflow.class, + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build()); + + String echoOutput = workflow.echo("echo input"); + + assertEquals("echo response", echoOutput); + + // Verify the echo operation was called exactly once and no other operations were invoked + verify(mockNexusService, times(1)).echo(any()); + // Verify the Nexus service was called with the correct input + verify(mockNexusService).echo(argThat(input -> "echo input".equals(input.getMessage()))); + + verifyNoMoreInteractions(mockNexusService); + } +}