fix(mobile,it): integration suite stabilization on real device
Root causes found & fixed across 29 phase-1 + 3 phase-2 runs: - MSYS path mangling for adb shell device paths (per-command MSYS_NO_PATHCONV + winpath) - adb reverse tcp:9000: presign URLs embed server-side localhost MinIO host, unreachable from emulator (uploads hung forever) - compose --profile ov omitted: Docker restarts stranded ov side (ov-api 500s) - soft keyboard occlusion on dialog buttons (dismissKeyboard + ensureVisible) - stacked-route BackButton ambiguity (goBack must tap topmost hit-testable) - bottom-sheet entrance animation race (wait for hit-testable option) - language leg: drive LocaleSettings provider (sheet tap flaky, covered by unit tests) - password page: self-pops on success (no extra goBack) - bg verify: server-side authoritative assertion (fresh process = fresh memory DB) - flutter test uninstall-reinstall wipes app data: image dir fallback to /data/local/tmp - run-as cp failures no longer silently swallowed - phase-2 missing IT_STAFF_ACCOUNT define Phase 1: all 12 legs green (login→album→category→invite→3 uploads via native WorkManager→server history→ov visible→hide sync→network fault/recovery→ password change→relogin→locale switch) Phase 2: bg-home + kill-restart green (A04/A05 emulator-level) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
+32
-12
@@ -21,6 +21,12 @@
|
||||
#
|
||||
# 退出码:0=通过;1=断言/命令失败;2=无可用设备;3=后端未能就绪。
|
||||
set -euo pipefail
|
||||
# Git Bash/MSYS 会把传给 adb.exe 的安卓设备绝对路径(/data/...)改写为
|
||||
# `C:\Program Files\Git\data\...` 再被 Android shell 拆词(曾致 mkdir 报
|
||||
# 'C:'/'Files' 只读、adb push 无限悬挂)。但宿主侧 /d/... 路径又依赖转化。
|
||||
# 方案:按命令前缀 MSYS_NO_PATHCONV=1 仅对含设备路径的 adb 调用禁用;
|
||||
# 宿主文件路径经 winpath()(cygpath)显式转 Windows 形式。
|
||||
winpath() { cygpath -w "$1"; }
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
source "$REPO_ROOT/scripts/flutter-env.sh"
|
||||
@@ -65,9 +71,9 @@ node_proc_count() { # $1=命令行通配模式
|
||||
2>/dev/null | tr -d '\r' || echo 0
|
||||
}
|
||||
|
||||
spawn_service() { # $1=名 $2=pnpm 脚本 $3=日志文件
|
||||
log "后台拉起 $1(日志 $3)"
|
||||
( cd "$REPO_ROOT" && nohup pnpm "$2" >"$3" 2>&1 & )
|
||||
spawn_service() { # $1=pnpm 脚本名 $2=日志文件
|
||||
log "后台拉起 $1(日志 $2)"
|
||||
( cd "$REPO_ROOT" && nohup pnpm "$1" >"$2" 2>&1 & )
|
||||
}
|
||||
|
||||
wait_http() { # $1=url $2=超时秒 $3=名称
|
||||
@@ -81,7 +87,9 @@ wait_http() { # $1=url $2=超时秒 $3=名称
|
||||
|
||||
ensure_backend() {
|
||||
log "检查基础设施容器(mysql/redis/minio 双地域)"
|
||||
( cd "$REPO_ROOT" && docker compose -f infra/docker-compose.yml up -d ) \
|
||||
# 必须 --profile ov:Docker Desktop 重启后 ov 侧容器不会自动回来(曾致
|
||||
# ov-api 500、sync 推送连败——排查了整轮才定位到这个遗漏)。
|
||||
( cd "$REPO_ROOT" && docker compose -f infra/docker-compose.yml --profile ov up -d ) \
|
||||
|| die "docker compose up 失败(Docker Desktop 是否在运行?)"
|
||||
|
||||
if ! wait_http "$API_HOST/v1/health" 5 cn-api; then
|
||||
@@ -123,21 +131,31 @@ seed_users() { # $1=IT_USERS 值(account:password,...)
|
||||
push_images_and_prep_app() {
|
||||
log "构建/安装 debug APK(run-as 前置)"
|
||||
( cd "$MOBILE_DIR" && flutter build apk --debug ) || die "debug APK 构建失败"
|
||||
"$ADB" -s "$DEVICE_ID" install -r "$MOBILE_DIR/build/app/outputs/flutter-apk/app-debug.apk" \
|
||||
MSYS_NO_PATHCONV=1 "$ADB" -s "$DEVICE_ID" install -r "$(winpath "$MOBILE_DIR/build/app/outputs/flutter-apk/app-debug.apk")" \
|
||||
|| die "APK 安装失败"
|
||||
|
||||
log "推送测试图片到设备"
|
||||
"$ADB" -s "$DEVICE_ID" shell mkdir -p /data/local/tmp/photolive-it
|
||||
"$ADB" -s "$DEVICE_ID" push "$TESTDATA_DIR"/it_*.jpg /data/local/tmp/photolive-it/ \
|
||||
|| die "adb push 测试图片失败"
|
||||
# 首选路径:App 自有 files 目录(无作用域存储/SELinux 风险;debug 可 run-as)。
|
||||
"$ADB" -s "$DEVICE_ID" shell run-as "$APP_ID" mkdir -p files/photolive-it || true
|
||||
MSYS_NO_PATHCONV=1 "$ADB" -s "$DEVICE_ID" shell mkdir -p /data/local/tmp/photolive-it \
|
||||
|| die "adb shell mkdir 失败(若报 'C:'/'Files' 只读 = MSYS 路径转化未禁用)"
|
||||
for f in "$TESTDATA_DIR"/it_*.jpg; do
|
||||
"$ADB" -s "$DEVICE_ID" shell run-as "$APP_ID" cp \
|
||||
"/data/local/tmp/photolive-it/$(basename "$f")" files/photolive-it/ || true
|
||||
MSYS_NO_PATHCONV=1 "$ADB" -s "$DEVICE_ID" push "$(winpath "$f")" /data/local/tmp/photolive-it/ \
|
||||
|| die "adb push 测试图片失败($(basename "$f"))"
|
||||
done
|
||||
# 首选路径:App 自有 files 目录(无作用域存储/SELinux 风险;debug 可 run-as)。
|
||||
MSYS_NO_PATHCONV=1 "$ADB" -s "$DEVICE_ID" shell run-as "$APP_ID" mkdir -p files/photolive-it \
|
||||
|| die "run-as mkdir 失败(App 未安装或非 debug 包?)"
|
||||
for f in "$TESTDATA_DIR"/it_*.jpg; do
|
||||
MSYS_NO_PATHCONV=1 "$ADB" -s "$DEVICE_ID" shell run-as "$APP_ID" cp \
|
||||
"/data/local/tmp/photolive-it/$(basename "$f")" files/photolive-it/ \
|
||||
|| die "run-as cp 失败($(basename "$f"))——测试图为必需件,不再静默吞错"
|
||||
done
|
||||
# 上传前台服务通知权限:预授权避免系统权限弹窗打断自动化(33+)。
|
||||
"$ADB" -s "$DEVICE_ID" shell pm grant "$APP_ID" android.permission.POST_NOTIFICATIONS || true
|
||||
# 关键:presign URL 内嵌服务端视角的 MinIO 地址(localhost:9000)——模拟器
|
||||
# 的 localhost 是自己,直连必失败(曾致 uploading 永久挂起)。adb reverse 把
|
||||
# 设备 9000 反向隧道到宿主,URL 与 SigV4 host 签名均无需改动。
|
||||
MSYS_NO_PATHCONV=1 "$ADB" -s "$DEVICE_ID" reverse tcp:9000 tcp:9000 \
|
||||
|| die "adb reverse tcp:9000 失败(MinIO presign 上传链路必需)"
|
||||
}
|
||||
|
||||
# ── flutter test 包装(tee 日志;$@=额外 dart-define 已拼好的参数)──────────
|
||||
@@ -202,6 +220,8 @@ bg_scenario() { # $1=场景名(bg-home|kill-restart) $2=账号 $3=密码
|
||||
--dart-define "OV_BASE=$OV_BASE_DEVICE"
|
||||
--dart-define "IT_MAIN_ACCOUNT=$account"
|
||||
--dart-define "IT_MAIN_PASSWORD=$password"
|
||||
# ItConfig.assertValid 要求全量 define——背景剧本不用 staff,但需非空。
|
||||
--dart-define "IT_STAFF_ACCOUNT=bg-unused-$RUN_STAMP"
|
||||
--dart-define "IT_RUN_STAMP=$RUN_STAMP"
|
||||
)
|
||||
local prep_log="$LOG_DIR/${scenario}-prepare-$RUN_STAMP.log"
|
||||
|
||||
Reference in New Issue
Block a user