"""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