Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,28 @@ def feeder():

@pytest.fixture(autouse=True)
def _assert_no_j1939_thread_leak():
"""Fail any test that leaves a j1939.* background thread alive."""
"""Fail any test that leaves a j1939.* background thread alive.

The poll window here (3.5s) is deliberately kept slightly above
ElectronicControlUnit.stop()'s own default dispatch_join_timeout (3.0s):
stop() only logs a warning (rather than failing) if the dispatch thread
doesn't exit within that timeout, e.g. while a slow subscriber callback
unwinds. If this fixture's window were shorter than stop()'s own
tolerance, a thread that stop() itself considers "still fine, just slow"
could trip a false-positive leak failure here. See #81.
"""
before = {t.ident for t in threading.enumerate()
if t.name.startswith('j1939.')}
yield
# Give freshly-stopped threads a brief moment to actually exit.
# Give freshly-stopped threads a chance to actually exit.
import time
for _ in range(20):
deadline = time.monotonic() + 3.5
while True:
leaked = [t for t in threading.enumerate()
if t.name.startswith('j1939.')
and t.ident not in before
and t.is_alive()]
if not leaked:
if not leaked or time.monotonic() >= deadline:
break
time.sleep(0.01)
assert not leaked, (
Expand Down