backup
This commit is contained in:
236
tests/unit/test_metrics.py
Normal file
236
tests/unit/test_metrics.py
Normal file
@@ -0,0 +1,236 @@
|
||||
"""Unit tests for metrics collection."""
|
||||
|
||||
import pytest
|
||||
|
||||
from src.server.utils.metrics import (
|
||||
MetricsCollector,
|
||||
MetricType,
|
||||
TimerContext,
|
||||
get_metrics_collector,
|
||||
)
|
||||
|
||||
|
||||
def test_metrics_collector_initialization():
|
||||
"""Test metrics collector initialization."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
assert collector is not None
|
||||
assert collector._metrics == {}
|
||||
assert collector._download_stats["completed"] == 0
|
||||
assert collector._download_stats["failed"] == 0
|
||||
|
||||
|
||||
def test_increment_counter():
|
||||
"""Test counter metric increment."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
collector.increment_counter("test_counter", 1.0, help_text="Test counter")
|
||||
collector.increment_counter("test_counter", 2.0)
|
||||
|
||||
assert "test_counter" in collector._metrics
|
||||
assert collector._metrics["test_counter"].value == 3.0
|
||||
assert collector._metrics["test_counter"].metric_type == MetricType.COUNTER
|
||||
|
||||
|
||||
def test_set_gauge():
|
||||
"""Test gauge metric."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
collector.set_gauge("test_gauge", 42.0, help_text="Test gauge")
|
||||
assert collector._metrics["test_gauge"].value == 42.0
|
||||
|
||||
collector.set_gauge("test_gauge", 100.0)
|
||||
assert collector._metrics["test_gauge"].value == 100.0
|
||||
|
||||
|
||||
def test_observe_histogram():
|
||||
"""Test histogram observation."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
collector.observe_histogram("request_duration", 0.5)
|
||||
collector.observe_histogram("request_duration", 1.2)
|
||||
collector.observe_histogram("request_duration", 0.8)
|
||||
|
||||
assert len(collector._request_timings["request_duration"]) == 3
|
||||
assert 0.5 in collector._request_timings["request_duration"]
|
||||
|
||||
|
||||
def test_start_and_end_timer():
|
||||
"""Test timer functionality."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
collector.start_timer("test_timer")
|
||||
import time
|
||||
|
||||
time.sleep(0.01) # Sleep for 10ms
|
||||
duration = collector.end_timer("test_timer", "test_duration")
|
||||
|
||||
assert duration >= 0.01
|
||||
assert "test_duration" in collector._metrics
|
||||
|
||||
|
||||
def test_record_download_success():
|
||||
"""Test download success recording."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
collector.record_download_success(1000000)
|
||||
collector.record_download_success(2000000)
|
||||
|
||||
stats = collector.get_download_stats()
|
||||
assert stats["completed"] == 2
|
||||
assert stats["total_size_bytes"] == 3000000
|
||||
assert stats["failed"] == 0
|
||||
|
||||
|
||||
def test_record_download_failure():
|
||||
"""Test download failure recording."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
collector.record_download_failure()
|
||||
collector.record_download_failure()
|
||||
|
||||
stats = collector.get_download_stats()
|
||||
assert stats["failed"] == 2
|
||||
assert stats["completed"] == 0
|
||||
|
||||
|
||||
def test_get_request_statistics():
|
||||
"""Test request statistics calculation."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
for val in [0.5, 1.0, 0.8, 0.6, 0.9]:
|
||||
collector.observe_histogram("request_latency", val)
|
||||
|
||||
stats = collector.get_request_statistics("request_latency")
|
||||
|
||||
assert stats is not None
|
||||
assert stats["count"] == 5
|
||||
assert stats["mean"] == pytest.approx(0.76, abs=0.01)
|
||||
assert stats["min"] == 0.5
|
||||
assert stats["max"] == 1.0
|
||||
|
||||
|
||||
def test_get_request_statistics_not_found():
|
||||
"""Test request statistics for non-existent metric."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
stats = collector.get_request_statistics("non_existent")
|
||||
assert stats is None
|
||||
|
||||
|
||||
def test_export_prometheus_format():
|
||||
"""Test Prometheus format export."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
collector.increment_counter(
|
||||
"requests_total", 10, help_text="Total requests"
|
||||
)
|
||||
collector.set_gauge("active_connections", 5)
|
||||
|
||||
prometheus_output = collector.export_prometheus_format()
|
||||
|
||||
assert "requests_total" in prometheus_output
|
||||
assert "active_connections" in prometheus_output
|
||||
assert "10" in prometheus_output
|
||||
assert "5" in prometheus_output
|
||||
|
||||
|
||||
def test_export_prometheus_with_labels():
|
||||
"""Test Prometheus format with labels."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
labels = {"endpoint": "/api/anime", "method": "GET"}
|
||||
collector.increment_counter("requests_total", labels=labels)
|
||||
|
||||
prometheus_output = collector.export_prometheus_format()
|
||||
|
||||
assert "endpoint" in prometheus_output
|
||||
assert "method" in prometheus_output
|
||||
assert "/api/anime" in prometheus_output
|
||||
assert "GET" in prometheus_output
|
||||
|
||||
|
||||
def test_export_json():
|
||||
"""Test JSON export."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
collector.increment_counter("test_counter", 5)
|
||||
collector.set_gauge("test_gauge", 42)
|
||||
collector.record_download_success(1000000)
|
||||
|
||||
json_export = collector.export_json()
|
||||
|
||||
assert "metrics" in json_export
|
||||
assert "downloads" in json_export
|
||||
assert "request_timings" in json_export
|
||||
assert json_export["downloads"]["completed"] == 1
|
||||
assert json_export["downloads"]["total_size_bytes"] == 1000000
|
||||
|
||||
|
||||
def test_reset_metrics():
|
||||
"""Test metrics reset."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
collector.increment_counter("test_counter", 10)
|
||||
collector.record_download_success(1000000)
|
||||
|
||||
assert len(collector._metrics) > 0
|
||||
assert collector._download_stats["completed"] == 1
|
||||
|
||||
collector.reset_metrics()
|
||||
|
||||
assert len(collector._metrics) == 0
|
||||
assert collector._download_stats["completed"] == 0
|
||||
|
||||
|
||||
def test_get_all_metrics():
|
||||
"""Test getting all metrics."""
|
||||
collector = MetricsCollector()
|
||||
|
||||
collector.increment_counter("counter1", 5)
|
||||
collector.set_gauge("gauge1", 10)
|
||||
collector.increment_counter("counter2", 3)
|
||||
|
||||
all_metrics = collector.get_all_metrics()
|
||||
|
||||
assert len(all_metrics) == 3
|
||||
assert "counter1" in all_metrics
|
||||
assert "gauge1" in all_metrics
|
||||
assert "counter2" in all_metrics
|
||||
|
||||
|
||||
def test_get_metrics_collector_singleton():
|
||||
"""Test singleton metrics collector."""
|
||||
collector1 = get_metrics_collector()
|
||||
collector2 = get_metrics_collector()
|
||||
|
||||
assert collector1 is collector2
|
||||
assert isinstance(collector1, MetricsCollector)
|
||||
|
||||
|
||||
def test_timer_context_manager():
|
||||
"""Test timer context manager."""
|
||||
collector = get_metrics_collector()
|
||||
collector.reset_metrics()
|
||||
|
||||
import time
|
||||
|
||||
with TimerContext("operation_duration", "timer1"):
|
||||
time.sleep(0.01)
|
||||
|
||||
stats = collector.get_request_statistics("operation_duration")
|
||||
assert stats is not None
|
||||
assert stats["count"] == 1
|
||||
assert stats["max"] >= 0.01
|
||||
|
||||
|
||||
def test_timer_context_with_labels():
|
||||
"""Test timer context manager with labels."""
|
||||
collector = get_metrics_collector()
|
||||
collector.reset_metrics()
|
||||
|
||||
labels = {"endpoint": "/api/test"}
|
||||
with TimerContext("endpoint_duration", labels=labels):
|
||||
pass
|
||||
|
||||
assert "endpoint_duration" in collector._metrics
|
||||
Reference in New Issue
Block a user