summaryrefslogtreecommitdiff
path: root/tests/integration/test_livesync.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/integration/test_livesync.py')
-rw-r--r--tests/integration/test_livesync.py108
1 files changed, 107 insertions, 1 deletions
diff --git a/tests/integration/test_livesync.py b/tests/integration/test_livesync.py
index 8dd754b..f4cb2db 100644
--- a/tests/integration/test_livesync.py
+++ b/tests/integration/test_livesync.py
@@ -10,7 +10,7 @@ import struct
10import subprocess 10import subprocess
11import unittest 11import unittest
12 12
13from harness import TRACKER, TrackerTestCase 13from harness import TRACKER, Tracker, TrackerTestCase
14 14
15# enum { OT_SYNC_PEER4, OT_SYNC_PEER6 } in src/ot_livesync.c 15# enum { OT_SYNC_PEER4, OT_SYNC_PEER6 } in src/ot_livesync.c
16SYNC_PEER4 = 0 16SYNC_PEER4 = 0
@@ -102,6 +102,17 @@ class LiveSyncIn(TrackerTestCase):
102 self.tracker.livesync_send(packet(99, [(info_hash, peer4("10.1.2.11", 6881, FLAG_SEEDING))])) 102 self.tracker.livesync_send(packet(99, [(info_hash, peer4("10.1.2.11", 6881, FLAG_SEEDING))]))
103 self.assertFalse(self.tracker.wait_until(lambda: self.counts(info_hash) is not None, timeout=1)) 103 self.assertFalse(self.tracker.wait_until(lambda: self.counts(info_hash) is not None, timeout=1))
104 104
105 def test_synced_peers_are_counted(self):
106 """The live sync worker keeps its own tally like every other worker,
107 and ?mode=syncs is the sum of them."""
108 before = int(self.tracker.stats("syncs").split()[0])
109 hashes = [self.hash_for("sync-count-%d" % i) for i in range(3)]
110 self.tracker.livesync_send(packet(SYNC_PEER4, [(h, peer4("10.1.2.%d" % (20 + i), 6881, FLAG_SEEDING))
111 for i, h in enumerate(hashes)]))
112 self.assertTrue(self.tracker.wait_until(
113 lambda: int(self.tracker.stats("syncs").split()[0]) == before + 3),
114 "syncs says %s" % self.tracker.stats("syncs").split()[0])
115
105 def test_a_packet_with_nothing_but_a_header_is_ignored(self): 116 def test_a_packet_with_nothing_but_a_header_is_ignored(self):
106 before = self.tracker.torrent_count() 117 before = self.tracker.torrent_count()
107 self.tracker.livesync_send(struct.pack("!I", 0xDEADBEEF) + struct.pack("!I", SYNC_PEER4)) 118 self.tracker.livesync_send(struct.pack("!I", 0xDEADBEEF) + struct.pack("!I", SYNC_PEER4))
@@ -119,3 +130,98 @@ class LiveSyncAccess(TrackerTestCase):
119 info_hash = self.hash_for("sync-unblessed") 130 info_hash = self.hash_for("sync-unblessed")
120 self.tracker.livesync_send(packet(SYNC_PEER4, [(info_hash, peer4("10.1.2.12", 6881, FLAG_SEEDING))])) 131 self.tracker.livesync_send(packet(SYNC_PEER4, [(info_hash, peer4("10.1.2.12", 6881, FLAG_SEEDING))]))
121 self.assertFalse(self.tracker.wait_until(lambda: self.tracker.torrent_count() != 0, timeout=1)) 132 self.assertFalse(self.tracker.wait_until(lambda: self.tracker.torrent_count() != 0, timeout=1))
133
134
135@unittest.skipUnless(has_livesync(), "this build has no WANT_SYNC_LIVE")
136class LiveSyncUnconfigured(TrackerTestCase):
137 """A binary that has the feature but no cluster to join. Somebody whose
138 packager turned WANT_SYNC_LIVE on did not ask for live sync and should
139 not be able to tell that it is there."""
140
141 config = ""
142
143 def test_the_tracker_runs_anyway(self):
144 info_hash = self.hash_for("no-cluster")
145 self.tracker.announce(info_hash, port=6881, left=0)
146 self.assertEqual(self.tracker.torrent_count(), 1)
147
148 def test_nothing_is_said_about_the_missing_cluster(self):
149 self.assertNotIn("sync", self.tracker.output().lower())
150
151 def test_no_socket_is_bound_for_it(self):
152 """A configured tracker holds the wildcard address on that port, so
153 taking it here proves nothing was started."""
154 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
155 try:
156 sock.bind(("0.0.0.0", self.tracker.livesync_port))
157 finally:
158 sock.close()
159
160 def test_announcing_stays_clean(self):
161 """Enough announces to pass the watermark that would flush an
162 outgoing buffer, if there were one to flush. The sanitizers in this
163 build turn anything the attempt touched into a failure."""
164 for i in range(200):
165 self.tracker.announce(self.hash_for("no-cluster-%d" % i), port=6881 + i, left=0)
166 self.assertEqual(self.tracker.torrent_count(), 200)
167
168
169# RFC 2365 sets 239.192.0.0/14 aside for exactly this kind of use
170OWN_GROUP = "239.192.0.7"
171# A group nothing in this suite ever joins. Deliberately not the default one:
172# other trackers here do join that, on ports the harness picks at random, and
173# a socket bound to the wildcard address shares a port's multicast traffic
174# with anything else on the host that has joined the group it is addressed
175# to. Two clusters sharing a host and a port is pathological in the field but
176# routine in a test suite.
177UNJOINED_GROUP = "239.192.0.99"
178
179
180@unittest.skipUnless(has_livesync(), "this build has no WANT_SYNC_LIVE")
181class LiveSyncGroup(TrackerTestCase):
182 config = ("livesync.cluster.group %s\n"
183 "livesync.cluster.listen 127.0.0.1:{livesync_port}\n"
184 "livesync.cluster.node_ip 127.0.0.1\n" % OWN_GROUP)
185
186 def test_the_configured_group_is_joined(self):
187 info_hash = self.hash_for("own-group")
188 self.tracker.livesync_send(packet(SYNC_PEER4, [(info_hash, peer4("10.1.3.1", 6881, FLAG_SEEDING))]),
189 group=OWN_GROUP)
190 self.assertTrue(self.tracker.wait_until(lambda: self.tracker.torrent_count() == 1))
191
192 def test_another_group_is_left_alone(self):
193 """A cluster that picked its own group hears nothing from the others."""
194 info_hash = self.hash_for("not-our-group")
195 self.tracker.livesync_send(packet(SYNC_PEER4, [(info_hash, peer4("10.1.3.2", 6881, FLAG_SEEDING))]),
196 group=UNJOINED_GROUP)
197 self.assertFalse(self.tracker.wait_until(lambda: self.tracker.torrent_count() != 0, timeout=1))
198
199
200@unittest.skipUnless(has_livesync(), "this build has no WANT_SYNC_LIVE")
201class LiveSyncGroupRefused(unittest.TestCase):
202 """A cluster that asked for a group of its own must not quietly end up on
203 the one every other opentracker is on, so a line that does not name a
204 group stops the tracker rather than falling back."""
205
206 def start_with(self, group):
207 return Tracker("livesync.cluster.group %s\n"
208 "livesync.cluster.listen 127.0.0.1:{livesync_port}\n"
209 "livesync.cluster.node_ip 127.0.0.1\n" % group)
210
211 def test_a_unicast_address_stops_the_tracker(self):
212 with self.assertRaises(AssertionError) as caught:
213 self.start_with("10.0.0.1")
214 self.assertIn("multicast address", str(caught.exception))
215
216 def test_so_does_something_that_is_not_an_address(self):
217 with self.assertRaises(AssertionError) as caught:
218 self.start_with("not-an-address")
219 self.assertIn("multicast address", str(caught.exception))
220
221 def test_a_group_at_either_end_of_the_range_is_taken(self):
222 for group in ("224.0.0.1", "239.255.255.255"):
223 tracker = self.start_with(group)
224 try:
225 self.assertEqual(tracker.torrent_count(), 0)
226 finally:
227 tracker.stop()