Skip to content

Commit 24f225c

Browse files
authored
Java test server support for attaching links to signal and signal with start requests (#2411)
* Java test server support for attaching links to signal and signal with start requests * Java test server support for attaching links to signal and signal with start requests * Java test server support for attaching links to signal and signal with start requests * Java test server support for attaching links to signal and signal with start requests * Java test server support for attaching links to signal and signal with start requests * Java test server support for attaching links to signal and signal with start requests * Java test server support for attaching links to signal and signal with start requests
1 parent f9a9cad commit 24f225c

File tree

3 files changed

+194
-19
lines changed

3 files changed

+194
-19
lines changed

temporal-test-server/src/main/java/io/temporal/internal/testservice/TestWorkflowMutableStateImpl.java

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
package io.temporal.internal.testservice;
2222

23+
import static io.temporal.api.enums.v1.EventType.*;
2324
import static io.temporal.api.enums.v1.UpdateWorkflowExecutionLifecycleStage.*;
2425
import static io.temporal.internal.common.LinkConverter.workflowEventToNexusLink;
2526
import static io.temporal.internal.testservice.CronUtils.getBackoffInterval;
@@ -60,17 +61,6 @@
6061
import io.temporal.internal.common.ProtoEnumNameUtils;
6162
import io.temporal.internal.common.ProtobufTimeUtils;
6263
import io.temporal.internal.common.WorkflowExecutionUtils;
63-
import io.temporal.internal.testservice.StateMachines.Action;
64-
import io.temporal.internal.testservice.StateMachines.ActivityTaskData;
65-
import io.temporal.internal.testservice.StateMachines.CancelExternalData;
66-
import io.temporal.internal.testservice.StateMachines.ChildWorkflowData;
67-
import io.temporal.internal.testservice.StateMachines.NexusOperationData;
68-
import io.temporal.internal.testservice.StateMachines.SignalExternalData;
69-
import io.temporal.internal.testservice.StateMachines.State;
70-
import io.temporal.internal.testservice.StateMachines.TimerData;
71-
import io.temporal.internal.testservice.StateMachines.UpdateWorkflowExecutionData;
72-
import io.temporal.internal.testservice.StateMachines.WorkflowData;
73-
import io.temporal.internal.testservice.StateMachines.WorkflowTaskData;
7464
import io.temporal.serviceclient.StatusUtils;
7565
import java.time.Duration;
7666
import java.util.*;
@@ -310,7 +300,7 @@ private void validateLinks(List<Link> links) {
310300
.withDescription("workflow event link must not have an empty run ID field")
311301
.asRuntimeException();
312302
}
313-
if (l.getWorkflowEvent().getEventRef().getEventType() == EventType.EVENT_TYPE_UNSPECIFIED
303+
if (l.getWorkflowEvent().getEventRef().getEventType() == EVENT_TYPE_UNSPECIFIED
314304
&& l.getWorkflowEvent().getEventRef().getEventId() != 0) {
315305
throw Status.INVALID_ARGUMENT
316306
.withDescription(
@@ -3372,9 +3362,9 @@ private static Optional<HistoryEvent> getStartEvent(List<HistoryEvent> history)
33723362
// This is true today (see StateMachines.startWorkflow), even in the signalWithStartCase (signal
33733363
// is the _second_ event). But if it becomes untrue in the future, we'd rather fail than lie.
33743364
Preconditions.checkState(
3375-
firstEvent.getEventType() == EventType.EVENT_TYPE_WORKFLOW_EXECUTION_STARTED,
3365+
firstEvent.getEventType() == EVENT_TYPE_WORKFLOW_EXECUTION_STARTED,
33763366
"The first event in a workflow's history should be %s, but was %s",
3377-
EventType.EVENT_TYPE_WORKFLOW_EXECUTION_STARTED.name(),
3367+
EVENT_TYPE_WORKFLOW_EXECUTION_STARTED.name(),
33783368
firstEvent.getEventType().name());
33793369

33803370
return Optional.of(firstEvent);
@@ -3399,12 +3389,17 @@ private void addExecutionSignaledEvent(
33993389
.setIdentity(signalRequest.getIdentity())
34003390
.setInput(signalRequest.getInput())
34013391
.setSignalName(signalRequest.getSignalName());
3402-
HistoryEvent executionSignaled =
3392+
3393+
HistoryEvent.Builder event =
34033394
HistoryEvent.newBuilder()
3404-
.setEventType(EventType.EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED)
3405-
.setWorkflowExecutionSignaledEventAttributes(a)
3406-
.build();
3407-
ctx.addEvent(executionSignaled);
3395+
.setEventType(EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED)
3396+
.setWorkflowExecutionSignaledEventAttributes(a);
3397+
3398+
if (signalRequest.getLinksCount() > 0) {
3399+
event.addAllLinks(signalRequest.getLinksList());
3400+
}
3401+
3402+
ctx.addEvent(event.build());
34083403
}
34093404

34103405
private void addExecutionSignaledByExternalEvent(

temporal-test-server/src/main/java/io/temporal/internal/testservice/TestWorkflowService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,7 @@ public void signalWithStartWorkflowExecution(
13251325
.setControl(r.getControl())
13261326
.setNamespace(r.getNamespace())
13271327
.setIdentity(r.getIdentity())
1328+
.addAllLinks(r.getLinksList())
13281329
.build();
13291330
if (mutableState != null && !mutableState.isTerminalState()) {
13301331
mutableState.signal(signalRequest);
@@ -1364,6 +1365,9 @@ public void signalWithStartWorkflowExecution(
13641365
if (r.hasWorkflowStartDelay()) {
13651366
startRequest.setWorkflowStartDelay(r.getWorkflowStartDelay());
13661367
}
1368+
if (!r.getLinksList().isEmpty()) {
1369+
startRequest.addAllLinks(r.getLinksList());
1370+
}
13671371

13681372
StartWorkflowExecutionResponse startResult =
13691373
startWorkflowExecutionImpl(
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/*
2+
* Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved.
3+
*
4+
* Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
5+
*
6+
* Modifications copyright (C) 2017 Uber Technologies, Inc.
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this material except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
package io.temporal.testserver.functional;
22+
23+
import static java.util.UUID.randomUUID;
24+
import static org.junit.Assert.assertEquals;
25+
import static org.junit.Assert.assertTrue;
26+
27+
import io.temporal.api.common.v1.Link;
28+
import io.temporal.api.common.v1.Payloads;
29+
import io.temporal.api.common.v1.WorkflowExecution;
30+
import io.temporal.api.common.v1.WorkflowType;
31+
import io.temporal.api.enums.v1.EventType;
32+
import io.temporal.api.history.v1.HistoryEvent;
33+
import io.temporal.api.history.v1.WorkflowExecutionSignaledEventAttributes;
34+
import io.temporal.api.taskqueue.v1.TaskQueue;
35+
import io.temporal.api.workflowservice.v1.*;
36+
import io.temporal.client.WorkflowStub;
37+
import io.temporal.testing.internal.SDKTestWorkflowRule;
38+
import io.temporal.workflow.WorkflowInterface;
39+
import io.temporal.workflow.WorkflowMethod;
40+
import org.junit.Rule;
41+
import org.junit.Test;
42+
43+
public class SignalLinksTest {
44+
@Rule
45+
public SDKTestWorkflowRule testWorkflowRule =
46+
SDKTestWorkflowRule.newBuilder().setWorkflowTypes(TestWorkflowImpl.class).build();
47+
48+
@Test
49+
public void testSignalWithLinks() {
50+
WorkflowStub stub = testWorkflowRule.newUntypedWorkflowStubTimeoutOptions("TestWorkflow");
51+
WorkflowExecution execution = stub.start();
52+
53+
Link testLink = createTestLink(execution.getRunId());
54+
SignalWorkflowExecutionRequest signalRequest =
55+
SignalWorkflowExecutionRequest.newBuilder()
56+
.setNamespace(testWorkflowRule.getWorkflowClient().getOptions().getNamespace())
57+
.setWorkflowExecution(execution)
58+
.setSignalName("test-signal")
59+
.setInput(Payloads.newBuilder().build())
60+
.addLinks(testLink)
61+
.build();
62+
63+
testWorkflowRule
64+
.getWorkflowServiceStubs()
65+
.blockingStub()
66+
.signalWorkflowExecution(signalRequest);
67+
68+
stub.getResult(Void.class);
69+
70+
verifySignalLink(execution, testLink);
71+
}
72+
73+
@Test
74+
public void testSignalWithStartLinks() {
75+
String workflowId = "test-workflow-id";
76+
Link testLink = createTestLink("some-run-id");
77+
78+
SignalWithStartWorkflowExecutionRequest signalWithStartRequest =
79+
SignalWithStartWorkflowExecutionRequest.newBuilder()
80+
.setTaskQueue(TaskQueue.newBuilder().setName(testWorkflowRule.getTaskQueue()).build())
81+
.setNamespace(testWorkflowRule.getWorkflowClient().getOptions().getNamespace())
82+
.setWorkflowType(WorkflowType.newBuilder().setName("TestWorkflow").build())
83+
.setSignalInput(Payloads.newBuilder().build())
84+
.setRequestId(randomUUID().toString())
85+
.setSignalName("test-signal")
86+
.setWorkflowId(workflowId)
87+
.addLinks(testLink)
88+
.build();
89+
90+
SignalWithStartWorkflowExecutionResponse response =
91+
testWorkflowRule
92+
.getWorkflowServiceStubs()
93+
.blockingStub()
94+
.signalWithStartWorkflowExecution(signalWithStartRequest);
95+
96+
WorkflowExecution execution =
97+
WorkflowExecution.newBuilder()
98+
.setWorkflowId(workflowId)
99+
.setRunId(response.getRunId())
100+
.build();
101+
102+
verifySignalLink(execution, testLink);
103+
verifyStartEventLink(execution, testLink);
104+
}
105+
106+
private Link createTestLink(String runId) {
107+
return Link.newBuilder()
108+
.setWorkflowEvent(
109+
Link.WorkflowEvent.newBuilder()
110+
.setWorkflowId("someWorkflow")
111+
.setNamespace("default")
112+
.setRunId(runId)
113+
.build())
114+
.build();
115+
}
116+
117+
private void verifySignalLink(WorkflowExecution execution, Link expectedLink) {
118+
GetWorkflowExecutionHistoryResponse history = getHistory(execution);
119+
boolean foundSignalWithLink = false;
120+
121+
for (HistoryEvent event : history.getHistory().getEventsList()) {
122+
if (event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED) {
123+
WorkflowExecutionSignaledEventAttributes attrs =
124+
event.getWorkflowExecutionSignaledEventAttributes();
125+
if ("test-signal".equals(attrs.getSignalName())) {
126+
assertEquals(1, event.getLinksCount());
127+
assertEquals(expectedLink, event.getLinks(0));
128+
foundSignalWithLink = true;
129+
break;
130+
}
131+
}
132+
}
133+
134+
assertTrue("Should have found signal event with link", foundSignalWithLink);
135+
}
136+
137+
private void verifyStartEventLink(WorkflowExecution execution, Link expectedLink) {
138+
GetWorkflowExecutionHistoryResponse history = getHistory(execution);
139+
boolean foundStartWithLink = false;
140+
141+
for (HistoryEvent event : history.getHistory().getEventsList()) {
142+
if (event.getEventType() == EventType.EVENT_TYPE_WORKFLOW_EXECUTION_STARTED) {
143+
assertEquals("Link should be present on start event", 1, event.getLinksCount());
144+
assertEquals("Link in start event should match", expectedLink, event.getLinks(0));
145+
foundStartWithLink = true;
146+
break;
147+
}
148+
}
149+
150+
assertTrue("Should have found start event with link", foundStartWithLink);
151+
}
152+
153+
private GetWorkflowExecutionHistoryResponse getHistory(WorkflowExecution execution) {
154+
return testWorkflowRule
155+
.getWorkflowServiceStubs()
156+
.blockingStub()
157+
.getWorkflowExecutionHistory(
158+
GetWorkflowExecutionHistoryRequest.newBuilder()
159+
.setNamespace(testWorkflowRule.getWorkflowClient().getOptions().getNamespace())
160+
.setExecution(execution)
161+
.build());
162+
}
163+
164+
@WorkflowInterface
165+
public interface TestWorkflow {
166+
@WorkflowMethod(name = "TestWorkflow")
167+
void run();
168+
}
169+
170+
public static class TestWorkflowImpl implements TestWorkflow {
171+
@Override
172+
public void run() {
173+
// Empty workflow that completes quickly
174+
}
175+
}
176+
}

0 commit comments

Comments
 (0)