"""Tests for extended PeerProfile with full profiling metrics.""" import os import time import pytest class TestPeerProfileExtended: """Tests for the extended PeerProfile fields and methods.""" def test_initial_state(self): from i2p_peer.profile import PeerProfile h = os.urandom(32) p = PeerProfile(router_hash=h) assert p.router_hash == h assert p.tunnel_builds_succeeded == 0 assert p.tunnel_builds_failed == 0 assert p.tunnel_builds_rejected == 0 assert p.send_success_count == 0 assert p.send_failure_count == 0 assert p.db_store_success_count == 0 assert p.db_store_failure_count == 0 assert p.db_lookup_success_count == 0 assert p.db_lookup_failure_count == 0 assert p.last_heard_from == 0.0 assert p.first_heard_about == 0.0 assert p.last_send_success == 0.0 assert p.last_send_failure == 0.0 assert p.capacity == 0.0 assert p.speed == 0.0 assert p.integration == 0.0 assert p.is_expanding is False assert p.is_active is True assert p.is_banned is False assert p.ban_expiry == 0.0 def test_tunnel_build_success_rate(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) for _ in range(7): p.record_tunnel_build_success() for _ in range(3): p.record_tunnel_build_failure() assert p.tunnel_builds_succeeded == 7 assert p.tunnel_builds_failed == 3 assert abs(p.tunnel_success_rate - 0.7) < 0.001 def test_tunnel_success_rate_no_builds(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) assert p.tunnel_success_rate == 0.0 def test_tunnel_build_rejection(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) p.record_tunnel_build_rejection() p.record_tunnel_build_rejection() assert p.tunnel_builds_rejected == 2 def test_send_success_rate(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) for _ in range(8): p.record_send_success() for _ in range(2): p.record_send_failure() assert p.send_success_count == 8 assert p.send_failure_count == 2 assert abs(p.send_success_rate - 0.8) < 0.001 def test_send_success_rate_no_sends(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) assert p.send_success_rate == 0.0 def test_db_success_rate(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) for _ in range(5): p.record_db_store_success() for _ in range(3): p.record_db_lookup_success() for _ in range(2): p.record_db_store_failure() # 8 success out of 10 total assert abs(p.db_success_rate - 0.8) < 0.001 def test_db_success_rate_no_ops(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) assert p.db_success_rate == 0.0 def test_latency_recording(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) p.record_latency(100.0) p.record_latency(200.0) p.record_latency(300.0) assert abs(p.average_latency - 200.0) < 0.001 def test_latency_no_samples(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) assert p.average_latency == 0.0 def test_latency_max_samples(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) # Fill with 50 samples of 100ms for _ in range(50): p.record_latency(100.0) # Add 10 more of 200ms (should evict oldest) for _ in range(10): p.record_latency(200.0) # Should have 50 samples: 40 * 100 + 10 * 200 = 6000 / 50 = 120 assert abs(p.average_latency - 120.0) < 0.001 def test_ban_and_unban(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) assert not p.is_currently_banned p.ban(60.0) # 60 seconds assert p.is_banned is True assert p.ban_expiry > time.time() assert p.is_currently_banned p.unban() assert p.is_banned is False assert not p.is_currently_banned def test_ban_expiry(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) # Ban for 0 seconds (immediately expired) p.ban(0.0) assert not p.is_currently_banned def test_heard_from_updates_timestamp(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) assert p.last_heard_from == 0.0 before = time.time() p.heard_from() after = time.time() assert before <= p.last_heard_from <= after def test_first_heard_about_set_once(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) p.heard_from() first = p.first_heard_about assert first > 0.0 time.sleep(0.01) p.heard_from() # first_heard_about should not change assert p.first_heard_about == first def test_to_dict_from_dict_roundtrip(self): from i2p_peer.profile import PeerProfile h = os.urandom(32) p = PeerProfile(h) for _ in range(5): p.record_tunnel_build_success() for _ in range(2): p.record_tunnel_build_failure() p.record_tunnel_build_rejection() for _ in range(3): p.record_send_success() p.record_send_failure() p.record_db_store_success() p.record_db_lookup_failure() p.record_latency(150.0) p.record_latency(250.0) p.heard_from() p.capacity = 0.75 p.speed = 0.6 p.integration = 0.5 p.is_expanding = True d = p.to_dict() p2 = PeerProfile.from_dict(d) assert p2.router_hash == h assert p2.tunnel_builds_succeeded == 5 assert p2.tunnel_builds_failed == 2 assert p2.tunnel_builds_rejected == 1 assert p2.send_success_count == 3 assert p2.send_failure_count == 1 assert p2.db_store_success_count == 1 assert p2.db_lookup_failure_count == 1 assert abs(p2.capacity - 0.75) < 0.001 assert abs(p2.speed - 0.6) < 0.001 assert abs(p2.integration - 0.5) < 0.001 assert p2.is_expanding is True assert len(p2._latency_samples) == 2 assert p2.last_heard_from == p.last_heard_from def test_is_established(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) # Not established with no history assert not p.is_established # Need at least some tunnel builds and sends for _ in range(5): p.record_tunnel_build_success() for _ in range(5): p.record_send_success() assert p.is_established def test_record_db_lookup_success(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) p.record_db_lookup_success() assert p.db_lookup_success_count == 1 def test_record_db_lookup_failure(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) p.record_db_lookup_failure() assert p.db_lookup_failure_count == 1 def test_send_timestamps_updated(self): from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) before = time.time() p.record_send_success() assert p.last_send_success >= before p.record_send_failure() assert p.last_send_failure >= before