use super::handlers::*;
use super::types::*;
use pforge_runtime::Handler;
fn project(dir: &std::path::Path) -> std::path::PathBuf {
let cfg = dir.join("forjar.yaml");
std::fs::write(
&cfg,
format!(
r#"
version: "1.0"
name: parity
machines:
local:
hostname: localhost
addr: localhost
resources:
real:
type: file
machine: local
path: {}
content: hi
action:
type: task
machine: local
phony: true
command: "echo run"
"#,
dir.join("f.txt").display()
),
)
.unwrap();
cfg
}
fn converged_lock(dir: &std::path::Path, cfg: &std::path::Path) {
let config = crate::core::parser::parse_and_validate(cfg).unwrap();
let hash = crate::core::planner::hash_desired_state(&config.resources["real"]);
let md = dir.join("state").join("local");
std::fs::create_dir_all(&md).unwrap();
std::fs::write(
md.join("state.lock.yaml"),
format!(
"schema: \"1.0\"\nmachine: local\nhostname: localhost\ngenerated_at: now\n\
generator: test\nblake3_version: \"1\"\nresources:\n real:\n type: file\n\
\x20 status: converged\n hash: \"{hash}\"\n"
),
)
.unwrap();
std::fs::write(dir.join("f.txt"), "hi").unwrap();
}
#[tokio::test]
async fn plan_reports_only_real_changes_not_every_resource() {
let d = tempfile::tempdir().unwrap();
let cfg = project(d.path());
converged_lock(d.path(), &cfg);
let out = PlanHandler
.handle(PlanInput {
path: cfg.display().to_string(),
state_dir: Some(d.path().join("state").display().to_string()),
resource: None,
tag: None,
})
.await
.expect("plan runs");
assert!(
!out.changes.iter().any(|c| c.resource_id == "real"),
"a converged resource must not be reported as a change: {:?}",
out.changes
);
assert!(
!out.changes.iter().any(|c| c.resource_id == "action"),
"a phony resource is goal-only and must not appear in a bulk plan: {:?}",
out.changes
);
}
#[tokio::test]
async fn plan_still_reports_a_genuine_change() {
let d = tempfile::tempdir().unwrap();
let cfg = project(d.path());
let out = PlanHandler
.handle(PlanInput {
path: cfg.display().to_string(),
state_dir: Some(d.path().join("state").display().to_string()),
resource: None,
tag: None,
})
.await
.expect("plan runs");
assert!(
out.changes.iter().any(|c| c.resource_id == "real"),
"nothing has been applied, so `real` must be planned: {:?}",
out.changes
);
}
#[tokio::test]
async fn status_finds_machines_whose_state_is_a_directory() {
let d = tempfile::tempdir().unwrap();
let cfg = project(d.path());
converged_lock(d.path(), &cfg);
let out = StatusHandler
.handle(StatusInput {
state_dir: Some(d.path().join("state").display().to_string()),
machine: None,
})
.await
.expect("status runs");
assert_eq!(
out.machines.len(),
1,
"expected the `local` machine: {:?}",
out.machines
);
assert_eq!(out.machines[0].name, "local");
assert_eq!(out.machines[0].resource_count, 1);
}
#[tokio::test]
async fn status_ignores_a_directory_with_no_lock() {
let d = tempfile::tempdir().unwrap();
std::fs::create_dir_all(d.path().join("state").join("not-a-machine")).unwrap();
let out = StatusHandler
.handle(StatusInput {
state_dir: Some(d.path().join("state").display().to_string()),
machine: None,
})
.await
.expect("status runs");
assert!(out.machines.is_empty(), "{:?}", out.machines);
}