diff options
| author | Dirk Engling <erdgeist@erdgeist.org> | 2026-10-27 00:28:35 +0100 |
|---|---|---|
| committer | Dirk Engling <erdgeist@erdgeist.org> | 2026-10-27 00:28:35 +0100 |
| commit | 8c482cb2f7019c2491f3bf4f25c4fb5d395ad5da (patch) | |
| tree | 78b43b10eb798aeaa46428a3391c8fde5bd565a5 /tests/integration | |
| parent | b1cfed46d5ac6d73246540ebb915cd1314e27f6e (diff) | |
add more checkers to the sanitizer and integration check runs
Diffstat (limited to 'tests/integration')
| -rw-r--r-- | tests/integration/harness.py | 60 |
1 files changed, 46 insertions, 14 deletions
diff --git a/tests/integration/harness.py b/tests/integration/harness.py index c8da1e2..868075d 100644 --- a/tests/integration/harness.py +++ b/tests/integration/harness.py | |||
| @@ -7,6 +7,8 @@ reports its own memory errors, which the teardown turns into test failures. | |||
| 7 | """ | 7 | """ |
| 8 | 8 | ||
| 9 | import os | 9 | import os |
| 10 | import shutil | ||
| 11 | import signal | ||
| 10 | import socket | 12 | import socket |
| 11 | import struct | 13 | import struct |
| 12 | import subprocess | 14 | import subprocess |
| @@ -61,15 +63,34 @@ class Tracker: | |||
| 61 | def __init__(self, extra_config=""): | 63 | def __init__(self, extra_config=""): |
| 62 | self.port = free_port() | 64 | self.port = free_port() |
| 63 | self.dir = tempfile.mkdtemp(prefix="ot-integration-") | 65 | self.dir = tempfile.mkdtemp(prefix="ot-integration-") |
| 64 | self.config = os.path.join(self.dir, "opentracker.conf") | 66 | self.log = None |
| 65 | with open(self.config, "w") as handle: | 67 | self.process = None |
| 66 | handle.write("listen.tcp 127.0.0.1:%d\n" % self.port) | 68 | try: |
| 67 | handle.write("listen.udp 127.0.0.1:%d\n" % self.port) | 69 | self.config = os.path.join(self.dir, "opentracker.conf") |
| 68 | handle.write(extra_config) | 70 | with open(self.config, "w") as handle: |
| 69 | self.log = open(os.path.join(self.dir, "tracker.log"), "w+b") | 71 | handle.write("listen.tcp 127.0.0.1:%d\n" % self.port) |
| 70 | environment = dict(os.environ, ASAN_OPTIONS="detect_leaks=0:abort_on_error=0") | 72 | handle.write("listen.udp 127.0.0.1:%d\n" % self.port) |
| 71 | self.process = subprocess.Popen([TRACKER, "-f", self.config], stdout=self.log, stderr=self.log, env=environment) | 73 | handle.write(extra_config) |
| 72 | self._wait_for_port() | 74 | 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 | ||
| 76 | # where LeakSanitizer exists and off where it does not. Asking for it | ||
| 77 | # by name makes the tracker refuse to start on macOS and FreeBSD. | ||
| 78 | environment = dict(os.environ, ASAN_OPTIONS="abort_on_error=0") | ||
| 79 | self.process = subprocess.Popen([TRACKER, "-f", self.config], stdout=self.log, stderr=self.log, env=environment) | ||
| 80 | self._wait_for_port() | ||
| 81 | except BaseException: | ||
| 82 | self._cleanup() | ||
| 83 | raise | ||
| 84 | |||
| 85 | def _cleanup(self): | ||
| 86 | """Close what we opened and take the scratch directory with it.""" | ||
| 87 | if self.process is not None and self.process.poll() is None: | ||
| 88 | self.process.kill() | ||
| 89 | self.process.wait() | ||
| 90 | if self.log is not None: | ||
| 91 | self.log.close() | ||
| 92 | self.log = None | ||
| 93 | shutil.rmtree(self.dir, ignore_errors=True) | ||
| 73 | 94 | ||
| 74 | def _wait_for_port(self): | 95 | def _wait_for_port(self): |
| 75 | for _ in range(200): | 96 | for _ in range(200): |
| @@ -84,21 +105,32 @@ class Tracker: | |||
| 84 | raise AssertionError("tracker never listened on %d:\n%s" % (self.port, self.output())) | 105 | raise AssertionError("tracker never listened on %d:\n%s" % (self.port, self.output())) |
| 85 | 106 | ||
| 86 | def output(self): | 107 | def output(self): |
| 108 | if self.log is None: | ||
| 109 | return "" | ||
| 87 | self.log.flush() | 110 | self.log.flush() |
| 88 | self.log.seek(0) | 111 | self.log.seek(0) |
| 89 | return self.log.read().decode("utf-8", "replace") | 112 | return self.log.read().decode("utf-8", "replace") |
| 90 | 113 | ||
| 91 | def stop(self): | 114 | def stop(self): |
| 92 | """Returns anything the tracker complained about on the way out.""" | 115 | """Returns anything the tracker complained about on the way out. |
| 93 | if self.process.poll() is None: | 116 | |
| 94 | self.process.kill() | 117 | The interrupt rather than a kill is what makes the leak check work at |
| 95 | self.process.wait() | 118 | all: LeakSanitizer reports from an exit handler, so a killed tracker |
| 119 | reports nothing and the suite passes over leaks it never looked for. | ||
| 120 | """ | ||
| 121 | if self.process is not None and self.process.poll() is None: | ||
| 122 | self.process.send_signal(signal.SIGINT) | ||
| 123 | try: | ||
| 124 | self.process.wait(timeout=5) | ||
| 125 | except subprocess.TimeoutExpired: | ||
| 126 | self.process.kill() | ||
| 127 | self.process.wait() | ||
| 96 | complaints = [ | 128 | complaints = [ |
| 97 | line | 129 | line |
| 98 | for line in self.output().splitlines() | 130 | for line in self.output().splitlines() |
| 99 | if "Sanitizer" in line or "runtime error" in line or line.startswith("ERROR") | 131 | if "Sanitizer" in line or "runtime error" in line or line.startswith("ERROR") |
| 100 | ] | 132 | ] |
| 101 | self.log.close() | 133 | self._cleanup() |
| 102 | return complaints | 134 | return complaints |
| 103 | 135 | ||
| 104 | # ----------------------------------------------------------- over http | 136 | # ----------------------------------------------------------- over http |
