AI_UIAutomation/scripts/run-p0-all.sh

285 lines
17 KiB
Bash
Executable File

#!/bin/bash
# 跑所有已调通的 P0 必测用例,累积出一份合并报告。
# 规则:ADD 阶段跑完后,失败的添加在进 CONTROL 前再重试最多 2 次;2 次仍失败则放弃、继续后续用例。
# SOAK_MODE=1:跨多次 vitest run 累积到 reports/.results.json,末尾 gen-combined 出报告。
set -u
cd /Users/woan/Desktop/AI_UIAutomation
LOG=reports/p0-all.log
export PLATFORM=android SOAK_MODE=1 SKIP_PROTO_NET=1
export LOCK_DEVICE="Lock 6D" LOCK_PRO_DEVICE="Lock Pro DE" BT_DEVICE="Blind Tilt 42"
# PLUG_CTRL_DEVICE 不导出:让 plug 控制走 getDeviceName('plug') → 注册表实际名(如 "Plug EU"),不写死
rm -f reports/.results.json
# 添加命令(含各设备专属 env);灯类/EU plug 用品类入口区分
ADD_CMDS=(
"npx vitest run tests/bot/bot_connect.test.ts"
"npx vitest run tests/meter/meter_connect.test.ts"
"npx vitest run tests/meter/meter_plus_connect.test.ts"
"npx vitest run tests/meter/outdoor_meter_connect.test.ts"
"npx vitest run tests/meter/meter_pro_connect.test.ts"
"npx vitest run tests/sensor/motion_sensor_connect.test.ts"
"npx vitest run tests/sensor/presence_sensor_connect.test.ts"
"npx vitest run tests/remote/remote_connect.test.ts"
"npx vitest run tests/curtain/curtain_connect.test.ts"
"CURTAIN_DEVICE='Curtain3 2B' CURTAIN_CALIBRATE=1 npx vitest run tests/curtain/curtain_connect.test.ts"
"CURTAIN_CALIBRATE=1 npx vitest run tests/curtain/curtain3_2025_connect.test.ts"
"npx vitest run tests/water_detector/water_detector_connect.test.ts"
"npx vitest run tests/weather_station/weather_station_connect.test.ts"
"npx vitest run tests/hub/hub_matter_connect.test.ts"
"npx vitest run tests/find_card/find_card_connect.test.ts"
"npx vitest run tests/safety_alarm/safety_alarm_connect.test.ts"
"PLUG_MINI_CATEGORY='Plug Mini (JP)' PLUG_MINI_RELAY=plug_mini npx vitest run tests/plug/plug_mini_connect.test.ts"
"PLUG_MINI_CATEGORY='Plug Mini (US)' PLUG_MINI_RELAY=plug_mini_us npx vitest run tests/plug/plug_mini_connect.test.ts"
"PLUG_MINI_CATEGORY='Plug Mini (EU)' PLUG_MINI_RELAY=plug_mini_eu PLUG_MINI_ONES=332918 npx vitest run tests/plug/plug_mini_connect.test.ts"
"npx vitest run tests/color_bulb/color_bulb_connect.test.ts"
"npx vitest run tests/ceiling_light/ceiling_light_pro_connect.test.ts"
"npx vitest run tests/strip_light/strip_light_connect.test.ts"
"npx vitest run tests/ceiling_light/floor_lamp_connect.test.ts"
"npx vitest run tests/ceiling_light/color_floor_lamp_connect.test.ts"
"npx vitest run tests/strip_light/neon_light_connect.test.ts"
"npx vitest run tests/strip_light/strip_light_3_connect.test.ts"
"npx vitest run tests/robot/robot_s1p_connect.test.ts"
"npx vitest run tests/robot/robot_s10_connect.test.ts"
"npx vitest run tests/keypad/keypad_vision_connect.test.ts"
"npx vitest run tests/keypad/keypad_touch_connect.test.ts"
"npx vitest run tests/aihub/aihub_connect.test.ts -t '通过BLE添加'"
"npx vitest run tests/air_purifier/air_purifier_connect.test.ts"
"npx vitest run tests/humidifier/humidifier2_connect.test.ts"
"npx vitest run tests/ceiling_light/eave_light_connect.test.ts"
"npx vitest run tests/ceiling_light/candle_lamp_connect.test.ts"
"npx vitest run tests/urc/urc_connect.test.ts"
"npx vitest run tests/switch/relay_switch_connect.test.ts"
"RELAY_SWITCH_SUBMODEL='Relay Switch 1PM' RELAY_SWITCH_RELAY=relay_switch_1pm RELAY_SWITCH_DEVICE='Relay Switch 1PM' RELAY_SWITCH_PATTERN='Relay Switch 1PM\\s*[0-9A-Za-z]{0,4}' npx vitest run tests/switch/relay_switch_connect.test.ts"
"RELAY_SWITCH_SUBMODEL='Relay Switch 2PM' RELAY_SWITCH_RELAY=relay_switch_2pm RELAY_SWITCH_DEVICE='Relay Switch 2PM' RELAY_SWITCH_PATTERN='Relay Switch 2PM\\s*[0-9A-Za-z]{0,4}' npx vitest run tests/switch/relay_switch_connect.test.ts"
"npx vitest run tests/hub/hub3_connect.test.ts"
"npx vitest run tests/hub/hub_plus_connect.test.ts"
"npx vitest run tests/aihub/ai_art_frame_connect.test.ts"
"npx vitest run tests/sensor/contact_sensor_connect.test.ts"
"npx vitest run tests/camera/doorbell_connect.test.ts"
"npx vitest run tests/camera/outdoor_ptc_connect.test.ts"
)
CONTROL=(
"npx vitest run tests/meter/meter_control.test.ts"
"METER_DEVICE='Meter 0B' npx vitest run tests/meter/meter_alert_calibration.test.ts"
"METER_DEVICE='Meter Plus C9' METER_ALERT_STEP=UZCtZRPy METER_CALT_STEP=9mheLMDJ METER_CALH_STEP=GSZv8BYm npx vitest run tests/meter/meter_alert_calibration.test.ts"
"METER_DEVICE='Outdoor Meter 6A' METER_ALERT_STEP=QwnZJARA METER_CALT_STEP=Ncg7BDeR METER_CALH_STEP=k6cqKqtZ npx vitest run tests/meter/meter_alert_calibration.test.ts"
"METER_DEVICE='Meter Pro (CO2 Monitor) 6E' METER_ALERT_STEP=JggzNXDo METER_CALT_STEP=L967RGHa METER_CALH_STEP=8Wzaj5pB npx vitest run tests/meter/meter_alert_calibration.test.ts"
"npx vitest run tests/bot/bot_card.test.ts"
"npx vitest run tests/lock/lock_card.test.ts"
"npx vitest run tests/curtain/curtain_control.test.ts"
"CURTAIN_DEVICE='Curtain3 Auto' npx vitest run tests/curtain/curtain_control.test.ts"
"CURTAIN_DEVICE='Curtain3 2025 Auto' npx vitest run tests/curtain/curtain_control.test.ts"
"PLUG_CTRL_DEVICE='Plug JP' npx vitest run tests/plug/plug_mini_control.test.ts"
"PLUG_CTRL_DEVICE='Plug US' npx vitest run tests/plug/plug_mini_control.test.ts"
"PLUG_CTRL_DEVICE='Plug EU' npx vitest run tests/plug/plug_mini_control.test.ts"
"npx vitest run tests/curtain/blind_tilt_control.test.ts"
"npx vitest run tests/humidifier/humidifier2_card.test.ts"
"npx vitest run tests/air_purifier/air_purifier_card.test.ts"
# 灯类首页卡片控制(电源+亮度+色温):通用用例 eave_light_control,按 LIGHT_CARD 覆盖每个灯(textContains 匹配,免后缀)
"LIGHT_REG=eaveLight LIGHT_CARD='Permanent Outdoor Lights' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
"LIGHT_REG=colorBulb LIGHT_CARD='Color Bulb' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
"LIGHT_REG=ceilingLight LIGHT_CARD='Ceiling Light Pro' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
"LIGHT_REG=colorFloorLamp LIGHT_CARD='RGBICWW Floor Lamp' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
"LIGHT_REG=floorLamp LIGHT_CARD='RGBWW Floor Lamp' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
"LIGHT_REG=stripLight LIGHT_CARD='Strip Light SB' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
"LIGHT_REG=stripLight3 LIGHT_CARD='RGBWW Strip Light 3' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
"LIGHT_REG=neonLight LIGHT_CARD='RGBIC Neon Rope Light' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
"LIGHT_REG=candleLamp LIGHT_CARD='Candle Warmer Lamp' npx vitest run tests/ceiling_light/eave_light_control.test.ts"
# ===== 功能页控制(进设备详情页操作,在卡片/弹窗控制之外补充) —— 今日新增调试通过 =====
"npx vitest run tests/lock/lock_control.test.ts"
"npx vitest run tests/curtain/curtain_feature_control.test.ts"
"CURTAIN_DEVICE='Curtain3 Auto' npx vitest run tests/curtain/curtain_feature_control.test.ts"
"CURTAIN_DEVICE='Curtain3 2025 Auto' npx vitest run tests/curtain/curtain_feature_control.test.ts"
"npx vitest run tests/curtain/blind_tilt_feature_control.test.ts"
"npx vitest run tests/plug/plug_feature_control.test.ts"
"npx vitest run tests/air_purifier/air_purifier_feature_control.test.ts"
"npx vitest run tests/humidifier/humidifier2_feature_control.test.ts"
"npx vitest run tests/color_bulb/color_bulb_feature_control.test.ts"
"npx vitest run tests/switch/relay_switch_feature_control.test.ts"
"npx vitest run tests/switch/relay_switch_card.test.ts"
"npx vitest run tests/switch/relay_switch_2pm_control.test.ts"
# 灯类功能页控制(通用 light_feature_control,按 LIGHT_CARD 覆盖每个灯)
"LIGHT_CARD='Permanent Outdoor Lights' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
"LIGHT_CARD='RGBICWW Floor Lamp' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
"LIGHT_CARD='RGBWW Floor Lamp' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
"LIGHT_CARD='RGBWW Strip Light 3' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
"LIGHT_CARD='RGBIC Neon Rope Light' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
"LIGHT_CARD='Ceiling Light Pro' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
"LIGHT_CARD='Candle Warmer Lamp' npx vitest run tests/ceiling_light/light_feature_control.test.ts"
)
TAIL=(
# Keypad 功能页闭环(绑锁+加密码+物理输密码解锁+清理),只跑一次;依赖 ADD 阶段已加 Keypad Vision Pro + 保留的 Lock 6D。
# 必须在 delete_account 之前(账号注销后设备全清)。默认 KEYPAD_CARD=Keypad Vision(Vision Pro 密码用例需覆盖)。
# ⚠️ Keypad Touch 的密码用例暂不支持(继电器物理键未接)→ 不在 P0 跑;仅 Vision Pro 走此用例。
"npx vitest run tests/keypad/keypad_lock_passcode.test.ts"
"STREAM_HOLD_MS=60000 npx vitest run tests/camera/camera_stream.test.ts"
"npx vitest run tests/platform/feedback.test.ts"
"npx vitest run tests/platform/rn_plugin.test.ts"
"npx vitest run tests/platform/create_room.test.ts"
"npx vitest run tests/platform/message_center.test.ts"
"npx vitest run tests/platform/scene_operation.test.ts"
"npx vitest run tests/auth/third_party_login.test.ts"
"npx vitest run tests/auth/eu_login.test.ts"
"npx vitest run tests/auth/register.test.ts"
"npx vitest run tests/auth/forgot_password.test.ts"
"npx vitest run tests/auth/delete_account.test.ts"
"npx vitest run tests/auth/login.test.ts"
)
# 纯 bash 看门狗:macOS 无 timeout/gtimeout。开 job-control(set -m)让命令成独立进程组,
# 超时 SIGTERM 整组(node+vitest worker 一起杀),25s 仍不退再 SIGKILL。appium server(4723)不在组内、不受影响。
# 入参:$1=超时秒, $2=命令, $3=输出文件。返回命令 rc;超时返回 124。
run_with_timeout() {
local secs="$1" cmd="$2" out="$3" pid w rc
set -m
bash -c "$cmd" > "$out" 2>&1 &
pid=$!
set +m
( sleep "$secs"; kill -TERM -"$pid" 2>/dev/null; sleep 25; kill -KILL -"$pid" 2>/dev/null ) >/dev/null 2>&1 &
w=$!
wait "$pid" 2>/dev/null; rc=$?
kill "$w" 2>/dev/null; wait "$w" 2>/dev/null # 命令已结束 → 取消看门狗(若它还在 sleep 计时)
return $rc # 超时时进程被 SIGTERM/KILL → rc=143/137(>128),由调用方判定
}
# 跑一条命令,过滤出结果行;含 "✗ [FAIL]" 视为失败(返回1),否则0(PASS/SKIP)
run_one() {
local cmd="$1" tmp rc
tmp=$(mktemp)
# 硬超时 720s(12min):通过用例最慢 251s、camera_stream 整条 ~521s,720s 绝不误杀;
# 但能兜住 outdoor_ptc 等崩溃后 appium session 销毁卡死(实测单条曾卡 ~48min 拖垮整链)。
run_with_timeout 720 "$cmd" "$tmp"; rc=$?
# 结果摘要 + 诊断/找不到原因都进主日志(方便定位"找不到设备")
grep -E '✓ \[PASS\]|✗ \[FAIL\]|○ \[SKIP\]|结果:|\[诊断\]|找不到|未找到|not found|Unable to perform' "$tmp" | tail -20
if [ $rc -gt 128 ] || [ $rc -eq 124 ]; then
echo "[TIMEOUT] 超过 720s 被强杀(崩溃/卡死,rc=$rc): $cmd"
{ echo "========== TIMEOUT(rc=$rc): $cmd @ $(date '+%F %T') =========="; tail -40 "$tmp"; echo; } >> reports/ctrl-fail.log
rm -f "$tmp"; return 1
fi
if grep -q '✗ \[FAIL\]' "$tmp"; then
# 失败:完整 stdout 存档到 reports/ctrl-fail.log,供后续定位(临时文件随后删)
{ echo "========== FAIL: $cmd @ $(date '+%F %T') =========="; cat "$tmp"; echo; } >> reports/ctrl-fail.log
rm -f "$tmp"; return 1
fi
rm -f "$tmp"; return 0
}
# 恢复手机 WiFi(BLE 控制阶段关了 WiFi)→ 打开并验证 wlan0 拿到 IP(联网成功),最多重试 5 次。
restore_wifi() {
for i in 1 2 3 4 5; do
adb shell svc wifi enable >/dev/null 2>&1
sleep 8
if adb shell ip addr show wlan0 2>/dev/null | grep -q "inet "; then
echo "[WiFi] 已恢复联网(第${i}次)"; return 0
fi
echo "[WiFi] 未联网,重试 ${i}/5..."; sleep 5
done
echo "[WiFi] WARN: 多次重试仍未恢复 WiFi,后续 WiFi 控制/平台/账号用例可能失败"
return 1
}
{
echo "===== $(date '+%F %T') P0 全量回归开始 ====="
echo "----- 复位:删除所有可重加设备(保留 锁/Blind Tilt + 摄像头/门铃,自动化无法重加)-----"
# 锁需物理校准、摄像头需扫码,均跳过添加 → 绝不可删,否则对应控制/拉流用例整晚无设备失败。
# Lock Lite / Video Doorbell 同样保留(Doorbell 关键字覆盖门铃,Lock Lite 关键字覆盖锁丽特)。
if [ -z "${CONTROL_ONLY:-}" ]; then
RESET_EXCEPT=1 KEEP_DEVICES="Lock 6D,Lock Pro DE,Blind Tilt 42" KEEP_KEYWORDS="Cam,Doorbell,Lock Lite" npx ts-node scripts/reset-except.ts 2>&1 | tail -8 || echo "复位异常(继续跑)"
echo "----- ADD 阶段 -----"
FAILED=()
for cmd in "${ADD_CMDS[@]}"; do
echo "--- $(date +%T) $cmd ---"
run_one "$cmd" || { echo "[ADD-FAIL] $cmd"; FAILED+=("$cmd"); }
done
# 规则:失败的添加,进 CONTROL 前重试最多 2 次;仍失败则放弃
if [ ${#FAILED[@]} -gt 0 ]; then
echo "===== 添加失败 ${#FAILED[@]} 个,重试(每个最多2次)====="
STILL=()
for cmd in "${FAILED[@]}"; do
ok=0
for att in 1 2; do
echo "--- 重试 $att/2: $cmd ---"
if run_one "$cmd"; then ok=1; echo "[RETRY-OK] $cmd"; break; fi
done
[ $ok -eq 0 ] && { echo "[RETRY-GIVEUP] $cmd"; STILL+=("$cmd"); }
done
echo "重试后仍失败 ${#STILL[@]} 个(已放弃,继续后续用例)"
fi
else
echo "----- CONTROL_ONLY=1:跳过复位+添加阶段,直接控制现有设备 -----"
fi
# 添加后:打开 Action Panel Settings 所有开关 → 点设备卡片才弹「快捷动作浮层」(灯/加湿器卡片控制依赖;
# 新加设备该开关默认可能 OFF → 否则点卡片进功能页致控制失败)。必须在 CONTROL 之前。
echo "----- 打开 Action Panel Settings 所有开关 -----"
run_one "npx vitest run tests/platform/action_panel_settings.test.ts" || true
echo "----- CONTROL 阶段(BLE + WiFi 各跑一遍,分别打 15975/15974 锚点)-----"
# 跑一遍控制清单。失败靠 vitest 用例级 retry:1(见 vitest.config.ts)就地重试一次,**不再 shell 整文件重跑一轮**(提速:整文件重跑最费时;robust finder + retry:1 已够)。$1=协议标签。
run_control_pass() {
local label="$1" cmd
export VITEST_RETRY=1 # 控制阶段:单个 it 失败自动重跑一次(用例级);添加阶段不受影响
export WAIT_IDLE_TIMEOUT=100 # 控制阶段:把 UiAutomator2 等待空闲从 1000ms 降到 100ms(RN 首页永不 idle,每条命令白等→大幅提速)
local failed=()
for cmd in "${CONTROL[@]}"; do
echo "--- $(date +%T) [$label] $cmd ---"
run_one "$cmd" || failed+=("$cmd")
done
# BLE 轮:失败多为**偶发设备无响应**(BLE 连接抖动)→ 复位蓝牙+下拉刷新恢复连接后,重试失败的一轮。
# (switch-ble.ts = 复位蓝牙 + 下拉刷新首页 + 响应度校验)。WiFi 轮设备在线、不做恢复重试,保持快。
if [ "$label" = "ble" ] && [ ${#failed[@]} -gt 0 ]; then
echo "===== [ble] 控制失败 ${#failed[@]} 个 → 复位蓝牙+下拉刷新后重试一轮 ====="
PLATFORM=android npx ts-node scripts/switch-ble.ts 2>&1 | tail -4 || true
for cmd in "${failed[@]}"; do
echo "--- $(date +%T) [ble][retry] $cmd ---"
run_one "$cmd" && echo "[CTRL-RETRY-OK][ble] $cmd" || echo "[CTRL-RETRY-GIVEUP][ble] $cmd"
done
fi
unset VITEST_RETRY WAIT_IDLE_TIMEOUT
}
if [ -n "${NO_PROTO_SPLIT:-}" ]; then
# ===== 单轮:不分 BLE/WiFi,保持当前 radio 态(WiFi+蓝牙都开),控制清单只跑一遍 =====
echo "===== 控制:单轮(不分协议, radio 保持当前态)====="
run_control_pass all
else
# BLE 阶段:切"仅 BLE"并校验设备已连上(关 WiFi + 复位蓝牙 + 下拉刷新 + 响应度校验 + 重试)。
# 根治"中途切 BLE 后首页卡片全无响应 → BLE 控制整片失败"。失败不阻塞,后续控制照跑。
echo "----- BLE 控制前:切 BLE 并校验设备连上(下拉刷新+重试)-----"
PLATFORM=android npx ts-node scripts/switch-ble.ts 2>&1 | tail -6 || echo "切 BLE 校验异常(继续跑)"
export PROTO=ble
echo "===== 控制 PROTO=ble(手机 WiFi 已关)====="
run_control_pass ble
# 关键:BLE 控制完成后恢复手机 WiFi(带重试)。没 WiFi 后续 WiFi 控制+平台+账号都会挂。
restore_wifi
# WiFi 轮:关蓝牙,强制走 WiFi/云(纯 WiFi 控制,不让 BLE 兜底)。轮后恢复蓝牙。
echo "----- WiFi 控制前:关闭蓝牙(纯 WiFi)-----"
adb shell svc bluetooth disable >/dev/null 2>&1; sleep 3
export PROTO=wifi
echo "===== 控制 PROTO=wifi(手机 WiFi 已恢复, 蓝牙已关)====="
run_control_pass wifi
unset PROTO
adb shell svc bluetooth enable >/dev/null 2>&1; sleep 3 # 恢复蓝牙(平台/账号阶段及收尾)
restore_wifi # 进平台/账号前再确保 WiFi 在线
fi
echo "----- 平台 + 账号阶段 -----"
if [ -z "${CONTROL_ONLY:-}" ]; then
export WAIT_IDLE_TIMEOUT=100 # 平台/账号阶段同样降空闲等待(登录表单/建房间/消息中心 查找多,无添加渲染顾虑)→ 提速
for cmd in "${TAIL[@]}"; do echo "--- $(date +%T) $cmd ---"; run_one "$cmd" || true; done
unset WAIT_IDLE_TIMEOUT
else
echo "----- CONTROL_ONLY=1:跳过平台/账号阶段 -----"
fi
echo "----- 生成合并报告 -----"
npx ts-node scripts/gen-combined.ts P0_All_Android
python3 scripts/gen-p0-report.py reports/p0-all.log reports/P0_Android_真实结果.md 2>&1 | tail -2 # 含 BLE/WiFi 控制成功率表
echo "===== $(date '+%F %T') 完成 ====="
} >> "$LOG" 2>&1