diff --git a/temporal-sdk/src/main/java/io/temporal/client/WorkflowClientOptions.java b/temporal-sdk/src/main/java/io/temporal/client/WorkflowClientOptions.java index e33160d2e7..e266b81048 100644 --- a/temporal-sdk/src/main/java/io/temporal/client/WorkflowClientOptions.java +++ b/temporal-sdk/src/main/java/io/temporal/client/WorkflowClientOptions.java @@ -47,6 +47,10 @@ public static Builder newBuilder(WorkflowClientOptions options) { return new Builder(options); } + public WorkflowClientOptions.Builder toBuilder() { + return new WorkflowClientOptions.Builder(this); + } + public static WorkflowClientOptions getDefaultInstance() { return DEFAULT_INSTANCE; } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/AwaitTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/AwaitTest.java index 3096f4cfd5..2bbe79eeac 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/AwaitTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/AwaitTest.java @@ -23,7 +23,6 @@ import static org.junit.Assert.assertFalse; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; import java.time.Duration; import org.junit.Rule; @@ -31,15 +30,9 @@ public class AwaitTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - @Rule public SDKTestWorkflowRule testWorkflowRule = - SDKTestWorkflowRule.newBuilder() - .setWorkflowTypes(TestAwait.class) - .setActivityImplementations(activitiesImpl) - .build(); + SDKTestWorkflowRule.newBuilder().setWorkflowTypes(TestAwait.class).build(); @Test public void testAwait() { diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/BinaryChecksumSetWhenTaskCompletedTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/BinaryChecksumSetWhenTaskCompletedTest.java new file mode 100644 index 0000000000..3b99f02b4d --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/BinaryChecksumSetWhenTaskCompletedTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import io.temporal.activity.ActivityOptions; +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.enums.v1.EventType; +import io.temporal.api.history.v1.History; +import io.temporal.api.history.v1.HistoryEvent; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowClientOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.workflow.shared.*; +import org.junit.Rule; +import org.junit.Test; + +public class BinaryChecksumSetWhenTaskCompletedTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowClientOptions( + WorkflowClientOptions.newBuilder() + .setBinaryChecksum(SDKTestWorkflowRule.BINARY_CHECKSUM) + .build()) + .setWorkflowTypes(SimpleTestWorkflow.class) + .build(); + + @Test + public void testBinaryChecksumSetWhenTaskCompleted() { + TestWorkflows.TestWorkflow1 client = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + WorkflowExecution execution = + WorkflowClient.start(client::execute, testWorkflowRule.getTaskQueue()); + WorkflowStub stub = WorkflowStub.fromTyped(client); + SDKTestWorkflowRule.waitForOKQuery(stub); + History history = testWorkflowRule.getWorkflowExecutionHistory(execution); + + boolean foundCompletedTask = false; + for (HistoryEvent event : history.getEventsList()) { + if (event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_TASK_COMPLETED) { + assertEquals( + SDKTestWorkflowRule.BINARY_CHECKSUM, + event.getWorkflowTaskCompletedEventAttributes().getBinaryChecksum()); + foundCompletedTask = true; + } + } + assertTrue(foundCompletedTask); + } + + public static class SimpleTestWorkflow implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + TestActivities testActivities = + Workflow.newActivityStub( + TestActivities.class, + ActivityOptions.newBuilder(TestOptions.newActivityOptionsForTaskQueue(taskQueue)) + .build()); + testActivities.activity(); + return "done"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ContinueAsNewNoArgsTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/ContinueAsNewNoArgsTest.java new file mode 100644 index 0000000000..b5948d82e2 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/ContinueAsNewNoArgsTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class ContinueAsNewNoArgsTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestContinueAsNewNoArgsImpl.class) + .setWorkerInterceptors( + new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) + .build(); + + @Test + public void testContinueAsNewNoArgs() { + + NoArgsWorkflow client = testWorkflowRule.newWorkflowStubTimeoutOptions(NoArgsWorkflow.class); + String result = client.execute(); + Assert.assertEquals("done", result); + testWorkflowRule + .getInterceptor(TracingWorkerInterceptor.class) + .setExpected( + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "continueAsNew", + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method"); + } + + @WorkflowInterface + public interface NoArgsWorkflow { + @WorkflowMethod + String execute(); + } + + public static class TestContinueAsNewNoArgsImpl implements NoArgsWorkflow { + + @Override + public String execute() { + NoArgsWorkflow next = Workflow.newContinueAsNewStub(NoArgsWorkflow.class); + WorkflowInfo info = Workflow.getInfo(); + if (!info.getContinuedExecutionRunId().isPresent()) { + next.execute(); + throw new RuntimeException("unreachable"); + } else { + return "done"; + } + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ContinueAsNewTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/ContinueAsNewTest.java new file mode 100644 index 0000000000..abedd97c0d --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/ContinueAsNewTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.assertEquals; + +import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class ContinueAsNewTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestContinueAsNewImpl.class) + .setWorkerInterceptors( + new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) + .build(); + + @Test + public void testContinueAsNew() { + TestContinueAsNew client = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestContinueAsNew.class); + int result = client.execute(4, testWorkflowRule.getTaskQueue()); + Assert.assertEquals(111, result); + testWorkflowRule + .getInterceptor(TracingWorkerInterceptor.class) + .setExpected( + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "continueAsNew", + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "continueAsNew", + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "continueAsNew", + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "continueAsNew", + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method"); + } + + @WorkflowInterface + public interface TestContinueAsNew { + + @WorkflowMethod + int execute(int count, String continueAsNewTaskQueue); + } + + public static class TestContinueAsNewImpl implements TestContinueAsNew { + + @Override + public int execute(int count, String continueAsNewTaskQueue) { + String taskQueue = Workflow.getInfo().getTaskQueue(); + if (count == 0) { + assertEquals(continueAsNewTaskQueue, taskQueue); + return 111; + } + Map memo = new HashMap<>(); + memo.put("myKey", "MyValue"); + Map searchAttributes = new HashMap<>(); + searchAttributes.put("CustomKeywordField", "foo1"); + ContinueAsNewOptions options = + ContinueAsNewOptions.newBuilder() + .setTaskQueue(continueAsNewTaskQueue) + .setMemo(memo) + .setSearchAttributes(searchAttributes) + .build(); + TestContinueAsNew next = Workflow.newContinueAsNewStub(TestContinueAsNew.class, options); + next.execute(count - 1, continueAsNewTaskQueue); + throw new RuntimeException("unreachable"); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/DetachedScopeTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/DetachedScopeTest.java new file mode 100644 index 0000000000..76f4b83ac4 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/DetachedScopeTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.*; + +import io.temporal.client.WorkflowFailedException; +import io.temporal.client.WorkflowStub; +import io.temporal.failure.ActivityFailure; +import io.temporal.failure.CanceledFailure; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class DetachedScopeTest { + + private final TestActivities.TestActivitiesImpl activitiesImpl = + new TestActivities.TestActivitiesImpl(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestDetachedCancellationScope.class) + .setActivityImplementations(activitiesImpl) + .build(); + + @Test + public void testDetachedScope() { + WorkflowStub client = testWorkflowRule.newUntypedWorkflowStubTimeoutOptions("TestWorkflow1"); + client.start(testWorkflowRule.getTaskQueue()); + testWorkflowRule.sleep(Duration.ofMillis(500)); // To let activityWithDelay start. + client.cancel(); + try { + client.getResult(String.class); + Assert.fail("unreachable"); + } catch (WorkflowFailedException e) { + Assert.assertTrue(e.getCause() instanceof CanceledFailure); + } + activitiesImpl.assertInvocations("activityWithDelay", "activity1", "activity2", "activity3"); + } + + public static class TestDetachedCancellationScope implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + TestActivities testActivities = + Workflow.newActivityStub( + TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); + try { + testActivities.activityWithDelay(100000, true); + fail("unreachable"); + } catch (ActivityFailure e) { + assertTrue(e.getCause() instanceof CanceledFailure); + Workflow.newDetachedCancellationScope(() -> assertEquals(1, testActivities.activity1(1))) + .run(); + } + try { + Workflow.sleep(Duration.ofHours(1)); + fail("unreachable"); + } catch (CanceledFailure e) { + Workflow.newDetachedCancellationScope( + () -> assertEquals("a12", testActivities.activity2("a1", 2))) + .run(); + } + try { + Workflow.newTimer(Duration.ofHours(1)).get(); + fail("unreachable"); + } catch (CanceledFailure e) { + Workflow.newDetachedCancellationScope( + () -> assertEquals("a123", testActivities.activity3("a1", 2, 3))) + .run(); + } + return "result"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ExceptionPropagationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/ExceptionPropagationTest.java new file mode 100644 index 0000000000..ca43b58850 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/ExceptionPropagationTest.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.*; + +import io.temporal.client.WorkflowFailedException; +import io.temporal.common.RetryOptions; +import io.temporal.failure.ActivityFailure; +import io.temporal.failure.ApplicationFailure; +import io.temporal.failure.ChildWorkflowFailure; +import io.temporal.worker.WorkflowImplementationOptions; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class ExceptionPropagationTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes( + WorkflowImplementationOptions.newBuilder() + .setFailWorkflowExceptionTypes( + NumberFormatException.class, FileNotFoundException.class) + .build(), + ThrowingChild.class, + TestExceptionPropagationImpl.class) + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) + .build(); + + /** + * Test that an NPE thrown in an activity executed from a child workflow results in the following + * chain of exceptions when an exception is received in an external client that executed workflow + * through a WorkflowClient: + * + *
+   * {@link WorkflowFailedException}
+   *     ->{@link ChildWorkflowFailure}
+   *         ->{@link ActivityFailure}
+   *             ->OriginalActivityException
+   * 
+ * + *

This test also tests that Checked exception wrapping and unwrapping works producing a nice + * exception chain without the wrappers. + */ + @Test + public void testExceptionPropagation() { + TestExceptionPropagation client = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestExceptionPropagation.class); + try { + client.execute(testWorkflowRule.getTaskQueue()); + Assert.fail("Unreachable"); + } catch (WorkflowFailedException e) { + // Rethrow the assertion failure + Throwable c1 = e.getCause(); + Throwable c2 = c1.getCause(); + Throwable c3 = c2.getCause(); + Throwable c4 = c3.getCause(); + Throwable c5 = c4.getCause(); + Throwable c6 = c5.getCause(); + if (c2 instanceof AssertionError) { + throw (AssertionError) c2; + } + assertNoEmptyStacks(e); + // Uncomment to see the actual trace. + // e.printStackTrace(); + Assert.assertTrue(e.getMessage(), e.getMessage().contains("TestExceptionPropagation")); + Assert.assertTrue(e.getStackTrace().length > 0); + Assert.assertTrue(c1 instanceof ApplicationFailure); + Assert.assertEquals( + FileNotFoundException.class.getName(), ((ApplicationFailure) c1).getType()); + Assert.assertTrue(c2 instanceof ChildWorkflowFailure); + Assert.assertTrue(c3 instanceof ApplicationFailure); + Assert.assertEquals( + NumberFormatException.class.getName(), ((ApplicationFailure) c3).getType()); + Assert.assertEquals(Throwable.class.getName(), ((ApplicationFailure) c4).getType()); + Assert.assertTrue(c5 instanceof ActivityFailure); + Assert.assertTrue(c6 instanceof ApplicationFailure); + Assert.assertEquals(IOException.class.getName(), ((ApplicationFailure) c6).getType()); + Assert.assertEquals( + "message='simulated IO problem', type='java.io.IOException', nonRetryable=false", + c6.getMessage()); + } + } + + private static void assertNoEmptyStacks(RuntimeException e) { + // Check that there are no empty stacks + Throwable c = e; + while (c != null) { + assertTrue(c.getStackTrace().length > 0); + c = c.getCause(); + } + } + + @WorkflowInterface + public interface TestExceptionPropagation { + @WorkflowMethod + void execute(String taskQueue); + } + + public static class ThrowingChild implements TestWorkflows.TestWorkflow1 { + + @Override + @SuppressWarnings("AssertionFailureIgnored") + public String execute(String taskQueue) { + TestActivities testActivities = + Workflow.newActivityStub( + TestActivities.class, + TestOptions.newActivityOptions20sScheduleToClose() + .toBuilder() + .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(1).build()) + .build()); + try { + testActivities.throwIO(); + fail("unreachable"); + return "ignored"; + } catch (ActivityFailure e) { + try { + assertTrue(e.getMessage().contains("ThrowIO")); + assertTrue(e.getCause() instanceof ApplicationFailure); + assertEquals(IOException.class.getName(), ((ApplicationFailure) e.getCause()).getType()); + assertEquals( + "message='simulated IO problem', type='java.io.IOException', nonRetryable=false", + e.getCause().getMessage()); + } catch (AssertionError ae) { + // Errors cause workflow task to fail. But we want workflow to fail in this case. + throw new RuntimeException(ae); + } + Exception ee = new NumberFormatException(); + ee.initCause(new Throwable("simulated throwable", e)); + throw Workflow.wrap(ee); + } + } + } + + public static class TestExceptionPropagationImpl implements TestExceptionPropagation { + + @Override + @SuppressWarnings("AssertionFailureIgnored") + public void execute(String taskQueue) { + ChildWorkflowOptions options = + ChildWorkflowOptions.newBuilder().setWorkflowRunTimeout(Duration.ofHours(1)).build(); + TestWorkflows.TestWorkflow1 child = + Workflow.newChildWorkflowStub(TestWorkflows.TestWorkflow1.class, options); + try { + child.execute(taskQueue); + fail("unreachable"); + } catch (RuntimeException e) { + Throwable c1 = e.getCause(); + Throwable c2 = c1.getCause(); + Throwable c3 = c2.getCause(); + Throwable c4 = c3.getCause(); + try { + assertNoEmptyStacks(e); + assertTrue(e.getMessage().contains("TestWorkflow1")); + assertTrue(e instanceof ChildWorkflowFailure); + assertTrue(c1 instanceof ApplicationFailure); + assertEquals(NumberFormatException.class.getName(), ((ApplicationFailure) c1).getType()); + assertEquals(Throwable.class.getName(), ((ApplicationFailure) c2).getType()); + assertTrue(c3 instanceof ActivityFailure); + assertTrue(c4 instanceof ApplicationFailure); + assertEquals(IOException.class.getName(), ((ApplicationFailure) c4).getType()); + assertEquals( + "message='simulated IO problem', type='java.io.IOException', nonRetryable=false", + c4.getMessage()); + } catch (AssertionError ae) { + // Errors cause workflow task to fail. But we want workflow to fail in this case. + throw new RuntimeException(ae); + } + Exception fnf = new FileNotFoundException("simulated exception"); + fnf.initCause(e); + throw Workflow.wrap(fnf); + } + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ExecuteTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/ExecuteTest.java new file mode 100644 index 0000000000..6c8612a2f7 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/ExecuteTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.client.WorkflowClient; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; +import java.util.concurrent.ExecutionException; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class ExecuteTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class) + .build(); + + @Test + public void testExecute() throws ExecutionException, InterruptedException { + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc stubF = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc.class); + Assert.assertEquals("func", WorkflowClient.execute(stubF::func).get()); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1 stubF1 = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1.class); + Assert.assertEquals(1, (int) WorkflowClient.execute(stubF1::func1, 1).get()); + Assert.assertEquals(1, stubF1.func1(1)); // Check that duplicated start just returns the result. + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc2 stubF2 = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc2.class); + Assert.assertEquals("12", WorkflowClient.execute(stubF2::func2, "1", 2).get()); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc3 stubF3 = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc3.class); + Assert.assertEquals("123", WorkflowClient.execute(stubF3::func3, "1", 2, 3).get()); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc4 stubF4 = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc4.class); + Assert.assertEquals("1234", WorkflowClient.execute(stubF4::func4, "1", 2, 3, 4).get()); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc5 stubF5 = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc5.class); + Assert.assertEquals("12345", WorkflowClient.execute(stubF5::func5, "1", 2, 3, 4, 5).get()); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc6 stubF6 = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc6.class); + Assert.assertEquals("123456", WorkflowClient.execute(stubF6::func6, "1", 2, 3, 4, 5, 6).get()); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc stubP = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc.class); + WorkflowClient.execute(stubP::proc).get(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc1 stubP1 = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc1.class); + WorkflowClient.execute(stubP1::proc1, "1").get(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc2 stubP2 = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc2.class); + WorkflowClient.execute(stubP2::proc2, "1", 2).get(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc3 stubP3 = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc3.class); + WorkflowClient.execute(stubP3::proc3, "1", 2, 3).get(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc4 stubP4 = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc4.class); + WorkflowClient.execute(stubP4::proc4, "1", 2, 3, 4).get(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc5 stubP5 = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc5.class); + WorkflowClient.execute(stubP5::proc5, "1", 2, 3, 4, 5).get(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc6 stubP6 = + testWorkflowRule.newWorkflowStubTimeoutOptions( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc6.class); + WorkflowClient.execute(stubP6::proc6, "1", 2, 3, 4, 5, 6).get(); + + Assert.assertEquals("proc", stubP.query()); + Assert.assertEquals("1", stubP1.query()); + Assert.assertEquals("12", stubP2.query()); + Assert.assertEquals("123", stubP3.query()); + Assert.assertEquals("1234", stubP4.query()); + Assert.assertEquals("12345", stubP5.query()); + Assert.assertEquals("123456", stubP6.query()); + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/GenericParametersWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/GenericParametersWorkflowTest.java new file mode 100644 index 0000000000..16db2cdb9f --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/GenericParametersWorkflowTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.activity.ActivityInterface; +import io.temporal.client.WorkflowClient; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestOptions; +import java.time.Duration; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class GenericParametersWorkflowTest { + + private final GenericParametersActivityImpl activitiesImpl = new GenericParametersActivityImpl(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(GenericParametersWorkflowImpl.class) + .setActivityImplementations(activitiesImpl) + .build(); + + @Test + public void testGenericParametersWorkflow() throws ExecutionException, InterruptedException { + GenericParametersWorkflow workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(GenericParametersWorkflow.class); + List uuidList = new ArrayList(); + uuidList.add(UUID.randomUUID()); + uuidList.add(UUID.randomUUID()); + Set uuidSet = new HashSet(); + uuidSet.add(UUID.randomUUID()); + uuidSet.add(UUID.randomUUID()); + uuidSet.add(UUID.randomUUID()); + CompletableFuture> resultF = + WorkflowClient.execute( + workflowStub::execute, testWorkflowRule.getTaskQueue(), uuidList, uuidSet); + // Test signal and query serialization + workflowStub.signal(uuidList); + testWorkflowRule.sleep(Duration.ofSeconds(1)); + List queryArg = new ArrayList(); + queryArg.add(UUID.randomUUID()); + queryArg.add(UUID.randomUUID()); + List queryResult = workflowStub.query(queryArg); + List expectedQueryResult = new ArrayList(); + expectedQueryResult.addAll(queryArg); + expectedQueryResult.addAll(uuidList); + expectedQueryResult.sort(UUID::compareTo); + queryResult.sort(UUID::compareTo); + Assert.assertEquals(expectedQueryResult, queryResult); + workflowStub.signal(new ArrayList()); // empty list unblocks workflow await. + // test workflow result serialization + List expectedResult = new ArrayList(); + expectedResult.addAll(uuidList); + expectedResult.addAll(uuidSet); + List result = resultF.get(); + result.sort(UUID::compareTo); + expectedResult.sort(UUID::compareTo); + Assert.assertEquals(expectedResult, result); + } + + @ActivityInterface + public interface GenericParametersActivity { + + List execute(List arg1, Set arg2); + } + + @WorkflowInterface + public interface GenericParametersWorkflow { + + @WorkflowMethod + List execute(String taskQueue, List arg1, Set arg2); + + @SignalMethod + void signal(List arg); + + @QueryMethod + List query(List arg); + } + + public static class GenericParametersActivityImpl implements GenericParametersActivity { + + @Override + public List execute(List arg1, Set arg2) { + List result = new ArrayList<>(); + result.addAll(arg1); + result.addAll(arg2); + return result; + } + } + + public static class GenericParametersWorkflowImpl implements GenericParametersWorkflow { + + private List signaled; + private GenericParametersActivity activity; + + @Override + public List execute(String taskQueue, List arg1, Set arg2) { + Workflow.await(() -> signaled != null && signaled.size() == 0); + activity = + Workflow.newActivityStub( + GenericParametersActivity.class, + TestOptions.newActivityOptionsForTaskQueue(taskQueue)); + return activity.execute(arg1, arg2); + } + + @Override + public void signal(List arg) { + signaled = arg; + } + + @Override + public List query(List arg) { + List result = new ArrayList<>(); + result.addAll(arg); + result.addAll(signaled); + return result; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/GetAttemptFromWorkflowInfoTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/GetAttemptFromWorkflowInfoTest.java new file mode 100644 index 0000000000..ba1fb6964e --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/GetAttemptFromWorkflowInfoTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.client.WorkflowOptions; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestOptions; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class GetAttemptFromWorkflowInfoTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes( + WorkflowTest.TestMultiargsWorkflowsFuncParent.class, + TestAttemptReturningWorkflowFunc.class) + .build(); + + @Test + public void testGetAttemptFromWorkflowInfo() { + String workflowId = "testGetAttemptWorkflow"; + WorkflowOptions workflowOptions = + TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()) + .toBuilder() + .setWorkflowId(workflowId) + .build(); + TestGetAttemptWorkflowsFunc workflow = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(TestGetAttemptWorkflowsFunc.class, workflowOptions); + int attempt = workflow.func(); + Assert.assertEquals(1, attempt); + } + + @WorkflowInterface + public interface TestGetAttemptWorkflowsFunc { + + @WorkflowMethod + int func(); + } + + public static class TestAttemptReturningWorkflowFunc implements TestGetAttemptWorkflowsFunc { + @Override + public int func() { + WorkflowInfo wi = Workflow.getInfo(); + return wi.getAttempt(); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/HeartbeatTimeoutDetailsTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/HeartbeatTimeoutDetailsTest.java new file mode 100644 index 0000000000..100193e5db --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/HeartbeatTimeoutDetailsTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import io.temporal.activity.ActivityOptions; +import io.temporal.api.enums.v1.TimeoutType; +import io.temporal.failure.ActivityFailure; +import io.temporal.failure.TimeoutFailure; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class HeartbeatTimeoutDetailsTest { + + private static final Logger log = LoggerFactory.getLogger(HeartbeatTimeoutDetailsTest.class); + private final TestActivities.TestActivitiesImpl activitiesImpl = + new TestActivities.TestActivitiesImpl(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestHeartbeatTimeoutDetails.class) + .setActivityImplementations(activitiesImpl) + .build(); + + @Test + public void testHeartbeatTimeoutDetails() { + activitiesImpl.setCompletionClient( + testWorkflowRule.getWorkflowClient().newActivityCompletionClient()); + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.assertEquals("heartbeatValue", result); + } + + public static class TestHeartbeatTimeoutDetails implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + ActivityOptions options = + ActivityOptions.newBuilder() + .setTaskQueue(taskQueue) + .setHeartbeatTimeout(Duration.ofSeconds(1)) // short heartbeat timeout; + .setScheduleToCloseTimeout(Duration.ofSeconds(5)) + .build(); + + TestActivities activities = Workflow.newActivityStub(TestActivities.class, options); + try { + // false for second argument means to heartbeat once to set details and then stop. + activities.activityWithDelay(5000, false); + } catch (ActivityFailure e) { + TimeoutFailure te = (TimeoutFailure) e.getCause(); + log.info("TestHeartbeatTimeoutDetails expected timeout", e); + assertEquals(TimeoutType.TIMEOUT_TYPE_SCHEDULE_TO_CLOSE, te.getTimeoutType()); + assertTrue(te.getCause() instanceof TimeoutFailure); + assertEquals( + TimeoutType.TIMEOUT_TYPE_HEARTBEAT, ((TimeoutFailure) te.getCause()).getTimeoutType()); + return (te.getLastHeartbeatDetails().get(String.class)); + } + throw new RuntimeException("unreachable"); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/LargeHistoryTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/LargeHistoryTest.java new file mode 100644 index 0000000000..d219b1e3e6 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/LargeHistoryTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.activity.ActivityInterface; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestOptions; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LargeHistoryTest { + + private static final Logger log = LoggerFactory.getLogger(LargeHistoryTest.class); + private final TestLargeWorkflowActivityImpl activitiesImpl = new TestLargeWorkflowActivityImpl(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestLargeHistory.class) + .setActivityImplementations(activitiesImpl) + .build(); + + @Test + @Ignore // Requires DEBUG_TIMEOUTS=true + public void testLargeHistory() { + final int activityCount = 1000; + TestLargeWorkflow workflowStub = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestLargeWorkflow.class, + TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()) + .toBuilder() + .setWorkflowTaskTimeout(Duration.ofSeconds(30)) + .build()); + long start = System.currentTimeMillis(); + String result = workflowStub.execute(activityCount, testWorkflowRule.getTaskQueue()); + long duration = System.currentTimeMillis() - start; + log.info(testWorkflowRule.getTestEnvironment().getNamespace() + " duration is " + duration); + Assert.assertEquals("done", result); + } + + @WorkflowInterface + public interface TestLargeWorkflow { + @WorkflowMethod + String execute(int activityCount, String taskQueue); + } + + @ActivityInterface + public interface TestLargeWorkflowActivity { + String activity(); + } + + public static class TestLargeWorkflowActivityImpl implements TestLargeWorkflowActivity { + @Override + public String activity() { + return "done"; + } + } + + public static class TestLargeHistory implements TestLargeWorkflow { + + @Override + public String execute(int activityCount, String taskQueue) { + TestLargeWorkflowActivity activities = + Workflow.newActivityStub( + TestLargeWorkflowActivity.class, + TestOptions.newActivityOptionsForTaskQueue(taskQueue)); + List> results = new ArrayList<>(); + for (int i = 0; i < activityCount; i++) { + Promise result = Async.function(activities::activity); + results.add(result); + } + Promise.allOf(results).get(); + return "done"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/MemoTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/MemoTest.java new file mode 100644 index 0000000000..75200f51b7 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/MemoTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import com.google.protobuf.ByteString; +import com.uber.m3.tally.NoopScope; +import io.temporal.api.common.v1.Memo; +import io.temporal.api.common.v1.Payload; +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.history.v1.HistoryEvent; +import io.temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryResponse; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.common.converter.GsonJsonPayloadConverter; +import io.temporal.internal.common.WorkflowExecutionUtils; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; +import io.temporal.workflow.shared.TestOptions; +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class MemoTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class) + .build(); + + @Test + public void testMemo() { + if (testWorkflowRule.getTestEnvironment() != null) { + String testMemoKey = "testKey"; + String testMemoValue = "testValue"; + Map memo = new HashMap(); + memo.put(testMemoKey, testMemoValue); + + WorkflowOptions workflowOptions = + TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()) + .toBuilder() + .setMemo(memo) + .build(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc stubF = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc.class, + workflowOptions); + WorkflowExecution executionF = WorkflowClient.start(stubF::func); + + GetWorkflowExecutionHistoryResponse historyResp = + WorkflowExecutionUtils.getHistoryPage( + testWorkflowRule.getTestEnvironment().getWorkflowService(), + SDKTestWorkflowRule.NAMESPACE, + executionF, + ByteString.EMPTY, + new NoopScope()); + HistoryEvent startEvent = historyResp.getHistory().getEvents(0); + Memo memoFromEvent = startEvent.getWorkflowExecutionStartedEventAttributes().getMemo(); + Payload memoBytes = memoFromEvent.getFieldsMap().get(testMemoKey); + String memoRetrieved = + GsonJsonPayloadConverter.getInstance().fromData(memoBytes, String.class, String.class); + Assert.assertEquals(testMemoValue, memoRetrieved); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/MultipleTimersTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/MultipleTimersTest.java new file mode 100644 index 0000000000..682648abfb --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/MultipleTimersTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class MultipleTimersTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder().setWorkflowTypes(TestMultipleTimersImpl.class).build(); + + @Test + public void testMultipleTimers() { + TestMultipleTimers workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestMultipleTimers.class); + long result = workflowStub.execute(); + Assert.assertTrue("should be around 1 second: " + result, result < 2000); + } + + @WorkflowInterface + public interface TestMultipleTimers { + @WorkflowMethod + long execute(); + } + + public static class TestMultipleTimersImpl implements TestMultipleTimers { + + @Override + public long execute() { + Promise t1 = Async.procedure(() -> Workflow.sleep(Duration.ofSeconds(1))); + Promise t2 = Async.procedure(() -> Workflow.sleep(Duration.ofSeconds(2))); + long start = Workflow.currentTimeMillis(); + Promise.anyOf(t1, t2).get(); + long elapsed = Workflow.currentTimeMillis() - start; + return elapsed; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/MutableSideEffectTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/MutableSideEffectTest.java new file mode 100644 index 0000000000..ebf5ab1867 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/MutableSideEffectTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import java.util.*; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class MutableSideEffectTest { + + private static final Map> mutableSideEffectValue = + Collections.synchronizedMap(new HashMap<>()); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestMutableSideEffectWorkflowImpl.class) + .build(); + + @Test + public void testMutableSideEffect() { + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + ArrayDeque values = new ArrayDeque(); + values.add(1234L); + values.add(1234L); + values.add(123L); // expected to be ignored as it is smaller than 1234. + values.add(3456L); + values.add(1234L); // expected to be ignored as it is smaller than 3456L. + values.add(4234L); + values.add(4234L); + values.add(3456L); // expected to be ignored as it is smaller than 4234L. + mutableSideEffectValue.put(testWorkflowRule.getTaskQueue(), values); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.assertEquals("1234, 1234, 1234, 3456, 3456, 4234, 4234, 4234", result); + } + + public static class TestMutableSideEffectWorkflowImpl implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + StringBuilder result = new StringBuilder(); + for (int j = 0; j < 1; j++) { + for (int i = 0; i < 8; i++) { + long value = + Workflow.mutableSideEffect( + "id1", + Long.class, + (o, n) -> n > o, + () -> mutableSideEffectValue.get(taskQueue).poll()); + if (result.length() > 0) { + result.append(", "); + } + result.append(value); + // Sleep is here to ensure that mutableSideEffect works when replaying a history. + if (i >= 8) { + Workflow.sleep(Duration.ofSeconds(1)); + } + } + } + return result.toString(); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/NoQueryThreadLeakTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/NoQueryThreadLeakTest.java new file mode 100644 index 0000000000..1929e5f17b --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/NoQueryThreadLeakTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowStub; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import java.lang.management.ManagementFactory; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class NoQueryThreadLeakTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder().setWorkflowTypes(TestNoQueryWorkflowImpl.class).build(); + + @Test + public void testNoQueryThreadLeak() throws InterruptedException { + int threadCount = ManagementFactory.getThreadMXBean().getThreadCount(); + WorkflowTest.QueryableWorkflow client = + testWorkflowRule.newWorkflowStubTimeoutOptions(WorkflowTest.QueryableWorkflow.class); + WorkflowClient.start(client::execute); + testWorkflowRule.sleep(Duration.ofSeconds(1)); + // Calls query multiple times to check at the end of the method that if it doesn't leak threads + int queryCount = 100; + for (int i = 0; i < queryCount; i++) { + Assert.assertEquals("some state", client.getState()); + if (SDKTestWorkflowRule.useExternalService) { + // Sleep a little bit to avoid server throttling error. + Thread.sleep(50); + } + } + client.mySignal("Hello "); + WorkflowStub.fromTyped(client).getResult(String.class); + // Ensures that no threads were leaked due to query + int threadsCreated = ManagementFactory.getThreadMXBean().getThreadCount() - threadCount; + Assert.assertTrue("query leaks threads: " + threadsCreated, threadsCreated < queryCount); + } + + public static class TestNoQueryWorkflowImpl implements WorkflowTest.QueryableWorkflow { + + CompletablePromise promise = Workflow.newPromise(); + + @Override + public String execute() { + promise.get(); + return "done"; + } + + @Override + public String getState() { + return "some state"; + } + + @Override + public void mySignal(String value) { + promise.complete(null); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/NonDeterministicWorkflowPolicyBlockWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/NonDeterministicWorkflowPolicyBlockWorkflowTest.java new file mode 100644 index 0000000000..24f8e0c381 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/NonDeterministicWorkflowPolicyBlockWorkflowTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.client.WorkflowFailedException; +import io.temporal.client.WorkflowOptions; +import io.temporal.failure.TimeoutFailure; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class NonDeterministicWorkflowPolicyBlockWorkflowTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(WorkflowTest.DeterminismFailingWorkflowImpl.class) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .build(); + + @Test + public void testNonDeterministicWorkflowPolicyBlockWorkflow() { + WorkflowOptions options = + WorkflowOptions.newBuilder() + .setWorkflowRunTimeout(Duration.ofSeconds(5)) + .setWorkflowTaskTimeout(Duration.ofSeconds(1)) + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build(); + WorkflowTest.DeterminismFailingWorkflow workflowStub = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(WorkflowTest.DeterminismFailingWorkflow.class, options); + try { + workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.fail("unreachable"); + } catch (WorkflowFailedException e) { + // expected to timeout as workflow is going get blocked. + Assert.assertTrue(e.getCause() instanceof TimeoutFailure); + } + + int workflowRootThreads = 0; + ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads(false, false); + for (ThreadInfo thread : threads) { + if (thread.getThreadName().contains("workflow-root")) { + workflowRootThreads++; + } + } + + Assert.assertTrue("workflow threads might leak", workflowRootThreads < 10); + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/NonDeterministicWorkflowPolicyFailWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/NonDeterministicWorkflowPolicyFailWorkflowTest.java new file mode 100644 index 0000000000..c86ba2674b --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/NonDeterministicWorkflowPolicyFailWorkflowTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.client.WorkflowFailedException; +import io.temporal.client.WorkflowOptions; +import io.temporal.failure.ApplicationFailure; +import io.temporal.internal.replay.InternalWorkflowTaskException; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.worker.WorkflowImplementationOptions; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class NonDeterministicWorkflowPolicyFailWorkflowTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) + .setWorkflowTypes( + WorkflowImplementationOptions.newBuilder() + .setFailWorkflowExceptionTypes(Throwable.class) + .build(), + WorkflowTest.DeterminismFailingWorkflowImpl.class) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .build(); + + @Test + public void testNonDeterministicWorkflowPolicyFailWorkflow() { + WorkflowOptions options = + WorkflowOptions.newBuilder() + .setWorkflowRunTimeout(Duration.ofSeconds(1)) + .setWorkflowTaskTimeout(Duration.ofSeconds(1)) + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build(); + WorkflowTest.DeterminismFailingWorkflow workflowStub = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(WorkflowTest.DeterminismFailingWorkflow.class, options); + try { + workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.fail("unreachable"); + } catch (WorkflowFailedException e) { + // expected to fail on non deterministic error + Assert.assertTrue(e.getCause() instanceof ApplicationFailure); + Assert.assertEquals( + InternalWorkflowTaskException.class.getName(), + ((ApplicationFailure) e.getCause()).getType()); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ParentContinueAsNewTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/ParentContinueAsNewTest.java new file mode 100644 index 0000000000..1a02e6f7d1 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/ParentContinueAsNewTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.api.enums.v1.WorkflowIdReusePolicy; +import io.temporal.client.WorkflowOptions; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class ParentContinueAsNewTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestParentWorkflowContinueAsNew.class, WorkflowTest.TestChild.class) + .build(); + + /** Reproduction of a bug when a child of continued as new workflow has the same UUID ID. */ + @Test + public void testParentContinueAsNew() { + + WorkflowOptions options = + WorkflowOptions.newBuilder() + .setWorkflowRunTimeout(Duration.ofSeconds(200)) + .setWorkflowTaskTimeout(Duration.ofSeconds(60)) + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build(); + TestWorkflows.TestWorkflow1 client = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); + Assert.assertEquals("foo", client.execute("not empty")); + } + + public static class TestParentWorkflowContinueAsNew implements TestWorkflows.TestWorkflow1 { + + private final WorkflowTest.ITestChild child1 = + Workflow.newChildWorkflowStub( + WorkflowTest.ITestChild.class, + ChildWorkflowOptions.newBuilder() + .setWorkflowIdReusePolicy( + WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE) + .build()); + private final TestWorkflows.TestWorkflow1 self = + Workflow.newContinueAsNewStub(TestWorkflows.TestWorkflow1.class); + + @Override + public String execute(String arg) { + child1.execute("Hello", 0); + if (arg.length() > 0) { + self.execute(""); // continue as new + } + return "foo"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/PolymorphicStartTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/PolymorphicStartTest.java new file mode 100644 index 0000000000..be98e4846f --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/PolymorphicStartTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class PolymorphicStartTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(WorkflowAImpl.class, WorkflowBImpl.class) + .build(); + + @Test + public void testPolymorphicStart() { + WorkflowBase[] stubs = + new WorkflowBase[] { + testWorkflowRule.newWorkflowStubTimeoutOptions(WorkflowA.class), + testWorkflowRule.newWorkflowStubTimeoutOptions(WorkflowB.class) + }; + String results = stubs[0].execute("0") + ", " + stubs[1].execute("1"); + Assert.assertEquals("WorkflowAImpl0, WorkflowBImpl1", results); + } + + public interface WorkflowBase { + @WorkflowMethod + String execute(String arg); + } + + @WorkflowInterface + public interface WorkflowA extends WorkflowBase {} + + @WorkflowInterface + public interface WorkflowB extends WorkflowBase {} + + public static class WorkflowBImpl implements WorkflowB { + @Override + public String execute(String arg) { + return "WorkflowBImpl" + arg; + } + } + + public static class WorkflowAImpl implements WorkflowA { + @Override + public String execute(String arg) { + return "WorkflowAImpl" + arg; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/SagaTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/SagaTest.java new file mode 100644 index 0000000000..349a0e2169 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/SagaTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.common.RetryOptions; +import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; +import io.temporal.workflow.shared.TestOptions; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class SagaTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes( + TestSagaWorkflowImpl.class, + TestCompensationWorkflowImpl.class, + TestMultiargsWorkflowsFuncImpl.class) + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) + .setWorkerInterceptors( + new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) + .build(); + + @Test + public void testSaga() { + TestSagaWorkflow sagaWorkflow = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestSagaWorkflow.class); + sagaWorkflow.execute(testWorkflowRule.getTaskQueue(), false); + testWorkflowRule + .getInterceptor(TracingWorkerInterceptor.class) + .setExpected( + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "executeActivity customActivity1", + "activity customActivity1", + "executeChildWorkflow TestMultiargsWorkflowsFunc", + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "executeActivity ThrowIO", + "activity ThrowIO", + "executeChildWorkflow TestCompensationWorkflow", + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "executeActivity Activity2", + "activity Activity2"); + } + + @Test + public void testSagaParallelCompensation() { + TestSagaWorkflow sagaWorkflow = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestSagaWorkflow.class); + sagaWorkflow.execute(testWorkflowRule.getTaskQueue(), true); + String trace = testWorkflowRule.getInterceptor(TracingWorkerInterceptor.class).getTrace(); + Assert.assertTrue(trace, trace.contains("executeChildWorkflow TestCompensationWorkflow")); + Assert.assertTrue(trace, trace.contains("executeActivity Activity2")); + } + + @WorkflowInterface + public interface TestSagaWorkflow { + @WorkflowMethod + String execute(String taskQueue, boolean parallelCompensation); + } + + @WorkflowInterface + public interface TestCompensationWorkflow { + @WorkflowMethod + void compensate(); + } + + public static class TestCompensationWorkflowImpl implements TestCompensationWorkflow { + @Override + public void compensate() {} + } + + public static class TestSagaWorkflowImpl implements TestSagaWorkflow { + + @Override + public String execute(String taskQueue, boolean parallelCompensation) { + TestActivities testActivities = + Workflow.newActivityStub( + TestActivities.class, + TestOptions.newActivityOptionsForTaskQueue(taskQueue) + .toBuilder() + .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(1).build()) + .build()); + + ChildWorkflowOptions workflowOptions = + ChildWorkflowOptions.newBuilder().setTaskQueue(taskQueue).build(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc stubF1 = + Workflow.newChildWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc.class, workflowOptions); + + Saga saga = + new Saga( + new Saga.Options.Builder().setParallelCompensation(parallelCompensation).build()); + try { + testActivities.activity1(10); + saga.addCompensation(testActivities::activity2, "compensate", -10); + + stubF1.func(); + + TestCompensationWorkflow compensationWorkflow = + Workflow.newChildWorkflowStub(TestCompensationWorkflow.class, workflowOptions); + saga.addCompensation(compensationWorkflow::compensate); + + testActivities.throwIO(); + saga.addCompensation( + () -> { + throw new RuntimeException("unreachable"); + }); + } catch (Exception e) { + saga.compensate(); + } + return "done"; + } + } + + public static class TestMultiargsWorkflowsFuncImpl + implements TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc { + + @Override + public String func() { + return "done"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/SearchAttributesTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/SearchAttributesTest.java new file mode 100644 index 0000000000..1b8bd08788 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/SearchAttributesTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.assertEquals; + +import com.google.protobuf.ByteString; +import com.uber.m3.tally.NoopScope; +import io.temporal.api.common.v1.Payload; +import io.temporal.api.common.v1.SearchAttributes; +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.history.v1.HistoryEvent; +import io.temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryResponse; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.common.converter.DataConverter; +import io.temporal.internal.common.WorkflowExecutionUtils; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; +import io.temporal.workflow.shared.TestOptions; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; +import org.junit.Rule; +import org.junit.Test; + +public class SearchAttributesTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class) + .build(); + + @Test + public void testSearchAttributes() { + if (SDKTestWorkflowRule.useExternalService) { + return; + } + String testKeyString = "CustomKeywordField"; + String testValueString = "testKeyword"; + String testKeyInteger = "CustomIntField"; + Integer testValueInteger = 1; + String testKeyDateTime = "CustomDatetimeField"; + LocalDateTime testValueDateTime = LocalDateTime.now(); + String testKeyBool = "CustomBoolField"; + Boolean testValueBool = true; + String testKeyDouble = "CustomDoubleField"; + Double testValueDouble = 1.23; + + // add more type to test + Map searchAttr = new HashMap<>(); + searchAttr.put(testKeyString, testValueString); + searchAttr.put(testKeyInteger, testValueInteger); + searchAttr.put(testKeyDateTime, testValueDateTime); + searchAttr.put(testKeyBool, testValueBool); + searchAttr.put(testKeyDouble, testValueDouble); + + WorkflowOptions workflowOptions = + TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()) + .toBuilder() + .setSearchAttributes(searchAttr) + .build(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc stubF = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc.class, workflowOptions); + WorkflowExecution executionF = WorkflowClient.start(stubF::func); + + GetWorkflowExecutionHistoryResponse historyResp = + WorkflowExecutionUtils.getHistoryPage( + testWorkflowRule.getTestEnvironment().getWorkflowService(), + SDKTestWorkflowRule.NAMESPACE, + executionF, + ByteString.EMPTY, + new NoopScope()); + HistoryEvent startEvent = historyResp.getHistory().getEvents(0); + SearchAttributes searchAttrFromEvent = + startEvent.getWorkflowExecutionStartedEventAttributes().getSearchAttributes(); + + Map fieldsMap = searchAttrFromEvent.getIndexedFieldsMap(); + Payload searchAttrStringBytes = fieldsMap.get(testKeyString); + DataConverter converter = DataConverter.getDefaultInstance(); + String retrievedString = + converter.fromPayload(searchAttrStringBytes, String.class, String.class); + assertEquals(testValueString, retrievedString); + Payload searchAttrIntegerBytes = fieldsMap.get(testKeyInteger); + Integer retrievedInteger = + converter.fromPayload(searchAttrIntegerBytes, Integer.class, Integer.class); + assertEquals(testValueInteger, retrievedInteger); + Payload searchAttrDateTimeBytes = fieldsMap.get(testKeyDateTime); + LocalDateTime retrievedDateTime = + converter.fromPayload(searchAttrDateTimeBytes, LocalDateTime.class, LocalDateTime.class); + assertEquals(testValueDateTime, retrievedDateTime); + Payload searchAttrBoolBytes = fieldsMap.get(testKeyBool); + Boolean retrievedBool = + converter.fromPayload(searchAttrBoolBytes, Boolean.class, Boolean.class); + assertEquals(testValueBool, retrievedBool); + Payload searchAttrDoubleBytes = fieldsMap.get(testKeyDouble); + Double retrievedDouble = + converter.fromPayload(searchAttrDoubleBytes, Double.class, Double.class); + assertEquals(testValueDouble, retrievedDouble); + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/SideEffectTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/SideEffectTest.java new file mode 100644 index 0000000000..18fb0a1f51 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/SideEffectTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.assertEquals; + +import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class SideEffectTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestSideEffectWorkflowImpl.class) + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) + .setWorkerInterceptors( + new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) + .build(); + + @Test + public void testSideEffect() { + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.assertEquals("activity1", result); + testWorkflowRule + .getInterceptor(TracingWorkerInterceptor.class) + .setExpected( + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "currentTimeMillis", + "sideEffect", + "sideEffect", + "sleep PT1S", + "executeActivity customActivity1", + "activity customActivity1"); + } + + public static class TestSideEffectWorkflowImpl implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + TestActivities testActivities = + Workflow.newActivityStub( + TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); + + long workflowTime = Workflow.currentTimeMillis(); + long time1 = Workflow.sideEffect(long.class, () -> workflowTime); + long time2 = Workflow.sideEffect(long.class, () -> workflowTime); + assertEquals(time1, time2); + Workflow.sleep(Duration.ofSeconds(1)); + String result; + if (workflowTime == time1) { + result = "activity" + testActivities.activity1(1); + } else { + result = testActivities.activity2("activity2", 2); + } + return result; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/StartTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/StartTest.java new file mode 100644 index 0000000000..c3e5c2fe4b --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/StartTest.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.assertEquals; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.enums.v1.WorkflowIdReusePolicy; +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; +import io.temporal.workflow.shared.TestOptions; +import java.util.Optional; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class StartTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class) + .build(); + + @Test + public void testStart() { + WorkflowOptions workflowOptions = + TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()) + .toBuilder() + .setWorkflowIdReusePolicy( + WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE) + .build(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc stubF = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc.class, workflowOptions); + assertResult("func", WorkflowClient.start(stubF::func)); + Assert.assertEquals( + "func", stubF.func()); // Check that duplicated start just returns the result. + WorkflowOptions options = + WorkflowOptions.newBuilder().setTaskQueue(testWorkflowRule.getTaskQueue()).build(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1 stubF1 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1.class, options); + + if (!SDKTestWorkflowRule.useExternalService) { + // Use worker that polls on a task queue configured through @WorkflowMethod annotation of + // func1 + assertResult(1, WorkflowClient.start(stubF1::func1, 1)); + Assert.assertEquals( + 1, stubF1.func1(1)); // Check that duplicated start just returns the result. + } + // Check that duplicated start is not allowed for AllowDuplicate IdReusePolicy + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc2 stubF2 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc2.class, + TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()) + .toBuilder() + .setWorkflowIdReusePolicy( + WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE) + .build()); + assertResult("12", WorkflowClient.start(stubF2::func2, "1", 2)); + try { + stubF2.func2("1", 2); + Assert.fail("unreachable"); + } catch (IllegalStateException e) { + // expected + } + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc3 stubF3 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc3.class, workflowOptions); + assertResult("123", WorkflowClient.start(stubF3::func3, "1", 2, 3)); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc4 stubF4 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc4.class, workflowOptions); + assertResult("1234", WorkflowClient.start(stubF4::func4, "1", 2, 3, 4)); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc5 stubF5 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc5.class, workflowOptions); + assertResult("12345", WorkflowClient.start(stubF5::func5, "1", 2, 3, 4, 5)); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc6 stubF6 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc6.class, workflowOptions); + assertResult("123456", WorkflowClient.start(stubF6::func6, "1", 2, 3, 4, 5, 6)); + + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc stubP = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc.class, workflowOptions); + waitForProc(WorkflowClient.start(stubP::proc)); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc1 stubP1 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc1.class, workflowOptions); + waitForProc(WorkflowClient.start(stubP1::proc1, "1")); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc2 stubP2 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc2.class, workflowOptions); + waitForProc(WorkflowClient.start(stubP2::proc2, "1", 2)); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc3 stubP3 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc3.class, workflowOptions); + waitForProc(WorkflowClient.start(stubP3::proc3, "1", 2, 3)); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc4 stubP4 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc4.class, workflowOptions); + waitForProc(WorkflowClient.start(stubP4::proc4, "1", 2, 3, 4)); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc5 stubP5 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc5.class, workflowOptions); + waitForProc(WorkflowClient.start(stubP5::proc5, "1", 2, 3, 4, 5)); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc6 stubP6 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc6.class, workflowOptions); + waitForProc(WorkflowClient.start(stubP6::proc6, "1", 2, 3, 4, 5, 6)); + + Assert.assertEquals("proc", stubP.query()); + Assert.assertEquals("1", stubP1.query()); + Assert.assertEquals("12", stubP2.query()); + Assert.assertEquals("123", stubP3.query()); + Assert.assertEquals("1234", stubP4.query()); + Assert.assertEquals("12345", stubP5.query()); + Assert.assertEquals("123456", stubP6.query()); + } + + private void assertResult(String expected, WorkflowExecution execution) { + String result = + testWorkflowRule + .getWorkflowClient() + .newUntypedWorkflowStub(execution, Optional.empty()) + .getResult(String.class); + assertEquals(expected, result); + } + + private void assertResult(int expected, WorkflowExecution execution) { + int result = + testWorkflowRule + .getWorkflowClient() + .newUntypedWorkflowStub(execution, Optional.empty()) + .getResult(int.class); + assertEquals(expected, result); + } + + private void waitForProc(WorkflowExecution execution) { + testWorkflowRule + .getWorkflowClient() + .newUntypedWorkflowStub(execution, Optional.empty()) + .getResult(Void.class); + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/SyncTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/SyncTest.java new file mode 100644 index 0000000000..73a1c62f3b --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/SyncTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static io.temporal.client.WorkflowClient.QUERY_TYPE_STACK_TRACE; +import static org.junit.Assert.*; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.client.WorkflowFailedException; +import io.temporal.client.WorkflowStub; +import io.temporal.failure.CanceledFailure; +import io.temporal.failure.TerminatedFailure; +import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class SyncTest { + + private final TestActivities.TestActivitiesImpl activitiesImpl = + new TestActivities.TestActivitiesImpl(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestSyncWorkflowImpl.class) + .setActivityImplementations(activitiesImpl) + .setWorkerInterceptors( + new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) + .build(); + + @Test + public void testSync() { + activitiesImpl.setCompletionClient( + testWorkflowRule.getWorkflowClient().newActivityCompletionClient()); + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.assertEquals("activity10", result); + testWorkflowRule + .getInterceptor(TracingWorkerInterceptor.class) + .setExpected( + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "newThread null", + "sleep PT2S", + "executeActivity ActivityWithDelay", + "activity ActivityWithDelay", + "executeActivity Activity2", + "activity Activity2"); + } + + @Test + public void testSyncUntypedAndStackTrace() { + activitiesImpl.setCompletionClient( + testWorkflowRule.getWorkflowClient().newActivityCompletionClient()); + WorkflowStub workflowStub = + testWorkflowRule.newUntypedWorkflowStubTimeoutOptions("TestWorkflow1"); + WorkflowExecution execution = workflowStub.start(testWorkflowRule.getTaskQueue()); + testWorkflowRule.sleep(Duration.ofMillis(500)); + String stackTrace = workflowStub.query(QUERY_TYPE_STACK_TRACE, String.class); + assertTrue(stackTrace, stackTrace.contains("TestSyncWorkflowImpl.execute")); + assertTrue(stackTrace, stackTrace.contains("activityWithDelay")); + // Test stub created from workflow execution. + workflowStub = + testWorkflowRule + .getWorkflowClient() + .newUntypedWorkflowStub(execution, workflowStub.getWorkflowType()); + stackTrace = workflowStub.query(QUERY_TYPE_STACK_TRACE, String.class); + assertTrue(stackTrace, stackTrace.contains("TestSyncWorkflowImpl.execute")); + assertTrue(stackTrace, stackTrace.contains("activityWithDelay")); + String result = workflowStub.getResult(String.class); + assertEquals("activity10", result); + } + + @Test + public void testWorkflowCancellation() { + WorkflowStub client = testWorkflowRule.newUntypedWorkflowStubTimeoutOptions("TestWorkflow1"); + client.start(testWorkflowRule.getTaskQueue()); + client.cancel(); + try { + client.getResult(String.class); + fail("unreachable"); + } catch (WorkflowFailedException e) { + assertTrue(e.getCause() instanceof CanceledFailure); + } + } + + @Test + public void testWorkflowTermination() throws InterruptedException { + WorkflowStub client = testWorkflowRule.newUntypedWorkflowStubTimeoutOptions("TestWorkflow1"); + client.start(testWorkflowRule.getTaskQueue()); + Thread.sleep(1000); + client.terminate("boo", "detail1", "detail2"); + try { + client.getResult(String.class); + fail("unreachable"); + } catch (WorkflowFailedException ignored) { + assertTrue(ignored.getCause() instanceof TerminatedFailure); + assertEquals("boo", ((TerminatedFailure) ignored.getCause()).getOriginalMessage()); + } + } + + public static class TestSyncWorkflowImpl implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + TestActivities activities = + Workflow.newActivityStub( + TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); + // Invoke synchronously in a separate thread for testing purposes only. + // In real workflows use + // Async.procedure(activities::activityWithDelay, 1000, true) + Promise a1 = Async.function(() -> activities.activityWithDelay(1000, true)); + Workflow.sleep(2000); + return activities.activity2(a1.get(), 10); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/TimerCallbackBlockedTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/TimerCallbackBlockedTest.java new file mode 100644 index 0000000000..2c975022df --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/TimerCallbackBlockedTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.client.WorkflowOptions; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class TimerCallbackBlockedTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestTimerCallbackBlockedWorkflowImpl.class) + .build(); + + /** Test that it is not allowed to block in the timer callback thread. */ + @Test + public void testTimerCallbackBlocked() { + WorkflowOptions options = + WorkflowOptions.newBuilder() + .setWorkflowRunTimeout(Duration.ofSeconds(10)) + .setWorkflowTaskTimeout(Duration.ofSeconds(1)) + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build(); + TestWorkflows.TestWorkflow1 client = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); + String result = client.execute(testWorkflowRule.getTaskQueue()); + Assert.assertEquals("timer2Fired", result); + } + + public static class TestTimerCallbackBlockedWorkflowImpl implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + Promise timer1 = Workflow.newTimer(Duration.ZERO); + Promise timer2 = Workflow.newTimer(Duration.ofSeconds(1)); + + return timer1 + .thenApply( + e -> { + timer2.get(); + return "timer2Fired"; + }) + .get(); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/TimerTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/TimerTest.java new file mode 100644 index 0000000000..38609b1b8f --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/TimerTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.assertTrue; + +import io.temporal.client.WorkflowOptions; +import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import java.util.List; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class TimerTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestTimerWorkflowImpl.class) + .setWorkerInterceptors( + new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) + .build(); + + @Test + public void testTimer() { + WorkflowOptions options; + if (SDKTestWorkflowRule.useExternalService) { + options = TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()); + } else { + options = + TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()) + .toBuilder() + .setWorkflowRunTimeout(Duration.ofDays(1)) + .build(); + } + TestWorkflows.TestWorkflow2 client = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(TestWorkflows.TestWorkflow2.class, options); + String result = client.execute(SDKTestWorkflowRule.useExternalService); + Assert.assertEquals("testTimer", result); + if (SDKTestWorkflowRule.useExternalService) { + testWorkflowRule + .getInterceptor(TracingWorkerInterceptor.class) + .setExpected( + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "registerQuery getTrace", + "newThread workflow-method", + "newTimer PT0.7S", + "newTimer PT1.3S", + "currentTimeMillis", + "newTimer PT10S", + "currentTimeMillis", + "currentTimeMillis", + "currentTimeMillis"); + } else { + testWorkflowRule + .getInterceptor(TracingWorkerInterceptor.class) + .setExpected( + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "registerQuery getTrace", + "newThread workflow-method", + "newTimer PT11M40S", + "newTimer PT21M40S", + "currentTimeMillis", + "newTimer PT10H", + "currentTimeMillis", + "currentTimeMillis", + "currentTimeMillis"); + } + } + + public static class TestTimerWorkflowImpl implements TestWorkflows.TestWorkflow2 { + + @Override + public String execute(boolean useExternalService) { + Promise timer1; + Promise timer2; + Duration timeout1 = useExternalService ? Duration.ofMillis(700) : Duration.ofSeconds(700); + Duration timeout2 = useExternalService ? Duration.ofMillis(1300) : Duration.ofSeconds(1300); + timer1 = Workflow.newTimer(timeout1); + timer2 = Workflow.newTimer(timeout2); + long time = Workflow.currentTimeMillis(); + timer1 + .thenApply( + r -> { + // Testing that timer can be created from a callback thread. + if (useExternalService) { + Workflow.newTimer(Duration.ofSeconds(10)); + } else { + Workflow.newTimer(Duration.ofHours(10)); + } + Workflow.currentTimeMillis(); // Testing that time is available here. + return r; + }) + .get(); + timer1.get(); + long slept = Workflow.currentTimeMillis() - time; + // Also checks that rounding up to a second works. + assertTrue(slept + "<" + timeout1.toMillis(), slept >= timeout1.toMillis()); + timer2.get(); + slept = Workflow.currentTimeMillis() - time; + assertTrue(String.valueOf(slept), slept >= timeout2.toMillis()); + return "testTimer"; + } + + @Override + public List getTrace() { + throw new UnsupportedOperationException("not implemented"); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/UUIDAndRandomTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/UUIDAndRandomTest.java new file mode 100644 index 0000000000..84a1e98d66 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/UUIDAndRandomTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.assertEquals; + +import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.util.Random; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class UUIDAndRandomTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestUUIDAndRandom.class) + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) + .setWorkerInterceptors( + new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) + .build(); + + @Test + public void testUUIDAndRandom() { + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.assertEquals("foo10", result); + testWorkflowRule + .getInterceptor(TracingWorkerInterceptor.class) + .setExpected( + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "sideEffect", + "sideEffect", + "executeActivity Activity2", + "activity Activity2"); + } + + public static class TestUUIDAndRandom implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + TestActivities activities = + Workflow.newActivityStub( + TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); + Random rand1 = Workflow.newRandom(); + int r11 = rand1.nextInt(); + int r12 = r11 + rand1.nextInt(); + int savedInt = Workflow.sideEffect(int.class, () -> r12); + String id = Workflow.randomUUID().toString() + "-" + Workflow.randomUUID().toString(); + String savedId = Workflow.sideEffect(String.class, () -> id); + // Invoke activity in a blocking mode to ensure that asserts run after replay. + String result = activities.activity2("foo", 10); + // Assert that during replay values didn't change. + assertEquals(savedId, id); + assertEquals(savedInt, r12); + return result; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/UntypedChildStubWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/UntypedChildStubWorkflowTest.java deleted file mode 100644 index 0f13bc1543..0000000000 --- a/temporal-sdk/src/test/java/io/temporal/workflow/UntypedChildStubWorkflowTest.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. - * - * Copyright 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 file except in compliance with the License. A copy of the License is - * located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file 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.workflow; - -import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; -import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; -import io.temporal.workflow.shared.TestWorkflows; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; - -public class UntypedChildStubWorkflowTest { - - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - - @Rule - public SDKTestWorkflowRule testWorkflowRule = - SDKTestWorkflowRule.newBuilder() - .setWorkflowTypes( - WorkflowTest.TestUntypedChildStubWorkflow.class, - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class) - .setActivityImplementations(activitiesImpl) - .build(); - - @Test - public void testUntypedChildStubWorkflow() { - TestWorkflows.TestWorkflow1 client = - testWorkflowRule.newWorkflowStub200sTimeoutOptions(TestWorkflows.TestWorkflow1.class); - Assert.assertEquals(null, client.execute(testWorkflowRule.getTaskQueue())); - } -} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/UpsertSearchAttributesTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/UpsertSearchAttributesTest.java new file mode 100644 index 0000000000..84629d00fb --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/UpsertSearchAttributesTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import io.temporal.api.common.v1.SearchAttributes; +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.enums.v1.EventType; +import io.temporal.api.history.v1.History; +import io.temporal.api.history.v1.HistoryEvent; +import io.temporal.client.WorkflowClient; +import io.temporal.internal.common.SearchAttributesUtil; +import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import java.util.HashMap; +import java.util.Map; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class UpsertSearchAttributesTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestUpsertSearchAttributesImpl.class) + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) + .setWorkerInterceptors( + new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) + .build(); + + @Test + public void testUpsertSearchAttributes() { + TestUpsertSearchAttributes testWorkflow = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestUpsertSearchAttributes.class); + WorkflowExecution execution = + WorkflowClient.start(testWorkflow::execute, testWorkflowRule.getTaskQueue(), "testKey"); + String result = testWorkflow.execute(testWorkflowRule.getTaskQueue(), "testKey"); + Assert.assertEquals("done", result); + testWorkflowRule + .getInterceptor(TracingWorkerInterceptor.class) + .setExpected( + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "upsertSearchAttributes", + "executeActivity Activity", + "activity Activity"); + History history = testWorkflowRule.getWorkflowExecutionHistory(execution); + + boolean found = false; + for (HistoryEvent event : history.getEventsList()) { + if (EventType.EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES == event.getEventType()) { + found = true; + break; + } + } + Assert.assertTrue("EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES found in the history", found); + } + + @WorkflowInterface + public interface TestUpsertSearchAttributes { + @WorkflowMethod + String execute(String taskQueue, String keyword); + } + + public static class TestUpsertSearchAttributesImpl implements TestUpsertSearchAttributes { + + @Override + public String execute(String taskQueue, String keyword) { + SearchAttributes searchAttributes = Workflow.getInfo().getSearchAttributes(); + assertNull(searchAttributes); + + Map searchAttrMap = new HashMap<>(); + searchAttrMap.put("CustomKeywordField", keyword); + Workflow.upsertSearchAttributes(searchAttrMap); + + searchAttributes = Workflow.getInfo().getSearchAttributes(); + assertEquals( + "testKey", + SearchAttributesUtil.getValueFromSearchAttributes( + searchAttributes, "CustomKeywordField", String.class)); + + // Running the activity below ensures that we have one more workflow task to be executed after + // adding the search attributes. This helps with replaying the history one more time to check + // against a possible NonDeterminisicWorkflowError which could be caused by missing + // UpsertWorkflowSearchAttributes event in history. + TestActivities activities = + Workflow.newActivityStub( + TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); + activities.activity(); + + return "done"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowCancellationScopePromiseTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowCancellationScopePromiseTest.java new file mode 100644 index 0000000000..41275a0fb0 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowCancellationScopePromiseTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.client.WorkflowFailedException; +import io.temporal.client.WorkflowStub; +import io.temporal.failure.CanceledFailure; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestWorkflows; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class WorkflowCancellationScopePromiseTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder().setWorkflowTypes(TestCancellationScopePromise.class).build(); + + @Test + public void testWorkflowCancellationScopePromise() { + WorkflowStub client = testWorkflowRule.newUntypedWorkflowStubTimeoutOptions("TestWorkflow1"); + client.start(testWorkflowRule.getTaskQueue()); + client.cancel(); + try { + client.getResult(String.class); + Assert.fail("unreachable"); + } catch (WorkflowFailedException e) { + Assert.assertTrue(e.getCause() instanceof CanceledFailure); + } + } + + public static class TestCancellationScopePromise implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + Promise cancellationRequest = CancellationScope.current().getCancellationRequest(); + cancellationRequest.get(); + return "done"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowFailureNonRetryableFlagTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowFailureNonRetryableFlagTest.java new file mode 100644 index 0000000000..347e6e67e0 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowFailureNonRetryableFlagTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.client.WorkflowException; +import io.temporal.common.RetryOptions; +import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestOptions; +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +public class WorkflowFailureNonRetryableFlagTest { + + private static final Map retryCount = new ConcurrentHashMap<>(); + + @Rule public TestName testName = new TestName(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder().setWorkflowTypes(TestWorkflowNonRetryableFlag.class).build(); + + @Test + public void testWorkflowFailureNonRetryableFlag() { + RetryOptions workflowRetryOptions = + RetryOptions.newBuilder() + .setInitialInterval(Duration.ofSeconds(1)) + .setMaximumAttempts(100) + .setBackoffCoefficient(1.0) + .build(); + WorkflowTest.TestWorkflowRetry workflowStub = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + WorkflowTest.TestWorkflowRetry.class, + TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()) + .toBuilder() + .setRetryOptions(workflowRetryOptions) + .build()); + try { + workflowStub.execute(testName.getMethodName()); + Assert.fail("unreachable"); + } catch (WorkflowException e) { + Assert.assertTrue(e.getCause() instanceof ApplicationFailure); + Assert.assertEquals("foo", ((ApplicationFailure) e.getCause()).getType()); + Assert.assertEquals( + "details1", ((ApplicationFailure) e.getCause()).getDetails().get(0, String.class)); + Assert.assertEquals( + Integer.valueOf(123), + ((ApplicationFailure) e.getCause()).getDetails().get(1, Integer.class)); + Assert.assertEquals( + "message='simulated 3', type='foo', nonRetryable=true", e.getCause().getMessage()); + } + } + + public static class TestWorkflowNonRetryableFlag implements WorkflowTest.TestWorkflowRetry { + + @Override + public String execute(String testName) { + AtomicInteger count = retryCount.get(testName); + if (count == null) { + count = new AtomicInteger(); + retryCount.put(testName, count); + } + int c = count.incrementAndGet(); + ApplicationFailure f = + ApplicationFailure.newFailure("simulated " + c, "foo", "details1", 123); + if (c == 3) { + f.setNonRetryable(true); + } + throw f; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowIdResuePolicyTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowIdResuePolicyTest.java new file mode 100644 index 0000000000..aaf87fcedf --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowIdResuePolicyTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.api.enums.v1.WorkflowIdReusePolicy; +import io.temporal.client.WorkflowOptions; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; +import io.temporal.workflow.shared.TestOptions; +import java.util.UUID; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class WorkflowIdResuePolicyTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class) + .build(); + + @Test + public void testWorkflowIdResuePolicy() { + // When WorkflowIdReusePolicy is not AllowDuplicate the semantics is to get result for the + // previous run. + String workflowId = UUID.randomUUID().toString(); + WorkflowOptions workflowOptions = + TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()) + .toBuilder() + .setWorkflowIdReusePolicy( + WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE_FAILED_ONLY) + .setWorkflowId(workflowId) + .build(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1 stubF1_1 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1.class, workflowOptions); + Assert.assertEquals(1, stubF1_1.func1(1)); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1 stubF1_2 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1.class, workflowOptions); + Assert.assertEquals(1, stubF1_2.func1(2)); + + // Setting WorkflowIdReusePolicy to AllowDuplicate will trigger new run. + workflowOptions = + TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()) + .toBuilder() + .setWorkflowIdReusePolicy( + WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE) + .setWorkflowId(workflowId) + .build(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1 stubF1_3 = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1.class, workflowOptions); + Assert.assertEquals(2, stubF1_3.func1(2)); + + // Setting WorkflowIdReusePolicy to RejectDuplicate or AllowDuplicateFailedOnly does not work as + // expected. See https://github.com/uber/cadence-java-client/issues/295. + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowLocalsTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowLocalsTest.java new file mode 100644 index 0000000000..57708a81c3 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowLocalsTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.assertEquals; + +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class WorkflowLocalsTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder().setWorkflowTypes(TestWorkflowLocals.class).build(); + + @Test + public void testWorkflowLocals() { + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.assertEquals("result=2, 100", result); + } + + public static class TestWorkflowLocals implements TestWorkflows.TestWorkflow1 { + + private final WorkflowThreadLocal threadLocal = + WorkflowThreadLocal.withInitial(() -> 2); + + private final WorkflowLocal workflowLocal = WorkflowLocal.withInitial(() -> 5); + + @Override + public String execute(String taskQueue) { + assertEquals(2, (int) threadLocal.get()); + assertEquals(5, (int) workflowLocal.get()); + Promise p1 = + Async.procedure( + () -> { + assertEquals(2, (int) threadLocal.get()); + threadLocal.set(10); + Workflow.sleep(Duration.ofSeconds(1)); + assertEquals(10, (int) threadLocal.get()); + assertEquals(100, (int) workflowLocal.get()); + }); + Promise p2 = + Async.procedure( + () -> { + assertEquals(2, (int) threadLocal.get()); + threadLocal.set(22); + workflowLocal.set(100); + assertEquals(22, (int) threadLocal.get()); + }); + p1.get(); + p2.get(); + return "result=" + threadLocal.get() + ", " + workflowLocal.get(); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowRetryDoNotRetryExceptionTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowRetryDoNotRetryExceptionTest.java new file mode 100644 index 0000000000..8699ef5004 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowRetryDoNotRetryExceptionTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.client.WorkflowException; +import io.temporal.common.RetryOptions; +import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestOptions; +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +public class WorkflowRetryDoNotRetryExceptionTest { + + private static final Map retryCount = new ConcurrentHashMap<>(); + + @Rule public TestName testName = new TestName(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestWorkflowRetryDoNotRetryException.class) + .build(); + + @Test + public void testWorkflowRetryDoNotRetryException() { + RetryOptions workflowRetryOptions = + RetryOptions.newBuilder() + .setInitialInterval(Duration.ofSeconds(1)) + .setDoNotRetry("NonRetryable") + .setMaximumAttempts(100) + .setBackoffCoefficient(1.0) + .build(); + WorkflowTest.TestWorkflowRetry workflowStub = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + WorkflowTest.TestWorkflowRetry.class, + TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()) + .toBuilder() + .setRetryOptions(workflowRetryOptions) + .build()); + try { + workflowStub.execute(testName.getMethodName()); + Assert.fail("unreachable"); + } catch (WorkflowException e) { + Assert.assertTrue(e.getCause() instanceof ApplicationFailure); + Assert.assertEquals("NonRetryable", ((ApplicationFailure) e.getCause()).getType()); + Assert.assertEquals( + "message='simulated 3', type='NonRetryable', nonRetryable=false", + e.getCause().getMessage()); + } + } + + public static class TestWorkflowRetryDoNotRetryException + implements WorkflowTest.TestWorkflowRetry { + + @Override + public String execute(String testName) { + AtomicInteger count = retryCount.get(testName); + if (count == null) { + count = new AtomicInteger(); + retryCount.put(testName, count); + } + int c = count.incrementAndGet(); + if (c < 3) { + throw new IllegalArgumentException("simulated " + c); + } else { + throw ApplicationFailure.newFailure("simulated " + c, "NonRetryable"); + } + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowRetryTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowRetryTest.java new file mode 100644 index 0000000000..ff6f9190ab --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowRetryTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.assertEquals; + +import io.temporal.client.WorkflowException; +import io.temporal.common.RetryOptions; +import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestOptions; +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +public class WorkflowRetryTest { + + private static final Map retryCount = new ConcurrentHashMap<>(); + + @Rule public TestName testName = new TestName(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder().setWorkflowTypes(TestWorkflowRetryImpl.class).build(); + + @Test + public void testWorkflowRetry() { + RetryOptions workflowRetryOptions = + RetryOptions.newBuilder() + .setInitialInterval(Duration.ofSeconds(1)) + .setMaximumAttempts(3) + .setBackoffCoefficient(1.0) + .build(); + WorkflowTest.TestWorkflowRetry workflowStub = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + WorkflowTest.TestWorkflowRetry.class, + TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()) + .toBuilder() + .setRetryOptions(workflowRetryOptions) + .build()); + long start = testWorkflowRule.getTestEnvironment().currentTimeMillis(); + try { + workflowStub.execute(testName.getMethodName()); + Assert.fail("unreachable"); + } catch (WorkflowException e) { + Assert.assertEquals( + e.toString(), + "message='simulated 3', type='test', nonRetryable=false", + e.getCause().getMessage()); + } finally { + long elapsed = testWorkflowRule.getTestEnvironment().currentTimeMillis() - start; + Assert.assertTrue( + String.valueOf(elapsed), elapsed >= 2000); // Ensure that retry delays the restart + } + } + + public static class TestWorkflowRetryImpl implements WorkflowTest.TestWorkflowRetry { + + @Override + public String execute(String testName) { + AtomicInteger count = retryCount.get(testName); + if (count == null) { + count = new AtomicInteger(); + retryCount.put(testName, count); + } + int attempt = Workflow.getInfo().getAttempt(); + assertEquals(count.get() + 1, attempt); + throw ApplicationFailure.newFailure("simulated " + count.incrementAndGet(), "test"); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowRetryWithMethodRetryDoNotRetryExceptionTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowRetryWithMethodRetryDoNotRetryExceptionTest.java new file mode 100644 index 0000000000..acd2748e1e --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowRetryWithMethodRetryDoNotRetryExceptionTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.client.WorkflowException; +import io.temporal.common.MethodRetry; +import io.temporal.failure.ApplicationFailure; +import io.temporal.worker.WorkflowImplementationOptions; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +public class WorkflowRetryWithMethodRetryDoNotRetryExceptionTest { + + private static final Map retryCount = new ConcurrentHashMap<>(); + + @Rule public TestName testName = new TestName(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes( + WorkflowImplementationOptions.newBuilder() + .setFailWorkflowExceptionTypes( + IllegalStateException.class, IllegalArgumentException.class) + .build(), + TestWorkflowRetryWithMethodRetryImpl.class) + .build(); + + @Test + public void testWorkflowRetryWithMethodRetryDoNotRetryException() { + TestWorkflowRetryWithMethodRetry workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflowRetryWithMethodRetry.class); + try { + workflowStub.execute(testName.getMethodName()); + Assert.fail("unreachable"); + } catch (WorkflowException e) { + Assert.assertTrue(e.getCause() instanceof ApplicationFailure); + Assert.assertEquals( + IllegalArgumentException.class.getName(), ((ApplicationFailure) e.getCause()).getType()); + Assert.assertEquals( + "message='simulated 3', type='java.lang.IllegalArgumentException', nonRetryable=false", + e.getCause().getMessage()); + } + } + + @WorkflowInterface + public interface TestWorkflowRetryWithMethodRetry { + + @WorkflowMethod + @MethodRetry( + initialIntervalSeconds = 1, + maximumIntervalSeconds = 1, + maximumAttempts = 30, + doNotRetry = "java.lang.IllegalArgumentException") + String execute(String testName); + } + + public static class TestWorkflowRetryWithMethodRetryImpl + implements TestWorkflowRetryWithMethodRetry { + + @Override + public String execute(String testName) { + AtomicInteger count = retryCount.get(testName); + if (count == null) { + count = new AtomicInteger(); + retryCount.put(testName, count); + } + int c = count.incrementAndGet(); + if (c < 3) { + throw new IllegalStateException("simulated " + c); + } else { + throw new IllegalArgumentException("simulated " + c); + } + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowTaskFailureBackoffTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowTaskFailureBackoffTest.java new file mode 100644 index 0000000000..f0263fece2 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowTaskFailureBackoffTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.enums.v1.EventType; +import io.temporal.api.history.v1.History; +import io.temporal.api.history.v1.HistoryEvent; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class WorkflowTaskFailureBackoffTest { + + private static int testWorkflowTaskFailureBackoffReplayCount; + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestWorkflowTaskFailureBackoff.class) + .build(); + + @Test + public void testWorkflowTaskFailureBackoff() { + testWorkflowTaskFailureBackoffReplayCount = 0; + WorkflowOptions options = + WorkflowOptions.newBuilder() + .setWorkflowRunTimeout(Duration.ofSeconds(10)) + .setWorkflowTaskTimeout(Duration.ofSeconds(1)) + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build(); + + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); + long start = testWorkflowRule.getTestEnvironment().currentTimeMillis(); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + long elapsed = testWorkflowRule.getTestEnvironment().currentTimeMillis() - start; + Assert.assertTrue("spinned on fail workflow task", elapsed > 1000); + Assert.assertEquals("result1", result); + WorkflowExecution execution = WorkflowStub.fromTyped(workflowStub).getExecution(); + History history = testWorkflowRule.getWorkflowExecutionHistory(execution); + + int failedTaskCount = 0; + for (HistoryEvent event : history.getEventsList()) { + if (event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_TASK_FAILED) { + failedTaskCount++; + } + } + Assert.assertEquals(1, failedTaskCount); + } + + public static class TestWorkflowTaskFailureBackoff implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + if (testWorkflowTaskFailureBackoffReplayCount++ < 2) { + throw new Error("simulated workflow task failure"); + } + return "result1"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowTaskNPEBackoffTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowTaskNPEBackoffTest.java new file mode 100644 index 0000000000..73da17de72 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowTaskNPEBackoffTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.enums.v1.EventType; +import io.temporal.api.history.v1.History; +import io.temporal.api.history.v1.HistoryEvent; +import io.temporal.client.WorkflowOptions; +import io.temporal.client.WorkflowStub; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class WorkflowTaskNPEBackoffTest { + + private static int testWorkflowTaskFailureBackoffReplayCount; + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder().setWorkflowTypes(TestWorkflowTaskNPEBackoff.class).build(); + + @Test + public void testWorkflowTaskNPEBackoff() { + testWorkflowTaskFailureBackoffReplayCount = 0; + WorkflowOptions options = + WorkflowOptions.newBuilder() + .setWorkflowRunTimeout(Duration.ofSeconds(10)) + .setWorkflowTaskTimeout(Duration.ofSeconds(1)) + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build(); + + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); + long start = testWorkflowRule.getTestEnvironment().currentTimeMillis(); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + long elapsed = testWorkflowRule.getTestEnvironment().currentTimeMillis() - start; + Assert.assertTrue("spinned on fail workflow task", elapsed > 1000); + Assert.assertEquals("result1", result); + WorkflowExecution execution = WorkflowStub.fromTyped(workflowStub).getExecution(); + History history = testWorkflowRule.getWorkflowExecutionHistory(execution); + + int failedTaskCount = 0; + for (HistoryEvent event : history.getEventsList()) { + if (event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_TASK_FAILED) { + failedTaskCount++; + } + } + Assert.assertEquals(1, failedTaskCount); + } + + public static class TestWorkflowTaskNPEBackoff implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + if (testWorkflowTaskFailureBackoffReplayCount++ < 2) { + throw new NullPointerException("simulated workflow task failure"); + } + return "result1"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowTaskTimeoutWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowTaskTimeoutWorkflowTest.java new file mode 100644 index 0000000000..e856527f0a --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowTaskTimeoutWorkflowTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import io.temporal.client.WorkflowOptions; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; + +public class WorkflowTaskTimeoutWorkflowTest { + + private static final Map retryCount = new ConcurrentHashMap<>(); + + @Rule public TestName testName = new TestName(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(WorkflowTaskTimeoutWorkflowImpl.class) + .build(); + + @Test + public void testWorkflowTaskTimeoutWorkflow() throws InterruptedException { + + WorkflowOptions options = + WorkflowOptions.newBuilder() + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .setWorkflowTaskTimeout(Duration.ofSeconds(1)) + .build(); + + WorkflowTaskTimeoutWorkflow stub = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(WorkflowTaskTimeoutWorkflow.class, options); + String result = stub.execute(testName.getMethodName()); + Assert.assertEquals("some result", result); + } + + @WorkflowInterface + public interface WorkflowTaskTimeoutWorkflow { + @WorkflowMethod + String execute(String testName) throws InterruptedException; + } + + public static class WorkflowTaskTimeoutWorkflowImpl implements WorkflowTaskTimeoutWorkflow { + + @Override + public String execute(String testName) throws InterruptedException { + + AtomicInteger count = retryCount.get(testName); + if (count == null) { + count = new AtomicInteger(); + retryCount.put(testName, count); + Thread.sleep(2000); + } + + return "some result"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowTest.java index 2e554104c0..49f5c24d98 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowTest.java @@ -19,3249 +19,196 @@ package io.temporal.workflow; -import static io.temporal.client.WorkflowClient.QUERY_TYPE_STACK_TRACE; -import static org.junit.Assert.*; - -import com.google.common.util.concurrent.UncheckedExecutionException; -import com.google.protobuf.ByteString; -import com.uber.m3.tally.NoopScope; -import io.temporal.activity.*; -import io.temporal.api.common.v1.Memo; -import io.temporal.api.common.v1.Payload; -import io.temporal.api.common.v1.SearchAttributes; -import io.temporal.api.common.v1.WorkflowExecution; -import io.temporal.api.enums.v1.*; -import io.temporal.api.history.v1.HistoryEvent; -import io.temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryRequest; -import io.temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryResponse; -import io.temporal.client.*; -import io.temporal.common.CronSchedule; -import io.temporal.common.MethodRetry; -import io.temporal.common.RetryOptions; -import io.temporal.common.converter.DataConverter; -import io.temporal.common.converter.GsonJsonPayloadConverter; -import io.temporal.common.interceptors.WorkflowClientCallsInterceptor; -import io.temporal.common.interceptors.WorkflowClientCallsInterceptorBase; -import io.temporal.common.interceptors.WorkflowClientInterceptorBase; -import io.temporal.failure.*; -import io.temporal.internal.common.SearchAttributesUtil; -import io.temporal.internal.common.WorkflowExecutionUtils; -import io.temporal.internal.replay.InternalWorkflowTaskException; -import io.temporal.serviceclient.WorkflowServiceStubs; -import io.temporal.serviceclient.WorkflowServiceStubsOptions; -import io.temporal.testing.*; -import io.temporal.worker.*; -import io.temporal.workflow.shared.*; -import io.temporal.workflow.shared.TestActivities; -import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; -import io.temporal.workflow.shared.TestWorkflows; -import java.io.*; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadInfo; -import java.text.SimpleDateFormat; -import java.time.Duration; -import java.time.LocalDateTime; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import org.junit.*; -import org.junit.rules.TestName; -import org.junit.rules.TestWatcher; -import org.junit.runner.Description; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class WorkflowTest { - private static final Logger log = LoggerFactory.getLogger(WorkflowTest.class); - private static final String serviceAddress = System.getenv("TEMPORAL_SERVICE_ADDRESS"); - private static WorkflowServiceStubs service; - private static TestWorkflowEnvironment testEnvironment; - private static final List> delayedCallbacks = new ArrayList<>(); - private final AtomicReference lastStartedWorkflowType = new AtomicReference<>(); - private String taskQueue; - private Worker worker; - private TestActivities.TestActivitiesImpl activitiesImpl; - private WorkflowClient workflowClient; - private TracingWorkerInterceptor tracer; - private WorkerFactory workerFactory; - private static ScheduledExecutorService scheduledExecutor; - - @Rule public TestName testName = new TestName(); - - @Rule - public TestWatcher watchman = - new TestWatcher() { - @Override - protected void failed(Throwable e, Description description) { - if (tracer != null) { - System.err.println("TRACE:\n" + tracer.getTrace()); - } - if (testEnvironment != null) { - System.err.println("HISTORIES:\n" + testEnvironment.getDiagnostics()); - } - } - }; - - @BeforeClass() - public static void startService() { - if (SDKTestWorkflowRule.REGENERATE_JSON_FILES && !SDKTestWorkflowRule.useExternalService) { - throw new IllegalStateException( - "SDKTestWorkflowRule.REGENERATE_JSON_FILES is true when SDKTestWorkflowRule.useExternalService is false"); - } - if (SDKTestWorkflowRule.useExternalService) { - service = - WorkflowServiceStubs.newInstance( - WorkflowServiceStubsOptions.newBuilder().setTarget(serviceAddress).build()); - } - } - - @AfterClass - public static void closeService() { - if (SDKTestWorkflowRule.useExternalService) { - service.shutdownNow(); - service.awaitTermination(10, TimeUnit.SECONDS); - } - } - - @Before - public void setUp() { - String testMethod = testName.getMethodName(); - if (testMethod.startsWith("testExecute") || testMethod.startsWith("testStart")) { - taskQueue = SDKTestWorkflowRule.ANNOTATION_TASK_QUEUE; - } else { - taskQueue = "WorkflowTest-" + testMethod + "-" + UUID.randomUUID().toString(); - } - TracingWorkerInterceptor.FilteredTrace trace = new TracingWorkerInterceptor.FilteredTrace(); - tracer = new TracingWorkerInterceptor(trace); - // TODO: Create a version of TestWorkflowEnvironment that runs against a real service. - lastStartedWorkflowType.set(null); - WorkflowClientOptions workflowClientOptions = - WorkflowClientOptions.newBuilder() - .setBinaryChecksum(SDKTestWorkflowRule.BINARY_CHECKSUM) - .setInterceptors( - new WorkflowClientInterceptorBase() { - @Override - public WorkflowClientCallsInterceptor workflowClientCallsInterceptor( - WorkflowClientCallsInterceptor next) { - return new WorkflowClientCallsInterceptorBase(next) { - @Override - public WorkflowStartOutput start(WorkflowStartInput input) { - lastStartedWorkflowType.set(input.getWorkflowType()); - return super.start(input); - } - - @Override - public WorkflowSignalWithStartOutput signalWithStart( - WorkflowSignalWithStartInput input) { - lastStartedWorkflowType.set( - input.getWorkflowStartInput().getWorkflowType()); - return super.signalWithStart(input); - } - }; - } - }) - .setNamespace(SDKTestWorkflowRule.NAMESPACE) - .build(); - boolean versionTest = testMethod.contains("GetVersion") || testMethod.contains("Deterministic"); - WorkerFactoryOptions factoryOptions = - WorkerFactoryOptions.newBuilder() - .setWorkerInterceptors(tracer) - .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) - .setWorkflowHostLocalTaskQueueScheduleToStartTimeout( - versionTest ? Duration.ZERO : Duration.ofSeconds(10)) - .build(); - if (SDKTestWorkflowRule.useExternalService) { - workflowClient = WorkflowClient.newInstance(service, workflowClientOptions); - workerFactory = WorkerFactory.newInstance(workflowClient, factoryOptions); - WorkerOptions workerOptions = - WorkerOptions.newBuilder().setMaxConcurrentActivityExecutionSize(1000).build(); - - worker = workerFactory.newWorker(taskQueue, workerOptions); - scheduledExecutor = new ScheduledThreadPoolExecutor(1); - } else { - TestEnvironmentOptions testOptions = - TestEnvironmentOptions.newBuilder() - .setWorkflowClientOptions(workflowClientOptions) - .setWorkerFactoryOptions(factoryOptions) - .build(); - testEnvironment = TestWorkflowEnvironment.newInstance(testOptions); - worker = testEnvironment.newWorker(taskQueue); - workflowClient = testEnvironment.getWorkflowClient(); - service = testEnvironment.getWorkflowService(); - } - - ActivityCompletionClient completionClient = workflowClient.newActivityCompletionClient(); - activitiesImpl = new TestActivities.TestActivitiesImpl(completionClient); - worker.registerActivitiesImplementations(activitiesImpl); - - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue); - - TestOptions.newActivityOptionsForTaskQueue(taskQueue); - activitiesImpl.invocations.clear(); - activitiesImpl.procResult.clear(); - } - - @After - public void tearDown() throws Throwable { - if (activitiesImpl != null) { - activitiesImpl.close(); - } - if (testEnvironment != null) { - testEnvironment.close(); - } else { - workerFactory.shutdown(); - } - for (ScheduledFuture result : delayedCallbacks) { - if (result.isDone() && !result.isCancelled()) { - try { - result.get(); - } catch (InterruptedException e) { - } catch (ExecutionException e) { - throw e.getCause(); - } - } - } - if (tracer != null) { - tracer.assertExpected(); - } - } - - private void startWorkerFor( - WorkflowImplementationOptions implementationOptions, Class... workflowTypes) { - worker.registerWorkflowImplementationTypes(implementationOptions, workflowTypes); - if (SDKTestWorkflowRule.useExternalService) { - workerFactory.start(); - } else { - testEnvironment.start(); - } - } - - private void startWorkerFor(Class... workflowTypes) { - worker.registerWorkflowImplementationTypes(workflowTypes); - if (SDKTestWorkflowRule.useExternalService) { - workerFactory.start(); - } else { - testEnvironment.start(); - } - } - - static void sleep(Duration d) { - if (SDKTestWorkflowRule.useExternalService) { - try { - Thread.sleep(d.toMillis()); - } catch (InterruptedException e) { - throw new RuntimeException("Interrupted", e); - } - } else { - testEnvironment.sleep(d); - } - } - - long currentTimeMillis() { - if (SDKTestWorkflowRule.useExternalService) { - return System.currentTimeMillis(); - } else { - return testEnvironment.currentTimeMillis(); - } - } - - @WorkflowInterface - public interface TestWorkflowSignaled { - - @WorkflowMethod - String execute(); - - @SignalMethod(name = "testSignal") - void signal1(String arg); - } - - public static class TestSyncWorkflowImpl implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - TestActivities activities = - Workflow.newActivityStub( - TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); - // Invoke synchronously in a separate thread for testing purposes only. - // In real workflows use - // Async.procedure(activities::activityWithDelay, 1000, true) - Promise a1 = Async.function(() -> activities.activityWithDelay(1000, true)); - Workflow.sleep(2000); - return activities.activity2(a1.get(), 10); - } - } - - @Test - public void testSync() { - startWorkerFor(TestSyncWorkflowImpl.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - String result = workflowStub.execute(taskQueue); - assertEquals("activity10", result); - tracer.setExpected( - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "newThread null", - "sleep PT2S", - "executeActivity ActivityWithDelay", - "activity ActivityWithDelay", - "executeActivity Activity2", - "activity Activity2"); - } - - @WorkflowInterface - public interface TestMultipleTimers { - @WorkflowMethod - long execute(); - } - - public static class TestMultipleTimersImpl implements TestMultipleTimers { - - @Override - public long execute() { - Promise t1 = Async.procedure(() -> Workflow.sleep(Duration.ofSeconds(1))); - Promise t2 = Async.procedure(() -> Workflow.sleep(Duration.ofSeconds(2))); - long start = Workflow.currentTimeMillis(); - Promise.anyOf(t1, t2).get(); - long elapsed = Workflow.currentTimeMillis() - start; - return elapsed; - } - } - - @Test - public void testMultipleTimers() { - startWorkerFor(TestMultipleTimersImpl.class); - TestMultipleTimers workflowStub = - workflowClient.newWorkflowStub( - TestMultipleTimers.class, TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - long result = workflowStub.execute(); - assertTrue("should be around 1 second: " + result, result < 2000); - } - - interface EmptyInterface {} - - interface UnrelatedInterface { - void unrelatedMethod(); - } - - public static class TestHeartbeatTimeoutDetails implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - ActivityOptions options = - ActivityOptions.newBuilder() - .setTaskQueue(taskQueue) - .setHeartbeatTimeout(Duration.ofSeconds(1)) // short heartbeat timeout; - .setScheduleToCloseTimeout(Duration.ofSeconds(5)) - .build(); - - TestActivities activities = Workflow.newActivityStub(TestActivities.class, options); - try { - // false for second argument means to heartbeat once to set details and then stop. - activities.activityWithDelay(5000, false); - } catch (ActivityFailure e) { - TimeoutFailure te = (TimeoutFailure) e.getCause(); - log.info("TestHeartbeatTimeoutDetails expected timeout", e); - assertEquals(TimeoutType.TIMEOUT_TYPE_SCHEDULE_TO_CLOSE, te.getTimeoutType()); - assertTrue(te.getCause() instanceof TimeoutFailure); - assertEquals( - TimeoutType.TIMEOUT_TYPE_HEARTBEAT, ((TimeoutFailure) te.getCause()).getTimeoutType()); - return (te.getLastHeartbeatDetails().get(String.class)); - } - throw new RuntimeException("unreachable"); - } - } - - @Test - public void testHeartbeatTimeoutDetails() { - startWorkerFor(TestHeartbeatTimeoutDetails.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - String result = workflowStub.execute(taskQueue); - assertEquals("heartbeatValue", result); - } - - @Test - public void testSyncUntypedAndStackTrace() { - startWorkerFor(TestSyncWorkflowImpl.class); - WorkflowStub workflowStub = - workflowClient.newUntypedWorkflowStub( - "TestWorkflow1", TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - WorkflowExecution execution = workflowStub.start(taskQueue); - sleep(Duration.ofMillis(500)); - String stackTrace = workflowStub.query(QUERY_TYPE_STACK_TRACE, String.class); - assertTrue(stackTrace, stackTrace.contains("WorkflowTest$TestSyncWorkflowImpl.execute")); - assertTrue(stackTrace, stackTrace.contains("activityWithDelay")); - // Test stub created from workflow execution. - workflowStub = workflowClient.newUntypedWorkflowStub(execution, workflowStub.getWorkflowType()); - stackTrace = workflowStub.query(QUERY_TYPE_STACK_TRACE, String.class); - assertTrue(stackTrace, stackTrace.contains("WorkflowTest$TestSyncWorkflowImpl.execute")); - assertTrue(stackTrace, stackTrace.contains("activityWithDelay")); - String result = workflowStub.getResult(String.class); - assertEquals("activity10", result); - } - - public static class TestCancellationForWorkflowsWithFailedPromises - implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - Async.function( - () -> { - throw new UncheckedExecutionException(new Exception("Oh noo!")); - }); - Async.function( - () -> { - throw new UncheckedExecutionException(new Exception("Oh noo again!")); - }); - Workflow.await(() -> false); - fail("unreachable"); - return "done"; - } - } - - @Test - public void workflowsWithFailedPromisesCanBeCanceled() { - startWorkerFor(TestCancellationForWorkflowsWithFailedPromises.class); - WorkflowStub client = - workflowClient.newUntypedWorkflowStub( - "TestWorkflow1", TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - client.start(taskQueue); - client.cancel(); - - try { - client.getResult(String.class); - fail("unreachable"); - } catch (WorkflowFailedException e) { - assertTrue(e.getCause() instanceof CanceledFailure); - } - } - - @Test - public void testWorkflowCancellation() { - startWorkerFor(TestSyncWorkflowImpl.class); - WorkflowStub client = - workflowClient.newUntypedWorkflowStub( - "TestWorkflow1", TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - client.start(taskQueue); - client.cancel(); - try { - client.getResult(String.class); - fail("unreachable"); - } catch (WorkflowFailedException e) { - assertTrue(e.getCause() instanceof CanceledFailure); - } - } - - @Test - public void testWorkflowTermination() throws InterruptedException { - startWorkerFor(TestSyncWorkflowImpl.class); - WorkflowStub client = - workflowClient.newUntypedWorkflowStub( - "TestWorkflow1", TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - client.start(taskQueue); - Thread.sleep(1000); - client.terminate("boo", "detail1", "detail2"); - try { - client.getResult(String.class); - fail("unreachable"); - } catch (WorkflowFailedException ignored) { - assertTrue(ignored.getCause() instanceof TerminatedFailure); - assertEquals("boo", ((TerminatedFailure) ignored.getCause()).getOriginalMessage()); - } - } - - public static class TestCancellationScopePromise implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - Promise cancellationRequest = CancellationScope.current().getCancellationRequest(); - cancellationRequest.get(); - return "done"; - } - } - - @Test - public void testWorkflowCancellationScopePromise() { - startWorkerFor(TestCancellationScopePromise.class); - WorkflowStub client = - workflowClient.newUntypedWorkflowStub( - "TestWorkflow1", TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - client.start(taskQueue); - client.cancel(); - try { - client.getResult(String.class); - fail("unreachable"); - } catch (WorkflowFailedException e) { - assertTrue(e.getCause() instanceof CanceledFailure); - } - } - - public static class TestDetachedCancellationScope implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - TestActivities testActivities = - Workflow.newActivityStub( - TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); - try { - testActivities.activityWithDelay(100000, true); - fail("unreachable"); - } catch (ActivityFailure e) { - assertTrue(e.getCause() instanceof CanceledFailure); - Workflow.newDetachedCancellationScope(() -> assertEquals(1, testActivities.activity1(1))) - .run(); - } - try { - Workflow.sleep(Duration.ofHours(1)); - fail("unreachable"); - } catch (CanceledFailure e) { - Workflow.newDetachedCancellationScope( - () -> assertEquals("a12", testActivities.activity2("a1", 2))) - .run(); - } - try { - Workflow.newTimer(Duration.ofHours(1)).get(); - fail("unreachable"); - } catch (CanceledFailure e) { - Workflow.newDetachedCancellationScope( - () -> assertEquals("a123", testActivities.activity3("a1", 2, 3))) - .run(); - } - return "result"; - } - } - - @Test - public void testDetachedScope() { - startWorkerFor(TestDetachedCancellationScope.class); - WorkflowStub client = - workflowClient.newUntypedWorkflowStub( - "TestWorkflow1", TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - client.start(taskQueue); - sleep(Duration.ofMillis(500)); // To let activityWithDelay start. - client.cancel(); - try { - client.getResult(String.class); - fail("unreachable"); - } catch (WorkflowFailedException e) { - assertTrue(e.getCause() instanceof CanceledFailure); - } - activitiesImpl.assertInvocations("activityWithDelay", "activity1", "activity2", "activity3"); - } - - @WorkflowInterface - public interface TestWorkflow { - @WorkflowMethod - void execute(ChildWorkflowCancellationType cancellationType); - } - - @WorkflowInterface - public interface TestChildWorkflow { - @WorkflowMethod - void execute(); - } - - public static class SimpleTestWorkflow implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - TestActivities testActivities = - Workflow.newActivityStub( - TestActivities.class, - ActivityOptions.newBuilder(TestOptions.newActivityOptionsForTaskQueue(taskQueue)) - .build()); - testActivities.activity(); - return "done"; - } - } - - @Test - public void testBinaryChecksumSetWhenTaskCompleted() { - startWorkerFor(SimpleTestWorkflow.class); - TestWorkflows.TestWorkflow1 client = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - WorkflowExecution execution = WorkflowClient.start(client::execute, taskQueue); - WorkflowStub stub = WorkflowStub.fromTyped(client); - SDKTestWorkflowRule.waitForOKQuery(stub); - GetWorkflowExecutionHistoryRequest request = - GetWorkflowExecutionHistoryRequest.newBuilder() - .setNamespace(SDKTestWorkflowRule.NAMESPACE) - .setExecution(execution) - .build(); - GetWorkflowExecutionHistoryResponse response = - service.blockingStub().getWorkflowExecutionHistory(request); - - boolean foundCompletedTask = false; - for (HistoryEvent event : response.getHistory().getEventsList()) { - if (event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_TASK_COMPLETED) { - assertEquals( - SDKTestWorkflowRule.BINARY_CHECKSUM, - event.getWorkflowTaskCompletedEventAttributes().getBinaryChecksum()); - foundCompletedTask = true; - } - } - assertTrue(foundCompletedTask); - } - - @WorkflowInterface - public interface TestContinueAsNew { - - @WorkflowMethod - int execute(int count, String continueAsNewTaskQueue); - } - - public static class TestContinueAsNewImpl implements TestContinueAsNew { - - @Override - public int execute(int count, String continueAsNewTaskQueue) { - String taskQueue = Workflow.getInfo().getTaskQueue(); - if (count == 0) { - assertEquals(continueAsNewTaskQueue, taskQueue); - return 111; - } - Map memo = new HashMap<>(); - memo.put("myKey", "MyValue"); - Map searchAttributes = new HashMap<>(); - searchAttributes.put("CustomKeywordField", "foo1"); - ContinueAsNewOptions options = - ContinueAsNewOptions.newBuilder() - .setTaskQueue(continueAsNewTaskQueue) - .setMemo(memo) - .setSearchAttributes(searchAttributes) - .build(); - TestContinueAsNew next = Workflow.newContinueAsNewStub(TestContinueAsNew.class, options); - next.execute(count - 1, continueAsNewTaskQueue); - throw new RuntimeException("unreachable"); - } - } - - @Test - public void testContinueAsNew() { - Worker w2; - String continuedTaskQueue = this.taskQueue + "_continued"; - if (SDKTestWorkflowRule.useExternalService) { - w2 = workerFactory.newWorker(continuedTaskQueue); - } else { - w2 = testEnvironment.newWorker(continuedTaskQueue); - } - w2.registerWorkflowImplementationTypes(TestContinueAsNewImpl.class); - startWorkerFor(TestContinueAsNewImpl.class); - - TestContinueAsNew client = - workflowClient.newWorkflowStub( - TestContinueAsNew.class, TestOptions.newWorkflowOptionsWithTimeouts(this.taskQueue)); - int result = client.execute(4, continuedTaskQueue); - assertEquals(111, result); - tracer.setExpected( - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "continueAsNew", - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "continueAsNew", - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "continueAsNew", - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "continueAsNew", - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method"); - } - - @WorkflowInterface - public interface NoArgsWorkflow { - @WorkflowMethod - String execute(); - } - - public static class TestContinueAsNewNoArgsImpl implements NoArgsWorkflow { - - @Override - public String execute() { - NoArgsWorkflow next = Workflow.newContinueAsNewStub(NoArgsWorkflow.class); - WorkflowInfo info = Workflow.getInfo(); - if (!info.getContinuedExecutionRunId().isPresent()) { - next.execute(); - throw new RuntimeException("unreachable"); - } else { - return "done"; - } - } - } - - @Test - public void testContinueAsNewNoArgs() { - startWorkerFor(TestContinueAsNewNoArgsImpl.class); - - NoArgsWorkflow client = - workflowClient.newWorkflowStub( - NoArgsWorkflow.class, TestOptions.newWorkflowOptionsWithTimeouts(this.taskQueue)); - String result = client.execute(); - assertEquals("done", result); - tracer.setExpected( - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "continueAsNew", - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method"); - } - - private void assertResult(String expected, WorkflowExecution execution) { - String result = - workflowClient.newUntypedWorkflowStub(execution, Optional.empty()).getResult(String.class); - assertEquals(expected, result); - } - - private void assertResult(int expected, WorkflowExecution execution) { - int result = - workflowClient.newUntypedWorkflowStub(execution, Optional.empty()).getResult(int.class); - assertEquals(expected, result); - } - - private void waitForProc(WorkflowExecution execution) { - workflowClient.newUntypedWorkflowStub(execution, Optional.empty()).getResult(Void.class); - } - - @Test - public void testStart() { - startWorkerFor(TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class); - WorkflowOptions workflowOptions = - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue) - .toBuilder() - .setWorkflowIdReusePolicy( - WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE) - .build(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc stubF = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc.class, workflowOptions); - assertResult("func", WorkflowClient.start(stubF::func)); - assertEquals("func", stubF.func()); // Check that duplicated start just returns the result. - WorkflowOptions options = WorkflowOptions.newBuilder().setTaskQueue(taskQueue).build(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1 stubF1 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1.class, options); - - if (!SDKTestWorkflowRule.useExternalService) { - // Use worker that polls on a task queue configured through @WorkflowMethod annotation of - // func1 - assertResult(1, WorkflowClient.start(stubF1::func1, 1)); - assertEquals(1, stubF1.func1(1)); // Check that duplicated start just returns the result. - } - // Check that duplicated start is not allowed for AllowDuplicate IdReusePolicy - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc2 stubF2 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc2.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue) - .toBuilder() - .setWorkflowIdReusePolicy( - WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE) - .build()); - assertResult("12", WorkflowClient.start(stubF2::func2, "1", 2)); - try { - stubF2.func2("1", 2); - fail("unreachable"); - } catch (IllegalStateException e) { - // expected - } - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc3 stubF3 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc3.class, workflowOptions); - assertResult("123", WorkflowClient.start(stubF3::func3, "1", 2, 3)); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc4 stubF4 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc4.class, workflowOptions); - assertResult("1234", WorkflowClient.start(stubF4::func4, "1", 2, 3, 4)); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc5 stubF5 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc5.class, workflowOptions); - assertResult("12345", WorkflowClient.start(stubF5::func5, "1", 2, 3, 4, 5)); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc6 stubF6 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc6.class, workflowOptions); - assertResult("123456", WorkflowClient.start(stubF6::func6, "1", 2, 3, 4, 5, 6)); - - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc stubP = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc.class, workflowOptions); - waitForProc(WorkflowClient.start(stubP::proc)); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc1 stubP1 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc1.class, workflowOptions); - waitForProc(WorkflowClient.start(stubP1::proc1, "1")); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc2 stubP2 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc2.class, workflowOptions); - waitForProc(WorkflowClient.start(stubP2::proc2, "1", 2)); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc3 stubP3 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc3.class, workflowOptions); - waitForProc(WorkflowClient.start(stubP3::proc3, "1", 2, 3)); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc4 stubP4 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc4.class, workflowOptions); - waitForProc(WorkflowClient.start(stubP4::proc4, "1", 2, 3, 4)); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc5 stubP5 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc5.class, workflowOptions); - waitForProc(WorkflowClient.start(stubP5::proc5, "1", 2, 3, 4, 5)); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc6 stubP6 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc6.class, workflowOptions); - waitForProc(WorkflowClient.start(stubP6::proc6, "1", 2, 3, 4, 5, 6)); - - assertEquals("proc", stubP.query()); - assertEquals("1", stubP1.query()); - assertEquals("12", stubP2.query()); - assertEquals("123", stubP3.query()); - assertEquals("1234", stubP4.query()); - assertEquals("12345", stubP5.query()); - assertEquals("123456", stubP6.query()); - } - - @Test - public void testMemo() { - if (testEnvironment != null) { - String testMemoKey = "testKey"; - String testMemoValue = "testValue"; - Map memo = new HashMap<>(); - memo.put(testMemoKey, testMemoValue); - - startWorkerFor(TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class); - WorkflowOptions workflowOptions = - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue).toBuilder().setMemo(memo).build(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc stubF = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc.class, workflowOptions); - WorkflowExecution executionF = WorkflowClient.start(stubF::func); - - GetWorkflowExecutionHistoryResponse historyResp = - WorkflowExecutionUtils.getHistoryPage( - testEnvironment.getWorkflowService(), - SDKTestWorkflowRule.NAMESPACE, - executionF, - ByteString.EMPTY, - new NoopScope()); - HistoryEvent startEvent = historyResp.getHistory().getEvents(0); - Memo memoFromEvent = startEvent.getWorkflowExecutionStartedEventAttributes().getMemo(); - Payload memoBytes = memoFromEvent.getFieldsMap().get(testMemoKey); - String memoRetrieved = - GsonJsonPayloadConverter.getInstance().fromData(memoBytes, String.class, String.class); - assertEquals(testMemoValue, memoRetrieved); - } - } - - @Test - public void testSearchAttributes() { - if (testEnvironment != null) { - String testKeyString = "CustomKeywordField"; - String testValueString = "testKeyword"; - String testKeyInteger = "CustomIntField"; - Integer testValueInteger = 1; - String testKeyDateTime = "CustomDateTimeField"; - LocalDateTime testValueDateTime = LocalDateTime.now(); - String testKeyBool = "CustomBoolField"; - Boolean testValueBool = true; - String testKeyDouble = "CustomDoubleField"; - Double testValueDouble = 1.23; - - // add more type to test - Map searchAttr = new HashMap<>(); - searchAttr.put(testKeyString, testValueString); - searchAttr.put(testKeyInteger, testValueInteger); - searchAttr.put(testKeyDateTime, testValueDateTime); - searchAttr.put(testKeyBool, testValueBool); - searchAttr.put(testKeyDouble, testValueDouble); - - startWorkerFor(TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class); - WorkflowOptions workflowOptions = - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue) - .toBuilder() - .setSearchAttributes(searchAttr) - .build(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc stubF = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc.class, workflowOptions); - WorkflowExecution executionF = WorkflowClient.start(stubF::func); - - GetWorkflowExecutionHistoryResponse historyResp = - WorkflowExecutionUtils.getHistoryPage( - testEnvironment.getWorkflowService(), - SDKTestWorkflowRule.NAMESPACE, - executionF, - ByteString.EMPTY, - new NoopScope()); - HistoryEvent startEvent = historyResp.getHistory().getEvents(0); - SearchAttributes searchAttrFromEvent = - startEvent.getWorkflowExecutionStartedEventAttributes().getSearchAttributes(); - - Map fieldsMap = searchAttrFromEvent.getIndexedFieldsMap(); - Payload searchAttrStringBytes = fieldsMap.get(testKeyString); - DataConverter converter = DataConverter.getDefaultInstance(); - String retrievedString = - converter.fromPayload(searchAttrStringBytes, String.class, String.class); - assertEquals(testValueString, retrievedString); - Payload searchAttrIntegerBytes = fieldsMap.get(testKeyInteger); - Integer retrievedInteger = - converter.fromPayload(searchAttrIntegerBytes, Integer.class, Integer.class); - assertEquals(testValueInteger, retrievedInteger); - Payload searchAttrDateTimeBytes = fieldsMap.get(testKeyDateTime); - LocalDateTime retrievedDateTime = - converter.fromPayload(searchAttrDateTimeBytes, LocalDateTime.class, LocalDateTime.class); - assertEquals(testValueDateTime, retrievedDateTime); - Payload searchAttrBoolBytes = fieldsMap.get(testKeyBool); - Boolean retrievedBool = - converter.fromPayload(searchAttrBoolBytes, Boolean.class, Boolean.class); - assertEquals(testValueBool, retrievedBool); - Payload searchAttrDoubleBytes = fieldsMap.get(testKeyDouble); - Double retrievedDouble = - converter.fromPayload(searchAttrDoubleBytes, Double.class, Double.class); - assertEquals(testValueDouble, retrievedDouble); - } - } - - @Test - public void testExecute() throws ExecutionException, InterruptedException { - startWorkerFor(TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class); - WorkflowOptions workflowOptions = TestOptions.newWorkflowOptionsWithTimeouts(taskQueue); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc stubF = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc.class, workflowOptions); - assertEquals("func", WorkflowClient.execute(stubF::func).get()); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1 stubF1 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1.class, workflowOptions); - assertEquals(1, (int) WorkflowClient.execute(stubF1::func1, 1).get()); - assertEquals(1, stubF1.func1(1)); // Check that duplicated start just returns the result. - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc2 stubF2 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc2.class, workflowOptions); - assertEquals("12", WorkflowClient.execute(stubF2::func2, "1", 2).get()); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc3 stubF3 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc3.class, workflowOptions); - assertEquals("123", WorkflowClient.execute(stubF3::func3, "1", 2, 3).get()); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc4 stubF4 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc4.class, workflowOptions); - assertEquals("1234", WorkflowClient.execute(stubF4::func4, "1", 2, 3, 4).get()); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc5 stubF5 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc5.class, workflowOptions); - assertEquals("12345", WorkflowClient.execute(stubF5::func5, "1", 2, 3, 4, 5).get()); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc6 stubF6 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc6.class, workflowOptions); - assertEquals("123456", WorkflowClient.execute(stubF6::func6, "1", 2, 3, 4, 5, 6).get()); - - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc stubP = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc.class, workflowOptions); - WorkflowClient.execute(stubP::proc).get(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc1 stubP1 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc1.class, workflowOptions); - WorkflowClient.execute(stubP1::proc1, "1").get(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc2 stubP2 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc2.class, workflowOptions); - WorkflowClient.execute(stubP2::proc2, "1", 2).get(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc3 stubP3 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc3.class, workflowOptions); - WorkflowClient.execute(stubP3::proc3, "1", 2, 3).get(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc4 stubP4 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc4.class, workflowOptions); - WorkflowClient.execute(stubP4::proc4, "1", 2, 3, 4).get(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc5 stubP5 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc5.class, workflowOptions); - WorkflowClient.execute(stubP5::proc5, "1", 2, 3, 4, 5).get(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc6 stubP6 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsProc6.class, workflowOptions); - WorkflowClient.execute(stubP6::proc6, "1", 2, 3, 4, 5, 6).get(); - - assertEquals("proc", stubP.query()); - assertEquals("1", stubP1.query()); - assertEquals("12", stubP2.query()); - assertEquals("123", stubP3.query()); - assertEquals("1234", stubP4.query()); - assertEquals("12345", stubP5.query()); - assertEquals("123456", stubP6.query()); - } - - @Test - public void testWorkflowIdResuePolicy() { - startWorkerFor(TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class); - - // When WorkflowIdReusePolicy is not AllowDuplicate the semantics is to get result for the - // previous run. - String workflowId = UUID.randomUUID().toString(); - WorkflowOptions workflowOptions = - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue) - .toBuilder() - .setWorkflowIdReusePolicy( - WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE_FAILED_ONLY) - .setWorkflowId(workflowId) - .build(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1 stubF1_1 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1.class, workflowOptions); - assertEquals(1, stubF1_1.func1(1)); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1 stubF1_2 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1.class, workflowOptions); - assertEquals(1, stubF1_2.func1(2)); - - // Setting WorkflowIdReusePolicy to AllowDuplicate will trigger new run. - workflowOptions = - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue) - .toBuilder() - .setWorkflowIdReusePolicy( - WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_ALLOW_DUPLICATE) - .setWorkflowId(workflowId) - .build(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1 stubF1_3 = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1.class, workflowOptions); - assertEquals(2, stubF1_3.func1(2)); - - // Setting WorkflowIdReusePolicy to RejectDuplicate or AllowDuplicateFailedOnly does not work as - // expected. See https://github.com/uber/cadence-java-client/issues/295. - } - - public static class TestUntypedChildStubWorkflow implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - ChildWorkflowOptions workflowOptions = - ChildWorkflowOptions.newBuilder().setTaskQueue(taskQueue).build(); - ChildWorkflowStub stubF = - Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsFunc", workflowOptions); - assertEquals("func", stubF.execute(String.class)); - // Workflow type overridden through the @WorkflowMethod.name - ChildWorkflowStub stubF1 = Workflow.newUntypedChildWorkflowStub("func1", workflowOptions); - assertEquals("1", stubF1.execute(String.class, "1")); - ChildWorkflowStub stubF2 = - Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsFunc2", workflowOptions); - assertEquals("12", stubF2.execute(String.class, "1", 2)); - ChildWorkflowStub stubF3 = - Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsFunc3", workflowOptions); - assertEquals("123", stubF3.execute(String.class, "1", 2, 3)); - ChildWorkflowStub stubF4 = - Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsFunc4", workflowOptions); - assertEquals("1234", stubF4.execute(String.class, "1", 2, 3, 4)); - ChildWorkflowStub stubF5 = - Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsFunc5", workflowOptions); - assertEquals("12345", stubF5.execute(String.class, "1", 2, 3, 4, 5)); - ChildWorkflowStub stubF6 = - Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsFunc6", workflowOptions); - assertEquals("123456", stubF6.execute(String.class, "1", 2, 3, 4, 5, 6)); - - ChildWorkflowStub stubP = - Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc", workflowOptions); - stubP.execute(Void.class); - ChildWorkflowStub stubP1 = - Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc1", workflowOptions); - stubP1.execute(Void.class, "1"); - ChildWorkflowStub stubP2 = - Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc2", workflowOptions); - stubP2.execute(Void.class, "1", 2); - ChildWorkflowStub stubP3 = - Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc3", workflowOptions); - stubP3.execute(Void.class, "1", 2, 3); - ChildWorkflowStub stubP4 = - Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc4", workflowOptions); - stubP4.execute(Void.class, "1", 2, 3, 4); - ChildWorkflowStub stubP5 = - Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc5", workflowOptions); - stubP5.execute(Void.class, "1", 2, 3, 4, 5); - ChildWorkflowStub stubP6 = - Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc6", workflowOptions); - stubP6.execute(Void.class, "1", 2, 3, 4, 5, 6); - return null; - } - } - - public static class TestTimerWorkflowImpl implements TestWorkflows.TestWorkflow2 { - - @Override - public String execute(boolean useExternalService) { - Promise timer1; - Promise timer2; - Duration timeout1 = useExternalService ? Duration.ofMillis(700) : Duration.ofSeconds(700); - Duration timeout2 = useExternalService ? Duration.ofMillis(1300) : Duration.ofSeconds(1300); - timer1 = Workflow.newTimer(timeout1); - timer2 = Workflow.newTimer(timeout2); - long time = Workflow.currentTimeMillis(); - timer1 - .thenApply( - r -> { - // Testing that timer can be created from a callback thread. - if (useExternalService) { - Workflow.newTimer(Duration.ofSeconds(10)); - } else { - Workflow.newTimer(Duration.ofHours(10)); - } - Workflow.currentTimeMillis(); // Testing that time is available here. - return r; - }) - .get(); - timer1.get(); - long slept = Workflow.currentTimeMillis() - time; - // Also checks that rounding up to a second works. - assertTrue(slept + "<" + timeout1.toMillis(), slept >= timeout1.toMillis()); - timer2.get(); - slept = Workflow.currentTimeMillis() - time; - assertTrue(String.valueOf(slept), slept >= timeout2.toMillis()); - return "testTimer"; - } - - @Override - public List getTrace() { - throw new UnsupportedOperationException("not implemented"); - } - } - - @Test - public void testTimer() { - startWorkerFor(TestTimerWorkflowImpl.class); - WorkflowOptions options; - if (SDKTestWorkflowRule.useExternalService) { - options = TestOptions.newWorkflowOptionsWithTimeouts(taskQueue); - } else { - options = - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue) - .toBuilder() - .setWorkflowRunTimeout(Duration.ofDays(1)) - .build(); - } - TestWorkflows.TestWorkflow2 client = - workflowClient.newWorkflowStub(TestWorkflows.TestWorkflow2.class, options); - String result = client.execute(SDKTestWorkflowRule.useExternalService); - assertEquals("testTimer", result); - if (SDKTestWorkflowRule.useExternalService) { - tracer.setExpected( - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "registerQuery getTrace", - "newThread workflow-method", - "newTimer PT0.7S", - "newTimer PT1.3S", - "currentTimeMillis", - "newTimer PT10S", - "currentTimeMillis", - "currentTimeMillis", - "currentTimeMillis"); - } else { - tracer.setExpected( - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "registerQuery getTrace", - "newThread workflow-method", - "newTimer PT11M40S", - "newTimer PT21M40S", - "currentTimeMillis", - "newTimer PT10H", - "currentTimeMillis", - "currentTimeMillis", - "currentTimeMillis"); - } - } - - @WorkflowInterface - public interface TestExceptionPropagation { - @WorkflowMethod - void execute(String taskQueue); - } - - public static class ThrowingChild implements TestWorkflows.TestWorkflow1 { - - @Override - @SuppressWarnings("AssertionFailureIgnored") - public String execute(String taskQueue) { - TestActivities testActivities = - Workflow.newActivityStub( - TestActivities.class, - TestOptions.newActivityOptions20sScheduleToClose() - .toBuilder() - .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(1).build()) - .build()); - try { - testActivities.throwIO(); - fail("unreachable"); - return "ignored"; - } catch (ActivityFailure e) { - try { - assertTrue(e.getMessage().contains("ThrowIO")); - assertTrue(e.getCause() instanceof ApplicationFailure); - assertEquals(IOException.class.getName(), ((ApplicationFailure) e.getCause()).getType()); - assertEquals( - "message='simulated IO problem', type='java.io.IOException', nonRetryable=false", - e.getCause().getMessage()); - } catch (AssertionError ae) { - // Errors cause workflow task to fail. But we want workflow to fail in this case. - throw new RuntimeException(ae); - } - Exception ee = new NumberFormatException(); - ee.initCause(new Throwable("simulated throwable", e)); - throw Workflow.wrap(ee); - } - } - } - - public static class TestExceptionPropagationImpl implements TestExceptionPropagation { - - @Override - @SuppressWarnings("AssertionFailureIgnored") - public void execute(String taskQueue) { - ChildWorkflowOptions options = - ChildWorkflowOptions.newBuilder().setWorkflowRunTimeout(Duration.ofHours(1)).build(); - TestWorkflows.TestWorkflow1 child = - Workflow.newChildWorkflowStub(TestWorkflows.TestWorkflow1.class, options); - try { - child.execute(taskQueue); - fail("unreachable"); - } catch (RuntimeException e) { - Throwable c1 = e.getCause(); - Throwable c2 = c1.getCause(); - Throwable c3 = c2.getCause(); - Throwable c4 = c3.getCause(); - try { - assertNoEmptyStacks(e); - assertTrue(e.getMessage().contains("TestWorkflow1")); - assertTrue(e instanceof ChildWorkflowFailure); - assertTrue(c1 instanceof ApplicationFailure); - assertEquals(NumberFormatException.class.getName(), ((ApplicationFailure) c1).getType()); - assertEquals(Throwable.class.getName(), ((ApplicationFailure) c2).getType()); - assertTrue(c3 instanceof ActivityFailure); - assertTrue(c4 instanceof ApplicationFailure); - assertEquals(IOException.class.getName(), ((ApplicationFailure) c4).getType()); - assertEquals( - "message='simulated IO problem', type='java.io.IOException', nonRetryable=false", - c4.getMessage()); - } catch (AssertionError ae) { - // Errors cause workflow task to fail. But we want workflow to fail in this case. - throw new RuntimeException(ae); - } - Exception fnf = new FileNotFoundException("simulated exception"); - fnf.initCause(e); - throw Workflow.wrap(fnf); - } - } - } - - private static void assertNoEmptyStacks(RuntimeException e) { - // Check that there are no empty stacks - Throwable c = e; - while (c != null) { - assertTrue(c.getStackTrace().length > 0); - c = c.getCause(); - } - } - - /** - * Test that an NPE thrown in an activity executed from a child workflow results in the following - * chain of exceptions when an exception is received in an external client that executed workflow - * through a WorkflowClient: - * - *

-   * {@link WorkflowFailedException}
-   *     ->{@link ChildWorkflowFailure}
-   *         ->{@link ActivityFailure}
-   *             ->OriginalActivityException
-   * 
- * - *

This test also tests that Checked exception wrapping and unwrapping works producing a nice - * exception chain without the wrappers. - */ - @Test - public void testExceptionPropagation() { - startWorkerFor( - WorkflowImplementationOptions.newBuilder() - .setFailWorkflowExceptionTypes(NumberFormatException.class, FileNotFoundException.class) - .build(), - ThrowingChild.class, - TestExceptionPropagationImpl.class); - TestExceptionPropagation client = - workflowClient.newWorkflowStub( - TestExceptionPropagation.class, TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - try { - client.execute(taskQueue); - fail("Unreachable"); - } catch (WorkflowFailedException e) { - // Rethrow the assertion failure - Throwable c1 = e.getCause(); - Throwable c2 = c1.getCause(); - Throwable c3 = c2.getCause(); - Throwable c4 = c3.getCause(); - Throwable c5 = c4.getCause(); - Throwable c6 = c5.getCause(); - if (c2 instanceof AssertionError) { - throw (AssertionError) c2; - } - assertNoEmptyStacks(e); - // Uncomment to see the actual trace. - // e.printStackTrace(); - assertTrue(e.getMessage(), e.getMessage().contains("TestExceptionPropagation")); - assertTrue(e.getStackTrace().length > 0); - assertTrue(c1 instanceof ApplicationFailure); - assertEquals(FileNotFoundException.class.getName(), ((ApplicationFailure) c1).getType()); - assertTrue(c2 instanceof ChildWorkflowFailure); - assertTrue(c3 instanceof ApplicationFailure); - assertEquals(NumberFormatException.class.getName(), ((ApplicationFailure) c3).getType()); - assertEquals(Throwable.class.getName(), ((ApplicationFailure) c4).getType()); - assertTrue(c5 instanceof ActivityFailure); - assertTrue(c6 instanceof ApplicationFailure); - assertEquals(IOException.class.getName(), ((ApplicationFailure) c6).getType()); - assertEquals( - "message='simulated IO problem', type='java.io.IOException', nonRetryable=false", - c6.getMessage()); - } - } - - @WorkflowInterface - public interface QueryableWorkflow { - - @WorkflowMethod - String execute(); - - @QueryMethod - String getState(); - - @SignalMethod(name = "testSignal") - void mySignal(String value); - } - - public static class TestNoQueryWorkflowImpl implements QueryableWorkflow { - - CompletablePromise promise = Workflow.newPromise(); - - @Override - public String execute() { - promise.get(); - return "done"; - } - - @Override - public String getState() { - return "some state"; - } - - @Override - public void mySignal(String value) { - promise.complete(null); - } - } - - @Test - public void testNoQueryThreadLeak() throws InterruptedException { - startWorkerFor(TestNoQueryWorkflowImpl.class); - int threadCount = ManagementFactory.getThreadMXBean().getThreadCount(); - QueryableWorkflow client = - workflowClient.newWorkflowStub( - QueryableWorkflow.class, TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - WorkflowClient.start(client::execute); - sleep(Duration.ofSeconds(1)); - // Calls query multiple times to check at the end of the method that if it doesn't leak threads - int queryCount = 100; - for (int i = 0; i < queryCount; i++) { - assertEquals("some state", client.getState()); - if (SDKTestWorkflowRule.useExternalService) { - // Sleep a little bit to avoid server throttling error. - Thread.sleep(50); - } - } - client.mySignal("Hello "); - WorkflowStub.fromTyped(client).getResult(String.class); - // Ensures that no threads were leaked due to query - int threadsCreated = ManagementFactory.getThreadMXBean().getThreadCount() - threadCount; - assertTrue("query leaks threads: " + threadsCreated, threadsCreated < queryCount); - } - - public static class TestTimerCallbackBlockedWorkflowImpl implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - Promise timer1 = Workflow.newTimer(Duration.ZERO); - Promise timer2 = Workflow.newTimer(Duration.ofSeconds(1)); - - return timer1 - .thenApply( - e -> { - timer2.get(); - return "timer2Fired"; - }) - .get(); - } - } - - /** Test that it is not allowed to block in the timer callback thread. */ - @Test - public void testTimerCallbackBlocked() { - startWorkerFor(TestTimerCallbackBlockedWorkflowImpl.class); - WorkflowOptions options = - WorkflowOptions.newBuilder() - .setWorkflowRunTimeout(Duration.ofSeconds(10)) - .setWorkflowTaskTimeout(Duration.ofSeconds(1)) - .setTaskQueue(taskQueue) - .build(); - TestWorkflows.TestWorkflow1 client = - workflowClient.newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); - String result = client.execute(taskQueue); - assertEquals("timer2Fired", result); - } - - @WorkflowInterface - public interface ITestChild { - - @WorkflowMethod - String execute(String arg, int delay); - } - - @WorkflowInterface - public interface ITestNamedChild { - - @WorkflowMethod(name = "namedChild") - String execute(String arg); - } - - public static class TestChild implements ITestChild { - - @Override - public String execute(String arg, int delay) { - Workflow.sleep(delay); - return arg.toUpperCase(); - } - } - - public static class TestParentWorkflowContinueAsNew implements TestWorkflows.TestWorkflow1 { - - private final ITestChild child1 = - Workflow.newChildWorkflowStub( - ITestChild.class, - ChildWorkflowOptions.newBuilder() - .setWorkflowIdReusePolicy( - WorkflowIdReusePolicy.WORKFLOW_ID_REUSE_POLICY_REJECT_DUPLICATE) - .build()); - private final TestWorkflows.TestWorkflow1 self = - Workflow.newContinueAsNewStub(TestWorkflows.TestWorkflow1.class); - - @Override - public String execute(String arg) { - child1.execute("Hello", 0); - if (arg.length() > 0) { - self.execute(""); // continue as new - } - return "foo"; - } - } - - /** Reproduction of a bug when a child of continued as new workflow has the same UUID ID. */ - @Test - public void testParentContinueAsNew() { - startWorkerFor(TestParentWorkflowContinueAsNew.class, TestChild.class); - - WorkflowOptions options = - WorkflowOptions.newBuilder() - .setWorkflowRunTimeout(Duration.ofSeconds(200)) - .setWorkflowTaskTimeout(Duration.ofSeconds(60)) - .setTaskQueue(taskQueue) - .build(); - TestWorkflows.TestWorkflow1 client = - workflowClient.newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); - assertEquals("foo", client.execute("not empty")); - } - - public static class AngryChild implements ITestChild { - - @Override - public String execute(String taskQueue, int delay) { - TestActivities.AngryChildActivity activity = - Workflow.newActivityStub( - TestActivities.AngryChildActivity.class, - ActivityOptions.newBuilder() - .setTaskQueue(taskQueue) - .setScheduleToCloseTimeout(Duration.ofSeconds(5)) - .build()); - activity.execute(); - throw ApplicationFailure.newFailure("simulated failure", "test"); - } - } - - @WorkflowInterface - public interface SignalingChild { - - @WorkflowMethod - String execute(String arg, String parentWorkflowId); - } - - private static int testWorkflowTaskFailureBackoffReplayCount; - - public static class TestWorkflowTaskFailureBackoff implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - if (testWorkflowTaskFailureBackoffReplayCount++ < 2) { - throw new Error("simulated workflow task failure"); - } - return "result1"; - } - } - - @Test - public void testWorkflowTaskFailureBackoff() { - testWorkflowTaskFailureBackoffReplayCount = 0; - startWorkerFor(TestWorkflowTaskFailureBackoff.class); - WorkflowOptions o = - WorkflowOptions.newBuilder() - .setWorkflowRunTimeout(Duration.ofSeconds(10)) - .setWorkflowTaskTimeout(Duration.ofSeconds(1)) - .setTaskQueue(taskQueue) - .build(); - - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub(TestWorkflows.TestWorkflow1.class, o); - long start = currentTimeMillis(); - String result = workflowStub.execute(taskQueue); - long elapsed = currentTimeMillis() - start; - assertTrue("spinned on fail workflow task", elapsed > 1000); - assertEquals("result1", result); - GetWorkflowExecutionHistoryRequest request = - GetWorkflowExecutionHistoryRequest.newBuilder() - .setNamespace(SDKTestWorkflowRule.NAMESPACE) - .setExecution(WorkflowStub.fromTyped(workflowStub).getExecution()) - .build(); - GetWorkflowExecutionHistoryResponse response = - service.blockingStub().getWorkflowExecutionHistory(request); - - int failedTaskCount = 0; - for (HistoryEvent event : response.getHistory().getEventsList()) { - if (event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_TASK_FAILED) { - failedTaskCount++; - } - } - assertEquals(1, failedTaskCount); - } - - public static class TestWorkflowTaskNPEBackoff implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - if (testWorkflowTaskFailureBackoffReplayCount++ < 2) { - throw new NullPointerException("simulated workflow task failure"); - } - return "result1"; - } - } - - @Test - public void testWorkflowTaskNPEBackoff() { - testWorkflowTaskFailureBackoffReplayCount = 0; - startWorkerFor(TestWorkflowTaskNPEBackoff.class); - WorkflowOptions o = - WorkflowOptions.newBuilder() - .setWorkflowRunTimeout(Duration.ofSeconds(10)) - .setWorkflowTaskTimeout(Duration.ofSeconds(1)) - .setTaskQueue(taskQueue) - .build(); - - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub(TestWorkflows.TestWorkflow1.class, o); - long start = currentTimeMillis(); - String result = workflowStub.execute(taskQueue); - long elapsed = currentTimeMillis() - start; - assertTrue("spinned on fail workflow task", elapsed > 1000); - assertEquals("result1", result); - GetWorkflowExecutionHistoryRequest request = - GetWorkflowExecutionHistoryRequest.newBuilder() - .setNamespace(SDKTestWorkflowRule.NAMESPACE) - .setExecution(WorkflowStub.fromTyped(workflowStub).getExecution()) - .build(); - GetWorkflowExecutionHistoryResponse response = - service.blockingStub().getWorkflowExecutionHistory(request); - - int failedTaskCount = 0; - for (HistoryEvent event : response.getHistory().getEventsList()) { - if (event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_TASK_FAILED) { - failedTaskCount++; - } - } - assertEquals(1, failedTaskCount); - } - - private static final Map retryCount = new ConcurrentHashMap<>(); - - @WorkflowInterface - public interface TestWorkflowRetry { - - @WorkflowMethod - String execute(String testName); - } - - public static class TestWorkflowRetryImpl implements TestWorkflowRetry { - - @Override - public String execute(String testName) { - AtomicInteger count = retryCount.get(testName); - if (count == null) { - count = new AtomicInteger(); - retryCount.put(testName, count); - } - int attempt = Workflow.getInfo().getAttempt(); - assertEquals(count.get() + 1, attempt); - throw ApplicationFailure.newFailure("simulated " + count.incrementAndGet(), "test"); - } - } - - @Test - public void testWorkflowRetry() { - startWorkerFor(TestWorkflowRetryImpl.class); - RetryOptions workflowRetryOptions = - RetryOptions.newBuilder() - .setInitialInterval(Duration.ofSeconds(1)) - .setMaximumAttempts(3) - .setBackoffCoefficient(1.0) - .build(); - TestWorkflowRetry workflowStub = - workflowClient.newWorkflowStub( - TestWorkflowRetry.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue) - .toBuilder() - .setRetryOptions(workflowRetryOptions) - .build()); - long start = currentTimeMillis(); - try { - workflowStub.execute(testName.getMethodName()); - fail("unreachable"); - } catch (WorkflowException e) { - assertEquals( - e.toString(), - "message='simulated 3', type='test', nonRetryable=false", - e.getCause().getMessage()); - } finally { - long elapsed = currentTimeMillis() - start; - assertTrue(String.valueOf(elapsed), elapsed >= 2000); // Ensure that retry delays the restart - } - } - - public static class TestWorkflowRetryDoNotRetryException implements TestWorkflowRetry { - - @Override - public String execute(String testName) { - AtomicInteger count = retryCount.get(testName); - if (count == null) { - count = new AtomicInteger(); - retryCount.put(testName, count); - } - int c = count.incrementAndGet(); - if (c < 3) { - throw new IllegalArgumentException("simulated " + c); - } else { - throw ApplicationFailure.newFailure("simulated " + c, "NonRetryable"); - } - } - } - - @Test - public void testWorkflowRetryDoNotRetryException() { - startWorkerFor(TestWorkflowRetryDoNotRetryException.class); - RetryOptions workflowRetryOptions = - RetryOptions.newBuilder() - .setInitialInterval(Duration.ofSeconds(1)) - .setDoNotRetry("NonRetryable") - .setMaximumAttempts(100) - .setBackoffCoefficient(1.0) - .build(); - TestWorkflowRetry workflowStub = - workflowClient.newWorkflowStub( - TestWorkflowRetry.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue) - .toBuilder() - .setRetryOptions(workflowRetryOptions) - .build()); - try { - workflowStub.execute(testName.getMethodName()); - fail("unreachable"); - } catch (WorkflowException e) { - assertTrue(e.getCause() instanceof ApplicationFailure); - assertEquals("NonRetryable", ((ApplicationFailure) e.getCause()).getType()); - assertEquals( - "message='simulated 3', type='NonRetryable', nonRetryable=false", - e.getCause().getMessage()); - } - } - - public static class TestWorkflowNonRetryableFlag implements TestWorkflowRetry { - - @Override - public String execute(String testName) { - AtomicInteger count = retryCount.get(testName); - if (count == null) { - count = new AtomicInteger(); - retryCount.put(testName, count); - } - int c = count.incrementAndGet(); - ApplicationFailure f = - ApplicationFailure.newFailure("simulated " + c, "foo", "details1", 123); - if (c == 3) { - f.setNonRetryable(true); - } - throw f; - } - } - - @Test - public void testWorkflowFailureNonRetryableFlag() { - startWorkerFor(TestWorkflowNonRetryableFlag.class); - RetryOptions workflowRetryOptions = - RetryOptions.newBuilder() - .setInitialInterval(Duration.ofSeconds(1)) - .setMaximumAttempts(100) - .setBackoffCoefficient(1.0) - .build(); - TestWorkflowRetry workflowStub = - workflowClient.newWorkflowStub( - TestWorkflowRetry.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue) - .toBuilder() - .setRetryOptions(workflowRetryOptions) - .build()); - try { - workflowStub.execute(testName.getMethodName()); - fail("unreachable"); - } catch (WorkflowException e) { - assertTrue(e.getCause() instanceof ApplicationFailure); - assertEquals("foo", ((ApplicationFailure) e.getCause()).getType()); - assertEquals( - "details1", ((ApplicationFailure) e.getCause()).getDetails().get(0, String.class)); - assertEquals( - Integer.valueOf(123), - ((ApplicationFailure) e.getCause()).getDetails().get(1, Integer.class)); - assertEquals( - "message='simulated 3', type='foo', nonRetryable=true", e.getCause().getMessage()); - } - } - - @WorkflowInterface - public interface TestWorkflowRetryWithMethodRetry { - - @WorkflowMethod - @MethodRetry( - initialIntervalSeconds = 1, - maximumIntervalSeconds = 1, - maximumAttempts = 30, - doNotRetry = "java.lang.IllegalArgumentException") - String execute(String testName); - } - - public static class TestWorkflowRetryWithMethodRetryImpl - implements TestWorkflowRetryWithMethodRetry { - - @Override - public String execute(String testName) { - AtomicInteger count = retryCount.get(testName); - if (count == null) { - count = new AtomicInteger(); - retryCount.put(testName, count); - } - int c = count.incrementAndGet(); - if (c < 3) { - throw new IllegalStateException("simulated " + c); - } else { - throw new IllegalArgumentException("simulated " + c); - } - } - } - - @Test - public void testWorkflowRetryWithMethodRetryDoNotRetryException() { - startWorkerFor( - WorkflowImplementationOptions.newBuilder() - .setFailWorkflowExceptionTypes( - IllegalStateException.class, IllegalArgumentException.class) - .build(), - TestWorkflowRetryWithMethodRetryImpl.class); - TestWorkflowRetryWithMethodRetry workflowStub = - workflowClient.newWorkflowStub( - TestWorkflowRetryWithMethodRetry.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - try { - workflowStub.execute(testName.getMethodName()); - fail("unreachable"); - } catch (WorkflowException e) { - assertTrue(e.getCause() instanceof ApplicationFailure); - assertEquals( - IllegalArgumentException.class.getName(), ((ApplicationFailure) e.getCause()).getType()); - assertEquals( - "message='simulated 3', type='java.lang.IllegalArgumentException', nonRetryable=false", - e.getCause().getMessage()); - } - } - - @WorkflowInterface - public interface TestWorkflowWithCronSchedule { - @WorkflowMethod - @CronSchedule("0 * * * *") - String execute(String testName); - } - - static String lastCompletionResult; - static Optional lastFail; - - public static class TestWorkflowWithCronScheduleImpl implements TestWorkflowWithCronSchedule { - - @Override - public String execute(String testName) { - Logger log = Workflow.getLogger(TestWorkflowWithCronScheduleImpl.class); - - if (CancellationScope.current().isCancelRequested()) { - log.debug("TestWorkflowWithCronScheduleImpl run canceled."); - return null; - } - - lastCompletionResult = Workflow.getLastCompletionResult(String.class); - lastFail = Workflow.getPreviousRunFailure(); - - AtomicInteger count = retryCount.get(testName); - if (count == null) { - count = new AtomicInteger(); - retryCount.put(testName, count); - } - int c = count.incrementAndGet(); - - if (c == 3) { - throw ApplicationFailure.newFailure("simulated error", "test"); - } - - SimpleDateFormat sdf = new SimpleDateFormat("MMM dd,yyyy HH:mm:ss.SSS"); - Date now = new Date(Workflow.currentTimeMillis()); - log.debug("TestWorkflowWithCronScheduleImpl run at " + sdf.format(now)); - return "run " + c; - } - } - - public static class TestCronParentWorkflow implements TestWorkflows.TestWorkflow1 { - - private final TestWorkflowWithCronSchedule cronChild = - Workflow.newChildWorkflowStub(TestWorkflowWithCronSchedule.class); - - @Override - public String execute(String taskQueue) { - return cronChild.execute(taskQueue); - } - } - - public interface ProcInvocationQueryable { - - @QueryMethod(name = "getTrace") - String query(); - } - - @WorkflowInterface - public interface TestGetAttemptWorkflowsFunc { - - @WorkflowMethod - int func(); - } - - public static class TestWorkflowLocals implements TestWorkflows.TestWorkflow1 { - - private final WorkflowThreadLocal threadLocal = - WorkflowThreadLocal.withInitial(() -> 2); - - private final WorkflowLocal workflowLocal = WorkflowLocal.withInitial(() -> 5); - - @Override - public String execute(String taskQueue) { - assertEquals(2, (int) threadLocal.get()); - assertEquals(5, (int) workflowLocal.get()); - Promise p1 = - Async.procedure( - () -> { - assertEquals(2, (int) threadLocal.get()); - threadLocal.set(10); - Workflow.sleep(Duration.ofSeconds(1)); - assertEquals(10, (int) threadLocal.get()); - assertEquals(100, (int) workflowLocal.get()); - }); - Promise p2 = - Async.procedure( - () -> { - assertEquals(2, (int) threadLocal.get()); - threadLocal.set(22); - workflowLocal.set(100); - assertEquals(22, (int) threadLocal.get()); - }); - p1.get(); - p2.get(); - return "result=" + threadLocal.get() + ", " + workflowLocal.get(); - } - } - - @Test - public void testWorkflowLocals() { - startWorkerFor(TestWorkflowLocals.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - String result = workflowStub.execute(taskQueue); - assertEquals("result=2, 100", result); - } - - public static class TestSideEffectWorkflowImpl implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - TestActivities testActivities = - Workflow.newActivityStub( - TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); - - long workflowTime = Workflow.currentTimeMillis(); - long time1 = Workflow.sideEffect(long.class, () -> workflowTime); - long time2 = Workflow.sideEffect(long.class, () -> workflowTime); - assertEquals(time1, time2); - Workflow.sleep(Duration.ofSeconds(1)); - String result; - if (workflowTime == time1) { - result = "activity" + testActivities.activity1(1); - } else { - result = testActivities.activity2("activity2", 2); - } - return result; - } - } - - @Test - public void testSideEffect() { - startWorkerFor(TestSideEffectWorkflowImpl.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - String result = workflowStub.execute(taskQueue); - assertEquals("activity1", result); - tracer.setExpected( - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "currentTimeMillis", - "sideEffect", - "sideEffect", - "sleep PT1S", - "executeActivity customActivity1", - "activity customActivity1"); - } - - private static final Map> mutableSideEffectValue = - Collections.synchronizedMap(new HashMap<>()); - - public static class TestMutableSideEffectWorkflowImpl implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - StringBuilder result = new StringBuilder(); - for (int j = 0; j < 1; j++) { - for (int i = 0; i < 8; i++) { - long value = - Workflow.mutableSideEffect( - "id1", - Long.class, - (o, n) -> n > o, - () -> mutableSideEffectValue.get(taskQueue).poll()); - if (result.length() > 0) { - result.append(", "); - } - result.append(value); - // Sleep is here to ensure that mutableSideEffect works when replaying a history. - if (i >= 8) { - Workflow.sleep(Duration.ofSeconds(1)); - } - } - } - return result.toString(); - } - } - - @Test - public void testMutableSideEffect() { - startWorkerFor(TestMutableSideEffectWorkflowImpl.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - ArrayDeque values = new ArrayDeque<>(); - values.add(1234L); - values.add(1234L); - values.add(123L); // expected to be ignored as it is smaller than 1234. - values.add(3456L); - values.add(1234L); // expected to be ignored as it is smaller than 3456L. - values.add(4234L); - values.add(4234L); - values.add(3456L); // expected to be ignored as it is smaller than 4234L. - mutableSideEffectValue.put(taskQueue, values); - String result = workflowStub.execute(taskQueue); - assertEquals("1234, 1234, 1234, 3456, 3456, 4234, 4234, 4234", result); - } - - public static class TestGetVersionWorkflowImpl implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - TestActivities testActivities = - Workflow.newActivityStub( - TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); - - // Test adding a version check in non-replay code. - int version = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 1); - assertEquals(version, 1); - String result = testActivities.activity2("activity2", 2); - - // Test version change in non-replay code. - version = Workflow.getVersion("test_change", 1, 2); - assertEquals(version, 1); - result += "activity" + testActivities.activity1(1); - - boolean replaying = false; - // Test adding a version check in replay code. - if (!Workflow.isReplaying()) { - result += "activity" + testActivities.activity1(1); // This is executed in non-replay mode. - } else { - replaying = true; - int version2 = Workflow.getVersion("test_change_2", Workflow.DEFAULT_VERSION, 1); - assertEquals(version2, Workflow.DEFAULT_VERSION); - result += "activity" + testActivities.activity1(1); - } - - // Test get version in replay mode. - Workflow.sleep(1000); - version = Workflow.getVersion("test_change", 1, 2); - assertEquals(version, 1); - result += "activity" + testActivities.activity1(1); - assertTrue(replaying); - return result; - } - } - - @Test - public void testGetVersion() { - startWorkerFor(TestGetVersionWorkflowImpl.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - String result = workflowStub.execute(taskQueue); - assertEquals("activity22activity1activity1activity1", result); - tracer.setExpected( - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "getVersion", - "executeActivity Activity2", - "activity Activity2", - "getVersion", - "executeActivity customActivity1", - "activity customActivity1", - "executeActivity customActivity1", - "activity customActivity1", - "sleep PT1S", - "getVersion", - "executeActivity customActivity1", - "activity customActivity1"); - } - - public static class TestGetVersionSameIdOnReplay implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - // Test adding a version check in replay code. - if (!Workflow.isReplaying()) { - Workflow.sleep(Duration.ofMinutes(1)); - } else { - int version2 = Workflow.getVersion("test_change_2", Workflow.DEFAULT_VERSION, 11); - Workflow.sleep(Duration.ofMinutes(1)); - int version3 = Workflow.getVersion("test_change_2", Workflow.DEFAULT_VERSION, 11); - - assertEquals(Workflow.DEFAULT_VERSION, version3); - assertEquals(version2, version3); - } - - return "test"; - } - } - - @Test - public void testGetVersionSameIdOnReplay() { - Assume.assumeFalse("skipping for docker tests", SDKTestWorkflowRule.useExternalService); - - startWorkerFor(TestGetVersionSameIdOnReplay.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - workflowStub.execute(taskQueue); - WorkflowExecution execution = WorkflowStub.fromTyped(workflowStub).getExecution(); - GetWorkflowExecutionHistoryRequest request = - GetWorkflowExecutionHistoryRequest.newBuilder() - .setNamespace(SDKTestWorkflowRule.NAMESPACE) - .setExecution(execution) - .build(); - - // Validate that no marker is recorded - GetWorkflowExecutionHistoryResponse response = - service.blockingStub().getWorkflowExecutionHistory(request); - for (HistoryEvent event : response.getHistory().getEventsList()) { - assertFalse(EventType.EVENT_TYPE_MARKER_RECORDED == event.getEventType()); - } - } - - public static class TestGetVersionSameId implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - // Test adding a version check in replay code. - if (!Workflow.isReplaying()) { - int version2 = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 11); - Workflow.sleep(Duration.ofMinutes(1)); - } else { - int version2 = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 11); - Workflow.sleep(Duration.ofMinutes(1)); - int version3 = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 11); - - assertEquals(11, version3); - assertEquals(version2, version3); - } - - return "test"; - } - } - - @Test - public void testGetVersionSameId() { - Assume.assumeFalse("skipping for docker tests", SDKTestWorkflowRule.useExternalService); - - startWorkerFor(TestGetVersionSameId.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - workflowStub.execute(taskQueue); - } - - public static class TestGetVersionWorkflowAddNewBefore implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - log.info("TestGetVersionWorkflow3Impl this=" + this.hashCode()); - // Test adding a version check in replay code. - if (!Workflow.isReplaying()) { - // The first version of the code - int changeFoo = Workflow.getVersion("changeFoo", Workflow.DEFAULT_VERSION, 1); - if (changeFoo != 1) { - throw new IllegalStateException("Unexpected version: " + 1); - } - } else { - // The updated code - int changeBar = Workflow.getVersion("changeBar", Workflow.DEFAULT_VERSION, 1); - if (changeBar != Workflow.DEFAULT_VERSION) { - throw new IllegalStateException("Unexpected version: " + changeBar); - } - int changeFoo = Workflow.getVersion("changeFoo", Workflow.DEFAULT_VERSION, 1); - if (changeFoo != 1) { - throw new IllegalStateException("Unexpected version: " + changeFoo); - } - } - Workflow.sleep(1000); // forces new workflow task - return "test"; - } - } - - @Test - public void testGetVersionAddNewBefore() { - Assume.assumeFalse("skipping for docker tests", SDKTestWorkflowRule.useExternalService); - - startWorkerFor(TestGetVersionWorkflowAddNewBefore.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - workflowStub.execute(taskQueue); - } - - public static class TestGetVersionWorkflowReplaceGetVersionId - implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - log.info("TestGetVersionWorkflow3Impl this=" + this.hashCode()); - // Test adding a version check in replay code. - if (!Workflow.isReplaying()) { - // The first version of the code - int changeFoo1 = Workflow.getVersion("changeFoo0", Workflow.DEFAULT_VERSION, 2); - if (changeFoo1 != 2) { - throw new IllegalStateException("Unexpected version: " + changeFoo1); - } - int changeFoo2 = Workflow.getVersion("changeFoo1", Workflow.DEFAULT_VERSION, 111); - if (changeFoo2 != 111) { - throw new IllegalStateException("Unexpected version: " + changeFoo2); - } - } else { - // The updated code - int changeBar = Workflow.getVersion("changeBar", Workflow.DEFAULT_VERSION, 1); - if (changeBar != Workflow.DEFAULT_VERSION) { - throw new IllegalStateException("Unexpected version: " + changeBar); - } - int changeFoo = Workflow.getVersion("changeFoo1", Workflow.DEFAULT_VERSION, 123); - if (changeFoo != 111) { - throw new IllegalStateException("Unexpected version: " + changeFoo); - } - } - Workflow.sleep(1000); // forces new workflow task - return "test"; - } - } - - @Test - public void testGetVersionWorkflowReplaceGetVersionId() { - Assume.assumeFalse("skipping for docker tests", SDKTestWorkflowRule.useExternalService); - - startWorkerFor(TestGetVersionWorkflowReplaceGetVersionId.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - workflowStub.execute(taskQueue); - } - - public static class TestGetVersionWorkflowReplaceCompletely - implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - log.info("TestGetVersionWorkflow3Impl this=" + this.hashCode()); - // Test adding a version check in replay code. - if (!Workflow.isReplaying()) { - // The first version of the code - Workflow.getVersion("changeFoo0", Workflow.DEFAULT_VERSION, 2); - Workflow.getVersion("changeFoo1", Workflow.DEFAULT_VERSION, 111); - Workflow.getVersion("changeFoo2", Workflow.DEFAULT_VERSION, 101); - } else { - // The updated code - int changeBar = Workflow.getVersion("changeBar", Workflow.DEFAULT_VERSION, 1); - if (changeBar != Workflow.DEFAULT_VERSION) { - throw new IllegalStateException("Unexpected version: " + changeBar); - } - int changeFoo = Workflow.getVersion("changeFoo10", Workflow.DEFAULT_VERSION, 123); - if (changeFoo != Workflow.DEFAULT_VERSION) { - throw new IllegalStateException("Unexpected version: " + changeFoo); - } - } - Workflow.sleep(1000); // forces new workflow task - return "test"; - } - } - - @Test - public void testGetVersionWorkflowReplaceCompletely() { - Assume.assumeFalse("skipping for docker tests", SDKTestWorkflowRule.useExternalService); - - startWorkerFor(TestGetVersionWorkflowReplaceCompletely.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - workflowStub.execute(taskQueue); - } - - public static class TestGetVersionWorkflowRemove implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - TestActivities activities = - Workflow.newActivityStub( - TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); - String result; - // Test adding a version check in replay code. - if (!Workflow.isReplaying()) { - // The first version of the code - int changeFoo = Workflow.getVersion("changeFoo", Workflow.DEFAULT_VERSION, 1); - if (changeFoo != 1) { - throw new IllegalStateException("Unexpected version: " + 1); - } - result = activities.activity2("foo", 10); - } else { - // No getVersionCall - result = activities.activity2("foo", 10); - } - Workflow.sleep(1000); // forces new workflow task - return result; - } - } - - @Test - public void testGetVersionWorkflowRemove() { - Assume.assumeFalse("skipping for docker tests", SDKTestWorkflowRule.useExternalService); - - startWorkerFor(TestGetVersionWorkflowRemove.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - assertEquals("foo10", workflowStub.execute(taskQueue)); - } - - static CompletableFuture executionStarted = new CompletableFuture<>(); - - public static class TestGetVersionWithoutCommandEventWorkflowImpl - implements TestWorkflowSignaled { - - CompletablePromise signalReceived = Workflow.newPromise(); - - @Override - public String execute() { - try { - if (!Workflow.isReplaying()) { - executionStarted.complete(true); - signalReceived.get(); - } else { - // Execute getVersion in replay mode. In this case we have no command event, only a - // signal. - int version = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 1); - if (version == Workflow.DEFAULT_VERSION) { - signalReceived.get(); - return "result 1"; - } else { - return "result 2"; - } - } - Workflow.sleep(1000); - } catch (Exception e) { - throw new RuntimeException("failed to get from signal"); - } - - throw new RuntimeException("unreachable"); - } - - @Override - public void signal1(String arg) { - signalReceived.complete(true); - } - } - - @Test - public void testGetVersionWithoutCommandEvent() throws Exception { - executionStarted = new CompletableFuture<>(); - startWorkerFor(TestGetVersionWithoutCommandEventWorkflowImpl.class); - TestWorkflowSignaled workflowStub = - workflowClient.newWorkflowStub( - TestWorkflowSignaled.class, TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - WorkflowClient.start(workflowStub::execute); - executionStarted.get(); - workflowStub.signal1("test signal"); - String result = WorkflowStub.fromTyped(workflowStub).getResult(String.class); - assertEquals("result 1", result); - } - - // The following test covers the scenario where getVersion call is removed before a - // non-version-marker command. - public static class TestGetVersionRemovedInReplay implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - TestActivities testActivities = - Workflow.newActivityStub( - TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); - String result; - // Test removing a version check in replay code. - if (!Workflow.isReplaying()) { - int version = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 13); - assertEquals(13, version); - result = testActivities.activity2("activity2", 2); - } else { - result = testActivities.activity2("activity2", 2); - } - result += testActivities.activity(); - return result; - } - } - - @Test - public void testGetVersionRemovedInReplay() { - startWorkerFor(TestGetVersionRemovedInReplay.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - String result = workflowStub.execute(taskQueue); - assertEquals("activity22activity", result); - tracer.setExpected( - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "getVersion", - "executeActivity Activity2", - "activity Activity2", - "executeActivity Activity", - "activity Activity"); - } - - // The following test covers the scenario where getVersion call is removed before another - // version-marker command. - public static class TestGetVersionRemovedBefore implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - TestActivities testActivities = - Workflow.newActivityStub( - TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); - // Test removing a version check in replay code. - if (!Workflow.isReplaying()) { - Workflow.getVersion("test_change1", Workflow.DEFAULT_VERSION, 11); - Workflow.getVersion("test_change2", Workflow.DEFAULT_VERSION, 12); - Workflow.getVersion("test_change3", Workflow.DEFAULT_VERSION, 13); - Workflow.getVersion("test_change4", Workflow.DEFAULT_VERSION, 14); - } else { - int version = Workflow.getVersion("test_change3", Workflow.DEFAULT_VERSION, 22); - assertEquals(13, version); - } - return testActivities.activity(); - } - } - - @Test - public void testGetVersionRemovedBefore() { - startWorkerFor(TestGetVersionRemovedBefore.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - String result = workflowStub.execute(taskQueue); - assertEquals("activity", result); - tracer.setExpected( - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "getVersion", - "getVersion", - "getVersion", - "getVersion", - "executeActivity Activity", - "activity Activity"); - } - - public static class TestVersionNotSupportedWorkflowImpl implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - TestActivities testActivities = - Workflow.newActivityStub( - TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); - - // Test adding a version check in non-replay code. - int version = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 1); - String result = ""; - if (version == Workflow.DEFAULT_VERSION) { - result += "activity" + testActivities.activity1(1); - } else { - result += testActivities.activity2("activity2", 2); // This is executed. - } - - // Catching error from getVersion is only for unit test purpose. - // Do not ever do it in production code. - try { - Workflow.getVersion("test_change", 2, 3); - } catch (Error e) { - throw Workflow.wrap(ApplicationFailure.newFailure("unsupported change version", "test")); - } - return result; - } - } - - @Test - public void testVersionNotSupported() { - startWorkerFor(TestVersionNotSupportedWorkflowImpl.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - - try { - workflowStub.execute(taskQueue); - fail("unreachable"); - } catch (WorkflowException e) { - assertEquals( - "message='unsupported change version', type='test', nonRetryable=false", - e.getCause().getMessage()); - } - } - - @WorkflowInterface - public interface DeterminismFailingWorkflow { - @WorkflowMethod - void execute(String taskQueue); - } - - public static class DeterminismFailingWorkflowImpl implements DeterminismFailingWorkflow { - - @Override - public void execute(String taskQueue) { - TestActivities activities = - Workflow.newActivityStub( - TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); - if (!Workflow.isReplaying()) { - activities.activity1(1); - } - } - } - - @Test - public void testNonDeterministicWorkflowPolicyBlockWorkflow() { - startWorkerFor(DeterminismFailingWorkflowImpl.class); - WorkflowOptions options = - WorkflowOptions.newBuilder() - .setWorkflowRunTimeout(Duration.ofSeconds(5)) - .setWorkflowTaskTimeout(Duration.ofSeconds(1)) - .setTaskQueue(taskQueue) - .build(); - DeterminismFailingWorkflow workflowStub = - workflowClient.newWorkflowStub(DeterminismFailingWorkflow.class, options); - try { - workflowStub.execute(taskQueue); - fail("unreachable"); - } catch (WorkflowFailedException e) { - // expected to timeout as workflow is going get blocked. - assertTrue(e.getCause() instanceof TimeoutFailure); - } - - int workflowRootThreads = 0; - ThreadInfo[] threads = ManagementFactory.getThreadMXBean().dumpAllThreads(false, false); - for (ThreadInfo thread : threads) { - if (thread.getThreadName().contains("workflow-root")) { - workflowRootThreads++; - } - } - - assertTrue("workflow threads might leak", workflowRootThreads < 10); - } - - @Test - public void testNonDeterministicWorkflowPolicyFailWorkflow() { - WorkflowImplementationOptions implementationOptions = - WorkflowImplementationOptions.newBuilder() - .setFailWorkflowExceptionTypes(Throwable.class) - .build(); - worker.registerWorkflowImplementationTypes( - implementationOptions, DeterminismFailingWorkflowImpl.class); - if (SDKTestWorkflowRule.useExternalService) { - workerFactory.start(); - } else { - testEnvironment.start(); - } - WorkflowOptions options = - WorkflowOptions.newBuilder() - .setWorkflowRunTimeout(Duration.ofSeconds(1)) - .setWorkflowTaskTimeout(Duration.ofSeconds(1)) - .setTaskQueue(taskQueue) - .build(); - DeterminismFailingWorkflow workflowStub = - workflowClient.newWorkflowStub(DeterminismFailingWorkflow.class, options); - try { - workflowStub.execute(taskQueue); - fail("unreachable"); - } catch (WorkflowFailedException e) { - // expected to fail on non deterministic error - assertTrue(e.getCause() instanceof ApplicationFailure); - assertEquals( - InternalWorkflowTaskException.class.getName(), - ((ApplicationFailure) e.getCause()).getType()); - } - } - - public static class TestUUIDAndRandom implements TestWorkflows.TestWorkflow1 { - - @Override - public String execute(String taskQueue) { - TestActivities activities = - Workflow.newActivityStub( - TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); - Random rand1 = Workflow.newRandom(); - int r11 = rand1.nextInt(); - int r12 = r11 + rand1.nextInt(); - int savedInt = Workflow.sideEffect(int.class, () -> r12); - String id = Workflow.randomUUID().toString() + "-" + Workflow.randomUUID().toString(); - String savedId = Workflow.sideEffect(String.class, () -> id); - // Invoke activity in a blocking mode to ensure that asserts run after replay. - String result = activities.activity2("foo", 10); - // Assert that during replay values didn't change. - assertEquals(savedId, id); - assertEquals(savedInt, r12); - return result; - } - } - - @Test - public void testUUIDAndRandom() { - startWorkerFor(TestUUIDAndRandom.class); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub( - TestWorkflows.TestWorkflow1.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - String result = workflowStub.execute(taskQueue); - assertEquals("foo10", result); - tracer.setExpected( - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "sideEffect", - "sideEffect", - "executeActivity Activity2", - "activity Activity2"); - } - - @ActivityInterface - public interface GenericParametersActivity { - - List execute(List arg1, Set arg2); - } - - public static class GenericParametersActivityImpl implements GenericParametersActivity { - - @Override - public List execute(List arg1, Set arg2) { - List result = new ArrayList<>(); - result.addAll(arg1); - result.addAll(arg2); - return result; - } - } - - @WorkflowInterface - public interface GenericParametersWorkflow { - - @WorkflowMethod - List execute(String taskQueue, List arg1, Set arg2); - - @SignalMethod - void signal(List arg); - - @QueryMethod - List query(List arg); - } - - public static class GenericParametersWorkflowImpl implements GenericParametersWorkflow { - - private List signaled; - private GenericParametersActivity activity; - - @Override - public List execute(String taskQueue, List arg1, Set arg2) { - Workflow.await(() -> signaled != null && signaled.size() == 0); - activity = - Workflow.newActivityStub( - GenericParametersActivity.class, - TestOptions.newActivityOptionsForTaskQueue(taskQueue)); - return activity.execute(arg1, arg2); - } - - @Override - public void signal(List arg) { - signaled = arg; - } - - @Override - public List query(List arg) { - List result = new ArrayList<>(); - result.addAll(arg); - result.addAll(signaled); - return result; - } - } - - @Test - public void testGenericParametersWorkflow() throws ExecutionException, InterruptedException { - worker.registerActivitiesImplementations(new GenericParametersActivityImpl()); - startWorkerFor(GenericParametersWorkflowImpl.class); - GenericParametersWorkflow workflowStub = - workflowClient.newWorkflowStub( - GenericParametersWorkflow.class, TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - List uuidList = new ArrayList<>(); - uuidList.add(UUID.randomUUID()); - uuidList.add(UUID.randomUUID()); - Set uuidSet = new HashSet<>(); - uuidSet.add(UUID.randomUUID()); - uuidSet.add(UUID.randomUUID()); - uuidSet.add(UUID.randomUUID()); - CompletableFuture> resultF = - WorkflowClient.execute(workflowStub::execute, taskQueue, uuidList, uuidSet); - // Test signal and query serialization - workflowStub.signal(uuidList); - sleep(Duration.ofSeconds(1)); - List queryArg = new ArrayList<>(); - queryArg.add(UUID.randomUUID()); - queryArg.add(UUID.randomUUID()); - List queryResult = workflowStub.query(queryArg); - List expectedQueryResult = new ArrayList<>(); - expectedQueryResult.addAll(queryArg); - expectedQueryResult.addAll(uuidList); - expectedQueryResult.sort(UUID::compareTo); - queryResult.sort(UUID::compareTo); - assertEquals(expectedQueryResult, queryResult); - workflowStub.signal(new ArrayList<>()); // empty list unblocks workflow await. - // test workflow result serialization - List expectedResult = new ArrayList<>(); - expectedResult.addAll(uuidList); - expectedResult.addAll(uuidSet); - List result = resultF.get(); - result.sort(UUID::compareTo); - expectedResult.sort(UUID::compareTo); - assertEquals(expectedResult, result); - } - - public static class NonSerializableException extends RuntimeException { - @SuppressWarnings("unused") - private final InputStream file; // gson chokes on this field - - public NonSerializableException() { - try { - file = new FileInputStream(File.createTempFile("foo", "bar")); - } catch (IOException e) { - throw Activity.wrap(e); - } - } - } - - @ActivityInterface - public interface NonSerializableExceptionActivity { - void execute(); - } - - public static class NonSerializableExceptionActivityImpl - implements NonSerializableExceptionActivity { - - @Override - public void execute() { - throw new NonSerializableException(); - } - } - - @ActivityInterface - public interface NonDeserializableArgumentsActivity { - void execute(int arg); - } +import io.temporal.activity.Activity; +import io.temporal.activity.ActivityOptions; +import io.temporal.common.CronSchedule; +import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; +import io.temporal.workflow.shared.TestOptions; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.SimpleDateFormat; +import java.time.Duration; +import java.util.Date; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import org.slf4j.Logger; - public static class NonDeserializableExceptionActivityImpl - implements NonDeserializableArgumentsActivity { +public class WorkflowTest { - @Override - public void execute(int arg) {} - } + private static final Map retryCount = new ConcurrentHashMap<>(); + public static String lastCompletionResult; + static Optional lastFail; @WorkflowInterface - public interface NonSerializableExceptionChildWorkflow { + public interface TestWorkflowSignaled { @WorkflowMethod - String execute(String taskQueue); + String execute(); + + @SignalMethod(name = "testSignal") + void signal1(String arg); } @WorkflowInterface - public interface TestLargeWorkflow { + public interface TestWorkflow { @WorkflowMethod - String execute(int activityCount, String taskQueue); - } - - @ActivityInterface - public interface TestLargeWorkflowActivity { - String activity(); - } - - public static class TestLargeWorkflowActivityImpl implements TestLargeWorkflowActivity { - @Override - public String activity() { - return "done"; - } - } - - public static class TestLargeHistory implements TestLargeWorkflow { - - @Override - public String execute(int activityCount, String taskQueue) { - TestLargeWorkflowActivity activities = - Workflow.newActivityStub( - TestLargeWorkflowActivity.class, - TestOptions.newActivityOptionsForTaskQueue(taskQueue)); - List> results = new ArrayList<>(); - for (int i = 0; i < activityCount; i++) { - Promise result = Async.function(activities::activity); - results.add(result); - } - Promise.allOf(results).get(); - return "done"; - } - } - - @Test - @Ignore // Requires DEBUG_TIMEOUTS=true - public void testLargeHistory() { - final int activityCount = 1000; - worker.registerActivitiesImplementations(new TestLargeWorkflowActivityImpl()); - startWorkerFor(TestLargeHistory.class); - TestLargeWorkflow workflowStub = - workflowClient.newWorkflowStub( - TestLargeWorkflow.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue) - .toBuilder() - .setWorkflowTaskTimeout(Duration.ofSeconds(30)) - .build()); - long start = System.currentTimeMillis(); - String result = workflowStub.execute(activityCount, taskQueue); - long duration = System.currentTimeMillis() - start; - log.info(testName.toString() + " duration is " + duration); - assertEquals("done", result); + void execute(ChildWorkflowCancellationType cancellationType); } @WorkflowInterface - public interface WorkflowTaskTimeoutWorkflow { + public interface TestChildWorkflow { @WorkflowMethod - String execute(String testName) throws InterruptedException; - } - - public static class WorkflowTaskTimeoutWorkflowImpl implements WorkflowTaskTimeoutWorkflow { - - @Override - public String execute(String testName) throws InterruptedException { - - AtomicInteger count = retryCount.get(testName); - if (count == null) { - count = new AtomicInteger(); - retryCount.put(testName, count); - Thread.sleep(2000); - } - - return "some result"; - } - } - - @Test - public void testWorkflowTaskTimeoutWorkflow() throws InterruptedException { - startWorkerFor(WorkflowTaskTimeoutWorkflowImpl.class); - - WorkflowOptions options = - WorkflowOptions.newBuilder() - .setTaskQueue(taskQueue) - .setWorkflowTaskTimeout(Duration.ofSeconds(1)) - .build(); - - WorkflowTaskTimeoutWorkflow stub = - workflowClient.newWorkflowStub(WorkflowTaskTimeoutWorkflow.class, options); - String result = stub.execute(testName.getMethodName()); - assertEquals("some result", result); - } - - public static class TestParallelLocalActivitiesWorkflowImpl - implements TestWorkflows.TestWorkflow1 { - static final int COUNT = 100; - - @Override - public String execute(String taskQueue) { - TestActivities localActivities = - Workflow.newLocalActivityStub( - TestActivities.class, TestOptions.newLocalActivityOptions()); - List> laResults = new ArrayList<>(); - Random r = Workflow.newRandom(); - for (int i = 0; i < COUNT; i++) { - laResults.add(Async.function(localActivities::sleepActivity, (long) r.nextInt(3000), i)); - } - Promise.allOf(laResults).get(); - return "done"; - } + void execute(); } - public static class TestLocalActivitiesWorkflowTaskHeartbeatWorkflowImpl - implements TestWorkflows.TestWorkflow1 { - @Override - public String execute(String taskQueue) { - TestActivities localActivities = - Workflow.newLocalActivityStub( - TestActivities.class, TestOptions.newLocalActivityOptions()); - String result = ""; - for (int i = 0; i < 5; i++) { - result += localActivities.sleepActivity(2000, i); - } - return result; - } - } + @WorkflowInterface + public interface QueryableWorkflow { - @Test - public void testLocalActivitiesWorkflowTaskHeartbeat() - throws ExecutionException, InterruptedException { - startWorkerFor(TestLocalActivitiesWorkflowTaskHeartbeatWorkflowImpl.class); - WorkflowOptions options = - WorkflowOptions.newBuilder() - .setWorkflowRunTimeout(Duration.ofMinutes(5)) - .setWorkflowTaskTimeout(Duration.ofSeconds(4)) - .setTaskQueue(taskQueue) - .build(); - int count = 5; - Future[] result = new Future[count]; - for (int i = 0; i < count; i++) { - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); - result[i] = WorkflowClient.execute(workflowStub::execute, taskQueue); - } - for (int i = 0; i < count; i++) { - assertEquals( - "sleepActivity0sleepActivity1sleepActivity2sleepActivity3sleepActivity4", - result[i].get()); - } - assertEquals(activitiesImpl.toString(), 5 * count, activitiesImpl.invocations.size()); - } + @WorkflowMethod + String execute(); - public static class TestLongLocalActivityWorkflowTaskHeartbeatWorkflowImpl - implements TestWorkflows.TestWorkflow1 { - @Override - public String execute(String taskQueue) { - TestActivities localActivities = - Workflow.newLocalActivityStub( - TestActivities.class, TestOptions.newLocalActivityOptions()); - return localActivities.sleepActivity(5000, 123); - } - } + @QueryMethod + String getState(); - @Test - public void testLongLocalActivityWorkflowTaskHeartbeat() { - startWorkerFor(TestLongLocalActivityWorkflowTaskHeartbeatWorkflowImpl.class); - WorkflowOptions options = - WorkflowOptions.newBuilder() - .setWorkflowRunTimeout(Duration.ofMinutes(5)) - .setWorkflowTaskTimeout(Duration.ofSeconds(2)) - .setTaskQueue(taskQueue) - .build(); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); - String result = workflowStub.execute(taskQueue); - assertEquals("sleepActivity123", result); - assertEquals(activitiesImpl.toString(), 1, activitiesImpl.invocations.size()); + @SignalMethod(name = "testSignal") + void mySignal(String value); } - public static class TestLongLocalActivityWorkflowTaskHeartbeatFailureWorkflowImpl - implements TestWorkflows.TestWorkflow1 { - - static boolean invoked; - - @Override - public String execute(String taskQueue) { - TestActivities localActivities = - Workflow.newLocalActivityStub( - TestActivities.class, TestOptions.newLocalActivityOptions()); - String result = localActivities.sleepActivity(5000, 123); - if (!invoked) { - invoked = true; - throw new Error("Simulate decision failure to force replay"); - } - return result; - } - } + @WorkflowInterface + public interface ITestChild { - /** - * Test that local activity is not lost during replay if it was started before forced - * WorkflowTask. - */ - @Test - public void testLongLocalActivityWorkflowTaskHeartbeatFailure() { - startWorkerFor(TestLongLocalActivityWorkflowTaskHeartbeatFailureWorkflowImpl.class); - WorkflowOptions options = - WorkflowOptions.newBuilder() - .setWorkflowRunTimeout(Duration.ofMinutes(5)) - .setWorkflowTaskTimeout(Duration.ofSeconds(2)) - .setTaskQueue(taskQueue) - .build(); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); - String result = workflowStub.execute(taskQueue); - assertEquals("sleepActivity123", result); - assertEquals(activitiesImpl.toString(), 2, activitiesImpl.invocations.size()); + @WorkflowMethod + String execute(String arg, int delay); } - public static class TestParallelLocalActivityExecutionWorkflowImpl - implements TestWorkflows.TestWorkflow1 { - @Override - public String execute(String taskQueue) { - TestActivities localActivities = - Workflow.newLocalActivityStub( - TestActivities.class, TestOptions.newLocalActivityOptions()); - List> results = new ArrayList<>(4); - for (int i = 1; i <= 4; i++) { - results.add(Async.function(localActivities::sleepActivity, (long) 1000 * i, i)); - } - - Promise result2 = - Async.function( - () -> { - String result = ""; - for (int i = 0; i < 3; i++) { - result += localActivities.sleepActivity(1000, 21); - } - return result; - }); - - return results.get(0).get() - + results.get(1).get() - + results.get(2).get() - + results.get(3).get() - + result2.get(); - } - } + @WorkflowInterface + public interface ITestNamedChild { - @Test - public void testParallelLocalActivityExecutionWorkflow() { - startWorkerFor(TestParallelLocalActivityExecutionWorkflowImpl.class); - WorkflowOptions options = - WorkflowOptions.newBuilder() - .setWorkflowRunTimeout(Duration.ofMinutes(5)) - .setWorkflowTaskTimeout(Duration.ofSeconds(5)) - .setTaskQueue(taskQueue) - .build(); - TestWorkflows.TestWorkflow1 workflowStub = - workflowClient.newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); - String result = workflowStub.execute(taskQueue); - assertEquals( - "sleepActivity1sleepActivity2sleepActivity3sleepActivity4sleepActivity21sleepActivity21sleepActivity21", - result); + @WorkflowMethod(name = "namedChild") + String execute(String arg); } @WorkflowInterface - public interface TestWorkflowQuery { - - @WorkflowMethod() - String execute(String taskQueue); + public interface SignalingChild { - @QueryMethod() - String query(); + @WorkflowMethod + String execute(String arg, String parentWorkflowId); } - public interface GreetingWorkflow { + @WorkflowInterface + public interface TestWorkflowRetry { @WorkflowMethod - void createGreeting(String name); - } - - public interface GreetingActivities { - @ActivityMethod - String composeGreeting(String string); + String execute(String testName); } - static class GreetingActivitiesImpl implements GreetingActivities { - @Override - public String composeGreeting(String string) { - try { - Thread.sleep(10000); - } catch (InterruptedException e) { - throw new Error("Unexpected", e); - } - return "greetings: " + string; - } + @WorkflowInterface + public interface TestWorkflowWithCronSchedule { + @WorkflowMethod + @CronSchedule("0 * * * *") + String execute(String testName); } @WorkflowInterface - public interface TestCompensationWorkflow { + public interface DeterminismFailingWorkflow { @WorkflowMethod - void compensate(); + void execute(String taskQueue); } - public static class TestMultiargsWorkflowsFuncImpl - implements TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc { + public interface SignalQueryBase { + @SignalMethod + void signal(String arg); - @Override - public String func() { - return "done"; - } + @QueryMethod + String getSignal(); } - public static class TestCompensationWorkflowImpl implements TestCompensationWorkflow { - @Override - public void compensate() {} - } + public static class TestChild implements ITestChild { - @WorkflowInterface - public interface TestSagaWorkflow { - @WorkflowMethod - String execute(String taskQueue, boolean parallelCompensation); + @Override + public String execute(String arg, int delay) { + Workflow.sleep(delay); + return arg.toUpperCase(); + } } - public static class TestSagaWorkflowImpl implements TestSagaWorkflow { + public static class AngryChild implements ITestChild { @Override - public String execute(String taskQueue, boolean parallelCompensation) { - TestActivities testActivities = + public String execute(String taskQueue, int delay) { + TestActivities.AngryChildActivity activity = Workflow.newActivityStub( - TestActivities.class, - TestOptions.newActivityOptionsForTaskQueue(taskQueue) - .toBuilder() - .setRetryOptions(RetryOptions.newBuilder().setMaximumAttempts(1).build()) + TestActivities.AngryChildActivity.class, + ActivityOptions.newBuilder() + .setTaskQueue(taskQueue) + .setScheduleToCloseTimeout(Duration.ofSeconds(5)) .build()); + activity.execute(); + throw ApplicationFailure.newFailure("simulated failure", "test"); + } + } - ChildWorkflowOptions workflowOptions = - ChildWorkflowOptions.newBuilder().setTaskQueue(taskQueue).build(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc stubF1 = - Workflow.newChildWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc.class, workflowOptions); + public static class TestWorkflowWithCronScheduleImpl implements TestWorkflowWithCronSchedule { - Saga saga = - new Saga( - new Saga.Options.Builder().setParallelCompensation(parallelCompensation).build()); - try { - testActivities.activity1(10); - saga.addCompensation(testActivities::activity2, "compensate", -10); + @Override + public String execute(String testName) { + Logger log = Workflow.getLogger(TestWorkflowWithCronScheduleImpl.class); - stubF1.func(); + if (CancellationScope.current().isCancelRequested()) { + log.debug("TestWorkflowWithCronScheduleImpl run canceled."); + return null; + } - TestCompensationWorkflow compensationWorkflow = - Workflow.newChildWorkflowStub(TestCompensationWorkflow.class, workflowOptions); - saga.addCompensation(compensationWorkflow::compensate); + lastCompletionResult = Workflow.getLastCompletionResult(String.class); + lastFail = Workflow.getPreviousRunFailure(); - testActivities.throwIO(); - saga.addCompensation( - () -> { - throw new RuntimeException("unreachable"); - }); - } catch (Exception e) { - saga.compensate(); + AtomicInteger count = retryCount.get(testName); + if (count == null) { + count = new AtomicInteger(); + retryCount.put(testName, count); } - return "done"; - } - } - - @Test - public void testSaga() { - startWorkerFor( - TestSagaWorkflowImpl.class, - TestMultiargsWorkflowsFuncImpl.class, - TestCompensationWorkflowImpl.class); - TestSagaWorkflow sagaWorkflow = - workflowClient.newWorkflowStub( - TestSagaWorkflow.class, TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - sagaWorkflow.execute(taskQueue, false); - tracer.setExpected( - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "executeActivity customActivity1", - "activity customActivity1", - "executeChildWorkflow TestMultiargsWorkflowsFunc", - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "executeActivity ThrowIO", - "activity ThrowIO", - "executeChildWorkflow TestCompensationWorkflow", - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "executeActivity Activity2", - "activity Activity2"); - } + int c = count.incrementAndGet(); - @Test - public void testSagaParallelCompensation() { - startWorkerFor( - TestSagaWorkflowImpl.class, - TestMultiargsWorkflowsFuncImpl.class, - TestCompensationWorkflowImpl.class); - TestSagaWorkflow sagaWorkflow = - workflowClient.newWorkflowStub( - TestSagaWorkflow.class, TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - sagaWorkflow.execute(taskQueue, true); - String trace = tracer.getTrace(); - assertTrue(trace, trace.contains("executeChildWorkflow TestCompensationWorkflow")); - assertTrue(trace, trace.contains("executeActivity Activity2")); - } + if (c == 3) { + throw ApplicationFailure.newFailure("simulated error", "test"); + } - @WorkflowInterface - public interface TestUpsertSearchAttributes { - @WorkflowMethod - String execute(String taskQueue, String keyword); + SimpleDateFormat sdf = new SimpleDateFormat("MMM dd,yyyy HH:mm:ss.SSS"); + Date now = new Date(Workflow.currentTimeMillis()); + log.debug("TestWorkflowWithCronScheduleImpl run at " + sdf.format(now)); + return "run " + c; + } } - public static class TestUpsertSearchAttributesImpl implements TestUpsertSearchAttributes { + public static class DeterminismFailingWorkflowImpl implements DeterminismFailingWorkflow { @Override - public String execute(String taskQueue, String keyword) { - SearchAttributes searchAttributes = Workflow.getInfo().getSearchAttributes(); - assertNull(searchAttributes); - - Map searchAttrMap = new HashMap<>(); - searchAttrMap.put("CustomKeywordField", keyword); - Workflow.upsertSearchAttributes(searchAttrMap); - - searchAttributes = Workflow.getInfo().getSearchAttributes(); - assertEquals( - "testKey", - SearchAttributesUtil.getValueFromSearchAttributes( - searchAttributes, "CustomKeywordField", String.class)); - - // Running the activity below ensures that we have one more workflow task to be executed after - // adding the search attributes. This helps with replaying the history one more time to check - // against a possible NonDeterminisicWorkflowError which could be caused by missing - // UpsertWorkflowSearchAttributes event in history. + public void execute(String taskQueue) { TestActivities activities = Workflow.newActivityStub( TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); - activities.activity(); - - return "done"; - } - } - - @Test - public void testUpsertSearchAttributes() { - startWorkerFor(TestUpsertSearchAttributesImpl.class); - TestUpsertSearchAttributes testWorkflow = - workflowClient.newWorkflowStub( - TestUpsertSearchAttributes.class, - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue)); - WorkflowExecution execution = WorkflowClient.start(testWorkflow::execute, taskQueue, "testKey"); - String result = testWorkflow.execute(taskQueue, "testKey"); - assertEquals("done", result); - tracer.setExpected( - "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, - "newThread workflow-method", - "upsertSearchAttributes", - "executeActivity Activity", - "activity Activity"); - GetWorkflowExecutionHistoryRequest request = - GetWorkflowExecutionHistoryRequest.newBuilder() - .setNamespace(SDKTestWorkflowRule.NAMESPACE) - .setExecution(execution) - .build(); - GetWorkflowExecutionHistoryResponse response = - service.blockingStub().getWorkflowExecutionHistory(request); - - boolean found = false; - for (HistoryEvent event : response.getHistory().getEventsList()) { - if (EventType.EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES == event.getEventType()) { - found = true; - break; + if (!Workflow.isReplaying()) { + activities.activity1(1); } } - assertTrue("EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES found in the history", found); } - public static class TestMultiargsWorkflowsFuncChild - implements TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc2 { - @Override - public String func2(String s, int i) { - WorkflowInfo wi = Workflow.getInfo(); - Optional parentId = wi.getParentWorkflowId(); - return parentId.get(); - } - } + public static class NonSerializableException extends RuntimeException { + @SuppressWarnings("unused") + private final InputStream file; // gson chokes on this field - public static class TestAttemptReturningWorkflowFunc implements TestGetAttemptWorkflowsFunc { - @Override - public int func() { - WorkflowInfo wi = Workflow.getInfo(); - return wi.getAttempt(); + public NonSerializableException() { + try { + file = new FileInputStream(File.createTempFile("foo", "bar")); + } catch (IOException e) { + throw Activity.wrap(e); + } } } @@ -3286,84 +233,4 @@ public String func() { return result; } } - - @Test - public void testParentWorkflowInfoInChildWorkflows() { - startWorkerFor(TestMultiargsWorkflowsFuncParent.class, TestMultiargsWorkflowsFuncChild.class); - - String workflowId = "testParentWorkflowInfoInChildWorkflows"; - WorkflowOptions workflowOptions = - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue) - .toBuilder() - .setWorkflowId(workflowId) - .build(); - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc parent = - workflowClient.newWorkflowStub( - TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc.class, workflowOptions); - - String result = parent.func(); - String expected = String.format("%s - %s", false, workflowId); - assertEquals(expected, result); - } - - @Test - public void testGetAttemptFromWorkflowInfo() { - startWorkerFor(TestMultiargsWorkflowsFuncParent.class, TestAttemptReturningWorkflowFunc.class); - String workflowId = "testGetAttemptWorkflow"; - WorkflowOptions workflowOptions = - TestOptions.newWorkflowOptionsWithTimeouts(taskQueue) - .toBuilder() - .setWorkflowId(workflowId) - .build(); - TestGetAttemptWorkflowsFunc workflow = - workflowClient.newWorkflowStub(TestGetAttemptWorkflowsFunc.class, workflowOptions); - int attempt = workflow.func(); - assertEquals(1, attempt); - } - - public interface WorkflowBase { - @WorkflowMethod - String execute(String arg); - } - - @WorkflowInterface - public interface WorkflowA extends WorkflowBase {} - - @WorkflowInterface - public interface WorkflowB extends WorkflowBase {} - - public static class WorkflowAImpl implements WorkflowA { - @Override - public String execute(String arg) { - return "WorkflowAImpl" + arg; - } - } - - public static class WorkflowBImpl implements WorkflowB { - @Override - public String execute(String arg) { - return "WorkflowBImpl" + arg; - } - } - - @Test - public void testPolymorphicStart() { - startWorkerFor(WorkflowBImpl.class, WorkflowAImpl.class); - WorkflowOptions options = TestOptions.newWorkflowOptionsWithTimeouts(taskQueue); - WorkflowBase[] stubs = - new WorkflowBase[] { - workflowClient.newWorkflowStub(WorkflowA.class, options), - workflowClient.newWorkflowStub(WorkflowB.class, options), - }; - String results = stubs[0].execute("0") + ", " + stubs[1].execute("1"); - assertEquals("WorkflowAImpl0, WorkflowBImpl1", results); - } - - public interface SignalQueryBase { - @SignalMethod - void signal(String arg); - - @QueryMethod - String getSignal(); - } } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowWithCronScheduleTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowWithCronScheduleTest.java index d89b51cb58..ddb88d47fd 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowWithCronScheduleTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowWithCronScheduleTest.java @@ -27,7 +27,6 @@ import io.temporal.client.WorkflowStub; import io.temporal.failure.CanceledFailure; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import java.time.Duration; import org.junit.Assume; import org.junit.Rule; @@ -36,16 +35,12 @@ public class WorkflowWithCronScheduleTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - @Rule public TestName testName = new TestName(); @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes(WorkflowTest.TestWorkflowWithCronScheduleImpl.class) - .setActivityImplementations(activitiesImpl) .build(); @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowsWithFailedPromisesCanBeCanceledTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowsWithFailedPromisesCanBeCanceledTest.java new file mode 100644 index 0000000000..8be608c926 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/WorkflowsWithFailedPromisesCanBeCanceledTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow; + +import static org.junit.Assert.fail; + +import com.google.common.util.concurrent.UncheckedExecutionException; +import io.temporal.client.WorkflowFailedException; +import io.temporal.client.WorkflowStub; +import io.temporal.failure.CanceledFailure; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestWorkflows; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class WorkflowsWithFailedPromisesCanBeCanceledTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestCancellationForWorkflowsWithFailedPromises.class) + .build(); + + @Test + public void workflowsWithFailedPromisesCanBeCanceled() { + WorkflowStub client = testWorkflowRule.newUntypedWorkflowStubTimeoutOptions("TestWorkflow1"); + client.start(testWorkflowRule.getTaskQueue()); + client.cancel(); + + try { + client.getResult(String.class); + Assert.fail("unreachable"); + } catch (WorkflowFailedException e) { + Assert.assertTrue(e.getCause() instanceof CanceledFailure); + } + } + + public static class TestCancellationForWorkflowsWithFailedPromises + implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + Async.function( + () -> { + throw new UncheckedExecutionException(new Exception("Oh noo!")); + }); + Async.function( + () -> { + throw new UncheckedExecutionException(new Exception("Oh noo again!")); + }); + Workflow.await(() -> false); + fail("unreachable"); + return "done"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/AbandonOnCancelActivityTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AbandonOnCancelActivityTest.java similarity index 77% rename from temporal-sdk/src/test/java/io/temporal/workflow/AbandonOnCancelActivityTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AbandonOnCancelActivityTest.java index 78ed806a02..b0b873c0a7 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/AbandonOnCancelActivityTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AbandonOnCancelActivityTest.java @@ -17,23 +17,20 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.ActivityCancellationType; import io.temporal.activity.ActivityOptions; import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.api.enums.v1.EventType; +import io.temporal.api.history.v1.History; import io.temporal.api.history.v1.HistoryEvent; -import io.temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryRequest; -import io.temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryResponse; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowFailedException; import io.temporal.client.WorkflowStub; import io.temporal.failure.CanceledFailure; -import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; -import io.temporal.workflow.shared.TestOptions; -import io.temporal.workflow.shared.TestWorkflows; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.*; import java.time.Duration; import org.junit.Assert; import org.junit.Rule; @@ -42,7 +39,7 @@ public class AbandonOnCancelActivityTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = @@ -73,19 +70,9 @@ public void testAbandonOnCancelActivity() { long elapsed = testWorkflowRule.getTestEnvironment().currentTimeMillis() - start; Assert.assertTrue(String.valueOf(elapsed), elapsed < 500); activitiesImpl.assertInvocations("activityWithDelay"); - GetWorkflowExecutionHistoryRequest request = - GetWorkflowExecutionHistoryRequest.newBuilder() - .setNamespace(testWorkflowRule.getTestEnvironment().getNamespace()) - .setExecution(execution) - .build(); - GetWorkflowExecutionHistoryResponse response = - testWorkflowRule - .getWorkflowClient() - .getWorkflowServiceStubs() - .blockingStub() - .getWorkflowExecutionHistory(request); + History history = testWorkflowRule.getWorkflowExecutionHistory(execution); - for (HistoryEvent event : response.getHistory().getEventsList()) { + for (HistoryEvent event : history.getEventsList()) { Assert.assertNotEquals( EventType.EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED, event.getEventType()); } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityApplicationFailureNonRetryableTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityApplicationFailureNonRetryableTest.java similarity index 96% rename from temporal-sdk/src/test/java/io/temporal/workflow/ActivityApplicationFailureNonRetryableTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityApplicationFailureNonRetryableTest.java index ece0f9c028..fa6793ca52 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityApplicationFailureNonRetryableTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityApplicationFailureNonRetryableTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.ActivityOptions; import io.temporal.api.enums.v1.RetryState; @@ -25,6 +25,7 @@ import io.temporal.common.RetryOptions; import io.temporal.failure.ActivityFailure; import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; @@ -37,7 +38,7 @@ public class ActivityApplicationFailureNonRetryableTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityApplicationFailureRetryTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityApplicationFailureRetryTest.java similarity index 96% rename from temporal-sdk/src/test/java/io/temporal/workflow/ActivityApplicationFailureRetryTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityApplicationFailureRetryTest.java index ac972d5a90..e0ab46ff1e 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityApplicationFailureRetryTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityApplicationFailureRetryTest.java @@ -17,13 +17,14 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowException; import io.temporal.common.RetryOptions; import io.temporal.failure.ActivityFailure; import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; @@ -35,7 +36,7 @@ public class ActivityApplicationFailureRetryTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityApplicationNoSpecifiedRetryTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityApplicationNoSpecifiedRetryTest.java similarity index 95% rename from temporal-sdk/src/test/java/io/temporal/workflow/ActivityApplicationNoSpecifiedRetryTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityApplicationNoSpecifiedRetryTest.java index 722c2e83a1..4e8b3e0200 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityApplicationNoSpecifiedRetryTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityApplicationNoSpecifiedRetryTest.java @@ -17,12 +17,13 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowException; import io.temporal.failure.ActivityFailure; import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; @@ -34,7 +35,7 @@ public class ActivityApplicationNoSpecifiedRetryTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityApplicationOptOutOfRetryTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityApplicationOptOutOfRetryTest.java similarity index 95% rename from temporal-sdk/src/test/java/io/temporal/workflow/ActivityApplicationOptOutOfRetryTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityApplicationOptOutOfRetryTest.java index 89964faa8e..be29f4094e 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityApplicationOptOutOfRetryTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityApplicationOptOutOfRetryTest.java @@ -17,13 +17,14 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowException; import io.temporal.common.RetryOptions; import io.temporal.failure.ActivityFailure; import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; @@ -35,7 +36,7 @@ public class ActivityApplicationOptOutOfRetryTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityPollerPrefetchingTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityPollerPrefetchingTest.java similarity index 98% rename from temporal-sdk/src/test/java/io/temporal/workflow/ActivityPollerPrefetchingTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityPollerPrefetchingTest.java index 40544e51c2..91954a12c8 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityPollerPrefetchingTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityPollerPrefetchingTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.Activity; import io.temporal.activity.ActivityInterface; @@ -25,6 +25,7 @@ import io.temporal.activity.ActivityOptions; import io.temporal.common.RetryOptions; import io.temporal.worker.WorkerOptions; +import io.temporal.workflow.*; import io.temporal.workflow.shared.SDKTestWorkflowRule; import java.time.Duration; import java.util.ArrayList; diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryAnnotatedTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryAnnotatedTest.java similarity index 95% rename from temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryAnnotatedTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryAnnotatedTest.java index 67e7b91eef..53e20e778a 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryAnnotatedTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryAnnotatedTest.java @@ -17,12 +17,13 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowException; import io.temporal.failure.ActivityFailure; import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; @@ -35,7 +36,7 @@ public class ActivityRetryAnnotatedTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryOnTimeoutTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryOnTimeoutTest.java similarity index 96% rename from temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryOnTimeoutTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryOnTimeoutTest.java index d59b2cd1ab..2729665024 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryOnTimeoutTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryOnTimeoutTest.java @@ -17,13 +17,14 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowException; import io.temporal.common.RetryOptions; import io.temporal.failure.ActivityFailure; import io.temporal.failure.TimeoutFailure; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; @@ -35,7 +36,7 @@ public class ActivityRetryOnTimeoutTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public TestName testName = new TestName(); diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryOptionsChangeTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryOptionsChangeTest.java similarity index 96% rename from temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryOptionsChangeTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryOptionsChangeTest.java index 7831ecb489..64a81731cf 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryOptionsChangeTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryOptionsChangeTest.java @@ -17,12 +17,13 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowException; import io.temporal.common.RetryOptions; import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; @@ -36,7 +37,7 @@ public class ActivityRetryOptionsChangeTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryWithExpirationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryWithExpirationTest.java similarity index 91% rename from temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryWithExpirationTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryWithExpirationTest.java index 533daa1f09..51310e27c2 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryWithExpirationTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryWithExpirationTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import static org.junit.Assert.fail; @@ -26,6 +26,7 @@ import io.temporal.common.RetryOptions; import io.temporal.failure.ActivityFailure; import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; @@ -38,7 +39,7 @@ public class ActivityRetryWithExpirationTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = @@ -63,10 +64,14 @@ public void testActivityRetryWithExpiration() { Assert.assertEquals(activitiesImpl.toString(), 3, activitiesImpl.invocations.size()); } + public interface EmptyInterface {} + + public interface UnrelatedInterface { + void unrelatedMethod(); + } + public static class TestActivityRetryWithExpiration - implements TestWorkflows.TestWorkflow1, - WorkflowTest.EmptyInterface, - WorkflowTest.UnrelatedInterface { + implements TestWorkflows.TestWorkflow1, EmptyInterface, UnrelatedInterface { @Override @SuppressWarnings("Finally") diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryWithMaxAttemptsTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryWithMaxAttemptsTest.java similarity index 97% rename from temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryWithMaxAttemptsTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryWithMaxAttemptsTest.java index 9f0fb7d4e9..ce3be284fe 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityRetryWithMaxAttemptsTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityRetryWithMaxAttemptsTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import static org.junit.Assert.*; @@ -27,6 +27,7 @@ import io.temporal.failure.ActivityFailure; import io.temporal.failure.ApplicationFailure; import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; @@ -38,7 +39,7 @@ public class ActivityRetryWithMaxAttemptsTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityThrowingErrorTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityThrowingErrorTest.java similarity index 97% rename from temporal-sdk/src/test/java/io/temporal/workflow/ActivityThrowingErrorTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityThrowingErrorTest.java index 775fea0279..d9685e74b2 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ActivityThrowingErrorTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ActivityThrowingErrorTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -34,6 +34,9 @@ import io.temporal.testing.TestEnvironmentOptions; import io.temporal.testing.TestWorkflowEnvironment; import io.temporal.worker.Worker; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; import java.time.Duration; import java.util.UUID; import org.junit.After; diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncActivityCompleteWithErrorTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityCompleteWithErrorTest.java similarity index 97% rename from temporal-sdk/src/test/java/io/temporal/workflow/AsyncActivityCompleteWithErrorTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityCompleteWithErrorTest.java index ae1d59f3d3..4a3725aa5a 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncActivityCompleteWithErrorTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityCompleteWithErrorTest.java @@ -17,12 +17,13 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.*; import io.temporal.activity.ManualActivityCompletionClient; import io.temporal.common.RetryOptions; import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.*; import io.temporal.workflow.shared.SDKTestWorkflowRule; import java.time.Duration; import java.util.concurrent.ForkJoinPool; diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncActivityRetryOptionsChangeTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityRetryOptionsChangeTest.java similarity index 95% rename from temporal-sdk/src/test/java/io/temporal/workflow/AsyncActivityRetryOptionsChangeTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityRetryOptionsChangeTest.java index 8b5f978d2a..783e62cca2 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncActivityRetryOptionsChangeTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityRetryOptionsChangeTest.java @@ -17,13 +17,15 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowException; import io.temporal.common.RetryOptions; import io.temporal.failure.ActivityFailure; import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.Async; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; @@ -36,7 +38,7 @@ public class AsyncActivityRetryOptionsChangeTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncActivityRetry.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityRetryTest.java similarity index 95% rename from temporal-sdk/src/test/java/io/temporal/workflow/AsyncActivityRetry.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityRetryTest.java index a16830aace..8efda50ca9 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncActivityRetry.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityRetryTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.ActivityOptions; import io.temporal.api.common.v1.WorkflowExecution; @@ -26,6 +26,8 @@ import io.temporal.common.RetryOptions; import io.temporal.failure.ApplicationFailure; import io.temporal.testing.WorkflowReplayer; +import io.temporal.workflow.Async; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; @@ -36,9 +38,9 @@ import org.junit.Rule; import org.junit.Test; -public class AsyncActivityRetry { +public class AsyncActivityRetryTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncActivityTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityTest.java similarity index 95% rename from temporal-sdk/src/test/java/io/temporal/workflow/AsyncActivityTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityTest.java index 7892566bc8..e11654d1d6 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncActivityTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityTest.java @@ -17,10 +17,13 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import static org.junit.Assert.assertEquals; +import io.temporal.workflow.Async; +import io.temporal.workflow.Promise; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestOptions; @@ -34,7 +37,7 @@ public class AsyncActivityTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = @@ -45,8 +48,6 @@ public class AsyncActivityTest { @Test public void testAsyncActivity() { - // TODO: (vkoby) See if this activityImpl could be constructed from within the rule with the - // right completion client. activitiesImpl.completionClient = testWorkflowRule.getWorkflowClient().newActivityCompletionClient(); TestWorkflows.TestWorkflow1 client = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncRetryOptionsChangeTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncRetryOptionsChangeTest.java similarity index 94% rename from temporal-sdk/src/test/java/io/temporal/workflow/AsyncRetryOptionsChangeTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncRetryOptionsChangeTest.java index 1fc3569b6e..402c322390 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncRetryOptionsChangeTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncRetryOptionsChangeTest.java @@ -17,15 +17,16 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.client.WorkflowException; import io.temporal.common.RetryOptions; import io.temporal.failure.ApplicationFailure; import io.temporal.internal.sync.DeterministicRunnerTest; import io.temporal.worker.WorkflowImplementationOptions; +import io.temporal.workflow.Async; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; import java.time.Duration; import java.util.ArrayList; @@ -37,9 +38,6 @@ public class AsyncRetryOptionsChangeTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() @@ -48,7 +46,6 @@ public class AsyncRetryOptionsChangeTest { .setFailWorkflowExceptionTypes(IllegalThreadStateException.class) .build(), TestAsyncRetryOptionsChangeWorkflow.class) - .setActivityImplementations(activitiesImpl) .build(); /** @see DeterministicRunnerTest#testRetry() */ diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncRetryTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncRetryTest.java similarity index 90% rename from temporal-sdk/src/test/java/io/temporal/workflow/AsyncRetryTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncRetryTest.java index a53bd61451..13869333a3 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncRetryTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncRetryTest.java @@ -17,14 +17,15 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.client.WorkflowException; import io.temporal.common.RetryOptions; import io.temporal.failure.ApplicationFailure; import io.temporal.internal.sync.DeterministicRunnerTest; +import io.temporal.workflow.Async; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; import java.time.Duration; import java.util.ArrayList; @@ -36,15 +37,9 @@ public class AsyncRetryTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - @Rule public SDKTestWorkflowRule testWorkflowRule = - SDKTestWorkflowRule.newBuilder() - .setWorkflowTypes(TestAsyncRetryWorkflowImpl.class) - .setActivityImplementations(activitiesImpl) - .build(); + SDKTestWorkflowRule.newBuilder().setWorkflowTypes(TestAsyncRetryWorkflowImpl.class).build(); /** @see DeterministicRunnerTest#testRetry() */ @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncUntyped2ActivityTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncUntyped2ActivityTest.java similarity index 95% rename from temporal-sdk/src/test/java/io/temporal/workflow/AsyncUntyped2ActivityTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncUntyped2ActivityTest.java index 068b1a1f0d..d5f1b91565 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncUntyped2ActivityTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncUntyped2ActivityTest.java @@ -17,10 +17,13 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import static org.junit.Assert.assertEquals; +import io.temporal.workflow.ActivityStub; +import io.temporal.workflow.Promise; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestOptions; @@ -32,7 +35,7 @@ public class AsyncUntyped2ActivityTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = @@ -43,8 +46,6 @@ public class AsyncUntyped2ActivityTest { @Test public void testAsyncUntyped2Activity() { - // TODO: (vkoby) See if this activityImpl could be constructed from within the rule with the - // right completion client. activitiesImpl.completionClient = testWorkflowRule.getWorkflowClient().newActivityCompletionClient(); TestWorkflows.TestWorkflow1 client = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncUntypedActivityTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncUntypedActivityTest.java similarity index 93% rename from temporal-sdk/src/test/java/io/temporal/workflow/AsyncUntypedActivityTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncUntypedActivityTest.java index 95780e2c96..f261694394 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/AsyncUntypedActivityTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncUntypedActivityTest.java @@ -17,10 +17,14 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import static org.junit.Assert.assertEquals; +import io.temporal.workflow.ActivityStub; +import io.temporal.workflow.Async; +import io.temporal.workflow.Promise; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestOptions; @@ -32,7 +36,7 @@ public class AsyncUntypedActivityTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = @@ -43,8 +47,6 @@ public class AsyncUntypedActivityTest { @Test public void testAsyncUntypedActivity() { - // TODO: (vkoby) See if this activityImpl could be constructed from within the rule with the - // right completion client. activitiesImpl.completionClient = testWorkflowRule.getWorkflowClient().newActivityCompletionClient(); TestWorkflows.TestWorkflow1 client = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivitiesWorkflowTaskHeartbeatTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivitiesWorkflowTaskHeartbeatTest.java new file mode 100644 index 0000000000..fbebbceaab --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivitiesWorkflowTaskHeartbeatTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.activityTests; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class LocalActivitiesWorkflowTaskHeartbeatTest { + + private final TestActivities.TestActivitiesImpl activitiesImpl = + new TestActivities.TestActivitiesImpl(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestLocalActivitiesWorkflowTaskHeartbeatWorkflowImpl.class) + .setActivityImplementations(activitiesImpl) + .setTestTimeoutSeconds(15) + .build(); + + @Test + public void testLocalActivitiesWorkflowTaskHeartbeat() + throws ExecutionException, InterruptedException { + WorkflowOptions options = + WorkflowOptions.newBuilder() + .setWorkflowRunTimeout(Duration.ofMinutes(5)) + .setWorkflowTaskTimeout(Duration.ofSeconds(4)) + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build(); + int count = 5; + Future[] result = new Future[count]; + for (int i = 0; i < count; i++) { + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); + result[i] = WorkflowClient.execute(workflowStub::execute, testWorkflowRule.getTaskQueue()); + } + for (int i = 0; i < count; i++) { + Assert.assertEquals( + "sleepActivity0sleepActivity1sleepActivity2sleepActivity3sleepActivity4", + result[i].get()); + } + Assert.assertEquals(activitiesImpl.toString(), 5 * count, activitiesImpl.invocations.size()); + } + + public static class TestLocalActivitiesWorkflowTaskHeartbeatWorkflowImpl + implements TestWorkflows.TestWorkflow1 { + @Override + public String execute(String taskQueue) { + TestActivities localActivities = + Workflow.newLocalActivityStub( + TestActivities.class, TestOptions.newLocalActivityOptions()); + String result = ""; + for (int i = 0; i < 5; i++) { + result += localActivities.sleepActivity(2000, i); + } + return result; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/LocalActivityAndQueryTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivityAndQueryTest.java similarity index 94% rename from temporal-sdk/src/test/java/io/temporal/workflow/LocalActivityAndQueryTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivityAndQueryTest.java index eaefb60db1..452689b632 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/LocalActivityAndQueryTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivityAndQueryTest.java @@ -17,12 +17,16 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; import io.temporal.testing.TestWorkflowRule; +import io.temporal.workflow.QueryMethod; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestOptions; import java.time.Duration; @@ -38,7 +42,7 @@ public class LocalActivityAndQueryTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public TestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/LocalActivityManyWorkflowsTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivityManyWorkflowsTest.java similarity index 94% rename from temporal-sdk/src/test/java/io/temporal/workflow/LocalActivityManyWorkflowsTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivityManyWorkflowsTest.java index 7c8500a47d..7f1f7c95ea 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/LocalActivityManyWorkflowsTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivityManyWorkflowsTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import static org.junit.Assert.assertEquals; @@ -28,6 +28,9 @@ import io.temporal.testing.TestEnvironmentOptions; import io.temporal.testing.TestWorkflowEnvironment; import io.temporal.worker.Worker; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; import java.time.Duration; import org.junit.After; import org.junit.Before; diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/LocalActivityRetryTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivityRetryTest.java similarity index 96% rename from temporal-sdk/src/test/java/io/temporal/workflow/LocalActivityRetryTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivityRetryTest.java index accae29ccc..abaa77dd5b 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/LocalActivityRetryTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivityRetryTest.java @@ -17,13 +17,14 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.LocalActivityOptions; import io.temporal.client.WorkflowException; import io.temporal.common.RetryOptions; import io.temporal.failure.ActivityFailure; import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; @@ -35,7 +36,7 @@ public class LocalActivityRetryTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/LocalActivityTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivityTest.java similarity index 96% rename from temporal-sdk/src/test/java/io/temporal/workflow/LocalActivityTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivityTest.java index 80e2f70587..7e3239c914 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/LocalActivityTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LocalActivityTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -25,6 +25,7 @@ import io.temporal.failure.ActivityFailure; import io.temporal.failure.ApplicationFailure; import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestOptions; @@ -37,7 +38,7 @@ public class LocalActivityTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LongLocalActivityWorkflowTaskHeartbeatFailureTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LongLocalActivityWorkflowTaskHeartbeatFailureTest.java new file mode 100644 index 0000000000..957a9ce726 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LongLocalActivityWorkflowTaskHeartbeatFailureTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.activityTests; + +import io.temporal.client.WorkflowOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class LongLocalActivityWorkflowTaskHeartbeatFailureTest { + + private final TestActivities.TestActivitiesImpl activitiesImpl = + new TestActivities.TestActivitiesImpl(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestLongLocalActivityWorkflowTaskHeartbeatFailureWorkflowImpl.class) + .setActivityImplementations(activitiesImpl) + .setTestTimeoutSeconds(15) + .build(); + + /** + * Test that local activity is not lost during replay if it was started before forced + * WorkflowTask. + */ + @Test + public void testLongLocalActivityWorkflowTaskHeartbeatFailure() { + WorkflowOptions options = + WorkflowOptions.newBuilder() + .setWorkflowRunTimeout(Duration.ofMinutes(5)) + .setWorkflowTaskTimeout(Duration.ofSeconds(2)) + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build(); + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.assertEquals("sleepActivity123", result); + Assert.assertEquals(activitiesImpl.toString(), 2, activitiesImpl.invocations.size()); + } + + public static class TestLongLocalActivityWorkflowTaskHeartbeatFailureWorkflowImpl + implements TestWorkflows.TestWorkflow1 { + + static boolean invoked; + + @Override + public String execute(String taskQueue) { + TestActivities localActivities = + Workflow.newLocalActivityStub( + TestActivities.class, TestOptions.newLocalActivityOptions()); + String result = localActivities.sleepActivity(5000, 123); + if (!invoked) { + invoked = true; + throw new Error("Simulate decision failure to force replay"); + } + return result; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LongLocalActivityWorkflowTaskHeartbeatTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LongLocalActivityWorkflowTaskHeartbeatTest.java new file mode 100644 index 0000000000..6d66276598 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/LongLocalActivityWorkflowTaskHeartbeatTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.activityTests; + +import io.temporal.client.WorkflowOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class LongLocalActivityWorkflowTaskHeartbeatTest { + + private final TestActivities.TestActivitiesImpl activitiesImpl = + new TestActivities.TestActivitiesImpl(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestLongLocalActivityWorkflowTaskHeartbeatWorkflowImpl.class) + .setActivityImplementations(activitiesImpl) + .build(); + + @Test + public void testLongLocalActivityWorkflowTaskHeartbeat() { + WorkflowOptions options = + WorkflowOptions.newBuilder() + .setWorkflowRunTimeout(Duration.ofMinutes(5)) + .setWorkflowTaskTimeout(Duration.ofSeconds(2)) + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build(); + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.assertEquals("sleepActivity123", result); + Assert.assertEquals(activitiesImpl.toString(), 1, activitiesImpl.invocations.size()); + } + + public static class TestLongLocalActivityWorkflowTaskHeartbeatWorkflowImpl + implements TestWorkflows.TestWorkflow1 { + @Override + public String execute(String taskQueue) { + TestActivities localActivities = + Workflow.newLocalActivityStub( + TestActivities.class, TestOptions.newLocalActivityOptions()); + return localActivities.sleepActivity(5000, 123); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/NonSerializableArgumentsInActivityTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/NonSerializableArgumentsInActivityTest.java similarity index 87% rename from temporal-sdk/src/test/java/io/temporal/workflow/NonSerializableArgumentsInActivityTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/NonSerializableArgumentsInActivityTest.java index 236876f6d5..8c74d8e1cc 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/NonSerializableArgumentsInActivityTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/NonSerializableArgumentsInActivityTest.java @@ -17,13 +17,16 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; +import io.temporal.activity.ActivityInterface; import io.temporal.activity.ActivityOptions; import io.temporal.activity.LocalActivityOptions; import io.temporal.common.RetryOptions; import io.temporal.failure.ActivityFailure; import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.ActivityStub; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestWorkflows; import java.time.Duration; @@ -33,8 +36,8 @@ public class NonSerializableArgumentsInActivityTest { - private final WorkflowTest.NonDeserializableExceptionActivityImpl activitiesImpl = - new WorkflowTest.NonDeserializableExceptionActivityImpl(); + private final NonDeserializableExceptionActivityImpl activitiesImpl = + new NonDeserializableExceptionActivityImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = @@ -53,6 +56,11 @@ public void testNonSerializableArgumentsInActivity() { "ApplicationFailure-io.temporal.common.converter.DataConverterException", result); } + @ActivityInterface + public interface NonDeserializableArgumentsActivity { + void execute(int arg); + } + public static class TestNonSerializableArgumentsInActivityWorkflow implements TestWorkflows.TestWorkflow1 { @@ -86,7 +94,7 @@ public String execute(String taskQueue) { } public class NonDeserializableExceptionActivityImpl - implements WorkflowTest.NonDeserializableArgumentsActivity { + implements NonDeserializableArgumentsActivity { @Override public void execute(int arg) {} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/NonSerializableExceptionInActivityWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/NonSerializableExceptionInActivityWorkflowTest.java similarity index 75% rename from temporal-sdk/src/test/java/io/temporal/workflow/NonSerializableExceptionInActivityWorkflowTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/NonSerializableExceptionInActivityWorkflowTest.java index 3261344727..510116e607 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/NonSerializableExceptionInActivityWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/NonSerializableExceptionInActivityWorkflowTest.java @@ -17,10 +17,13 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; +import io.temporal.activity.ActivityInterface; import io.temporal.activity.ActivityOptions; import io.temporal.failure.ActivityFailure; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowTest; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestWorkflows; import java.time.Duration; @@ -30,8 +33,8 @@ public class NonSerializableExceptionInActivityWorkflowTest { - private final WorkflowTest.NonSerializableExceptionActivityImpl activitiesImpl = - new WorkflowTest.NonSerializableExceptionActivityImpl(); + private final NonSerializableExceptionActivityImpl activitiesImpl = + new NonSerializableExceptionActivityImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = @@ -49,14 +52,28 @@ public void testNonSerializableExceptionInActivity() { Assert.assertTrue(result.contains("NonSerializableException")); } + @ActivityInterface + public interface NonSerializableExceptionActivity { + void execute(); + } + + public static class NonSerializableExceptionActivityImpl + implements NonSerializableExceptionActivity { + + @Override + public void execute() { + throw new WorkflowTest.NonSerializableException(); + } + } + public static class TestNonSerializableExceptionInActivityWorkflow implements TestWorkflows.TestWorkflow1 { @Override public String execute(String taskQueue) { - WorkflowTest.NonSerializableExceptionActivity activity = + NonSerializableExceptionActivity activity = Workflow.newActivityStub( - WorkflowTest.NonSerializableExceptionActivity.class, + NonSerializableExceptionActivity.class, ActivityOptions.newBuilder() .setScheduleToCloseTimeout(Duration.ofSeconds(5)) .build()); diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ParallelLocalActivitiesTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ParallelLocalActivitiesTest.java similarity index 89% rename from temporal-sdk/src/test/java/io/temporal/workflow/ParallelLocalActivitiesTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ParallelLocalActivitiesTest.java index be79b7544a..740612a698 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ParallelLocalActivitiesTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ParallelLocalActivitiesTest.java @@ -17,10 +17,13 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; -import io.temporal.client.*; +import io.temporal.client.WorkflowOptions; import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.workflow.Async; +import io.temporal.workflow.Promise; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestOptions; @@ -36,7 +39,7 @@ public class ParallelLocalActivitiesTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = @@ -66,11 +69,11 @@ public void testParallelLocalActivities() { List expected = new ArrayList(); expected.add("interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP); expected.add("newThread workflow-method"); - for (int i = 0; i < WorkflowTest.TestParallelLocalActivitiesWorkflowImpl.COUNT; i++) { + for (int i = 0; i < TestParallelLocalActivitiesWorkflowImpl.COUNT; i++) { expected.add("executeLocalActivity SleepActivity"); expected.add("currentTimeMillis"); } - for (int i = 0; i < WorkflowTest.TestParallelLocalActivitiesWorkflowImpl.COUNT; i++) { + for (int i = 0; i < TestParallelLocalActivitiesWorkflowImpl.COUNT; i++) { expected.add("local activity SleepActivity"); } testWorkflowRule diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ParallelLocalActivityExecutionWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ParallelLocalActivityExecutionWorkflowTest.java new file mode 100644 index 0000000000..ecd81907d8 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/ParallelLocalActivityExecutionWorkflowTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.activityTests; + +import io.temporal.client.WorkflowOptions; +import io.temporal.workflow.Async; +import io.temporal.workflow.Promise; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class ParallelLocalActivityExecutionWorkflowTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestParallelLocalActivityExecutionWorkflowImpl.class) + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) + .build(); + + @Test + public void testParallelLocalActivityExecutionWorkflow() { + WorkflowOptions options = + WorkflowOptions.newBuilder() + .setWorkflowRunTimeout(Duration.ofMinutes(5)) + .setWorkflowTaskTimeout(Duration.ofSeconds(5)) + .setTaskQueue(testWorkflowRule.getTaskQueue()) + .build(); + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub(TestWorkflows.TestWorkflow1.class, options); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.assertEquals( + "sleepActivity1sleepActivity2sleepActivity3sleepActivity4sleepActivity21sleepActivity21sleepActivity21", + result); + } + + public static class TestParallelLocalActivityExecutionWorkflowImpl + implements TestWorkflows.TestWorkflow1 { + @Override + public String execute(String taskQueue) { + TestActivities localActivities = + Workflow.newLocalActivityStub( + TestActivities.class, TestOptions.newLocalActivityOptions()); + List> results = new ArrayList<>(4); + for (int i = 1; i <= 4; i++) { + results.add(Async.function(localActivities::sleepActivity, (long) 1000 * i, i)); + } + + Promise result2 = + Async.function( + () -> { + String result = ""; + for (int i = 0; i < 3; i++) { + result += localActivities.sleepActivity(1000, 21); + } + return result; + }); + + return results.get(0).get() + + results.get(1).get() + + results.get(2).get() + + results.get(3).get() + + result2.get(); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/TryCancelActivityTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/TryCancelActivityTest.java similarity index 96% rename from temporal-sdk/src/test/java/io/temporal/workflow/TryCancelActivityTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/TryCancelActivityTest.java index 6a31dcef64..907421d5f6 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/TryCancelActivityTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/TryCancelActivityTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.ActivityCancellationType; import io.temporal.activity.ActivityOptions; @@ -25,6 +25,7 @@ import io.temporal.client.WorkflowFailedException; import io.temporal.client.WorkflowStub; import io.temporal.failure.CanceledFailure; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestOptions; @@ -37,7 +38,7 @@ public class TryCancelActivityTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/UntypedActivityRetryTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/UntypedActivityRetryTest.java similarity index 95% rename from temporal-sdk/src/test/java/io/temporal/workflow/UntypedActivityRetryTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/activityTests/UntypedActivityRetryTest.java index f3b21efc02..ab6bfb8e29 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/UntypedActivityRetryTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/UntypedActivityRetryTest.java @@ -17,13 +17,15 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.activityTests; import io.temporal.activity.ActivityOptions; import io.temporal.client.WorkflowException; import io.temporal.common.RetryOptions; import io.temporal.failure.ActivityFailure; import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.ActivityStub; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; @@ -36,7 +38,7 @@ public class UntypedActivityRetryTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ChildAsyncLambdaWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildAsyncLambdaWorkflowTest.java similarity index 93% rename from temporal-sdk/src/test/java/io/temporal/workflow/ChildAsyncLambdaWorkflowTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildAsyncLambdaWorkflowTest.java index 2836210a4d..80d43d3af4 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ChildAsyncLambdaWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildAsyncLambdaWorkflowTest.java @@ -17,14 +17,14 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.workflow.*; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; import java.time.Duration; import org.junit.Assert; @@ -33,14 +33,10 @@ public class ChildAsyncLambdaWorkflowTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes(TestWaitOnSignalWorkflowImpl.class, TestChildAsyncLambdaWorkflow.class) - .setActivityImplementations(activitiesImpl) .build(); /** diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ChildAsyncWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildAsyncWorkflowTest.java similarity index 94% rename from temporal-sdk/src/test/java/io/temporal/workflow/ChildAsyncWorkflowTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildAsyncWorkflowTest.java index 58bd082fa7..dd9ea0a82e 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ChildAsyncWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildAsyncWorkflowTest.java @@ -17,12 +17,14 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; import static org.junit.Assert.assertEquals; +import io.temporal.workflow.Async; +import io.temporal.workflow.ChildWorkflowOptions; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; import io.temporal.workflow.shared.TestWorkflows; import org.junit.Assert; @@ -31,16 +33,12 @@ public class ChildAsyncWorkflowTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes( TestChildAsyncWorkflow.class, TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class) - .setActivityImplementations(activitiesImpl) .build(); @Test @@ -59,7 +57,7 @@ public String execute(String taskQueue) { TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc stubF = Workflow.newChildWorkflowStub( TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc.class, workflowOptions); - assertEquals("func", Async.function(stubF::func).get()); + Assert.assertEquals("func", Async.function(stubF::func).get()); TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1 stubF1 = Workflow.newChildWorkflowStub( TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc1.class, workflowOptions); diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowAsyncRetryTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowAsyncRetryTest.java similarity index 95% rename from temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowAsyncRetryTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowAsyncRetryTest.java index d194d4a5aa..4e7c9a55f7 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowAsyncRetryTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowAsyncRetryTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; import static org.junit.Assert.*; @@ -27,6 +27,10 @@ import io.temporal.failure.ApplicationFailure; import io.temporal.failure.ChildWorkflowFailure; import io.temporal.testing.WorkflowReplayer; +import io.temporal.workflow.Async; +import io.temporal.workflow.ChildWorkflowOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowTest; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowCancellationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowCancellationTest.java similarity index 71% rename from temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowCancellationTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowCancellationTest.java index 92c0f261cc..21538e0553 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowCancellationTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowCancellationTest.java @@ -17,16 +17,19 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.api.enums.v1.EventType; +import io.temporal.api.history.v1.History; import io.temporal.api.history.v1.HistoryEvent; -import io.temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryRequest; -import io.temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryResponse; import io.temporal.client.WorkflowFailedException; import io.temporal.client.WorkflowStub; import io.temporal.failure.CanceledFailure; +import io.temporal.workflow.ChildWorkflowCancellationType; +import io.temporal.workflow.ChildWorkflowOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowTest; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import java.time.Duration; @@ -36,7 +39,7 @@ public class ChildWorkflowCancellationTest { private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); + new TestActivities.TestActivitiesImpl(); @Rule public SDKTestWorkflowRule testWorkflowRule = @@ -58,21 +61,11 @@ public void testChildWorkflowWaitCancellationRequested() { } catch (WorkflowFailedException e) { Assert.assertTrue(e.getCause() instanceof CanceledFailure); } - GetWorkflowExecutionHistoryRequest request = - GetWorkflowExecutionHistoryRequest.newBuilder() - .setNamespace(testWorkflowRule.getTestEnvironment().getNamespace()) - .setExecution(execution) - .build(); - GetWorkflowExecutionHistoryResponse response = - testWorkflowRule - .getTestEnvironment() - .getWorkflowService() - .blockingStub() - .getWorkflowExecutionHistory(request); + History history = testWorkflowRule.getWorkflowExecutionHistory(execution); boolean hasChildCanceled = false; boolean hasChildCancelRequested = false; - for (HistoryEvent event : response.getHistory().getEventsList()) { + for (HistoryEvent event : history.getEventsList()) { if (event.getEventType() == EventType.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED) { hasChildCanceled = true; } @@ -98,20 +91,10 @@ public void testChildWorkflowWaitCancellationCompleted() { } catch (WorkflowFailedException e) { Assert.assertTrue(e.getCause() instanceof CanceledFailure); } - GetWorkflowExecutionHistoryRequest request = - GetWorkflowExecutionHistoryRequest.newBuilder() - .setNamespace(testWorkflowRule.getTestEnvironment().getNamespace()) - .setExecution(execution) - .build(); - GetWorkflowExecutionHistoryResponse response = - testWorkflowRule - .getTestEnvironment() - .getWorkflowService() - .blockingStub() - .getWorkflowExecutionHistory(request); + History history = testWorkflowRule.getWorkflowExecutionHistory(execution); boolean hasChildCanceled = false; - for (HistoryEvent event : response.getHistory().getEventsList()) { + for (HistoryEvent event : history.getEventsList()) { if (event.getEventType() == EventType.EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED) { hasChildCanceled = true; } @@ -131,20 +114,10 @@ public void testChildWorkflowCancellationAbandon() { } catch (WorkflowFailedException e) { Assert.assertTrue(e.getCause() instanceof CanceledFailure); } - GetWorkflowExecutionHistoryRequest request = - GetWorkflowExecutionHistoryRequest.newBuilder() - .setNamespace(testWorkflowRule.getTestEnvironment().getNamespace()) - .setExecution(execution) - .build(); - GetWorkflowExecutionHistoryResponse response = - testWorkflowRule - .getTestEnvironment() - .getWorkflowService() - .blockingStub() - .getWorkflowExecutionHistory(request); + History history = testWorkflowRule.getWorkflowExecutionHistory(execution); boolean hasChildCancelInitiated = false; - for (HistoryEvent event : response.getHistory().getEventsList()) { + for (HistoryEvent event : history.getEventsList()) { if (event.getEventType() == EventType.EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED) { hasChildCancelInitiated = true; @@ -165,21 +138,11 @@ public void testChildWorkflowCancellationTryCancel() { } catch (WorkflowFailedException e) { Assert.assertTrue(e.getCause() instanceof CanceledFailure); } - GetWorkflowExecutionHistoryRequest request = - GetWorkflowExecutionHistoryRequest.newBuilder() - .setNamespace(testWorkflowRule.getTestEnvironment().getNamespace()) - .setExecution(execution) - .build(); - GetWorkflowExecutionHistoryResponse response = - testWorkflowRule - .getTestEnvironment() - .getWorkflowService() - .blockingStub() - .getWorkflowExecutionHistory(request); + History history = testWorkflowRule.getWorkflowExecutionHistory(execution); boolean hasChildCancelInitiated = false; boolean hasChildCancelRequested = false; - for (HistoryEvent event : response.getHistory().getEventsList()) { + for (HistoryEvent event : history.getEventsList()) { if (event.getEventType() == EventType.EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED) { hasChildCancelInitiated = true; diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowExecutionPromiseHandlerTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowExecutionPromiseHandlerTest.java similarity index 92% rename from temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowExecutionPromiseHandlerTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowExecutionPromiseHandlerTest.java index 3f45ed6d36..b2820af6d1 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowExecutionPromiseHandlerTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowExecutionPromiseHandlerTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; import static org.junit.Assert.assertEquals; @@ -25,7 +25,7 @@ import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.testing.TestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.*; import io.temporal.workflow.shared.TestWorkflows; import java.time.Duration; import org.junit.Rule; @@ -33,14 +33,10 @@ public class ChildWorkflowExecutionPromiseHandlerTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - @Rule public TestWorkflowRule testWorkflowRule = TestWorkflowRule.newBuilder() .setWorkflowTypes(TestNamedChild.class, TestChildWorkflowExecutionPromiseHandler.class) - .setActivityImplementations(activitiesImpl) .build(); /** Tests that handler of the WorkflowExecution promise is executed in a workflow thread. */ diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowRetryTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowRetryTest.java similarity index 97% rename from temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowRetryTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowRetryTest.java index 7d729bd4b6..42f3be7e78 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowRetryTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowRetryTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; import static io.temporal.workflow.shared.SDKTestWorkflowRule.NAMESPACE; import static io.temporal.workflow.shared.SDKTestWorkflowRule.regenerateHistoryForReplay; @@ -36,6 +36,9 @@ import io.temporal.failure.ChildWorkflowFailure; import io.temporal.testing.WorkflowReplayer; import io.temporal.worker.WorkflowImplementationOptions; +import io.temporal.workflow.ChildWorkflowOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowTest; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowTest.java similarity index 91% rename from temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowTest.java index a90cd811e5..68362d3e95 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowTest.java @@ -17,12 +17,12 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; import static org.junit.Assert.assertEquals; +import io.temporal.workflow.*; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; import java.util.UUID; import org.junit.Rule; @@ -31,15 +31,12 @@ public class ChildWorkflowTest { private static String child2Id; - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes( TestParentWorkflow.class, TestNamedChild.class, WorkflowTest.TestChild.class) - .setActivityImplementations(activitiesImpl) .build(); @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowTimeoutTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowTimeoutTest.java similarity index 90% rename from temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowTimeoutTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowTimeoutTest.java index 0e73c10df4..78cbd4fea0 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowTimeoutTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowTimeoutTest.java @@ -17,13 +17,15 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; import static org.junit.Assert.assertTrue; import com.google.common.base.Throwables; +import io.temporal.workflow.ChildWorkflowOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowTest; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; import java.time.Duration; import org.junit.Rule; @@ -31,14 +33,10 @@ public class ChildWorkflowTimeoutTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes(TestParentWorkflowWithChildTimeout.class, WorkflowTest.TestChild.class) - .setActivityImplementations(activitiesImpl) .build(); @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowWithCronScheduleTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowWithCronScheduleTest.java similarity index 91% rename from temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowWithCronScheduleTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowWithCronScheduleTest.java index 6bee4c05a3..ee065e786a 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ChildWorkflowWithCronScheduleTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowWithCronScheduleTest.java @@ -17,18 +17,18 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; import static io.temporal.workflow.WorkflowTest.lastCompletionResult; import static io.temporal.workflow.shared.TestOptions.newWorkflowOptionsWithTimeouts; import static org.junit.Assert.*; -import static org.junit.Assert.assertTrue; import io.temporal.client.WorkflowFailedException; import io.temporal.client.WorkflowStub; import io.temporal.failure.CanceledFailure; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowTest; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; import java.time.Duration; import org.junit.Assume; @@ -38,9 +38,6 @@ public class ChildWorkflowWithCronScheduleTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - @Rule public TestName testName = new TestName(); @Rule @@ -48,7 +45,6 @@ public class ChildWorkflowWithCronScheduleTest { SDKTestWorkflowRule.newBuilder() .setWorkflowTypes( TestCronParentWorkflow.class, WorkflowTest.TestWorkflowWithCronScheduleImpl.class) - .setActivityImplementations(activitiesImpl) .build(); @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/NamedChildTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/NamedChildTest.java similarity index 94% rename from temporal-sdk/src/test/java/io/temporal/workflow/NamedChildTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/NamedChildTest.java index eb65b639b5..4ccef2ee73 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/NamedChildTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/NamedChildTest.java @@ -17,15 +17,15 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; import static org.junit.Assert.*; import io.temporal.api.enums.v1.WorkflowIdReusePolicy; import io.temporal.client.WorkflowFailedException; import io.temporal.failure.ChildWorkflowFailure; +import io.temporal.workflow.*; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import java.util.UUID; import org.junit.Rule; import org.junit.Test; @@ -33,14 +33,11 @@ public class NamedChildTest { private static final String childReexecuteId = UUID.randomUUID().toString(); - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes(TestNamedChild.class, TestChildReexecuteWorkflow.class) - .setActivityImplementations(activitiesImpl) .build(); @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/NonSerializableExceptionInChildWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/NonSerializableExceptionInChildWorkflowTest.java similarity index 81% rename from temporal-sdk/src/test/java/io/temporal/workflow/NonSerializableExceptionInChildWorkflowTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/NonSerializableExceptionInChildWorkflowTest.java index e7fd9848dd..ab012adb0d 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/NonSerializableExceptionInChildWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/NonSerializableExceptionInChildWorkflowTest.java @@ -17,12 +17,15 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; import io.temporal.failure.ChildWorkflowFailure; import io.temporal.worker.WorkflowImplementationOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import io.temporal.workflow.WorkflowTest; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; import org.junit.Assert; import org.junit.Rule; @@ -30,9 +33,6 @@ public class NonSerializableExceptionInChildWorkflowTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() @@ -42,7 +42,6 @@ public class NonSerializableExceptionInChildWorkflowTest { .build(), TestNonSerializableExceptionInChildWorkflow.class, NonSerializableExceptionChildWorkflowImpl.class) - .setActivityImplementations(activitiesImpl) .build(); @Test @@ -53,8 +52,15 @@ public void testNonSerializableExceptionInChildWorkflow() { Assert.assertTrue(result.contains("NonSerializableException")); } + @WorkflowInterface + public interface NonSerializableExceptionChildWorkflow { + + @WorkflowMethod + String execute(String taskQueue); + } + public static class NonSerializableExceptionChildWorkflowImpl - implements WorkflowTest.NonSerializableExceptionChildWorkflow { + implements NonSerializableExceptionChildWorkflow { @Override public String execute(String taskQueue) { @@ -67,8 +73,8 @@ public static class TestNonSerializableExceptionInChildWorkflow @Override public String execute(String taskQueue) { - WorkflowTest.NonSerializableExceptionChildWorkflow child = - Workflow.newChildWorkflowStub(WorkflowTest.NonSerializableExceptionChildWorkflow.class); + NonSerializableExceptionChildWorkflow child = + Workflow.newChildWorkflowStub(NonSerializableExceptionChildWorkflow.class); try { child.execute(taskQueue); } catch (ChildWorkflowFailure e) { diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ParentWorkflowInfoInChildWorkflowsTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ParentWorkflowInfoInChildWorkflowsTest.java new file mode 100644 index 0000000000..4c73189cc0 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ParentWorkflowInfoInChildWorkflowsTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.childWorkflowTests; + +import io.temporal.client.WorkflowOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInfo; +import io.temporal.workflow.WorkflowTest; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; +import io.temporal.workflow.shared.TestOptions; +import java.util.Optional; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class ParentWorkflowInfoInChildWorkflowsTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes( + WorkflowTest.TestMultiargsWorkflowsFuncParent.class, + TestMultiargsWorkflowsFuncChild.class) + .build(); + + @Test + public void testParentWorkflowInfoInChildWorkflows() { + + String workflowId = "testParentWorkflowInfoInChildWorkflows"; + WorkflowOptions workflowOptions = + TestOptions.newWorkflowOptionsWithTimeouts(testWorkflowRule.getTaskQueue()) + .toBuilder() + .setWorkflowId(workflowId) + .build(); + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc parent = + testWorkflowRule + .getWorkflowClient() + .newWorkflowStub( + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc.class, workflowOptions); + + String result = parent.func(); + String expected = String.format("%s - %s", false, workflowId); + Assert.assertEquals(expected, result); + } + + public static class TestMultiargsWorkflowsFuncChild + implements TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsFunc2 { + @Override + public String func2(String s, int i) { + WorkflowInfo wi = Workflow.getInfo(); + Optional parentId = wi.getParentWorkflowId(); + return parentId.get(); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/StartChildWorkflowWithCancellationScopeAndCancelParentTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/StartChildWorkflowWithCancellationScopeAndCancelParentTest.java similarity index 92% rename from temporal-sdk/src/test/java/io/temporal/workflow/StartChildWorkflowWithCancellationScopeAndCancelParentTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/StartChildWorkflowWithCancellationScopeAndCancelParentTest.java index 2f17acc40e..ed89ffd235 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/StartChildWorkflowWithCancellationScopeAndCancelParentTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/StartChildWorkflowWithCancellationScopeAndCancelParentTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -25,8 +25,8 @@ import io.temporal.client.WorkflowFailedException; import io.temporal.client.WorkflowStub; import io.temporal.failure.CanceledFailure; +import io.temporal.workflow.*; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import java.util.ArrayList; import java.util.List; import org.junit.Rule; @@ -34,14 +34,10 @@ public class StartChildWorkflowWithCancellationScopeAndCancelParentTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes(ParentThatStartsChildInCancellationScope.class, SleepyChild.class) - .setActivityImplementations(activitiesImpl) .build(); @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/UntypedChildStubWorkflowAsyncInvokeTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/UntypedChildStubWorkflowAsyncInvokeTest.java similarity index 94% rename from temporal-sdk/src/test/java/io/temporal/workflow/UntypedChildStubWorkflowAsyncInvokeTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/UntypedChildStubWorkflowAsyncInvokeTest.java index 95da7815e5..a23c1a5fc0 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/UntypedChildStubWorkflowAsyncInvokeTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/UntypedChildStubWorkflowAsyncInvokeTest.java @@ -17,10 +17,13 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; +import io.temporal.workflow.Async; +import io.temporal.workflow.ChildWorkflowOptions; +import io.temporal.workflow.ChildWorkflowStub; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; import io.temporal.workflow.shared.TestWorkflows; import org.junit.Assert; @@ -29,16 +32,12 @@ public class UntypedChildStubWorkflowAsyncInvokeTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes( TestUntypedChildStubWorkflowAsyncInvoke.class, TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class) - .setActivityImplementations(activitiesImpl) .build(); @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/UntypedChildStubWorkflowAsyncTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/UntypedChildStubWorkflowAsyncTest.java similarity index 94% rename from temporal-sdk/src/test/java/io/temporal/workflow/UntypedChildStubWorkflowAsyncTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/UntypedChildStubWorkflowAsyncTest.java index d39d9a912d..1b19b708ad 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/UntypedChildStubWorkflowAsyncTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/UntypedChildStubWorkflowAsyncTest.java @@ -17,10 +17,12 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.childWorkflowTests; +import io.temporal.workflow.ChildWorkflowOptions; +import io.temporal.workflow.ChildWorkflowStub; +import io.temporal.workflow.Workflow; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; import io.temporal.workflow.shared.TestWorkflows; import org.junit.Assert; @@ -29,16 +31,12 @@ public class UntypedChildStubWorkflowAsyncTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); - @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes( TestUntypedChildStubWorkflowAsync.class, TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class) - .setActivityImplementations(activitiesImpl) .build(); @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/UntypedChildStubWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/UntypedChildStubWorkflowTest.java new file mode 100644 index 0000000000..9f5b6bf0e1 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/UntypedChildStubWorkflowTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.childWorkflowTests; + +import static org.junit.Assert.assertEquals; + +import io.temporal.workflow.ChildWorkflowOptions; +import io.temporal.workflow.ChildWorkflowStub; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestMultiargdsWorkflowFunctions; +import io.temporal.workflow.shared.TestWorkflows; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class UntypedChildStubWorkflowTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes( + TestUntypedChildStubWorkflow.class, + TestMultiargdsWorkflowFunctions.TestMultiargsWorkflowsImpl.class) + .build(); + + @Test + public void testUntypedChildStubWorkflow() { + TestWorkflows.TestWorkflow1 client = + testWorkflowRule.newWorkflowStub200sTimeoutOptions(TestWorkflows.TestWorkflow1.class); + Assert.assertEquals(null, client.execute(testWorkflowRule.getTaskQueue())); + } + + public static class TestUntypedChildStubWorkflow implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + ChildWorkflowOptions workflowOptions = + ChildWorkflowOptions.newBuilder().setTaskQueue(taskQueue).build(); + ChildWorkflowStub stubF = + Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsFunc", workflowOptions); + assertEquals("func", stubF.execute(String.class)); + // Workflow type overridden through the @WorkflowMethod.name + ChildWorkflowStub stubF1 = Workflow.newUntypedChildWorkflowStub("func1", workflowOptions); + assertEquals("1", stubF1.execute(String.class, "1")); + ChildWorkflowStub stubF2 = + Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsFunc2", workflowOptions); + assertEquals("12", stubF2.execute(String.class, "1", 2)); + ChildWorkflowStub stubF3 = + Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsFunc3", workflowOptions); + assertEquals("123", stubF3.execute(String.class, "1", 2, 3)); + ChildWorkflowStub stubF4 = + Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsFunc4", workflowOptions); + assertEquals("1234", stubF4.execute(String.class, "1", 2, 3, 4)); + ChildWorkflowStub stubF5 = + Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsFunc5", workflowOptions); + assertEquals("12345", stubF5.execute(String.class, "1", 2, 3, 4, 5)); + ChildWorkflowStub stubF6 = + Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsFunc6", workflowOptions); + assertEquals("123456", stubF6.execute(String.class, "1", 2, 3, 4, 5, 6)); + + ChildWorkflowStub stubP = + Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc", workflowOptions); + stubP.execute(Void.class); + ChildWorkflowStub stubP1 = + Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc1", workflowOptions); + stubP1.execute(Void.class, "1"); + ChildWorkflowStub stubP2 = + Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc2", workflowOptions); + stubP2.execute(Void.class, "1", 2); + ChildWorkflowStub stubP3 = + Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc3", workflowOptions); + stubP3.execute(Void.class, "1", 2, 3); + ChildWorkflowStub stubP4 = + Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc4", workflowOptions); + stubP4.execute(Void.class, "1", 2, 3, 4); + ChildWorkflowStub stubP5 = + Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc5", workflowOptions); + stubP5.execute(Void.class, "1", 2, 3, 4, 5); + ChildWorkflowStub stubP6 = + Workflow.newUntypedChildWorkflowStub("TestMultiargsWorkflowsProc6", workflowOptions); + stubP6.execute(Void.class, "1", 2, 3, 4, 5, 6); + return null; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/shared/SDKTestWorkflowRule.java b/temporal-sdk/src/test/java/io/temporal/workflow/shared/SDKTestWorkflowRule.java index aeaaa607cc..004e847f3d 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/shared/SDKTestWorkflowRule.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/shared/SDKTestWorkflowRule.java @@ -26,8 +26,10 @@ import com.google.common.io.CharSink; import com.google.common.io.Files; import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.history.v1.History; import io.temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryRequest; import io.temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryResponse; +import io.temporal.api.workflowservice.v1.WorkflowServiceGrpc; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.client.WorkflowQueryException; @@ -37,6 +39,7 @@ import io.temporal.serviceclient.WorkflowServiceStubs; import io.temporal.testing.TestWorkflowEnvironment; import io.temporal.testing.TestWorkflowRule; +import io.temporal.worker.WorkerFactoryOptions; import io.temporal.worker.WorkerOptions; import io.temporal.worker.WorkflowImplementationOptions; import io.temporal.workflow.Functions; @@ -97,6 +100,11 @@ public Builder setWorkerOptions(WorkerOptions options) { return this; } + public Builder setWorkerFactoryOptions(WorkerFactoryOptions options) { + testWorkflowRuleBuilder.setWorkerFactoryOptions(options); + return this; + } + public Builder setWorkflowClientOptions(WorkflowClientOptions workflowClientOptions) { testWorkflowRuleBuilder.setWorkflowClientOptions(workflowClientOptions); return this; @@ -157,6 +165,10 @@ public Statement apply(Statement base, Description description) { return testWorkflowRule.apply(base, description); } + public WorkflowServiceGrpc.WorkflowServiceBlockingStub blockingStub() { + return testWorkflowRule.blockingStub(); + } + public T getInterceptor(Class type) { return testWorkflowRule.getInterceptor(type); } @@ -165,6 +177,10 @@ public String getTaskQueue() { return testWorkflowRule.getTaskQueue(); } + public History getWorkflowExecutionHistory(WorkflowExecution execution) { + return testWorkflowRule.getWorkflowExecutionHistory(execution); + } + public WorkflowClient getWorkflowClient() { return testWorkflowRule.getWorkflowClient(); } @@ -251,8 +267,7 @@ public static void regenerateHistoryForReplay( } } - // TODO: Refactor testEnvironment to support testing through real service to avoid this - // switches + // TODO: Refactor testEnv to support testing through real service to avoid these switches. public void registerDelayedCallback(Duration delay, Runnable r) { if (useExternalService) { ScheduledFuture result = diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/shared/TestActivities.java b/temporal-sdk/src/test/java/io/temporal/workflow/shared/TestActivities.java index 4471b068bf..5255950de8 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/shared/TestActivities.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/shared/TestActivities.java @@ -101,7 +101,7 @@ class TestActivitiesImpl implements TestActivities { public ActivityCompletionClient completionClient; int lastAttempt; - public TestActivitiesImpl(ActivityCompletionClient completionClient) { + public void setCompletionClient(ActivityCompletionClient completionClient) { this.completionClient = completionClient; } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/shared/TestMultiargdsWorkflowFunctions.java b/temporal-sdk/src/test/java/io/temporal/workflow/shared/TestMultiargdsWorkflowFunctions.java index 669b1bfa68..5c1d53a768 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/shared/TestMultiargdsWorkflowFunctions.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/shared/TestMultiargdsWorkflowFunctions.java @@ -19,9 +19,9 @@ package io.temporal.workflow.shared; +import io.temporal.workflow.QueryMethod; import io.temporal.workflow.WorkflowInterface; import io.temporal.workflow.WorkflowMethod; -import io.temporal.workflow.WorkflowTest; public class TestMultiargdsWorkflowFunctions { @@ -74,50 +74,56 @@ public interface TestMultiargsWorkflowsFunc6 { String func6(String a1, int a2, int a3, int a4, int a5, int a6); } + public interface ProcInvocationQueryable { + + @QueryMethod(name = "getTrace") + String query(); + } + @WorkflowInterface - public interface TestMultiargsWorkflowsProc extends WorkflowTest.ProcInvocationQueryable { + public interface TestMultiargsWorkflowsProc extends ProcInvocationQueryable { @WorkflowMethod void proc(); } @WorkflowInterface - public interface TestMultiargsWorkflowsProc1 extends WorkflowTest.ProcInvocationQueryable { + public interface TestMultiargsWorkflowsProc1 extends ProcInvocationQueryable { @WorkflowMethod void proc1(String input); } @WorkflowInterface - public interface TestMultiargsWorkflowsProc2 extends WorkflowTest.ProcInvocationQueryable { + public interface TestMultiargsWorkflowsProc2 extends ProcInvocationQueryable { @WorkflowMethod void proc2(String a1, int a2); } @WorkflowInterface - public interface TestMultiargsWorkflowsProc3 extends WorkflowTest.ProcInvocationQueryable { + public interface TestMultiargsWorkflowsProc3 extends ProcInvocationQueryable { @WorkflowMethod void proc3(String a1, int a2, int a3); } @WorkflowInterface - public interface TestMultiargsWorkflowsProc4 extends WorkflowTest.ProcInvocationQueryable { + public interface TestMultiargsWorkflowsProc4 extends ProcInvocationQueryable { @WorkflowMethod void proc4(String a1, int a2, int a3, int a4); } @WorkflowInterface - public interface TestMultiargsWorkflowsProc5 extends WorkflowTest.ProcInvocationQueryable { + public interface TestMultiargsWorkflowsProc5 extends ProcInvocationQueryable { @WorkflowMethod void proc5(String a1, int a2, int a3, int a4, int a5); } @WorkflowInterface - public interface TestMultiargsWorkflowsProc6 extends WorkflowTest.ProcInvocationQueryable { + public interface TestMultiargsWorkflowsProc6 extends ProcInvocationQueryable { @WorkflowMethod void proc6(String a1, int a2, int a3, int a4, int a5, int a6); diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/ExceptionInSignalTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/ExceptionInSignalTest.java similarity index 92% rename from temporal-sdk/src/test/java/io/temporal/workflow/ExceptionInSignalTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/signalTests/ExceptionInSignalTest.java index 8489137598..23c63215a0 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/ExceptionInSignalTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/ExceptionInSignalTest.java @@ -17,12 +17,15 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.signalTests; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import io.temporal.client.WorkflowClient; +import io.temporal.workflow.Async; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowTest; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import java.lang.management.ManagementFactory; @@ -34,14 +37,12 @@ import org.junit.Test; public class ExceptionInSignalTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes(TestSignalExceptionWorkflowImpl.class) - .setActivityImplementations(activitiesImpl) + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) .setTestTimeoutSeconds(20) .build(); diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/SignalAndQueryInterfaceTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalAndQueryInterfaceTest.java similarity index 86% rename from temporal-sdk/src/test/java/io/temporal/workflow/SignalAndQueryInterfaceTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalAndQueryInterfaceTest.java index 33de90f1af..a5385e895c 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/SignalAndQueryInterfaceTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalAndQueryInterfaceTest.java @@ -17,27 +17,25 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.signalTests; import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowStub; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; +import io.temporal.workflow.WorkflowTest; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; public class SignalAndQueryInterfaceTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); @Rule public SDKTestWorkflowRule testWorkflowRule = - SDKTestWorkflowRule.newBuilder() - .setWorkflowTypes(SignalQueryWorkflowAImpl.class) - .setActivityImplementations(activitiesImpl) - .build(); + SDKTestWorkflowRule.newBuilder().setWorkflowTypes(SignalQueryWorkflowAImpl.class).build(); @Test public void testSignalAndQueryInterface() { diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/SignalAndQueryListenerTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalAndQueryListenerTest.java similarity index 94% rename from temporal-sdk/src/test/java/io/temporal/workflow/SignalAndQueryListenerTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalAndQueryListenerTest.java index f90630ab75..34045f7c01 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/SignalAndQueryListenerTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalAndQueryListenerTest.java @@ -17,15 +17,15 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.signalTests; import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowQueryException; import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.workflow.*; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestOptions; import java.util.ArrayList; import java.util.List; @@ -34,14 +34,11 @@ import org.junit.Test; public class SignalAndQueryListenerTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes(TestSignalAndQueryListenerWorkflowImpl.class) - .setActivityImplementations(activitiesImpl) .setWorkerInterceptors( new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) .build(); diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/SignalDuringLastWorkflowTaskTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalDuringLastWorkflowTaskTest.java similarity index 93% rename from temporal-sdk/src/test/java/io/temporal/workflow/SignalDuringLastWorkflowTaskTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalDuringLastWorkflowTaskTest.java index 0e824beff1..4521e2f9fe 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/SignalDuringLastWorkflowTaskTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalDuringLastWorkflowTaskTest.java @@ -17,13 +17,13 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.signalTests; import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; +import io.temporal.workflow.WorkflowTest; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestOptions; import java.time.Duration; import java.util.Optional; @@ -41,14 +41,11 @@ public class SignalDuringLastWorkflowTaskTest { private static final AtomicInteger workflowTaskCount = new AtomicInteger(); private static CompletableFuture sendSignal; - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes(TestSignalDuringLastWorkflowTaskWorkflowImpl.class) - .setActivityImplementations(activitiesImpl) .build(); @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/SignalExternalWorkflowFailureTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalExternalWorkflowFailureTest.java similarity index 91% rename from temporal-sdk/src/test/java/io/temporal/workflow/SignalExternalWorkflowFailureTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalExternalWorkflowFailureTest.java index 6a41d864a3..a78e7d684f 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/SignalExternalWorkflowFailureTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalExternalWorkflowFailureTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.signalTests; import static org.junit.Assert.*; @@ -25,22 +25,20 @@ import io.temporal.client.WorkflowFailedException; import io.temporal.client.WorkflowOptions; import io.temporal.failure.ApplicationFailure; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowTest; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; import java.time.Duration; import org.junit.Rule; import org.junit.Test; public class SignalExternalWorkflowFailureTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes(TestSignalExternalWorkflowFailure.class) - .setActivityImplementations(activitiesImpl) .build(); @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/SignalExternalWorkflowImmediateCancellationTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalExternalWorkflowImmediateCancellationTest.java similarity index 92% rename from temporal-sdk/src/test/java/io/temporal/workflow/SignalExternalWorkflowImmediateCancellationTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalExternalWorkflowImmediateCancellationTest.java index 7af55d2339..c42f21fb20 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/SignalExternalWorkflowImmediateCancellationTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalExternalWorkflowImmediateCancellationTest.java @@ -17,14 +17,14 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.signalTests; import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.client.WorkflowFailedException; import io.temporal.client.WorkflowOptions; import io.temporal.failure.CanceledFailure; +import io.temporal.workflow.*; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestWorkflows; import java.time.Duration; import org.junit.Assert; @@ -32,14 +32,11 @@ import org.junit.Test; public class SignalExternalWorkflowImmediateCancellationTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes(TestSignalExternalWorkflowImmediateCancellation.class) - .setActivityImplementations(activitiesImpl) .build(); @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/SignalExternalWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalExternalWorkflowTest.java similarity index 93% rename from temporal-sdk/src/test/java/io/temporal/workflow/SignalExternalWorkflowTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalExternalWorkflowTest.java index 27c6a38a78..0a390ba113 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/SignalExternalWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalExternalWorkflowTest.java @@ -17,28 +17,25 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.signalTests; import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.workflow.*; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import java.time.Duration; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; public class SignalExternalWorkflowTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes(TestSignalExternalWorkflow.class, SignalingChildImpl.class) - .setActivityImplementations(activitiesImpl) .setWorkerInterceptors( new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) .build(); diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/SignalOrderingWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalOrderingWorkflowTest.java similarity index 91% rename from temporal-sdk/src/test/java/io/temporal/workflow/SignalOrderingWorkflowTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalOrderingWorkflowTest.java index bf914e56ee..e885f0073b 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/SignalOrderingWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalOrderingWorkflowTest.java @@ -17,12 +17,16 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.signalTests; import com.google.common.reflect.TypeToken; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowOptions; import io.temporal.client.WorkflowStub; +import io.temporal.workflow.SignalMethod; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowInterface; +import io.temporal.workflow.WorkflowMethod; import io.temporal.workflow.shared.SDKTestWorkflowRule; import io.temporal.workflow.shared.TestActivities; import java.time.Duration; @@ -34,14 +38,12 @@ import org.junit.Test; public class SignalOrderingWorkflowTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes(SignalOrderingWorkflowImpl.class) - .setActivityImplementations(activitiesImpl) + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) .build(); @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/SignalTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalTest.java similarity index 97% rename from temporal-sdk/src/test/java/io/temporal/workflow/SignalTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalTest.java index 8b703e35bb..9baa95101e 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/SignalTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/SignalTest.java @@ -17,7 +17,7 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.signalTests; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -27,8 +27,10 @@ import io.temporal.api.enums.v1.WorkflowExecutionStatus; import io.temporal.api.enums.v1.WorkflowIdReusePolicy; import io.temporal.client.*; +import io.temporal.workflow.CompletablePromise; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowTest; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import io.temporal.workflow.shared.TestOptions; import java.time.Duration; import java.util.ArrayList; @@ -44,14 +46,11 @@ public class SignalTest { private static final Logger log = LoggerFactory.getLogger(SignalTest.class); - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes(TestSignalWorkflowImpl.class) - .setActivityImplementations(activitiesImpl) .setTestTimeoutSeconds(15) .build(); diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/UntypedSignalExternalWorkflowTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/UntypedSignalExternalWorkflowTest.java similarity index 91% rename from temporal-sdk/src/test/java/io/temporal/workflow/UntypedSignalExternalWorkflowTest.java rename to temporal-sdk/src/test/java/io/temporal/workflow/signalTests/UntypedSignalExternalWorkflowTest.java index ce20b7111e..f389d8c12b 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/UntypedSignalExternalWorkflowTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/signalTests/UntypedSignalExternalWorkflowTest.java @@ -17,26 +17,23 @@ * permissions and limitations under the License. */ -package io.temporal.workflow; +package io.temporal.workflow.signalTests; import io.temporal.client.WorkflowOptions; +import io.temporal.workflow.*; import io.temporal.workflow.shared.SDKTestWorkflowRule; -import io.temporal.workflow.shared.TestActivities; import java.time.Duration; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; public class UntypedSignalExternalWorkflowTest { - private final TestActivities.TestActivitiesImpl activitiesImpl = - new TestActivities.TestActivitiesImpl(null); @Rule public SDKTestWorkflowRule testWorkflowRule = SDKTestWorkflowRule.newBuilder() .setWorkflowTypes( TestUntypedSignalExternalWorkflow.class, UntypedSignalingChildImpl.class) - .setActivityImplementations(activitiesImpl) .build(); @Test diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionAddNewBeforeTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionAddNewBeforeTest.java new file mode 100644 index 0000000000..0dd5cd4479 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionAddNewBeforeTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.versionTests; + +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assume; +import org.junit.Rule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GetVersionAddNewBeforeTest { + + private static final Logger log = LoggerFactory.getLogger(GetVersionAddNewBeforeTest.class); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestGetVersionWorkflowAddNewBefore.class) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .build(); + + @Test + public void testGetVersionAddNewBefore() { + Assume.assumeFalse("skipping for docker tests", SDKTestWorkflowRule.useExternalService); + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + workflowStub.execute(testWorkflowRule.getTaskQueue()); + } + + public static class TestGetVersionWorkflowAddNewBefore implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + log.info("TestGetVersionWorkflow3Impl this=" + this.hashCode()); + // Test adding a version check in replay code. + if (!Workflow.isReplaying()) { + // The first version of the code + int changeFoo = Workflow.getVersion("changeFoo", Workflow.DEFAULT_VERSION, 1); + if (changeFoo != 1) { + throw new IllegalStateException("Unexpected version: " + 1); + } + } else { + // The updated code + int changeBar = Workflow.getVersion("changeBar", Workflow.DEFAULT_VERSION, 1); + if (changeBar != Workflow.DEFAULT_VERSION) { + throw new IllegalStateException("Unexpected version: " + changeBar); + } + int changeFoo = Workflow.getVersion("changeFoo", Workflow.DEFAULT_VERSION, 1); + if (changeFoo != 1) { + throw new IllegalStateException("Unexpected version: " + changeFoo); + } + } + Workflow.sleep(1000); // forces new workflow task + return "test"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionRemovedBeforeTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionRemovedBeforeTest.java new file mode 100644 index 0000000000..0ae54b2073 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionRemovedBeforeTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.versionTests; + +import static org.junit.Assert.assertEquals; + +import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class GetVersionRemovedBeforeTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestGetVersionRemovedBefore.class) + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .setWorkerInterceptors( + new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) + .build(); + + @Test + public void testGetVersionRemovedBefore() { + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.assertEquals("activity", result); + testWorkflowRule + .getInterceptor(TracingWorkerInterceptor.class) + .setExpected( + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "getVersion", + "getVersion", + "getVersion", + "getVersion", + "executeActivity Activity", + "activity Activity"); + } + + // The following test covers the scenario where getVersion call is removed before another + // version-marker command. + public static class TestGetVersionRemovedBefore implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + TestActivities testActivities = + Workflow.newActivityStub( + TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); + // Test removing a version check in replay code. + if (!Workflow.isReplaying()) { + Workflow.getVersion("test_change1", Workflow.DEFAULT_VERSION, 11); + Workflow.getVersion("test_change2", Workflow.DEFAULT_VERSION, 12); + Workflow.getVersion("test_change3", Workflow.DEFAULT_VERSION, 13); + Workflow.getVersion("test_change4", Workflow.DEFAULT_VERSION, 14); + } else { + int version = Workflow.getVersion("test_change3", Workflow.DEFAULT_VERSION, 22); + assertEquals(13, version); + } + return testActivities.activity(); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionRemovedInReplayTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionRemovedInReplayTest.java new file mode 100644 index 0000000000..203f94f1cf --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionRemovedInReplayTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.versionTests; + +import static org.junit.Assert.assertEquals; + +import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class GetVersionRemovedInReplayTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestGetVersionRemovedInReplay.class) + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .setWorkerInterceptors( + new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) + .build(); + + @Test + public void testGetVersionRemovedInReplay() { + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.assertEquals("activity22activity", result); + testWorkflowRule + .getInterceptor(TracingWorkerInterceptor.class) + .setExpected( + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "getVersion", + "executeActivity Activity2", + "activity Activity2", + "executeActivity Activity", + "activity Activity"); + } + + // The following test covers the scenario where getVersion call is removed before a + // non-version-marker command. + public static class TestGetVersionRemovedInReplay implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + TestActivities testActivities = + Workflow.newActivityStub( + TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); + String result; + // Test removing a version check in replay code. + if (!Workflow.isReplaying()) { + int version = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 13); + assertEquals(13, version); + result = testActivities.activity2("activity2", 2); + } else { + result = testActivities.activity2("activity2", 2); + } + result += testActivities.activity(); + return result; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionSameIdOnReplayTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionSameIdOnReplayTest.java new file mode 100644 index 0000000000..941e4f3a51 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionSameIdOnReplayTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.versionTests; + +import static org.junit.Assert.assertEquals; + +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.enums.v1.EventType; +import io.temporal.api.history.v1.History; +import io.temporal.api.history.v1.HistoryEvent; +import io.temporal.client.WorkflowStub; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Rule; +import org.junit.Test; + +public class GetVersionSameIdOnReplayTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestGetVersionSameIdOnReplay.class) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .build(); + + @Test + public void testGetVersionSameIdOnReplay() { + Assume.assumeFalse("skipping for docker tests", SDKTestWorkflowRule.useExternalService); + + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + workflowStub.execute(testWorkflowRule.getTaskQueue()); + WorkflowExecution execution = WorkflowStub.fromTyped(workflowStub).getExecution(); + History history = testWorkflowRule.getWorkflowExecutionHistory(execution); + + // Validate that no marker is recorded + for (HistoryEvent event : history.getEventsList()) { + Assert.assertFalse(EventType.EVENT_TYPE_MARKER_RECORDED == event.getEventType()); + } + } + + public static class TestGetVersionSameIdOnReplay implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + // Test adding a version check in replay code. + if (!Workflow.isReplaying()) { + Workflow.sleep(Duration.ofMinutes(1)); + } else { + int version2 = Workflow.getVersion("test_change_2", Workflow.DEFAULT_VERSION, 11); + Workflow.sleep(Duration.ofMinutes(1)); + int version3 = Workflow.getVersion("test_change_2", Workflow.DEFAULT_VERSION, 11); + + assertEquals(Workflow.DEFAULT_VERSION, version3); + assertEquals(version2, version3); + } + + return "test"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionSameIdTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionSameIdTest.java new file mode 100644 index 0000000000..4d53b949d3 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionSameIdTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.versionTests; + +import static org.junit.Assert.assertEquals; + +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assume; +import org.junit.Rule; +import org.junit.Test; + +public class GetVersionSameIdTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestGetVersionSameId.class) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .build(); + + @Test + public void testGetVersionSameId() { + Assume.assumeFalse("skipping for docker tests", SDKTestWorkflowRule.useExternalService); + + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + workflowStub.execute(testWorkflowRule.getTaskQueue()); + } + + public static class TestGetVersionSameId implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + // Test adding a version check in replay code. + if (!Workflow.isReplaying()) { + int version2 = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 11); + Workflow.sleep(Duration.ofMinutes(1)); + } else { + int version2 = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 11); + Workflow.sleep(Duration.ofMinutes(1)); + int version3 = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 11); + + assertEquals(11, version3); + assertEquals(version2, version3); + } + + return "test"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionTest.java new file mode 100644 index 0000000000..842fc58d77 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.versionTests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class GetVersionTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestGetVersionWorkflowImpl.class) + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .setWorkerInterceptors( + new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) + .build(); + + @Test + public void testGetVersion() { + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.assertEquals("activity22activity1activity1activity1", result); + testWorkflowRule + .getInterceptor(TracingWorkerInterceptor.class) + .setExpected( + "interceptExecuteWorkflow " + SDKTestWorkflowRule.UUID_REGEXP, + "newThread workflow-method", + "getVersion", + "executeActivity Activity2", + "activity Activity2", + "getVersion", + "executeActivity customActivity1", + "activity customActivity1", + "executeActivity customActivity1", + "activity customActivity1", + "sleep PT1S", + "getVersion", + "executeActivity customActivity1", + "activity customActivity1"); + } + + public static class TestGetVersionWorkflowImpl implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + TestActivities testActivities = + Workflow.newActivityStub( + TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); + + // Test adding a version check in non-replay code. + int version = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 1); + assertEquals(version, 1); + String result = testActivities.activity2("activity2", 2); + + // Test version change in non-replay code. + version = Workflow.getVersion("test_change", 1, 2); + assertEquals(version, 1); + result += "activity" + testActivities.activity1(1); + + boolean replaying = false; + // Test adding a version check in replay code. + if (!Workflow.isReplaying()) { + result += "activity" + testActivities.activity1(1); // This is executed in non-replay mode. + } else { + replaying = true; + int version2 = Workflow.getVersion("test_change_2", Workflow.DEFAULT_VERSION, 1); + assertEquals(version2, Workflow.DEFAULT_VERSION); + result += "activity" + testActivities.activity1(1); + } + + // Test get version in replay mode. + Workflow.sleep(1000); + version = Workflow.getVersion("test_change", 1, 2); + assertEquals(version, 1); + result += "activity" + testActivities.activity1(1); + assertTrue(replaying); + return result; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionWithoutCommandEventTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionWithoutCommandEventTest.java new file mode 100644 index 0000000000..2ca1844d80 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionWithoutCommandEventTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.versionTests; + +import io.temporal.client.WorkflowClient; +import io.temporal.client.WorkflowStub; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.CompletablePromise; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.WorkflowTest; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import java.time.Duration; +import java.util.concurrent.CompletableFuture; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class GetVersionWithoutCommandEventTest { + + private static CompletableFuture executionStarted = new CompletableFuture<>(); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestGetVersionWithoutCommandEventWorkflowImpl.class) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .build(); + + @Test + public void testGetVersionWithoutCommandEvent() throws Exception { + executionStarted = new CompletableFuture(); + WorkflowTest.TestWorkflowSignaled workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(WorkflowTest.TestWorkflowSignaled.class); + WorkflowClient.start(workflowStub::execute); + executionStarted.get(); + workflowStub.signal1("test signal"); + String result = WorkflowStub.fromTyped(workflowStub).getResult(String.class); + Assert.assertEquals("result 1", result); + } + + public static class TestGetVersionWithoutCommandEventWorkflowImpl + implements WorkflowTest.TestWorkflowSignaled { + + CompletablePromise signalReceived = Workflow.newPromise(); + + @Override + public String execute() { + try { + if (!Workflow.isReplaying()) { + executionStarted.complete(true); + signalReceived.get(); + } else { + // Execute getVersion in replay mode. In this case we have no command event, only a + // signal. + int version = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 1); + if (version == Workflow.DEFAULT_VERSION) { + signalReceived.get(); + return "result 1"; + } else { + return "result 2"; + } + } + Workflow.sleep(1000); + } catch (Exception e) { + throw new RuntimeException("failed to get from signal"); + } + + throw new RuntimeException("unreachable"); + } + + @Override + public void signal1(String arg) { + signalReceived.complete(true); + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionWorkflowRemoveTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionWorkflowRemoveTest.java new file mode 100644 index 0000000000..17e65b43e7 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionWorkflowRemoveTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.versionTests; + +import io.temporal.testing.TracingWorkerInterceptor; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Rule; +import org.junit.Test; + +public class GetVersionWorkflowRemoveTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestGetVersionWorkflowRemove.class) + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .setWorkerInterceptors( + new TracingWorkerInterceptor(new TracingWorkerInterceptor.FilteredTrace())) + .build(); + + @Test + public void testGetVersionWorkflowRemove() { + Assume.assumeFalse("skipping for docker tests", SDKTestWorkflowRule.useExternalService); + + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + Assert.assertEquals("foo10", workflowStub.execute(testWorkflowRule.getTaskQueue())); + } + + public static class TestGetVersionWorkflowRemove implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + TestActivities activities = + Workflow.newActivityStub( + TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); + String result; + // Test adding a version check in replay code. + if (!Workflow.isReplaying()) { + // The first version of the code + int changeFoo = Workflow.getVersion("changeFoo", Workflow.DEFAULT_VERSION, 1); + if (changeFoo != 1) { + throw new IllegalStateException("Unexpected version: " + 1); + } + result = activities.activity2("foo", 10); + } else { + // No getVersionCall + result = activities.activity2("foo", 10); + } + Workflow.sleep(1000); // forces new workflow task + return result; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionWorkflowReplaceCompletelyTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionWorkflowReplaceCompletelyTest.java new file mode 100644 index 0000000000..aeaf873793 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionWorkflowReplaceCompletelyTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.versionTests; + +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assume; +import org.junit.Rule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GetVersionWorkflowReplaceCompletelyTest { + + private static final Logger log = + LoggerFactory.getLogger(GetVersionWorkflowReplaceCompletelyTest.class); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestGetVersionWorkflowReplaceCompletely.class) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .build(); + + @Test + public void testGetVersionWorkflowReplaceCompletely() { + Assume.assumeFalse("skipping for docker tests", SDKTestWorkflowRule.useExternalService); + + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + workflowStub.execute(testWorkflowRule.getTaskQueue()); + } + + public static class TestGetVersionWorkflowReplaceCompletely + implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + log.info("TestGetVersionWorkflow3Impl this=" + this.hashCode()); + // Test adding a version check in replay code. + if (!Workflow.isReplaying()) { + // The first version of the code + Workflow.getVersion("changeFoo0", Workflow.DEFAULT_VERSION, 2); + Workflow.getVersion("changeFoo1", Workflow.DEFAULT_VERSION, 111); + Workflow.getVersion("changeFoo2", Workflow.DEFAULT_VERSION, 101); + } else { + // The updated code + int changeBar = Workflow.getVersion("changeBar", Workflow.DEFAULT_VERSION, 1); + if (changeBar != Workflow.DEFAULT_VERSION) { + throw new IllegalStateException("Unexpected version: " + changeBar); + } + int changeFoo = Workflow.getVersion("changeFoo10", Workflow.DEFAULT_VERSION, 123); + if (changeFoo != Workflow.DEFAULT_VERSION) { + throw new IllegalStateException("Unexpected version: " + changeFoo); + } + } + Workflow.sleep(1000); // forces new workflow task + return "test"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionWorkflowReplaceGetVersionIdTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionWorkflowReplaceGetVersionIdTest.java new file mode 100644 index 0000000000..4fab6e937e --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionWorkflowReplaceGetVersionIdTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.versionTests; + +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assume; +import org.junit.Rule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class GetVersionWorkflowReplaceGetVersionIdTest { + + private static final Logger log = + LoggerFactory.getLogger(GetVersionWorkflowReplaceGetVersionIdTest.class); + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestGetVersionWorkflowReplaceGetVersionId.class) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .build(); + + @Test + public void testGetVersionWorkflowReplaceGetVersionId() { + Assume.assumeFalse("skipping for docker tests", SDKTestWorkflowRule.useExternalService); + + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + workflowStub.execute(testWorkflowRule.getTaskQueue()); + } + + public static class TestGetVersionWorkflowReplaceGetVersionId + implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + log.info("TestGetVersionWorkflow3Impl this=" + this.hashCode()); + // Test adding a version check in replay code. + if (!Workflow.isReplaying()) { + // The first version of the code + int changeFoo1 = Workflow.getVersion("changeFoo0", Workflow.DEFAULT_VERSION, 2); + if (changeFoo1 != 2) { + throw new IllegalStateException("Unexpected version: " + changeFoo1); + } + int changeFoo2 = Workflow.getVersion("changeFoo1", Workflow.DEFAULT_VERSION, 111); + if (changeFoo2 != 111) { + throw new IllegalStateException("Unexpected version: " + changeFoo2); + } + } else { + // The updated code + int changeBar = Workflow.getVersion("changeBar", Workflow.DEFAULT_VERSION, 1); + if (changeBar != Workflow.DEFAULT_VERSION) { + throw new IllegalStateException("Unexpected version: " + changeBar); + } + int changeFoo = Workflow.getVersion("changeFoo1", Workflow.DEFAULT_VERSION, 123); + if (changeFoo != 111) { + throw new IllegalStateException("Unexpected version: " + changeFoo); + } + } + Workflow.sleep(1000); // forces new workflow task + return "test"; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/VersionNotSupportedTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/VersionNotSupportedTest.java new file mode 100644 index 0000000000..6bd9065df4 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/VersionNotSupportedTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2020 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright 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 file except in compliance with the License. A copy of the License is + * located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.workflow.versionTests; + +import io.temporal.client.WorkflowException; +import io.temporal.failure.ApplicationFailure; +import io.temporal.worker.WorkerFactoryOptions; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.SDKTestWorkflowRule; +import io.temporal.workflow.shared.TestActivities; +import io.temporal.workflow.shared.TestOptions; +import io.temporal.workflow.shared.TestWorkflows; +import java.time.Duration; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +public class VersionNotSupportedTest { + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestVersionNotSupportedWorkflowImpl.class) + .setActivityImplementations(new TestActivities.TestActivitiesImpl()) + .setWorkerFactoryOptions( + WorkerFactoryOptions.newBuilder() + .setWorkflowHostLocalTaskQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .build(); + + @Test + public void testVersionNotSupported() { + TestWorkflows.TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflows.TestWorkflow1.class); + + try { + workflowStub.execute(testWorkflowRule.getTaskQueue()); + Assert.fail("unreachable"); + } catch (WorkflowException e) { + Assert.assertEquals( + "message='unsupported change version', type='test', nonRetryable=false", + e.getCause().getMessage()); + } + } + + public static class TestVersionNotSupportedWorkflowImpl implements TestWorkflows.TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + TestActivities testActivities = + Workflow.newActivityStub( + TestActivities.class, TestOptions.newActivityOptionsForTaskQueue(taskQueue)); + + // Test adding a version check in non-replay code. + int version = Workflow.getVersion("test_change", Workflow.DEFAULT_VERSION, 1); + String result = ""; + if (version == Workflow.DEFAULT_VERSION) { + result += "activity" + testActivities.activity1(1); + } else { + result += testActivities.activity2("activity2", 2); // This is executed. + } + + // Catching error from getVersion is only for unit test purpose. + // Do not ever do it in production code. + try { + Workflow.getVersion("test_change", 2, 3); + } catch (Error e) { + throw Workflow.wrap(ApplicationFailure.newFailure("unsupported change version", "test")); + } + return result; + } + } +} diff --git a/temporal-testing-junit4/src/main/java/io/temporal/testing/TestWorkflowRule.java b/temporal-testing-junit4/src/main/java/io/temporal/testing/TestWorkflowRule.java index d275d9dd66..afce0b82a7 100644 --- a/temporal-testing-junit4/src/main/java/io/temporal/testing/TestWorkflowRule.java +++ b/temporal-testing-junit4/src/main/java/io/temporal/testing/TestWorkflowRule.java @@ -19,6 +19,10 @@ package io.temporal.testing; +import io.temporal.api.common.v1.WorkflowExecution; +import io.temporal.api.history.v1.History; +import io.temporal.api.workflowservice.v1.GetWorkflowExecutionHistoryRequest; +import io.temporal.api.workflowservice.v1.WorkflowServiceGrpc; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowClientOptions; import io.temporal.common.interceptors.WorkerInterceptor; @@ -69,6 +73,8 @@ public class TestWorkflowRule implements TestRule { private final WorkerInterceptor[] interceptors; private final WorkflowImplementationOptions workflowImplementationOptions; private final WorkerOptions workerOptions; + private final WorkerFactoryOptions workerFactoryOptions; + private final String namespace; private final TestWorkflowEnvironment testEnvironment; private final TestWatcher watchman = new TestWatcher() { @@ -82,11 +88,10 @@ protected void failed(Throwable e, Description description) { private TestWorkflowRule(Builder builder) { - String namespace = (builder.namespace == null) ? "UnitTest" : builder.namespace; - doNotStart = builder.doNotStart; interceptors = builder.workerInterceptors; useExternalService = builder.useExternalService; + namespace = (builder.namespace == null) ? "UnitTest" : builder.namespace; workflowTypes = (builder.workflowTypes == null) ? new Class[0] : builder.workflowTypes; activityImplementations = (builder.activityImplementations == null) ? new Object[0] : builder.activityImplementations; @@ -94,6 +99,10 @@ private TestWorkflowRule(Builder builder) { (builder.workerOptions == null) ? WorkerOptions.newBuilder().build() : builder.workerOptions; + workerFactoryOptions = + (builder.workerFactoryOptions == null) + ? WorkerFactoryOptions.newBuilder().setWorkerInterceptors(interceptors).build() + : builder.workerFactoryOptions.toBuilder().setWorkerInterceptors(interceptors).build(); workflowImplementationOptions = (builder.workflowImplementationOptions == null) ? WorkflowImplementationOptions.newBuilder().build() @@ -107,13 +116,11 @@ private TestWorkflowRule(Builder builder) { WorkflowClientOptions clientOptions = (builder.workflowClientOptions == null) ? WorkflowClientOptions.newBuilder().setNamespace(namespace).build() - : builder.workflowClientOptions; - WorkerFactoryOptions factoryOptions = - WorkerFactoryOptions.newBuilder().setWorkerInterceptors(interceptors).build(); + : builder.workflowClientOptions.toBuilder().setNamespace(namespace).build(); TestEnvironmentOptions testOptions = TestEnvironmentOptions.newBuilder() .setWorkflowClientOptions(clientOptions) - .setWorkerFactoryOptions(factoryOptions) + .setWorkerFactoryOptions(workerFactoryOptions) .setUseExternalService(useExternalService) .setTarget(builder.target) .build(); @@ -129,6 +136,7 @@ public static class Builder { private WorkflowImplementationOptions workflowImplementationOptions; private WorkerOptions workerOptions; + private WorkerFactoryOptions workerFactoryOptions; private WorkflowClientOptions workflowClientOptions; private String namespace; private Class[] workflowTypes; @@ -146,6 +154,10 @@ public Builder setWorkerOptions(WorkerOptions options) { return this; } + public void setWorkerFactoryOptions(WorkerFactoryOptions options) { + this.workerFactoryOptions = options; + } + /** * Override {@link WorkflowClientOptions} for test environment. If set, takes precedence over * {@link #setNamespace(String) namespace}. @@ -266,6 +278,11 @@ protected void shutdown() throws Throwable { } } + /** Returns blockingStub */ + public WorkflowServiceGrpc.WorkflowServiceBlockingStub blockingStub() { + return testEnvironment.getWorkflowService().blockingStub(); + } + /** Returns tracer. */ public T getInterceptor(Class type) { if (interceptors != null) { @@ -283,6 +300,20 @@ public String getTaskQueue() { return taskQueue; } + /** + * Returns name of the task queue that test worker is polling. + * + * @return + */ + public History getWorkflowExecutionHistory(WorkflowExecution execution) { + GetWorkflowExecutionHistoryRequest request = + GetWorkflowExecutionHistoryRequest.newBuilder() + .setNamespace(namespace) + .setExecution(execution) + .build(); + return this.blockingStub().getWorkflowExecutionHistory(request).getHistory(); + } + /** Returns client to the Temporal service used to start and query workflows. */ public WorkflowClient getWorkflowClient() { return testEnvironment.getWorkflowClient();