Closer/qa/entrypoint_smoke.sh

101 lines
5.0 KiB
Bash
Raw Permalink Normal View History

#!/usr/bin/env bash
# qa/entrypoint_smoke.sh — Cold-start / entry-point launch-integrity smoke.
#
# WHY THIS EXISTS: a whole bug class makes the app "open and immediately close" on a REAL notification
# cold-start (e.g. the splash-exit `provider.iconView` NPE — the OS hands over a splash with no icon on
# the notification/PendingIntent launch path). It breaks EVERY notification at once (shared cold-start
# path) yet is invisible to `adb am start` (different launch path) and to the normal launcher icon.
# The only reliable catch is a real push, delivered to a genuinely killed app (`am kill`, NOT
# `am force-stop` — force-stopped apps are excluded from FCM), tapped from the shade.
#
# For each entry the app must: OPEN, STAY UP (process alive, 0 FATAL), and land OFF the launcher.
# Emulator FCM-to-killed-app is flaky (FcmRetry); undeliverable cases are reported BLOCKED, not FAIL —
# only an actual open-and-close / crash is a FAIL.
#
# Usage: qa/entrypoint_smoke.sh <serial> [recipient_uid]
# qa/entrypoint_smoke.sh emulator-5556 imDjjOTTQvXGGjyUhUc5JSeHWkU2
# Env overrides: PKG, SA_JSON, COUPLE_ID.
# Runtime: ~37 min (flaky emulator FCM adds retries). Run in the background and read the matrix.
# Exit 0 only if zero FAIL (BLOCK = undeliverable push, environmental — rerun, not an app bug).
set -u
SERIAL="${1:-emulator-5554}"
RUID="${2:-}"
PKG="${PKG:-closer.app}"
HERE="$(cd "$(dirname "$0")" && pwd)"
export NODE_PATH="${NODE_PATH:-$HERE/../functions/node_modules}"
PASS=0; FAIL=0; BLOCKED=0
adbs() { adb -s "$SERIAL" "$@"; }
alive() { adbs shell pidof "$PKG" 2>/dev/null | tr -d '\r'; }
crashed() { adbs logcat -d -t 1500 2>/dev/null | grep -E "FATAL EXCEPTION|getIconView|Force finishing.*$PKG" | grep -v AppsFilter | head -3; }
on_launcher() { adbs shell dumpsys activity activities 2>/dev/null | grep -m1 "ResumedActivity" | grep -qi "launcher"; }
ok() { echo " PASS $1"; PASS=$((PASS+1)); }
bad() { echo " FAIL $1 [$2]"; FAIL=$((FAIL+1)); }
blkd() { echo " BLOCK $1 [$2]"; BLOCKED=$((BLOCKED+1)); }
verify() { # <label> — the real check: app opened and STAYED (no crash/close)
local c a; c="$(crashed)"; a="$(alive)"
if [ -n "$a" ] && [ -z "$c" ] && ! on_launcher; then ok "$1"
else bad "$1" "alive='${a:-none}' crash='${c:-none}' onLauncher=$(on_launcher && echo yes || echo no)"; fi
}
settle_fcm() { adbs shell monkey -p "$PKG" -c android.intent.category.LAUNCHER 1 >/dev/null 2>&1; sleep 15; adbs shell input keyevent KEYCODE_HOME >/dev/null 2>&1; sleep 1; }
# find the QA-SMOKE:<type> notification in the shade; echoes "x y" if present
find_notif() { # <type>
adbs shell cmd statusbar expand-notifications >/dev/null 2>&1; sleep 2
adbs shell uiautomator dump /sdcard/sm.xml >/dev/null 2>&1
adbs pull /sdcard/sm.xml "/tmp/sm_${SERIAL}.xml" >/dev/null 2>&1
python3 - "/tmp/sm_${SERIAL}.xml" "$1" <<'PY'
import re,sys
xml=open(sys.argv[1],encoding="utf-8",errors="ignore").read(); want="QA-SMOKE:"+sys.argv[2]
for n in re.findall(r'<node[^>]*>',xml):
t=re.search(r'text="([^"]*)"',n)
if t and want in t.group(1):
b=re.search(r'bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"',n)
if b: print((int(b.group(1))+int(b.group(3)))//2,(int(b.group(2))+int(b.group(4)))//2); break
PY
}
echo "== entrypoint smoke :: $SERIAL =="
settle_fcm # clear 'stopped' flag, register token, give FCM time to connect
# 1) Launcher icon cold-start.
adbs shell am kill "$PKG" >/dev/null 2>&1; sleep 2
adbs logcat -c 2>/dev/null
adbs shell monkey -p "$PKG" -c android.intent.category.LAUNCHER 1 >/dev/null 2>&1
sleep 6
verify "launcher cold-start"
# 2) Notification cold-starts (real push -> killed app -> tap).
if [ -n "$RUID" ]; then
for CASE in \
"partner_started_game|game_type=this_or_that" \
"partner_completed_part|game_type=this_or_that" \
"partner_finished_game|game_type=wheel" \
"chat_message|conversation_id=main" \
"partner_answered|" ; do
TYPE="${CASE%%|*}"; EXTRAS="${CASE#*|}"
XY=""; ATTEMPT=0
while [ -z "$XY" ] && [ "$ATTEMPT" -lt 2 ]; do
ATTEMPT=$((ATTEMPT+1))
[ "$ATTEMPT" -eq 2 ] && settle_fcm # 2nd try: relaunch to kick the FCM transport
adbs shell am kill "$PKG" >/dev/null 2>&1; sleep 2
adbs logcat -c 2>/dev/null
OUT="$(node "$HERE/qa_push.js" "$RUID" "$TYPE" $EXTRAS 2>&1)"
if ! echo "$OUT" | grep -q "^SENT"; then bad "notif:$TYPE (send)" "$OUT"; break; fi
# poll for delivery up to ~24s
for _ in 1 2 3 4 5 6; do sleep 4; XY="$(find_notif "$TYPE")"; [ -n "$XY" ] && break; adbs shell cmd statusbar collapse >/dev/null 2>&1; done
done
if echo "${OUT:-}" | grep -q "^SENT" && [ -z "$XY" ]; then blkd "notif:$TYPE" "not delivered (flaky emulator FCM); rerun"; continue; fi
[ -z "$XY" ] && continue
adbs shell input tap $XY >/dev/null 2>&1
sleep 8
verify "notif:$TYPE tap -> opens & stays"
done
else
echo " (notification cases skipped — pass a recipient_uid to run them)"
fi
echo "== result: ${PASS} passed, ${FAIL} failed, ${BLOCKED} blocked =="
[ "$FAIL" -eq 0 ]