fastest was originally created for Den as ci-fast.bash by @sini.
It uses nix-eval-jobs for parallel nix-unit-like test execution. Unlike nix-unit, fastest is designed for speed, because
many Den integration tests use real NixOS evaluations; this parallel execution drops some nix-unit features: No error diff, No expect-throws.
This test harness work for both Nix flakes and non-flake .nix files.
By default, falls back to nix-unit for test traces when a single test is specified. Controllable via --nix-unit.
- Parallel execution:
nix-eval-jobsruns tests across multiple workers - Flake mode: Test Nix flakes with
--flake <path or path#tests> - File mode: Test raw
.nixfiles with--file <path> -A <attr> - Optional suite: Run all tests by omitting suite name, or specify suite for subset
- Individual test traces: Falls back to
nix-unitfor debugging (configurable via--nix-unit) - Auto-detected system: Detects current system (can override with
-s) - Configurable parallelism: Default 8 workers, 2GB memory per worker
- Max parallelism mode: Use all CPU cores with unlimited memory (
-P) - Environment variable overrides: Configure via env vars
- Backward compatible: Positional arguments still work
nix run github:denful/fastest#fastest -- --help
Or build locally:
nix build ./vic/fastest#fastest ./result/bin/fastest --help
Test a Nix flake's test suites (suite is optional):
# Run specific suite fastest --flake ./templates/ci#tests nested-aspects # Run all tests (no suite specified) fastest --flake ./templates/ci#tests # Run specific test with traces fastest --flake ./templates/ci#tests nested-aspects.test-direct-nesting-basic # Via nix run nix run ./fastest#fastest -- --flake ./templates/ci#tests smoke
Flake reference format:
path#tests- Evaluatestestsattribute (required for test discovery)path#tests suite- Run specific test suitepath#testsalone - Run all tests- Omitting
#testssuffix adds it automatically
Test raw .nix files:
# File must export tests under an attribute fastest --file ./tests.nix -A mysuites.smoke # Example: test.nix with structure { mysuites.smoke.test-name = { expr = ...; expected = ...; }; }
-j, --workers N Parallel workers (default: 8, max: 8)
Env: FASTEST_WORKERS
--max-memory-size N Memory per worker in MiB (default: 2048)
Env: FASTEST_MAX_MEMORY
-P, --max-parallelism Use all CPU cores, unlimited memory
Env: FASTEST_MAX_PARALLELISM=1
-s, --system SYSTEM Target system (default: auto-detected)
-q, --quiet Suppress progress output
Env: FASTEST_QUIET=1
--show-trace Show Nix evaluation traces
--override-input KEY VAL Override Nix input (repeatable)
--nix-unit auto|never|always nix-unit usage mode (default: auto)
auto = use nix-unit only for single-test traces
never = always use nix-eval-jobs (no traces)
always = force nix-unit for all runs (full traces, slower)
--option KEY VAL Pass nix option (repeatable)
-h, --help Show help and env vars
# Run specific suite fastest --flake ./myflake#tests smoke # Run all tests (no suite specified) fastest --flake ./myflake#tests # With custom parallelism fastest -j 4 --flake ./myflake#tests smoke # Maximum parallelism (all CPU cores) fastest -P --flake ./myflake#tests smoke # Via env vars FASTEST_WORKERS=16 FASTEST_QUIET=1 fastest --flake ./myflake#tests smoke # File mode (specific suite) fastest --file ./smoke/noflake/tests.nix -A tests smoke # File mode (all tests in attribute) fastest --file ./smoke/noflake/tests.nix -A tests # Individual test with traces fastest --flake ./myflake#tests nested-aspects.test-xyz # With Nix overrides (useful for flakes that depend on other flakes) fastest --override-input den . --flake ./templates/ci#tests deadbugs # Auto-detected system (no -s needed) fastest --flake ./myflake#tests smoke # Override system if needed fastest -s aarch64-darwin --flake ./myflake#tests smoke
- Uses
nix-eval-jobsto discover and run tests in parallel - Flake must export
.testsattribute as a set of test suites - Optionally filter by suite name (e.g.,
tests.smoke), or run all tests - Each test is a set with
exprandexpectedkeys - Workers are capped at 8 (default) to prevent OOM
- On individual test request, falls back to
nix-unitfor full traces (unless--nix-unit never) - System is auto-detected (can override with
-s/--system)
- Uses
nix eval --fileto load.nixfile - Evaluates the given attribute path
- Uses jq to recursively process tests
- Compares
expr == expectedfor each test - Works with any
.nixfile exporting a test structure
- Default: 8 workers, 2GB memory per worker (prevents OOM on infinite recursion)
- Custom:
-j Nto set workers,--max-memory-size Mfor memory - Max parallelism:
-Puses all CPU cores with unlimited memory per worker
FASTEST_WORKERS Number of parallel workers (default: 8)
FASTEST_MAX_MEMORY Memory per worker in MiB (default: 2048)
FASTEST_MAX_PARALLELISM Enable max parallelism mode (1 = on, 0 = off)
FASTEST_QUIET Suppress progress output (1 = on, 0 = off)
Examples:
# Run with 16 workers FASTEST_WORKERS=16 fastest --flake ./myflake smoke # Max parallelism + quiet FASTEST_MAX_PARALLELISM=1 FASTEST_QUIET=1 fastest --flake ./myflake smoke
{ outputs = { ... }: { tests.smoke = { test-pass = { expr = 1 + 1; expected = 2; }; test-nested.test-inner = { expr = "hello"; expected = "hello"; }; }; }; }
# tests.nix { tests.smoke = { test-add = { expr = 1 + 1; expected = 2; }; test-string = { expr = "world"; expected = "world"; }; }; } # Run with: fastest --file ./tests.nix -A tests.smoke
-
fastest.bash: Main test runner script
- Parses flags, env vars, positional args
- Delegates to
nix-eval-jobs(flake mode) or jq (file mode) - Configurable
nix-unitusage via--nix-unit auto|never|always - Formats output consistently across modes
-
flake.nix: Exposes app
fastest- Uses
writeShellApplication(includes shellcheck) - Provides
devShellwith required tools
- Uses
-
default.nix: Wraps
fastest.bashfornix-build
just smoke-test # Run local smoke tests (flake + file mode) just ci-env # Test with env vars set just ci-trace # Test individual test with traces
just den-smoke-test # Test against remote den CI flake (single test) just den-deadbugs-test # Test den's deadbugs suite (13 tests) just den-all-tests # Run ALL den tests (829 tests, slow!)
just ci # Run all tests (smoke + den integration)