From f2135607b20931c65e88fede53014a1346fa54ee Mon Sep 17 00:00:00 2001 From: godosa Date: Wed, 7 Oct 2026 20:09:02 +0200 Subject: res: queue coalesces same-lock gates on descendant commits Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01JEAjUkQRrCYX5MZhWxdtj2 --- tests/test_res_io.py | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) (limited to 'tests/test_res_io.py') diff --git a/tests/test_res_io.py b/tests/test_res_io.py index c30b21f..3d5b789 100644 --- a/tests/test_res_io.py +++ b/tests/test_res_io.py @@ -27,6 +27,7 @@ class Fake: self.scopes = {} # name → {prop: value} for agent session scopes self.manager_env = "PATH=/usr/bin\nHOME=/h/u\n" self.git = {} # git subcommand (branch | rev-parse) → stdout + self.real_git = False # True: git calls run for real (cwd = a synthetic repo) def __call__(self, argv): self.calls.append(list(argv)) @@ -34,6 +35,8 @@ class Fake: if key in self.fail: return subprocess.CompletedProcess(argv, 1, "", self.fail[key] + "\n") out = "" + if argv[0] == "git" and self.real_git: + return subprocess.run(argv, capture_output=True, text=True) if argv[:3] == ["systemctl", "--user", "show"]: blocks = [] for name in argv[5:]: @@ -685,6 +688,72 @@ class Robust(IOBase): self.assertEqual((code, err), (1, "wf: [Errno 13] Permission denied: '/proc/meminfo'\n")) +class CoalesceIO(IOBase): + """Batch of commits a ← b ← c, each queueing its gate (real repo): one queued gate per lock, on c.""" + + def setUp(self): + super().setUp() + repo = self.box.tmp / "proj" + git = lambda *a: subprocess.run(["git", "-C", str(repo), *a], check=True, capture_output=True, text=True).stdout + git("init", "-q", "-b", "master") + self.sha = {} + for c in ("a", "b", "c"): + git("-c", "user.name=t", "-c", "user.email=t@t", "commit", "-q", "--allow-empty", "-m", c) + self.sha[c] = git("rev-parse", "HEAD").strip() + git("checkout", "-q", "-b", "side", self.sha["a"]) + git("-c", "user.name=t", "-c", "user.email=t@t", "commit", "-q", "--allow-empty", "-m", "x") + self.sha["x"] = git("rev-parse", "HEAD").strip() + self.box.fake.real_git = True + + def gate(self, c, *extra): + return self.box.wf("run", "--queue", "--mem", "2G", "--for", "30m", "--title", f"gate {self.sha[c][:7]}", + *extra, "--", "x") + + def test_batch_yields_one_queued_gate(self): + self.box.wf("run", "--mem", "2G", "--for", "30m", "--title", "gate running", "--", "x") # r-1 holds the lock + self.assertEqual(self.gate("a")[0], 0) + self.box.tick(60) + self.gate("b") + self.box.tick(60) + code, out, _ = self.gate("c") + self.assertEqual(code, 0) + self.assertIn("r-4 queued, position 1 (lock held by r-1)", out) + self.assertIn("supersedes r-3", out) + led = self.box.ledger() + self.assertEqual([(e.id, e.commit) for e in led.entries if e.state == "queued"], [("r-4", self.sha["c"])]) + self.assertEqual(led.get("r-4").covers, [self.sha["a"], self.sha["b"]]) + self.assertEqual(led.get("r-4").queued, led.get("r-2").queued) + self.assertEqual([led.get(i).superseded_by for i in ("r-2", "r-3")], ["r-3", "r-4"]) # chain; wait follows it + code, out, _ = self.gate("b") # late ancestor: covered, nothing new + self.assertEqual(code, 0) + self.assertTrue(out.startswith("r-4 queued"), out) + self.assertIn(f"covers {self.sha['b'][:7]}", out) + self.assertEqual(len([e for e in self.box.ledger().entries if e.state == "queued"]), 1) + code, out, _ = self.gate("x") # side branch: own gate + self.assertTrue(out.startswith("r-5 queued"), out) + code, out, _ = self.box.wf("run", "--queue", "--mem", "2G", "--for", "30m", "--title", "gate", + "--commit", "master", "--", "x") + self.assertTrue(out.startswith("r-4 queued"), out) # --commit REV, no hex in title + self.assertNotEqual(self.box.wf("run", "--queue", "--mem", "2G", "--for", "30m", "--title", "gate", + "--commit", "nope", "--", "x")[0], 0) + + def test_wait_follows_superseded_and_red_names_range(self): + self.box.wf("run", "--mem", "2G", "--for", "30m", "--title", "gate running", "--", "x") + self.gate("a") + self.gate("c") + self.box.fake.units["wf-r-1.service"] = ("inactive", None) + self.box.wf("status") # r-3 starts + logs = self.box.env.state / "logs" + logs.mkdir(parents=True, exist_ok=True) + (logs / "r-3.rc").write_text("1\n") + self.box.fake.units["wf-r-3.service"] = ("inactive", None) + code, out, _ = self.box.wf("wait", "r-2") + self.assertEqual(code, 0) + self.assertIn("r-2 superseded by r-3", out) + self.assertIn(f"r-3 done rc=1", out) + self.assertIn(f"{self.sha['a'][:7]}^..{self.sha['c'][:7]}", out) + + if __name__ == "__main__": unittest.main() -- cgit