sevzero / tests /test_propagation.py
Mist-ic's picture
Add tests and fix premature termination bug
5f8bd3c
"""Tests for queueing theory and propagation."""
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from server.propagation import (
compute_utilisation,
compute_queueing_latency_multiplier,
compute_retry_amplification,
CircuitBreaker,
BreakerState,
)
import random
class TestQueueingTheory:
"""Little's Law and M/M/c approximations."""
def test_utilisation_basic(self):
# L = 100 * 0.05 = 5, T = 50, ρ = 0.1
rho = compute_utilisation(100.0, 0.05, 50)
assert abs(rho - 0.1) < 0.001
def test_utilisation_saturated(self):
# L = 1000 * 0.1 = 100, T = 50, ρ = 2.0 → capped at 1.0
rho = compute_utilisation(1000.0, 0.1, 50)
assert rho == 1.0
def test_utilisation_zero_traffic(self):
rho = compute_utilisation(0.0, 0.05, 50)
assert rho == 0.0
def test_latency_multiplier_low_utilisation(self):
mult = compute_queueing_latency_multiplier(0.1)
assert 1.0 < mult < 2.0 # ~1.11x
def test_latency_multiplier_high_utilisation(self):
mult = compute_queueing_latency_multiplier(0.95)
assert mult >= 10.0
def test_latency_multiplier_saturated(self):
mult = compute_queueing_latency_multiplier(0.99)
assert mult >= 20.0
def test_retry_amplification_no_failures(self):
amp = compute_retry_amplification(0.0, 3)
assert amp == 1.0
def test_retry_amplification_total_failure(self):
amp = compute_retry_amplification(1.0, 3)
assert amp == 4.0 # 1 + 3 retries
def test_retry_amplification_partial(self):
amp = compute_retry_amplification(0.5, 3)
assert 1.0 < amp < 4.0
class TestCircuitBreaker:
"""Circuit breaker state transitions."""
def test_starts_closed(self):
cb = CircuitBreaker()
assert cb.state == BreakerState.CLOSED
def test_trips_open_on_high_errors(self):
cb = CircuitBreaker(error_threshold=0.5, window_size=3)
rng = random.Random(42)
for _ in range(5):
cb.tick(0.8, rng)
assert cb.state == BreakerState.OPEN
def test_transitions_to_half_open(self):
cb = CircuitBreaker(error_threshold=0.5, cooldown_ticks=5, window_size=2)
rng = random.Random(42)
# Trip open
for _ in range(3):
cb.tick(0.9, rng)
assert cb.state == BreakerState.OPEN
# Wait for cooldown
for _ in range(6):
cb.tick(0.0, rng)
assert cb.state in (BreakerState.HALF_OPEN, BreakerState.CLOSED)
def test_dampening_factor(self):
cb = CircuitBreaker()
assert cb.dampening_factor == 1.0 # CLOSED
cb.state = BreakerState.OPEN
assert cb.dampening_factor == 0.05
cb.state = BreakerState.HALF_OPEN
assert cb.dampening_factor == 0.3