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
91 lines
2.7 KiB
Rust
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
|
|
);
|
|
}
|