Harnesses: the null-sink cases other tests prove leave

The grblHAL harnesses keep what only a running controller shows; the
cases a host unit test in grblHAL-glowforge proves, and the log and
reply wording, leave.

- laser_lifecycle_test: test_arm_waits_for_the_fans goes. laser_arm_test
  case A4 (grblHAL-glowforge) proves the fan grace stretching the arm's
  acknowledgment budget, on the same arm path. The docstring names it.
- xy_mode_test: case_x32, case_invalid and the log checks go; the
  default, x16 and the low tick stay. xy_scale_test holds each mode's
  tick and the not-a-mode parse.
- planner_blocks_test: one restart, at $398 1000; the 400 pass and the
  fresh-store probe go.
- ctlport_test: test_poll_lf and test_crlf go (the CR LF poll stays); in
  test_sender_out the network turn-away goes (serial_test holds it), and
  the busy gating, the grant and the outlives-client part stay.
  test_port_dark is whole.
- mcode_test: the timeout case runs on the host build's 5 s
  GFMCODE_WAIT_S (grblHAL-glowforge's CI configures it; the image keeps
  30 s) and still shows the hold, at 5.1 s; 5 s outlasts the 3 s
  test_dark watches the wait; test_table refuses one form per
  parser branch. test_timeout_holds and test_dark stay.
- envelope_test: test_unset and test_bounds go (lens_home_test holds the
  clamp); test_armed and the open, apply and close cases stay.
- manual_home_test: the out-of-range offset block goes, a repeat of
  gfhome_clamp_home_mm (lens_home_test); the modal-M3 FIRE check and
  every release and energize case stay.
- cool_report_test: one non-hex secret and one CR LF injection stay;
  runner-malformed and the exact header-set checks go. A bad secret is
  never sent and a good one is.
- tray_test: test_offset keeps 20 mm; test_errors keeps a bad P and a
  bad axis; the frame shift, envelope, barrier, persistence, port op,
  unreferenced lens and camera home stay.

Proof: with grblHAL-glowforge's matching commit, the eleven harnesses
its CI runs pass under Linux against the null-sink build: nine on a
build with a 1 s M-code wait, and mcode_test and tray_test, the two
that wait at an M-code, on the 5 s build CI configures
(-DGFMCODE_WAIT_S=5.0). pyflakes reports nothing in the nine changed
files.

Push this before grblHAL-glowforge's commit.

Acceptance: none; host harnesses only.
This commit is contained in:
ScottW514
2026-10-13 21:20:31 -04:00
parent 520d62ac05
commit 8e1fe5090d
9 changed files with 66 additions and 216 deletions
+1 -28
View File
@@ -22,7 +22,7 @@ reported messages:
5. arming refused while the cooling verdict blocks fire, or before
the engine acknowledges the session: laser_arm_test.c cases C, A2
and A3, and cooling_test.c's arm-time gate; the wait for the fans
is this harness's
is laser_arm_test.c case A4
6. with a switch source present (GF_SWITCH_FILE), the arm blocks on the
button: a press with the lid closed arms, and the lid or the
interlock loop opening during the wait cancels the job (a clean
@@ -558,32 +558,6 @@ def test_rx_overrun_aborts():
s.close()
def test_arm_waits_for_the_fans():
"""Rule 5: the acknowledgment budget follows the fan grace. The
engine acknowledges once the fans are at their floors, seconds after
the arm; with cool_fan_grace_s at 8 the controller waits up to 13 s
for it, and an acknowledgment at 9 s arms the job rather than
refusing it at the old 5 s budget."""
ack_s = 9.0
s = Session("arm-fans", fire_ok=True, ack_after_s=ack_s,
conf_extra="cool_fan_grace_s = 8\n")
try:
t0 = time.time()
s.send_raw("M4 S100")
s.send_raw("G1 X1 F600")
if not wait_for(s.log, ARMED, 20, s.sock):
fail("[arm-fans] the arm never completed with the acknowledgment at %.0f s "
"(the budget did not follow cool_fan_grace_s)" % ack_s)
dt = time.time() - t0
if dt < ack_s - 0.5:
fail("[arm-fans] armed after %.1f s, before the fans were up at %.1f s" % (dt, ack_s))
if BLOCKED in "".join(s.log):
fail("[arm-fans] the wait for the fans was reported as a refusal")
print("PASS [arm-fans]: the arm waited %.1f s for the fans, then armed" % dt)
finally:
s.close()
def test_sigterm_mid_job():
"""Rule 5: a termination signal during an armed job is a STOP, not a
"finish the job first". The supervisor's expected-stop path (mode
@@ -980,7 +954,6 @@ def main():
test_lid_cancels_and_returns()
test_pause_then_lid_cancel_returns_to_the_job_start()
test_lid_policy_hold()
test_arm_waits_for_the_fans()
test_sigterm_mid_job()
print("PASS: the armed-window lifecycle holds")