Files
agent-manager/tests/stats_test.rs
T

111 lines
3.8 KiB
Rust

//! stats + log: aggregation and filtering over the event journal.
mod common;
use agent_manager::app::App;
use agent_manager::commands::log_cmd;
use agent_manager::commands::stats_cmd;
use agent_manager::events;
fn app_with_events(tag: &str, lines: &[&str]) -> App {
let app = common::test_app(tag, &["stats"]);
let month = chrono::Utc::now().format("%Y%m").to_string();
let path = app.events_dir().join(format!("events-{month}.jsonl"));
let mut text = String::new();
for l in lines {
text.push_str(l);
text.push('\n');
}
std::fs::create_dir_all(app.events_dir()).unwrap();
std::fs::write(&path, text).unwrap();
app
}
#[test]
fn stats_aggregate_counts_everything() {
let app = app_with_events(
"agg",
&[
r#"{"ts":"2026-08-01T10:00:00Z","kind":"run","agent":"a","exit_code":0,"duration_s":10}"#,
r#"{"ts":"2026-08-02T10:00:00Z","kind":"run","agent":"a","exit_code":0,"duration_s":30}"#,
r#"{"ts":"2026-08-03T10:00:00Z","kind":"run","agent":"b","exit_code":1,"duration_s":5}"#,
r#"{"ts":"2026-08-03T11:00:00Z","kind":"install","agent":"a"}"#,
r#"{"ts":"2026-08-03T12:00:00Z","kind":"update","agent":"a"}"#,
],
);
let rows = stats_cmd::aggregate(&app, None, None).unwrap();
let a = rows.iter().find(|r| r.agent == "a").unwrap();
assert_eq!(a.launches, 2);
assert_eq!(a.total_duration_s, 40);
assert_eq!(a.avg_duration_s, 20);
assert_eq!(a.failures, 0);
assert_eq!(a.installs, 1);
assert_eq!(a.updates, 1);
let b = rows.iter().find(|r| r.agent == "b").unwrap();
assert_eq!(b.failures, 1);
assert_eq!(b.launches, 1);
}
#[test]
fn stats_period_cuts_old_events() {
let app = app_with_events(
"period",
&[r#"{"ts":"2020-01-01T10:00:00Z","kind":"run","agent":"old","exit_code":0}"#],
);
assert!(stats_cmd::aggregate(&app, None, Some("30d")).unwrap().is_empty());
assert_eq!(stats_cmd::aggregate(&app, None, None).unwrap().len(), 1);
assert!(stats_cmd::aggregate(&app, None, Some("7d")).unwrap().is_empty());
}
#[test]
fn log_filters_by_agent_kind_and_limit() {
let app = app_with_events(
"logf",
&[
r#"{"ts":"2026-08-01T10:00:00Z","kind":"run","agent":"a","exit_code":0}"#,
r#"{"ts":"2026-08-01T10:00:01Z","kind":"start","agent":"a","pid":42}"#,
r#"{"ts":"2026-08-01T10:00:02Z","kind":"run","agent":"b","exit_code":1}"#,
],
);
let all = log_cmd::filter_events(&app, None, None, None, 50).unwrap();
assert_eq!(all.len(), 3);
assert_eq!(all[0].agent.as_deref(), Some("b"), "most recent first");
let only_a = log_cmd::filter_events(&app, Some("a"), None, None, 50).unwrap();
assert_eq!(only_a.len(), 2);
let starts = log_cmd::filter_events(&app, None, Some("start"), None, 50).unwrap();
assert_eq!(starts.len(), 1);
assert_eq!(starts[0].pid, Some(42));
let limited = log_cmd::filter_events(&app, None, None, None, 1).unwrap();
assert_eq!(limited.len(), 1);
let since = log_cmd::filter_events(&app, None, None, Some("2026-09-01"), 50).unwrap();
assert!(since.is_empty());
}
#[test]
fn stats_command_runs() {
let app = app_with_events(
"cmd",
&[r#"{"ts":"2026-08-01T10:00:00Z","kind":"run","agent":"a","exit_code":0}"#],
);
let code = stats_cmd::run(&app, None, None).unwrap();
assert_eq!(code, 0);
}
#[test]
fn journal_reads_back_through_events_api() {
let app = app_with_events("api", &[]);
let mut log = events::EventLog::new(app.events_dir());
log.append(
&events::Event::now(events::EventKind::Run)
.with_agent("x")
.with_exit_code(0),
)
.unwrap();
let all = events::read_events(&app.events_dir(), 0);
assert_eq!(all.len(), 1);
}