"""A persistent failure must not restart the bot forever. 2026-08-28: a 25-minute scheduled break left D2R on a screen the bot could not re-enter ("select_char: Could not find online/offline tabs"). restart_or_exit spawned a replacement process and exited — with no attempt limit and no backoff — so it span up a new process roughly every 20 seconds. Instances stacked and then refused to die. The counter MUST survive the exec: each restart is a new process, so an in-memory counter cannot bound the chain. """ import os import pytest @pytest.fixture def clean_counter(): from bot import Bot Bot._reset_restart_count() yield Bot Bot._reset_restart_count() def test_restart_count_persists_across_processes(clean_counter): """The whole point: an in-memory counter cannot stop a chain of execs.""" Bot = clean_counter assert Bot._bump_restart_count() == 1 assert Bot._bump_restart_count() == 2 # Simulates a fresh process reading the same on-disk state. assert Bot._bump_restart_count() == 3 assert os.path.exists(Bot._RESTART_COUNT_FILE) def test_reaching_town_clears_the_count(clean_counter): Bot = clean_counter Bot._bump_restart_count() Bot._bump_restart_count() Bot._reset_restart_count() assert Bot._bump_restart_count() == 1, "a recovered bot still counts toward the cap" def test_cap_is_bounded_and_reachable(clean_counter): Bot = clean_counter assert 1 <= Bot._MAX_CONSECUTIVE_RESTARTS <= 20 def test_restart_path_has_a_cap_and_a_backoff(): import inspect from bot import Bot src = inspect.getsource(Bot.restart_or_exit) assert "_MAX_CONSECUTIVE_RESTARTS" in src, "restart loop is unbounded" assert "time.sleep(" in src, "no backoff — a fast failure can stack processes" cap_at = src.index("_MAX_CONSECUTIVE_RESTARTS") spawn_at = src.index("subprocess.Popen") assert cap_at < spawn_at, "the cap must be checked BEFORE spawning a replacement" def test_missing_counter_file_is_treated_as_zero(clean_counter): """First run has no file; that must not raise.""" Bot = clean_counter if os.path.exists(Bot._RESTART_COUNT_FILE): os.remove(Bot._RESTART_COUNT_FILE) assert Bot._bump_restart_count() == 1