Skip to content

Testing and Quality

Mihai edited this page Sep 6, 2026 · 5 revisions

Testing and Quality

Validation combines workspace tests, randomized scenarios, static checks, and live network exercises. Select checks that cover the changed behavior and record what each result establishes. Formal Verification describes the separate proof workflow.

Choose checks by scope

Documentation changes need relevant formatting and link checks. Contract changes need linting, workspace tests, and focused regression coverage. Changes to arithmetic, authorization, accounting, risk, pricing, or strategies also need properties or adversarial cases that exercise the affected boundary.

Build contract fixtures first using Building and Contributing. The baseline contract checks are:

make fmt-check
cargo clippy --workspace --all-targets --features price-aggregator/testing -- -D warnings
make test

make test runs the whole workspace with price-aggregator/testing, including contract suites outside the shared harness. Running only the harness does not cover those suites. Avoid --all-features for ordinary tests: the certora feature has a separate compilation and proof path.

For contract artifact changes, make wasm-size-check builds deployment WASM and checks both size budgets and prohibited testing entrypoints. make access-control-check checks the declared authorization coverage of state-changing entrypoints. These checks complement behavioral tests.

In-process harness

The harness in tests/test-harness/ combines native contracts and WASM fixtures in a Soroban test environment. Controller, governance, and price-aggregator contracts run natively; pool and position-NFT contracts load WASM. Rebuild fixtures after changing their contracts.

The default fixture mocks authorization and disables resource limits. Dedicated authorization tests must configure realistic authorization, and resource tests must enable or measure the relevant limits. A passing default scenario alone does not establish those properties.

Use focused targets while developing:

make test-harness
make test-one FILE=controller
make test-match PATTERN=liquidation
make test-pool

The domain binaries include smoke_test, controller, governance, oracle, pool, strategy, composition, meta, and fuzz. Additional regression binaries cover specific behavior.

Tests run in parallel by default because each test owns its environment and snapshot. Set TEST_THREADS=1 when diagnosing interactions between tests. Property-test targets run serially.

Property tests and fuzzing

Property tests generate contract scenarios and check invariants such as accounting conservation, liquidation arithmetic, authorization, and strategy settlement. The suite includes an exact rational reference for liquidation calculations and persists failing randomized cases in source-adjacent *.proptest-regressions files.

make proptest
make proptest-one TEST=prop_accounting_conservation PROPTEST_CASES=256

The property targets use release mode. Each randomized module has its own default case count; PROPTEST_CASES overrides that count. Deterministic regression tests in the same binary do not become randomized when the override changes.

The separate tests/fuzz/ workspace uses libFuzzer through cargo-fuzz and nightly Rust:

make fuzz-build
make fuzz FUZZ_TIME=60
make fuzz-contract FUZZ_TIME=60

make fuzz runs fp_math, rates_and_index, and fp_ops. make fuzz-contract runs flow_e2e, flow_strategy, pool_native, and aggregator. The time limit applies to each target.

Preserve and minimize a failing input before diagnosing it. A fuzz campaign establishes what its targets, seeds, inputs, and runtime exercise; it does not exhaust all protocol states.

Additional quality checks

Use these checks for a specific validation question:

Check Command What the result shows
Miri make miri-common Undefined-behavior checks for the selected pure fixed-point helpers.
Mutation testing make mutants-math, make mutants-pool Whether the selected tests detect generated changes to arithmetic or pool code.
Broader mutation testing make mutants Mutation checks across the configured contract and shared-code targets.
Coverage make coverage-merged Instrumented source coverage across the configured contract suites and shared harness.
Scoped coverage make coverage-controller, make coverage-pool Coverage for a selected contract.
Documentation make docs-check Repository documentation links and source references resolve.

Coverage output is written under target/coverage/. Coverage measures executed source, while mutation results help evaluate whether tests detect wrong behavior. Neither establishes protocol correctness on its own.

The keeper and lending exporter use separate Cargo workspaces. Run their checks through their own manifests when changing those services:

cargo test --manifest-path services/keeper/Cargo.toml
cargo test --manifest-path services/lending-exporter/Cargo.toml

Live testnet integration

The scripts in tests/integration/ deploy contracts, fund test wallets, and submit real network transactions. They exercise integration with the Stellar CLI, RPC, price sources, and swap routes. Local harness results do not establish that those dependencies are reachable or configured correctly.

From the repository root, build integration artifacts and run the testnet lanes:

make integration-wasm
NETWORK=testnet RUN_TS=$(date +%Y%m%d-%H%M%S) bash tests/integration/scenarios/parallel_e2e.sh

The default lanes are agg, liq, stress, flash, and blend. Each uses a separate run identifier and environment. E2E_LANES selects a narrower set for focused work.

The parallel runner checks process exits, completion markers, and each lane's recorded results. Unresolved failures, unexpected successes, and simulation errors fail the gate. Review the action log and expected failures as well as the final status; selecting fewer lanes narrows the evidence.

CI and review evidence

Workflows have branch and path filters, so inspect which jobs actually ran for the change.

Workflow Validation
tests.yml Formatting, documentation checks, selected shell syntax checks, artifact checks, workspace tests, and linting.
security.yml Authorization-coverage checks and Soroban security detectors.
scout.yml Scout detector reports with the configured severity threshold.
fuzz.yml Pull-request fuzz, property, Miri, and mutation checks; scheduled and manual campaigns.
coverage.yml Coverage reports and comparison with the main-branch baseline.
e2e.yml Manually dispatched testnet integration.

A useful review record identifies the revision, selected checks, inputs or case counts, observed results, and limitations. Report skipped checks and environmental failures explicitly. Passing CI is evidence for the jobs that execute, not a substitute for reviewing assumptions or deployed configuration.

Sources and related pages

Clone this wiki locally