Files
PiCloud/crates/picloud-cli/tests/enabled.rs
MechaCat02 9e1c24f729 test(enabled): end-to-end route-disable journey
Close the coverage asymmetry flagged in review: script-disable had a full
e2e journey but route-disable was only unit-tested (compile_routes) plus
the apply-refresh path. Add an HTTP-level journey — claim a Host for the
app (two-phase dispatch needs it), then serve `/hello` (200), flip the
route's `enabled = false` and re-apply (404, indistinguishable from
absent), and re-enable (200).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 20:48:04 +02:00

178 lines
5.7 KiB
Rust

//! `enabled` three-state lifecycle, end to end: disabling a script via the
//! manifest makes it non-invocable (404 on the execute-by-id bypass), and
//! re-enabling restores it — proving the data path + runtime honoring.
use std::fs;
use std::path::Path;
use serde_json::Value;
use tempfile::TempDir;
use crate::common;
use crate::common::cleanup::AppGuard;
#[ignore = "needs DATABASE_URL pointing at a running Postgres"]
#[test]
fn disabling_a_script_makes_it_uninvocable_then_reenable() {
let Some(fx) = common::fixture_or_skip() else {
return;
};
let env = common::admin_env(fx);
let slug = common::unique_slug("enabled");
common::pic_as(&env)
.args(["apps", "create", &slug])
.assert()
.success();
let _guard = AppGuard::new(&env.url, &env.token, &slug);
let dir = TempDir::new().unwrap();
fs::create_dir_all(dir.path().join("scripts")).unwrap();
fs::write(dir.path().join("scripts/hello.rhai"), "\"hi\"").unwrap();
let manifest_path = dir.path().join("picloud.toml");
let manifest = |enabled_line: &str| {
format!(
"[app]\nslug = \"{slug}\"\nname = \"Enabled\"\n\n\
[[scripts]]\nname = \"hello\"\nfile = \"scripts/hello.rhai\"\n{enabled_line}"
)
};
// Active → invocable.
fs::write(&manifest_path, manifest("")).unwrap();
apply(&env, &manifest_path);
let id = script_id(&env, &slug, "hello");
assert_eq!(invoke_status(&env, &id), 200, "active script must invoke");
// Disabled → 404 (not invocable), but still deployed (re-pull would show it).
fs::write(&manifest_path, manifest("enabled = false\n")).unwrap();
apply(&env, &manifest_path);
assert_eq!(
invoke_status(&env, &id),
404,
"disabled script must 404 on execute-by-id"
);
// Re-enabled → invocable again.
fs::write(&manifest_path, manifest("enabled = true\n")).unwrap();
apply(&env, &manifest_path);
assert_eq!(
invoke_status(&env, &id),
200,
"re-enabled script must invoke"
);
}
#[ignore = "needs DATABASE_URL pointing at a running Postgres"]
#[test]
fn disabling_a_route_makes_it_404_then_reenable() {
let Some(fx) = common::fixture_or_skip() else {
return;
};
let env = common::admin_env(fx);
let slug = common::unique_slug("enbl-route");
common::pic_as(&env)
.args(["apps", "create", &slug])
.assert()
.success();
let _guard = AppGuard::new(&env.url, &env.token, &slug);
// The app must claim a Host before its routes are reachable (two-phase
// dispatch: Host → app → route). A unique strict host avoids colliding
// with other tests' instance-global claims.
let host = format!("{slug}.test");
common::pic_as(&env)
.args(["apps", "domains", "add", &slug, &host])
.assert()
.success();
let dir = TempDir::new().unwrap();
fs::create_dir_all(dir.path().join("scripts")).unwrap();
fs::write(dir.path().join("scripts/hello.rhai"), "\"hi\"").unwrap();
let manifest_path = dir.path().join("picloud.toml");
let manifest = |enabled_line: &str| {
format!(
"[app]\nslug = \"{slug}\"\nname = \"EnabledRoute\"\n\n\
[[scripts]]\nname = \"hello\"\nfile = \"scripts/hello.rhai\"\n\n\
[[routes]]\nscript = \"hello\"\nmethod = \"GET\"\n\
host_kind = \"any\"\npath_kind = \"exact\"\npath = \"/hello\"\n{enabled_line}"
)
};
// Active → the route serves.
fs::write(&manifest_path, manifest("")).unwrap();
apply(&env, &manifest_path);
assert_eq!(
route_status(&env, &host, "/hello"),
200,
"active route serves"
);
// Disabled → 404, indistinguishable from absent.
fs::write(&manifest_path, manifest("enabled = false\n")).unwrap();
apply(&env, &manifest_path);
assert_eq!(
route_status(&env, &host, "/hello"),
404,
"disabled route must 404"
);
// Re-enabled → serves again.
fs::write(&manifest_path, manifest("enabled = true\n")).unwrap();
apply(&env, &manifest_path);
assert_eq!(
route_status(&env, &host, "/hello"),
200,
"re-enabled route serves"
);
}
fn apply(env: &common::TestEnv, manifest_path: &Path) {
common::pic_as(env)
.args(["apply", "--file"])
.arg(manifest_path)
.assert()
.success();
}
/// GET a user route under an explicit `Host` (the claimed domain) and return
/// the HTTP status code.
fn route_status(env: &common::TestEnv, host: &str, path: &str) -> u16 {
let client = reqwest::blocking::Client::new();
client
.get(format!("{}{path}", env.url))
.header(reqwest::header::HOST, host)
.send()
.unwrap()
.status()
.as_u16()
}
/// Resolve a script's id via the admin API (the manifest carries no ids).
fn script_id(env: &common::TestEnv, slug: &str, name: &str) -> String {
let client = reqwest::blocking::Client::new();
let scripts: Vec<Value> = client
.get(format!("{}/api/v1/admin/scripts?app={slug}", env.url))
.bearer_auth(&env.token)
.send()
.unwrap()
.json()
.unwrap();
scripts
.into_iter()
.find(|s| s["name"] == name)
.and_then(|s| s["id"].as_str().map(String::from))
.expect("script id")
}
/// POST the execute-by-id bypass and return the HTTP status code.
fn invoke_status(env: &common::TestEnv, id: &str) -> u16 {
let client = reqwest::blocking::Client::new();
client
.post(format!("{}/api/v1/execute/{id}", env.url))
.bearer_auth(&env.token)
.body("{}")
.send()
.unwrap()
.status()
.as_u16()
}