summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--tests/integration/harness.py38
2 files changed, 43 insertions, 5 deletions
diff --git a/Makefile b/Makefile
index b172af6..ad2ca4e 100644
--- a/Makefile
+++ b/Makefile
@@ -152,7 +152,7 @@ check-sanitize: $(TESTBIN).sanitize
152# cannot reach. Built with the sanitizers on, so the tracker reports its own 152# cannot reach. Built with the sanitizers on, so the tracker reports its own
153# memory errors and the harness turns those into failures. 153# memory errors and the harness turns those into failures.
154PYTHON?=python3 154PYTHON?=python3
155FEATURES_integration=$(FEATURES) -DWANT_IP_FROM_QUERY_STRING 155FEATURES_integration=$(FEATURES) -DWANT_IP_FROM_QUERY_STRING -DWANT_ACCESSLIST_BLACK
156CFLAGS_integration=$(CFLAGS) $(OPTS_debug) $(FEATURES_integration) -fsanitize=address,undefined -fno-omit-frame-pointer 156CFLAGS_integration=$(CFLAGS) $(OPTS_debug) $(FEATURES_integration) -fsanitize=address,undefined -fno-omit-frame-pointer
157LDFLAGS_integration=$(LDFLAGS) -fsanitize=address,undefined 157LDFLAGS_integration=$(LDFLAGS) -fsanitize=address,undefined
158 158
@@ -162,7 +162,13 @@ opentracker.integration: $(SOURCES) $(HEADERS)
162check-integration: opentracker.integration 162check-integration: opentracker.integration
163 OPENTRACKER=./opentracker.integration $(PYTHON) -m unittest discover -s tests/integration 163 OPENTRACKER=./opentracker.integration $(PYTHON) -m unittest discover -s tests/integration
164 164
165.PHONY: all check check-sanitize check-integration clean install 165# Everything, cheapest first, so a quick failure comes back quickly.
166check-all:
167 $(MAKE) check
168 $(MAKE) check-sanitize
169 $(MAKE) check-integration
170
171.PHONY: all check check-sanitize check-integration check-all clean install
166 172
167clean: 173clean:
168 rm -rf opentracker opentracker.debug opentracker.integration proxy proxy.debug $(TESTBIN) $(TESTBIN).sanitize *.o *~ 174 rm -rf opentracker opentracker.debug opentracker.integration proxy proxy.debug $(TESTBIN) $(TESTBIN).sanitize *.o *~
diff --git a/tests/integration/harness.py b/tests/integration/harness.py
index 868075d..7e75574 100644
--- a/tests/integration/harness.py
+++ b/tests/integration/harness.py
@@ -60,17 +60,20 @@ def free_port():
60class Tracker: 60class Tracker:
61 """One tracker process, listening on loopback.""" 61 """One tracker process, listening on loopback."""
62 62
63 def __init__(self, extra_config=""): 63 def __init__(self, extra_config="", files=None):
64 self.port = free_port() 64 self.port = free_port()
65 self.dir = tempfile.mkdtemp(prefix="ot-integration-") 65 self.dir = tempfile.mkdtemp(prefix="ot-integration-")
66 self.log = None 66 self.log = None
67 self.process = None 67 self.process = None
68 try: 68 try:
69 for name, content in (files or {}).items():
70 with open(os.path.join(self.dir, name), "wb") as handle:
71 handle.write(content)
69 self.config = os.path.join(self.dir, "opentracker.conf") 72 self.config = os.path.join(self.dir, "opentracker.conf")
70 with open(self.config, "w") as handle: 73 with open(self.config, "w") as handle:
71 handle.write("listen.tcp 127.0.0.1:%d\n" % self.port) 74 handle.write("listen.tcp 127.0.0.1:%d\n" % self.port)
72 handle.write("listen.udp 127.0.0.1:%d\n" % self.port) 75 handle.write("listen.udp 127.0.0.1:%d\n" % self.port)
73 handle.write(extra_config) 76 handle.write(extra_config.replace("{dir}", self.dir))
74 self.log = open(os.path.join(self.dir, "tracker.log"), "w+b") 77 self.log = open(os.path.join(self.dir, "tracker.log"), "w+b")
75 # Leak detection is left at the sanitizer's own default, which is on 78 # Leak detection is left at the sanitizer's own default, which is on
76 # where LeakSanitizer exists and off where it does not. Asking for it 79 # where LeakSanitizer exists and off where it does not. Asking for it
@@ -154,6 +157,12 @@ class Tracker:
154 def stats(self, mode): 157 def stats(self, mode):
155 return self.get("/stats?mode=" + mode) 158 return self.get("/stats?mode=" + mode)
156 159
160 def get_with_headers(self, path, headers=None, timeout=10):
161 """The body and the response headers, for the compressed answers."""
162 request = urllib.request.Request("http://127.0.0.1:%d%s" % (self.port, path), headers=headers or {})
163 with urllib.request.urlopen(request, timeout=timeout) as response:
164 return response.read(), dict(response.headers)
165
157 def torrent_count(self): 166 def torrent_count(self):
158 return int(self.stats("torr").split()[0]) 167 return int(self.stats("torr").split()[0])
159 168
@@ -180,14 +189,37 @@ class Tracker:
180 assert action == 1, "udp announce answered action %d" % action 189 assert action == 1, "udp announce answered action %d" % action
181 return {"interval": interval, "leechers": leechers, "seeders": seeders, "peers": answer[20:]} 190 return {"interval": interval, "leechers": leechers, "seeders": seeders, "peers": answer[20:]}
182 191
192 def udp_scrape(self, sock, connection_id, hashes):
193 """One (seeders, completed, leechers) triple per hash, in order."""
194 sock.sendto(struct.pack(">QII", connection_id, 2, 3) + b"".join(hashes), ("127.0.0.1", self.port))
195 answer = sock.recv(2048)
196 action, _ = struct.unpack(">II", answer[:8])
197 assert action == 2, "udp scrape answered action %d" % action
198 return [struct.unpack(">III", answer[8 + 12 * i : 20 + 12 * i]) for i in range(len(hashes))]
199
200 def udp_raw(self, payload, timeout=1.0):
201 """Sends a packet exactly as given. Returns the answer, or None if the
202 tracker chose to say nothing, which is how it treats a broken one."""
203 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
204 sock.settimeout(timeout)
205 try:
206 sock.sendto(payload, ("127.0.0.1", self.port))
207 try:
208 return sock.recv(2048)
209 except socket.timeout:
210 return None
211 finally:
212 sock.close()
213
183 214
184class TrackerTestCase(unittest.TestCase): 215class TrackerTestCase(unittest.TestCase):
185 """Gives every test its own tracker and fails it on any sanitizer output.""" 216 """Gives every test its own tracker and fails it on any sanitizer output."""
186 217
187 config = "" 218 config = ""
219 files = None
188 220
189 def setUp(self): 221 def setUp(self):
190 self.tracker = Tracker(self.config) 222 self.tracker = Tracker(self.config, self.files)
191 223
192 def tearDown(self): 224 def tearDown(self):
193 complaints = self.tracker.stop() 225 complaints = self.tracker.stop()