- scripts/bench/tray_test.py, run by the driver's CI: M103 P1 and P0
move Z and its envelope by tray_offset_mm on the lens step grid, tell
the sender, write and remove the marker beside the shared config, and
ship no step; a missing P, P2, P0.5, P-1, and an axis word are errors
that change nothing; the switch behind a move waits for the move; the
port's tray op with a sender connected, its count exact, refused out of
form, during a program, and at a package's M-code; the mode across a
soft reset and a killed controller, a start over the marker taking the
lens reference in the tray-out frame; the offset's range; an
unreferenced lens; a camera home in both modes handing the runner the
same park. The kernel-idle half of the barrier needs the pulse device:
a null sink is always idle.
- scripts/bench/ctlport_test.py: the dark case carries tray out and in
under an open armed window.
- forgetest: motion.tray in its own module, suite/tray.py, so no other
test's fingerprint moves. It switches the mode both ways through the
panel's route and through M103 from a Grbl client and judges each
switch: /status's mode, Z, and reach moved by the offset's grid, the
port's state, the marker, the reference and its source unchanged, the
client told, the kernel's counters unmoved. A jog to the Z the lens
read before a switch is refused in the other mode and taken back in
the mode found; a setup card started with the tray out is refused in
the operator's words; the panel page carries the switch. The mode goes
back as found in a finally. It does not restart the controller, which
would drop the X and Y reference: persistence is tray_test.py's.
- The bench registry and README list tray_test.py.
Proof: tray_test.py ALL PASS against the driver with the mode, and six
driver copies each missing one part of it fail. The driver's whole CI
harness list passes. The forgetest unit suite: 500 tests OK. The
coverage lint over the working trees: nothing uncovered, 126 tests. On
the bench reference, with the binaries hot-deployed on the fx18 image:
motion.tray PASS, and FAIL against the driver whose anchor lost its
source word on the second switch.
Acceptance. motion.tray is new; the suite and bench files are in no
other test's fingerprint.
- suite/extsender.py (new module, so no other test's fingerprint moves):
exthost.sender-keep-out. A reference package whose service claims the
Grbl sender out as it starts, installed with the sender.keep_out
grant (and refused without it), on an idle GRBL-mode machine with no
sender connected. It checks the holder and the ext: lease of the
extension kind, the host's claim file fresh past forgectrl's grace, a
sender from the machine's LAN address turned away with the message
and one from the loopback admitted, the operator's release (lease
gone, network welcomed, the package reading released), a new claim
after a restart, and the stale end with the notice after a disable;
everything is put back as found.
- camera.lid-privacy: the head camera answers the panel's token and the
extension host's header with the lid open, and refuses the cloud
client's form (no token, no header) and a stream for no local viewer;
the lid camera stays refused to everyone. covers gains src/auth.*.
- scripts/bench/ctlport_test.py: test_sender_out on the null-sink
controller build (Sender(host=) and closed, own_address(),
generation()).
Proof: forgetest's unit tests pass; the coverage lint passes against the
working trees' file lists. Against the current pins it reports
src/senderout.* as selecting nothing until forgectrl's pin moves to the
revision that adds it, which lands with this. On the bench reference
with the suite mounted: exthost.sender-keep-out PASS (first run found
the check racing the host's first write; the test now waits for the
file and holds past the grace), and camera.lid-privacy passed every
check of its body (its hand-back failed only on the controller gated by
the privacy advisory's Revision 5 before it was accepted).
ctlport_test.py passes in the driver's CI.
Two host harnesses for the grblHAL driver's null-sink build, in the bench
registry and the README with the others. The driver's CI runs them.
ctlport_test.py drives the controller port beside a scripted Grbl sender
that counts every ok and error it is sent, which is the only way to see a
status routed to the wrong source. 13 cases: the socket's mode; a port
jog's status going to the port with the sender's count exact and the jog
run whole under the sender's '?' polls; a port error the sender's next line
does not inherit; the sender's line canceling a fast port jog and drawing
its own ok (fast on purpose: a slow jog stops at once and would pass with no
hold at all); a sender line queued right behind the port's; the refusals;
one client, and five reconnects right after a close; the status hook across
a soft reset; the dead-man; a CR LF sender; a sender that polls the way
LightBurn does, '?' with an end of line behind it, LF and CR LF (every port
jog accepted, a 60 mm port jog run whole with the polls landing inside it,
one ok per poll, a real line still canceling a port jog); and every
operation of both sets under an open armed window with M3 modal and S500,
where the dump must hold no FIRE tick.
manual_home_test.py reads the stream dump (GFSINK_DUMP) and the attribute
log (GFSINK_ATTR_LOG), so it can say that nothing was shipped and which
current was written, and how many times. 9 cases: a manual $H ships no step
and no FIRE tick and declares the offsets with the soft limits on and Z
kept; $H refused in a cycle; $MD refused under an open armed window with
nothing written; every motion source and $X refused while released; each
energize written exactly once; the port's panel operations; both pairs of
home offsets, alone and at once; and a controller killed under a release,
whose replacement writes only 0 and 0.
Both pass against the driver's extensions tree. The poll cases fail against
the driver without its empty-line rule ("8 of 8 port jogs were refused under
a status poll"), which is the defect they were written from: it was found
on the bench reference with LightBurn connected, and the sender these
harnesses had until then polled a bare '?'.