from itertools import count import fakeredis import pytest from app.dsp.stats import InMemoryStatsBackend, RedisStatsBackend class TestInMemoryStatsBackend: @pytest.fixture def backend(self) -> InMemoryStatsBackend: return InMemoryStatsBackend() def test_initial_snapshot_is_zero(self, backend: InMemoryStatsBackend) -> None: stats = backend.snapshot() assert stats.requests == 0 assert stats.retries == 0 assert stats.rate_limited == 0 assert stats.rps is None def test_incr_requests(self, backend: InMemoryStatsBackend) -> None: backend.incr_requests() backend.incr_requests() assert backend.snapshot().requests == 2 def test_incr_retries(self, backend: InMemoryStatsBackend) -> None: backend.incr_retries() backend.incr_retries() backend.incr_retries() assert backend.snapshot().retries == 3 def test_incr_rate_limited(self, backend: InMemoryStatsBackend) -> None: backend.incr_rate_limited() assert backend.snapshot().rate_limited == 1 def test_total_attempts(self, backend: InMemoryStatsBackend) -> None: backend.incr_requests() backend.incr_requests() backend.incr_retries() assert backend.snapshot().total_attempts == 3 def test_rps_is_none_for_single_request( self, backend: InMemoryStatsBackend ) -> None: backend.incr_requests() assert backend.snapshot().rps is None def test_rps_is_set_after_multiple_requests( self, backend: InMemoryStatsBackend, mocker ) -> None: tick = count(0) mocker.patch( "app.dsp.stats.time.monotonic", side_effect=lambda: next(tick) * 0.1 ) for _ in range(5): backend.incr_requests() stats = backend.snapshot() assert stats.rps is not None assert stats.rps > 0 class TestRedisStatsBackend: @pytest.fixture def backend(self) -> RedisStatsBackend: return RedisStatsBackend(fakeredis.FakeRedis(), key_prefix="test") def test_initial_snapshot_is_zero(self, backend: RedisStatsBackend) -> None: stats = backend.snapshot() assert stats.requests == 0 assert stats.retries == 0 assert stats.rate_limited == 0 assert stats.rps is None def test_incr_requests(self, backend: RedisStatsBackend) -> None: backend.incr_requests() backend.incr_requests() assert backend.snapshot().requests == 2 def test_incr_retries(self, backend: RedisStatsBackend) -> None: backend.incr_retries() backend.incr_retries() backend.incr_retries() assert backend.snapshot().retries == 3 def test_incr_rate_limited(self, backend: RedisStatsBackend) -> None: backend.incr_rate_limited() assert backend.snapshot().rate_limited == 1 def test_total_attempts(self, backend: RedisStatsBackend) -> None: backend.incr_requests() backend.incr_requests() backend.incr_retries() assert backend.snapshot().total_attempts == 3 def test_rps_is_none_for_single_request(self, backend: RedisStatsBackend) -> None: backend.incr_requests() assert backend.snapshot().rps is None def test_rps_is_set_after_multiple_requests( self, backend: RedisStatsBackend, mocker ) -> None: tick = count(0) mocker.patch("app.dsp.stats.time.time", side_effect=lambda: next(tick) * 0.1) for _ in range(5): backend.incr_requests() stats = backend.snapshot() assert stats.rps is not None assert stats.rps > 0