A Python port of the Invisible Internet Project (I2P)
at main 228 lines 8.4 kB view raw
1"""Tests for peer profile organizer.""" 2 3import os 4 5import pytest 6 7 8def _make_profile(capacity: float = 0.0, speed: float = 0.0, 9 integration: float = 0.0, is_banned: bool = False, 10 tunnel_builds: int = 0, sends: int = 0): 11 """Helper to create a profile with preset scores.""" 12 from i2p_peer.profile import PeerProfile 13 14 p = PeerProfile(os.urandom(32)) 15 p.capacity = capacity 16 p.speed = speed 17 p.integration = integration 18 p.is_banned = is_banned 19 # Fake some history for is_established checks 20 p.tunnel_builds_succeeded = tunnel_builds 21 p.send_success_count = sends 22 return p 23 24 25class TestProfileOrganizer: 26 def test_classify_fast(self): 27 from i2p_peer.organizer import PeerTier, ProfileOrganizer 28 29 org = ProfileOrganizer() 30 p = _make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10) 31 org.add_profile(p) 32 assert org.get_tier(p.router_hash) == PeerTier.FAST 33 34 def test_classify_high_capacity(self): 35 from i2p_peer.organizer import PeerTier, ProfileOrganizer 36 37 org = ProfileOrganizer() 38 p = _make_profile(capacity=0.7, speed=0.3, tunnel_builds=15, sends=10) 39 org.add_profile(p) 40 assert org.get_tier(p.router_hash) == PeerTier.HIGH_CAPACITY 41 42 def test_classify_standard(self): 43 from i2p_peer.organizer import PeerTier, ProfileOrganizer 44 45 org = ProfileOrganizer() 46 p = _make_profile(capacity=0.4, speed=0.3, tunnel_builds=5, sends=5) 47 org.add_profile(p) 48 assert org.get_tier(p.router_hash) == PeerTier.STANDARD 49 50 def test_classify_failing(self): 51 from i2p_peer.organizer import PeerTier, ProfileOrganizer 52 53 org = ProfileOrganizer() 54 p = _make_profile(capacity=0.1, speed=0.1) 55 org.add_profile(p) 56 assert org.get_tier(p.router_hash) == PeerTier.FAILING 57 58 def test_classify_banned(self): 59 from i2p_peer.organizer import PeerTier, ProfileOrganizer 60 61 org = ProfileOrganizer() 62 p = _make_profile(capacity=0.9, speed=0.9, is_banned=True) 63 p.ban(3600.0) # ban for an hour 64 org.add_profile(p) 65 assert org.get_tier(p.router_hash) == PeerTier.BANNED 66 67 def test_select_fast_peers(self): 68 from i2p_peer.organizer import PeerTier, ProfileOrganizer 69 70 org = ProfileOrganizer() 71 fast_hashes = set() 72 for _ in range(3): 73 p = _make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10) 74 org.add_profile(p) 75 fast_hashes.add(p.router_hash) 76 # Add some non-fast peers 77 for _ in range(3): 78 p = _make_profile(capacity=0.2, speed=0.1) 79 org.add_profile(p) 80 81 result = org.select_fast_peers(count=5) 82 assert len(result) == 3 83 for h in result: 84 assert h in fast_hashes 85 86 def test_select_with_exclude(self): 87 from i2p_peer.organizer import ProfileOrganizer 88 89 org = ProfileOrganizer() 90 profiles = [] 91 for _ in range(5): 92 p = _make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10) 93 org.add_profile(p) 94 profiles.append(p) 95 96 exclude = {profiles[0].router_hash, profiles[1].router_hash} 97 result = org.select_fast_peers(count=10, exclude=exclude) 98 assert len(result) == 3 99 for h in result: 100 assert h not in exclude 101 102 def test_select_peers_min_tier(self): 103 from i2p_peer.organizer import PeerTier, ProfileOrganizer 104 105 org = ProfileOrganizer() 106 # Add peers at different tiers 107 fast = _make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10) 108 org.add_profile(fast) 109 hicap = _make_profile(capacity=0.7, speed=0.3, tunnel_builds=15, sends=10) 110 org.add_profile(hicap) 111 standard = _make_profile(capacity=0.4, speed=0.3, tunnel_builds=5, sends=5) 112 org.add_profile(standard) 113 failing = _make_profile(capacity=0.1, speed=0.1) 114 org.add_profile(failing) 115 116 # Select with min_tier=HIGH_CAPACITY should get fast + hicap 117 result = org.select_peers(count=10, min_tier=PeerTier.HIGH_CAPACITY) 118 assert len(result) == 2 119 assert fast.router_hash in result 120 assert hicap.router_hash in result 121 122 def test_select_peers_min_tier_standard(self): 123 from i2p_peer.organizer import PeerTier, ProfileOrganizer 124 125 org = ProfileOrganizer() 126 fast = _make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10) 127 org.add_profile(fast) 128 standard = _make_profile(capacity=0.4, speed=0.3, tunnel_builds=5, sends=5) 129 org.add_profile(standard) 130 failing = _make_profile(capacity=0.1, speed=0.1) 131 org.add_profile(failing) 132 133 result = org.select_peers(count=10, min_tier=PeerTier.STANDARD) 134 assert len(result) == 2 135 assert failing.router_hash not in result 136 137 def test_reclassify_on_update(self): 138 from i2p_peer.organizer import PeerTier, ProfileOrganizer 139 140 org = ProfileOrganizer() 141 p = _make_profile(capacity=0.1, speed=0.1) 142 org.add_profile(p) 143 assert org.get_tier(p.router_hash) == PeerTier.FAILING 144 145 # Update the profile scores 146 p.capacity = 0.9 147 p.speed = 0.8 148 p.tunnel_builds_succeeded = 15 149 p.send_success_count = 10 150 org.add_profile(p) # Re-add triggers reclassification 151 assert org.get_tier(p.router_hash) == PeerTier.FAST 152 153 def test_add_remove_profile(self): 154 from i2p_peer.organizer import ProfileOrganizer 155 156 org = ProfileOrganizer() 157 p = _make_profile(capacity=0.5, speed=0.5, tunnel_builds=5, sends=5) 158 org.add_profile(p) 159 assert org.total_count == 1 160 assert org.get_profile(p.router_hash) is not None 161 162 org.remove_profile(p.router_hash) 163 assert org.total_count == 0 164 assert org.get_profile(p.router_hash) is None 165 166 def test_tier_counts(self): 167 from i2p_peer.organizer import ProfileOrganizer 168 169 org = ProfileOrganizer() 170 org.add_profile(_make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10)) 171 org.add_profile(_make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10)) 172 org.add_profile(_make_profile(capacity=0.7, speed=0.3, tunnel_builds=15, sends=10)) 173 org.add_profile(_make_profile(capacity=0.4, speed=0.3, tunnel_builds=5, sends=5)) 174 org.add_profile(_make_profile(capacity=0.1, speed=0.1)) 175 176 assert org.fast_count == 2 177 assert org.high_capacity_count == 1 178 assert org.standard_count == 1 179 assert org.failing_count == 1 180 assert org.total_count == 5 181 182 def test_reclassify_all(self): 183 from i2p_peer.organizer import PeerTier, ProfileOrganizer 184 185 org = ProfileOrganizer() 186 p = _make_profile(capacity=0.1, speed=0.1) 187 org.add_profile(p) 188 assert org.get_tier(p.router_hash) == PeerTier.FAILING 189 190 # Mutate directly without re-adding 191 p.capacity = 0.9 192 p.speed = 0.8 193 p.tunnel_builds_succeeded = 15 194 p.send_success_count = 10 195 org.reclassify_all() 196 assert org.get_tier(p.router_hash) == PeerTier.FAST 197 198 def test_select_high_capacity_peers(self): 199 from i2p_peer.organizer import ProfileOrganizer 200 201 org = ProfileOrganizer() 202 hicap_hashes = set() 203 for _ in range(3): 204 p = _make_profile(capacity=0.7, speed=0.3, tunnel_builds=15, sends=10) 205 org.add_profile(p) 206 hicap_hashes.add(p.router_hash) 207 # Add a fast peer (should not be returned by select_high_capacity) 208 fast = _make_profile(capacity=0.9, speed=0.8, tunnel_builds=15, sends=10) 209 org.add_profile(fast) 210 211 result = org.select_high_capacity_peers(count=10) 212 assert len(result) == 3 213 for h in result: 214 assert h in hicap_hashes 215 216 def test_remove_nonexistent(self): 217 from i2p_peer.organizer import ProfileOrganizer 218 219 org = ProfileOrganizer() 220 # Should not raise 221 org.remove_profile(os.urandom(32)) 222 223 def test_get_tier_unknown(self): 224 from i2p_peer.organizer import PeerTier, ProfileOrganizer 225 226 org = ProfileOrganizer() 227 # Unknown peer defaults to FAILING 228 assert org.get_tier(os.urandom(32)) == PeerTier.FAILING