Fix some leaks/hangs on close: unstarted StreamInterface streams & TCP reader unblock

This commit is contained in:
Ian McEwen
2026-05-31 13:48:06 -07:00
parent c2a01f8294
commit ce5bbcda68
4 changed files with 43 additions and 6 deletions

View File

@@ -33,6 +33,17 @@ def test_StreamInterface_close_safe_when_thread_never_started():
iface.close()
@pytest.mark.unit
@pytest.mark.usefixtures("reset_mt_config")
def test_StreamInterface_close_when_thread_never_started_closes_stream():
"""If no reader thread was started, close() should still close the stream."""
iface = StreamInterface(noProto=True, connectNow=False)
stream = MagicMock()
iface.stream = stream
iface.close()
stream.close.assert_called_once()
@pytest.mark.unit
@pytest.mark.usefixtures("reset_mt_config")
def test_StreamInterface_init_cleans_up_when_connect_raises():

View File

@@ -1,7 +1,7 @@
"""Meshtastic unit tests for tcp_interface.py"""
import re
from unittest.mock import patch
from unittest.mock import MagicMock, patch
import pytest
@@ -54,3 +54,25 @@ def test_TCPInterface_without_connecting():
with patch("socket.socket"):
iface = TCPInterface(hostname="localhost", noProto=True, connectNow=False)
assert iface.socket is None
@pytest.mark.unit
def test_TCPInterface_close_shutdowns_socket_before_super_close():
"""Close should unblock socket reads before waiting on StreamInterface.close()."""
iface = TCPInterface(hostname="localhost", noProto=True, connectNow=False)
sock = MagicMock()
iface.socket = sock
call_order = []
with patch.object(TCPInterface, "_socket_shutdown", autospec=True) as mock_shutdown:
with patch(
"meshtastic.stream_interface.StreamInterface.close", autospec=True
) as mock_super_close:
mock_shutdown.side_effect = lambda _self: call_order.append("shutdown")
mock_super_close.side_effect = lambda _self: call_order.append("super_close")
iface.close()
assert call_order == ["shutdown", "super_close"]
sock.close.assert_called_once()
assert iface.socket is None