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 85f3b97346..391eb2c9e4 100644 --- a/temporal-testing/src/main/java/io/temporal/testing/TestWorkflowExtension.java +++ b/temporal-testing/src/main/java/io/temporal/testing/TestWorkflowExtension.java @@ -31,10 +31,12 @@ import io.temporal.worker.Worker; import io.temporal.worker.WorkerFactoryOptions; import io.temporal.worker.WorkerOptions; +import io.temporal.worker.WorkflowImplementationOptions; import io.temporal.workflow.DynamicWorkflow; import java.lang.reflect.Constructor; import java.lang.reflect.Parameter; import java.time.Instant; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -91,7 +93,7 @@ public class TestWorkflowExtension private final WorkerOptions workerOptions; private final WorkflowClientOptions workflowClientOptions; private final WorkerFactoryOptions workerFactoryOptions; - private final Class[] workflowTypes; + private final Map, WorkflowImplementationOptions> workflowTypes; private final Object[] activityImplementations; private final boolean useExternalService; private final String target; @@ -128,7 +130,7 @@ private TestWorkflowExtension(Builder builder) { supportedParameterTypes.add(WorkflowOptions.class); supportedParameterTypes.add(Worker.class); - for (Class workflowType : workflowTypes) { + for (Class workflowType : workflowTypes.keySet()) { if (DynamicWorkflow.class.isAssignableFrom(workflowType)) { includesDynamicWorkflow = true; continue; @@ -211,7 +213,7 @@ public void beforeEach(ExtensionContext context) { String taskQueue = String.format("WorkflowTest-%s-%s", context.getDisplayName(), context.getUniqueId()); Worker worker = testEnvironment.newWorker(taskQueue, workerOptions); - worker.registerWorkflowImplementationTypes(workflowTypes); + workflowTypes.forEach((wft, o) -> worker.registerWorkflowImplementationTypes(o, wft)); worker.registerActivitiesImplementations(activityImplementations); if (!doNotStart) { @@ -281,14 +283,13 @@ private ExtensionContext.Store getStore(ExtensionContext context) { public static class Builder { - private static final Class[] NO_WORKFLOWS = new Class[0]; private static final Object[] NO_ACTIVITIES = new Object[0]; private WorkerOptions workerOptions = WorkerOptions.getDefaultInstance(); private WorkflowClientOptions workflowClientOptions; private WorkerFactoryOptions workerFactoryOptions; private String namespace = "UnitTest"; - private Class[] workflowTypes = NO_WORKFLOWS; + private Map, WorkflowImplementationOptions> workflowTypes = new HashMap<>(); private Object[] activityImplementations = NO_ACTIVITIES; private boolean useExternalService = false; private String target = null; @@ -345,11 +346,35 @@ public Builder setNamespace(String namespace) { * * @see Worker#registerWorkflowImplementationTypes(Class[]) */ - public Builder setWorkflowTypes(Class... workflowTypes) { - this.workflowTypes = workflowTypes; + public Builder registerWorkflowImplementationTypes(Class... workflowTypes) { + WorkflowImplementationOptions defaultOptions = + WorkflowImplementationOptions.newBuilder().build(); + Arrays.stream(workflowTypes).forEach(wf -> this.workflowTypes.put(wf, defaultOptions)); + return this; + } + + /** + * Specify workflow implementation types to register with the Temporal worker. + * + * @see Worker#registerWorkflowImplementationTypes(Class[]) + */ + public Builder registerWorkflowImplementationTypes( + WorkflowImplementationOptions options, Class... workflowTypes) { + Arrays.stream(workflowTypes).forEach(wf -> this.workflowTypes.put(wf, options)); return this; } + /** + * Specify workflow implementation types to register with the Temporal worker. + * + * @see Worker#registerWorkflowImplementationTypes(Class[]) + * @deprecated use registerWorkflowImplementationTypes instead + */ + @Deprecated + public Builder setWorkflowTypes(Class... workflowTypes) { + return this.registerWorkflowImplementationTypes(workflowTypes); + } + /** * Specify activity implementations to register with the Temporal worker * diff --git a/temporal-testing/src/test/java/io/temporal/testing/junit5/TestWorkflowExtensionDynamicTest.java b/temporal-testing/src/test/java/io/temporal/testing/junit5/TestWorkflowExtensionDynamicTest.java index 2c92d80130..1c562ccc66 100644 --- a/temporal-testing/src/test/java/io/temporal/testing/junit5/TestWorkflowExtensionDynamicTest.java +++ b/temporal-testing/src/test/java/io/temporal/testing/junit5/TestWorkflowExtensionDynamicTest.java @@ -49,7 +49,7 @@ public class TestWorkflowExtensionDynamicTest { @RegisterExtension public static final TestWorkflowExtension testWorkflow = TestWorkflowExtension.newBuilder() - .setWorkflowTypes(HelloDynamicWorkflowImpl.class) + .registerWorkflowImplementationTypes(HelloDynamicWorkflowImpl.class) .setActivityImplementations(new HelloDynamicActivityImpl()) .build(); 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 adf6db83a5..d03d347373 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 @@ -53,7 +53,7 @@ public class TestWorkflowExtensionTest { @RegisterExtension public static final TestWorkflowExtension testWorkflow = TestWorkflowExtension.newBuilder() - .setWorkflowTypes(HelloWorkflowImpl.class) + .registerWorkflowImplementationTypes(HelloWorkflowImpl.class) .setActivityImplementations(new HelloActivityImpl()) .setInitialTime(Instant.parse("2021-10-10T10:01:00Z")) .build(); diff --git a/temporal-testing/src/test/java/io/temporal/testing/junit5/testWorkflowImplementationOptions/TestWorkflowImplementationOptionsCommon.java b/temporal-testing/src/test/java/io/temporal/testing/junit5/testWorkflowImplementationOptions/TestWorkflowImplementationOptionsCommon.java new file mode 100644 index 0000000000..95637a02ff --- /dev/null +++ b/temporal-testing/src/test/java/io/temporal/testing/junit5/testWorkflowImplementationOptions/TestWorkflowImplementationOptionsCommon.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.temporal.testing.junit5.testWorkflowImplementationOptions; + +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Timeout; +import org.slf4j.Logger; + +@Timeout(value = 30, unit = TimeUnit.SECONDS) +public class TestWorkflowImplementationOptionsCommon { + + @WorkflowInterface + public interface HelloWorkflow { + + @WorkflowMethod + String sayHello(String name); + } + + /* No full Exceptionimplementation. Just for testing TestWorkflowExtension::registerWorkflowImplementationTypes*/ + public static class TestException extends RuntimeException { + public TestException(String message) { + super(message); + } + } + + public static class HelloWorkflowImpl implements HelloWorkflow { + + private static final Logger logger = Workflow.getLogger(HelloWorkflowImpl.class); + + @Override + public String sayHello(String name) { + logger.info("Hello, {}", name); + throw new TestException("Hello World"); + } + } +} diff --git a/temporal-testing/src/test/java/io/temporal/testing/junit5/testWorkflowImplementationOptions/TestWorkflowImplementationOptionsMain.java b/temporal-testing/src/test/java/io/temporal/testing/junit5/testWorkflowImplementationOptions/TestWorkflowImplementationOptionsMain.java new file mode 100644 index 0000000000..f4331a4af6 --- /dev/null +++ b/temporal-testing/src/test/java/io/temporal/testing/junit5/testWorkflowImplementationOptions/TestWorkflowImplementationOptionsMain.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.temporal.testing.junit5.testWorkflowImplementationOptions; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import io.temporal.client.WorkflowFailedException; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.testing.WorkflowInitialTime; +import io.temporal.testing.junit5.testWorkflowImplementationOptions.TestWorkflowImplementationOptionsCommon.HelloWorkflow; +import io.temporal.testing.junit5.testWorkflowImplementationOptions.TestWorkflowImplementationOptionsCommon.HelloWorkflowImpl; +import io.temporal.testing.junit5.testWorkflowImplementationOptions.TestWorkflowImplementationOptionsCommon.TestException; +import io.temporal.worker.WorkflowImplementationOptions; +import java.time.Instant; +import java.util.concurrent.TimeUnit; +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 TestWorkflowImplementationOptionsMain { + + static WorkflowImplementationOptions failWorkflowOnTestException() { + return WorkflowImplementationOptions.newBuilder() + .setFailWorkflowExceptionTypes(TestException.class) + .build(); + } + + @RegisterExtension + public static final TestWorkflowExtension testWorkflow = + TestWorkflowExtension.newBuilder() + .registerWorkflowImplementationTypes( + failWorkflowOnTestException(), HelloWorkflowImpl.class) + .setInitialTime(Instant.parse("2021-10-10T10:01:00Z")) + .build(); + + @Test + @WorkflowInitialTime("2020-01-01T01:00:00Z") + public void extensionShouldLaunchTestEnvironmentWithWorkflowImplementationOptions( + HelloWorkflow workflow) { + + assertThrows(WorkflowFailedException.class, () -> workflow.sayHello("World")); + } +} diff --git a/temporal-testing/src/test/java/io/temporal/testing/junit5/testWorkflowImplementationOptions/TestWorkflowImplementationOptionsViceVersa.java b/temporal-testing/src/test/java/io/temporal/testing/junit5/testWorkflowImplementationOptions/TestWorkflowImplementationOptionsViceVersa.java new file mode 100644 index 0000000000..ddc4790009 --- /dev/null +++ b/temporal-testing/src/test/java/io/temporal/testing/junit5/testWorkflowImplementationOptions/TestWorkflowImplementationOptionsViceVersa.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.temporal.testing.junit5.testWorkflowImplementationOptions; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.testing.TestWorkflowEnvironment; +import io.temporal.testing.TestWorkflowExtension; +import io.temporal.testing.WorkflowInitialTime; +import io.temporal.testing.junit5.testWorkflowImplementationOptions.TestWorkflowImplementationOptionsCommon.HelloWorkflowImpl; +import io.temporal.worker.Worker; +import java.time.Instant; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +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 TestWorkflowImplementationOptionsViceVersa { + + @RegisterExtension + public static final TestWorkflowExtension testWorkflow = + TestWorkflowExtension.newBuilder() + .registerWorkflowImplementationTypes(HelloWorkflowImpl.class) + .setInitialTime(Instant.parse("2021-10-10T10:01:00Z")) + .build(); + + @Test + @WorkflowInitialTime("2020-01-01T01:00:00Z") + public void extensionShouldNotBeAbleToCallActivityBasedOnMissingTimeouts( + TestWorkflowEnvironment testEnv, WorkflowOptions workflowOptions, Worker worker) + throws InterruptedException, ExecutionException, TimeoutException { + + WorkflowStub cut = + testEnv.getWorkflowClient().newUntypedWorkflowStub("HelloWorkflow", workflowOptions); + cut.start("World"); + + CompletableFuture resultAsync = cut.getResultAsync(String.class); + assertThrows(TimeoutException.class, () -> resultAsync.get(5, TimeUnit.SECONDS)); + } +}