testParallelChecksMatchOneAtATime
Checking what's received in several checker processes at once stores what checking it in one does, and still rejects tampered source among many.
import { plainEnv, tcmBin, tempDir, withChildren } from "#codebase/tcmts/cli/test/e2e/harness"; import { codebase } from "#codebase/tcmts/cli/test/e2e/sync"; import assert from "node:assert/strict"; import { spawn } from "node:child_process"; import fs from "node:fs"; import path from "node:path"; export const testParallelChecksMatchOneAtATime = () => withChildren(async (keep) => { const root = tempDir("sync parallel"); // a server checking in 4 processes, and one checking itself const serve = async (name: string, checkers: string) => { const s = codebase(root, name); fs.rmSync(path.join(s.dir, "scratch.ts")); const child = keep( spawn(process.execPath, [tcmBin(), "serve", "--port", "0", "--token", "tok"], { cwd: s.dir, env: { ...plainEnv(), TCM_CHECKERS: checkers }, }), ); let out = ""; child.stdout!.setEncoding("utf8").on("data", (d: string) => (out += d)); const url = await new Promise<string>((resolve, reject) => { const check = () => { const m = /url\s+(https?:\/\/[\d.]+:\d+)/.exec(out); if (m) resolve(m[1]!); else if (child.exitCode !== null) reject(new Error(out)); else setTimeout(check, 20); }; check(); }); return { url, log: () => out }; }; const many = await serve("many", "4"); const one = await serve("one", "1"); // 90 components using each other (and a type, a class, a function) across any cut into runs const a = codebase(root, "a"); const defs = [ "// tcm: namespace lib", "export type Point = { x: number; y: number };", "export class Box { p: Point; constructor(p: Point) { this.p = p; } size(): number { return this.p.x * this.p.y; } }", "export const v0 = (p: Point): number => new Box(p).size();", ...Array.from( { length: 87 }, (_, i) => `export const v${i + 1} = (p: Point): number => v${i}(p) + ${i} /* ${i} */;`, ), ]; a.scratch(defs.join("\n") + "\n"); a.tcm("add"); a.tcm("remote", "add", "many", many.url, "--token", "tok"); a.tcm("remote", "add", "one", one.url, "--token", "tok"); assert.match(a.tcm("push", "many"), /sent 90 definition\(s\)/); assert.match(a.tcm("push", "one"), /sent 90 definition\(s\)/); await new Promise((r) => setTimeout(r, 200)); assert.match(many.log(), /received 90 definition\(s\), checked by [2-4] processes/); assert.match(one.log(), /received 90 definition\(s\)\n/); const call = async (base: string, route: string, body: unknown) => (await ( await fetch(`${base}/${route}`, { method: "POST", headers: { authorization: "Bearer tok" }, body: JSON.stringify(body), }) ).json()) as any; const hashes = (await call(many.url, "branch", { name: "main" })).branch.names.map( (n: { hash: string }) => n.hash, ); const stored = async (base: string) => new Map( ((await call(base, "get", { hashes })).records as Record<string, unknown>[]).map((r) => [ r.hash, JSON.stringify([r.ir, r.deps, r.signature, r.shape, r.componentHash, r.componentIndex]), ]), ); const [fromMany, fromOne] = [await stored(many.url), await stored(one.url)]; assert.equal(fromMany.size, 90); assert.deepEqual(fromMany, fromOne, "the same, checked either way"); // and one tampered among many is still caught, by whichever process checks it const third = await serve("third", "4"); const records = (await call(many.url, "get", { hashes })).records as { hash: string; sourceText: string; }[]; const evil = records.map((r, i) => i === 70 ? { ...r, sourceText: r.sourceText.replace("/* ", "/* tampered ").replace(/\+ \d+/, "+ 1000"), } : r, ); const res = await fetch(`${third.url}/put`, { method: "POST", headers: { authorization: "Bearer tok" }, body: JSON.stringify({ records: evil }), }); assert.equal(res.status, 400); assert.match( ((await res.json()) as { error: string }).error, /source does not match their hashes/, ); })