"""Explicit, side-effect-free planning followed by selected registered-device scenarios.""" import argparse import json from pathlib import Path # name: (instrumentation family, board required, side effect) SCENARIOS = { 'animation-library': ('ble', True, 'focused animation download, warm cache, read-only BLE/WiFi chunk equality; no network switches'), 'wifi-transport': ('ble', True, 'encrypted WiFi upgrade, identical image transfer comparison; no mutations'), 'wifi-transport-network': ('ble', True, 'reapply currently active board WiFi with password retained; verify hybrid routing recovery'), 'wifi-transport-restart': ('ble', True, 'restart board main service only after authenticated WiFi readiness; verify new BLE/WiFi session'), 'wifi-transport-recovery': ('ble', True, 'phone WiFi and Bluetooth disable/restore; verify fallback and whole-session termination'), 'connection': ('ble', True, 'scan, handshake, disconnect and reconnect'), 'data': ('ble', True, 'read status/settings/storage/library/frame/wifi'), 'library-order': ('ble', True, 'read BLE pages and board order digest'), 'library-cache': ('ble', True, 'read two image tiers, then verify unchanged reconnect reuses app cache'), 'cache-storage': ('ble', False, 'verify private image cache isolation, corruption handling and clear'), 'conflict': ('ble', True, 'submit deliberately stale revision; expect rejection'), 'polling': ('ble', True, 'up to 60 status/frame polls'), 'controller-background': ('ble', True, 'controller background release and reconnect'), 'wifi-scan': ('ble', True, 'scan board WiFi without switching'), 'controls': ('ble', True, 'write current values; temporarily pause active animation and restore'), 'wifi-reapply': ('ble', True, 'reapply current network; brief network interruption'), 'navigation': ('activity', False, 'navigate disconnected App and menus; no board access'), 'activity-background': ('activity', True, 'Home, background release and reconnect'), 'rename': ('activity', True, 'rename device then restore name'), 'remember': ('activity', True, 'forget and reconnect test device'), 'bluetooth-toggle': ('activity', True, 'disable and restore phone Bluetooth'), 'connection-entry': ('layout', True, 'connected entry, rescan and reconnect; layout restore'), 'wifi-connection-entry': ('layout', True, 'production WiFi indicator, root rescan/disconnect/reconnect; no layout changes'), 'layout': ('layout', True, 'three layout configurations and frame bounds; layout restore'), } COMMON = ('connection', 'data', 'library-order', 'navigation') def main(argv=None): p = argparse.ArgumentParser(description=__doc__) p.add_argument('--list-scenarios', action='store_true') p.add_argument('--dry-run', action='store_true') choose = p.add_mutually_exclusive_group() choose.add_argument('--scenario', action='append', choices=SCENARIOS) choose.add_argument('--full-common', action='store_true', help='Explicit common regression; excludes mutation, long polling and recovery tests') p.add_argument('--adb') p.add_argument('--build', type=Path) p.add_argument('--poll-cycles', type=int, default=60) args = p.parse_args(argv) if args.list_scenarios: for name, (family, board, effect) in SCENARIOS.items(): print(f'{name}: family={family}; board={board}; {effect}') return 0 selected = list(COMMON) if args.full_common else list(dict.fromkeys(args.scenario or [])) if not selected: p.print_help(); return 2 if not 1 <= args.poll_cycles <= 60: p.error('poll-cycles must be 1..60') plan = [{'scenario': n, 'phone': 'registered root phone', 'board': SCENARIOS[n][1], 'effect': SCENARIOS[n][2]} for n in selected] print(json.dumps({'selected': plan, 'unselected': [n for n in SCENARIOS if n not in selected]}, ensure_ascii=False), flush=True) if args.dry_run: return 0 if not args.adb or not args.build: p.error('--adb and --build required for execution') from device_test_runner import main as execute for name in selected: flags = ['--adb', args.adb, '--build', str(args.build), '--scenario', name, '--test', SCENARIOS[name][0], '--poll-cycles', str(args.poll_cycles if name == 'polling' else 0)] flags += {'controls': ['--verify-current-controls'], 'wifi-reapply': ['--reapply-current-wifi'], 'bluetooth-toggle': ['--toggle-bluetooth']}.get(name, []) try: execute(flags) except Exception: print(json.dumps({'scenario': name, 'result': 'failed', 'remaining': 'not run'}), flush=True) raise print(json.dumps({'scenario': name, 'result': 'passed'}), flush=True) return 0 if __name__ == '__main__': raise SystemExit(main())