The single bare-metal integration test now reuses a `LazyLock<Fixture>` that spawns picloud once on a private port and shares it across every test in the binary. Sets the stage for per-surface journey modules (auth, apps, scripts, invoke, logs, roles, output) without each one paying for its own server spawn — same trick the dashboard Playwright suite uses with global-setup. Notes: - `tests/cli.rs` becomes a tiny module list; the seed flow moved to `tests/integration.rs`. The seed slug now goes through `common::unique_slug` so parallel/serial reruns can't collide. - `autotests = false` + an explicit `[[test]] name = "cli"` keeps Cargo from auto-promoting future `tests/*.rs` files into their own binaries (which would each respawn picloud). - Subprocess cleanup uses `libc::atexit` to SIGTERM picloud when the test binary exits. PR_SET_PDEATHSIG was tried and rejected: it fires when the *thread* that forked dies, and cargo's per-test worker threads exit between tests, which killed the fixture mid-suite. - New helpers: AppGuard/UserGuard (RAII teardown), member_user / grant_membership / update_membership (direct API for role tests), unique_slug / unique_username, pic_as / pic_no_env. - Two `fixture_url_is_shared_*` tests prove the LazyLock is actually shared, not respawned per test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
62 lines
1.5 KiB
Rust
62 lines
1.5 KiB
Rust
//! RAII guards that delete server-side resources on `Drop`.
|
|
//!
|
|
//! Each guard owns the minimum it needs to issue a single DELETE: the
|
|
//! base URL, an admin bearer token, and the resource identifier.
|
|
//! Failures are swallowed because Drop runs during teardown — a panic
|
|
//! here would just mask the real failure that the test was reporting.
|
|
|
|
pub struct AppGuard {
|
|
url: String,
|
|
token: String,
|
|
slug: String,
|
|
}
|
|
|
|
impl AppGuard {
|
|
pub fn new(url: &str, token: &str, slug: &str) -> Self {
|
|
Self {
|
|
url: url.to_string(),
|
|
token: token.to_string(),
|
|
slug: slug.to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Drop for AppGuard {
|
|
fn drop(&mut self) {
|
|
let client = reqwest::blocking::Client::new();
|
|
let _ = client
|
|
.delete(format!(
|
|
"{}/api/v1/admin/apps/{}?force=true",
|
|
self.url, self.slug
|
|
))
|
|
.bearer_auth(&self.token)
|
|
.send();
|
|
}
|
|
}
|
|
|
|
pub struct UserGuard {
|
|
url: String,
|
|
token: String,
|
|
user_id: String,
|
|
}
|
|
|
|
impl UserGuard {
|
|
pub fn new(url: &str, token: &str, user_id: &str) -> Self {
|
|
Self {
|
|
url: url.to_string(),
|
|
token: token.to_string(),
|
|
user_id: user_id.to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Drop for UserGuard {
|
|
fn drop(&mut self) {
|
|
let client = reqwest::blocking::Client::new();
|
|
let _ = client
|
|
.delete(format!("{}/api/v1/admin/admins/{}", self.url, self.user_id))
|
|
.bearer_auth(&self.token)
|
|
.send();
|
|
}
|
|
}
|