Files
cthulhu/tests/native_internal_ui.py

118 lines
4.8 KiB
Python

#!/usr/bin/env python3
"""Run actions and editable internal controls on a private X11/AT-SPI desktop."""
import json
import os
from pathlib import Path
import subprocess
import sys
import tempfile
import time
def run_inside():
root = Path(__file__).resolve().parents[1]
environment = dict(os.environ, GOCACHE="/tmp/cthulhu-cache", CTHULHU_NATIVE_X11="1",
CTHULHU_NATIVE_BROWSER="1")
probe = subprocess.Popen(["xev", "-name", "Internal UI background", "-event", "keyboard"],
stdout=subprocess.DEVNULL)
try:
deadline = time.monotonic() + 5
while True:
found = subprocess.run(["xdotool", "search", "--onlyvisible", "--name", "^Internal UI background$"],
capture_output=True, text=True)
if found.returncode == 0:
background = found.stdout.strip().splitlines()[0]
environment["CTHULHU_UI_BACKGROUND"] = background
subprocess.run(["xdotool", "windowfocus", background], check=True)
break
if time.monotonic() >= deadline:
raise RuntimeError("keyboard probe did not open")
time.sleep(0.02)
subprocess.run(["go", "test", "./internal/platform/xorg", "-count=1", "-timeout=60s",
"-run", "^TestNative(InternalUICapturesAndReleases|LearnModeCapturesKeysAndRestoresCommands|CustomBindingsUpdateAndRelease|CommandGrabSuspensionAndRestoration|SecureInputDropsKeysAndRestoresGrabs|BrowseKeyTransitions)$"],
cwd=root, env=environment, check=True)
finally:
probe.terminate()
probe.wait(timeout=5)
with tempfile.TemporaryDirectory(prefix="cthulhu-internal-ui-") as temporary:
marker = Path(temporary) / "state.json"
environment.update(CTHULHU_UI_MARKER=str(marker), CTHULHU_NATIVE_INTERNAL_UI="1")
fixture = subprocess.Popen([sys.executable, __file__, "--fixture"], env=environment)
try:
deadline = time.monotonic() + 10
window = ""
while time.monotonic() < deadline:
found = subprocess.run(["xdotool", "search", "--onlyvisible", "--name",
"^Internal UI action probe$"], capture_output=True, text=True)
if found.returncode == 0:
window = found.stdout.strip().splitlines()[0]
break
time.sleep(0.02)
if not window:
raise RuntimeError("GTK fixture did not open")
subprocess.run(["xdotool", "windowfocus", "--sync", window], check=True)
subprocess.run(["go", "test", "./internal/app", "-count=1", "-timeout=30s",
"-run", "^TestNative(InternalUIActionsAndEntry|TentacleClipboardTargetsAndTemporaryImage)$"],
cwd=root, env=environment, check=True)
finally:
fixture.terminate()
fixture.wait(timeout=5)
def run_fixture():
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
window = Gtk.Window(title="Internal UI action probe")
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
button = Gtk.Button(label="Run action")
entry = Gtk.Entry()
entry.get_accessible().set_name("Application text")
box.pack_start(button, False, False, 0)
box.pack_start(entry, False, False, 0)
lines = Gtk.TextView()
lines.get_accessible().set_name("Transfer text lines")
lines.get_buffer().set_text("First line\nSecond line")
lines.get_buffer().place_cursor(lines.get_buffer().get_start_iter())
box.pack_start(lines, False, False, 0)
password = Gtk.Entry()
password.set_visibility(False)
password.set_text("private fixture password")
password.get_accessible().set_name("Protected transfer text")
box.pack_start(password, False, False, 0)
window.add(box)
state = {"clicks": 0, "text": ""}
marker = Path(os.environ["CTHULHU_UI_MARKER"])
def save():
replacement = marker.with_suffix(".tmp")
replacement.write_text(json.dumps(state))
replacement.replace(marker)
def clicked(_button):
state["clicks"] += 1
save()
def changed(_entry):
state["text"] = entry.get_text()
save()
button.connect("clicked", clicked)
entry.connect("changed", changed)
window.connect("destroy", Gtk.main_quit)
window.show_all()
button.grab_focus()
save()
Gtk.main()
if __name__ == "__main__":
if "--fixture" in sys.argv:
run_fixture()
elif "--inside" in sys.argv:
run_inside()
else:
subprocess.run(["xvfb-run", "-a", "dbus-run-session", "--", sys.executable,
__file__, "--inside"], check=True,
env=dict(os.environ, GTK_MODULES="gail:atk-bridge", NO_AT_BRIDGE="0"))