use std::path::PathBuf;
use std::process::{Command, Output};
fn bin() -> PathBuf {
PathBuf::from(env!("CARGO_BIN_EXE_supercode"))
}
fn fixtures() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../harness/tests/fixtures")
}
fn run(args: &[&str]) -> Output {
let fixtures = fixtures();
Command::new(bin())
.env("CLAUDE_CONFIG_DIR", fixtures.join("claude_jobs_home"))
.env("HERMES_HOME", fixtures.join("hermes_home"))
.env("OPENCLAW_STATE_DIR", fixtures.join("openclaw_home"))
.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 the RPC result verbatim")
}
#[test]
fn jobs_list_json_returns_the_rpc_rows_for_all_three_stores() {
let result = json_of(&run(&["jobs", "list", "--json"]));
let ids: Vec<&str> = result["jobs"]
.as_array()
.unwrap()
.iter()
.map(|job| job["id"].as_str().unwrap())
.collect();
assert_eq!(
ids,
vec![
"release-watch",
"toolu_wake_recheck",
"digest-15m",
"nightly-audit",
"coder-standup",
"ops-once-boot",
"85ad7832-896f-42be-af31-3e1ed2fbdc4b",
"8bb7d938-ca46-4a6d-90eb-c92331155566",
"cron_standup",
"cron_reindex",
],
"{result}"
);
let standup = result["jobs"]
.as_array()
.unwrap()
.iter()
.find(|job| job["id"] == "cron_standup")
.unwrap();
assert_eq!(standup["harness"], "openclaw");
assert_eq!(standup["scope"], "install");
assert_eq!(standup["session_target"], "isolated");
assert_eq!(standup["deliver"]["mode"], "announce");
assert_eq!(standup["deliver"]["target"], "slack");
assert_eq!(standup["deliver"]["chat_id"], "C0429ABCD");
assert_eq!(standup["schedule"]["display"], "30 8 * * 1-5");
assert!(result["sources"].as_array().unwrap().len() >= 4, "{result}");
}
#[test]
fn jobs_list_table_carries_the_eight_declared_columns() {
let output = run(&["jobs", "list", "--harness", "hermes"]);
assert!(output.status.success());
let text = String::from_utf8_lossy(&output.stdout);
let header = text.lines().next().unwrap();
for column in [
"HARNESS",
"ID",
"SCOPE",
"SCHEDULE",
"PAYLOAD",
"NEXT_RUN",
"DELIVERY",
"LAST_STATUS",
] {
assert!(header.contains(column), "header `{header}` lacks {column}");
}
assert!(text.contains("digest-15m"), "{text}");
assert!(text.contains("every 15 min"), "{text}");
assert!(text.contains("origin \u{2192} -100777:55"), "{text}");
assert!(
!text.contains("cron_standup"),
"--harness must filter: {text}"
);
}
#[test]
fn jobs_get_json_carries_the_row_and_the_native_record() {
let result = json_of(&run(&[
"jobs",
"get",
"--harness",
"openclaw",
"cron_standup",
"--json",
]));
assert_eq!(result["job"]["id"], "cron_standup");
assert_eq!(result["job"]["payload"]["kind"], "prompt");
assert_eq!(result["source"]["name"], "standup");
assert_eq!(result["source"]["delivery"]["channel"], "slack");
}
#[test]
fn a_harness_without_scheduled_jobs_fails_instead_of_listing_nothing() {
let output = run(&["jobs", "list", "--harness", "codex", "--json"]);
assert!(
!output.status.success(),
"codex has no scheduled-job concept; an empty list would be a silent no-op"
);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(stderr.contains("has no scheduled jobs"), "{stderr}");
}