Commit Graph
3 Commits
Author SHA1 Message Date
ScottW514 8e1fe5090d 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.
2026-10-13 21:20:31 -04:00
ScottW514 d40ebb090e cool_report_test: the homing runner is handed the report secret
The runner case asserted that the homing runner the controller starts
does not inherit GF_REPORT_SECRET. The runner is the reporter while a
gfcloud $H holds the machine (the controller sends no report then), so
the assertion described the defect: every camera home ran with nobody
reporting, and the cooling engine's hung-controller dead-man stopped the
session's first motion.

The case now requires the runner to be handed exactly the controller's
secret, and two new cases require that it be handed none when the
controller was started with no secret (runner-none) or with one that is
not 32 hex digits (runner-malformed). The harness's descriptions in
scripts/bench/README.md and in the bench page's catalog say so.

Proof: all 11 cases pass on the driver that hands the secret over
(grblHAL-glowforge, "gfhome: the homing runner is handed the report
secret"); the driver before it fails the runner case: "the homing
runner was handed [], not '0123456789abcdef0123456789abcdef'".

Acceptance: a host harness in the driver's CI; no catalog test runs it.
forgetest/forgetest/bench.py changes one description string, which no
test judges.
2026-09-25 14:22:50 -04:00
ScottW514 965f7c3ca9 The cooling report secret: a driver harness, and two catalog tests
forgectrl's POST /cool/state now asks for the secret the supervisor hands
the running controller at its spawn; both controllers' cooling clients
send it.

scripts/bench/cool_report_test.py is the driver's host harness for it
(null-sink controller, a stand-in for forgectrl's listener on
FORGECTRL_PORT): every report carries the secret and no other new header;
none does when there is none; a value that is not 32 hex digits, a CR LF
with a header behind it included, never reaches the wire; the homing
runner the controller starts does not inherit the secret. It is in the
bench registry and the bench README, and the driver's CI runs it.

forgectrl.auth: the loopback case used to assert that any local peer is
accepted. It now asserts the three answers: no secret 403, a made-up
secret 403, and the running controller's own secret 200, read as only root
on the machine can read it, out of the controller's environment, and never
logged. The LAN cases carry the secret too and are still refused.

cooling.report-channel is new, the drill the change exists for: M8 opens a
run session, three forged idle reports from this host (no secret, a
made-up one, a made-up one with a forged Host) are each refused, and over
the next five seconds the engine stays in phase run and no commanded fan
duty drops; M9 ends the session on the controller's own report.

Proven. The harness passes on the host-built controller, with three
negative controls that each fail as they should. The unit suite passes
(421) with no undefined name. On the bench reference, forgectrl and both
clients hot-deployed over image 20260920152153: forgectrl.auth PASS,
cooling.report-channel PASS (phase run throughout, the exhaust at 65535 and
the intake at 43278), and cooling.fans-quiet-after-motion and motion.job
PASS on the same binaries.

Acceptance. forgectrl.auth and cooling.report-channel are the gate for the
report channel's secret; cloud.dark-print gates the cloud client's side.
2026-09-20 16:46:01 -04:00