Skip to content

Commit c6ca0e4

Browse files
committed
updated tests
1 parent 66da59b commit c6ca0e4

4 files changed

Lines changed: 113 additions & 56 deletions

File tree

endtoendtests/src/main/java/com/functions/RewindTest.java

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88
import com.microsoft.azure.functions.annotation.FunctionName;
99
import com.microsoft.azure.functions.annotation.HttpTrigger;
1010
import com.microsoft.durabletask.DurableTaskClient;
11+
import com.microsoft.durabletask.OrchestrationMetadata;
1112
import com.microsoft.durabletask.TaskOrchestrationContext;
1213
import com.microsoft.durabletask.azurefunctions.DurableActivityTrigger;
1314
import com.microsoft.durabletask.azurefunctions.DurableClientContext;
1415
import com.microsoft.durabletask.azurefunctions.DurableClientInput;
1516
import com.microsoft.durabletask.azurefunctions.DurableOrchestrationTrigger;
1617

18+
import java.time.Duration;
1719
import java.util.Optional;
20+
import java.util.concurrent.TimeoutException;
1821
import java.util.concurrent.atomic.AtomicBoolean;
1922

2023
/**
@@ -30,7 +33,9 @@ public class RewindTest {
3033
private static final AtomicBoolean shouldSubFail = new AtomicBoolean(true);
3134

3235
/**
33-
* HTTP trigger to start the rewindable orchestration.
36+
* HTTP trigger that starts a rewindable orchestration, waits for it to fail,
37+
* then rewinds it using client.rewindInstance(). Returns the check status response
38+
* so the caller can poll for the orchestration to complete after the rewind.
3439
*/
3540
@FunctionName("StartRewindableOrchestration")
3641
public HttpResponseMessage startRewindableOrchestration(
@@ -45,6 +50,59 @@ public HttpResponseMessage startRewindableOrchestration(
4550
DurableTaskClient client = durableContext.getClient();
4651
String instanceId = client.scheduleNewOrchestrationInstance("RewindableOrchestration");
4752
context.getLogger().info("Created new Java orchestration with instance ID = " + instanceId);
53+
54+
// Wait for the orchestration to reach a terminal state (expected: Failed)
55+
try {
56+
OrchestrationMetadata metadata = client.waitForInstanceCompletion(instanceId, Duration.ofSeconds(30), false);
57+
context.getLogger().info("Orchestration reached terminal state: " + metadata.getRuntimeStatus());
58+
} catch (TimeoutException e) {
59+
context.getLogger().severe("Orchestration did not reach terminal state in time.");
60+
return request.createResponseBuilder(com.microsoft.azure.functions.HttpStatus.INTERNAL_SERVER_ERROR)
61+
.body("Orchestration did not fail within the expected time.")
62+
.build();
63+
}
64+
65+
// Rewind the failed orchestration using the client method
66+
client.rewindInstance(instanceId, "Testing rewind functionality");
67+
context.getLogger().info("Rewind request sent for instance: " + instanceId);
68+
69+
return durableContext.createCheckStatusResponse(request, instanceId);
70+
}
71+
72+
/**
73+
* HTTP trigger that starts a non-failing orchestration, waits for it to complete,
74+
* then attempts to rewind it using client.rewindInstance(). Returns the check status
75+
* response so the caller can verify the orchestration remains in the Completed state.
76+
*/
77+
@FunctionName("StartRewindNonFailedOrchestration")
78+
public HttpResponseMessage startRewindNonFailedOrchestration(
79+
@HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
80+
@DurableClientInput(name = "durableContext") DurableClientContext durableContext,
81+
final ExecutionContext context) {
82+
context.getLogger().info("Starting non-failing orchestration for rewind test.");
83+
84+
// Ensure the activity will NOT fail
85+
shouldFail.set(false);
86+
87+
DurableTaskClient client = durableContext.getClient();
88+
String instanceId = client.scheduleNewOrchestrationInstance("RewindableOrchestration");
89+
context.getLogger().info("Created orchestration with instance ID = " + instanceId);
90+
91+
// Wait for the orchestration to complete successfully
92+
try {
93+
client.waitForInstanceCompletion(instanceId, Duration.ofSeconds(30), false);
94+
context.getLogger().info("Orchestration completed successfully.");
95+
} catch (TimeoutException e) {
96+
context.getLogger().severe("Orchestration did not complete in time.");
97+
return request.createResponseBuilder(com.microsoft.azure.functions.HttpStatus.INTERNAL_SERVER_ERROR)
98+
.body("Orchestration did not complete within the expected time.")
99+
.build();
100+
}
101+
102+
// Attempt to rewind the non-failed orchestration using the client method
103+
client.rewindInstance(instanceId, "Testing rewind on non-failed orchestration");
104+
context.getLogger().info("Rewind request sent for non-failed instance: " + instanceId);
105+
48106
return durableContext.createCheckStatusResponse(request, instanceId);
49107
}
50108

@@ -93,7 +151,9 @@ public HttpResponseMessage resetRewindFailureFlag(
93151
// --- Sub-orchestration rewind test functions ---
94152

95153
/**
96-
* HTTP trigger to start the parent orchestration for sub-orchestration rewind test.
154+
* HTTP trigger that starts a parent orchestration with a failing sub-orchestration,
155+
* waits for it to fail, then rewinds it using client.rewindInstance().
156+
* Returns the check status response so the caller can poll for completion.
97157
*/
98158
@FunctionName("StartRewindableSubOrchestration")
99159
public HttpResponseMessage startRewindableSubOrchestration(
@@ -108,6 +168,22 @@ public HttpResponseMessage startRewindableSubOrchestration(
108168
DurableTaskClient client = durableContext.getClient();
109169
String instanceId = client.scheduleNewOrchestrationInstance("RewindableParentOrchestration");
110170
context.getLogger().info("Created parent orchestration with instance ID = " + instanceId);
171+
172+
// Wait for the parent orchestration to reach a terminal state (expected: Failed)
173+
try {
174+
OrchestrationMetadata metadata = client.waitForInstanceCompletion(instanceId, Duration.ofSeconds(30), false);
175+
context.getLogger().info("Parent orchestration reached terminal state: " + metadata.getRuntimeStatus());
176+
} catch (TimeoutException e) {
177+
context.getLogger().severe("Parent orchestration did not reach terminal state in time.");
178+
return request.createResponseBuilder(com.microsoft.azure.functions.HttpStatus.INTERNAL_SERVER_ERROR)
179+
.body("Parent orchestration did not fail within the expected time.")
180+
.build();
181+
}
182+
183+
// Rewind the failed parent orchestration using the client method
184+
client.rewindInstance(instanceId, "Testing rewind with sub-orchestration failure");
185+
context.getLogger().info("Rewind request sent for parent instance: " + instanceId);
186+
111187
return durableContext.createCheckStatusResponse(request, instanceId);
112188
}
113189

endtoendtests/src/test/java/com/functions/EndToEndTests.java

Lines changed: 10 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -236,26 +236,14 @@ public void suspendResume() throws InterruptedException {
236236

237237
@Test
238238
public void rewindFailedOrchestration() throws InterruptedException {
239-
// Reset the failure flag before starting
240-
post("/api/ResetRewindFailureFlag");
241-
242-
// Start the orchestration - it will fail on the first activity call
239+
// Start the orchestration - the trigger waits for failure and calls
240+
// client.rewindInstance() internally before returning
243241
String startOrchestrationPath = "/api/StartRewindableOrchestration";
244242
Response response = post(startOrchestrationPath);
245243
JsonPath jsonPath = response.jsonPath();
246244
String statusQueryGetUri = jsonPath.get("statusQueryGetUri");
247245

248-
// Wait for the orchestration to fail
249-
boolean failed = pollingCheck(statusQueryGetUri, "Failed", null, Duration.ofSeconds(15));
250-
assertTrue(failed, "Orchestration should have failed");
251-
252-
// Get the rewind URI and rewind the orchestration
253-
String rewindPostUri = jsonPath.get("rewindPostUri");
254-
rewindPostUri = rewindPostUri.replace("{text}", "Testing rewind functionality");
255-
Response rewindResponse = post(rewindPostUri);
256-
assertEquals(202, rewindResponse.getStatusCode(), "Rewind should return 202 Accepted");
257-
258-
// Wait for the orchestration to complete after rewind
246+
// The trigger already called client.rewindInstance(), so just poll for completion
259247
boolean completed = pollingCheck(statusQueryGetUri, "Completed", null, Duration.ofSeconds(30));
260248
assertTrue(completed, "Orchestration should complete after rewind");
261249

@@ -267,21 +255,14 @@ public void rewindFailedOrchestration() throws InterruptedException {
267255

268256
@Test
269257
public void rewindNonFailedOrchestration() throws InterruptedException {
270-
// Start a normal orchestration and wait for it to complete
271-
String startOrchestrationPath = "/api/StartOrchestration";
258+
// Start a non-failing orchestration - the trigger waits for completion
259+
// and then calls client.rewindInstance() internally before returning
260+
String startOrchestrationPath = "/api/StartRewindNonFailedOrchestration";
272261
Response response = post(startOrchestrationPath);
273262
JsonPath jsonPath = response.jsonPath();
274263
String statusQueryGetUri = jsonPath.get("statusQueryGetUri");
275264

276-
boolean completed = pollingCheck(statusQueryGetUri, "Completed", null, Duration.ofSeconds(15));
277-
assertTrue(completed, "Orchestration should complete before rewind attempt");
278-
279-
// Attempt to rewind the completed (non-failed) orchestration
280-
String rewindPostUri = jsonPath.get("rewindPostUri");
281-
rewindPostUri = rewindPostUri.replace("{text}", "Testing rewind on non-failed orchestration");
282-
post(rewindPostUri);
283-
284-
// Wait a few seconds to allow any potential state change
265+
// Wait a few seconds to allow any potential state change from the rewind attempt
285266
Thread.sleep(5000);
286267

287268
// Verify the orchestration remains in Completed state (rewind should have no effect)
@@ -293,26 +274,14 @@ public void rewindNonFailedOrchestration() throws InterruptedException {
293274

294275
@Test
295276
public void rewindSubOrchestrationFailure() throws InterruptedException {
296-
// Reset the sub-orchestration failure flag before starting
297-
post("/api/ResetSubRewindFailureFlag");
298-
299-
// Start the parent orchestration - the sub-orchestration's activity will fail
277+
// Start the parent orchestration - the trigger waits for the sub-orchestration
278+
// to fail, then calls client.rewindInstance() internally before returning
300279
String startOrchestrationPath = "/api/StartRewindableSubOrchestration";
301280
Response response = post(startOrchestrationPath);
302281
JsonPath jsonPath = response.jsonPath();
303282
String statusQueryGetUri = jsonPath.get("statusQueryGetUri");
304283

305-
// Wait for the parent orchestration to fail (due to sub-orchestration failure)
306-
boolean failed = pollingCheck(statusQueryGetUri, "Failed", null, Duration.ofSeconds(15));
307-
assertTrue(failed, "Parent orchestration should have failed due to sub-orchestration failure");
308-
309-
// Rewind the parent orchestration
310-
String rewindPostUri = jsonPath.get("rewindPostUri");
311-
rewindPostUri = rewindPostUri.replace("{text}", "Testing rewind with sub-orchestration failure");
312-
Response rewindResponse = post(rewindPostUri);
313-
assertEquals(202, rewindResponse.getStatusCode(), "Rewind should return 202 Accepted");
314-
315-
// Wait for the parent orchestration to complete after rewind
284+
// The trigger already called client.rewindInstance(), so just poll for completion
316285
boolean completed = pollingCheck(statusQueryGetUri, "Completed", null, Duration.ofSeconds(30));
317286
assertTrue(completed, "Parent orchestration should complete after rewind");
318287

samples-azure-functions/src/main/java/com/functions/RewindTest.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,16 @@
1111
import com.microsoft.azure.functions.annotation.FunctionName;
1212
import com.microsoft.azure.functions.annotation.HttpTrigger;
1313
import com.microsoft.durabletask.DurableTaskClient;
14+
import com.microsoft.durabletask.OrchestrationMetadata;
1415
import com.microsoft.durabletask.TaskOrchestrationContext;
1516
import com.microsoft.durabletask.azurefunctions.DurableActivityTrigger;
1617
import com.microsoft.durabletask.azurefunctions.DurableClientContext;
1718
import com.microsoft.durabletask.azurefunctions.DurableClientInput;
1819
import com.microsoft.durabletask.azurefunctions.DurableOrchestrationTrigger;
1920

21+
import java.time.Duration;
2022
import java.util.Optional;
23+
import java.util.concurrent.TimeoutException;
2124
import java.util.concurrent.atomic.AtomicBoolean;
2225

2326
/**
@@ -30,7 +33,9 @@ public class RewindTest {
3033
private static final AtomicBoolean shouldFail = new AtomicBoolean(true);
3134

3235
/**
33-
* HTTP trigger to start the rewindable orchestration.
36+
* HTTP trigger that starts a rewindable orchestration, waits for it to fail,
37+
* then rewinds it using client.rewindInstance(). Returns the check status response
38+
* so the caller can poll for the orchestration to complete after the rewind.
3439
*/
3540
@FunctionName("StartRewindableOrchestration")
3641
public HttpResponseMessage startRewindableOrchestration(
@@ -42,6 +47,22 @@ public HttpResponseMessage startRewindableOrchestration(
4247
DurableTaskClient client = durableContext.getClient();
4348
String instanceId = client.scheduleNewOrchestrationInstance("RewindableOrchestration");
4449
context.getLogger().info("Created new Java orchestration with instance ID = " + instanceId);
50+
51+
// Wait for the orchestration to reach a terminal state (expected: Failed)
52+
try {
53+
OrchestrationMetadata metadata = client.waitForInstanceCompletion(instanceId, Duration.ofSeconds(30), false);
54+
context.getLogger().info("Orchestration reached terminal state: " + metadata.getRuntimeStatus());
55+
} catch (TimeoutException e) {
56+
context.getLogger().severe("Orchestration did not reach terminal state in time.");
57+
return request.createResponseBuilder(HttpStatus.INTERNAL_SERVER_ERROR)
58+
.body("Orchestration did not fail within the expected time.")
59+
.build();
60+
}
61+
62+
// Rewind the failed orchestration using the client method
63+
client.rewindInstance(instanceId, "Testing rewind functionality");
64+
context.getLogger().info("Rewind request sent for instance: " + instanceId);
65+
4566
return durableContext.createCheckStatusResponse(request, instanceId);
4667
}
4768

samples-azure-functions/src/test/java/com/functions/EndToEndTests.java

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -234,23 +234,14 @@ public void rewindFailedOrchestration() throws InterruptedException {
234234
// Reset the failure flag before starting
235235
post("/api/ResetRewindFailureFlag");
236236

237-
// Start the orchestration - it will fail on the first activity call
237+
// Start the orchestration - the trigger waits for failure and calls
238+
// client.rewindInstance() internally before returning
238239
String startOrchestrationPath = "/api/StartRewindableOrchestration";
239240
Response response = post(startOrchestrationPath);
240241
JsonPath jsonPath = response.jsonPath();
241242
String statusQueryGetUri = jsonPath.get("statusQueryGetUri");
242243

243-
// Wait for the orchestration to fail
244-
boolean failed = pollingCheck(statusQueryGetUri, "Failed", null, Duration.ofSeconds(10));
245-
assertTrue(failed, "Orchestration should have failed");
246-
247-
// Get the rewind URI and rewind the orchestration
248-
String rewindPostUri = jsonPath.get("rewindPostUri");
249-
rewindPostUri = rewindPostUri.replace("{text}", "Testing rewind functionality");
250-
Response rewindResponse = post(rewindPostUri);
251-
assertEquals(202, rewindResponse.getStatusCode(), "Rewind should return 202 Accepted");
252-
253-
// Wait for the orchestration to complete after rewind
244+
// The trigger already called client.rewindInstance(), so just poll for completion
254245
Set<String> continueStates = new HashSet<>();
255246
continueStates.add("Pending");
256247
continueStates.add("Running");

0 commit comments

Comments
 (0)