Building & Testing¶
Toolchain¶
The Rust toolchain is pinned in rust-toolchain.toml at the repository root.
rustup reads this file automatically, so the first build on a fresh checkout
installs the exact compiler, rustfmt, and clippy versions used by CI.
No manual rustup override is needed.
Building¶
Testing¶
A bare cargo test needs all four services
Several test binaries connect to a real service before their first test
can even run, and Cargo stops the whole run at the first binary that
fails. On a machine that's missing one of them — say, no MongoDB —
cargo test dies at mongo_app_manager's 30-second connection timeout,
and every binary Cargo would have run after it (percore*,
mysql_app_manager, postgres_app_manager, redis_*, rest, signin, tls, watchlist,
webhooks) never runs at all — including the ones that need no
infrastructure. Use the commands below instead of a bare cargo test.
Do not add --all-targets to cargo test
cargo test --all-targets -- --test-threads=1 fails, and not because
anything is broken. --all-targets pulls in the four criterion benches
(fanout, fanout_sink, mailbox, app_lookup), which are
harness = false and parse their own arguments — criterion rejects
--test-threads with error: unexpected argument found and the run dies
after every real test has already passed.
--all-targets belongs on cargo clippy, where the repo and CI both use
it, not on cargo test. A bare cargo test is safe (the bench targets are
test = false, so they are never built or run). If you want everything
except benches under a single-threaded harness, name the target kinds
explicitly:
Benches are exercised separately with cargo bench.
Tests that need no infrastructure¶
This is the primary, always-on gate CI runs, and needs nothing but the pinned toolchain. Run it before opening a pull request if you don't have the services below available locally:
scripts/test-no-infra.sh is the single source for this command: CI's
check job (services running) and its check-no-infra job (none at all)
both run it verbatim, so this page and CI cannot drift apart — a future test
that quietly needs a service (like one that used to sit here, see "Cluster /
Redis tests" below) fails the check-no-infra job instead of only a
contributor's local run.
Full suite (all services)¶
Running everything — the clustered/Redis suites and the per-backend AppManager suites included — requires all four services below:
| Service | Port | Env var |
|---|---|---|
| Redis | 6390 | PYLON_TEST_REDIS_URL |
| MySQL 8 | 3307 | PYLON_TEST_MYSQL_URL |
| Postgres 16 | 5433 | PYLON_TEST_POSTGRES_URL |
| Mongo 7 | 27018 | PYLON_TEST_MONGO_URL |
deploy/docker/docker-compose.test.yml
brings up all four on those ports: docker compose -f deploy/docker/docker-compose.test.yml up -d.
With those running and reachable, export the env vars above explicitly —
naming the instance each suite talks to is worth the keystrokes when the run
writes to it — and pass --no-fail-fast so one missing or misbehaving
backend doesn't hide the results of the others:
export PYLON_TEST_REDIS_URL=redis://127.0.0.1:6390
export PYLON_TEST_MYSQL_URL=mysql://root:pylon@127.0.0.1:3307/pylon_test
export PYLON_TEST_POSTGRES_URL=postgres://postgres:pylon@127.0.0.1:5433/pylon_test
export PYLON_TEST_MONGO_URL=mongodb://127.0.0.1:27018/pylon_test
cargo test --locked --no-fail-fast -- --test-threads=1
Cluster / Redis tests¶
Tests that exercise the clustered path, the Redis adapter, or the Redis-backed
L2 app cache and cross-node invalidation require a local Redis instance.
Point at it with the PYLON_TEST_REDIS_URL environment variable:
PYLON_TEST_REDIS_URL=redis://127.0.0.1:6390 \
cargo test --test cluster_bridge --test redis_app_cache --test redis_cluster -- --test-threads=1
Never FLUSH a shared Redis
Tests isolate themselves with random key prefixes. Do not run
FLUSHALL or FLUSHDB on a Redis instance that holds data you care
about — and never point PYLON_TEST_REDIS_URL at a production Redis.
Cluster tests must run serially (--test-threads=1) because several of them
assert on short Redis round-trip timing windows that race under parallel
execution.
Formatting and Linting¶
Both are gated in CI on every push and pull request:
cargo fmt --all --check # check formatting (CI gate)
cargo fmt --all # apply formatting (before committing)
cargo clippy --all-targets --locked -- -D warnings # lint (CI gate; zero warnings allowed)
cargo clippy --locked --lib --bins -- -D warnings # lint, default features only (CI gate)
CI runs both clippy commands, not just the first. A dev-dependency self-reference enables the
test-hooks feature whenever test targets are in the build graph, so --all-targets cannot see
warnings that only appear in the default-features build (cargo build --release, cargo install)
— the second command is the only one that lints that build.
Load-Testing Crate¶
The load/ workspace crate contains scenario-based load tests and the
pylon-ceiling capacity-finder binary. pylon-ceiling ramps connections in
fixed-size batches (--conn-batch) to find the maximum sustainable
concurrency on a given host, taking latency, CPU, and memory constraints as
stop criteria.
See load/ for details
on running load scenarios and the ceiling tool.