"""Tests for peer profile organizer.""" import os import pytest def _make_profile(capacity: float = 0.0, speed: float = 0.0, integration: float = 0.0, is_banned: bool = False, tunnel_builds: int = 0, sends: int = 0): """Helper to create a profile with preset scores.""" from i2p_peer.profile import PeerProfile p = PeerProfile(os.urandom(32)) p.capacity = capacity p.speed = speed p.integration = integration p.is_banned = is_banned # Fake some history for is_established checks p.tunnel_builds_succeeded = tunnel_builds p.send_success_count = sends return p class TestProfileOrganizer: def test_classify_fast(self): from i2p_peer.organizer import PeerTier, ProfileOrganizer org = ProfileOrganizer() p = _make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10) org.add_profile(p) assert org.get_tier(p.router_hash) == PeerTier.FAST def test_classify_high_capacity(self): from i2p_peer.organizer import PeerTier, ProfileOrganizer org = ProfileOrganizer() p = _make_profile(capacity=0.7, speed=0.3, tunnel_builds=15, sends=10) org.add_profile(p) assert org.get_tier(p.router_hash) == PeerTier.HIGH_CAPACITY def test_classify_standard(self): from i2p_peer.organizer import PeerTier, ProfileOrganizer org = ProfileOrganizer() p = _make_profile(capacity=0.4, speed=0.3, tunnel_builds=5, sends=5) org.add_profile(p) assert org.get_tier(p.router_hash) == PeerTier.STANDARD def test_classify_failing(self): from i2p_peer.organizer import PeerTier, ProfileOrganizer org = ProfileOrganizer() p = _make_profile(capacity=0.1, speed=0.1) org.add_profile(p) assert org.get_tier(p.router_hash) == PeerTier.FAILING def test_classify_banned(self): from i2p_peer.organizer import PeerTier, ProfileOrganizer org = ProfileOrganizer() p = _make_profile(capacity=0.9, speed=0.9, is_banned=True) p.ban(3600.0) # ban for an hour org.add_profile(p) assert org.get_tier(p.router_hash) == PeerTier.BANNED def test_select_fast_peers(self): from i2p_peer.organizer import PeerTier, ProfileOrganizer org = ProfileOrganizer() fast_hashes = set() for _ in range(3): p = _make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10) org.add_profile(p) fast_hashes.add(p.router_hash) # Add some non-fast peers for _ in range(3): p = _make_profile(capacity=0.2, speed=0.1) org.add_profile(p) result = org.select_fast_peers(count=5) assert len(result) == 3 for h in result: assert h in fast_hashes def test_select_with_exclude(self): from i2p_peer.organizer import ProfileOrganizer org = ProfileOrganizer() profiles = [] for _ in range(5): p = _make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10) org.add_profile(p) profiles.append(p) exclude = {profiles[0].router_hash, profiles[1].router_hash} result = org.select_fast_peers(count=10, exclude=exclude) assert len(result) == 3 for h in result: assert h not in exclude def test_select_peers_min_tier(self): from i2p_peer.organizer import PeerTier, ProfileOrganizer org = ProfileOrganizer() # Add peers at different tiers fast = _make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10) org.add_profile(fast) hicap = _make_profile(capacity=0.7, speed=0.3, tunnel_builds=15, sends=10) org.add_profile(hicap) standard = _make_profile(capacity=0.4, speed=0.3, tunnel_builds=5, sends=5) org.add_profile(standard) failing = _make_profile(capacity=0.1, speed=0.1) org.add_profile(failing) # Select with min_tier=HIGH_CAPACITY should get fast + hicap result = org.select_peers(count=10, min_tier=PeerTier.HIGH_CAPACITY) assert len(result) == 2 assert fast.router_hash in result assert hicap.router_hash in result def test_select_peers_min_tier_standard(self): from i2p_peer.organizer import PeerTier, ProfileOrganizer org = ProfileOrganizer() fast = _make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10) org.add_profile(fast) standard = _make_profile(capacity=0.4, speed=0.3, tunnel_builds=5, sends=5) org.add_profile(standard) failing = _make_profile(capacity=0.1, speed=0.1) org.add_profile(failing) result = org.select_peers(count=10, min_tier=PeerTier.STANDARD) assert len(result) == 2 assert failing.router_hash not in result def test_reclassify_on_update(self): from i2p_peer.organizer import PeerTier, ProfileOrganizer org = ProfileOrganizer() p = _make_profile(capacity=0.1, speed=0.1) org.add_profile(p) assert org.get_tier(p.router_hash) == PeerTier.FAILING # Update the profile scores p.capacity = 0.9 p.speed = 0.8 p.tunnel_builds_succeeded = 15 p.send_success_count = 10 org.add_profile(p) # Re-add triggers reclassification assert org.get_tier(p.router_hash) == PeerTier.FAST def test_add_remove_profile(self): from i2p_peer.organizer import ProfileOrganizer org = ProfileOrganizer() p = _make_profile(capacity=0.5, speed=0.5, tunnel_builds=5, sends=5) org.add_profile(p) assert org.total_count == 1 assert org.get_profile(p.router_hash) is not None org.remove_profile(p.router_hash) assert org.total_count == 0 assert org.get_profile(p.router_hash) is None def test_tier_counts(self): from i2p_peer.organizer import ProfileOrganizer org = ProfileOrganizer() org.add_profile(_make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10)) org.add_profile(_make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10)) org.add_profile(_make_profile(capacity=0.7, speed=0.3, tunnel_builds=15, sends=10)) org.add_profile(_make_profile(capacity=0.4, speed=0.3, tunnel_builds=5, sends=5)) org.add_profile(_make_profile(capacity=0.1, speed=0.1)) assert org.fast_count == 2 assert org.high_capacity_count == 1 assert org.standard_count == 1 assert org.failing_count == 1 assert org.total_count == 5 def test_reclassify_all(self): from i2p_peer.organizer import PeerTier, ProfileOrganizer org = ProfileOrganizer() p = _make_profile(capacity=0.1, speed=0.1) org.add_profile(p) assert org.get_tier(p.router_hash) == PeerTier.FAILING # Mutate directly without re-adding p.capacity = 0.9 p.speed = 0.8 p.tunnel_builds_succeeded = 15 p.send_success_count = 10 org.reclassify_all() assert org.get_tier(p.router_hash) == PeerTier.FAST def test_select_high_capacity_peers(self): from i2p_peer.organizer import ProfileOrganizer org = ProfileOrganizer() hicap_hashes = set() for _ in range(3): p = _make_profile(capacity=0.7, speed=0.3, tunnel_builds=15, sends=10) org.add_profile(p) hicap_hashes.add(p.router_hash) # Add a fast peer (should not be returned by select_high_capacity) fast = _make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10) org.add_profile(fast) result = org.select_high_capacity_peers(count=10) assert len(result) == 3 for h in result: assert h in hicap_hashes def test_remove_nonexistent(self): from i2p_peer.organizer import ProfileOrganizer org = ProfileOrganizer() # Should not raise org.remove_profile(os.urandom(32)) def test_get_tier_unknown(self): from i2p_peer.organizer import PeerTier, ProfileOrganizer org = ProfileOrganizer() # Unknown peer defaults to FAILING assert org.get_tier(os.urandom(32)) == PeerTier.FAILING