Skip to content

Commit 144bdab

Browse files
authored
test: add missing RetryableTask coverage for non-retriable, remaining-timeout, and complete() override (#289)
1 parent dd8f53e commit 144bdab

1 file changed

Lines changed: 77 additions & 0 deletions

File tree

packages/durabletask-js/test/retryable-task.spec.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,53 @@ describe("RetryableTask", () => {
296296
expect(delay).toBeDefined();
297297
expect(delay).toBeGreaterThan(0);
298298
});
299+
300+
it("should return undefined when last failure is marked non-retriable", () => {
301+
// Arrange
302+
const retryPolicy = new RetryPolicy({
303+
maxNumberOfAttempts: 10,
304+
firstRetryIntervalInMilliseconds: 1000,
305+
});
306+
const action = new pb.OrchestratorAction();
307+
const startTime = new Date();
308+
const task = new RetryableTask<string>(retryPolicy, action, startTime, "activity");
309+
310+
// Record a non-retriable failure (e.g., activity not found, version mismatch)
311+
const failureDetails = new pb.TaskFailureDetails();
312+
failureDetails.setErrortype("ActivityNotFoundError");
313+
failureDetails.setErrormessage("Activity 'DoWork' is not registered");
314+
failureDetails.setIsnonretriable(true);
315+
task.recordFailure("Activity 'DoWork' is not registered", failureDetails);
316+
317+
const currentTime = new Date(startTime.getTime() + 100);
318+
319+
// Act
320+
const delay = task.computeNextDelayInMilliseconds(currentTime);
321+
322+
// Assert - non-retriable failures must not be retried regardless of policy
323+
expect(delay).toBeUndefined();
324+
});
325+
326+
it("should return undefined when computed delay exceeds remaining timeout", () => {
327+
// Arrange - timeout is 5000ms, elapsed is 4500ms, so remaining is 500ms.
328+
// With firstRetryInterval of 1000ms, the computed delay (1000) > remaining (500).
329+
const retryPolicy = new RetryPolicy({
330+
maxNumberOfAttempts: 10,
331+
firstRetryIntervalInMilliseconds: 1000,
332+
retryTimeoutInMilliseconds: 5000,
333+
});
334+
const startTime = new Date();
335+
const action = new pb.OrchestratorAction();
336+
const task = new RetryableTask<string>(retryPolicy, action, startTime, "activity");
337+
// 4500ms elapsed — within the 5000ms timeout, but delay (1000ms) exceeds remaining (500ms)
338+
const currentTime = new Date(startTime.getTime() + 4500);
339+
340+
// Act
341+
const delay = task.computeNextDelayInMilliseconds(currentTime);
342+
343+
// Assert - delay would overshoot the timeout, so no more retries
344+
expect(delay).toBeUndefined();
345+
});
299346
});
300347

301348
describe("incrementAttemptCount", () => {
@@ -361,6 +408,36 @@ describe("RetryableTask", () => {
361408
});
362409
});
363410

411+
describe("complete", () => {
412+
it("should clear failure state when retry succeeds", () => {
413+
// Arrange
414+
const retryPolicy = new RetryPolicy({
415+
maxNumberOfAttempts: 5,
416+
firstRetryIntervalInMilliseconds: 1000,
417+
});
418+
const action = new pb.OrchestratorAction();
419+
const task = new RetryableTask<string>(retryPolicy, action, new Date(), "activity");
420+
421+
// Simulate a failed attempt followed by a successful retry
422+
const failureDetails = new pb.TaskFailureDetails();
423+
failureDetails.setErrortype("TransientError");
424+
failureDetails.setErrormessage("Temporary failure");
425+
task.recordFailure("Temporary failure", failureDetails);
426+
427+
// Verify failure is recorded
428+
expect(task.lastFailure).toBeDefined();
429+
430+
// Act - retry succeeds
431+
task.complete("success");
432+
433+
// Assert - failure state is cleared, result is set
434+
expect(task.lastFailure).toBeUndefined();
435+
expect(task.isFailed).toBe(false);
436+
expect(task.getResult()).toBe("success");
437+
expect(task.isComplete).toBe(true);
438+
});
439+
});
440+
364441
describe("task types", () => {
365442
it("should support activity task type", () => {
366443
// Arrange

0 commit comments

Comments
 (0)