109 lines
3.1 KiB
JavaScript
109 lines
3.1 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
import test from "node:test";
|
|
|
|
import Ajv2020 from "ajv/dist/2020.js";
|
|
|
|
import { readAcpxSidecarProtocolVersion } from "../scripts/acpx-sidecar-contract.mjs";
|
|
|
|
const schema = JSON.parse(
|
|
await readFile(
|
|
new URL(
|
|
"../protocol/provider-schemas/acpx-sidecar.schema.json",
|
|
import.meta.url,
|
|
),
|
|
"utf8",
|
|
),
|
|
);
|
|
const validate = new Ajv2020({ allErrors: true, strict: true }).compile(schema);
|
|
const protocolVersion = readAcpxSidecarProtocolVersion(schema);
|
|
|
|
const messages = [
|
|
{
|
|
protocolVersion,
|
|
id: 1,
|
|
command: "initialize",
|
|
params: {},
|
|
},
|
|
{
|
|
protocolVersion,
|
|
id: 1,
|
|
ok: true,
|
|
result: {},
|
|
},
|
|
{
|
|
protocolVersion,
|
|
sequence: 1,
|
|
eventType: "runtime.event",
|
|
runId: "run-1",
|
|
turnId: "turn-1",
|
|
payload: {},
|
|
},
|
|
];
|
|
|
|
test("the ACPX sidecar schema accepts each versioned message family", () => {
|
|
for (const message of messages) {
|
|
assert.equal(validate(message), true, JSON.stringify(validate.errors));
|
|
}
|
|
});
|
|
|
|
test("the ACPX sidecar schema shares the durable stable-identity boundary", () => {
|
|
const longestTurnId = "t".repeat(240);
|
|
assert.equal(validate({ ...messages[2], turnId: longestTurnId }), true);
|
|
assert.equal(validate({ ...messages[2], turnId: "t".repeat(241) }), false);
|
|
for (const turnId of ["turn 1", "réturn-1", "turn/1", "_turn-1"]) {
|
|
assert.equal(validate({ ...messages[2], turnId }), false, turnId);
|
|
}
|
|
assert.equal(validate({ ...messages[2], runId: "r".repeat(161) }), false);
|
|
for (const runId of ["run 1", "rún-1", "run/1", "_run-1"]) {
|
|
assert.equal(validate({ ...messages[2], runId }), false, runId);
|
|
}
|
|
});
|
|
|
|
test("the ACPX sidecar schema fails closed on drift", () => {
|
|
for (const message of [
|
|
{ ...messages[0], protocolVersion: protocolVersion + 1 },
|
|
{ ...messages[0], command: "session.destroy" },
|
|
{ protocolVersion, id: 1, ok: true, result: {}, error: error() },
|
|
{ protocolVersion, id: 1, ok: true },
|
|
{ protocolVersion, id: 1, ok: false },
|
|
{ protocolVersion, id: 1, ok: false, result: {}, error: error() },
|
|
{ ...messages[2], unexpected: true },
|
|
]) {
|
|
assert.equal(validate(message), false);
|
|
}
|
|
});
|
|
|
|
test("every ACPX sidecar message family uses the shared version", () => {
|
|
for (const family of ["request", "response", "event"]) {
|
|
assert.deepEqual(schema.$defs[family].properties.protocolVersion, {
|
|
$ref: "#/$defs/protocolVersion",
|
|
});
|
|
}
|
|
});
|
|
|
|
test("the ACPX sidecar schema id carries the declared protocol version", () => {
|
|
assert.equal(
|
|
schema.$id,
|
|
`https://paperclip.dev/schemas/acpx-sidecar/v${protocolVersion}/message.schema.json`,
|
|
);
|
|
});
|
|
|
|
test("a coordinated family-version upgrade cannot outpace the schema id", () => {
|
|
const driftedSchema = structuredClone(schema);
|
|
driftedSchema.$defs.protocolVersion.const = protocolVersion + 1;
|
|
|
|
assert.throws(
|
|
() => readAcpxSidecarProtocolVersion(driftedSchema),
|
|
/must match its authoritative schema \$id/,
|
|
);
|
|
});
|
|
|
|
function error() {
|
|
return {
|
|
code: "runtime_failed",
|
|
message: "The runtime failed.",
|
|
retryable: false,
|
|
};
|
|
}
|