use crate::models::ProbeResult;
#[derive(Debug, Clone, PartialEq)]
pub struct RegressionSummary {
pub previous_ttfb_ms: u64,
pub current_ttfb_ms: u64,
pub delta_ms: i64,
pub delta_percent: f64,
pub threshold_percent: f64,
pub exceeded_threshold: bool,
}
pub fn compare_ttfb(
previous: &ProbeResult,
current: &ProbeResult,
threshold_percent: f64,
) -> Option<RegressionSummary> {
if previous.report.ttfb_ms == 0 {
return None;
}
let previous_ttfb_ms = previous.report.ttfb_ms;
let current_ttfb_ms = current.report.ttfb_ms;
let delta_ms = current_ttfb_ms as i64 - previous_ttfb_ms as i64;
let delta_percent = ((current_ttfb_ms as f64 - previous_ttfb_ms as f64)
/ previous_ttfb_ms as f64)
* 100.0;
Some(RegressionSummary {
previous_ttfb_ms,
current_ttfb_ms,
delta_ms,
delta_percent,
threshold_percent,
exceeded_threshold: delta_percent >= threshold_percent,
})
}
#[cfg(test)]
mod tests {
use crate::engine::timing::build_report;
use crate::models::{ProbeResult, ProbeStatus};
use super::compare_ttfb;
fn probe_result(ttfb_ms: u64) -> ProbeResult {
ProbeResult {
id: 1,
target: "http://localhost:3000".to_string(),
request_path: "/".to_string(),
report: build_report(10, 20, 30, ttfb_ms, 0),
status: ProbeStatus::Succeeded,
response_status_code: Some(200),
response_status_text: Some("OK".to_string()),
response_bytes: Some(128),
error_message: None,
tls: None,
created_at_ms: 1,
}
}
#[test]
fn compare_ttfb_detects_regression_above_threshold() {
let previous = probe_result(100);
let current = probe_result(150);
let summary = compare_ttfb(&previous, ¤t, 40.0).expect("summary should exist");
assert_eq!(summary.previous_ttfb_ms, 100);
assert_eq!(summary.current_ttfb_ms, 150);
assert_eq!(summary.delta_ms, 50);
assert_eq!(summary.delta_percent, 50.0);
assert!(summary.exceeded_threshold);
}
#[test]
fn compare_ttfb_detects_improvement_without_threshold_breach() {
let previous = probe_result(100);
let current = probe_result(80);
let summary = compare_ttfb(&previous, ¤t, 40.0).expect("summary should exist");
assert_eq!(summary.delta_ms, -20);
assert_eq!(summary.delta_percent, -20.0);
assert!(!summary.exceeded_threshold);
}
#[test]
fn compare_ttfb_returns_none_when_previous_is_zero() {
let previous = probe_result(0);
let current = probe_result(80);
assert!(compare_ttfb(&previous, ¤t, 40.0).is_none());
}
}