Files
flowgraph/test/helpers/helpers.test.ts

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();
});
});
});