171 lines
5.0 KiB
TypeScript
171 lines
5.0 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import {
|
|
createLinearGraph,
|
|
createDiamondGraph,
|
|
createOperationGraph,
|
|
createCallGraph,
|
|
} from "@test/graph-factory.js";
|
|
import {
|
|
createTestReactiveRoot,
|
|
assertStatus,
|
|
assertPreconditions,
|
|
assertBlockedByFailure,
|
|
} from "@test/reactive.js";
|
|
import {
|
|
CompatibleInputSchema,
|
|
CompatibleOutputSchema,
|
|
NarrowOutputSchema,
|
|
WideInputSchema,
|
|
IncompatibleNumberOutputSchema,
|
|
IncompatibleStringInputSchema,
|
|
compatiblePairs,
|
|
incompatiblePairs,
|
|
unknownSchemas,
|
|
} from "@test/schemas.js";
|
|
|
|
describe("test helpers smoke tests", () => {
|
|
describe("graph-factory", () => {
|
|
it("creates a linear graph", () => {
|
|
const graph = createLinearGraph(["A", "B", "C"]);
|
|
expect(graph.nodes()).toEqual(["A", "B", "C"]);
|
|
expect(graph.edges()).toEqual(["A->B", "B->C"]);
|
|
});
|
|
|
|
it("creates a diamond graph", () => {
|
|
const graph = createDiamondGraph("top", "left", "right", "bottom");
|
|
expect(graph.nodes()).toEqual(["top", "left", "right", "bottom"]);
|
|
expect(graph.edges()).toEqual([
|
|
"top->left",
|
|
"top->right",
|
|
"left->bottom",
|
|
"right->bottom",
|
|
]);
|
|
});
|
|
|
|
it("creates an operation graph", () => {
|
|
const graph = createOperationGraph(
|
|
[
|
|
{ name: "classify", namespace: "task" },
|
|
{ name: "enrich", namespace: "task" },
|
|
],
|
|
[{ source: "task.classify", target: "task.enrich" }],
|
|
);
|
|
expect(graph.nodes()).toEqual(["task.classify", "task.enrich"]);
|
|
expect(graph.edges()).toEqual(["task.classify->task.enrich"]);
|
|
});
|
|
|
|
it("creates a call graph", () => {
|
|
const graph = createCallGraph([
|
|
{ requestId: "req1", operationId: "op1", status: "completed" },
|
|
{
|
|
requestId: "req2",
|
|
operationId: "op2",
|
|
status: "running",
|
|
parentRequestId: "req1",
|
|
},
|
|
]);
|
|
expect(graph.nodes()).toEqual(["req1", "req2"]);
|
|
expect(graph.edges()).toEqual(["req1->req2"]);
|
|
});
|
|
});
|
|
|
|
describe("reactive", () => {
|
|
it("creates reactive root with setup-transition-assert-dispose", () => {
|
|
const graph = createDiamondGraph("A", "B", "C", "D");
|
|
const root = createTestReactiveRoot(graph);
|
|
|
|
try {
|
|
assertStatus(root, "A", "idle");
|
|
assertStatus(root, "B", "idle");
|
|
assertPreconditions(root, "A", true);
|
|
assertPreconditions(root, "D", false);
|
|
|
|
root.statusMap.get("A")!.value = "completed";
|
|
assertPreconditions(root, "B", true);
|
|
assertPreconditions(root, "C", true);
|
|
assertPreconditions(root, "D", false);
|
|
|
|
root.statusMap.get("B")!.value = "completed";
|
|
root.statusMap.get("C")!.value = "completed";
|
|
assertPreconditions(root, "D", true);
|
|
} finally {
|
|
root.dispose();
|
|
}
|
|
});
|
|
|
|
it("propagates failure to blockedByFailure", () => {
|
|
const graph = createLinearGraph(["A", "B"]);
|
|
const root = createTestReactiveRoot(graph);
|
|
|
|
try {
|
|
assertBlockedByFailure(root, "B", false);
|
|
root.statusMap.get("A")!.value = "failed";
|
|
assertBlockedByFailure(root, "B", true);
|
|
} finally {
|
|
root.dispose();
|
|
}
|
|
});
|
|
|
|
it("auto-aborts idle nodes when blockedByFailure fires", () => {
|
|
const graph = createLinearGraph(["A", "B"]);
|
|
const root = createTestReactiveRoot(graph);
|
|
|
|
try {
|
|
assertStatus(root, "B", "idle");
|
|
assertBlockedByFailure(root, "B", false);
|
|
|
|
root.statusMap.get("A")!.value = "failed";
|
|
|
|
assertBlockedByFailure(root, "B", true);
|
|
assertStatus(root, "B", "aborted");
|
|
} finally {
|
|
root.dispose();
|
|
}
|
|
});
|
|
|
|
it("skipped satisfies preconditions", () => {
|
|
const graph = createLinearGraph(["A", "B"]);
|
|
const root = createTestReactiveRoot(graph);
|
|
|
|
try {
|
|
root.statusMap.get("A")!.value = "skipped";
|
|
assertPreconditions(root, "B", true);
|
|
} finally {
|
|
root.dispose();
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("schemas", () => {
|
|
it("provides compatible pairs", () => {
|
|
expect(compatiblePairs.length).toBeGreaterThan(0);
|
|
for (const pair of compatiblePairs) {
|
|
expect(pair.name).toBeTruthy();
|
|
expect(pair.output).toBeDefined();
|
|
expect(pair.input).toBeDefined();
|
|
}
|
|
});
|
|
|
|
it("provides incompatible pairs", () => {
|
|
expect(incompatiblePairs.length).toBeGreaterThan(0);
|
|
for (const pair of incompatiblePairs) {
|
|
expect(pair.name).toBeTruthy();
|
|
expect(pair.output).toBeDefined();
|
|
expect(pair.input).toBeDefined();
|
|
}
|
|
});
|
|
|
|
it("provides unknown schemas", () => {
|
|
expect(unknownSchemas.length).toBeGreaterThan(0);
|
|
for (const item of unknownSchemas) {
|
|
expect(item.name).toBeTruthy();
|
|
expect(item.schema).toBeDefined();
|
|
}
|
|
});
|
|
|
|
it("CompatibleInputSchema and CompatibleOutputSchema have same structure", () => {
|
|
expect(CompatibleInputSchema).toBeDefined();
|
|
expect(CompatibleOutputSchema).toBeDefined();
|
|
});
|
|
});
|
|
}); |