doc/TockHardwareCI.md
This guide provides a walkthrough on how to perform hardware continuous integration (CI) using Treadmill. By leveraging the tock-hardware-ci repository, you can automatically test your code on real hardware within your CI pipelines. This guide covers:
tock-hardware-ci repository.Before proceeding, ensure you are familiar with the following concepts:
Treadmill Terminology, especially terms like Host, Supervisor, and Device Under Test (DUT).
The Integrating Treadmill with GitHub Actions guide, which explains how to set up Treadmill jobs and GitHub Actions runners.
tock-hardware-ciThe tock-hardware-ci repository is designed to facilitate hardware testing within the Tock ecosystem using Treadmill. It provides:
By using tock-hardware-ci, you can automate testing on real hardware, ensuring that changes to your codebase are validated against actual devices.
The repository is organized as follows:
hwci/: Contains the core Python modules for hardware CI.
boards/: Definitions and implementations of different board harnesses.tests/: Test scripts that can be executed on the boards.utils/: Utility modules for serial communication and test helpers.core/: Core classes like BoardHarness and TestHarness.README.md: Provides an overview of the repository.requirements.txt: Python dependencies required for the CI scripts.select_tests.py: Script to select tests based on code changes (placeholder for future enhancements).tock-hardware-ci RepositoryBegin by cloning the repository to include it in your project:
git clone https://github.com/tock/tock-hardware-ci.git
Ensure you have access to a Treadmill deployment. You may refer to the treadmill.ci Deployment page for details on available deployments and hardware resources.
Make sure the Treadmill image you plan to use includes all necessary dependencies and configurations to run your tests and the self-hosted runner. You can find available images and their details on the treadmill.ci Public Images page.
In your GitHub repository:
TREADMILL_API_TOKEN: API token for authenticating with Treadmill.Ensure these are securely stored in your repository's settings under Settings → Secrets and variables → Actions.
Create a workflow file (e.g., .github/workflows/hardware-ci.yml) that integrates with Treadmill and runs your hardware tests.
name: Hardware CI
on:
pull_request:
push:
jobs:
test-prepare:
runs-on: ubuntu-latest
outputs:
runner-id: ${{ steps.treadmill-job-launch.outputs.runner-id }}
tml-job-id: ${{ steps.treadmill-job-launch.outputs.tml-job-id }}
steps:
# Checkout the repositories, set up the environment, and compile necessary tools
# Enqueue the Treadmill job and obtain the runner ID
# Refer to the 'Integrating Treadmill with GitHub Actions' guide for detailed steps
test-execute:
needs: test-prepare
runs-on: ${{ needs.test-prepare.outputs.runner-id }}
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set Up Python Environment
run: |
python -m venv venv
source venv/bin/activate
pip install -r hwci/requirements.txt
- name: Run Hardware Tests
run: |
python hwci/core/main.py --board hwci/boards/nrf52dk.py --test hwci/tests/c_hello.py
Note: The test-prepare job should follow the steps outlined in the Integrating Treadmill with GitHub Actions guide, including creating a just-in-time GitHub Actions runner and launching a Treadmill job.
Implement or modify a board harness in hwci/boards/ to match your hardware. For example, to create a new board harness:
# hwci/boards/my_custom_board.py
from core.board_harness import BoardHarness
from utils.serial_port import SerialPort
class MyCustomBoard(BoardHarness):
def __init__(self):
super().__init__()
# Set up board-specific configurations
self.uart_port = "/dev/ttyUSB0"
self.uart_baudrate = 115200
self.serial = SerialPort(self.uart_port, self.uart_baudrate)
# Implement required methods like flash_kernel, erase_board, etc.
board = MyCustomBoard()
Write test scripts in hwci/tests/ that perform the desired testing logic. Here's an example test script:
# hwci/tests/my_test.py
from utils.test_helpers import OneshotTest
class MyTest(OneshotTest):
def __init__(self):
super().__init__(apps=["my_app"])
def oneshot_test(self, board):
# Implement test logic
output = board.serial.expect("Expected Output", timeout=10)
if output:
print("Test passed")
else:
raise Exception("Test failed")
test = MyTest()
Push your changes to trigger the GitHub Actions workflow. Monitor the workflow runs under the Actions tab in your repository to ensure everything executes as expected.
Coming soon
Coming soon