forgetest: a press the fixture could not make leaves a notice that comes down at the press

press_now and arm_press hand the arm press to the operator when the
bench actuator refuses it (the box is off) or when the button never
lights for it within the arm wait, and put the notice up for a person.
Those three fallbacks raised the notice without the watch that takes
it down at the press, so the notice stood until the test's next step:
the second-press hazard the watch exists for, because a press during
the job pauses it. Each fallback now calls _clear_when_taken() after
its notice, so the notice comes down the moment the controller takes
the press, as the operator's own path does. No press, judge, or energy
path changes.

Proof: forgetest-ci "Unit tests" (`python -B -m unittest discover -s
tests -v` in forgetest), on Ubuntu 24.04 with python 3.12:
test_fixture.py's test_the_arm_notice_comes_down_when_the_press_is_taken
gains the leg where the fixture cannot press: press_now's notice for a
refused press, arm_press's notice for a refused press, and arm_press's
notice for a button that never lit each come down within 2 s of the
press. Three runs OK, the file's 21 tests OK. Negative control on a
scratch copy: the leg against the runner without the three calls fails
at the first press, the notice still standing. pyflakes reports no
undefined name.

Acceptance: every catalog test's fingerprint moves: runner.py is a
shared judge, in every implementation hash (43 of 43 move). Against
the campaign this series already needs, that adds no run: 850498f
moved all 43 once. tests/ are in none.
This commit is contained in:
ScottW514
2026-10-15 18:06:36 -04:00
parent 3d2f2d9ab4
commit a596767a9a
2 changed files with 35 additions and 0 deletions
+3
View File
@@ -485,6 +485,7 @@ class Context:
rec["fixture_error"] = str(e) rec["fixture_error"] = str(e)
self.log("ARM press: fixture failed (%s) - asking the operator", e) self.log("ARM press: fixture failed (%s) - asking the operator", e)
self.notice(text) self.notice(text)
self._clear_when_taken()
return False return False
rec["by"] = "fixture" rec["by"] = "fixture"
self.log("ARM press by the fixture, at the machine's own press prompt") self.log("ARM press by the fixture, at the machine's own press prompt")
@@ -566,6 +567,7 @@ class Context:
if lit is None: if lit is None:
self.log("ARM: the button never lit within %d s - asking the operator", lit_timeout) self.log("ARM: the button never lit within %d s - asking the operator", lit_timeout)
self.notice(text) self.notice(text)
self._clear_when_taken()
return return
try: try:
fixture.act("button", "press") fixture.act("button", "press")
@@ -573,6 +575,7 @@ class Context:
self.log("ARM press: fixture failed (%s) - asking the operator", e) self.log("ARM press: fixture failed (%s) - asking the operator", e)
rec["fixture_error"] = str(e) rec["fixture_error"] = str(e)
self.notice(text) self.notice(text)
self._clear_when_taken()
return return
rec["by"] = "fixture" rec["by"] = "fixture"
rec["took_s"] = round(lit, 2) rec["took_s"] = round(lit, 2)
+32
View File
@@ -594,6 +594,38 @@ class RoutingTests(unittest.TestCase):
time.sleep(0.02) time.sleep(0.02)
self.assertFalse(watching()) self.assertFalse(watching())
self.assertIsNotNone(run.notice) # the finished run's notice is left as it was self.assertIsNotNone(run.notice) # the finished run's notice is left as it was
# A press the fixture could not make is asked of the operator, and
# that notice comes down at the press like any other: press_now and
# arm_press with the box refusing, and arm_press with the button
# never lit for the box.
self.stub.arm_press = True
self.stub.fail = True
run = Run("test", "r.live", "r.live")
ctx = Context(run, self.runner, self.reg["r.live"])
def settles(up):
deadline = time.time() + 2
while (run.notice is not None) != up and time.time() < deadline:
time.sleep(0.02)
return (run.notice is not None) == up
lit["v"] = True # the machine waits for the press
self.assertFalse(ctx.press_now()) # the box is off: the operator is asked
self.assertIsNotNone(run.notice)
time.sleep(0.2) # lit: the arm waits for the press
lit["v"] = False # the operator's press is taken
self.assertTrue(settles(False))
lit["v"] = True
self.assertTrue(ctx.arm_press()) # the fixture is asked, and refuses
self.assertTrue(settles(True))
time.sleep(0.2)
lit["v"] = False
self.assertTrue(settles(False))
self.assertTrue(ctx.arm_press(lit_timeout=0)) # the button never lit for the fixture
self.assertTrue(settles(True))
lit["v"] = True
time.sleep(0.2)
lit["v"] = False
self.assertTrue(settles(False))
finally: finally:
runner_mod.hw.button_lit = saved runner_mod.hw.button_lit = saved