summaryrefslogtreecommitdiff
path: root/tests/integration
diff options
context:
space:
mode:
Diffstat (limited to 'tests/integration')
-rw-r--r--tests/integration/harness.py26
-rw-r--r--tests/integration/test_expiry.py39
2 files changed, 59 insertions, 6 deletions
diff --git a/tests/integration/harness.py b/tests/integration/harness.py
index 122c36d..b98ce83 100644
--- a/tests/integration/harness.py
+++ b/tests/integration/harness.py
@@ -49,12 +49,26 @@ def bdecode(data):
49 return value(0)[1] 49 return value(0)[1]
50 50
51 51
52def free_port(): 52def free_port(attempts=50):
53 probe = socket.socket() 53 """A port free for both protocols, because the tracker binds both.
54 probe.bind(("127.0.0.1", 0)) 54
55 port = probe.getsockname()[1] 55 Asking the kernel for a free tcp port says nothing about the udp port of
56 probe.close() 56 the same number, and anything on the machine holding that one makes the
57 return port 57 tracker exit at once with "Address already in use".
58 """
59 for _ in range(attempts):
60 tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
61 udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
62 try:
63 tcp.bind(("127.0.0.1", 0))
64 udp.bind(("127.0.0.1", tcp.getsockname()[1]))
65 return tcp.getsockname()[1]
66 except OSError:
67 continue
68 finally:
69 tcp.close()
70 udp.close()
71 raise AssertionError("no port free for both tcp and udp after %d tries" % attempts)
58 72
59 73
60class Tracker: 74class Tracker:
diff --git a/tests/integration/test_expiry.py b/tests/integration/test_expiry.py
new file mode 100644
index 0000000..5a21e57
--- /dev/null
+++ b/tests/integration/test_expiry.py
@@ -0,0 +1,39 @@
1"""What the expiry sweep finds, and what it must not find.
2
3A plain request is answered and the connection closed by http_close, not by
4the sweep. If that path left the descriptor's slot behind, the sweep would
5walk into it once the client timeout had passed and free a cookie that is
6already gone; the sanitizer build reports that and teardown turns it into a
7failure.
8
9Both halves share one tracker and one wait, because the wait is the whole
10cost of the test.
11
12The two numbers below mirror OT_CLIENT_TIMEOUT and
13OT_CLIENT_TIMEOUT_CHECKINTERVAL in FEATURES_integration.
14"""
15
16import socket
17import time
18import unittest
19
20from harness import TrackerTestCase
21
22CLIENT_TIMEOUT = 5
23CHECK_INTERVAL = 1
24
25
26class ExpirySweep(TrackerTestCase):
27 def test_the_sweep_takes_the_idle_and_leaves_the_answered(self):
28 idle = socket.create_connection(("127.0.0.1", self.tracker.port), timeout=5)
29 try:
30 self.assertEqual(self.tracker.announce(self.hash_for("expiry-sweep"))[b"complete"], 1)
31
32 time.sleep(CLIENT_TIMEOUT + 3 * CHECK_INTERVAL)
33
34 self.assertEqual(self.tracker.torrent_count(), 1, "the tracker stopped serving while sweeping")
35
36 idle.settimeout(5)
37 self.assertEqual(idle.recv(64), b"", "a connection that never sent a request was not swept")
38 finally:
39 idle.close()