diff --git a/forgetest/forgetest/runner.py b/forgetest/forgetest/runner.py index 27cd4fe..75f6db5 100644 --- a/forgetest/forgetest/runner.py +++ b/forgetest/forgetest/runner.py @@ -464,8 +464,9 @@ class Context: The fixture presses where the bench took this test's presses (or opted in standing); otherwise the notice goes up for a person, - who is looking at the same prompt. Returns True when the fixture - pressed.""" + who is looking at the same prompt. A press the fixture reports + failed while the button went out was taken all the same, and no + notice goes up for it. Returns True when the fixture pressed.""" fixture = getattr(self.runner, "fixture", None) if self.runner is not None else None rec = {"channel": "button", "state": "arm", "by": "operator", "ts": now_ts()} self.evidence.setdefault("actions", []).append(rec) @@ -483,6 +484,8 @@ class Context: fixture.act("button", "press") except _fixture.FixtureError as e: rec["fixture_error"] = str(e) + if self._press_taken(rec, e): + return True self.log("ARM press: fixture failed (%s) - asking the operator", e) self.notice(text) self._clear_when_taken() @@ -491,6 +494,20 @@ class Context: self.log("ARM press by the fixture, at the machine's own press prompt") return True + def _press_taken(self, rec, err): + """After the box reported a failed press of a lit button: True when + the button is out, so the controller took a press (the box pressed + and its reply was lost). The press is recorded as the box's, and + no notice goes up, because it would ask for a second press, and a + press during the job pauses it. A button still lit, or unreadable, + is False: the operator is asked.""" + if hw.button_lit() is not False: + return False + rec["by"] = "fixture" + self.log("ARM press: the fixture reported a failure (%s), and the button is out: the press " + "was taken; no notice", err) + return True + def _clear_when_taken(self, lit_timeout=ARM_LIT_WAIT_S): """Take the arm notice down the moment the press is taken: the controller lights the button white for its arm wait and puts it out @@ -541,8 +558,9 @@ class Context: seconds for the button to light (the job may still be on its way to the arm wait; a card that settles the coolant first takes minutes) and presses once, recorded as the fixture's; if the - button never lights or the press fails, the notice goes up for a - person. Returns True when the fixture has been asked.""" + button never lights, or the press fails with the button still lit, + the notice goes up for a person. Returns True when the fixture has + been asked.""" fixture = getattr(self.runner, "fixture", None) if self.runner is not None else None rec = {"channel": "button", "state": "arm", "by": "operator", "ts": now_ts()} self.evidence.setdefault("actions", []).append(rec) @@ -572,8 +590,11 @@ class Context: try: fixture.act("button", "press") except _fixture.FixtureError as e: - self.log("ARM press: fixture failed (%s) - asking the operator", e) rec["fixture_error"] = str(e) + if self._press_taken(rec, e): + rec["took_s"] = round(lit, 2) + return + self.log("ARM press: fixture failed (%s) - asking the operator", e) self.notice(text) self._clear_when_taken() return diff --git a/forgetest/tests/test_fixture.py b/forgetest/tests/test_fixture.py index 9f7d2ae..a0ad57a 100644 --- a/forgetest/tests/test_fixture.py +++ b/forgetest/tests/test_fixture.py @@ -626,6 +626,25 @@ class RoutingTests(unittest.TestCase): time.sleep(0.2) lit["v"] = False self.assertTrue(settles(False)) + # A press the box made and reported failed (its reply lost after + # the press): the button is out when the error arrives, so the + # press was taken, and no notice asks for a second one. + def pressed_then_failed(channel, state, ms=None): + lit["v"] = False # the controller takes the press + raise fx.FixtureError("timed out") + self.stub.act = pressed_then_failed + lit["v"] = True + self.assertTrue(ctx.press_now()) + self.assertIsNone(run.notice) + self.assertEqual(ctx.evidence["actions"][-1]["by"], "fixture") + lit["v"] = True + self.assertTrue(ctx.arm_press()) + deadline = time.time() + 2 + while ctx.evidence["actions"][-1]["by"] != "fixture" and time.time() < deadline: + time.sleep(0.02) + time.sleep(0.1) + self.assertEqual(ctx.evidence["actions"][-1]["by"], "fixture") + self.assertIsNone(run.notice) finally: runner_mod.hw.button_lit = saved