145 lines
4.8 KiB
Python
145 lines
4.8 KiB
Python
from __future__ import annotations
|
|
|
|
import pytest
|
|
from yuxi.channel.metrics import (
|
|
Counter,
|
|
Gauge,
|
|
Histogram,
|
|
channel_active_connections,
|
|
channel_delivery_duration_seconds,
|
|
channel_messages_delivered_total,
|
|
channel_messages_failed_total,
|
|
channel_messages_received_total,
|
|
channel_rate_limited_total,
|
|
channel_reconnect_total,
|
|
dump,
|
|
)
|
|
|
|
|
|
class TestCounter:
|
|
def test_inc_without_labels(self):
|
|
counter = Counter("test_counter")
|
|
counter.inc()
|
|
assert counter.get() == 1
|
|
|
|
def test_inc_with_labels(self):
|
|
counter = Counter("test_counter")
|
|
counter.inc(labels={"channel": "feishu"})
|
|
counter.inc(labels={"channel": "feishu"})
|
|
assert counter.get(labels={"channel": "feishu"}) == 2
|
|
|
|
def test_inc_with_amount(self):
|
|
counter = Counter("test_counter")
|
|
counter.inc(amount=5)
|
|
assert counter.get() == 5
|
|
|
|
def test_inc_negative_raises(self):
|
|
counter = Counter("test_counter")
|
|
try:
|
|
counter.inc(amount=-1)
|
|
assert False, "expected ValueError"
|
|
except ValueError as exc:
|
|
assert "non-negative" in str(exc)
|
|
|
|
def test_different_labels_are_isolated(self):
|
|
counter = Counter("test_counter")
|
|
counter.inc(labels={"a": "1"})
|
|
counter.inc(labels={"b": "2"})
|
|
assert counter.get(labels={"a": "1"}) == 1
|
|
assert counter.get(labels={"b": "2"}) == 1
|
|
assert counter.get() == 0
|
|
|
|
|
|
class TestGauge:
|
|
def test_inc_and_dec(self):
|
|
gauge = Gauge("test_gauge")
|
|
gauge.inc()
|
|
gauge.inc()
|
|
gauge.dec()
|
|
assert gauge.get() == 1
|
|
|
|
def test_set(self):
|
|
gauge = Gauge("test_gauge")
|
|
gauge.set(value=42)
|
|
assert gauge.get() == 42
|
|
|
|
def test_with_labels(self):
|
|
gauge = Gauge("test_gauge")
|
|
gauge.inc(labels={"channel": "slack"}, amount=3)
|
|
gauge.dec(labels={"channel": "slack"})
|
|
assert gauge.get(labels={"channel": "slack"}) == 2
|
|
|
|
|
|
class TestHistogram:
|
|
def test_observe_count_and_sum(self):
|
|
hist = Histogram("test_hist")
|
|
hist.observe(value=0.05)
|
|
hist.observe(value=1.5)
|
|
result = hist.get()
|
|
assert result["count"] == 2
|
|
assert result["sum"] == pytest.approx(1.55)
|
|
|
|
def test_buckets(self):
|
|
hist = Histogram("test_hist", buckets=(0.1, 1.0, 10.0))
|
|
hist.observe(value=0.05)
|
|
hist.observe(value=0.5)
|
|
hist.observe(value=5.0)
|
|
hist.observe(value=20.0)
|
|
result = hist.get()
|
|
assert result["buckets"][0] == 1 # <= 0.1
|
|
assert result["buckets"][1] == 2 # <= 1.0
|
|
assert result["buckets"][2] == 3 # <= 10.0
|
|
assert result["buckets"][3] == 4 # > 10.0
|
|
|
|
def test_empty_get(self):
|
|
hist = Histogram("test_hist")
|
|
result = hist.get()
|
|
assert result["count"] == 0
|
|
assert result["sum"] == 0
|
|
assert all(v == 0 for v in result["buckets"].values())
|
|
|
|
def test_with_labels(self):
|
|
hist = Histogram("test_hist")
|
|
hist.observe(labels={"channel": "dingtalk"}, value=0.5)
|
|
result = hist.get(labels={"channel": "dingtalk"})
|
|
assert result["count"] == 1
|
|
|
|
|
|
class TestGlobalMetrics:
|
|
def test_global_counters_exist(self):
|
|
assert channel_messages_received_total.name == "channel_messages_received_total"
|
|
assert channel_messages_delivered_total.name == "channel_messages_delivered_total"
|
|
assert channel_messages_failed_total.name == "channel_messages_failed_total"
|
|
assert channel_reconnect_total.name == "channel_reconnect_total"
|
|
assert channel_rate_limited_total.name == "channel_rate_limited_total"
|
|
|
|
def test_global_gauge_exists(self):
|
|
assert channel_active_connections.name == "channel_active_connections"
|
|
|
|
def test_global_histogram_exists(self):
|
|
assert channel_delivery_duration_seconds.name == "channel_delivery_duration_seconds"
|
|
|
|
|
|
class TestDump:
|
|
def test_dump_structure(self):
|
|
channel_messages_received_total.inc(labels={"channel_type": "feishu"})
|
|
channel_active_connections.set(labels={"channel_type": "slack"}, value=2)
|
|
channel_delivery_duration_seconds.observe(value=0.1)
|
|
|
|
snapshot = dump()
|
|
assert "counters" in snapshot
|
|
assert "gauges" in snapshot
|
|
assert "histograms" in snapshot
|
|
|
|
assert "channel_messages_received_total" in snapshot["counters"]
|
|
assert "channel_active_connections" in snapshot["gauges"]
|
|
assert "channel_delivery_duration_seconds" in snapshot["histograms"]
|
|
|
|
def test_dump_label_formatting(self):
|
|
counter = Counter("fmt_counter")
|
|
counter.inc(labels={"a": "1", "b": "2"})
|
|
from yuxi.channel.metrics import _format_labels
|
|
|
|
key = tuple(sorted({"a": "1", "b": "2"}.items()))
|
|
assert _format_labels(key) == 'a="1",b="2"'
|