use std::sync::atomic::Ordering;
use super::*;
use crate::{ErrorCode, Occupied};
fn sealing() -> String {
let mut m: serde_json::Value = serde_json::from_str(&without_guest_delivery()).unwrap();
m["params"].as_array_mut().unwrap().push(serde_json::json!({
"name": "sealed", "description": "The lab is sealed: its internet: false networks closed at the cloud's firewalls.",
"default": "false", "values": ["true", "false"], "set_by": "runner",
"deliver": [{"via": "tf_var", "var": "sealed"}]
}));
let apply = m["lifecycle"]["up"].as_array().unwrap().iter().find(|s| s["id"] == "apply").unwrap().clone();
let mut seal = apply;
seal["id"] = serde_json::json!("seal");
m["lifecycle"]["seal"] = serde_json::json!({"param": "sealed", "steps": [seal]});
m.to_string()
}
fn sealed_in(a: &Account, what: &str) -> Vec<String> {
let calls = a.fake.calls();
calls
.iter()
.filter(|c| c.line().starts_with(what))
.map(|c| c.env("TF_VAR_sealed").unwrap_or("-").to_owned())
.collect()
}
#[tokio::test(start_paused = true)]
async fn a_run_is_sealed_once_ready_then_reported_ready() {
let a = account_of(&sealing(), 0);
let lab = a.runner.open(&a.folder.manifest, None).unwrap();
let run = lab.up(&opts("eu-west-3", "labs"), &Recorder::new()).await.unwrap();
assert_eq!(sealed_in(&a, "terraform apply"), ["false", "true"], "set up open, then sealed");
let lines = a.fake.lines();
let seal = lines.iter().rposition(|l| l.starts_with("terraform apply")).unwrap();
assert!(seal > lines.iter().position(|l| l.contains("head -n 1")).unwrap(), "after the ready file");
assert_eq!(run.record.params.get("sealed").map(String::as_str), Some("true"));
assert_eq!(run.record.state, RunState::Ready);
}
#[tokio::test(start_paused = true)]
async fn a_failed_seal_leaves_the_run_not_ready_and_says_so() {
let a = account_of(&sealing(), 0);
a.cloud.seal_fails.store(true, Ordering::SeqCst);
let lab = a.runner.open(&a.folder.manifest, None).unwrap();
let err = lab.up(&opts("eu-west-3", "labs"), &Recorder::new()).await.unwrap_err();
assert_eq!(err.code(), ErrorCode::NotSealed);
assert!(err.to_string().contains("UnauthorizedOperation"), "{err}");
let record = a.runner.store.record(lab.name()).unwrap().unwrap();
assert_eq!(record.state, RunState::Failed, "never ready unsealed");
assert_eq!(record.last.unwrap().code, Some(ErrorCode::NotSealed));
assert_ne!(lab.status().await.unwrap().state, RunState::Ready);
lab.down(&opts("eu-west-3", "labs"), &Recorder::new()).await.unwrap();
assert_eq!(sealed_in(&a, "terraform destroy"), ["true"]);
}
#[tokio::test(start_paused = true)]
async fn every_later_operation_replays_the_seal_and_a_down_forgets_it() {
let a = account_of(&sealing(), 0);
let lab = a.runner.open(&a.folder.manifest, None).unwrap();
lab.up(&opts("eu-west-3", "labs"), &Recorder::new()).await.unwrap();
let again = opts("us-east-1", "default").with_occupied(Occupied::Replace);
lab.up(&again, &Recorder::new()).await.unwrap();
assert_eq!(sealed_in(&a, "terraform destroy"), ["true"], "the leftovers' destroy keeps the seal");
let destroy = a.fake.last("terraform destroy").unwrap();
assert_eq!(destroy.env("TF_VAR_region"), Some("eu-west-3"), "and goes where they were applied");
assert_eq!(sealed_in(&a, "terraform apply"), ["false", "true", "false", "true"]);
lab.down(&opts("us-east-1", "default"), &Recorder::new()).await.unwrap();
assert_eq!(sealed_in(&a, "terraform destroy"), ["true", "true"], "the down replays it");
let record = a.runner.store.record(lab.name()).unwrap().unwrap();
assert!(!record.params.contains_key("sealed"), "forgotten after a successful down");
lab.up(&opts("eu-west-3", "labs"), &Recorder::new()).await.unwrap();
assert_eq!(sealed_in(&a, "terraform apply")[4], "false", "a fresh start begins unsealed");
}