test: block real mouse/keyboard input and window moves during pytest
Many tests run real bot code paths with only the screen faked; those paths end in win_input's SendInput/SetCursorPos, which act on the focused window. Running the suite while the bot played on 2026-09-15 sent test clicks and keys into D2R (a game started with no bot input, the inventory opened, the character got stranded), and the bot was blamed for getting stuck. conftest now wraps win_input.user32 so SendInput/SetCursorPos/keybd_event/ mouse_event report success and do nothing, and no-ops utils.misc window SetWindowPos/SetForegroundWindow/ShowWindow. Verified: a test calling win_input.mouse_move leaves the real cursor in place; with BOTTY_TESTS_ALLOW_REAL_INPUT=1 the same test moves it. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f11034869b
commit
b0d8fdf028
@@ -21,3 +21,41 @@ if sys.platform == "win32":
|
||||
pass
|
||||
|
||||
ssl.SSLContext.load_default_certs = _safe_load_default_certs
|
||||
|
||||
|
||||
# Never let a test drive the real desktop.
|
||||
#
|
||||
# Many tests run real bot code paths (town maintenance, waypoints, NPC clicks, game
|
||||
# creation) with only the screen faked. Those paths end in win_input's SendInput /
|
||||
# SetCursorPos, which act on whatever window has focus. On 2026-09-15 the suite was
|
||||
# run repeatedly while the bot was playing: D2R received test keystrokes and clicks -
|
||||
# a game started with no bot input, the inventory opened, and the character ended up
|
||||
# stranded - and the bot was blamed for "getting stuck".
|
||||
#
|
||||
# Block it at the lowest layer so no test can reach the OS, whatever it forgets to
|
||||
# mock. Set BOTTY_TESTS_ALLOW_REAL_INPUT=1 to opt out for a deliberate live test.
|
||||
if sys.platform == "win32":
|
||||
import os
|
||||
|
||||
if not os.environ.get("BOTTY_TESTS_ALLOW_REAL_INPUT"):
|
||||
|
||||
class _NoRealInputUser32:
|
||||
"""user32 proxy: input and cursor calls report success and do nothing."""
|
||||
|
||||
def __init__(self, real):
|
||||
self._real = real
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name == "SendInput":
|
||||
return lambda count, *args: count # "all events inserted"
|
||||
if name in ("SetCursorPos", "keybd_event", "mouse_event"):
|
||||
return lambda *args: 1
|
||||
return getattr(self._real, name)
|
||||
|
||||
from input_layer import win_input as _win_input
|
||||
from utils import misc as _misc
|
||||
|
||||
_win_input.user32 = _NoRealInputUser32(_win_input.user32)
|
||||
# Window moves / focus steals: tests must not reposition or front D2R either.
|
||||
for _name in ("SetWindowPos", "SetForegroundWindow", "ShowWindow"):
|
||||
setattr(_misc, _name, lambda *args, **kwargs: None)
|
||||
|
||||
Reference in New Issue
Block a user