Compare commits

...
Author SHA1 Message Date
ChuckandClaude Opus 5.5 2de875caed test(starlark): stop the pixlet-editor route tests leaking a fake Popen into the captive-portal check
TestPixletEditorHostDefaultsButDoesNotOverride patched Popen on the shared
subprocess module. The app's before_request captive-portal hook runs
subprocess.run (`with Popen(...) as p`) for `systemctl is-active hostapd`
whenever its 30s AP-mode cache is cold, so on a Linux host with systemctl -
the CI runner - the hook got the FakeProcess and the request 500'd with
"'FakeProcess' object does not support the context manager protocol".
Whether it happened depended on how long ago the previous request ran,
hence the intermittency; Windows has no systemctl and never reached it.

- Patch the starlark route module's own `subprocess` binding instead of
  the global Popen.
- Pin is_ap_mode_active to False in this file's client fixture, so no
  request here shells out to systemctl/nmcli at all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 17:23:55 -04:00
@@ -26,8 +26,15 @@ import pytest
@pytest.fixture
def client():
def client(monkeypatch):
from web_interface import app as web_app
from web_interface.app import app
# The captive-portal before_request hook shells out to systemctl/nmcli
# whenever its 30s cache is cold, so on a Linux host whether a request
# here runs subprocess depended on how long ago the previous one was --
# and several tests below stub subprocess. Pin it: no test in this file
# is about AP mode.
monkeypatch.setattr(web_app, 'is_ap_mode_active', lambda: False)
app.config['TESTING'] = True
with app.test_client() as c:
yield c
@@ -1136,12 +1143,23 @@ class TestPixletEditorHostDefaultsButDoesNotOverride:
captured['env'] = env
return FakeProcess()
# Swap the route module's own ``subprocess`` binding, not the shared
# ``subprocess.Popen``: patching the attribute on the real module is
# process-wide, and the app's before_request hook (the captive-portal
# check) runs ``subprocess.run`` -- ``with Popen(...)`` -- whenever its
# 30s AP-mode cache is cold on a host with systemctl. On the Linux CI
# runner that handed it this FakeProcess and 500'd the request, but
# only when the previous request was more than 30s earlier.
fake_subprocess = types.ModuleType('subprocess')
fake_subprocess.__dict__.update(mod.subprocess.__dict__)
fake_subprocess.Popen = fake_popen
with patch.object(mod, '_validate_starlark_app_path',
return_value=(app_dir, None)), \
patch.object(mod, '_PIXLET_EDITOR_SCRIPT', script), \
patch.object(mod, '_PIXLET_EDITOR_STATE', state_file), \
patch.object(mod, '_find_pixlet_binary', return_value='/usr/bin/pixlet'), \
patch.object(mod.subprocess, 'Popen', side_effect=fake_popen), \
patch.object(mod, 'subprocess', fake_subprocess), \
patch.dict(os.environ):
if operator_host is None:
os.environ.pop('PIXLET_EDITOR_HOST', None)