ForcePilot/backend/test/unit/channels/test_nostr_metrics.py

141 lines
5.7 KiB
Python
Raw Normal View History

from __future__ import annotations
import pytest
from yuxi.channels.adapters.nostr.metrics import NostrMetrics, MetricsSnapshot
class TestNostrMetrics:
@pytest.fixture
def metrics(self):
return NostrMetrics()
def test_increment_counter(self, metrics):
metrics.increment("test.counter", 1)
assert metrics.get_counter("test.counter") == 1
def test_increment_multiple(self, metrics):
metrics.increment("test.counter", 5)
metrics.increment("test.counter", 3)
assert metrics.get_counter("test.counter") == 8
def test_increment_default_value(self, metrics):
metrics.increment("default_val")
assert metrics.get_counter("default_val") == 1
def test_set_gauge(self, metrics):
metrics.set_gauge("test.gauge", 42.0)
assert metrics.get_gauge("test.gauge") == 42.0
def test_adjust_gauge_positive(self, metrics):
metrics.set_gauge("test.gauge", 10.0)
metrics.adjust_gauge("test.gauge", 5.0)
assert metrics.get_gauge("test.gauge") == 15.0
def test_adjust_gauge_negative(self, metrics):
metrics.set_gauge("test.gauge", 10.0)
metrics.adjust_gauge("test.gauge", -3.0)
assert metrics.get_gauge("test.gauge") == 7.0
def test_snapshot_contains_counters(self, metrics):
metrics.increment("event.count", 10)
metrics.set_gauge("memory.size", 1024.0)
snapshot = metrics.snapshot()
assert isinstance(snapshot, MetricsSnapshot)
assert snapshot.counters["event.count"] == 10
assert snapshot.gauges["memory.size"] == 1024.0
assert snapshot.timestamp > 0
def test_reset_clears_all(self, metrics):
metrics.increment("counter1", 100)
metrics.set_gauge("gauge1", 50.0)
metrics.reset()
assert metrics.get_counter("counter1") == 0
assert metrics.get_gauge("gauge1") == 0.0
def test_record_event_received(self, metrics):
metrics.record_event_received(1)
metrics.record_event_received(4)
assert metrics.get_counter("event.received.total") == 2
assert metrics.get_counter("event.received.kind_1") == 1
assert metrics.get_counter("event.received.kind_4") == 1
def test_record_event_rejected(self, metrics):
metrics.record_event_rejected("duplicate")
metrics.record_event_rejected("rate_limit")
assert metrics.get_counter("event.rejected.total") == 2
assert metrics.get_counter("event.rejected.duplicate") == 1
def test_record_event_accepted(self, metrics):
metrics.record_event_accepted()
metrics.record_event_accepted()
assert metrics.get_counter("event.accepted.total") == 2
def test_record_relay_connect(self, metrics):
metrics.record_relay_connect("wss://relay.example.com")
assert metrics.get_counter("relay.connect.total") == 1
def test_record_relay_disconnect(self, metrics):
metrics.record_relay_disconnect("wss://relay.example.com")
assert metrics.get_counter("relay.disconnect.total") == 1
def test_record_relay_send_success(self, metrics):
metrics.record_relay_send_success("wss://relay.example.com")
assert metrics.get_counter("relay.send.success.total") == 1
def test_record_relay_send_failure(self, metrics):
metrics.record_relay_send_failure("wss://relay.example.com")
assert metrics.get_counter("relay.send.failure.total") == 1
def test_record_circuit_breaker_state(self, metrics):
metrics.record_circuit_breaker_state("wss://relay.example.com", "closed")
assert metrics.get_gauge("circuit_breaker.wss_relay_example_com.state") == 0
metrics.record_circuit_breaker_state("wss://relay.example.com", "open")
assert metrics.get_gauge("circuit_breaker.wss_relay_example_com.state") == 2
def test_record_rate_limit_hit_sender(self, metrics):
metrics.record_rate_limit_hit(sender_pubkey="abc123", global_hit=False)
assert metrics.get_counter("rate_limit.sender.hit") == 1
def test_record_rate_limit_hit_global(self, metrics):
metrics.record_rate_limit_hit(global_hit=True)
assert metrics.get_counter("rate_limit.global.hit") == 1
def test_record_decrypt_success_nip04(self, metrics):
metrics.record_decrypt_success("nip04")
assert metrics.get_counter("decrypt.nip04.success") == 1
def test_record_decrypt_success_nip17(self, metrics):
metrics.record_decrypt_success("nip17")
assert metrics.get_counter("decrypt.nip17.success") == 1
def test_record_decrypt_failure(self, metrics):
metrics.record_decrypt_failure("nip04")
assert metrics.get_counter("decrypt.nip04.failure") == 1
def test_record_seen_tracker_size(self, metrics):
metrics.record_seen_tracker_size(500)
assert metrics.get_gauge("memory.seen_tracker_size") == 500
def test_record_inflight_size(self, metrics):
metrics.record_inflight_size(10)
assert metrics.get_gauge("memory.inflight_size") == 10
def test_safe_label_replaces_special_chars(self):
result = NostrMetrics._safe_label("wss://relay.example.com/path/")
assert "://" not in result
assert "." not in result
assert "/" not in result
def test_snapshot_is_independent(self, metrics):
metrics.increment("counter_x", 5)
snap = metrics.snapshot()
metrics.increment("counter_x", 10)
assert snap.counters["counter_x"] == 5
assert metrics.get_counter("counter_x") == 15
def test_get_nonexistent_counter(self, metrics):
assert metrics.get_counter("nonexistent") == 0
def test_get_nonexistent_gauge(self, metrics):
assert metrics.get_gauge("nonexistent") == 0.0