Expose authoritative lifecycle deletion through capability bindings
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/parser.js";
|
||||
import { formatQx } from "../src/capability-language/source.js";
|
||||
import { compileExecutionPlan, compileKernelProgram } from "../src/execution-world/index.js";
|
||||
const contract = `interface Item id "item" revision "item@1" {
|
||||
operation remove id "remove" : unit -> unit {
|
||||
call id "remove:call" execution transaction targets [server];
|
||||
}
|
||||
}`;
|
||||
const workspace = `workspace Lifecycle id "workspace:lifecycle" revision "workspace:lifecycle@1" commit "${"a".repeat(40)}" {
|
||||
import interface Item;
|
||||
atom Node id "node";
|
||||
conform Node as Item id "node:item" {
|
||||
private edge Links id "links" {
|
||||
atom Node projection children id "children" many on-delete "cascade-other";
|
||||
atom Node projection parent id "parent" optional-one on-delete "detach";
|
||||
}
|
||||
bind remove.call to lifecycle.delete;
|
||||
}
|
||||
}`;
|
||||
function compile(ifaceSource = contract, workspaceSource = workspace) {
|
||||
const iface = compileCapabilityResourceSource(ifaceSource, {
|
||||
source: { repository: "https://example.test/lifecycle.git", commit: "a".repeat(40) },
|
||||
});
|
||||
assert.ok(iface.ok && iface.resource.kind === "interface", JSON.stringify(iface.diagnostics));
|
||||
return compileCapabilitySource(workspaceSource, "workspace.qx", {
|
||||
interfaces: new Map([["Item", iface.resource.revision]]),
|
||||
});
|
||||
}
|
||||
test("lifecycle binding and endpoint policies survive formatting and kernel compilation", () => {
|
||||
const result = compile();
|
||||
assert.ok(result.ok, JSON.stringify(result.diagnostics));
|
||||
const formatted = compile(formatQx(contract), formatQx(workspace));
|
||||
assert.ok(formatted.ok, JSON.stringify(formatted.diagnostics));
|
||||
const plan = compileExecutionPlan(result.workspace);
|
||||
assert.equal(compileExecutionPlan(formatted.workspace).digest, plan.digest);
|
||||
const kernel = compileKernelProgram(plan) as {
|
||||
operations: { binding: unknown }[];
|
||||
model: { edges: { a: { onDelete: string }; b: { onDelete: string } }[] };
|
||||
};
|
||||
assert.deepEqual(kernel.operations[0]!.binding, { kind: "lifecycle", primitive: "delete" });
|
||||
assert.equal(kernel.model.edges[0]!.a.onDelete, "cascade-other");
|
||||
assert.equal(kernel.model.edges[0]!.b.onDelete, "detach");
|
||||
});
|
||||
test("deletion rejects browser, snapshot, remote, class, payload and unknown primitive promises", () => {
|
||||
for (const [iface, ws] of [
|
||||
[contract.replace("targets [server]", "targets [browser, server]"), workspace],
|
||||
[contract.replace("transaction targets", "snapshot targets"), workspace],
|
||||
[contract.replace("execution transaction targets [server]", "execution remote"), workspace],
|
||||
[contract.replace("execution transaction targets [server]", ""), workspace],
|
||||
[contract.replace("operation remove", "static operation remove"), workspace],
|
||||
[contract.replace("unit -> unit", "string -> unit"), workspace],
|
||||
[contract.replace("unit -> unit", "unit -> string"), workspace],
|
||||
[contract, workspace.replace("lifecycle.delete", "lifecycle.resurrect")],
|
||||
]) {
|
||||
const result = compile(iface, ws);
|
||||
assert.equal(result.ok, false, iface + ws);
|
||||
assert.ok(
|
||||
result.diagnostics.some((d) =>
|
||||
["invalid-execution-contract", "invalid-lifecycle-binding", "invalid-package-binding"].includes(d.code),
|
||||
),
|
||||
JSON.stringify(result.diagnostics),
|
||||
);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user