Design: TestRunSpec
Overview
A TestRunSpec is a static, immutable description of one test
group. It answers the question “which command should be run, on which class
of tentacle, and how?”.
Each spec is a singleton constant defined in the testrunspecs/ package:
TESTRUNSPEC_RUNTESTS_STANDARD = TestRunSpec(
label="RUN-TESTS_STANDARD",
label_intuitive="run-tests.py",
command=["run-tests.py"],
required_fut=EnumFut.FUT_MCU_ONLY,
requires_reference_tentacle=False,
testrun_class=TestRunRunTests,
timeout_s=3660.0,
...
)
All singletons are registered in _TESTRUN_SPECS inside
util_testrunner.py and selected at startup by get_testrun_specs().
During a test run the TestRunSpec also becomes mutable in one
regard: its tsvs_todo list shrinks as individual TestRun
instances are completed.
Key fields
Field |
Type |
Purpose |
|---|---|---|
|
|
Unique identifier, e.g. |
|
|
Human-readable shorthand shown in reports, e.g. |
|
|
The executable and its fixed arguments, e.g.
|
|
|
The Feature Under Test that a tentacle must declare in its inventory
to be eligible, e.g. |
|
|
When |
|
|
The concrete subclass instantiated when a tentacle is ready. |
|
|
The remaining board-variants still to be tested. Populated by
|
|
|
Hard wall-clock limit for one |
|
|
Scheduling hint (higher = run earlier). |
Relationship to tentacle types
The chain from hardware inventory down to an individual test execution goes through four distinct classes.
classDiagram
direction TB
class TentacleSpecMicropython {
board: str
futs: set[EnumFut]
build_variants: list[str]
}
note for TentacleSpecMicropython "Static per-board description\nlived in tentacles_inventory.py"
class TentacleSpecVariant {
tentacle: TentacleMicropython
variant: str
role: TestRole
}
note for TentacleSpecVariant "One (board, variant, role) tuple\ncreated at assign_tentacles() time"
class TentacleSpecVariants {
list[TentacleSpecVariant]
}
note for TentacleSpecVariants "The todo-list of a TestRunSpec"
class TestRunSpec {
label: str
required_fut: EnumFut
tsvs_todo: TentacleSpecVariants
generate() -> TestRun
}
class TestRun {
testrun_spec: TestRunSpec
tentacle_variant: TentacleSpecVariant
tentacle_reference: TentacleMicropython | None
}
note for TestRun "One concrete execution\n(one board-variant on one tentacle)"
TentacleSpecMicropython "1" --> "0..*" TentacleSpecVariant : expanded into
TentacleSpecVariant "0..*" --* TentacleSpecVariants : contained in
TentacleSpecVariants "1" --* TestRunSpec : tsvs_todo
TestRunSpec "1" --> "0..*" TestRun : generate()
TentacleSpecVariant "1" --* TestRun : tentacle_variant
TentacleSpecMicropython — the static board description
Defined once per physical board type in the tentacle inventory. It holds the
board name, the set of supported FUTs, and the build_variants tag which
lists the firmware variants the board can run (e.g. ["", "RISCV"] for the
RP2350).
TentacleSpecVariant — one (tentacle, variant, role) tuple
Created at runtime by tentacle_spec_2_tsvs() when assign_tentacles()
expands each tentacle according to its build_variants. For a RP2350 this
yields two entries: RPI_PICO2("") and RPI_PICO2("RISCV").
When a test requires two tentacles (e.g. WLAN STA ↔ AP), two
TentacleSpecVariant objects are created for the same tentacle, one
with role=ROLE_INSTANCE0 and one with role=ROLE_INSTANCE1.
TentacleSpecVariants — the todo-list
A typed list[TentacleSpecVariant]. It is stored as
TestRunSpec.tsvs_todo and acts as the scheduler’s work queue for that
spec. Every time a TestRun finishes, mark_as_done() removes the
corresponding entry. When the list is empty, this spec is fully done.
TestRun — one concrete execution
Produced by TestRunSpec.generate() when a tentacle is available and its
firmware has been built. It carries:
testrun_spec— back-reference to the owning spectentacle_variant— which physical board and variant to testtentacle_reference— optional second tentacle for multi-device tests
TestRun.test() (overridden per subclass) contains the actual subprocess
call to e.g. run-tests.py.
Lifecycle of tsvs_todo
assign_tentacles() # fills tsvs_todo from ConnectedTentacles
|
v
generate() # yields TestRun for each ready (tentacle, variant)
|
v
TestRun executes
|
v
mark_as_done() # removes the TentacleSpecVariant from tsvs_todo
|
v
tsvs_todo empty → spec done
assign_tentacles() is called once after get_testrun_specs() resolves
the active set. generate() is called repeatedly by the
TestBartender scheduler – it only yields a TestRun if the
required firmware is already built and the tentacle is not busy.