Files
mesh-catalog/modules/gitea/test/announcing.test.ts
T
jochen 1dca181e03
mesh/merge-gate pass: builds gitea → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery superseded: a newer delivery to the same trunk took over its walk
Put every repository path through the segment helper, gitea_open_pulls's included
After merging #159 (issue 347): every /repos/<owner>/<name> the client builds
now takes its owner and name through one helper, whether they came from a
caller or from the forge's answer; the open-pulls fixture's shas are commits.
2026-10-09 13:41:35 +02:00

92 lines
5.0 KiB
TypeScript

import assert from "node:assert/strict";
import { test } from "node:test";
import { createServer } from "node:http";
// **A pull request opened after its push is still checked** (novox/hq issue 347). The announcer read only the
// repositories whose update time moved since its last pass, less a minute's margin; opening, reopening or
// retargeting a pull request does not move a repository's update time, so a pull request opened more than a
// minute or so after its push was never announced, never checked, and nothing said so.
const repo = (full: string, updated: string) => {
const [owner, name] = full.split("/");
return { full_name: full, owner, name, private: false, html_url: "", updated_at: updated };
};
test("a pull request opened after the margin is looked at, by its own update time", async () => {
const { reposToLook } = await import("../pulls.ts");
const pushed = "2026-10-09T10:00:00Z"; // the branch pushed: the repository's update time
// The pull request opened two minutes later; the last pass was at 10:02:30, so the floor is 10:01:30.
const floor = "2026-10-09T10:01:30Z";
const repos = [repo("novox/mesh-sdk", pushed), repo("novox/hq", "2026-10-09T09:00:00Z")];
const opened = [{ owner: "novox", name: "mesh-sdk", updated_at: "2026-10-09T10:02:00Z" }];
assert.deepEqual(reposToLook(repos, floor, opened, false).map((r) => r.full_name), ["novox/mesh-sdk"],
"the repository of a pull request updated since the floor, though the repository itself did not move");
assert.deepEqual(reposToLook(repos, floor, [], false).map((r) => r.full_name), [],
"without the pull request's own time nothing is looked at — the fault");
assert.deepEqual(reposToLook(repos, floor, [], true).map((r) => r.full_name).sort(), ["novox/hq", "novox/mesh-sdk"],
"a sweep looks at every repository");
assert.deepEqual(reposToLook(repos, "", [], false).length, 2, "the first pass looks at every repository");
});
test("every open pull request is read with what its base requires and what its head has (gitea_open_pulls)", async () => {
const { GiteaClient } = await import("../client.ts");
const asked: string[] = [];
const server = createServer((req, res) => {
asked.push(req.url ?? "");
const url = req.url ?? "";
const send = (v: unknown) => res.end(JSON.stringify(v));
if (url.startsWith("/api/v1/repos/issues/search")) {
return send(url.includes("page=1") ? [
{ number: 243, repository: { owner: "novox", name: "hq", full_name: "novox/hq" }, updated_at: "2026-10-09T11:00:00Z" },
{ number: 14, repository: { owner: "novox", name: "mesh-sdk", full_name: "novox/mesh-sdk" } },
] : []);
}
if (url.startsWith("/api/v1/repos/novox/hq/pulls/243")) {
return send({ number: 243, state: "open", base: { ref: "main" }, head: { ref: "x", sha: "aaa1111" }, html_url: "h" });
}
if (url.startsWith("/api/v1/repos/novox/mesh-sdk/pulls/14")) {
return send({ number: 14, state: "open", base: { ref: "main" }, head: { ref: "y", sha: "bbb2222" }, html_url: "s" });
}
if (url.startsWith("/api/v1/repos/novox/hq/branch_protections")) {
return send([{ rule_name: "main", enable_status_check: true, status_check_contexts: ["mesh/repo-check"] }]);
}
if (url.startsWith("/api/v1/repos/novox/mesh-sdk/branch_protections")) {
return send([{ rule_name: "main", enable_status_check: true, status_check_contexts: ["mesh/merge-gate", "mesh/repo-check"] }]);
}
if (url.includes("/commits/aaa1111/status")) return send({ statuses: [] });
if (url.includes("/commits/bbb2222/status")) return send({ statuses: [{ context: "mesh/merge-gate", status: "pending" }] });
res.statusCode = 404;
res.end("{}");
});
await new Promise<void>((r) => server.listen(0, r));
const client = new GiteaClient(`http://127.0.0.1:${(server.address() as any).port}`, "t");
try {
const open = await client.openPulls();
assert.deepEqual(open.map((p) => [p.owner, p.repo, p.number, p.base, p.head_sha, p.required, p.statuses]), [
["novox", "hq", 243, "main", "aaa1111", ["mesh/repo-check"], []],
["novox", "mesh-sdk", 14, "main", "bbb2222", ["mesh/merge-gate", "mesh/repo-check"], ["mesh/merge-gate"]],
]);
} finally {
server.close();
}
});
test("a pull request or issue number that is not one is refused before the forge is asked", async () => {
const { GiteaClient } = await import("../client.ts");
let asked = 0;
const server = createServer((_req, res) => {
asked++;
res.end("{}");
});
await new Promise<void>((r) => server.listen(0, r));
const client = new GiteaClient(`http://127.0.0.1:${(server.address() as any).port}`, "t");
try {
await assert.rejects(client.getPullRequest("novox", "hq", Number(undefined)), /whole number/);
await assert.rejects(client.addComment("novox", "hq", 0, "x"), /whole number/);
await assert.rejects(client.listPullFiles("novox", "hq", 1.5), /whole number/);
assert.equal(asked, 0, "the forge was asked about pulls/NaN");
} finally {
server.close();
}
});