mirror of
https://github.com/Klipper4FlashForge/firmware.git
synced 2026-10-21 21:02:16 -05:00
Two changes that turned out to be one.
MOVED, NOT DELETED. `test/ffsim/` and `test/integration/printer/` are
`tools/replica/`. They were never tests: bin/patch.sh calls
bin/build-payload.py, which starts a replica and assembles the payload by
running the PRINTER'S OWN opkg against / inside it -- so the "test harness"
was on the build path, and deleting it as asked would have broken `make
build`. qa/lib/replica.py drives the same directory unmodified. No content
changed; what changed is qa/lib/replica.py's build directory, three launcher
sys.path lines, the Makefile targets and the CI shellcheck glob.
tools/replica/README.md says who drives it and why it is not under test/.
CUT TO 28. The five surviving modules were 136 tests; they are 28, chosen on
one question: would this failure be SILENT? What is kept is the mistakes that
run perfectly and are wrong --
test_startup 8 no stamp unless the values are verifiably saved (a
stamp written early is a printer that has lost its
factory calibration for good), and the handover order
test_tool_transform 7 every one is a move to the wrong place: a sign, a
frame left applied while probing, a stale gcode_move
cache, a config a calibrated printer cannot parse
test_ffscreen 5 the four ways it can do harm rather than look wrong
test_chamber 4 the chamber mistakes that cost a print before anyone
sees them, plus the parse gate they rest on
test_gcode 4 a renamed macro, and the safe file being cold
What went: the panel narration, the geometry probe and parse_geometry, the
z_adjust and per-job-Z bookkeeping, the config layout checks, the G-code
bounds checks. Each is either a wrong number shown to a person, or a failure
the printer reports loudly the first time -- and qa/replica/test_boot_screen.py
already renders the real frames on the real machine.
The rewrite is not a delete: assertions were folded so a kept test asks its
question in every direction it can be got wrong (both models, both rotations,
all four ways the migration can fail), and each file's header now says what it
dropped and why, where the next person will open it.
Also gone: conftest's `rootfs` fixture, orphaned two commits ago. Nothing under
test/ needs the firmware, docker, or a network any more.
28 host-side tests pass in 0.15s. qa/static unchanged at 218. `make rootfs`
re-verified end to end from its new path.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UzLebCrvc8ssWR5JuEsha4
82 lines
3.2 KiB
Python
82 lines
3.2 KiB
Python
"""Fixtures for the replica lane.
|
|
|
|
WHAT THE `printer` FIXTURE IS
|
|
|
|
A replica of the machine WITH OUR PACKAGE ALREADY INSTALLED -- installed by the
|
|
printer's own /usr/prog/app_startup.sh, from a genuine FAT filesystem on
|
|
/dev/sda1, exactly as a user installs it off a USB stick.
|
|
|
|
That is deliberate and it is the second time this repo has had to learn it.
|
|
An earlier version of this file handed the tests a machine into which
|
|
qa/replica/actions/install-payload.sh had copied payload/*.sh and
|
|
payload/init.d/S* by hand. Two things were wrong with that:
|
|
|
|
* it was a SECOND implementation of the install, so every assertion
|
|
downstream described a layout the harness had built rather than one the
|
|
installer produced -- the real installer could have broken and nothing
|
|
here would have gone red;
|
|
* it could only place what is in payload/, so anything the BUILD produces
|
|
was missing. The cross-compiled s6 is the obvious one: it lives in
|
|
work/.s6 and the payload carries it, so a hand-placed
|
|
payload has no supervisor at all and the tests had to carry a stand-in
|
|
scanner to paper over it.
|
|
|
|
Installing for real fixes both at once. The install is now under test because
|
|
it is the setup, and the payload under test is the built artefact -- real s6,
|
|
real CPython, real Klipper extras, staged exactly as they ship.
|
|
|
|
case-install.sh's header records the same lesson from the first time:
|
|
|
|
An earlier version of this file replayed app_startup.sh by hand -- which
|
|
meant a bug in our reading of it could never be caught.
|
|
|
|
COST
|
|
|
|
The install is the machine's own shell running under qemu and it takes
|
|
minutes, so it is baked into an image ONCE per package and cached under a tag
|
|
derived from the package's md5 -- the same trick
|
|
tools/replica/build-printer-image.sh uses for the stock baseline. Rebuild
|
|
the package and the tag changes, so the next run bakes again instead of
|
|
testing yesterday's build.
|
|
|
|
Module-scoped containers start from that image, which is the same isolation
|
|
boundary the case scripts have: each starts from a freshly assembled machine
|
|
and none shares state with another.
|
|
|
|
Nothing here skips. A machine with no docker, no daemon or no built package
|
|
cannot answer the question these tests exist to ask, and ReplicaMissing says
|
|
so -- with the fix -- rather than reporting a clean skip. See qa/conftest.py.
|
|
"""
|
|
import pytest
|
|
|
|
from lib import replica
|
|
from lib.config import Config, ConfigError
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def config():
|
|
try:
|
|
return Config.load()
|
|
except ConfigError as broken:
|
|
# Not a skip. A broken config.env is a broken harness, and the reason
|
|
# Config raises here is that the shell version could not tell the two
|
|
# apart -- a half-sourced file left STOCK_TGZ_* empty, and the run
|
|
# reported a clean skip on a machine that had everything.
|
|
pytest.fail(str(broken))
|
|
|
|
|
|
@pytest.fixture(scope="session")
|
|
def mod_image(config):
|
|
"""An image that IS a printer with our package installed. Baked once."""
|
|
return replica.installed_image(config, on_output=print)
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def printer(config, mod_image):
|
|
"""A live installed replica, held open for this module."""
|
|
live = replica.start(config, image=mod_image)
|
|
try:
|
|
yield live
|
|
finally:
|
|
replica.stop(live)
|