Write a test
Use this guide when you have a supported board and want to add a test for it. It assumes the board has already been added to the shared hardware pool. If it has not, start with Integrate hardware.
A hardware test is a small Python test plus a config.toml file. The
configuration says which boards can run it. The Python code says what to do
with the selected board.
Check that the platform is available
A platform is supported when at least one compatible board is available in the
shared pool. Ask your team for the platform’s capability tags and the controls
it exposes. Common examples are adsp and sc598 for board selection, and
ssh, a serial console, power control, or a debugger for test operations.
If you do not know whether a board is already available, the infrastructure owner can check the shared pool. If it is not, see Integrate hardware before writing a test that depends on it.
Create the test directory
Give the test a descriptive, stable path under tests/. For example:
tests/adsp/my-board-smoke/
config.toml
test.py
requirements.txt
The directory path is the test name. In this example, its name is
adsp/my-board-smoke.
Describe the hardware you need
In config.toml, list the board-selection tags provided by the platform.
These must match tags on a board slot (a Labgrid
Place). hw-test selects a board only when every value in needs
matches that place’s tags.
needs = ["sc598", "ezkit"]
For example, a board slot tagged with family=adsp, board=sc598, and
kind=ezkit matches this test because it has both sc598 and ezkit.
It does not matter which matching board is selected; hw-test reserves one
that is currently free.
Keep needs about hardware capabilities, not an individual board-slot name,
lab location, or the drivers the test will use. That lets the same test run on
any compatible board and makes the infrastructure easier to grow. To understand
how place tags are assigned, see Integrate hardware.
Write the test
Use LabgridClient to find and reserve a compatible board. The with
block is important: it always releases the board, including when the test
fails.
from hw_tests.labgrid import LabgridClient
def test_smoke(context):
client = LabgridClient(context)
with client.acquire() as target:
ssh = target.get_driver("SSHDriver")
ssh.run_check("true")
Drivers represent capabilities attached to the board: a serial console, power switch, GPIO, debug probe, or SSH connection to the hardware host. Ask for a driver by its protocol where possible, so the test does not depend on a particular fixture’s implementation.
For example, a test that controls boot mode and power might start like this:
with client.acquire() as target:
boot_mode = target.get_driver("DigitalOutputProtocol", name="spi_boot")
power = target.get_driver("PowerProtocol")
boot_mode.set(True)
power.cycle()
The board’s available drivers are defined by its environment file. If a driver is missing, ask the person who maintains the fixture to update it; the mapping is explained in Hardware Model.
Use build artifacts when needed
Tests can retrieve artifacts from the GitHub workflow that produced them. The
test context contains the workflow run information. For a single, known
artifact, GitHub downloads it by name:
from hw_tests.github import GitHub
artifacts = GitHub(context).download("my-build-artifact")
image = artifacts / "my-image.bin"
Resolve artifacts by role with Images
Different build systems publish the same board under different artifact names and internal layouts (Buildroot, standalone U-Boot, Yocto). A single workflow run also publishes one artifact per board. Hardcoding an artifact name and its inner filenames ties a test to one build system and one board.
Images removes that coupling: a test asks for a role (spl, uboot,
kernel, dtb, …) and Images resolves the right file for whatever
was built.
from hw_tests.github import GitHub
from hw_tests.images import Images
images = Images(context, GitHub(context))
spl = images.get("spl")
uboot = images.get("uboot")
Images.get resolves in three steps:
The build system, detected from the repository under test (
br2-external→br2,u-boot→uboot,lnxdsp-adi-meta→yocto). Setflavorin the context to override detection for a local run. An unknown repository skips the test.The artifact is selected from the run by matching every
needstoken as a case-insensitive substring of the artifact name, soneeds = ["sc598", "ezkit"]picks the sc598 ezkit build and rejectsezliteorsc589.Role descriptor maps each role, per flavor, to an artifact and an inner-file pattern.
If a role is not defined for the detected flavor, the test is skipped rather than failed (that image source does not support it).
The descriptor lives at tests/<category>/artifacts.toml, next to the tests
that use it — category is the first path segment of the test name, so
adsp/u-boot reads tests/adsp/artifacts.toml. Each entry names an
artifact glob (matched against the run’s artifact names) and a file glob
(matched against files inside it):
[br2.spl]
artifact = "*-bootstrap"
file = "u-boot-spl"
[br2.kernel]
artifact = "*-bootstrap"
file = "Image"
[yocto.spl]
artifact = "*"
file = "u-boot-spl-*.elf"
For a local run that needs artifacts, provide GITHUB_TOKEN and
workflow_run_url as shown in Run a test. Without a token, Images
falls back to files placed locally by GitHub.download; see
Run a test.
Try it locally
If the test has a requirements.txt file, install it first. Then run only
the test you are working on:
~$
python3 -m pip install -r tests/adsp/my-board-smoke/requirements.txt
~$
set='{"name": "adsp/my-board-smoke"}' pytest -vvv
The first run is a good time to verify that the test selects the intended type
of board. Avoid pytest tests while developing: it can reserve and run many
boards at once.
When the local test is reliable, add it to your workflow using Run tests in CI.
Next steps
Run a test for local setup and common failures.
Integrate hardware if no compatible board exists.
Test API and client reference for fuller driver examples and CI details.