Files
quixos-protocol/test/compound-crdt.test.ts
T

74 lines
3.6 KiB
TypeScript

import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { test } from "node:test";
import { compoundCrdtPlan } from "./compound-crdt-fixture.js";
import { compileCapabilityResourceSource, compileCapabilitySource } from "../src/capability-language/parser.js";
import { compileKernelProgram } from "../src/execution-world/index.js";
import { generatePortableTypeScriptBindings } from "../src/bindings/portable.js";
const source = { repository: "https://example.test/change.git", commit: "a".repeat(40) };
test("compound captured changes survive planning, transport lowering and typed edit ports", async () => {
const plan = await compoundCrdtPlan();
const kernel = compileKernelProgram(plan) as {
operations: {
operation: string;
inputChanges?: (string | null)[][];
input: { fields: { change: { kind: string } } };
}[];
};
const operation = kernel.operations.find((op) => op.operation === "compound:update:call")!;
assert.equal(operation.input.fields.change.kind, "record");
const paths = kernel.operations as unknown as { operation: string; inputChanges?: (string | null)[][] }[];
assert.deepEqual(paths.find((op) => op.operation === "compound:update:call")!.inputChanges, [["change"]]);
assert.deepEqual(paths.find((op) => op.operation === "compound:batch:call")!.inputChanges, [
["edits", null, "change"],
]);
assert.deepEqual(paths.find((op) => op.operation === "compound:content:edit")!.inputChanges, [[]]);
const code = generatePortableTypeScriptBindings(plan.definition.bindingSchema, "compound:runtime@1", {
target: "target:org.quixos.execution.javascript@1",
});
assert.ok(code.includes("PreparedChange<"));
assert.ok(code.includes('"edit"'));
assert.ok(!code.includes('"compound:runtime:check"'));
});
test("prepared changes require one storable materialized type", () => {
for (const shape of ["change<string, bool>", "change<atom N>", "change<atom-ref<N>>", "change<change<string>>"]) {
const result = compileCapabilityResourceSource(
`symbol JavaScript id "target:org.quixos.execution.javascript@1";
external atom N id "n"; package P id "p" revision "p@1" {
function f id "f" : ${shape} -> unit execution transaction targets [JavaScript, server];
}`,
{ source },
);
assert.equal(result.ok, false, shape);
}
});
test("captured changes cannot be persisted in a register or CRDT", async () => {
const iface = compileCapabilityResourceSource(await readFile("test/fixtures/compound-crdt/NoteData.qx", "utf8"), {
source,
});
assert.ok(iface.ok && iface.resource.kind === "interface", JSON.stringify(iface.diagnostics));
const pkg = compileCapabilityResourceSource(await readFile("test/fixtures/compound-crdt/EditRuntime.qx", "utf8"), {
source,
});
assert.ok(pkg.ok && pkg.resource.kind === "package", JSON.stringify(pkg.diagnostics));
const workspace = await readFile("test/fixtures/compound-crdt/workspace.qx", "utf8");
for (const policy of ["register", "crdt(change<Content>)"]) {
const result = compileCapabilitySource(
workspace.replace(
"private state Allowed",
`private state Captured id "captured" on Note : record { captured: change<Content>; } policy ${policy};\n private state Allowed`,
),
"workspace.qx",
{
interfaces: new Map([["NoteData", iface.resource.revision]]),
packages: new Map([["EditRuntime", pkg.resource.revision]]),
},
);
assert.equal(result.ok, false);
assert.ok(
result.diagnostics.some((d) => d.code === "invalid-attachment"),
JSON.stringify(result.diagnostics),
);
}
});