diff options
Diffstat (limited to 'tools/ui_flow.py')
| -rw-r--r-- | tools/ui_flow.py | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/tools/ui_flow.py b/tools/ui_flow.py index f43cf81..3e82231 100644 --- a/tools/ui_flow.py +++ b/tools/ui_flow.py @@ -19,7 +19,8 @@ drawing each screen, so every step waits for the screen it expects instead of sleeping. Menus are native Menu2 views that print nothing; for those the script waits a fixed time. -The flow covers: the list, a TOTP entry, a HOTP entry and its next code, the +The flow covers: the results of an Aegis import sent through the settings +form (the fixture sets the form, as the phone would), the list, a TOTP entry, a HOTP entry and its next code, the PIN screen, a wrong PIN, a correct PIN opening a locked entry, auto-lock closing it, the menu, the About screen (watches with buttons; touch-only menus have no focus to move) and the lockout after 5 wrong PINs. @@ -46,6 +47,8 @@ import sim_screenshot as shots EXIT_OK, EXIT_DIFFERENT, EXIT_FLOW = 0, 1, 2 SCREEN_TIMEOUT_S = 20.0 AUTO_LOCK_TIMEOUT_S = 25.0 # the UI-test build locks after 10 s without input +IMPORT_TIMEOUT_S = 90.0 # the 100-entry fixture import runs on a timer after start-up +IMPORT_MEMORY_BUDGET = 0.70 # README 18: peak memory at most 70 % of the watch-app memory MENU_SETTLE_S = 1.5 # Menu2 has no "shown" line SETTLE_S = 0.4 # after a "shown" line, before the screenshot CLICK_PAUSE_S = 0.25 @@ -225,6 +228,12 @@ class Flow: else: self.sim.swipe(self._w() // 2, self._h() * 3 // 4, self._w() // 2, self._h() // 4) + def prev(self) -> None: + if self.sim.has("up"): + self.sim.press("up") + else: + self.sim.swipe(self._w() // 2, self._h() // 4, self._w() // 2, self._h() * 3 // 4) + def back(self) -> None: self.sim.press("esc") @@ -305,9 +314,26 @@ class Flow: self.results[name] = shots.check_golden(screen, label, out, golden) +def flow_import(f: Flow) -> None: + """The fixture's 100-entry Aegis import through the settings form opens its + results; its peak memory must stay within the budget.""" + f.expect("results", IMPORT_TIMEOUT_S) + stats = f.log.latest(r"DIAG import entries=(\d+) wall_ms=(\d+) mem_peak=(\d+) mem_total=(\d+)") + if stats is None: + raise FlowError("the import didn't report its statistics") + entries, wall_ms, peak, total = (int(v) for v in stats.groups()) + fraction = peak / total + print(f"[{f.sim.device_dir.name}] import of {entries} entries: {wall_ms} ms, peak memory {fraction:.1%}") + if fraction > IMPORT_MEMORY_BUDGET: + raise FlowError(f"import peak memory {fraction:.1%} is over {IMPORT_MEMORY_BUDGET:.0%}") + f.shot("import_results") + f.act() + f.back() + f.expect("list") + + def flow_entries(f: Flow) -> None: """The list, a TOTP entry, a HOTP entry and its next code.""" - f.expect("list") f.shot("list") f.act() f.open_focused_row() # GitHub, TOTP @@ -333,8 +359,7 @@ def flow_entries(f: Flow) -> None: def flow_locked_entry(f: Flow) -> None: """Bank is locked: PIN screen, a wrong PIN, the right PIN, then auto-lock.""" - for _ in range(6): # wrap around to Bank (index 2 of 7) - f.next() + f.prev() # from VPN back to Bank f.act() f.open_focused_row() f.expect("pin") @@ -391,6 +416,7 @@ def flow_lockout(f: Flow) -> None: def run_flow(f: Flow) -> None: """The scripted session; see the module docstring.""" + flow_import(f) flow_entries(f) flow_locked_entry(f) flow_menu(f) |
