forgetest: the update drill reads the daemon's reply, and a queue start waits for the fixture probe

update.slots-and-signature's apply section required 200 from
POST /update/apply, where the daemon answers 202 with started, like
every job endpoint, so its first bench run on image 20260902144848
ended before the job did; the cleanup then deleted the staged archive
under the running job. The drill requires 202 and started, and looks
for the daemon's refusal ("archive is not signed with the ForgeFIRM
release key"). Bench: the apply started, the job ended with that
refusal, PASS.

A queue started 4 s after a forgetest restart ran 7 tests instead of
10. The bench page's /state poll had a fixture probe in flight (an mDNS
answer), probe_fixture stamped its time at its start, and the queue
start read the stale fixture, none, so the three operator tests the
fixture runs in the unattended queue were routed to nobody. The probe
now runs under a lock and is stamped when it completes: a caller that
arrives during a probe waits for its answer. tests/test_fixture.py
holds the race with a slow scripted probe; it fails on the old code.

Catalog consequence: the update implementation hash moves; the runner
change is dev-only.
This commit is contained in:
ScottW514
2026-09-02 17:02:33 -04:00
parent 1fef9c6f51
commit 7605a90946
3 changed files with 46 additions and 20 deletions
+2 -1
View File
@@ -96,7 +96,8 @@ def slots_and_signature(ctx):
ctx.log("slot %s is selected for the next boot: the apply is refused before the "
"signature check, which is its own guard", target)
else:
ctx.check(st == 200, "the apply job did not start: %s %s", st, body)
ctx.check(st == 202 and isinstance(body, dict) and body.get("started") is True,
"the apply job did not start: %s %s", st, body)
result = None
t0 = time.time()
while time.time() - t0 < 60: