99 行
5.4 KiB
Python
99 行
5.4 KiB
Python
"""Verify ui.py against both native Glyphix emulator profiles (not a physical S2).
|
|
|
|
Build deviceprobe QuickApps first. Supply a compatible vendor global/launcher
|
|
image using --seed (or initialize the probe image). Never attaches to an
|
|
existing Inspector or terminates another user's emulator.
|
|
"""
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
import shutil
|
|
import socket
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
|
|
PROJECT = Path(__file__).resolve().parents[1]
|
|
ROOT = PROJECT.parent
|
|
sys.path.insert(0, str(PROJECT))
|
|
from ui import Inspector
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument('--output', required=True, type=Path)
|
|
parser.add_argument('--seed', type=Path, default=ROOT / 'com.sydxky.rtos.deviceprobe/.glyphix-work/image/generic-watch-466x466',
|
|
help='Initialized vendor image containing global/, global.pkg and apps/emulator.launcher.pkg')
|
|
args = parser.parse_args()
|
|
output = args.output.resolve()
|
|
output.mkdir(parents=True, exist_ok=True)
|
|
results = []
|
|
for shape, device in [('round', '466x466'), ('rect', '390x450')]:
|
|
with socket.socket() as sock:
|
|
if sock.connect_ex(('127.0.0.1', 14201)) == 0:
|
|
raise RuntimeError('Inspector port in use; will not attach to another runtime')
|
|
folder = output / shape
|
|
image = folder / 'image'
|
|
image.mkdir(parents=True, exist_ok=True)
|
|
seed = args.seed.resolve()
|
|
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')
|
|
name = 'com.sydxky.rtos.deviceprobe'
|
|
package = ROOT / name / '.glyphix-work/dist' / ('generic-watch-' + device + '-quickapp') / name / 'bundle.pkg'
|
|
shutil.copy2(package, image / 'apps' / (name + '.pkg'))
|
|
(image / 'pkgs.db').write_text(json.dumps({'apps': {p: {'uri': 'pkg://' + p} for p in (name, 'emulator.launcher')}, 'dials': {}}), encoding='utf-8')
|
|
command = [str(ROOT / 'temp/glyphix-v0.7.2-windows-x64/bin/glyphix-emu.exe'), '--config', 'pkgs.db', '--target', name, '--inspector']
|
|
command += ['--width', '624', '--height', '624', '--dpi', '326', '--font-size', '32', '--round', '--surface', 'surface/surface-466x466.json'] if shape == 'round' else ['--width', '390', '--height', '450', '--dpi', '321', '--font-size', '29']
|
|
command += ['--memory-profile', '8192', '--font-map', 'font-faces', '--font-family', 'sans-serif']
|
|
client = Inspector('http://127.0.0.1:14201')
|
|
item = {'profile': shape, 'evidence_scope': 'native_emulator_not_S2', 'package_sha256': hashlib.sha256(package.read_bytes()).hexdigest(), 'passed': False}
|
|
results.append(item)
|
|
with open(folder / 'stdout.log', 'w', encoding='utf-8') as out, open(folder / 'stderr.log', 'w', encoding='utf-8') as err:
|
|
proc = subprocess.Popen(command, cwd=image, stdin=subprocess.PIPE, stdout=out, stderr=err, creationflags=subprocess.CREATE_NO_WINDOW)
|
|
try:
|
|
for _ in range(70):
|
|
if proc.poll() is not None:
|
|
raise RuntimeError('Emulator exited before Inspector startup')
|
|
try:
|
|
client.request('/logs')
|
|
break
|
|
except OSError:
|
|
time.sleep(.3)
|
|
else:
|
|
raise TimeoutError('Inspector did not start')
|
|
time.sleep(1)
|
|
item['before'] = client.screenshot(folder / 'before.png')
|
|
item['initial_visible'] = client.exists(('text', '点击次数:0'))
|
|
client.click(('text', '点击验证'))
|
|
item['after_visible'] = client.exists(('text', '点击次数:1'))
|
|
item['after'] = client.screenshot(folder / 'after.png')
|
|
plan = json.loads((PROJECT / 'examples/probe-inspector.json').read_text(encoding='utf-8'))
|
|
plan['steps'][0]['value'] = '点击次数:1'
|
|
plan['steps'][2]['value'] = '点击次数:2'
|
|
planfile = folder / 'plan.json'
|
|
planfile.write_text(json.dumps(plan, ensure_ascii=False), encoding='utf-8')
|
|
run = subprocess.run([sys.executable, str(PROJECT / 'ui.py'), '--target', 'inspector', '--inspector', client.base, 'run', str(planfile), '--output', str(folder / 'plan-results')], capture_output=True, timeout=90)
|
|
item['plan_exit'] = run.returncode
|
|
item['passed'] = item['initial_visible'] and item['after_visible'] and run.returncode == 0
|
|
if run.returncode:
|
|
raise RuntimeError(run.stderr.decode('utf-8', 'replace') or 'UI plan failed')
|
|
except Exception as error:
|
|
item['error'] = type(error).__name__
|
|
raise
|
|
finally:
|
|
if proc.poll() is None:
|
|
proc.terminate()
|
|
proc.wait(timeout=10)
|
|
proc.stdin.close()
|
|
(output / 'results.json').write_text(json.dumps(results, ensure_ascii=False, indent=2), encoding='utf-8')
|
|
print(json.dumps(item, ensure_ascii=True), flush=True)
|
|
time.sleep(2)
|
|
return 0 if all(item['passed'] for item in results) else 1
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|