From 8dc7c0bc56582aa1be20de7157ea6d09c27f7e1d Mon Sep 17 00:00:00 2001 From: ScottW514 Date: Fri, 25 Sep 2026 19:05:17 -0400 Subject: [PATCH] forgetest: the stale boot reference judged at a held uptime, on both sides of the limit test_stale_preconfig_reference_is_retaken_on_a_fresh_boot read the host's uptime after boot_reference() had read it to decide, and expected the decision its own reading implied. On a CI runner the uptime crossed BOOT_MAX_AGE_S (600 s) between the two readings: boot_reference retook the reference and the test expected the stale one (forgetest-ci on 0eb0a16). The test now holds uptime_s() at 60 s under and over the limit and judges both answers: retaken with the fresh sysfs under it, the stale reference kept and marked over it. Proof: test_baseline passes on Windows and on Linux; with boot_reference() ignoring the uptime (a planted fault) the test fails in all three classes that run it. --- forgetest/tests/test_baseline.py | 33 +++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/forgetest/tests/test_baseline.py b/forgetest/tests/test_baseline.py index aac783f..a6a298a 100644 --- a/forgetest/tests/test_baseline.py +++ b/forgetest/tests/test_baseline.py @@ -434,22 +434,29 @@ class BaselineTests(unittest.TestCase): "forgectrl": {"/settings": {"xy_microsteps": "16"}}})) def test_stale_preconfig_reference_is_retaken_on_a_fresh_boot(self): + # Both sides of BOOT_MAX_AGE_S, with the uptime held: read from the host, it can cross the limit + # between boot_reference()'s reading and the test's (it did, on a CI runner 600 s after its boot). os.environ["FORGETEST_BOOT_ID"] = "test-boot-2" + real = baseline.uptime_s try: - path = os.path.join(self.tmp, "boot-test-boot-2.json") - with open(path, "w") as f: - json.dump({"ts": "old", "sysfs": {"cnc/motor_lock": "0", "cnc/step_freq": "10000", - "cnc/y_mode": "1"}}, f) - ref = baseline.boot_reference(self.lines.append, self.tmp) - up = baseline.uptime_s() - if up is None or up > baseline.BOOT_MAX_AGE_S: - # too old to retake: the stale reference stands, marked - self.assertTrue(any("predates the controller's config" in l for l in self.lines)) - self.assertEqual(ref["ts"], "old") - else: - self.assertTrue(any("retaking" in l for l in self.lines)) - self.assertEqual(ref["sysfs"]["cnc/motor_lock"], "0") + for up, fresh in ((baseline.BOOT_MAX_AGE_S - 60, True), (baseline.BOOT_MAX_AGE_S + 60, False)): + self.lines.clear() + path = os.path.join(self.tmp, "boot-test-boot-2.json") + with open(path, "w") as f: + json.dump({"ts": "old", "sysfs": {"cnc/motor_lock": "0", "cnc/step_freq": "10000", + "cnc/y_mode": "1"}}, f) + baseline.uptime_s = lambda up=up: up + ref = baseline.boot_reference(self.lines.append, self.tmp) + if fresh: + self.assertTrue(any("retaking" in l for l in self.lines), self.lines) + self.assertNotEqual(ref["ts"], "old") + self.assertEqual(ref["sysfs"]["cnc/motor_lock"], "0") + else: + # too old to retake: the stale reference stands, marked + self.assertTrue(any("predates the controller's config" in l for l in self.lines), self.lines) + self.assertEqual(ref["ts"], "old") finally: + baseline.uptime_s = real os.environ.pop("FORGETEST_BOOT_ID", None)