diff options
| author | cirakg <cirakg@cirakg.xyz> | 2026-10-21 03:55:10 +0200 |
|---|---|---|
| committer | cirakg <cirakg@cirakg.xyz> | 2026-10-21 03:55:10 +0200 |
| commit | 56e0c351bb95cfdf63aa76ab8c5d725a694bad63 (patch) | |
| tree | e99c7af6eca0656948279055c20a5f87d855d4c8 /docker | |
| parent | 5e8ac1e2f5a660e55ea132996e1d5730cfa4fa64 (diff) | |
test(build): add make watchdog, the glance memory budget and the glance screenshot
- make watchdog (in make ci): a stress build encodes, packs, turns into
runs and draws the largest code of every 2D symbology at two steps per
event on the Forerunner 255S and 70; it fails on a watchdog trip, and
the last code left on the screen must decode (bitmap path on the 70).
- make memtest checks the glance (DIAG glance, budget 70 % of 64 KB).
- screenshots.sh launches the app again after the flow and compares the
glance with the favourite's code (glance_code.png on 7 watches); the
About goldens show 0.8.0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'docker')
| -rwxr-xr-x | docker/scripts/app-diag.sh | 63 | ||||
| -rwxr-xr-x | docker/scripts/build-app.sh | 16 | ||||
| -rwxr-xr-x | docker/scripts/screenshots.sh | 33 |
3 files changed, 99 insertions, 13 deletions
diff --git a/docker/scripts/app-diag.sh b/docker/scripts/app-diag.sh index 804d68a..025fd49 100755 --- a/docker/scripts/app-diag.sh +++ b/docker/scripts/app-diag.sh @@ -1,21 +1,74 @@ #!/usr/bin/env bash # Author: cirakg & claude ai -# Summary: Run the debug app on each device in the headless simulator and check start-up time or memory budgets. +# Summary: Run the debug app on each device in the headless simulator and check start-up time, memory, or the watchdog stress test. # -# Usage: app-diag.sh perf|mem DEVICE [DEVICE ...] +# Usage: app-diag.sh perf|mem|watchdog DEVICE [DEVICE ...] # Output: build/diag/<DEVICE>.log (console with DIAG and HARNESS lines) and # build/diag/<perf|mem>-summary.json; verdict from tools/check_budgets.py. +# watchdog: the stress build (source/util/StressTest.mc) on each +# device, build/diag/watchdog-<DEVICE>.log; it fails when the +# simulator reports an error (such as "Watchdog Tripped"), the +# test doesn't finish, or its last code (left on the screen) +# doesn't decode. set -euo pipefail # shellcheck source=ciq-env.sh source "$(dirname "${BASH_SOURCE[0]}")/ciq-env.sh" -kind="${1:?usage: app-diag.sh perf|mem DEVICE [DEVICE ...]}" +kind="${1:?usage: app-diag.sh perf|mem|watchdog DEVICE [DEVICE ...]}" shift -[[ "${kind}" == perf || "${kind}" == mem ]] || die "unknown kind '${kind}' (use perf or mem)" -(($# > 0)) || die "usage: app-diag.sh perf|mem DEVICE [DEVICE ...]" +[[ "${kind}" == perf || "${kind}" == mem || "${kind}" == watchdog ]] || die "unknown kind '${kind}' (use perf, mem or watchdog)" +(($# > 0)) || die "usage: app-diag.sh perf|mem|watchdog DEVICE [DEVICE ...]" ciq_require_sdk ciq_require_key +# The stress test takes a few minutes per device (about 3,500 job steps at +# 50 ms on the 512 KB watches). +WATCHDOG_TIMEOUT_S=1200 +STRESS_ITEMS=10 + +if [[ "${kind}" == watchdog ]]; then + for device in "$@"; do + build-app.sh stress "${device}" + done + ciq_start_display + ciq_start_simulator + mkdir -p "${BUILD_DIR}/diag" + failed=0 + for device in "$@"; do + log="${BUILD_DIR}/diag/watchdog-${device}.log" + log "watchdog stress test on ${device}" + ciq_launch_app "${device}" "${log}" stress || log "no first frame on ${device}" + for _ in $(seq 1 "${WATCHDOG_TIMEOUT_S}"); do + grep -q "DIAG stress all done\|Error" "${log}" && break + kill -0 "${CIQ_MONKEYDO_PID}" 2>/dev/null || break + sleep 1 + done + # The last code stays on the screen; it must decode (on most watches + # it was drawn from a bitmap). + decoded=1 + if grep -aq "DIAG stress all done" "${log}"; then + sleep 1 + python3 /work/tools/ui_flow.py --decode "OTPW stress" --device-dir "${CIQ_HOME}/Devices/${device}" \ + --window "$(ciq_simulator_window)" --out "${BUILD_DIR}/diag/watchdog-${device}" >&2 || decoded=0 + fi + ciq_stop_app + grep -a "DIAG stress" "${log}" | sed "s/^/[${device}] /" >&2 || true + done_count="$(grep -ac "DIAG stress done name=" "${log}" || true)" + if grep -aq "Error" "${log}"; then + grep -a "Error" "${log}" | sed "s/^/[${device}] /" >&2 + failed=1 + elif ! grep -aq "DIAG stress all done" "${log}" || ((done_count != STRESS_ITEMS)); then + log "${device}: the stress test did not finish (${done_count} of ${STRESS_ITEMS} items)" + failed=1 + elif ((decoded == 0)); then + failed=1 + fi + done + ((failed == 0)) || die "watchdog stress test failed; logs in build/diag/" + log "watchdog stress test passed on: $*" + exit 0 +fi + for device in "$@"; do build-app.sh debug "${device}" done diff --git a/docker/scripts/build-app.sh b/docker/scripts/build-app.sh index 1a7d59a..5ead272 100755 --- a/docker/scripts/build-app.sh +++ b/docker/scripts/build-app.sh @@ -1,21 +1,22 @@ #!/usr/bin/env bash # Author: cirakg & claude ai -# Summary: Compile the watch app for one device: debug, release, unit-test or UI-test build. +# Summary: Compile the watch app for one device: debug, release, unit-test, UI-test or watchdog stress build. # -# Usage: build-app.sh debug|release|test|uitest DEVICE +# Usage: build-app.sh debug|release|test|uitest|stress DEVICE # Output: build/<mode>/<DEVICE>.prg, and the compiler log next to it. # # Policy (README section 17.7): strict type checking (-l 3), and any compiler # warning fails the build. UI-test builds add uitest.jungle (fixed clock, -# fake entries; see source/util/TestMode.mc). Test builds add test.jungle, so test code never -# reaches debug or release builds; release builds (-r) also drop every +# fake entries; see source/util/TestMode.mc), stress builds stress.jungle (the +# watchdog stress test, source/util/StressTest.mc). Test builds add +# test.jungle, so test code never reaches debug or release builds; release builds (-r) also drop every # (:debug) declaration, such as the diagnostics in source/util/Diag.mc. set -euo pipefail # shellcheck source=ciq-env.sh source "$(dirname "${BASH_SOURCE[0]}")/ciq-env.sh" -mode="${1:?usage: build-app.sh debug|release|test|uitest DEVICE}" -device="${2:?usage: build-app.sh debug|release|test|uitest DEVICE}" +mode="${1:?usage: build-app.sh debug|release|test|uitest|stress DEVICE}" +device="${2:?usage: build-app.sh debug|release|test|uitest|stress DEVICE}" ciq_require_sdk ciq_require_key @@ -29,11 +30,12 @@ case "${mode}" in debug) ;; release) args+=(-r) ;; uitest) jungles="${jungles};/work/uitest.jungle" ;; + stress) jungles="${jungles};/work/stress.jungle" ;; test) jungles="${jungles};/work/test.jungle" args+=(-t) ;; - *) die "unknown build mode '${mode}' (use debug, release, test or uitest)" ;; + *) die "unknown build mode '${mode}' (use debug, release, test, uitest or stress)" ;; esac out_dir="${BUILD_DIR}/${mode}" diff --git a/docker/scripts/screenshots.sh b/docker/scripts/screenshots.sh index 414af52..91477c4 100755 --- a/docker/scripts/screenshots.sh +++ b/docker/scripts/screenshots.sh @@ -9,7 +9,9 @@ # # Uses the UI-test build (uitest.jungle): fake entries, PIN 123456 and a # frozen clock, so every screenshot is reproducible. tools/ui_flow.py -# drives the app and checks the screens. +# drives the app and checks the screens. Then the app is launched again and +# its glance, which now shows the favourite's code (the first run sealed it), +# is checked as glance_code.png. set -euo pipefail # shellcheck source=ciq-env.sh source "$(dirname "${BASH_SOURCE[0]}")/ciq-env.sh" @@ -26,6 +28,34 @@ ciq_start_display ciq_start_simulator out="${BUILD_DIR}/screenshots" + +# A new launch starts in the glance; screenshot it before anything opens the app. +shoot_glance() { + local device="$1" glance_log="${out}/$1/glance.log" + : >"${glance_log}" + monkeydo "${BUILD_DIR}/uitest/${device}.prg" "${device}" >>"${glance_log}" 2>&1 & + CIQ_MONKEYDO_PID=$! + local shown=0 + for _ in $(seq 1 600); do + if grep -q "DIAG shown glance_code" "${glance_log}"; then + shown=1 + break + fi + sleep 0.05 + done + if ((shown == 0)); then + ciq_stop_app + log "${device}: the glance with the favourite's code didn't appear; see ${glance_log}" + return 1 + fi + sleep 1 + local status=0 + python3 /work/tools/ui_flow.py --shot glance_code --device-dir "${CIQ_HOME}/Devices/${device}" \ + --window "$(ciq_simulator_window)" --out "${out}/${device}" --golden "/work/test/golden/${device}" \ + "${approve[@]}" || status=1 + ciq_stop_app + return "${status}" +} mkdir -p "${out}" approve=() [[ "${APPROVE:-0}" == 1 ]] && approve=(--approve) @@ -43,6 +73,7 @@ for device in "$@"; do --window "$(ciq_simulator_window)" --out "${out}/${device}" --golden "/work/test/golden/${device}" \ "${approve[@]}" || failed=1 ciq_stop_app + shoot_glance "${device}" || failed=1 done ((failed == 0)) || die "screenshot checks failed; see build/screenshots/" |
