"""Opt-in cache regression on a selected Android device with Chrome and the helper. Set ARTEMIS_TEST_DEVICE_SERIAL and run this file with ``pytest -m android``. Opens a disposable local page via ADB reverse; no model call or system-setting edit. """ import base64 from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from io import BytesIO import os import subprocess import threading import time from uuid import uuid4 from PIL import Image import pytest from artemis.clients.accessibility_client import AccessibilityClient from artemis.runtime.adb_endpoint import adb_command from artemis.runtime.device_lock import DeviceExecutionLock pytestmark = [pytest.mark.android, pytest.mark.integration] def test_helper_refreshes_dynamic_web_text_and_pixels(tmp_path): serial = os.getenv("ARTEMIS_TEST_DEVICE_SERIAL") if not serial: pytest.skip("Select ARTEMIS_TEST_DEVICE_SERIAL explicitly") marker = "updated-" + uuid4().hex[:8] state = {"value": "baseline"} class Handler(BaseHTTPRequestHandler): def log_message(self, *_args): pass def do_GET(self): if self.path == "/state": body = state["value"].encode() else: body = b""" ARTEMIS dynamic observation fixture

loading

""" self.send_response(200) self.send_header("Content-Type", "text/html; charset=utf-8") self.send_header("Cache-Control", "no-store") self.end_headers() self.wfile.write(body) def adb(*arguments, check=True): return subprocess.run( adb_command(["-s", serial, *arguments]), capture_output=True, check=check, timeout=15, ) lease = DeviceExecutionLock(serial, description="Dynamic helper observation regression") lease.acquire(blocking=False) server = ThreadingHTTPServer(("127.0.0.1", 0), Handler) worker = threading.Thread(target=server.serve_forever, daemon=True) worker.start() client = AccessibilityClient(serial, provision_on_connect=False) device_port = None try: client.connect() # Let ADB allocate an unused reverse port; never replace a user's mapping. device_port = adb("reverse", "tcp:0", f"tcp:{server.server_port}").stdout.decode().strip() assert device_port.isdigit(), "ADB did not allocate a reverse port" adb( "shell", "am", "start", "-a", "android.intent.action.VIEW", "-d", f"http://127.0.0.1:{device_port}/", "-p", "com.android.chrome", ) def await_observation(expected, green): deadline = time.monotonic() + 15 observed_text = [] while time.monotonic() < deadline: observation = client.get_screen_data() observed_text = [element.get("text") for element in observation.elements] raw = base64.b64decode(observation.base64) with Image.open(BytesIO(raw)) as picture: pixels = list(picture.convert("RGB").resize((32, 32)).getdata()) count = sum( g > 150 and r < 100 if green else r > 150 and g < 100 for r, g, _ in pixels ) if expected in observed_text and count > len(pixels) // 4: (tmp_path / f"{expected}.jpg").write_bytes(raw) return time.sleep(0.5) pytest.fail(f"Pixels and UI hierarchy did not converge to {expected}: {observed_text}") await_observation("baseline", False) state["value"] = marker await_observation(marker, True) state["value"] = "baseline" await_observation("baseline", False) finally: client.disconnect() if device_port and device_port.isdigit(): adb("reverse", "--remove", f"tcp:{device_port}", check=False) server.shutdown() server.server_close() worker.join(timeout=5) lease.release()