use std::path::PathBuf;
use std::process::{Command, Output};
const SESSION: &str = "7c1d2e3f-4a5b-6c7d-8e9f-0a1b2c3d4e5f";
fn bin() -> PathBuf {
PathBuf::from(env!("CARGO_BIN_EXE_supercode"))
}
fn fixtures() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../harness/tests/fixtures")
}
fn temp_root(label: &str) -> PathBuf {
let dir = std::env::temp_dir().join(format!(
"orc11-import-{label}-{}-{}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
));
std::fs::create_dir_all(&dir).unwrap();
dir
}
fn run(root: &PathBuf, args: &[&str]) -> Output {
Command::new(bin())
.env("CLAUDE_CONFIG_DIR", fixtures().join("claude_jobs_home"))
.env("SUPERCODE_ORCHESTRATOR_HOME", root)
.env("HERMES_HOME", root.join("no-hermes"))
.env("OPENCLAW_STATE_DIR", root.join("no-openclaw"))
.args(args)
.output()
.expect("supercode binary runs")
}
fn json_of(output: &Output) -> serde_json::Value {
assert!(
output.status.success(),
"command failed: {}",
String::from_utf8_lossy(&output.stderr)
);
serde_json::from_slice(&output.stdout).expect("stdout is JSON")
}
#[test]
fn import_compiles_the_sessions_cron_and_wakeup_into_the_orchestrators_store() {
let root = temp_root("compile");
let result = json_of(&run(
&root,
&[
"orchestrator",
"import",
"--from",
"claude-session",
SESSION,
"--json",
],
));
assert_eq!(result["source"]["kind"], "claude-session");
assert_eq!(result["source"]["id"], SESSION);
assert_eq!(result["fired"], 0);
assert_eq!(
result["added"]
.as_array()
.unwrap()
.iter()
.map(|id| id.as_str().unwrap())
.collect::<Vec<_>>(),
vec![
format!("{SESSION}-release-watch"),
format!("{SESSION}-toolu_wake_recheck"),
]
);
let store = root.join("cron/jobs.json");
assert!(store.exists(), "{}", store.display());
let jobs: Vec<serde_json::Value> =
serde_json::from_str(&std::fs::read_to_string(&store).unwrap()).unwrap();
assert_eq!(jobs.len(), 2);
assert_eq!(jobs[0]["schedule"]["kind"], "cron");
assert_eq!(jobs[0]["schedule"]["expr"], "*/10 * * * *");
assert_eq!(jobs[0]["schedule"]["tz"], "UTC");
assert_eq!(
jobs[0]["prompt"],
"Check the release branch for new failures."
);
assert_eq!(jobs[0]["workdir"], "/workspace/project");
assert_eq!(jobs[0]["enabled"], true);
assert!(jobs[0]["next_run_at"].is_string(), "{}", jobs[0]);
assert_eq!(jobs[1]["schedule"]["kind"], "once");
assert!(jobs[1]["schedule"]["run_at"].is_string(), "{}", jobs[1]);
assert_eq!(
jobs[1]["prompt"],
"Re-read the release branch status and report."
);
std::fs::remove_dir_all(root).ok();
}
#[test]
fn the_imported_jobs_are_listed_under_the_orchestrator_and_still_under_claude_code() {
let root = temp_root("listing");
assert!(run(
&root,
&[
"orchestrator",
"import",
"--from",
"claude-session",
SESSION,
"--json",
],
)
.status
.success());
let listed = json_of(&run(
&root,
&["jobs", "list", "--harness", "orchestrator", "--json"],
));
let ids: Vec<&str> = listed["jobs"]
.as_array()
.unwrap()
.iter()
.map(|job| job["id"].as_str().unwrap())
.collect();
assert_eq!(
ids,
vec![
format!("{SESSION}-release-watch"),
format!("{SESSION}-toolu_wake_recheck")
]
);
assert_eq!(listed["jobs"][0]["harness"], "orchestrator");
assert_eq!(listed["jobs"][0]["schedule"]["display"], "*/10 * * * *");
assert_eq!(
listed["jobs"][0]["payload"]["text"],
"Check the release branch for new failures."
);
let claude = json_of(&run(
&root,
&["jobs", "list", "--harness", "claude-code", "--json"],
));
let claude_ids: Vec<&str> = claude["jobs"]
.as_array()
.unwrap()
.iter()
.map(|job| job["id"].as_str().unwrap())
.collect();
assert_eq!(claude_ids, vec!["release-watch", "toolu_wake_recheck"]);
std::fs::remove_dir_all(root).ok();
}
#[test]
fn a_second_import_replaces_only_its_own_rows_and_leaves_the_rest_alone() {
let root = temp_root("merge");
std::fs::create_dir_all(root.join("cron")).unwrap();
let foreign = "[\n {\n \"id\": \"digest-15m\",\n \"schedule\": {\n \"kind\": \"interval\",\n \"minutes\": 15\n },\n \"prompt\": \"digest\",\n \"enabled\": true\n }\n]\n";
std::fs::write(root.join("cron/jobs.json"), foreign).unwrap();
let args = [
"orchestrator",
"import",
"--from",
"claude-session",
SESSION,
"--json",
];
let first = json_of(&run(&root, &args));
assert_eq!(first["added"].as_array().unwrap().len(), 2);
assert_eq!(first["untouched"], 1);
let second = json_of(&run(&root, &args));
assert!(second["added"].as_array().unwrap().is_empty());
assert_eq!(second["replaced"].as_array().unwrap().len(), 2);
assert_eq!(second["untouched"], 1);
let jobs: Vec<serde_json::Value> =
serde_json::from_str(&std::fs::read_to_string(root.join("cron/jobs.json")).unwrap())
.unwrap();
assert_eq!(jobs.len(), 3, "a re-import must not duplicate its own jobs");
assert_eq!(jobs[0]["id"], "digest-15m");
assert_eq!(jobs[0]["prompt"], "digest");
assert_eq!(jobs[0]["schedule"]["minutes"], 15);
std::fs::remove_dir_all(root).ok();
}
#[test]
fn an_unknown_source_and_an_unknown_session_are_refused_by_name() {
let root = temp_root("refusals");
let bad_kind = run(
&root,
&["orchestrator", "import", "--from", "codex-session", "abc"],
);
assert!(!bad_kind.status.success());
let stderr = String::from_utf8_lossy(&bad_kind.stderr);
assert!(stderr.contains("codex-session"), "{stderr}");
assert!(stderr.contains("claude-session"), "{stderr}");
let missing = run(
&root,
&[
"orchestrator",
"import",
"--from",
"claude-session",
"00000000-0000-0000-0000-000000000000",
],
);
assert!(!missing.status.success());
let stderr = String::from_utf8_lossy(&missing.stderr);
assert!(
stderr.contains("00000000-0000-0000-0000-000000000000"),
"{stderr}"
);
assert!(
!root.join("cron/jobs.json").exists(),
"a refusal writes nothing"
);
std::fs::remove_dir_all(root).ok();
}