use super::tests_common::{rpt, rpt_with_latencies};
use super::*;
#[test]
fn assert_benchmarks_empty_reports() {
let r = assert_benchmarks(&[], Some(1000), Some(0.5), Some(100.0));
assert!(
!r.is_fail(),
"empty-reports skip must not surface as failure"
);
assert!(r.is_skip(), "no reports must surface as skipped");
assert!(!r.is_pass(), "skip is not pass");
let skip_details: Vec<&AssertDetail> = r.skip_details().collect();
assert!(
skip_details
.iter()
.any(|d| matches!(d.kind, DetailKind::Skip) && d.message.contains("no worker reports")),
"skip detail must carry the 'no worker reports' reason: {:?}",
skip_details,
);
}
#[test]
fn assert_benchmarks_no_thresholds() {
let reports = [rpt_with_latencies(
1,
vec![1000, 2000, 3000],
10,
5_000_000_000,
)];
let r = assert_benchmarks(&reports, None, None, None);
assert!(r.is_pass());
}
#[test]
fn assert_benchmarks_p99_pass() {
let reports = [rpt_with_latencies(
1,
vec![100, 200, 300, 400, 500],
10,
5_000_000_000,
)];
let r = assert_benchmarks(&reports, Some(1000), None, None);
assert!(r.is_pass(), "p99 500ns < 1000ns limit: {:?}", r.outcomes);
}
#[test]
fn assert_benchmarks_p99_n100_at_limit_passes() {
let latencies: Vec<u64> = (0..100).collect();
let reports = [rpt_with_latencies(1, latencies, 100, 5_000_000_000)];
let r = assert_benchmarks(&reports, Some(99), None, None);
assert!(
r.is_pass(),
"p99 should be 98, under limit 99: {:?}",
r.outcomes
);
}
#[test]
fn assert_benchmarks_p99_n100_below_old_p100_passes() {
let latencies: Vec<u64> = (0..100).collect();
let reports = [rpt_with_latencies(1, latencies, 100, 5_000_000_000)];
let r = assert_benchmarks(&reports, Some(98), None, None);
assert!(
r.is_pass(),
"corrected p99 (98) must equal limit 98 and pass: {:?}",
r.outcomes
);
}
#[test]
fn assert_not_starved_p99_n100_is_99_microseconds() {
let latencies: Vec<u64> = (1..=100).map(|v: u64| v * 1000).collect();
let reports = [rpt_with_latencies(1, latencies, 100, 5_000_000_000)];
let r = assert_not_starved(&reports);
assert_eq!(
r.stats.worst_p99_wake_latency_us, 99.0,
"p99 must equal 99.0us (sorted[98] = 99_000ns), got {}us",
r.stats.worst_p99_wake_latency_us
);
}
#[test]
fn assert_benchmarks_p99_fail() {
let reports = [rpt_with_latencies(
1,
vec![100, 200, 300, 400, 2000],
10,
5_000_000_000,
)];
let r = assert_benchmarks(&reports, Some(1000), None, None);
assert!(r.is_fail());
assert!(
r.failure_details()
.any(|d| matches!(d.kind, DetailKind::Benchmark)
&& d.message.contains("p99 wake latency"))
);
}
#[test]
fn assert_p99_ns_threshold_compares_against_ns_latencies() {
let reports = [rpt_with_latencies(1, vec![5000], 10, 5_000_000_000)];
let fail = assert_benchmarks(&reports, Some(4999), None, None);
assert!(
fail.is_fail(),
"threshold 4999 ns against 5000 ns p99 must fail — if this \
passes, the comparison may be converting to µs and eating \
3 digits of resolution",
);
let pass = assert_benchmarks(&reports, Some(5001), None, None);
assert!(
pass.is_pass(),
"threshold 5001 ns against 5000 ns p99 must pass — if this \
fails, the comparison may be multiplying the threshold by \
1000 (treating it as µs)",
);
let stats = assert_not_starved(&reports);
assert_eq!(
stats.stats.worst_p99_wake_latency_us, 5.0,
"5000 ns / 1000 = 5.0 µs — if this renders as 5000 (forgot /1000) \
or 0.005 (extra /1000), the reporting-path unit conversion drifted",
);
}
#[test]
fn assert_benchmarks_cv_pass() {
let reports = [rpt_with_latencies(
1,
vec![1000, 1000, 1000, 1000],
10,
5_000_000_000,
)];
let r = assert_benchmarks(&reports, None, Some(0.5), None);
assert!(r.is_pass(), "uniform latencies CV=0: {:?}", r.outcomes);
}
#[test]
fn assert_benchmarks_cv_fail() {
let reports = [rpt_with_latencies(
1,
vec![100, 100, 100, 100000],
10,
5_000_000_000,
)];
let r = assert_benchmarks(&reports, None, Some(0.5), None);
assert!(r.is_fail());
assert!(
r.failure_details()
.any(|d| matches!(d.kind, DetailKind::Benchmark)
&& d.message.contains("wake latency CV"))
);
}
#[test]
fn assert_benchmarks_iteration_rate_pass() {
let reports = [rpt_with_latencies(1, vec![], 1000, 5_000_000_000)];
let r = assert_benchmarks(&reports, None, None, Some(100.0));
assert!(r.is_pass(), "200/s > 100/s floor: {:?}", r.outcomes);
}
#[test]
fn assert_benchmarks_iteration_rate_fail() {
let reports = [rpt_with_latencies(1, vec![], 10, 5_000_000_000)];
let r = assert_benchmarks(&reports, None, None, Some(100.0));
assert!(r.is_fail());
assert!(
r.failure_details().any(
|d| matches!(d.kind, DetailKind::Benchmark) && d.message.contains("iteration rate")
)
);
}
#[test]
fn assert_benchmarks_zero_wall_time_yields_inconclusive() {
let reports = [rpt_with_latencies(1, vec![], 10, 0)];
let r = assert_benchmarks(&reports, None, None, Some(100.0));
assert!(
r.is_inconclusive(),
"all-zero wall_time must be Inconclusive, not Pass: {:?}",
r.outcomes,
);
assert!(!r.is_pass(), "must not silently pass on zero denominator");
assert!(!r.is_fail(), "no actual rate violation to report");
let reason = r
.inconclusive_details()
.find(|d| d.kind == DetailKind::Benchmark)
.unwrap_or_else(|| panic!("expected Inconclusive reason, got {:?}", r.outcomes));
assert!(
reason.message.contains("zero wall_time_ns"),
"diagnostic must name the root cause: {reason}"
);
assert!(
reason.message.contains("able to run"),
"diagnostic must surface the operator-actionable hint: {reason}"
);
}
#[test]
fn assert_benchmarks_mixed_zero_and_nonzero_wall_does_not_short_circuit() {
let reports = [
rpt_with_latencies(1, vec![], 10, 0),
rpt_with_latencies(2, vec![], 1, 5_000_000_000), ];
let r = assert_benchmarks(&reports, None, None, Some(100.0));
assert!(
r.is_fail(),
"non-zero-wall worker below floor must fail: {:?}",
r.outcomes,
);
assert!(!r.is_inconclusive(), "only all-zero is Inconclusive");
assert!(
r.failure_details()
.any(|d| d.message.contains("worker 2") && d.message.contains("iteration rate")),
"expected worker-2 rate failure: {:?}",
r.outcomes,
);
}
#[test]
fn assert_benchmarks_no_latencies_skips_p99() {
let reports = [rpt_with_latencies(1, vec![], 10, 5_000_000_000)];
let r = assert_benchmarks(&reports, Some(1000), None, None);
assert!(r.is_pass(), "empty latencies should skip p99 check");
}
#[test]
fn assert_benchmarks_single_latency_cv_skipped() {
let reports = [rpt_with_latencies(1, vec![1000], 10, 5_000_000_000)];
let r = assert_benchmarks(&reports, None, Some(0.1), None);
assert!(r.is_pass(), "single sample should skip CV check");
}
#[test]
fn assert_benchmarks_wake_latency_cv_zero_mean_yields_inconclusive() {
let reports = [rpt_with_latencies(1, vec![0, 0, 0, 0], 10, 5_000_000_000)];
let r = assert_benchmarks(&reports, None, Some(0.5), None);
assert!(
r.is_inconclusive(),
"zero-mean wake-latency CV must be Inconclusive, not Pass: {:?}",
r.outcomes,
);
assert!(!r.is_pass(), "must not silently pass on zero denominator");
assert!(!r.is_fail(), "no actual CV violation to report");
let reason = r
.inconclusive_details()
.find(|d| d.kind == DetailKind::Benchmark)
.unwrap_or_else(|| {
panic!(
"expected Benchmark Inconclusive reason, got {:?}",
r.outcomes
)
});
assert!(
reason.message.contains("wake latency CV inconclusive"),
"diagnostic must label the gate: {reason}",
);
assert!(
reason.message.contains("zero mean wake"),
"diagnostic must name the root cause: {reason}",
);
assert!(
reason.message.contains("non-zero latency"),
"diagnostic must surface the operator-actionable hint: {reason}",
);
}
#[test]
fn not_starved_wake_latency_stats() {
let reports = [
rpt_with_latencies(1, vec![1000, 2000, 3000, 4000, 5000], 100, 5_000_000_000),
rpt_with_latencies(2, vec![6000, 7000, 8000, 9000, 10000], 200, 5_000_000_000),
];
let r = assert_not_starved(&reports);
assert!(r.is_pass(), "{:?}", r.outcomes);
let s = &r.stats;
assert!(
s.worst_p99_wake_latency_us > 9.0,
"p99: {}",
s.worst_p99_wake_latency_us
);
assert!(
(s.worst_median_wake_latency_us - 5.0).abs() < 0.1,
"median: {}",
s.worst_median_wake_latency_us
);
assert!(
s.worst_wake_latency_cv > 0.0,
"cv: {}",
s.worst_wake_latency_cv
);
assert_eq!(s.total_iterations, 300);
}
#[test]
fn not_starved_empty_latencies_zero_stats() {
let reports = [rpt(1, 1000, 5e9 as u64, 5e8 as u64, &[0], 50)];
let r = assert_not_starved(&reports);
assert!(r.is_pass());
assert_eq!(r.stats.worst_p99_wake_latency_us, 0.0);
assert_eq!(r.stats.worst_median_wake_latency_us, 0.0);
assert_eq!(r.stats.worst_wake_latency_cv, 0.0);
}
#[test]
fn not_starved_run_delay_stats() {
let mut w1 = rpt(1, 1000, 5e9 as u64, 5e8 as u64, &[0], 50);
w1.schedstat_run_delay_ns = 100_000; let mut w2 = rpt(2, 1000, 5e9 as u64, 5e8 as u64, &[1], 50);
w2.schedstat_run_delay_ns = 300_000; let r = assert_not_starved(&[w1, w2]);
assert!(r.is_pass(), "{:?}", r.outcomes);
assert!(
(r.stats.worst_mean_run_delay_us - 200.0).abs() < 0.1,
"mean: {}",
r.stats.worst_mean_run_delay_us
);
assert!(
(r.stats.worst_run_delay_us - 300.0).abs() < 0.1,
"worst: {}",
r.stats.worst_run_delay_us
);
}
#[test]
fn plan_benchmarks_p99_via_assert_cgroup() {
let plan = AssertPlan {
not_starved: false,
isolation: false,
max_gap_ms: None,
max_spread_pct: None,
max_throughput_cv: None,
min_work_rate: None,
max_p99_wake_latency_ns: Some(500),
max_wake_latency_cv: None,
min_iteration_rate: None,
max_migration_ratio: None,
min_page_locality: None,
max_cross_node_migration_ratio: None,
max_slow_tier_ratio: None,
};
let reports = [rpt_with_latencies(
1,
vec![100, 200, 300, 400, 1000],
10,
5_000_000_000,
)];
let r = plan.assert_cgroup(&reports, None, None);
assert!(!r.is_pass(), "p99 1000ns > 500ns limit");
assert!(
r.failure_details()
.any(|d| matches!(d.kind, DetailKind::Benchmark)
&& d.message.contains("p99 wake latency"))
);
}
#[test]
fn plan_migration_ratio_gate() {
let mut w = rpt(1, 1000, 5e9 as u64, 5e8 as u64, &[0, 1], 50);
w.migration_count = 10;
w.iterations = 100;
let plan = AssertPlan {
not_starved: false,
isolation: false,
max_gap_ms: None,
max_spread_pct: None,
max_throughput_cv: None,
min_work_rate: None,
max_p99_wake_latency_ns: None,
max_wake_latency_cv: None,
min_iteration_rate: None,
max_migration_ratio: Some(0.05),
min_page_locality: None,
max_cross_node_migration_ratio: None,
max_slow_tier_ratio: None,
};
let r = plan.assert_cgroup(&[w], None, None);
assert!(r.is_fail());
assert!(
r.failure_details()
.any(|d| matches!(d.kind, DetailKind::Migration)
&& d.message.contains("migration ratio"))
);
}
#[test]
fn plan_migration_ratio_gate_pass() {
let mut w = rpt(1, 1000, 5e9 as u64, 5e8 as u64, &[0, 1], 50);
w.migration_count = 2;
w.iterations = 100;
let plan = AssertPlan {
not_starved: false,
isolation: false,
max_gap_ms: None,
max_spread_pct: None,
max_throughput_cv: None,
min_work_rate: None,
max_p99_wake_latency_ns: None,
max_wake_latency_cv: None,
min_iteration_rate: None,
max_migration_ratio: Some(0.05),
min_page_locality: None,
max_cross_node_migration_ratio: None,
max_slow_tier_ratio: None,
};
let r = plan.assert_cgroup(&[w], None, None);
assert!(r.is_pass(), "{:?}", r.outcomes);
}
#[test]
fn plan_migration_ratio_zero_iterations_is_inconclusive_not_pass() {
let mut w = rpt(1, 1000, 5e9 as u64, 5e8 as u64, &[0, 1], 50);
w.migration_count = 5;
w.iterations = 0; let plan = AssertPlan {
not_starved: false,
isolation: false,
max_gap_ms: None,
max_spread_pct: None,
max_throughput_cv: None,
min_work_rate: None,
max_p99_wake_latency_ns: None,
max_wake_latency_cv: None,
min_iteration_rate: None,
max_migration_ratio: Some(0.05),
min_page_locality: None,
max_cross_node_migration_ratio: None,
max_slow_tier_ratio: None,
};
let r = plan.assert_cgroup(&[w], None, None);
assert!(
!r.is_pass(),
"zero-iteration workload must NOT trivially pass migration-ratio gate; got: {:?}",
r.outcomes
);
assert!(
!r.is_fail(),
"zero-iteration workload is Inconclusive, not Fail; got: {:?}",
r.outcomes
);
assert!(
r.is_inconclusive(),
"expected Inconclusive verdict on zero denominator; got: {:?}",
r.outcomes
);
let reasons: Vec<_> = r.inconclusive_details().collect();
assert_eq!(reasons.len(), 1, "exactly one Inconclusive reason expected");
assert_eq!(reasons[0].kind, DetailKind::Migration);
assert!(
reasons[0].message.contains("0 iterations") && reasons[0].message.contains("inconclusive"),
"Inconclusive reason must name zero-iteration condition; got: {}",
reasons[0].message
);
}
#[test]
fn plan_benchmarks_iteration_rate_via_assert_cgroup() {
let plan = AssertPlan {
not_starved: false,
isolation: false,
max_gap_ms: None,
max_spread_pct: None,
max_throughput_cv: None,
min_work_rate: None,
max_p99_wake_latency_ns: None,
max_wake_latency_cv: None,
min_iteration_rate: Some(1000.0),
max_migration_ratio: None,
min_page_locality: None,
max_cross_node_migration_ratio: None,
max_slow_tier_ratio: None,
};
let reports = [rpt_with_latencies(1, vec![], 10, 5_000_000_000)];
let r = plan.assert_cgroup(&reports, None, None);
assert!(!r.is_pass(), "2/s < 1000/s floor");
assert!(
r.failure_details().any(
|d| matches!(d.kind, DetailKind::Benchmark) && d.message.contains("iteration rate")
)
);
}
#[test]
fn assert_throughput_parity_all_zero_cpu_time_inconclusive_when_cv_set() {
let mut a = rpt(1, 0, 5_000_000_000, 5_000_000_000, &[0], 0);
let mut b = rpt(2, 0, 5_000_000_000, 5_000_000_000, &[0], 0);
a.cpu_time_ns = 0;
b.cpu_time_ns = 0;
let r = assert_throughput_parity(&[a, b], Some(0.5), None);
assert!(
r.is_inconclusive(),
"all-zero cpu_time must be Inconclusive when max_cv set: {:?}",
r.outcomes,
);
assert!(!r.is_pass(), "must not silently pass on zero denominator");
assert!(!r.is_fail(), "no actual CV violation to report");
let reason = r
.inconclusive_details()
.find(|d| d.kind == DetailKind::Benchmark)
.unwrap_or_else(|| panic!("expected Inconclusive reason, got {:?}", r.outcomes));
assert!(
reason.message.contains("zero cpu_time_ns"),
"diagnostic must name the root cause: {reason}"
);
assert!(
reason.message.contains("able to run"),
"diagnostic must surface the operator-actionable hint: {reason}"
);
}
#[test]
fn assert_throughput_parity_all_zero_cpu_time_inconclusive_when_min_rate_set() {
let mut a = rpt(1, 0, 5_000_000_000, 5_000_000_000, &[0], 0);
let mut b = rpt(2, 0, 5_000_000_000, 5_000_000_000, &[0], 0);
a.cpu_time_ns = 0;
b.cpu_time_ns = 0;
let r = assert_throughput_parity(&[a, b], None, Some(100.0));
assert!(
r.is_inconclusive(),
"all-zero cpu_time must be Inconclusive when min_rate set: {:?}",
r.outcomes,
);
assert!(
!r.is_fail(),
"no per-worker Fail when every worker is zero-cpu"
);
let reason = r
.inconclusive_details()
.find(|d| d.kind == DetailKind::Benchmark)
.unwrap_or_else(|| panic!("expected Benchmark Inconclusive, got {:?}", r.outcomes));
assert!(
reason.message.contains("zero cpu_time_ns"),
"diagnostic must name the root cause: {reason}"
);
assert!(
reason.message.contains("min_rate 100"),
"diagnostic must name the unevaluated limit: {reason}"
);
}
#[test]
fn assert_throughput_parity_all_zero_cpu_time_emits_single_inconclusive_when_both_limits_set() {
let mut a = rpt(1, 0, 5_000_000_000, 5_000_000_000, &[0], 0);
let mut b = rpt(2, 0, 5_000_000_000, 5_000_000_000, &[0], 0);
a.cpu_time_ns = 0;
b.cpu_time_ns = 0;
let r = assert_throughput_parity(&[a, b], Some(0.5), Some(100.0));
assert!(r.is_inconclusive());
let inconclusives: Vec<_> = r.inconclusive_details().collect();
assert_eq!(
inconclusives.len(),
1,
"all-zero-cpu with both limits set must produce a single Inconclusive, got {:?}",
r.outcomes,
);
let msg = &inconclusives[0].message;
assert!(
msg.contains("max_cv 0.500"),
"must list max_cv limit: {msg}"
);
assert!(
msg.contains("min_rate 100"),
"must list min_rate limit: {msg}"
);
assert!(
msg.contains("zero cpu_time_ns"),
"must name root cause: {msg}"
);
}
#[test]
fn assert_throughput_parity_mixed_zero_and_nonzero_cpu_does_not_short_circuit() {
let mut a = rpt(1, 0, 5_000_000_000, 5_000_000_000, &[0], 0);
let mut b = rpt(2, 1, 5_000_000_000, 5_000_000_000, &[0], 0);
a.cpu_time_ns = 0;
b.cpu_time_ns = 5_000_000_000;
let r = assert_throughput_parity(&[a, b], None, Some(100.0));
assert!(
r.is_fail(),
"non-zero-cpu worker below floor must fail: {:?}",
r.outcomes,
);
assert!(!r.is_inconclusive(), "only all-zero is Inconclusive");
assert!(
r.failure_details()
.any(|d| d.message.contains("worker 2") && d.message.contains("below floor")),
"expected worker-2 below-floor failure: {:?}",
r.outcomes,
);
}
#[test]
fn assert_throughput_parity_all_zero_cpu_time_passes_without_cv() {
let mut a = rpt(1, 0, 5_000_000_000, 5_000_000_000, &[0], 0);
let mut b = rpt(2, 0, 5_000_000_000, 5_000_000_000, &[0], 0);
a.cpu_time_ns = 0;
b.cpu_time_ns = 0;
let r = assert_throughput_parity(&[a, b], None, None);
assert!(
r.is_pass(),
"no CV configured → no failure: {:?}",
r.outcomes
);
}