Row 93 follow-up: SIGTERM then SIGKILL for host git, rollback-failed, a total body deadline, fetch-aborted for a reviewer gone mid-fetch, working refs first in have, and tests for five untested refusals. Dewey approved in 28226 and Sage in 28225; Sage's full gate passed 16:57:32-17:01:32Z. The host side is live at the next bus restart. Co-Authored-By: Claude Opus 5.5 <[email protected]>
81 lines
3.6 KiB
JavaScript
81 lines
3.6 KiB
JavaScript
// The runner's git tools (src/git-tools.mjs) against a fake git socket that
|
|
// records the request line. The review loop over the real host's socket is in
|
|
// packages/cli/tests/git-socket.test.mjs.
|
|
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { spawnSync } from "node:child_process";
|
|
import { mkdirSync } from "node:fs";
|
|
import { createServer } from "node:net";
|
|
import { join } from "node:path";
|
|
import { fetchReview, HAVE_MAX } from "../src/git-tools.mjs";
|
|
import { scratch } from "./helpers.mjs";
|
|
|
|
const ENV = { PATH: process.env.PATH, HOME: "/nonexistent", GIT_CONFIG_NOSYSTEM: "1", GIT_CONFIG_GLOBAL: "/dev/null", LC_ALL: "C" };
|
|
|
|
function git(cwd, args, extra = {}) {
|
|
const r = spawnSync("git", ["-c", "user.name=t", "-c", "[email protected]", "-C", cwd, ...args], { env: { ...ENV, ...extra }, encoding: "utf8" });
|
|
assert.equal(r.status, 0, `git ${args.join(" ")}: ${r.stderr}`);
|
|
return r.stdout.trim();
|
|
}
|
|
|
|
// A clone at `dir` with `refs` (name -> commit time) pointing at commits of
|
|
// their own.
|
|
function clone(dir, refs) {
|
|
mkdirSync(dir, { recursive: true });
|
|
git(dir, ["init", "-q"]);
|
|
const tree = git(dir, ["mktree"]);
|
|
const oids = {};
|
|
for (const [name, time] of Object.entries(refs)) {
|
|
const date = `${time} +0000`;
|
|
oids[name] = git(dir, ["commit-tree", tree, "-m", name], { GIT_AUTHOR_DATE: date, GIT_COMMITTER_DATE: date });
|
|
git(dir, ["update-ref", name, oids[name]]);
|
|
}
|
|
return oids;
|
|
}
|
|
|
|
// A socket that keeps each request line and refuses it.
|
|
async function fakeHost(t, dir) {
|
|
const path = join(dir, "git.sock");
|
|
const lines = [];
|
|
const server = createServer((s) => {
|
|
let buf = "";
|
|
s.on("data", (b) => {
|
|
buf += b;
|
|
if (!buf.includes("\n")) return;
|
|
lines.push(JSON.parse(buf.split("\n")[0]));
|
|
s.end(`${JSON.stringify({ ok: false, error: "request-not-found" })}\n`);
|
|
});
|
|
});
|
|
await new Promise((r) => server.listen(path, r));
|
|
t.after(() => new Promise((r) => server.close(r)));
|
|
return { path, lines };
|
|
}
|
|
|
|
test("fetch_review's have lists the working refs before origin's, and no more than HAVE_MAX", async (t) => {
|
|
const dir = scratch(t);
|
|
const workspace = join(dir, "ws");
|
|
// 40 origin refs, newer than every working ref, and 13 working refs in two
|
|
// clones: 53 in all.
|
|
const stack = {};
|
|
for (let i = 0; i < 40; i++) stack[`refs/remotes/origin/b${i}`] = 1_800_000_000 + i;
|
|
for (let i = 1; i <= 10; i++) stack[`refs/remotes/working/work/vikunja-1-${i}`] = 1_700_000_000 + i;
|
|
const other = {};
|
|
for (let i = 1; i <= 3; i++) other[`refs/remotes/working/work/vikunja-2-${i}`] = 1_700_000_000 + i;
|
|
const a = clone(join(workspace, "stack"), stack);
|
|
const b = clone(join(workspace, "other"), other);
|
|
const host = await fakeHost(t, dir);
|
|
await assert.rejects(fetchReview({ path: host.path, cap: "c".repeat(64), workspace, task_ref: "vikunja:1/2", request: "r1", tmp: dir, env: ENV }), (e) => e.code === "request-not-found");
|
|
const [req] = host.lines;
|
|
assert.equal(req.op, "fetch");
|
|
assert.equal(HAVE_MAX, 32);
|
|
assert.equal(req.have.length, HAVE_MAX);
|
|
assert.equal(new Set(req.have).size, HAVE_MAX);
|
|
const working = [...Object.entries(a), ...Object.entries(b)].filter(([n]) => n.startsWith("refs/remotes/working/")).map(([, oid]) => oid);
|
|
assert.equal(working.length, 13);
|
|
// Every working ref, ahead of any of origin's.
|
|
assert.deepEqual(new Set(req.have.slice(0, 13)), new Set(working));
|
|
const origin = new Set(Object.entries(a).filter(([n]) => n.startsWith("refs/remotes/origin/")).map(([, oid]) => oid));
|
|
for (const oid of req.have.slice(13)) assert.ok(origin.has(oid), oid);
|
|
});
|