文件
crab-input-rtos/tests/emulator-validate.py
T

120 行
5.3 KiB
Python

"""Run real Glyphix native UI tests through its local Inspector (Python stdlib).
Build the input app and the minimal test fixture first; see the root README. No production
credentials, paid requests, Windows input injection or third party modules.
"""
import argparse
import datetime
import hashlib
import json
import pathlib
import shutil
import socket
import subprocess
import time
import urllib.parse
import urllib.request
ROOT = pathlib.Path(__file__).resolve().parents[1]
APPS = ['inputmethod', 'imefixture']
PROFILES = ['round', 'rect', 'round-quickapp', 'rect-quickapp']
BASE = 'http://127.0.0.1:14201'
def sha256(path):
return hashlib.sha256(path.read_bytes()).hexdigest().upper()
def request(path, params=None, method='GET'):
url = BASE + path + ('?' + urllib.parse.urlencode(params) if params else '')
with urllib.request.urlopen(urllib.request.Request(url, method=method), timeout=15) as response:
data = response.read()
try:
return json.loads(data)
except (ValueError, UnicodeDecodeError):
return data.decode('utf-8', errors='replace')
def evaluate(script):
return request('/fn/eval', {'lang': 'js', 'script': script}, 'POST')
def resume():
request('/control', {'pause': 'false'}, 'POST')
def snapshot(name, output):
try:
tree = request('/snapshot.json')
(output / (name + '.tree.json')).write_text(json.dumps(tree, ensure_ascii=False), encoding='utf-8')
with urllib.request.urlopen(BASE + '/snapshot/' + tree['frames'][-1]['snapshot'], timeout=15) as response:
(output / (name + '.png')).write_bytes(response.read())
finally:
# Capturing Inspector history pauses the runtime, including gestures/timers.
resume()
def prepare(profile, work):
device = 'generic-watch-' + ('466x466' if profile.startswith('round') else '390x450')
image = work / profile / 'image'
image.mkdir(parents=True, exist_ok=True)
seed = ROOT / 'com.sydxky.rtos.imefixture/.glyphix-work/image/generic-watch-466x466'
if not (seed / 'global.pkg').is_file() or not (seed / 'apps/emulator.launcher.pkg').is_file():
raise RuntimeError('Missing global assets/launcher: launch the round fixture emulator once with gx emulate first.')
shutil.copytree(seed / 'global', image / 'global', dirs_exist_ok=True)
shutil.copy2(seed / 'global.pkg', image / 'global.pkg')
(image / 'apps').mkdir(exist_ok=True)
shutil.copy2(seed / 'apps/emulator.launcher.pkg', image / 'apps/emulator.launcher.pkg')
artifacts = {}
for app in APPS:
package = 'com.sydxky.rtos.' + app
build = ROOT / package / '.glyphix-work'
if profile.endswith('-quickapp'):
source = build / 'dist' / (device + '-quickapp') / package / 'bundle.pkg'
else:
source = build / 'image' / device / 'apps' / (package + '.pkg')
shutil.copy2(source, image / 'apps' / (package + '.pkg'))
artifacts[app] = {'path': str(source), 'sha256': sha256(source), 'ux_sha256': sha256(ROOT / package / 'src/main/index.ux')}
packages = ['com.sydxky.rtos.' + app for app in APPS] + ['emulator.launcher']
(image / 'pkgs.db').write_text(json.dumps({'apps': {p: {'uri': 'pkg://' + p} for p in packages}, 'dials': {}}), encoding='utf-8')
return image, artifacts
def start(profile, work, first_app):
# Do not attach to or terminate another user's running emulator.
with socket.socket() as probe:
if probe.connect_ex(('127.0.0.1', 14201)) == 0:
raise RuntimeError('Inspector port 14201 is already in use; close the other emulator first.')
image, artifacts = prepare(profile, work)
executable = ROOT / 'temp/glyphix-v0.7.2-windows-x64/bin/glyphix-emu.exe'
args = [str(executable), '--config', 'pkgs.db', '--target', 'com.sydxky.rtos.' + first_app, '--inspector']
if profile.startswith('round'):
args += ['--width', '624', '--height', '624', '--dpi', '326', '--font-size', '32', '--round', '--surface', 'surface/surface-466x466.json']
else:
args += ['--width', '390', '--height', '450', '--dpi', '321', '--font-size', '29']
args += ['--memory-profile', '8192', '--font-map', 'font-faces', '--font-family', 'sans-serif']
stdout = open(work / profile / 'stdout.log', 'w', encoding='utf-8')
stderr = open(work / profile / 'stderr.log', 'w', encoding='utf-8')
# Keep stdin open: the vendor emulator exits when its console input sees EOF.
process = subprocess.Popen(args, cwd=image, stdin=subprocess.PIPE, stdout=stdout, stderr=stderr, creationflags=subprocess.CREATE_NO_WINDOW)
try:
deadline = time.time() + 20
while time.time() < deadline:
if process.poll() is not None:
raise RuntimeError('Emulator exited before Inspector was ready; inspect ' + str(work / profile / 'stderr.log'))
try:
request('/logs')
time.sleep(1)
return process, artifacts
except OSError:
time.sleep(0.25)
raise RuntimeError('Inspector startup timed out')
except BaseException:
if process.poll() is None:
process.terminate()
process.wait(timeout=10)
raise
finally:
stdout.close()
stderr.close()