//! Phase-3 config `vars`, end to end via `pic`: a group-owned var is //! inherited by an app underneath it, and an app-owned var of the same key //! overrides the inherited value (proximity wins, §3). //! //! Drives the real resolution path: a script does `vars::get("region")` //! and returns it; we invoke it via `/api/v1/execute/{id}` and assert on //! the body. First the group value flows down (inheritance), then an app //! value shadows it (override). use crate::common; use crate::common::cleanup::{AppGuard, GroupGuard}; #[ignore = "needs DATABASE_URL pointing at a running Postgres"] #[test] fn group_var_is_inherited_then_app_value_overrides() { let Some(fx) = common::fixture_or_skip() else { return; }; let env = common::admin_env(fx); let acme = common::unique_slug("v-acme"); let app = common::unique_slug("v-app"); // Group `acme`, then a `region` var on it (a JSON string "eu"). let _g_acme = GroupGuard::new(&env.url, &env.token, &acme); common::pic_as(&env) .args(["groups", "create", &acme]) .assert() .success(); common::pic_as(&env) .args(["vars", "set", "region", "eu", "--group", &acme]) .assert() .success(); // App under acme with a script that reads + returns the resolved var. let _app = AppGuard::new(&env.url, &env.token, &app); common::pic_as(&env) .args(["apps", "create", &app, "--group", &acme]) .assert() .success(); let fixture = common::fixture_path("read-var.rhai"); common::pic_as(&env) .args([ "scripts", "deploy", fixture.to_str().unwrap(), "--app", &app, ]) .assert() .success(); // Resolve the deployed script's id. let ls = common::pic_as(&env) .args(["scripts", "ls", "--app", &app]) .output() .expect("scripts ls"); let id = common::parse_first_id(std::str::from_utf8(&ls.stdout).unwrap()) .expect("scripts ls should produce one row"); // Inherited: the app has no own `region`, so the group's "eu" resolves. assert_eq!(invoke_body(&env, &id), serde_json::json!("eu"), "inherited"); // Proximity override: an app-owned `region` shadows the group value. common::pic_as(&env) .args(["vars", "set", "region", "us", "--app", &app]) .assert() .success(); assert_eq!(invoke_body(&env, &id), serde_json::json!("us"), "override"); } /// Invoke a script via `pic scripts invoke ` (→ `/api/v1/execute/{id}`) /// and parse its JSON body. fn invoke_body(env: &common::TestEnv, id: &str) -> serde_json::Value { let out = common::pic_as(env) .args(["scripts", "invoke", id]) .output() .expect("scripts invoke"); assert!( out.status.success(), "invoke failed: {}", String::from_utf8_lossy(&out.stderr) ); serde_json::from_slice(&out.stdout).expect("invoke body is JSON") }