Writing a Simple Boot Test
Create a boot test that power cycles your board, flashes firmware, and verifies the device boots.
Prerequisites
fwciCLI installed and authenticated- Git repository with
.firmwareciinfrastructure initialized (see Repository Setup) - DUT connected through a control interface (DUTCTL-compatible device)
- Access to target device over network
Quick Example
Complete boot test configuration:
DUT Configuration (.firmwareci/duts/arm-board/dut.yaml):
name: ARM-Board-DUT
label: arm-board
attributes:
Host: "arm-board.lan"
Flasher: "arm-board-dutctl.lan"Pre-Stage (.firmwareci/duts/arm-board/pre.yaml):
pre-stage:
- cmd: dutctl
name: Power off DUT
parameters:
host: "[[attributes.Flasher]]"
command: power
args: ["off"]
- cmd: dutctl
name: Flash firmware
parameters:
host: "[[attributes.Flasher]]"
command: flash
args: [write, "[[input.Binary]]"]
- cmd: dutctl
name: Power on DUT
parameters:
host: "[[attributes.Flasher]]"
command: power
args: ["hardreset"]
options:
timeout: 2mPost-Stage (.firmwareci/duts/arm-board/post.yaml):
post-stage:
- cmd: dutctl
name: Power off DUT
parameters:
host: "[[attributes.Flasher]]"
command: power
args: ["off"]Workflow (.firmwareci/workflows/arm-board/workflow.yaml):
name: ARM-Board-Workflow
description: Boot tests for ARM board
runs-on: arm-boardBoot Test (.firmwareci/workflows/arm-board/tests/boot.yaml):
name: Boot Test
description: Verify board boots and accepts SSH connections
stages:
- name: Boot Verification
steps:
- cmd: ping
name: Wait for SSH service
options:
timeout: 2m
parameters:
host: "[[attributes.Host]]"
- cmd: cmd
name: Verify device responds
transport:
proto: ssh
options:
host: "[[attributes.Host]]"
user: root
# Uses auto-discovery for SSH keys
parameters:
executable: echo
args: ["Hello, World!"]Step-by-Step Setup
1. Configure DUT
Update .firmwareci/duts/<dut-name>/dut.yaml with your device details:
| Field | Description | Example |
|---|---|---|
name | Display name | ARM-Board-DUT |
label | Hardware identifier for workflows | arm-board |
attributes.Host | Target device hostname/IP | arm-board.lan |
attributes.Flasher | DUTCTL interface hostname/IP | arm-board-dutctl.lan |
The label field connects workflows to hardware. Workflows targeting arm-board will run on DUTs with this label.
See DUT Configuration Reference for complete schema.
2. Configure Pre-Stage
Pre-stage operations prepare the DUT before tests run. Edit .firmwareci/duts/<dut-name>/pre.yaml:
pre-stage:
- cmd: dutctl
name: Power off DUT
parameters:
host: "[[attributes.Flasher]]"
command: power
args: ["off"]
- cmd: dutctl
name: Flash firmware
parameters:
host: "[[attributes.Flasher]]"
command: flash
args: [write, "[[input.Binary]]"]
- cmd: dutctl
name: Power on DUT
parameters:
host: "[[attributes.Flasher]]"
command: power
args: ["hardreset"]
options:
timeout: 2mTemplates used:
[[attributes.Flasher]]: DUTCTL interface address from DUT config[[input.Binary]]: Firmware binary path provided when triggering workflow
See Templating Reference for template syntax.
3. Configure Post-Stage
Post-stage operations clean up after tests complete. Edit .firmwareci/duts/<dut-name>/post.yaml:
post-stage:
- cmd: dutctl
name: Power off DUT
parameters:
host: "[[attributes.Flasher]]"
command: power
args: ["off"]Post-stage always runs, even if tests fail, ensuring proper hardware cleanup.
4. Update Workflow
Edit .firmwareci/workflows/<workflow-name>/workflow.yaml:
name: ARM-Board-Workflow
description: Boot tests for ARM board
runs-on: arm-boardThe runs-on field must match the DUT’s label value.
See Workflow Reference for complete configuration options.
5. Create Boot Test
Create .firmwareci/workflows/<workflow-name>/tests/boot.yaml:
name: Boot Test
description: Verify board boots and accepts SSH connections
stages:
- name: Boot Verification
steps:
- cmd: ping
name: Wait for SSH service
options:
timeout: 2m
parameters:
host: "[[attributes.Host]]"
- cmd: cmd
name: Verify device responds
transport:
proto: ssh
options:
host: "[[attributes.Host]]"
user: root
parameters:
executable: echo
args: ["Hello, World!"]Test execution flow:
- Pre-stage: Power off → Flash → Power on
- Ping command waits up to 2 minutes for SSH service
- SSH command executes on target device
- Post-stage: Power off
6. SSH Authentication
Option 1: Auto-Discovery (Recommended)
Omit identity_file and FirmwareCI automatically tries all organization SSH keys:
transport:
proto: ssh
options:
host: "[[attributes.Host]]"
user: root
# No identity_file specifiedOption 2: Specific Key
Reference a specific SSH key by name:
transport:
proto: ssh
options:
host: "[[attributes.Host]]"
user: root
identity_file: "[[ssh-keys.arm_board_key]]"Add SSH keys in the web interface under Settings → SSH Keys. See SSH Key Management.
Option 3: Password Authentication
Use for testing only - not recommended for production:
transport:
proto: ssh
options:
host: "[[attributes.Host]]"
user: root
password: root7. Validate and Deploy
Validate configuration:
fwci validateExpected output:
- duts
- all validations passed
- storage
- all validations passed
- workflows
- arm-board-workflowCommit and push:
git add .firmwareci
git commit -m "Add ARM board boot test"
git pushFirmwareCI automatically syncs changes and the workflow becomes available for triggering.
Test Images
Use pre-configured test container images with required tooling:
FirmwareCI Base Images: firmwareci-base-image repository
These images include all test step dependencies and can be customized for your DUT requirements.
Common Issues
| Problem | Solution |
|---|---|
| Ping timeout | Increase timeout in ping step options. Verify network connectivity to DUT. Check attributes.Host address. |
| SSH authentication fails | Verify SSH key exists in organization settings. Check username is correct. Confirm SSH service runs on DUT. |
| Flash command fails | Verify DUTCTL interface is accessible. Check attributes.Flasher address. Ensure firmware binary path is correct. |
| DUT doesn’t boot after flash | Check power cycle commands execute successfully. Verify firmware binary is valid. Increase power-on timeout. |
| Template not resolved | Verify template name matches exactly (case-sensitive). Check attribute exists in dut.yaml. Ensure input provided when triggering. |
| Validation fails | Check YAML syntax (use YAML linter). Verify all referenced templates exist. Ensure runs-on matches DUT label. |
See Also
- Test Execution Model - Understand stages and steps
- Test Step Commands - Available commands reference
- DUT Configuration - Complete DUT schema
- Templating Reference - Template syntax
- Job Triggers - Trigger workflows from CI/CD