forgetest: the burns, the lens and the intake checks follow forgectrl's review fixes

- baseline: the lid lamp fades to a new level (the kernel's smooth
  trigger), so the hand-back reads it until it holds the wanted level
  twice in a row, for up to 3 s, before it is a leftover.
  motion.deadman failed its hand-back reading 232 against 236 0.05 s
  after the supervisor re-applied 236 to a respawned controller.
- setup.check-lens and setup.focus: grblHAL reads the lens window and
  the edge only at its start, and their restore came after the wizard
  had restarted the controller on the test's values. Each test now waits
  for the step to end, puts the settings back, and restarts the
  controller (stop, start, running and verified with a new pid) on every
  exit path; cloud mode restarts nothing.
- setup.focus and setup.floor: the served program ends with G0 Z<edge>,
  G0 X0 Y0, G92.1, M2; setup.floor requires setup.focus and checks the
  scrap's thickness against the lens reach; the burns cover lenshome.
- setup.check-intakes: the two assertions that could not fail are gone;
  an intake-count prompt fails the test unanswered (the bench
  reference's intakes both turn). The precheck's refusal names no
  setting.
- setup.check-airflow: the machine's count rules (intake 2 turning
  writes 2; silent on a one-fan machine, the count is not written).

Shared text: setup_dark.py's precheck string (all setup_dark tests,
setup_burns, setup.check-envelope), setup_burns.py's imports, covers,
docstring and preview check, cooling_intake.py's docstring; every test
they move covers paths forgectrl changed in the same work.

Proof: the forgetest host suite passes (548), with new host tests for
the lamp's fade, the restarts on pass, fail and abort, the floor's Focus
refusal and reach, the tail without G92.1, the intakes prompt, and the
airflow count rules; pyflakes is clean on the changed modules.

Acceptance: these are the tests.
This commit is contained in:
ScottW514
2026-10-12 19:53:20 -04:00
parent 005ff8008b
commit 4c5dde2549
7 changed files with 666 additions and 146 deletions
+54
View File
@@ -686,11 +686,65 @@ class BaselineModeTests(BaselineTests):
import helpers
self.fc = helpers.FakeForgectrl().start()
baseline.Baseline._unreachable_until = 0.0
# the lamp's settle, short: five polls, so a lamp that never holds
# costs the suite no real seconds
self._lamp_timing = (baseline.LID_LAMP_SETTLE_S, baseline.LID_LAMP_POLL_S)
baseline.LID_LAMP_SETTLE_S, baseline.LID_LAMP_POLL_S = 0.05, 0.01
def tearDown(self):
baseline.LID_LAMP_SETTLE_S, baseline.LID_LAMP_POLL_S = self._lamp_timing
self.fc.stop()
super().tearDown()
def lamp_reads(self, *reads):
"""The lid lamp reads `reads` in turn, then what its file holds:
the smooth trigger's fade as the baseline polls it, one read per
poll, so the script does not depend on the clock."""
seq = list(reads)
real = baseline.hw.sysfs_read
def read(attr, default=None):
if attr == baseline.LID_LAMP_ATTR and seq:
return seq.pop(0)
return real(attr, default)
baseline.hw.sysfs_read = read
self.addCleanup(setattr, baseline.hw, "sysfs_read", real)
def lamp_polls(self):
return max(2, int(round(baseline.LID_LAMP_SETTLE_S / baseline.LID_LAMP_POLL_S)))
def test_a_lamp_still_fading_to_its_idle_level_is_not_a_leftover(self):
# The supervisor re-applied 236 a moment before the check: the lamp
# reads 232 on its way there and then holds 236. Nothing to restore,
# nothing to record.
self._attr("pic/lid_led", "236")
self.lamp_reads("232", "234", "236", "236")
writes = []
real_write = baseline.hw.sysfs_write
baseline.hw.sysfs_write = lambda attr, value: (writes.append(attr), real_write(attr, value))
self.addCleanup(setattr, baseline.hw, "sysfs_write", real_write)
left = self.bl().enforce("post", captured=None)
self.assertEqual(left, [])
self.assertNotIn(baseline.LID_LAMP_ATTR, writes)
self.assertTrue(any("the fade toward a level just written" in ln for ln in self.lines), self.lines)
def test_a_fade_that_only_passes_the_idle_level_is_a_leftover(self):
# A lamp left fading to 77 passes 236 on its way down: one read at
# the level is not the level held. It is restored and recorded at
# the level it settled on.
self.lamp_reads("240", "236", *(["77"] * (self.lamp_polls() - 1)))
left = self.bl().enforce("post", captured=None)
self.assertEqual([(x.item, x.found, x.expected, x.action) for x in left],
[("pic/lid_led", "77", "236", "restored")])
self.assertEqual(self._read("pic/lid_led"), "236")
def test_a_lamp_that_never_reaches_the_level_after_the_restore_says_so(self):
# the write does not take: the restore is recorded as failed, with
# the level the lamp holds
self.lamp_reads(*(["77"] * (2 * self.lamp_polls() + 1)))
left = self.bl().enforce("post", captured=None)
self.assertEqual([(x.item, x.action) for x in left], [("pic/lid_led", "failed: reads 77")])
def run(self, result=None):
# only this class's own tests, not the base class's
if self._testMethodName not in BaselineModeTests.__dict__: