Test your configuration¶
system-manager provides a container-based test framework that lets you verify your configuration works correctly before deploying it to real systems. The test framework runs inside the Nix build sandbox using systemd-nspawn containers, providing a fast and reproducible testing environment.
Prerequisites¶
Your Nix installation must have auto-allocate-uids enabled for the uid-range sandbox feature.
Add this to your Nix configuration (typically /etc/nix/nix.conf or ~/.config/nix/nix.conf):
Quick start¶
Add a container test to your project's flake.nix:
Run the test:
Test script API¶
The test script is Python code with access to a machine object.
The API is designed to be compatible with NixOS VM tests and includes testinfra integration for expressive assertions.
Available symbols¶
The test script has access to these symbols:
| Symbol | Description |
|---|---|
start_all() |
Start all containers (required at script start) |
subtest(name) |
Context manager to group related assertions with timing |
machine |
The container machine (when exactly one container) |
machines |
List of all machine objects |
driver |
The Driver instance |
Machine |
Machine class for type hints |
Machine methods¶
| Method | Description |
|---|---|
machine.activate() |
Activate system-manager profile and display output |
machine.succeed(cmd) |
Run command, fail test if exit code != 0 |
machine.fail(cmd) |
Run command, fail test if exit code == 0 |
machine.wait_for_unit(unit) |
Wait for systemd unit to be active |
machine.wait_for_file(path) |
Wait for file to exist |
machine.wait_for_open_port(port) |
Wait for TCP port to be listening |
machine.wait_until_succeeds(cmd) |
Retry command until it succeeds |
machine.execute(cmd) |
Run command, return result (does not fail test) |
machine.systemctl(args) |
Run systemctl with given arguments |
Testinfra assertions¶
The machine object provides testinfra assertions for declarative checks on services, files, and users.
The testinfra API is well-documented at https://testinfra.readthedocs.io/en/latest/modules.html.
These are more readable and provide better error messages than shell commands.
Service checks:
File checks:
User checks:
Grouping tests with subtest¶
Use the subtest context manager to group related assertions.
Each subtest logs timing information and provides clear output when tests fail.
Output shows each subtest name with timing:
Example test script¶
How it works¶
The test framework:
- Builds an Ubuntu 24.04 container image with the nix-installer binary included
- Starts the container using systemd-nspawn within the Nix build sandbox
- Installs Nix via nix-installer at container startup (multi-user mode with daemon)
- Copies your system-manager profile closure into the container via
nix copy - Executes your test script
This provides a realistic testing environment that matches how system-manager is deployed on non-NixOS systems.
Test script validation¶
Test scripts are automatically validated before execution to catch errors early.
Type checking with mypy: Validates that your test script uses the API correctly.
Type hints are automatically prepended so symbols like machine, subtest, and start_all are recognized.
Linting with pyflakes: Catches undefined variables and other common mistakes. The test framework symbols are automatically registered as builtins.
Both checks run during the build before the container starts. If either fails, you see the error immediately without waiting for container setup.
To disable validation when needed:
Debugging failed tests¶
If a test fails, the output will show:
- Which command failed
- Exit code and stdout/stderr
- Full system-manager activation output
Interactive debugging¶
For interactive debugging, build the test driver and run it with --interactive:
This starts the container and drops you into a Python REPL where you can run commands:
Press Ctrl+D to exit and stop the container.
To enter the container shell directly, you can use nsenter. The command using
nsenter is printed in the test output.
Comparison with VM tests¶
The container test driver complements the existing VM tests:
| Aspect | Container tests | VM tests |
|---|---|---|
| Speed | Fast (no QEMU) | Slower (full VM) |
| Isolation | systemd-nspawn | QEMU VM |
| Requirements | uid-range feature |
KVM support |
| Kernel | Shared with host | Full kernel |
| Use case | Integration testing | System-level testing |
Container tests are ideal for validating that your configuration activates correctly and services start as expected. VM tests are better suited for testing kernel-dependent features or scenarios requiring full system isolation.