From 8d400bf075f3f94e1bd90e194aef793efd97f9bd Mon Sep 17 00:00:00 2001 From: Dieter Olson Date: Fri, 31 Jul 2026 15:21:08 -0700 Subject: [PATCH] fix(tests): make sim backoff test deterministic across platforms test_backoff_progression_capped dialed 127.0.0.1:1 and slept a fixed 0.5 s; how fast the OS refuses that connect is platform-dependent (slow enough on Windows to capture fewer than two retries). The socket is now monkeypatched to refuse instantly and the test polls for the retries it asserts on, so it exercises the backoff schedule rather than the platform's TCP stack. Also applies ruff's mechanical import-block fix to this file (pre-existing I001/F401 that the pre-commit hook enforces on touch; CI does not run ruff). --- tests/test_sim_transport.py | 48 ++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/tests/test_sim_transport.py b/tests/test_sim_transport.py index d452c1221..36c346a02 100644 --- a/tests/test_sim_transport.py +++ b/tests/test_sim_transport.py @@ -5,17 +5,19 @@ """ import json import time -from typing import List, Optional +from typing import Optional import pytest from openflight.gspro.codec import GSProCodec -from openflight.sim.transport import find_json_end, TcpSimClient +from openflight.launch_monitor import ClubType +from openflight.sim.transport import TcpSimClient, find_json_end from openflight.sim.types import ( - ConnectionState, PlayerUpdate, ResolvedShot, ShotAck, + ConnectionState, + PlayerUpdate, + ResolvedShot, + ShotAck, ) -from openflight.launch_monitor import ClubType - # --- framing unit tests ------------------------------------------------------ @@ -250,14 +252,44 @@ def test_reconnect_after_server_drop(mock_sim): client.stop() -def test_backoff_progression_capped(): +def test_backoff_progression_capped(monkeypatch): + # Refuse instantly instead of dialing a real closed port: how fast the OS + # rejects a connect to 127.0.0.1:1 is platform-dependent (slow enough on + # Windows that a fixed sleep captured fewer than two retries), and the + # backoff schedule under test doesn't need a real socket at all. + from openflight.sim import transport as transport_mod + + class _InstantRefusalSocket: + def __init__(self, *args, **kwargs): + pass + + def settimeout(self, _timeout): + pass + + def connect(self, _addr): + raise ConnectionRefusedError("refused (test)") + + def close(self): + pass + + monkeypatch.setattr(transport_mod.socket, "socket", _InstantRefusalSocket) + client = TcpSimClient("127.0.0.1", 1, GSProCodec(), heartbeat_interval_s=60, backoff_seconds=(0.05, 0.1, 0.1)) statuses = [] client.on_status = statuses.append client.start() - time.sleep(0.5) - client.stop() + try: + # Poll for the retries instead of sleeping a fixed interval. + deadline = time.time() + 3.0 + while time.time() < deadline: + backoffs = [s.next_retry_in_s for s in statuses + if s.state == ConnectionState.CONNECTING and s.next_retry_in_s > 0] + if len(backoffs) >= 3: + break + time.sleep(0.02) + finally: + client.stop() # Before the first successful connection the client reports CONNECTING during # the retry backoff (RECONNECT_BACKOFF is reserved for a connection that was # established and then dropped). The backoff schedule is still carried on