Skip to content

Commit 2f33f20

Browse files
committed
test(storage_json): kill mutants — exact aggregates, time_to inclusive, by_model asserts
- test_get_event_stats_exact_aggregates: exact avg_duration, p50/p95/p99, avg_score, by_model count/avg - test_list_events_time_to_inclusive: event at created_at == time_to is included (<=) - Mutants killed: 25 -> 15 on storage_json (percentile/avg/division mutations) Made-with: Cursor
1 parent 066ae70 commit 2f33f20

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

src/server/storage_json.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,77 @@ mod tests {
13031303
assert_eq!(stats.total_cost_estimate, 4.0, "1.5 + 0.5 + 2.0");
13041304
}
13051305

1306+
/// Exact aggregate values so mutations in get_event_stats (avg, percentile formula) are caught.
1307+
#[tokio::test]
1308+
async fn test_get_event_stats_exact_aggregates() {
1309+
let dir = tempfile::tempdir().unwrap();
1310+
let backend = JsonStorageBackend::new(&dir.path().join("reviews.json"));
1311+
1312+
let now = now_ts();
1313+
for (i, &dur) in [100_u64, 200, 300].iter().enumerate() {
1314+
let mut s = make_session_with_event(
1315+
&format!("r{}", i),
1316+
now + i as i64,
1317+
ReviewStatus::Complete,
1318+
"review.completed",
1319+
"gpt-4o",
1320+
"head",
1321+
dur,
1322+
);
1323+
if let Some(ref mut e) = s.event {
1324+
e.overall_score = Some((i as f32 + 1.0) * 2.0); // 2.0, 4.0, 6.0 -> avg 4.0
1325+
}
1326+
backend.save_review(&s).await.unwrap();
1327+
}
1328+
1329+
let stats = backend
1330+
.get_event_stats(&EventFilters::default())
1331+
.await
1332+
.unwrap();
1333+
1334+
assert_eq!(stats.total_reviews, 3);
1335+
assert_eq!(stats.avg_duration_ms, 200.0, " (100+200+300)/3 ");
1336+
assert_eq!(
1337+
stats.p50_latency_ms, 200,
1338+
" percentile 50 of [100,200,300] "
1339+
);
1340+
assert_eq!(stats.p95_latency_ms, 300, " percentile 95 ");
1341+
assert_eq!(stats.p99_latency_ms, 300, " percentile 99 ");
1342+
assert_eq!(stats.avg_score, Some(4.0), " (2+4+6)/3 ");
1343+
assert_eq!(stats.by_model.len(), 1);
1344+
assert_eq!(stats.by_model[0].model, "gpt-4o");
1345+
assert_eq!(stats.by_model[0].count, 3);
1346+
assert_eq!(stats.by_model[0].avg_duration_ms, 200.0);
1347+
}
1348+
1349+
/// time_to filter: event with created_at == time_to must be included (<=).
1350+
#[tokio::test]
1351+
async fn test_list_events_time_to_inclusive() {
1352+
let dir = tempfile::tempdir().unwrap();
1353+
let backend = JsonStorageBackend::new(&dir.path().join("reviews.json"));
1354+
1355+
let t = chrono::Utc::now();
1356+
let mut s = make_session_with_event(
1357+
"r1",
1358+
0,
1359+
ReviewStatus::Complete,
1360+
"review.completed",
1361+
"gpt-4o",
1362+
"head",
1363+
100,
1364+
);
1365+
s.event.as_mut().unwrap().created_at = Some(t);
1366+
backend.save_review(&s).await.unwrap();
1367+
1368+
let filters = EventFilters {
1369+
time_from: Some(t - chrono::Duration::hours(1)),
1370+
time_to: Some(t),
1371+
..EventFilters::default()
1372+
};
1373+
let events = backend.list_events(&filters).await.unwrap();
1374+
assert_eq!(events.len(), 1, "event at exactly time_to must be included");
1375+
}
1376+
13061377
// ---------------------------------------------------------------
13071378
// 7. is_empty (via internal state check)
13081379
// ---------------------------------------------------------------

0 commit comments

Comments
 (0)