use std::path::PathBuf;
use std::process::Command;
use tempfile::TempDir;
fn bin(home: &TempDir) -> Command {
let mut c = Command::new(env!("CARGO_BIN_EXE_orchestratectl"));
c.env("ORCHESTRATECTL_HOME", home.path());
c
}
fn log_file(home: &TempDir) -> PathBuf {
home.path().join("logs").join("orchestratectl.log.jsonl")
}
#[test]
fn clean_exit_flushes_jsonl_log_lines() {
let home = TempDir::new().unwrap();
let out = bin(&home).arg("version").output().expect("spawn");
assert!(out.status.success(), "exit: {:?}", out.status);
let path = log_file(&home);
assert!(
path.exists(),
"log file was not created at {}",
path.display()
);
let contents = std::fs::read_to_string(&path).expect("read log file");
let lines: Vec<&str> = contents.lines().filter(|l| !l.trim().is_empty()).collect();
assert!(
!lines.is_empty(),
"no log lines were flushed — guard likely dropped before exit"
);
let mut saw_dispatch = false;
for line in &lines {
let v: serde_json::Value = serde_json::from_str(line)
.unwrap_or_else(|e| panic!("non-JSON log line {line:?}: {e}"));
assert!(v.is_object(), "log line is not a JSON object: {line:?}");
if v["fields"]["message"] == "command dispatched" {
saw_dispatch = true;
}
}
assert!(
saw_dispatch,
"did not find the 'command dispatched' event in:\n{contents}"
);
}
#[test]
fn repeated_invocations_append_without_truncation() {
let home = TempDir::new().unwrap();
let out1 = bin(&home).arg("version").output().expect("spawn 1");
assert!(out1.status.success(), "first run failed: {:?}", out1.status);
let first = std::fs::read_to_string(log_file(&home)).expect("read after first run");
let first_lines: Vec<String> = first
.lines()
.filter(|l| !l.trim().is_empty())
.map(str::to_owned)
.collect();
assert!(!first_lines.is_empty(), "first run wrote no log lines");
let out2 = bin(&home).arg("version").output().expect("spawn 2");
assert!(
out2.status.success(),
"second run failed: {:?}",
out2.status
);
let second = std::fs::read_to_string(log_file(&home)).expect("read after second run");
let second_lines: Vec<String> = second
.lines()
.filter(|l| !l.trim().is_empty())
.map(str::to_owned)
.collect();
assert!(
second_lines.len() > first_lines.len(),
"second run did not append (first={}, second={})",
first_lines.len(),
second_lines.len()
);
assert_eq!(
&second_lines[..first_lines.len()],
first_lines.as_slice(),
"first run's log lines were not preserved as a prefix — file was truncated/rewritten"
);
}