KeiSeiKit-1.0/_primitives/_rust/kei-spawn/tests/drive_smoke.rs
Parfii-bot 0be354a920 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

130 lines
3.9 KiB
Rust

//! drive_smoke — integration tests for `kei-spawn drive` subcommand.
//!
//! The drive subcommand shells the full pipeline:
//! 1. spawn_from_task (prepare + ledger fork)
//! 2. SpawnOutput JSON → stdout
//! 3. ManualDriver::invoke → NotImplemented → stderr + exit 64
//!
//! Because exit-code assertions require invoking the real binary, these
//! tests use `CARGO_BIN_EXE_kei-spawn` (populated by cargo for integration
//! tests) with `KEI_SPAWN_LEDGER_NOOP=1` set so the ledger subprocess is
//! a no-op.
use std::path::Path;
use std::process::Command;
use tempfile::TempDir;
fn write_capability(root: &Path, cat: &str, slug: &str, body: &str) {
let dir = root.join("_capabilities").join(cat).join(slug);
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("text.md"), body).unwrap();
}
fn write_role(root: &Path, name: &str, toml: &str) {
std::fs::create_dir_all(root.join("_roles")).unwrap();
std::fs::write(root.join("_roles").join(format!("{name}.toml")), toml).unwrap();
}
fn write_task(root: &Path, toml: &str) -> std::path::PathBuf {
let path = root.join("task.toml");
std::fs::write(&path, toml).unwrap();
path
}
fn minimal_kit(root: &Path) {
write_capability(root, "policy", "no-git-ops", "## Never git.\n");
write_capability(root, "output", "report-format", "## Report fields.\n");
write_role(
root,
"edit-local",
r#"
[role]
name = "edit-local"
spawnable = true
claude-subagent-type = "code-implementer"
[capabilities]
required = ["policy::no-git-ops", "output::report-format"]
"#,
);
}
fn bin() -> Command {
let mut c = Command::new(env!("CARGO_BIN_EXE_kei-spawn"));
c.env("KEI_SPAWN_LEDGER_NOOP", "1");
c
}
#[test]
fn drive_on_valid_task_emits_spawn_json_and_exits_64() {
let tmp = TempDir::new().unwrap();
let root = tmp.path();
minimal_kit(root);
let task_path = write_task(
root,
r#"
[task]
role = "edit-local"
[body]
text = "Drive smoke test."
"#,
);
let output = bin()
.arg("drive")
.arg(&task_path)
.arg("--kit-root")
.arg(root)
.output()
.expect("run kei-spawn drive");
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
// Stdout must be SpawnOutput JSON (contain agent_id + prompt fields).
assert!(stdout.contains("\"agent_id\""), "stdout missing agent_id: {stdout}");
assert!(stdout.contains("\"subagent_type\""), "stdout missing subagent_type: {stdout}");
assert!(stdout.contains("\"prompt\""), "stdout missing prompt: {stdout}");
// Stderr must explain the v0.1 NotImplemented state.
assert!(
stderr.contains("HTTP Anthropic-API integration not yet wired"),
"stderr missing NotImplemented msg: {stderr}"
);
// Exit code 64 (EX_USAGE range, NotImplemented convention).
assert_eq!(output.status.code(), Some(64), "exit code must be 64, got: {:?}; stderr={stderr}", output.status.code());
}
#[test]
fn drive_on_unknown_role_exits_nonzero_with_spawn_error() {
let tmp = TempDir::new().unwrap();
let root = tmp.path();
// NO minimal_kit — role cannot resolve.
let task_path = write_task(
root,
r#"
[task]
role = "ghost-role"
[body]
text = "x"
"#,
);
let output = bin()
.arg("drive")
.arg(&task_path)
.arg("--kit-root")
.arg(root)
.output()
.expect("run kei-spawn drive");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("drive") || stderr.contains("role") || stderr.contains("ghost-role"),
"stderr should reference the spawn failure: {stderr}"
);
// Spawn error surfaces as exit 1 (not 64); must NOT be success.
let code = output.status.code();
assert_ne!(code, Some(0), "unknown role must fail");
assert_ne!(code, Some(64), "unknown role must not be NotImplemented: stderr={stderr}");
}