Skip to content

Commit a743d33

Browse files
committed
test(run-engine): cover completeWaitpoint error passthrough vs classification wrapping
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PVbKhNnh8A5tWDGKq9GggV
1 parent 576941c commit a743d33

1 file changed

Lines changed: 68 additions & 0 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// completeWaitpoint's store-selection guard must only turn a genuine id-classification
2+
// failure into UnclassifiableWaitpointId. forWaitpointCompletion also probes the DB to
3+
// resolve the owning store, so a transient database/infra error can surface from the same
4+
// call — and those must bubble up UNCHANGED (keeping their original type, retryability, and
5+
// error grouping) rather than being mislabelled as an unclassifiable id.
6+
//
7+
// This is a hermetic unit test: the error is thrown on the very first line of
8+
// completeWaitpoint (runStore.forWaitpointCompletion), before any snapshot/enqueue work,
9+
// so we can drive it with a minimal SystemResources and a fake runStore — no DB, no Redis.
10+
import { UnclassifiableRunId } from "@trigger.dev/core/v3/isomorphic";
11+
import { expect } from "vitest";
12+
import { UnclassifiableWaitpointId } from "../errors.js";
13+
import type { SystemResources } from "../systems/systems.js";
14+
import { WaitpointSystem } from "../systems/waitpointSystem.js";
15+
16+
function createWaitpointSystem(forWaitpointCompletion: () => Promise<never>) {
17+
const runStore = { forWaitpointCompletion };
18+
19+
const resources = {
20+
runStore,
21+
logger: {
22+
error: vi.fn(),
23+
warn: vi.fn(),
24+
info: vi.fn(),
25+
debug: vi.fn(),
26+
},
27+
} as unknown as SystemResources;
28+
29+
return new WaitpointSystem({
30+
resources,
31+
// Never reached on the store-resolution error path.
32+
executionSnapshotSystem: {} as any,
33+
enqueueSystem: {} as any,
34+
});
35+
}
36+
37+
describe("completeWaitpoint store-resolution error classification", () => {
38+
it("rethrows a transient database error unchanged (never wraps it as UnclassifiableWaitpointId)", async () => {
39+
const dbError = new Error("Can't reach database server at db:5432");
40+
const waitpointSystem = createWaitpointSystem(() => Promise.reject(dbError));
41+
42+
// The original error bubbles up as-is...
43+
await expect(waitpointSystem.completeWaitpoint({ id: "waitpoint_transient" })).rejects.toBe(
44+
dbError
45+
);
46+
// ...and is NOT relabelled as a classification failure.
47+
await expect(
48+
waitpointSystem.completeWaitpoint({ id: "waitpoint_transient" })
49+
).rejects.not.toBeInstanceOf(UnclassifiableWaitpointId);
50+
});
51+
52+
it("wraps a genuine UnclassifiableRunId as UnclassifiableWaitpointId with the original as cause", async () => {
53+
const waitpointId = "waitpoint_unclassifiable";
54+
const classificationError = new UnclassifiableRunId(waitpointId);
55+
const waitpointSystem = createWaitpointSystem(() => Promise.reject(classificationError));
56+
57+
await expect(
58+
waitpointSystem.completeWaitpoint({ id: waitpointId })
59+
).rejects.toBeInstanceOf(UnclassifiableWaitpointId);
60+
61+
const caught = (await waitpointSystem
62+
.completeWaitpoint({ id: waitpointId })
63+
.catch((error: unknown) => error)) as UnclassifiableWaitpointId;
64+
expect(caught).toBeInstanceOf(UnclassifiableWaitpointId);
65+
expect(caught.waitpointId).toBe(waitpointId);
66+
expect(caught.cause).toBe(classificationError);
67+
});
68+
});

0 commit comments

Comments
 (0)