Skip to content

Commit 6ba2b04

Browse files
committed
more tests
1 parent 5edbb77 commit 6ba2b04

File tree

4 files changed

+272
-17
lines changed

4 files changed

+272
-17
lines changed

.cursor/rules/executing-commands.mdc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ But often, when running tests, it's better to `cd` into the directory and then r
1313

1414
```
1515
cd apps/webapp
16-
pnpm run test
16+
pnpm run test --run
1717
```
1818

1919
This way you can run for a single file easily:
2020

2121
```
2222
cd internal-packages/run-engine
23-
pnpm run test ./src/engine/tests/ttl.test.ts
23+
pnpm run test ./src/engine/tests/ttl.test.ts --run
2424
```

packages/cli-v3/src/entryPoints/dev-run-worker.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ const zodIpc = new ZodIpcConnection({
358358
tracer,
359359
tracingSDK,
360360
consoleInterceptor,
361-
config,
361+
retries: config.retries,
362362
handleErrorFn,
363363
});
364364

@@ -406,13 +406,7 @@ const zodIpc = new ZodIpcConnection({
406406
}
407407
});
408408

409-
const { result } = await executor.execute(
410-
execution,
411-
metadata,
412-
traceContext,
413-
measurement,
414-
signal
415-
);
409+
const { result } = await executor.execute(execution, metadata, traceContext, signal);
416410

417411
const usageSample = usage.stop(measurement);
418412

packages/core/src/v3/workers/taskExecutor.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,11 @@ export class TaskExecutor {
377377
)
378378
);
379379

380-
if (!hookError && result && typeof result === "object" && !Array.isArray(result)) {
380+
if (hookError) {
381+
throw hookError;
382+
}
383+
384+
if (result && typeof result === "object" && !Array.isArray(result)) {
381385
globalResults.push(result);
382386
}
383387
}
@@ -407,13 +411,12 @@ export class TaskExecutor {
407411
)
408412
);
409413

414+
if (hookError) {
415+
throw hookError;
416+
}
417+
410418
// Only merge if taskResult is an object
411-
if (
412-
!hookError &&
413-
taskResult &&
414-
typeof taskResult === "object" &&
415-
!Array.isArray(taskResult)
416-
) {
419+
if (taskResult && typeof taskResult === "object" && !Array.isArray(taskResult)) {
417420
return { ...mergedGlobalResults, ...taskResult };
418421
}
419422

@@ -645,6 +648,10 @@ export class TaskExecutor {
645648
}
646649
)
647650
);
651+
652+
if (hookError) {
653+
throw hookError;
654+
}
648655
}
649656

650657
if (taskStartHook) {
@@ -667,6 +674,10 @@ export class TaskExecutor {
667674
}
668675
)
669676
);
677+
678+
if (hookError) {
679+
throw hookError;
680+
}
670681
}
671682
}
672683
);

packages/core/test/taskExecutor.test.ts

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,256 @@ describe("TaskExecutor", () => {
953953
},
954954
});
955955
});
956+
957+
test("should propagate errors from init hooks", async () => {
958+
const executionOrder: string[] = [];
959+
const expectedError = new Error("Init hook error");
960+
961+
// Register global init hook that throws an error
962+
lifecycleHooks.registerGlobalInitHook({
963+
id: "failing-init",
964+
fn: async () => {
965+
executionOrder.push("global-init");
966+
throw expectedError;
967+
},
968+
});
969+
970+
// Register task init hook that should never be called
971+
lifecycleHooks.registerTaskInitHook("test-task", {
972+
id: "task-init",
973+
fn: async () => {
974+
executionOrder.push("task-init");
975+
return {
976+
foo: "bar",
977+
};
978+
},
979+
});
980+
981+
// Register failure hook to verify it's called
982+
lifecycleHooks.registerGlobalFailureHook({
983+
id: "global-failure",
984+
fn: async ({ error }) => {
985+
executionOrder.push("failure");
986+
expect(error).toBe(expectedError);
987+
},
988+
});
989+
990+
// Register complete hook to verify it's called with error
991+
lifecycleHooks.registerGlobalCompleteHook({
992+
id: "global-complete",
993+
fn: async ({ result }) => {
994+
executionOrder.push("complete");
995+
expect(result).toEqual({
996+
ok: false,
997+
error: expectedError,
998+
});
999+
},
1000+
});
1001+
1002+
const task = {
1003+
id: "test-task",
1004+
fns: {
1005+
run: async (payload: any, params: RunFnParams<any>) => {
1006+
executionOrder.push("run");
1007+
return {
1008+
output: "test-output",
1009+
};
1010+
},
1011+
},
1012+
};
1013+
1014+
const result = await executeTask(task, { test: "data" });
1015+
1016+
// Verify only the global init hook ran, and failure/complete hooks were called
1017+
expect(executionOrder).toEqual(["global-init", "failure", "complete"]);
1018+
1019+
// Verify the error result
1020+
expect(result).toEqual({
1021+
result: {
1022+
ok: false,
1023+
id: "test-run-id",
1024+
error: {
1025+
type: "BUILT_IN_ERROR",
1026+
message: "Init hook error",
1027+
name: "Error",
1028+
stackTrace: expect.any(String),
1029+
},
1030+
skippedRetrying: false,
1031+
},
1032+
});
1033+
});
1034+
1035+
test("should propagate errors from task init hooks", async () => {
1036+
const executionOrder: string[] = [];
1037+
const expectedError = new Error("Task init hook error");
1038+
1039+
// Register global init hook that succeeds
1040+
lifecycleHooks.registerGlobalInitHook({
1041+
id: "global-init",
1042+
fn: async () => {
1043+
executionOrder.push("global-init");
1044+
return {
1045+
foo: "bar",
1046+
};
1047+
},
1048+
});
1049+
1050+
// Register task init hook that throws an error
1051+
lifecycleHooks.registerTaskInitHook("test-task", {
1052+
id: "task-init",
1053+
fn: async () => {
1054+
executionOrder.push("task-init");
1055+
throw expectedError;
1056+
},
1057+
});
1058+
1059+
// Register failure hook to verify it's called
1060+
lifecycleHooks.registerGlobalFailureHook({
1061+
id: "global-failure",
1062+
fn: async ({ error, init }) => {
1063+
executionOrder.push("failure");
1064+
expect(error).toBe(expectedError);
1065+
// Verify we got the global init data
1066+
expect(init).toEqual({ foo: "bar" });
1067+
},
1068+
});
1069+
1070+
// Register complete hook to verify it's called with error
1071+
lifecycleHooks.registerGlobalCompleteHook({
1072+
id: "global-complete",
1073+
fn: async ({ result, init }) => {
1074+
executionOrder.push("complete");
1075+
expect(result).toEqual({
1076+
ok: false,
1077+
error: expectedError,
1078+
});
1079+
// Verify we got the global init data
1080+
expect(init).toEqual({ foo: "bar" });
1081+
},
1082+
});
1083+
1084+
const task = {
1085+
id: "test-task",
1086+
fns: {
1087+
run: async (payload: any, params: RunFnParams<any>) => {
1088+
executionOrder.push("run");
1089+
return {
1090+
output: "test-output",
1091+
};
1092+
},
1093+
},
1094+
};
1095+
1096+
const result = await executeTask(task, { test: "data" });
1097+
1098+
// Verify both init hooks ran, but run wasn't called, and failure/complete hooks were called
1099+
expect(executionOrder).toEqual(["global-init", "task-init", "failure", "complete"]);
1100+
1101+
// Verify the error result
1102+
expect(result).toEqual({
1103+
result: {
1104+
ok: false,
1105+
id: "test-run-id",
1106+
error: {
1107+
type: "BUILT_IN_ERROR",
1108+
message: "Task init hook error",
1109+
name: "Error",
1110+
stackTrace: expect.any(String),
1111+
},
1112+
skippedRetrying: false,
1113+
},
1114+
});
1115+
});
1116+
1117+
test("should propagate errors from start hooks", async () => {
1118+
const executionOrder: string[] = [];
1119+
const expectedError = new Error("Start hook error");
1120+
1121+
// Register global init hook that succeeds
1122+
lifecycleHooks.registerGlobalInitHook({
1123+
id: "global-init",
1124+
fn: async () => {
1125+
executionOrder.push("global-init");
1126+
return {
1127+
foo: "bar",
1128+
};
1129+
},
1130+
});
1131+
1132+
// Register global start hook that throws an error
1133+
lifecycleHooks.registerGlobalStartHook({
1134+
id: "global-start",
1135+
fn: async () => {
1136+
executionOrder.push("global-start");
1137+
throw expectedError;
1138+
},
1139+
});
1140+
1141+
// Register task start hook that should never be called
1142+
lifecycleHooks.registerTaskStartHook("test-task", {
1143+
id: "task-start",
1144+
fn: async () => {
1145+
executionOrder.push("task-start");
1146+
},
1147+
});
1148+
1149+
// Register failure hook to verify it's called
1150+
lifecycleHooks.registerGlobalFailureHook({
1151+
id: "global-failure",
1152+
fn: async ({ error, init }) => {
1153+
executionOrder.push("failure");
1154+
expect(error).toBe(expectedError);
1155+
// Verify we got the init data
1156+
expect(init).toEqual({ foo: "bar" });
1157+
},
1158+
});
1159+
1160+
// Register complete hook to verify it's called with error
1161+
lifecycleHooks.registerGlobalCompleteHook({
1162+
id: "global-complete",
1163+
fn: async ({ result, init }) => {
1164+
executionOrder.push("complete");
1165+
expect(result).toEqual({
1166+
ok: false,
1167+
error: expectedError,
1168+
});
1169+
// Verify we got the init data
1170+
expect(init).toEqual({ foo: "bar" });
1171+
},
1172+
});
1173+
1174+
const task = {
1175+
id: "test-task",
1176+
fns: {
1177+
run: async (payload: any, params: RunFnParams<any>) => {
1178+
executionOrder.push("run");
1179+
return {
1180+
output: "test-output",
1181+
};
1182+
},
1183+
},
1184+
};
1185+
1186+
const result = await executeTask(task, { test: "data" });
1187+
1188+
// Verify init succeeded, start hook failed, and run wasn't called
1189+
expect(executionOrder).toEqual(["global-init", "global-start", "failure", "complete"]);
1190+
1191+
// Verify the error result
1192+
expect(result).toEqual({
1193+
result: {
1194+
ok: false,
1195+
id: "test-run-id",
1196+
error: {
1197+
type: "BUILT_IN_ERROR",
1198+
message: "Start hook error",
1199+
name: "Error",
1200+
stackTrace: expect.any(String),
1201+
},
1202+
skippedRetrying: false,
1203+
},
1204+
});
1205+
});
9561206
});
9571207

9581208
function executeTask(task: TaskMetadataWithFunctions, payload: any) {

0 commit comments

Comments
 (0)