#10 transport (obdcore/transport.py): - TcpTransport.read raises IOError on a real socket error or peer-close instead of swallowing it as a timeout, so a dead WiFi link surfaces (via the #8 poll handler) as 'connection lost' rather than a frozen dashboard. - TcpTransport.reset_input_buffer drains at most 64 chunks — never spins forever. - BleTransport closes the client + stops the event-loop thread on connect timeout (no leak), caps the notification buffer at 64 KiB, and close() is robust when only partially initialised. #11 controller (gui/controller.py, obdcore/store.py): - connect() closes the transport and nulls the link if init()/connect() raises, so a failed/retried connect doesn't orphan sockets/threads. - stop_record() unhooks store.recorder BEFORE closing it, and CsvRecorder now has a 'closed' guard so a poll-thread write racing close() is a no-op instead of an I/O-on-closed-file crash. Closes #10 Closes #11 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016yT89n4zR4qbrySoSiEyZs
This commit is contained in:
@@ -5,6 +5,7 @@ import os
|
||||
import socket
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
@@ -89,6 +90,31 @@ def test_wifi_transport():
|
||||
srv.stop()
|
||||
|
||||
|
||||
def test_tcp_read_raises_on_closed_peer():
|
||||
# A dead WiFi connection must surface as an error, not silently look like a
|
||||
# perpetual timeout (which left the app frozen on "Connected").
|
||||
srv = socket.socket()
|
||||
srv.bind(("127.0.0.1", 0)); srv.listen(1)
|
||||
port = srv.getsockname()[1]
|
||||
|
||||
def serve():
|
||||
c, _ = srv.accept()
|
||||
c.close() # drop the client immediately
|
||||
|
||||
threading.Thread(target=serve, daemon=True).start()
|
||||
t = TcpTransport("127.0.0.1", port)
|
||||
time.sleep(0.1)
|
||||
raised = False
|
||||
try:
|
||||
for _ in range(5):
|
||||
t.read(64)
|
||||
except IOError:
|
||||
raised = True
|
||||
assert raised, "read should raise IOError when the peer closed the socket"
|
||||
t.close(); srv.close()
|
||||
print(" TCP dead-connection detected (read raises, not silent): OK")
|
||||
|
||||
|
||||
def test_factory_helpers():
|
||||
# the factory methods build the right transport type
|
||||
assert hasattr(ElmLink, "serial") and hasattr(ElmLink, "tcp") and hasattr(ElmLink, "ble")
|
||||
@@ -97,5 +123,6 @@ def test_factory_helpers():
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_wifi_transport()
|
||||
test_tcp_read_raises_on_closed_peer()
|
||||
test_factory_helpers()
|
||||
print("\nALL TRANSPORT TESTS PASS")
|
||||
|
||||
Reference in New Issue
Block a user