completed local setup with compose
Some checks failed
CI/CD Pipeline / Generate SBOM (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Code Quality & Linting (push) Has been cancelled
CI/CD Pipeline / Policy Validation (push) Has been cancelled
CI/CD Pipeline / Test Suite (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-coverage) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-extract) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-firm-connectors) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-forms) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-hmrc) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-ingestion) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-kg) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-normalize-map) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-ocr) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rag-indexer) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rag-retriever) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-reason) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rpa) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (ui-review) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-coverage) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-extract) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-kg) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-rag-retriever) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (ui-review) (push) Has been cancelled
CI/CD Pipeline / Notifications (push) Has been cancelled
Some checks failed
CI/CD Pipeline / Generate SBOM (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Code Quality & Linting (push) Has been cancelled
CI/CD Pipeline / Policy Validation (push) Has been cancelled
CI/CD Pipeline / Test Suite (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-coverage) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-extract) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-firm-connectors) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-forms) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-hmrc) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-ingestion) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-kg) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-normalize-map) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-ocr) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rag-indexer) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rag-retriever) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-reason) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rpa) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (ui-review) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-coverage) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-extract) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-kg) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-rag-retriever) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (ui-review) (push) Has been cancelled
CI/CD Pipeline / Notifications (push) Has been cancelled
This commit is contained in:
274
tests/unit/test_event_metrics.py
Normal file
274
tests/unit/test_event_metrics.py
Normal file
@@ -0,0 +1,274 @@
|
||||
"""Tests for event metrics."""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from libs.events.metrics import (
|
||||
EventMetricsCollector,
|
||||
event_consumed_total,
|
||||
event_dlq_total,
|
||||
event_processing_duration_seconds,
|
||||
event_processing_errors_total,
|
||||
event_publish_errors_total,
|
||||
event_published_total,
|
||||
event_publishing_duration_seconds,
|
||||
event_retry_total,
|
||||
event_schema_validation_errors_total,
|
||||
get_event_metrics_registry,
|
||||
nats_consumer_lag_messages,
|
||||
nats_stream_messages_total,
|
||||
)
|
||||
|
||||
|
||||
class TestEventMetrics:
|
||||
"""Test cases for event metrics."""
|
||||
|
||||
def test_get_event_metrics_registry(self) -> None:
|
||||
"""Test getting the metrics registry."""
|
||||
registry = get_event_metrics_registry()
|
||||
assert registry is not None
|
||||
|
||||
def test_metrics_exist(self) -> None:
|
||||
"""Test that all expected metrics are defined."""
|
||||
# Publishing metrics
|
||||
assert event_published_total is not None
|
||||
assert event_publish_errors_total is not None
|
||||
assert event_publishing_duration_seconds is not None
|
||||
|
||||
# Consumption metrics
|
||||
assert event_consumed_total is not None
|
||||
assert event_processing_duration_seconds is not None
|
||||
assert event_processing_errors_total is not None
|
||||
|
||||
# DLQ metrics
|
||||
assert event_dlq_total is not None
|
||||
assert event_retry_total is not None
|
||||
|
||||
# Schema validation metrics
|
||||
assert event_schema_validation_errors_total is not None
|
||||
|
||||
# NATS metrics
|
||||
assert nats_stream_messages_total is not None
|
||||
assert nats_consumer_lag_messages is not None
|
||||
|
||||
|
||||
class TestEventMetricsCollector:
|
||||
"""Test cases for EventMetricsCollector."""
|
||||
|
||||
def test_record_publish_success(self) -> None:
|
||||
"""Test recording successful publish."""
|
||||
with patch.object(event_published_total, "labels") as mock_labels:
|
||||
mock_counter = MagicMock()
|
||||
mock_labels.return_value = mock_counter
|
||||
|
||||
EventMetricsCollector.record_publish(
|
||||
topic="test.topic",
|
||||
duration_seconds=0.05,
|
||||
success=True,
|
||||
)
|
||||
|
||||
mock_labels.assert_called_once_with(topic="test.topic")
|
||||
mock_counter.inc.assert_called_once()
|
||||
|
||||
def test_record_publish_failure(self) -> None:
|
||||
"""Test recording failed publish."""
|
||||
with patch.object(event_publish_errors_total, "labels") as mock_labels:
|
||||
mock_counter = MagicMock()
|
||||
mock_labels.return_value = mock_counter
|
||||
|
||||
EventMetricsCollector.record_publish(
|
||||
topic="test.topic",
|
||||
duration_seconds=0.1,
|
||||
success=False,
|
||||
error_type="ConnectionError",
|
||||
)
|
||||
|
||||
mock_labels.assert_called_once_with(
|
||||
topic="test.topic", error_type="ConnectionError"
|
||||
)
|
||||
mock_counter.inc.assert_called_once()
|
||||
|
||||
def test_record_publish_duration(self) -> None:
|
||||
"""Test recording publish duration."""
|
||||
with patch.object(event_publishing_duration_seconds, "labels") as mock_labels:
|
||||
mock_histogram = MagicMock()
|
||||
mock_labels.return_value = mock_histogram
|
||||
|
||||
duration = 0.123
|
||||
EventMetricsCollector.record_publish(
|
||||
topic="test.topic",
|
||||
duration_seconds=duration,
|
||||
success=True,
|
||||
)
|
||||
|
||||
mock_labels.assert_called_once_with(topic="test.topic")
|
||||
mock_histogram.observe.assert_called_once_with(duration)
|
||||
|
||||
def test_record_consume_success(self) -> None:
|
||||
"""Test recording successful event consumption."""
|
||||
with patch.object(event_consumed_total, "labels") as mock_labels:
|
||||
mock_counter = MagicMock()
|
||||
mock_labels.return_value = mock_counter
|
||||
|
||||
EventMetricsCollector.record_consume(
|
||||
topic="test.topic",
|
||||
consumer_group="test-group",
|
||||
duration_seconds=0.5,
|
||||
success=True,
|
||||
)
|
||||
|
||||
mock_labels.assert_called_once_with(
|
||||
topic="test.topic", consumer_group="test-group"
|
||||
)
|
||||
mock_counter.inc.assert_called_once()
|
||||
|
||||
def test_record_consume_failure(self) -> None:
|
||||
"""Test recording failed event consumption."""
|
||||
with patch.object(event_processing_errors_total, "labels") as mock_labels:
|
||||
mock_counter = MagicMock()
|
||||
mock_labels.return_value = mock_counter
|
||||
|
||||
EventMetricsCollector.record_consume(
|
||||
topic="test.topic",
|
||||
consumer_group="test-group",
|
||||
duration_seconds=1.0,
|
||||
success=False,
|
||||
error_type="ValidationError",
|
||||
)
|
||||
|
||||
mock_labels.assert_called_once_with(
|
||||
topic="test.topic",
|
||||
consumer_group="test-group",
|
||||
error_type="ValidationError",
|
||||
)
|
||||
mock_counter.inc.assert_called_once()
|
||||
|
||||
def test_record_consume_duration(self) -> None:
|
||||
"""Test recording consumption duration."""
|
||||
with patch.object(event_processing_duration_seconds, "labels") as mock_labels:
|
||||
mock_histogram = MagicMock()
|
||||
mock_labels.return_value = mock_histogram
|
||||
|
||||
duration = 2.5
|
||||
EventMetricsCollector.record_consume(
|
||||
topic="test.topic",
|
||||
consumer_group="test-group",
|
||||
duration_seconds=duration,
|
||||
success=True,
|
||||
)
|
||||
|
||||
mock_labels.assert_called_once_with(
|
||||
topic="test.topic", consumer_group="test-group"
|
||||
)
|
||||
mock_histogram.observe.assert_called_once_with(duration)
|
||||
|
||||
def test_record_dlq(self) -> None:
|
||||
"""Test recording DLQ event."""
|
||||
with patch.object(event_dlq_total, "labels") as mock_labels:
|
||||
mock_counter = MagicMock()
|
||||
mock_labels.return_value = mock_counter
|
||||
|
||||
EventMetricsCollector.record_dlq(
|
||||
topic="test.topic", error_type="TimeoutError"
|
||||
)
|
||||
|
||||
mock_labels.assert_called_once_with(
|
||||
topic="test.topic", error_type="TimeoutError"
|
||||
)
|
||||
mock_counter.inc.assert_called_once()
|
||||
|
||||
def test_record_retry(self) -> None:
|
||||
"""Test recording retry attempt."""
|
||||
with patch.object(event_retry_total, "labels") as mock_labels:
|
||||
mock_counter = MagicMock()
|
||||
mock_labels.return_value = mock_counter
|
||||
|
||||
EventMetricsCollector.record_retry(topic="test.topic", retry_attempt=2)
|
||||
|
||||
mock_labels.assert_called_once_with(topic="test.topic", retry_attempt="2")
|
||||
mock_counter.inc.assert_called_once()
|
||||
|
||||
def test_record_schema_validation_error(self) -> None:
|
||||
"""Test recording schema validation error."""
|
||||
with patch.object(
|
||||
event_schema_validation_errors_total, "labels"
|
||||
) as mock_labels:
|
||||
mock_counter = MagicMock()
|
||||
mock_labels.return_value = mock_counter
|
||||
|
||||
EventMetricsCollector.record_schema_validation_error(
|
||||
topic="test.topic", validation_error="missing_required_field"
|
||||
)
|
||||
|
||||
mock_labels.assert_called_once_with(
|
||||
topic="test.topic", validation_error="missing_required_field"
|
||||
)
|
||||
mock_counter.inc.assert_called_once()
|
||||
|
||||
def test_record_nats_stream_message(self) -> None:
|
||||
"""Test recording NATS stream message."""
|
||||
with patch.object(nats_stream_messages_total, "labels") as mock_labels:
|
||||
mock_counter = MagicMock()
|
||||
mock_labels.return_value = mock_counter
|
||||
|
||||
EventMetricsCollector.record_nats_stream_message(
|
||||
stream_name="TAX_AGENT_EVENTS"
|
||||
)
|
||||
|
||||
mock_labels.assert_called_once_with(stream_name="TAX_AGENT_EVENTS")
|
||||
mock_counter.inc.assert_called_once()
|
||||
|
||||
def test_record_consumer_lag(self) -> None:
|
||||
"""Test recording consumer lag."""
|
||||
with patch.object(nats_consumer_lag_messages, "labels") as mock_labels:
|
||||
mock_histogram = MagicMock()
|
||||
mock_labels.return_value = mock_histogram
|
||||
|
||||
EventMetricsCollector.record_consumer_lag(
|
||||
stream_name="TAX_AGENT_EVENTS",
|
||||
consumer_group="tax-agent",
|
||||
lag_messages=150,
|
||||
)
|
||||
|
||||
mock_labels.assert_called_once_with(
|
||||
stream_name="TAX_AGENT_EVENTS", consumer_group="tax-agent"
|
||||
)
|
||||
mock_histogram.observe.assert_called_once_with(150)
|
||||
|
||||
def test_record_publish_with_default_error_type(self) -> None:
|
||||
"""Test recording publish failure with default error type."""
|
||||
with patch.object(event_publish_errors_total, "labels") as mock_labels:
|
||||
mock_counter = MagicMock()
|
||||
mock_labels.return_value = mock_counter
|
||||
|
||||
EventMetricsCollector.record_publish(
|
||||
topic="test.topic",
|
||||
duration_seconds=0.1,
|
||||
success=False,
|
||||
error_type=None, # No error type provided
|
||||
)
|
||||
|
||||
mock_labels.assert_called_once_with(
|
||||
topic="test.topic", error_type="unknown" # Should default to "unknown"
|
||||
)
|
||||
mock_counter.inc.assert_called_once()
|
||||
|
||||
def test_record_consume_with_default_error_type(self) -> None:
|
||||
"""Test recording consume failure with default error type."""
|
||||
with patch.object(event_processing_errors_total, "labels") as mock_labels:
|
||||
mock_counter = MagicMock()
|
||||
mock_labels.return_value = mock_counter
|
||||
|
||||
EventMetricsCollector.record_consume(
|
||||
topic="test.topic",
|
||||
consumer_group="test-group",
|
||||
duration_seconds=1.0,
|
||||
success=False,
|
||||
error_type=None, # No error type provided
|
||||
)
|
||||
|
||||
mock_labels.assert_called_once_with(
|
||||
topic="test.topic",
|
||||
consumer_group="test-group",
|
||||
error_type="unknown", # Should default to "unknown"
|
||||
)
|
||||
mock_counter.inc.assert_called_once()
|
||||
Reference in New Issue
Block a user