Skip to content

Commit 9429e47

Browse files
committed
ActivityClientCallsInterceptorChainTest: confirm ordering for 2 interceptors with real ActivityClient.
1 parent fc29246 commit 9429e47

1 file changed

Lines changed: 54 additions & 131 deletions

File tree

temporal-sdk/src/test/java/io/temporal/common/interceptors/ActivityClientCallsInterceptorChainTest.java

Lines changed: 54 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,172 +1,95 @@
11
package io.temporal.common.interceptors;
22

33
import static org.junit.Assert.*;
4-
import static org.mockito.Mockito.*;
4+
import static org.junit.Assume.assumeTrue;
55

6+
import io.temporal.activity.ActivityInterface;
7+
import io.temporal.activity.ActivityMethod;
8+
import io.temporal.client.ActivityClient;
9+
import io.temporal.client.ActivityClientOptions;
610
import io.temporal.client.StartActivityOptions;
711
import io.temporal.common.interceptors.ActivityClientCallsInterceptor.*;
12+
import io.temporal.testing.internal.SDKTestWorkflowRule;
813
import java.time.Duration;
914
import java.util.ArrayList;
1015
import java.util.Arrays;
11-
import java.util.Collections;
1216
import java.util.List;
17+
import java.util.UUID;
18+
import org.junit.Rule;
1319
import org.junit.Test;
1420

15-
/** Tests for the {@link ActivityClientInterceptor} factory pattern and chain-building behavior. */
21+
/**
22+
* Tests for interceptor chain ordering using a real Temporal server. Each test creates an {@link
23+
* ActivityClient} with two interceptors and verifies the call order through a client method.
24+
*/
1625
public class ActivityClientCallsInterceptorChainTest {
1726

18-
private static StartActivityInput minimalInput() {
19-
return new StartActivityInput(
20-
"MyActivity",
21-
Collections.emptyList(),
22-
StartActivityOptions.newBuilder()
23-
.setId("act-id")
24-
.setTaskQueue("tq")
25-
.setStartToCloseTimeout(Duration.ofSeconds(10))
26-
.build(),
27-
Header.empty());
27+
@ActivityInterface
28+
public interface EchoActivity {
29+
@ActivityMethod(name = "ChainTestEcho")
30+
String echo(String input);
2831
}
2932

30-
/**
31-
* Builds a chain from a list of interceptors and a root, replicating ActivityClientImpl logic.
32-
*/
33-
private static ActivityClientCallsInterceptor buildChain(
34-
List<ActivityClientInterceptor> interceptors, ActivityClientCallsInterceptor root) {
35-
ActivityClientCallsInterceptor invoker = root;
36-
for (ActivityClientInterceptor interceptor : interceptors) {
37-
invoker = interceptor.activityClientCallsInterceptor(invoker);
33+
static class EchoActivityImpl implements EchoActivity {
34+
@Override
35+
public String echo(String input) {
36+
return input;
3837
}
39-
return invoker;
4038
}
4139

42-
// ---- Chain ordering ----
40+
@Rule
41+
public SDKTestWorkflowRule testRule =
42+
SDKTestWorkflowRule.newBuilder().setActivityImplementations(new EchoActivityImpl()).build();
4343

4444
@Test
45-
public void testSingleInterceptorExecutesBeforeRoot() {
45+
public void testTwoInterceptorsCalledInOrderOnStart() {
46+
assumeTrue(SDKTestWorkflowRule.useExternalService);
4647
List<String> events = new ArrayList<>();
47-
ActivityClientCallsInterceptor root = mock(ActivityClientCallsInterceptor.class);
48-
when(root.startActivity(any()))
49-
.thenAnswer(
50-
inv -> {
51-
events.add("root");
52-
return new StartActivityOutput("id", null);
53-
});
54-
55-
ActivityClientInterceptor interceptor =
56-
new ActivityClientInterceptorBase() {
57-
@Override
58-
public ActivityClientCallsInterceptor activityClientCallsInterceptor(
59-
ActivityClientCallsInterceptor next) {
60-
return new ActivityClientCallsInterceptorBase(next) {
61-
@Override
62-
public StartActivityOutput startActivity(StartActivityInput input) {
63-
events.add("A");
64-
return super.startActivity(input);
65-
}
66-
};
67-
}
68-
};
6948

70-
ActivityClientCallsInterceptor chain = buildChain(Collections.singletonList(interceptor), root);
71-
chain.startActivity(minimalInput());
49+
ActivityClient client = newClient(startInterceptor("A", events), startInterceptor("B", events));
50+
String result = client.execute(EchoActivity.class, EchoActivity::echo, opts(uniqueId()), "hi");
7251

73-
assertEquals(Arrays.asList("A", "root"), events);
52+
assertEquals("hi", result);
53+
// B is last in the list → B wraps A → B is outermost → B called first
54+
assertEquals(Arrays.asList("B", "A"), events);
7455
}
7556

7657
@Test
77-
public void testTwoInterceptorsLastIsOutermost() {
58+
public void testInterceptorListOrderDeterminesCallOrder() {
59+
assumeTrue(SDKTestWorkflowRule.useExternalService);
7860
List<String> events = new ArrayList<>();
79-
ActivityClientCallsInterceptor root = mock(ActivityClientCallsInterceptor.class);
80-
when(root.startActivity(any()))
81-
.thenAnswer(
82-
inv -> {
83-
events.add("root");
84-
return new StartActivityOutput("id", null);
85-
});
86-
87-
ActivityClientInterceptor first = factoryInterceptor("A", events);
88-
ActivityClientInterceptor second = factoryInterceptor("B", events);
89-
90-
ActivityClientCallsInterceptor chain = buildChain(Arrays.asList(first, second), root);
91-
chain.startActivity(minimalInput());
9261

93-
assertEquals(Arrays.asList("B", "A", "root"), events);
94-
}
62+
// reversed list order: A is last → A wraps B → A is outermost → A called first
63+
ActivityClient client = newClient(startInterceptor("B", events), startInterceptor("A", events));
64+
client.execute(EchoActivity.class, EchoActivity::echo, opts(uniqueId()), "hi");
9565

96-
@Test
97-
public void testThreeInterceptorsLastIsOutermost() {
98-
List<String> events = new ArrayList<>();
99-
ActivityClientCallsInterceptor root = mock(ActivityClientCallsInterceptor.class);
100-
when(root.startActivity(any()))
101-
.thenAnswer(
102-
inv -> {
103-
events.add("root");
104-
return new StartActivityOutput("id", null);
105-
});
106-
107-
ActivityClientCallsInterceptor chain =
108-
buildChain(
109-
Arrays.asList(
110-
factoryInterceptor("A", events),
111-
factoryInterceptor("B", events),
112-
factoryInterceptor("C", events)),
113-
root);
114-
chain.startActivity(minimalInput());
115-
116-
assertEquals(Arrays.asList("C", "B", "A", "root"), events);
66+
assertEquals(Arrays.asList("A", "B"), events);
11767
}
11868

119-
// ---- ActivityClientInterceptorBase defaults ----
120-
121-
@Test
122-
public void testActivityClientInterceptorBaseDefaultPassesThrough() {
123-
// ActivityClientInterceptorBase.activityClientCallsInterceptor returns next unchanged.
124-
ActivityClientCallsInterceptor root = mock(ActivityClientCallsInterceptor.class);
125-
when(root.startActivity(any())).thenReturn(new StartActivityOutput("id", null));
126-
127-
ActivityClientInterceptor passthrough = new ActivityClientInterceptorBase() {};
128-
129-
ActivityClientCallsInterceptor chain = buildChain(Collections.singletonList(passthrough), root);
130-
StartActivityOutput output = chain.startActivity(minimalInput());
69+
// ---- Helpers ----
13170

132-
assertNotNull(output);
133-
verify(root).startActivity(any());
71+
private ActivityClient newClient(ActivityClientInterceptor... interceptors) {
72+
return ActivityClient.newInstance(
73+
testRule.getWorkflowServiceStubs(),
74+
ActivityClientOptions.newBuilder()
75+
.setNamespace(SDKTestWorkflowRule.NAMESPACE)
76+
.setInterceptors(Arrays.asList(interceptors))
77+
.build());
13478
}
13579

136-
@Test
137-
public void testInterceptorBaseCanWrapAndInterceptCalls() {
138-
List<String> events = new ArrayList<>();
139-
ActivityClientCallsInterceptor root = mock(ActivityClientCallsInterceptor.class);
140-
when(root.startActivity(any()))
141-
.thenAnswer(
142-
inv -> {
143-
events.add("root");
144-
return new StartActivityOutput("id", null);
145-
});
146-
147-
ActivityClientInterceptor factory =
148-
new ActivityClientInterceptorBase() {
149-
@Override
150-
public ActivityClientCallsInterceptor activityClientCallsInterceptor(
151-
ActivityClientCallsInterceptor next) {
152-
return new ActivityClientCallsInterceptorBase(next) {
153-
@Override
154-
public StartActivityOutput startActivity(StartActivityInput input) {
155-
events.add("intercepted");
156-
return super.startActivity(input);
157-
}
158-
};
159-
}
160-
};
161-
162-
buildChain(Collections.singletonList(factory), root).startActivity(minimalInput());
163-
164-
assertEquals(Arrays.asList("intercepted", "root"), events);
80+
private String uniqueId() {
81+
return "act-" + UUID.randomUUID();
16582
}
16683

167-
// ---- Helper ----
84+
private StartActivityOptions opts(String id) {
85+
return StartActivityOptions.newBuilder()
86+
.setId(id)
87+
.setTaskQueue(testRule.getTaskQueue())
88+
.setScheduleToCloseTimeout(Duration.ofMinutes(1))
89+
.build();
90+
}
16891

169-
private static ActivityClientInterceptor factoryInterceptor(String name, List<String> events) {
92+
private static ActivityClientInterceptor startInterceptor(String name, List<String> events) {
17093
return new ActivityClientInterceptorBase() {
17194
@Override
17295
public ActivityClientCallsInterceptor activityClientCallsInterceptor(

0 commit comments

Comments
 (0)