From 945158772877a5d2b17e866b43ba12cdb8785375 Mon Sep 17 00:00:00 2001 From: ScottW514 Date: Fri, 16 Oct 2026 14:44:40 -0400 Subject: [PATCH] setup.focus: the test's own sysfs reads go on record however the burn ends, and their tube-current check has a case emission_seen, the two peaks the test reads from sysfs at every poll and the count of polls that read both, was written inside emission_ok after the three checks of the burn's result. A burn the daemon reports dark fails at the first of them (Context.check raises), and a burn that ends in a wizard error, a timeout or an abort never reaches emission_ok. On each of those paths the record kept the daemon's word alone, where the test's own reading is the one worth comparing with it. burn() now records emission_seen, and logs it, in the finally of its run_check, so it is on record however the burn ends. emission_ok keeps its checks, in their order. The check that the tube current read over HV_ON from here had no case that could fail it: the one negative case reads both attributes at 0 and stops at the LASER_ON check, which comes first. A new case reads the LASER_ON count nonzero and the tube current at 0, and fails on the tube current. Proof: tests/test_setup_burns.py, the Unit tests step of forgetest-ci.yml (python -B -m unittest discover -s tests), 23 tests OK on Windows with python 3.14 and on Ubuntu 24.04 with python 3.12, with tests/test_setup_dark.py (20 OK): test_a_burn_whose_tube_current_the_test_never_saw_rise_fails (cnc/laser_on_sampled 118, pic/hv_current 0: Failed "the tube current never read over 30 from here", the settings as found); test_a_dark_burn_fails_and_still_restores finds emission_seen at 118 and 431 beside the dark result; the aborted burn's record carries emission_seen too. run_test keeps the Run of a test that fails. Negative controls on scratch copies: the tube-current check made vacuous (True or ...) fails the new case (Failed not raised); setup_burns.py as it was fails the dark case (no emission_seen) and the aborted case. pyflakes reports no undefined name. Acceptance: setup.focus's fingerprint moves (setup_burns.py's shared text); no other test moves (source_sha compared before and after). Against the campaign this series already needs, that adds no run: 850498f moved all 43 once. --- forgetest/forgetest/suite/setup_burns.py | 9 ++++++--- forgetest/tests/test_setup_burns.py | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/forgetest/forgetest/suite/setup_burns.py b/forgetest/forgetest/suite/setup_burns.py index 265d608..cc5fd0f 100644 --- a/forgetest/forgetest/suite/setup_burns.py +++ b/forgetest/forgetest/suite/setup_burns.py @@ -176,9 +176,6 @@ def emission_ok(ctx, last, seen): "the result does not record the beam sensor: %s", e) ctx.log("the beam sensor rose %s (seen: %s)", e.get("thermopile_delta"), e.get("beam_sensor_seen")) w = seen.record() - ctx.evidence["emission_seen"] = w - ctx.log("seen from here: LASER_ON count peak %s, tube current peak %s over %d polls", - w["laser_on_max"], w["hv_max"], w["reads"]) ctx.check(w["reads"] > 0, "the test could not read the witnesses from sysfs during the burn") ctx.check((w["laser_on_max"] or 0) > 0, "the kernel's LASER_ON count never read nonzero from here during the burn (%d reads); the " @@ -231,6 +228,12 @@ def burn(ctx, wid, arm, pick, want): last = run_check(ctx, wid, on_prompt, 900, on_poll=seen) finally: ctx.clear_notice() + # What the test read itself goes on record however the burn ends: + # reported dark, failed, timed out, or aborted. + w = seen.record() + ctx.evidence["emission_seen"] = w + ctx.log("seen from here: LASER_ON count peak %s, tube current peak %s over %d polls", + w["laser_on_max"], w["hv_max"], w["reads"]) emission_ok(ctx, last, seen) r = last.get("result") or {} missing = [k for k in want if k not in r] diff --git a/forgetest/tests/test_setup_burns.py b/forgetest/tests/test_setup_burns.py index 7d9e9bc..3dfdc2a 100644 --- a/forgetest/tests/test_setup_burns.py +++ b/forgetest/tests/test_setup_burns.py @@ -314,7 +314,7 @@ class BurnRunTests(unittest.TestCase): def run_test(self, tid): t = catalog.load_suite()[tid] - run = Run("test", t.id, t.title) + run = self.run = Run("test", t.id, t.title) # kept for a run that fails run.unattended = True # the ready gate passes; the arm cue is a notice t.fn(Context(run, None, t)) return run @@ -434,6 +434,9 @@ class BurnRunTests(unittest.TestCase): with self.assertRaises(Failed) as cm: self.run_test("setup.focus") self.assertIn("the tube current never rose", str(cm.exception)) + # what the test read itself is on record beside the daemon's word + seen = self.run.evidence["emission_seen"] + self.assertEqual((seen["laser_on_max"], seen["hv_max"]), (118, 431)) self.assert_found() def test_a_head_off_its_home_fails_before_any_start(self): @@ -469,6 +472,15 @@ class BurnRunTests(unittest.TestCase): self.assert_found() self.assert_restarted_on_found() + def test_a_burn_whose_tube_current_the_test_never_saw_rise_fails(self): + # The LASER_ON count read nonzero from here, and the tube current + # never left zero: the second witness is judged on its own reads. + self.plant("pic/hv_current", "0") + with self.assertRaises(Failed) as cm: + self.run_test("setup.focus") + self.assertIn("tube current never read over %d from here" % setup_burns.HV_ON, str(cm.exception)) + self.assert_found() + def test_a_burn_with_a_silent_beam_sensor_passes(self): # A head whose beam sensor gives no output: the tube current and # LASER_ON saw the beam, so the burn counts. @@ -511,6 +523,7 @@ class BurnRunTests(unittest.TestCase): with self.assertRaises(Aborted): t.fn(Context(run, None, t)) self.assertEqual(self.daemon.aborted, ["laser.focus"]) + self.assertIn("emission_seen", run.evidence) # the test's own reads, on record all the same self.assert_found() self.assert_restarted_on_found()