101 lines
5.0 KiB
Bash
101 lines
5.0 KiB
Bash
|
|
#!/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: ~3–7 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 ]
|