ci: run the DB-backed tests that CI was silently skipping

CI ran `cargo test --workspace` with no `--include-ignored`, so it executed 927
tests and skipped 237 — every DB-backed integration test is
`#[ignore = "needs DATABASE_URL..."]`, which covers ALL of api.rs, ALL of
authz.rs, and the entire CLI journey suite. The isolation and RBAC tests existed
but never ran (AUDIT.md F-Q-014, logged and never remediated). CI provides
Postgres, so it can run them.

Three things had to be right for that to go green:

- **`--all-targets`, not a bare workspace run.** `-- --include-ignored` un-ignores
  not just `#[ignore]` tests but also ` ```ignore ` DOCTESTS, which are
  illustrative pseudocode that does not compile. `--all-targets` runs lib/bins/
  integration tests but excludes doctests (the same reason clippy uses it); a
  separate `--doc` step runs the doctests without the flag. Structural, so a
  future pseudocode doctest can't silently break CI either.

- **The CLI journeys are their own step.** They spawn a real picloud whose
  dispatcher/orchestrator claim loops are global by design; run concurrently with
  the manager-core suites on the shared database they would claim those suites'
  outbox and workflow rows. Sequential steps keep the live server off the DB
  while the other suites use it. The step also rebuilds `-p picloud` first (the
  harness execs the prebuilt binary) and sets the dev-mode env the server needs.

- **A higher `max_connections`.** `#[sqlx::test]` pools are lazy, but mass-parallel
  test startup briefly opens many at once (each test creates its own throwaway
  database); on a many-core box that transient spike exceeded the default 100 and
  Postgres answered "sorry, too many clients already". Steady-state peak is only
  ~26; 500 absorbs the spike with room to spare. Serving the app needs nothing
  like this many. (This is the local compose ceiling; a small CI runner's default
  100 has ample headroom for its lower parallelism.)

Also fixes the test the CI gap had let rot: api.rs asserted `v["schema"] == 66`
with a hand-bump comment, and since nothing ran it, it sat broken from migration
0066 to 0073. It now asserts `/version` surfaces the live constants
(`migrations::latest_version()`, `SDK_VERSION`) — the wiring — while value drift
stays caught by schema_snapshot + check-versioning. A constant hand-synced to
another constant is a chore, not a test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-15 07:27:21 +02:00
parent 251d7fe3dd
commit b5ce4cec01
3 changed files with 67 additions and 13 deletions

View File

@@ -47,11 +47,49 @@ jobs:
- name: Clippy - name: Clippy
run: cargo clippy --all-targets --all-features -- -D warnings run: cargo clippy --all-targets --all-features -- -D warnings
# Runs the whole workspace, including the schema-snapshot guardrail # `--include-ignored` is load-bearing. Every DB-backed integration test is
# (it picks up DATABASE_URL from the env above and the postgres # `#[ignore = "needs DATABASE_URL..."]`, and CI omitted the flag — so CI ran
# service; without a DB it would skip cleanly). # 927 tests and silently skipped 237, among them ALL of authz.rs and api.rs
- name: Test # and the entire CLI journey suite. The isolation and RBAC tests existed but
run: cargo test --workspace # never executed (AUDIT.md F-Q-014). CI does provide Postgres, so run them.
#
# `--all-targets` (not a bare `cargo test`) is deliberate: it runs the lib,
# bins, and integration tests but NOT doctests. `-- --include-ignored`
# un-ignores not just `#[ignore]` tests but also ` ```ignore ` DOCTESTS,
# which are illustrative pseudocode that does not compile — so a bare
# `cargo test ... -- --include-ignored` fails on them. Doctests run in their
# own step below, without the flag. (Clippy already uses `--all-targets` for
# the same doctest-excluding reason.)
#
# The CLI journeys are a SEPARATE step, and deliberately not part of the
# workspace run: they spawn a real picloud whose dispatcher/orchestrator
# claim loops are global by design (one instance owns one database). Run
# concurrently with the manager-core suites — which share this database —
# it would claim their outbox and workflow rows out from under them. Keeping
# the steps sequential keeps that live server off the shared DB while the
# other suites are using it.
- name: Test (workspace, including DB-backed tests)
run: cargo test --workspace --exclude picloud-cli --all-targets -- --include-ignored
# Doctests, run WITHOUT --include-ignored so ` ```ignore ` snippets stay
# ignored. `--all-targets` above skips these, so nothing else covers them.
- name: Doctests
run: cargo test --workspace --doc
# The journey harness execs the prebuilt target/debug/picloud and does NOT
# rebuild it, so a stale binary would silently test old server code.
- name: Build picloud (the journey harness execs this binary)
run: cargo build -p picloud
# The spawned server inherits this env; without a secret key it aborts at
# startup and every journey fails as "/healthz never returned 200".
# `--all-targets` for the same reason as above (the journeys are `#[ignore]`
# integration tests; picloud-cli's doctests, if any, run in the Doctests step).
- name: Test (CLI journeys)
env:
PICLOUD_DEV_MODE: "true"
PICLOUD_DEV_INSECURE_KEY: i-understand-this-is-insecure
run: cargo test -p picloud-cli --all-targets -- --include-ignored
dashboard: dashboard:
name: Dashboard — check name: Dashboard — check

View File

@@ -890,14 +890,22 @@ async fn version_includes_public_base_url(pool: PgPool) {
let v: Value = r.json(); let v: Value = r.json();
assert!(v["public_base_url"].is_string()); assert!(v["public_base_url"].is_string());
assert_eq!(v["api"], 1); assert_eq!(v["api"], 1);
// `schema` is migrations::latest_version() — the highest embedded // This asserts the WIRING — that `/version` actually surfaces the live
// migration number, currently 66 (…0065_group_queues, then // constants — not the values themselves. It used to hardcode `66`, with a
// 0066_projects wiring the §7 multi-repo ownership seam). This test is // comment to bump it by hand on every migration. Nobody did: CI never ran
// #[ignore]-gated so it doesn't run in the default `cargo test`; pinned to // this test (it is `#[ignore]`d, and CI omitted `--include-ignored`), so it
// current reality so an unintended schema change is still caught. Bump it // sat broken from 0066 all the way to 0073 and only surfaced when the CI gap
// whenever a migration lands. // was closed. A constant that must be hand-synced with a constant is not a
assert_eq!(v["schema"], 66); // test, it is a chore that fails silently.
assert_eq!(v["sdk"], "1.10"); //
// Drift in the values is already caught where it belongs: the schema by
// `manager-core/tests/schema_snapshot.rs`, the version surfaces by
// `scripts/check-versioning.sh`.
assert_eq!(
v["schema"],
picloud_manager_core::migrations::latest_version()
);
assert_eq!(v["sdk"], picloud_shared::version::SDK_VERSION);
} }
// ============================================================================ // ============================================================================

View File

@@ -14,6 +14,14 @@ name: picloud
services: services:
postgres: postgres:
image: postgres:16-alpine image: postgres:16-alpine
# The default ceiling of 100 is not enough to RUN THE TEST SUITE. libtest runs
# ~nproc tests concurrently, and every `#[sqlx::test]` opens its own pool
# against its own throwaway database — on a 16-core box that alone exceeds 100,
# and Postgres answers with "sorry, too many clients already". The DB-backed
# tests were all `#[ignore]`d and CI never passed `--include-ignored`, so this
# ceiling was never actually exercised; it surfaced the moment CI started
# running them. Serving the app needs nothing like this many.
command: postgres -c max_connections=500
environment: environment:
POSTGRES_DB: ${POSTGRES_DB:-picloud} POSTGRES_DB: ${POSTGRES_DB:-picloud}
POSTGRES_USER: ${POSTGRES_USER:-picloud} POSTGRES_USER: ${POSTGRES_USER:-picloud}