From c9598446083559f761a36596f91631c60c5fe23b Mon Sep 17 00:00:00 2001 From: Mika Date: Thu, 12 Mar 2026 11:51:45 +0000 Subject: [PATCH] Add outlier_analysis/tests/test_core.py --- outlier_analysis/tests/test_core.py | 66 +++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 outlier_analysis/tests/test_core.py diff --git a/outlier_analysis/tests/test_core.py b/outlier_analysis/tests/test_core.py new file mode 100644 index 0000000..402a4a1 --- /dev/null +++ b/outlier_analysis/tests/test_core.py @@ -0,0 +1,66 @@ +import pytest +import math +from typing import List, Dict +from outlier_analysis import core + + +@pytest.fixture +def sample_log_data() -> List[Dict]: + return [ + {"run_id": "18", "latency_ms": 45.0, "stratum": "near-expiry-unpinned", "job_parallelism": 4, "retry_total_overhead_ms": 0.0}, + {"run_id": "18", "latency_ms": 120.0, "stratum": "near-expiry-unpinned", "job_parallelism": 4, "retry_total_overhead_ms": 10.0}, + {"run_id": "18", "latency_ms": 95.0, "stratum": "pinned", "job_parallelism": 4, "retry_total_overhead_ms": 5.0}, + {"run_id": "19", "latency_ms": 80.0, "stratum": "pinned", "job_parallelism": 8, "retry_total_overhead_ms": 0.0}, + {"run_id": "19", "latency_ms": 101.0, "stratum": "unpinned", "job_parallelism": 8, "retry_total_overhead_ms": 3.5}, + {"run_id": "19", "latency_ms": 200.0, "stratum": "unpinned", "job_parallelism": 8, "retry_total_overhead_ms": 15.0}, + {"run_id": "20", "latency_ms": 49.0, "stratum": "pinned", "job_parallelism": 2, "retry_total_overhead_ms": 0.0}, + {"run_id": "20", "latency_ms": 52.0, "stratum": "pinned", "job_parallelism": 2, "retry_total_overhead_ms": 0.0} + ] + + +def test_analyze_outliers_returns_valid_structure(sample_log_data): + result = core.analyze_outliers(sample_log_data) + + assert isinstance(result, dict) + assert all(isinstance(v, dict) for v in result.values()) + + for run_id, summary in result.items(): + assert set(summary.keys()) == {"run_id", "outlier_count", "latency_distribution"} + assert isinstance(summary["run_id"], str) + assert isinstance(summary["outlier_count"], int) + dist = summary["latency_distribution"] + assert isinstance(dist, dict) + for key in ("p50", "p95", "p99", "max"): + assert key in dist + assert isinstance(dist[key], (int, float)) + + +def test_outlier_detection_counts(sample_log_data): + result = core.analyze_outliers(sample_log_data) + # Run 18 has 2 entries >90ms, expect 2 outliers + assert result["18"]["outlier_count"] == 2 + # Run 19 has 2 entries >90ms as well + assert result["19"]["outlier_count"] == 2 + # Run 20 has none >90ms + assert result["20"]["outlier_count"] == 0 + + +def test_latency_distribution_values(sample_log_data): + result = core.analyze_outliers(sample_log_data) + for run_id, summary in result.items(): + dist = summary["latency_distribution"] + for k, v in dist.items(): + assert v >= 0.0, f"Latency metric {k} should be non-negative" + # Monotonic: p50 <= p95 <= p99 <= max + assert dist["p50"] <= dist["p95"] <= dist["p99"] <= dist["max"] + + +def test_empty_input_returns_empty(): + result = core.analyze_outliers([]) + assert isinstance(result, dict) + assert result == {} + + +def test_invalid_input_type_raises(): + with pytest.raises((AssertionError, TypeError)): + core.analyze_outliers(None) # type: ignore