scripts/bench/envelope_test.py drives the null-sink controller with the scripted sender and port client of ctlport_test.py, homing manually: unset keys are the axis travel; envelope_x_mm and envelope_y_mm are the far edges at a home and are held to 50 mm up to the travel plus 30 mm; the port's envelope open is refused before a home and under an open armed window, and lets the port's jogs reach the travel plus 30 mm; envelope apply puts the keys' edges back without a home; a status poll and an empty line leave an open envelope open, while the sender's first line closes it before the core reads it (a jog into the margin draws error:15), a running port jog canceled first; a soft reset and the port client going away each close it. It is registered in the bench registry as a CI harness, not a bench-page tool. setup.check-envelope (suite/bedsize.py, its own module): with cloud mode on, the machine is homed with the camera, and the Bed size check runs with its jog prompts answered as the page would, out 60.1 mm in X and 61.1 mm in Y from the home. The ends it reports are the home plus those, the far edges 1 mm short of them are written as envelope_x_mm and envelope_y_mm, and the controller holds them at once: a panel jog 0.5 mm short of each edge runs, and one 0.5 mm past it is refused with nothing moved. A second run is opened, and while its first prompt waits a Grbl client sends one line, which draws the controller's word that the envelope closed and then ok; the port then says the envelope is closed, the next answer ends the check in words, and the keys are as the first run left them. The head is jogged back to the home, and the keys, the homing mode, and the setup record are put back as found, the record under a restart. Proof: envelope_test.py ALL PASS on the host build of the controller of this change. On the bench reference, with that controller and forgectrl of the same change bind-mounted: the first two campaigns found flaws in the test, not the check (jogs of 20 mm made an edge below the 50 mm forgectrl refuses; the second run started while the machine was still busy; the head was not returned to the home), then setup.check-envelope PASS, with forgectrl.auth, kernel.latch-locked-idle, motion.pacing, motion.jog-roundtrip, and motion.port-jog PASS in the same campaign, and cloud.mode-switch, motion.soft-limits, and homing.cloud-offsets PASS after it. forgetest's unit tests pass (452), and the coverage lint passes with --enforce.
forgetest - the ForgeFIRM release acceptance tool
The daemon behind http://<machine>:8090/ on the dev image: runs the
acceptance catalog against the machine, keeps the append-only result log,
decides which results still apply to the image that is running, exports
the release artifact scripts/release.sh gates on, and serves the bench
diagnostics page. The contract - catalog, campaigns, fingerprints,
inheritance, the gate, the coverage rule - is
the Acceptance page of the documentation site.
Run the host tests
cd forgetest
python3 -m unittest discover -s tests -v
Run the daemon on a workstation (against a mock or a manifest file)
FORGETEST_DATA=/tmp/ft FORGETEST_MANIFEST=../tree-manifest.json \
FORGECTRL_URL=http://<machine> python3 -m forgetest --port 8090
scripts/manifest-from-tree.py produces tree-manifest.json from the recipe
pins; the coverage lint is python3 -m forgetest.coverage --manifest ....
Environment
| Variable | Default | Purpose |
|---|---|---|
FORGETEST_DATA |
/data/forgetest |
results.jsonl, bench.jsonl, token, export/ |
FORGETEST_MANIFEST |
/etc/forgefirm-manifest.json |
the image manifest |
FORGETEST_PORT, FORGETEST_HOST |
8090, 0.0.0.0 | listener |
FORGETEST_BENCH_DIR |
/usr/share/forgetest/bench |
the installed bench scripts |
FORGETEST_BENCH_DATA |
<FORGETEST_DATA>/bench |
passed to bench tools: where they keep their data files (with GF_HOST=127.0.0.1 and the panel token in GF_TOKEN) |
FORGETEST_MARKER |
/run/forgetest.active |
takeover marker |
FORGECTRL_URL, FORGECTRL_TOKEN_FILE |
http://127.0.0.1, /data/forgefirm/panel.token |
forgectrl client (HTTP; the token authorizes writes from the board) |
FORGECTRL_TLS_URL |
https://127.0.0.1 |
forgectrl over HTTPS (self-signed, unverified), for the login test |
GF_SYSFS_ROOT |
/sys/glowforge/ |
kernel module sysfs |
GRBL_HOST, GRBL_PORT |
127.0.0.1, 23 | Grbl TCP |
Adding a test
Register it in the subsystem module under forgetest/suite/ with
@test(...): id subsystem.name, kind, hardware, mode (the controller
mode the test needs; the runner switches to it first), covers,
requires, always, steps. The body gets a Context (log, check, fail,
prompt, confirm, instruct, sleep, evidence, forgectrl, sysfs,
grbl, takeover). Return normally for PASS, raise runner.Failed for
FAIL. Then run the unit tests and the coverage lint.