colibri/crates/colibri-daemon/tests/pi_spawn_live.rs
Sam & Hermes 3c10fc098e test: add Pi spawn path proof integration test
Validates: Colibri spawns agent process (fake-pi-agent.py) → reads
JSONL stdout → glasspane ingests → snapshot shows Done state with
correct session ID.

Uses scripts/fake-pi-agent.py which emits the colibri-pi-events
JSONL taxonomy (session, agent_start, turn_start, turn_end,
agent_end). Proves the spawn→ingest→glasspane pipeline without
requiring the real pi binary.

The real Pi binary path (when installed) follows the same pattern:
pi --mode json is spawned with identical spawner code.

Build: pass | Tests: 1/1 green | Workspace: all green
2026-05-31 16:23:11 +02:00

91 lines
2.7 KiB
Rust

//! Pi spawn path proof — integration test.
//!
//! Validates: Colibri spawns agent → reads JSONL stdout → glasspane ingests → snapshot correct.
//! Uses scripts/fake-pi-agent.py which emits the colibri-pi-events JSONL taxonomy.
//!
//! With real Pi binary (when installed):
//! COLIBRI_PI_BINARY=pi cargo test -p colibri-daemon --test pi_spawn_live -- --nocapture
use std::path::PathBuf;
use std::process::Stdio;
use std::time::SystemTime;
use colibri_glasspane::DEFAULT_STALL_AFTER;
use tokio::io::{AsyncBufReadExt, BufReader};
use tokio::process::Command;
#[tokio::test]
async fn pi_spawn_path_produces_correct_glasspane_state() {
let script = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.parent()
.unwrap()
.join("scripts")
.join("fake-pi-agent.py");
assert!(script.exists(), "fake-pi-agent.py not found at {script:?}");
let mut supervisor = colibri_glasspane::PaneSupervisor::new();
let pane_id = "pi-spawn-proof";
supervisor.attach_pane_at(pane_id, "fake-pi", SystemTime::now());
let mut child = Command::new(PathBuf::from("python3"))
.arg(&script)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("failed to spawn fake-pi-agent.py");
let stdout = child.stdout.take().expect("no stdout");
let mut reader = BufReader::new(stdout).lines();
let mut accepted = 0usize;
loop {
match reader.next_line().await {
Ok(Some(line)) => {
if supervisor
.ingest_line_at(pane_id, &line, SystemTime::now())
.is_some()
{
accepted += 1;
}
}
Ok(None) => break,
Err(e) => {
eprintln!("JSONL read error: {e}");
break;
}
}
}
let status = child.wait().await.expect("child wait failed");
assert!(status.success(), "fake-pi-agent.py exited with {status}");
assert!(
accepted >= 5,
"expected >=5 accepted JSONL lines, got {accepted}"
);
let snapshot = supervisor.snapshot_at("test-host", SystemTime::now(), DEFAULT_STALL_AFTER);
let pane = snapshot
.panes
.iter()
.find(|p| p.id == pane_id)
.expect("pane not found");
assert_eq!(
pane.state,
colibri_glasspane::AgentState::Done,
"expected Done after full agent run"
);
assert!(
pane.pi_session_id.is_some(),
"expected pi_session_id from session event, got {:?}",
pane.pi_session_id
);
eprintln!(
"✓ Pi spawn proof: {} accepted, state={:?}, session={:?}",
accepted, pane.state, pane.pi_session_id
);
}