use std::time::{Duration, Instant};
use crate::harness::{
agent, counts, human, plan_of, renamed, reporting, Counts, World, LOOP_STATS_ENV,
};
use serde_json::{json, Value};
const WINDOW: Duration = Duration::from_secs(60);
fn measured(name: &str) -> World {
World::new(name).with_env(LOOP_STATS_ENV, "1")
}
fn state_changes(world: &World, run: &str) -> usize {
world
.journal(run)
.into_iter()
.filter(|event| event["source"] == "pipeline")
.filter(|event| {
matches!(
event["kind"].as_str().unwrap_or_default(),
"node-settled" | "node-dispatched" | "edit-committed" | "release-adopted"
)
})
.count()
}
fn recorded(world: &World, run: &str, kind: &str, node: &str) -> bool {
world
.events_of(run, kind)
.iter()
.any(|event| event["labels"]["node"] == node)
}
fn at(event: &Value) -> u64 {
let ts = event["ts"]
.as_str()
.unwrap_or_else(|| panic!("no ts: {event}"));
let (date, time) = ts
.trim_end_matches('Z')
.split_once('T')
.unwrap_or_else(|| panic!("not an RFC 3339 timestamp: {ts}"));
let number = |text: &str| -> u64 {
text.parse()
.unwrap_or_else(|e| panic!("{text} of {ts} is not a number: {e}"))
};
let day: Vec<&str> = date.split('-').collect();
let clock: Vec<&str> = time.split(':').collect();
let (second, millis) = clock[2].split_once('.').unwrap_or((clock[2], "0"));
let days = number(day[0]) * 372 + number(day[1]) * 31 + number(day[2]);
((days * 24 + number(clock[0])) * 60 + number(clock[1])) * 60_000
+ number(second) * 1_000
+ number(millis)
}
fn one(world: &World, run: &str, kind: &str, node: &str) -> Value {
let found: Vec<Value> = world
.events_of(run, kind)
.into_iter()
.filter(|event| event["labels"]["node"] == node)
.collect();
assert_eq!(
found.len(),
1,
"{run} recorded {kind} for {node}: {found:?}"
);
found.into_iter().next().expect("one record")
}
#[test]
fn a_converged_run_does_no_scheduling_work_while_it_records_nothing() {
let world = measured("loopcost-idle");
world.script("hold.wait", "hold");
let plan = world.plan("idle", &plan_of("idle", vec![agent("hold", &[])]));
world.run(&["start", &plan, "--detach"]).exited(0);
world.until("the dispatch to start", |world| {
recorded(world, "idle", "node-dispatched", "hold")
});
reporting(&world, "idle");
std::thread::sleep(Duration::from_secs(2));
let wrote = world.journal("idle").len();
let before = counts(&world, "idle");
std::thread::sleep(WINDOW);
let did = counts(&world, "idle").since(before);
assert_eq!(
world.journal("idle").len(),
wrote,
"the run recorded something inside the window this claim is about"
);
assert_eq!(
did.statuses, 0,
"the graph's statuses were re-derived: {did:?}"
);
assert_eq!(did.publications, 0, "the board was re-published: {did:?}");
assert_eq!(did.store_bytes, 0, "the run store was read: {did:?}");
assert_eq!(
did.upstream_reads, 0,
"a run with no cross-DAG dependency read another run's ledger: {did:?}"
);
assert_eq!(
did.release_asks, 0,
"a run with nothing awaiting a release asked about one: {did:?}"
);
assert!(
did.passes <= WINDOW.as_secs(),
"a converged driver ran more than one scheduling pass a second: {did:?}"
);
world.release("hold.go");
world.until("the run to settle", |world| {
world.run_file("idle", "result.json").is_file()
});
}
#[test]
fn an_idle_pass_does_not_grow_with_the_run_it_is_idling_on() {
let world = measured("loopcost-scale");
world.script("hold.wait", "hold");
let small = world.plan("small", &plan_of("small", vec![agent("hold", &[])]));
let mut many: Vec<Value> = (0..99).map(|n| agent(&format!("n{n}"), &[])).collect();
many.push(agent("hold", &[]));
let large = world.plan("large", &plan_of("large", many));
world.run(&["start", &small, "--detach"]).exited(0);
world.run(&["start", &large, "--detach"]).exited(0);
for run in ["small", "large"] {
world.until("both dispatches to start", |world| {
recorded(world, run, "node-dispatched", "hold")
});
reporting(&world, run);
}
world.until("the large run's other nodes to settle", |world| {
world
.events_of("large", "node-settled")
.iter()
.filter(|event| event["labels"]["node"] != "hold")
.count()
== 99
});
std::thread::sleep(Duration::from_secs(2));
let sizes: Vec<usize> = ["small", "large"]
.iter()
.map(|run| world.journal(run).len())
.collect();
assert!(
sizes[1] > sizes[0] * 10,
"the two runs are not orders of magnitude apart: {sizes:?}"
);
let before: Vec<Counts> = ["small", "large"]
.iter()
.map(|run| counts(&world, run))
.collect();
std::thread::sleep(WINDOW);
let did: Vec<Counts> = ["small", "large"]
.iter()
.enumerate()
.map(|(nth, run)| counts(&world, run).since(before[nth]))
.collect();
assert!(
did[1].store_bytes <= 8 * (did[0].store_bytes + 1),
"what an idle pass reads grew with the run: {did:?}"
);
for (nth, run) in ["small", "large"].iter().enumerate() {
assert_eq!(
did[nth].store_bytes, 0,
"{run} read its store idle: {did:?}"
);
assert_eq!(
did[nth].statuses, 0,
"{run} re-derived its statuses: {did:?}"
);
}
world.release("hold.go");
for run in ["small", "large"] {
world.until("the run to settle", |world| {
world.run_file(run, "result.json").is_file()
});
}
}
#[test]
fn the_board_and_the_frontier_are_recomputed_once_per_recorded_state_change() {
let world = measured("loopcost-changes");
for node in ["hold", "a", "b", "c"] {
world.script(&format!("{node}.wait"), "hold");
}
let plan = world.plan(
"changes",
&plan_of(
"changes",
vec![
agent("hold", &[]),
agent("a", &[]),
agent("b", &["a"]),
agent("c", &["b"]),
],
),
);
world.run(&["start", &plan, "--detach"]).exited(0);
world.until("the chain to start", |world| {
recorded(world, "changes", "node-dispatched", "a")
});
reporting(&world, "changes");
std::thread::sleep(Duration::from_secs(1));
let before = counts(&world, "changes");
let changed_before = state_changes(&world, "changes");
for node in ["a", "b", "c"] {
world.release(&format!("{node}.go"));
world.until("the chain to advance", |world| {
recorded(world, "changes", "node-settled", node)
});
}
std::thread::sleep(Duration::from_secs(1));
let did = counts(&world, "changes").since(before);
let changes = (state_changes(&world, "changes") - changed_before) as u64;
assert!(
changes >= 5,
"the window recorded too little to judge: {changes}"
);
assert!(
did.publications <= changes,
"the board was published more often than the run changed: {did:?} over {changes} changes"
);
assert!(
did.statuses <= changes,
"the frontier was derived more often than the run changed: {did:?} over {changes} changes"
);
world.release("hold.go");
world.until("the run to settle", |world| {
world.run_file("changes", "result.json").is_file()
});
}
#[test]
fn another_runs_ledger_is_read_on_its_own_interval_and_not_on_the_loops() {
let world = measured("loopcost-paced");
let upstream = world.plan(
"moving",
&plan_of("moving", vec![agent("build", &[]), human("approve", &[])]),
);
world.run(&["start", &upstream, "--attach"]).settled();
for (run, every) in [("chatty", "50"), ("quiet", "500")] {
world.script(&format!("{run}-hold.wait"), "hold");
world.script(&format!("{run}-hold.heartbeat"), every);
let mut consumer = agent("ship", &[]);
consumer["deps"] = json!(["run:moving#build"]);
let plan = world.plan(
run,
&plan_of(run, vec![agent(&format!("{run}-hold"), &[]), consumer]),
);
world.run(&["start", &plan, "--detach"]).exited(0);
reporting(&world, run);
}
std::thread::sleep(Duration::from_secs(1));
let before: Vec<Counts> = ["chatty", "quiet"]
.iter()
.map(|run| counts(&world, run))
.collect();
std::thread::sleep(WINDOW);
let did: Vec<Counts> = ["chatty", "quiet"]
.iter()
.enumerate()
.map(|(nth, run)| counts(&world, run).since(before[nth]))
.collect();
assert!(
did[0].passes > did[1].passes * 4,
"the two loops did not run at different rates: {did:?}"
);
let ceiling = 4 * WINDOW.as_secs() + 4;
for (nth, run) in ["chatty", "quiet"].iter().enumerate() {
assert!(
did[nth].upstream_reads <= ceiling,
"{run} read the upstream more often than the interval allows: {did:?}"
);
}
assert!(
did[0].upstream_reads <= 2 * did[1].upstream_reads + 4,
"reading the upstream tracked the loop's pass rate: {did:?}"
);
for run in ["chatty", "quiet"] {
world.release(&format!("{run}-hold.go"));
}
}
#[test]
fn every_answer_the_loop_owes_arrives_inside_a_second() {
let world = World::new("loopcost-latency");
world.script("build.wait", "hold");
world.script("hold.wait", "hold");
let plan = world.plan(
"prompt",
&plan_of(
"prompt",
vec![
agent("hold", &[]),
agent("build", &[]),
agent("ship", &["build"]),
human("approve", &[]),
agent("after", &["approve"]),
],
),
);
world.run(&["start", &plan, "--detach"]).exited(0);
world.until("the first dispatch to start", |world| {
recorded(world, "prompt", "node-dispatched", "build")
});
let released = Instant::now();
world.release("build.go");
world.until("the settlement to be readable", |world| {
recorded(world, "prompt", "node-settled", "build")
});
let readable = released.elapsed();
assert!(
readable < Duration::from_secs(1),
"a settlement took {readable:?} to become readable"
);
world.until("the dependent to start", |world| {
recorded(world, "prompt", "node-dispatched", "ship")
});
let waited = at(&one(&world, "prompt", "node-dispatched", "ship"))
- at(&one(&world, "prompt", "node-settled", "build"));
assert!(
waited < 1_000,
"a node waited {waited}ms after its last dependency settled"
);
let asked = Instant::now();
world.run(&["attest", "prompt", "approve"]).exited(0);
let answered = asked.elapsed();
assert!(
answered < Duration::from_secs(1),
"an edit took {answered:?} to be answered"
);
world.until("the held subtree to start", |world| {
recorded(world, "prompt", "node-dispatched", "after")
});
let resumed = at(&one(&world, "prompt", "node-dispatched", "after"))
- at(&one(&world, "prompt", "human-attested", "approve"));
assert!(
resumed < 1_000,
"a subtree waited {resumed}ms after its decision cleared"
);
world.release("hold.go");
world.until("the run to settle", |world| {
world.run_file("prompt", "result.json").is_file()
});
}
#[test]
fn a_consumer_proceeds_within_a_second_of_its_upstream_settling() {
let world = World::new("loopcost-upstream");
world.script("late.wait", "hold");
let mut consumer = agent("ship", &[]);
consumer["deps"] = json!(["run:moving#build"]);
let plan = world.plan(
"watcher",
&plan_of("watcher", vec![agent("late", &[]), consumer]),
);
world.run(&["start", &plan, "--detach"]).exited(0);
world.until("the consumer to be held", |world| {
!world
.events_of("watcher", "node-held")
.iter()
.filter(|event| event["labels"]["node"] == "ship")
.count()
.eq(&0)
});
let holds = world.events_of("watcher", "node-held");
let ship = holds
.iter()
.find(|event| event["labels"]["node"] == "ship")
.expect("the consumer is held");
assert!(
ship["payload"]["reasons"]
.as_array()
.expect("a hold carries reasons")
.iter()
.any(|reason| reason["kind"] == "dependencies"
&& reason["blocking"] == json!(["run:moving#build"])),
"the hold on a cross-run dependency does not name the run it waits on: {ship}"
);
let upstream = world.plan("moving", &plan_of("moving", vec![agent("build", &[])]));
world.run(&["start", &upstream, "--attach"]).exited(0);
world.until("the consumer to proceed", |world| {
recorded(world, "watcher", "node-dispatched", "ship")
});
let waited = at(&one(&world, "watcher", "node-dispatched", "ship"))
- at(&one(&world, "moving", "node-settled", "build"));
assert!(
waited < 1_000,
"a consumer waited {waited}ms after its upstream settled in another run"
);
world.release("late.go");
world.until("the run to settle", |world| {
world.run_file("watcher", "result.json").is_file()
});
}
#[test]
fn a_projection_that_fails_while_the_run_records_nothing_still_reaches_the_planner() {
let world = World::new("loopcost-unprojected");
world.script("hold.wait", "hold");
world.script("first.wait", "hold");
let project = world.plan(
"unprojected",
&plan_of("unprojected", vec![agent("hold", &[]), agent("first", &[])]),
);
world.run(&["start", &project, "--detach"]).exited(0);
world.until("the run to reach the store", |world| {
world.store_tasks(&project).iter().any(|task| {
task["item"]["metadata"]["onepipeline.id"] == "first"
&& task["item"]["status"]["category"] == "in-progress"
})
});
let unavailable = world.root.join("plan-store-unavailable");
renamed(
&world.store(),
&unavailable,
"the store becomes unreachable",
);
world.release("first.go");
world.until("the node to settle", |world| {
recorded(world, "unprojected", "node-settled", "first")
});
world.until("the failed projection to reach the planner", |world| {
world
.events_of("unprojected", "planner-surface-queued")
.iter()
.any(|event| {
event["payload"]["message"]
.as_str()
.is_some_and(|said| said.contains("did not take this run's projection"))
})
});
renamed(&unavailable, &world.store(), "the store returns");
world.release("hold.go");
world.until("the run to settle", |world| {
world.run_file("unprojected", "result.json").is_file()
});
}
#[test]
fn a_driver_that_cannot_write_the_counts_it_was_asked_for_says_so() {
let world = measured("loopcost-unwritable");
world.script("hold.wait", "hold");
let plan = world.plan(
"unwritable",
&plan_of("unwritable", vec![agent("hold", &[])]),
);
world.run(&["start", &plan, "--detach"]).exited(0);
reporting(&world, "unwritable");
let obstruction = world.run_file("unwritable", "loop-stats.json");
std::fs::remove_file(&obstruction).expect("the counts are replaced");
std::fs::create_dir_all(&obstruction).expect("the obstruction is placed");
std::fs::write(obstruction.join("held"), "not the counts").expect("the obstruction holds");
world.until("the driver to report what it could not write", |world| {
std::fs::read_to_string(world.run_file("unwritable", "driver.log"))
.unwrap_or_default()
.contains("loop-stats.json")
});
assert!(
!recorded(&world, "unwritable", "node-settled", "hold"),
"the driver went on running after refusing"
);
assert!(
obstruction.is_dir() && obstruction.join("held").is_file(),
"the run wrote over the obstruction it refused on"
);
world.release("hold.go");
}