Files
solidcraft/docs/book/src/dev/testing.md
T
Dahak BuildsandDahak Builds d3720041b6 CI tooling: opt-in bound for local test concurrency (#1188) (#6831)
* claim: #1188

* #1188: split per-binary test threads and matrix workers under SOLIDCRAFT_TEST_JOBS

---------

Co-authored-by: Dahak Builds <dahakbuilds@users.noreply.github.com>
2026-10-26 11:50:10 +00:00

136 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Test harnesses
`cargo xtask ci` runs everything a pull request must pass: fmt, `xtask assets`,
`xtask licences --check`, `xtask layers`, clippy with `-D warnings`, the tests with the `ci`
profile and the wasm build check.
| Harness | Where | What it catches |
|---|---|---|
| Unit and engine tests | next to the code, `*_tests.rs` | measured results: volume, area, topology counts against derived values |
| Hostile input | `hostile_params_never_panic`, `crates/engine/src/tests.rs` | every command × every documented parameter × junk values: errors, never panics |
| Sketch fuzz | `crates/engine/src/cmd/sketch_fuzz_tests.rs` | random sketches through the solver and profile finder |
| UI scenarios | `crates/ui-egui/tests/scenarios/*.json` | the real app, headless: clicks, keys, drags, assertions |
| Layout tests | `crates/ui-egui/tests/ui_layout.rs`, `window_widths.rs` | panels and dialogs at every window width |
| Design-file corpus | `apps/solidcraft-cli/tests/corpus` | every saved file version still opens and evaluates the same |
| Kill mid-save | `apps/solidcraft-cli/tests/kill_mid_save.rs` | a save killed at any moment leaves a readable file |
| Reference tests | `cargo xtask oracle` → [docs/oracle.md](oracle.md) | parts rebuilt from `tests/oracle/*/recipe.json`, compared with analytic or FreeCAD expected values |
## Dependency advisories
Scheduled and manually dispatched CI runs have a separate **Dependency advisories** job;
new advisories do not fail unrelated pull requests. To run the same scan locally:
```sh
cargo install cargo-deny --version 0.20.2 --locked
cargo deny --locked check --warn unmaintained advisories bans sources
```
The checked-in `deny.toml` rejects vulnerabilities and unknown registries/git sources.
Unmaintained crates, yanked versions and duplicate versions warn; licences remain covered
by `cargo xtask licences --check`. Review advisory failures and update dependencies rather
than adding broad ignores. The first scan prompted an update to quick-xml 0.41.0 for
[RUSTSEC-2026-0194](https://rustsec.org/advisories/RUSTSEC-2026-0194) and
[RUSTSEC-2026-0195](https://rustsec.org/advisories/RUSTSEC-2026-0195).
Coverage excludes the version matching of local path patches: `truck-shapeops`,
`truck-stepio`, `truck-meshalgo`, `matext4cgmath` and `egui-wgpu` in `vendor/`. Their checked-in
code and patches still need comparison with their permissively licensed upstreams; a green
scan does not establish their security or incorporate an upstream fix automatically.
## UI scenarios
A scenario is a JSON list of steps run against the real app with a headless egui context:
```json
[
{"start": "sketch.create"},
{"click": {"plane": "XY"}},
{"start": "sketch.rectangle.two_point"},
{"click": {"sketch": [0, 0]}},
{"click": {"sketch": [40, 30]}},
{"expect": {"errors": 0}}
]
```
A new file in `crates/ui-egui/tests/scenarios/` is picked up automatically. To record a bug
before it's fixed, add a `{"pending": "why"}` step; its test is then ignored with that reason, and
the fix removes the step.
## CI profile
CI runs the tests with `--profile ci`: light optimisation, line tables, no LTO and debug
assertions off. Some truck debug assertions fail on valid geometry; the `ci` profile disables
them while building faster than `--release`. If a test fails only in a plain debug build, say
so in the PR.
Run `cargo xtask test` to build with this profile and run the test binaries concurrently,
with doc tests alongside. Arguments after `--` go to each test binary, for example
`cargo xtask test -- shell`. To run the test binaries sequentially instead, use
`cargo test --workspace --profile ci`. On a loaded machine set `SOLIDCRAFT_TEST_JOBS=N` to
bound how many test binaries and side commands run at once; each binary then gets
`RUST_TEST_THREADS` and `ACTION_MATRIX_JOBS` of `max(1, cpus / N)` so the binaries in flight
share the machine instead of each defaulting to one worker per CPU. Setting
`RUST_TEST_THREADS` or `ACTION_MATRIX_JOBS` yourself overrides that split, and leaving
`SOLIDCRAFT_TEST_JOBS` unset keeps the original all-at-once behaviour.
## Test-level scheduling for full local CI
Install [cargo-nextest](https://nexte.st/docs/installation/pre-built-binaries/), then set
`SOLIDCRAFT_TEST_RUNNER=nextest` when running `cargo xtask ci`. For example, on PowerShell:
```powershell
$env:SOLIDCRAFT_TEST_RUNNER = 'nextest'
cargo xtask ci
```
This optional backend builds the workspace tests once, then schedules individual tests using
the `local-ci` nextest profile, which inherits `ci`. The action matrix runs first, then the longest geometry
cases start before the other costly tests, so the ordinary queue does not stall behind an
all-slot reservation. It **ignores the default filter**,
so the heavy tests below still run, does not stop after a test failure, and does not retry failures.
Tests marked `#[ignore]` remain ignored, as with the ordinary full local CI.
The default concurrency is at most four tests; `NEXTEST_TEST_THREADS` overrides it. The action
matrix's child workers default to the smaller of that budget and the host CPU count;
`ACTION_MATRIX_JOBS` explicitly overrides this worker count. The local profile reserves CPU
slots for the matrix and keeps its scheduling changes separate from GitHub CI. On Windows,
the `solidcraft-gpu` and app packages, plus UI offscreen/GPU tests, use a serial group. The Wasm check and doc tests still run alongside,
and the web-offline gate still follows a successful native/Wasm/doc run.
The backend keeps Cargo and binary metadata under `target/xtask-nextest/` and reuses it for the
native run, freeing Cargo to run the side gates. Nextest prints each test's result and duration
as it finishes. `SOLIDCRAFT_TEST_RUNNER=libtest` (or leaving it unset) retains the original runner;
`cargo xtask test` and its Cargo/libtest argument forwarding are unchanged. Unknown runner names
fail explicitly.
## CI sharding and heavy tests
On GitHub, one job builds the tests into a [cargo-nextest](https://nexte.st/) archive and four
jobs run a quarter of the tests each (two halves on a pull request; `--partition slice:N/4`,
settings in `.config/nextest.toml`), the slowest tests first; doc tests run in their own job.
Pull requests skip a few heavy tests (each takes one to twelve minutes); they run on every push to
`main`, nightly, and in `cargo xtask test`:
- `solidcraft-engine`: `tests::hostile_params_never_panic`, everything in `tests::robustness` and
the seeds of `tests::robustness_goldens` (`seed_00` … `seed_95`; pull requests that change the kernel, truck or
the goldens run all but the slowest, `SLOW_SEEDS` in `ci.yml`),
`pattern_suppress_tests::enclosure_arc_extinction_keeps_a_real_sharp_inner_lip_after_resize_and_reopen`,
`pattern_suppress_tests::enclosure_datums_follow_wall_height_and_board_depth_with_material_proofs`,
`cmd::plastic::tests::enclosure_snap_fit_follows_resized_front_wall`, the `atomic_commands` contract tests
- `solidcraft-kernel`: `tests::boolean_identity_on_tangent_primitives`,
`tspline::tests::hostile_tsplines_never_panic`, and the `boolean_props` property tests
(these run only in the nightly "Property tests" job: their inputs are random, so main skips them too)
- `solidcraft-ui-egui` scenarios: `acceptance_sensor_enclosure`
The **action matrix** (`apps/solidcraft-cli/tests/action_matrix.rs`) tries every ordinary action
(sketch, offset plane, press pull, hole, draft, shell, fillet, chamfer, construction geometry, move,
mirror, pattern) on every face, edge, vertex and body of a corpus of designs and compares with a
checked-in baseline: an action that passed there and fails now fails the test. Every run checks a
fixed sample; the nightly "Action matrix" job runs it all. After a fix, record what passes now with
`cargo xtask action-matrix --bless`. The results and the causes of the failures are in
[the action matrix page](https://github.com/bherbruck/solidcraft/blob/main/docs/action-matrix.md).
To run exactly what a pull request runs: `cargo nextest run --cargo-profile ci --profile ci`;
add `--ignore-default-filter` for the full set. A new test that takes over a minute on CI can
join the list (the `default-filter` in `.config/nextest.toml`) if it guards robustness rather
than everyday behaviour.