Merge pull request 'Serve a seat's verbs from the membership once one is issued (hq issue 218)' (#45) from fix/issue-218-the-membership-decides-the-seats into main
This commit was merged in pull request #45.
This commit is contained in:
@@ -342,13 +342,16 @@ async function serveClaimedSeats(
|
|||||||
for (const module of served) {
|
for (const module of served) {
|
||||||
const m = typeof broker.membership === "function" ? broker.membership(module) : undefined;
|
const m = typeof broker.membership === "function" ? broker.membership(module) : undefined;
|
||||||
for (const s of m?.seats ?? []) add({ seat: s.seat, verb: s.verb, subject: s.subject, holder: module });
|
for (const s of m?.seats ?? []) add({ seat: s.seat, verb: s.verb, subject: s.subject, holder: module });
|
||||||
// The credential's claims, for the module's own runtime: where the mesh issued the verb when
|
// The credential's claims, for the module's own runtime, ONLY until the mesh issues a
|
||||||
// it has; the derived shape until then.
|
// membership (novox/hq issue 218). The credential names what the module claims; the membership
|
||||||
if (module !== self) continue;
|
// names what it holds on this machine. A seat held once for the mesh is claimed by every
|
||||||
|
// machine running the module and held by one, so once a membership exists it decides: a claim
|
||||||
|
// it leaves out is not held here, and serving it anyway announced the seat from a machine the
|
||||||
|
// bus then refused it on.
|
||||||
|
if (module !== self || m) continue;
|
||||||
for (const claim of credential?.claims ?? []) {
|
for (const claim of credential?.claims ?? []) {
|
||||||
for (const verb of claim.serves ?? []) {
|
for (const verb of claim.serves ?? []) {
|
||||||
const subject = m?.seats?.find((s) => s.seat === claim.seat && s.verb === verb)?.subject
|
const subject = seatToolSubject(claim.seat, verb, claim.scope, credential?.node);
|
||||||
?? seatToolSubject(claim.seat, verb, claim.scope, credential?.node);
|
|
||||||
add({ seat: claim.seat, verb, subject, holder: module });
|
add({ seat: claim.seat, verb, subject, holder: module });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
// A copy for the issue 218 test: a fixture registers once per process, at import.
|
||||||
|
// A module that is both software and a role: postgres's own tools under its name, and its
|
||||||
|
// implementation of the mesh-store seat's verbs under the seat's (novox/hq ADR 0159, 0160).
|
||||||
|
import { registerModuleTools } from "@novox/mesh-sdk/tools";
|
||||||
|
|
||||||
|
registerModuleTools("postgres", () => [
|
||||||
|
{ name: "postgres_create_database", description: "make one", input: {}, run: async () => ({ made: true }) },
|
||||||
|
{ name: "databases", description: "postgres's own listing", input: {}, run: async () => ({ software: "postgres" }) },
|
||||||
|
]);
|
||||||
|
|
||||||
|
registerModuleTools("mesh-store", () => [
|
||||||
|
{ name: "databases", description: "what the store holds", input: {}, run: async () => ({ seat: "mesh-store" }) },
|
||||||
|
]);
|
||||||
@@ -140,6 +140,36 @@ test("a seat's verbs are implemented under the seat's name, served where issued,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// novox/hq issue 218: the store seat is claimed by every machine running postgres and held by one.
|
||||||
|
// Where the mesh issued a membership without the seat, the claim in the credential serves nothing:
|
||||||
|
// the module's own tools answer, the seat's verbs do not, and the runtime does not announce them.
|
||||||
|
test("a claimant the membership does not make the holder serves none of the seat's verbs", async (t) => {
|
||||||
|
if (!url) return t.skip("MESH_TEST_NATS unset");
|
||||||
|
resetTools();
|
||||||
|
const stream = await anAssignmentsStream();
|
||||||
|
await stream.issue({
|
||||||
|
node: "elsewhere",
|
||||||
|
module: "postgres",
|
||||||
|
serves: [{ subject: "mesh.mod.postgres.tool.{tool}.elsewhere" }],
|
||||||
|
emits: "mesh.mod.postgres.event.{event}",
|
||||||
|
tools: "mesh.mod.postgres.tool.tools",
|
||||||
|
});
|
||||||
|
const credential = { url, node: "elsewhere", module: "postgres", claims: [{ seat: "mesh-store", scope: "mesh", serves: ["databases", "query"] }] };
|
||||||
|
const pg = await connectNats(credential);
|
||||||
|
const asker = await connectNats({ url, module: "console", node: "workstation" });
|
||||||
|
let stop = () => {};
|
||||||
|
try {
|
||||||
|
stop = await runTools({ broker: pg, credential, moduleEntrypoints: [fixture("store-claimant.mjs")] });
|
||||||
|
assert.deepEqual((await callTool(asker, "postgres.databases@elsewhere", {})).result, { software: "postgres" });
|
||||||
|
await assert.rejects(callTool(asker, "seat:mesh-store.databases", {}), /no responders|503/i, "the store is not held here");
|
||||||
|
} finally {
|
||||||
|
stop();
|
||||||
|
await asker.close();
|
||||||
|
await pg.close();
|
||||||
|
await stream.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test("a module named like its seat registers once, and answers as the module and as the seat", async (t) => {
|
test("a module named like its seat registers once, and answers as the module and as the seat", async (t) => {
|
||||||
if (!url) return t.skip("MESH_TEST_NATS unset");
|
if (!url) return t.skip("MESH_TEST_NATS unset");
|
||||||
resetTools();
|
resetTools();
|
||||||
|
|||||||
Reference in New Issue
Block a user