| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- # -*- coding: utf-8 -*-
- """
- Tests für Satellite Metrics System.
- """
- import pytest
- from datetime import datetime, timedelta
- from trixy_core.satellite.metrics import (
- SatelliteMetricsCollector,
- MetricType,
- MetricValue,
- SatelliteMetrics,
- MetricsAggregator,
- AggregationType,
- AggregatedMetric,
- TimeWindow,
- )
- class TestMetricType:
- """Tests für MetricType."""
- def test_metric_types(self):
- """Testet Metrik-Typen."""
- assert MetricType.COUNTER.name == "COUNTER"
- assert MetricType.GAUGE.name == "GAUGE"
- assert MetricType.HISTOGRAM.name == "HISTOGRAM"
- assert MetricType.TIMING.name == "TIMING"
- class TestMetricValue:
- """Tests für MetricValue."""
- def test_value_creation(self):
- """Testet Value-Erstellung."""
- value = MetricValue(
- name="latency",
- value=15.5,
- metric_type=MetricType.TIMING,
- unit="ms",
- )
- assert value.name == "latency"
- assert value.value == 15.5
- assert value.metric_type == MetricType.TIMING
- assert value.unit == "ms"
- def test_value_with_labels(self):
- """Testet Value mit Labels."""
- value = MetricValue(
- name="requests",
- value=100,
- labels={"endpoint": "/api/data"},
- )
- assert value.labels["endpoint"] == "/api/data"
- def test_to_dict(self):
- """Testet Dictionary-Konvertierung."""
- value = MetricValue(
- name="test",
- value=42.0,
- metric_type=MetricType.GAUGE,
- )
- d = value.to_dict()
- assert d["name"] == "test"
- assert d["value"] == 42.0
- assert d["type"] == "GAUGE"
- class TestSatelliteMetrics:
- """Tests für SatelliteMetrics."""
- @pytest.fixture
- def metrics(self):
- """Erstellt SatelliteMetrics."""
- return SatelliteMetrics(satellite_id="sat-001")
- def test_initial_metrics(self, metrics):
- """Testet initiale Metriken."""
- assert metrics.satellite_id == "sat-001"
- assert metrics.latency_ms == 0.0
- assert metrics.messages_sent == 0
- assert metrics.error_count == 0
- def test_record_latency(self, metrics):
- """Testet Latenz-Aufzeichnung."""
- metrics.record_latency(15.5)
- assert metrics.latency_ms == 15.5
- assert len(metrics.latency_history) == 1
- def test_record_error(self, metrics):
- """Testet Fehler-Aufzeichnung."""
- metrics.record_error("Connection timeout")
- assert metrics.error_count == 1
- assert metrics.last_error == "Connection timeout"
- assert metrics.last_error_time is not None
- def test_get_avg_latency(self, metrics):
- """Testet Durchschnitts-Latenz."""
- metrics.record_latency(10.0)
- metrics.record_latency(20.0)
- metrics.record_latency(30.0)
- avg = metrics.get_avg_latency(300)
- assert avg == 20.0
- def test_to_dict(self, metrics):
- """Testet Dictionary-Konvertierung."""
- metrics.latency_ms = 15.0
- metrics.messages_sent = 100
- d = metrics.to_dict()
- assert d["satellite_id"] == "sat-001"
- assert d["network"]["latency_ms"] == 15.0
- assert d["network"]["messages_sent"] == 100
- class TestSatelliteMetricsCollector:
- """Tests für SatelliteMetricsCollector."""
- @pytest.fixture
- def collector(self):
- """Erstellt MetricsCollector."""
- return SatelliteMetricsCollector()
- def test_record_latency(self, collector):
- """Testet Latenz-Aufzeichnung."""
- collector.record_latency("sat-001", 15.5)
- metrics = collector.get_metrics("sat-001")
- assert metrics is not None
- assert metrics.latency_ms == 15.5
- def test_record_message_sent(self, collector):
- """Testet gesendete Nachricht."""
- collector.record_message_sent("sat-001", 256)
- metrics = collector.get_metrics("sat-001")
- assert metrics.messages_sent == 1
- assert metrics.bytes_sent == 256
- def test_record_message_received(self, collector):
- """Testet empfangene Nachricht."""
- collector.record_message_received("sat-001", 512)
- metrics = collector.get_metrics("sat-001")
- assert metrics.messages_received == 1
- assert metrics.bytes_received == 512
- def test_record_heartbeat(self, collector):
- """Testet Heartbeat-Aufzeichnung."""
- collector.record_heartbeat("sat-001")
- metrics = collector.get_metrics("sat-001")
- assert metrics.last_heartbeat is not None
- def test_record_reconnect(self, collector):
- """Testet Reconnect-Aufzeichnung."""
- collector.record_reconnect("sat-001")
- metrics = collector.get_metrics("sat-001")
- assert metrics.reconnect_count == 1
- def test_record_error(self, collector):
- """Testet Fehler-Aufzeichnung."""
- collector.record_error("sat-001", "Connection lost")
- metrics = collector.get_metrics("sat-001")
- assert metrics.error_count == 1
- def test_record_packet_loss(self, collector):
- """Testet Paketverlust-Aufzeichnung."""
- collector.record_packet_loss("sat-001", 2.5)
- metrics = collector.get_metrics("sat-001")
- assert metrics.packet_loss_percent == 2.5
- def test_record_bandwidth(self, collector):
- """Testet Bandbreiten-Aufzeichnung."""
- collector.record_bandwidth("sat-001", 1000.0)
- metrics = collector.get_metrics("sat-001")
- assert metrics.bandwidth_kbps == 1000.0
- def test_record_custom(self, collector):
- """Testet benutzerdefinierte Metrik."""
- collector.record_custom(
- "sat-001",
- "cpu_usage",
- 45.5,
- metric_type=MetricType.GAUGE,
- unit="%",
- )
- history = collector.get_custom_metric("sat-001", "cpu_usage")
- assert len(history) == 1
- assert history[0].value == 45.5
- def test_get_all_metrics(self, collector):
- """Testet Abruf aller Metriken."""
- collector.record_latency("sat-001", 10.0)
- collector.record_latency("sat-002", 20.0)
- all_metrics = collector.get_all_metrics()
- assert len(all_metrics) == 2
- assert "sat-001" in all_metrics
- assert "sat-002" in all_metrics
- def test_remove_satellite(self, collector):
- """Testet Satellite-Entfernung."""
- collector.record_latency("sat-001", 10.0)
- assert collector.remove_satellite("sat-001")
- assert collector.get_metrics("sat-001") is None
- def test_get_summary(self, collector):
- """Testet Zusammenfassung."""
- collector.record_latency("sat-001", 10.0)
- collector.record_latency("sat-002", 20.0)
- collector.record_error("sat-001", "Error")
- summary = collector.get_summary()
- assert summary["satellite_count"] == 2
- assert summary["avg_latency_ms"] == 15.0
- assert summary["total_errors"] == 1
- def test_on_metric_callback(self, collector):
- """Testet Metrik-Callback."""
- received = []
- def on_metric(sat_id, value):
- received.append((sat_id, value.name))
- collector.on_metric(on_metric)
- collector.record_latency("sat-001", 10.0)
- assert ("sat-001", "latency") in received
- def test_clear_all(self, collector):
- """Testet Löschen aller Metriken."""
- collector.record_latency("sat-001", 10.0)
- collector.record_latency("sat-002", 20.0)
- collector.clear_all()
- assert collector.satellite_count == 0
- class TestTimeWindow:
- """Tests für TimeWindow."""
- def test_window_values(self):
- """Testet Window-Werte."""
- assert TimeWindow.MINUTE.value == 60
- assert TimeWindow.FIVE_MINUTES.value == 300
- assert TimeWindow.HOUR.value == 3600
- assert TimeWindow.DAY.value == 86400
- class TestAggregationType:
- """Tests für AggregationType."""
- def test_aggregation_types(self):
- """Testet Aggregations-Typen."""
- assert AggregationType.SUM.name == "SUM"
- assert AggregationType.AVG.name == "AVG"
- assert AggregationType.MIN.name == "MIN"
- assert AggregationType.MAX.name == "MAX"
- assert AggregationType.P95.name == "P95"
- class TestAggregatedMetric:
- """Tests für AggregatedMetric."""
- def test_metric_creation(self):
- """Testet Metrik-Erstellung."""
- metric = AggregatedMetric(
- name="latency",
- aggregation=AggregationType.AVG,
- value=15.5,
- window=TimeWindow.FIVE_MINUTES,
- sample_count=100,
- start_time=datetime.now() - timedelta(minutes=5),
- end_time=datetime.now(),
- )
- assert metric.name == "latency"
- assert metric.value == 15.5
- assert metric.sample_count == 100
- def test_to_dict(self):
- """Testet Dictionary-Konvertierung."""
- metric = AggregatedMetric(
- name="test",
- aggregation=AggregationType.AVG,
- value=42.0,
- window=TimeWindow.MINUTE,
- sample_count=10,
- start_time=datetime.now(),
- end_time=datetime.now(),
- )
- d = metric.to_dict()
- assert d["name"] == "test"
- assert d["aggregation"] == "AVG"
- assert d["value"] == 42.0
- class TestMetricsAggregator:
- """Tests für MetricsAggregator."""
- @pytest.fixture
- def collector(self):
- """Erstellt Collector mit Testdaten."""
- collector = SatelliteMetricsCollector()
- # Testdaten hinzufügen
- collector.record_latency("sat-001", 10.0)
- collector.record_latency("sat-002", 20.0)
- collector.record_latency("sat-003", 30.0)
- collector.record_error("sat-001", "Error 1")
- collector.record_error("sat-002", "Error 2")
- return collector
- @pytest.fixture
- def aggregator(self, collector):
- """Erstellt Aggregator."""
- return MetricsAggregator(collector)
- def test_aggregate_avg(self, aggregator):
- """Testet Durchschnitts-Aggregation."""
- result = aggregator.aggregate(
- "latency",
- AggregationType.AVG,
- TimeWindow.HOUR,
- )
- assert result.value == 20.0
- assert result.sample_count == 3
- def test_aggregate_sum(self, aggregator):
- """Testet Summen-Aggregation."""
- result = aggregator.aggregate(
- "latency",
- AggregationType.SUM,
- TimeWindow.HOUR,
- )
- assert result.value == 60.0
- def test_aggregate_min(self, aggregator):
- """Testet Minimum-Aggregation."""
- result = aggregator.aggregate(
- "latency",
- AggregationType.MIN,
- TimeWindow.HOUR,
- )
- assert result.value == 10.0
- def test_aggregate_max(self, aggregator):
- """Testet Maximum-Aggregation."""
- result = aggregator.aggregate(
- "latency",
- AggregationType.MAX,
- TimeWindow.HOUR,
- )
- assert result.value == 30.0
- def test_aggregate_count(self, aggregator):
- """Testet Zähl-Aggregation."""
- result = aggregator.aggregate(
- "latency",
- AggregationType.COUNT,
- TimeWindow.HOUR,
- )
- assert result.value == 3.0
- def test_aggregate_median(self, aggregator):
- """Testet Median-Aggregation."""
- result = aggregator.aggregate(
- "latency",
- AggregationType.MEDIAN,
- TimeWindow.HOUR,
- )
- assert result.value == 20.0
- def test_aggregate_multiple(self, aggregator):
- """Testet mehrfache Aggregation."""
- results = aggregator.aggregate_multiple(
- ["latency", "error_count"],
- [AggregationType.AVG, AggregationType.SUM],
- )
- assert "latency" in results
- assert "error_count" in results
- assert "AVG" in results["latency"]
- assert "SUM" in results["latency"]
- def test_get_top_satellites(self, aggregator):
- """Testet Top-Satellites."""
- top = aggregator.get_top_satellites("latency", limit=2)
- assert len(top) == 2
- # Höchste Latenz zuerst
- assert top[0][1] == 30.0
- def test_get_top_satellites_ascending(self, aggregator):
- """Testet Top-Satellites aufsteigend."""
- top = aggregator.get_top_satellites(
- "latency",
- limit=2,
- ascending=True,
- )
- # Niedrigste Latenz zuerst
- assert top[0][1] == 10.0
- def test_get_metric_distribution(self, aggregator):
- """Testet Metrik-Verteilung."""
- dist = aggregator.get_metric_distribution(
- "latency",
- buckets=3,
- )
- assert "buckets" in dist
- assert dist["min"] == 10.0
- assert dist["max"] == 30.0
- assert dist["count"] == 3
- def test_get_satellite_comparison(self, aggregator):
- """Testet Satellite-Vergleich."""
- comparison = aggregator.get_satellite_comparison(
- "latency",
- ["sat-001", "sat-002"],
- )
- assert "sat-001" in comparison
- assert "sat-002" in comparison
- assert comparison["sat-001"]["current"] == 10.0
- assert comparison["sat-002"]["current"] == 20.0
- def test_get_health_summary(self, aggregator):
- """Testet Gesundheits-Übersicht."""
- summary = aggregator.get_health_summary()
- assert "status" in summary
- assert "metrics" in summary
- assert "satellite_count" in summary
- def test_cache_functionality(self, aggregator):
- """Testet Cache-Funktionalität."""
- # Erste Abfrage
- result1 = aggregator.aggregate("latency", AggregationType.AVG)
- # Zweite Abfrage (sollte aus Cache kommen)
- result2 = aggregator.aggregate("latency", AggregationType.AVG)
- assert result1.value == result2.value
- def test_clear_cache(self, aggregator):
- """Testet Cache-Löschen."""
- aggregator.aggregate("latency", AggregationType.AVG)
- assert len(aggregator._cache) > 0
- aggregator.clear_cache()
- assert len(aggregator._cache) == 0
|