"""Tests for packet scheduler and congestion control.""" import pytest class TestRetransmitTimer: def test_initial_rto(self): from i2p_streaming.scheduler import RetransmitTimer timer = RetransmitTimer() assert timer.rto == 3000 # Initial RTO: 3 seconds def test_update_rtt(self): from i2p_streaming.scheduler import RetransmitTimer timer = RetransmitTimer() timer.update_rtt(100) # 100ms RTT assert timer.rto > 0 assert timer.rto < 3000 # Should be less than initial def test_backoff(self): from i2p_streaming.scheduler import RetransmitTimer timer = RetransmitTimer() rto1 = timer.rto timer.backoff() assert timer.rto == rto1 * 2 def test_max_backoff(self): from i2p_streaming.scheduler import RetransmitTimer timer = RetransmitTimer() for _ in range(20): timer.backoff() assert timer.rto <= 60000 # Max 60 seconds def test_update_rtt_smoothing(self): from i2p_streaming.scheduler import RetransmitTimer timer = RetransmitTimer() timer.update_rtt(100) rto1 = timer.rto timer.update_rtt(200) rto2 = timer.rto # RTO should change but be smoothed assert rto2 != rto1 class TestCongestionWindow: def test_initial_window(self): from i2p_streaming.scheduler import CongestionWindow cw = CongestionWindow(initial_size=6) assert cw.size == 6 def test_slow_start_increase(self): from i2p_streaming.scheduler import CongestionWindow cw = CongestionWindow(initial_size=1, ssthresh=16) cw.on_ack() assert cw.size == 2 # Doubles in slow start def test_congestion_avoidance(self): from i2p_streaming.scheduler import CongestionWindow cw = CongestionWindow(initial_size=16, ssthresh=16) cw.on_ack() # In congestion avoidance, increase is additive (~1/size per ACK) assert cw.size > 16 assert cw.size <= 17 def test_on_loss(self): from i2p_streaming.scheduler import CongestionWindow cw = CongestionWindow(initial_size=20, ssthresh=32) cw.on_loss() # AIMD: halve the window assert cw.size == 10 assert cw.ssthresh == 10 def test_minimum_window(self): from i2p_streaming.scheduler import CongestionWindow cw = CongestionWindow(initial_size=1, ssthresh=16) cw.on_loss() assert cw.size >= 1 # Never go below 1 def test_max_window(self): from i2p_streaming.scheduler import CongestionWindow cw = CongestionWindow(initial_size=1, ssthresh=16, max_size=128) for _ in range(200): cw.on_ack() assert cw.size <= 128 class TestPacketScheduler: def test_can_send_within_window(self): from i2p_streaming.scheduler import PacketScheduler sched = PacketScheduler(window_size=10) assert sched.can_send() def test_cannot_send_window_full(self): from i2p_streaming.scheduler import PacketScheduler sched = PacketScheduler(window_size=2) sched.on_packet_sent(seq=0) sched.on_packet_sent(seq=1) assert not sched.can_send() def test_ack_frees_window(self): from i2p_streaming.scheduler import PacketScheduler sched = PacketScheduler(window_size=1) sched.on_packet_sent(seq=0) assert not sched.can_send() sched.on_ack(seq=0) assert sched.can_send() def test_outstanding_count(self): from i2p_streaming.scheduler import PacketScheduler sched = PacketScheduler(window_size=10) sched.on_packet_sent(seq=0) sched.on_packet_sent(seq=1) assert sched.outstanding == 2 sched.on_ack(seq=0) assert sched.outstanding == 1