diff --git a/scripts/regression_test.py b/scripts/regression_test.py index a9afb21..efec4ec 100644 --- a/scripts/regression_test.py +++ b/scripts/regression_test.py @@ -21,6 +21,14 @@ import signal # 项目根加入 sys.path(脚本在 scripts/ 下运行,保证可 import web_server/config) sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +# Windows 控制台默认 GBK:汇总里的 ⚠/❌/✅ 会抛 UnicodeEncodeError, +# 而且崩在"打印汇总"这一步 —— 看起来像脚本挂了、其实探测已经全跑完 +try: + sys.stdout.reconfigure(encoding="utf-8", errors="replace") + sys.stderr.reconfigure(encoding="utf-8", errors="replace") +except Exception: + pass + # 测试模式:禁用 cron 调度器(否则 test_client 会按 DB 里的任务 cron 真跑任务, # 干扰回归/占用设备——实测 ocr关键字任务每 30 分钟触发导致回归超时) os.environ["DISABLE_SCHEDULER"] = "1" @@ -59,14 +67,33 @@ _SKIP_PREFIXES = ( "/api/screen/stream", "/api/screen/thumb", "/api/uiauto/screenshot", "/api/device/screenshot", ) +# 测试用的目标设备:运行期从设备池里挑一台真实的(占位串是池空时的兜底)。 +# 以前这里写死 Tailscale 时代的 100.100.10.11:5555,设备早换了 → 每次回归都要等 +# 好几轮 30s 的 adb connect 超时,还会误报"关键 POST 失败"。 +_TEST_SERIAL = "100.100.10.11:5555" +_SERIAL_PH = "@SERIAL@" + + +def _pick_serial(): + """从设备池里挑一台启用的设备当测试目标(池空则返回占位串)。""" + try: + from core.models import Device, db as _db + with app.app_context(): + d = _db.session.query(Device).filter(Device.enabled.is_(True)).order_by( + Device.serial).first() + return d.serial if d else _TEST_SERIAL + except Exception: + return _TEST_SERIAL + + # 关键业务 POST:用真实参数验证(这些覆盖了核心链路) _KEY_POSTS = [ ("一键亮屏", "/api/device/screen_all", {"mode": "on"}), ("一键息屏", "/api/device/screen_all", {"mode": "off"}), ("剪贴板注入", "/api/tools/clipboard/set", - {"serials": ["100.100.10.11:5555"], "text": "回归测试"}), + {"serials": [_SERIAL_PH], "text": "回归测试"}), ("测试步骤(wait)", "/api/steps/test", - {"serial": "100.100.10.11:5555", + {"serial": _SERIAL_PH, "step": {"type": "wait", "label": "等待", "params": {"max": 1, "min": 1, "probability": 100}}}), ("adb 终端执行", "/api/adb/cmd", {"cmd": "adb devices"}), ("adb 红线拦截", "/api/adb/cmd", {"cmd": "adb kill-server"}), @@ -76,10 +103,21 @@ _KEY_POSTS = [ _EXPECT_REJECT = {"/api/adb/cmd"} +def _sub_serial(obj): + """把请求体里的 @SERIAL@ 占位替换成运行期选定的设备串(支持嵌套 list/dict)。""" + if isinstance(obj, str): + return _TEST_SERIAL if obj == _SERIAL_PH else obj + if isinstance(obj, list): + return [_sub_serial(x) for x in obj] + if isinstance(obj, dict): + return {k: _sub_serial(v) for k, v in obj.items()} + return obj + + def _fill_path_params(rule): """把路由路径参数 替换为测试值(serial 用真实设备)。""" url = rule - url = url.replace("", "100.100.10.11:5555") + url = url.replace("", _TEST_SERIAL) url = url.replace("", "x") url = url.replace("", "x") url = url.replace("", "x") @@ -158,7 +196,12 @@ def main(): print(f"写操作路由: {len(write_rules)} 个(空 body 探测)") # ========== 3. 关键业务 POST(真实参数) ========== + global _TEST_SERIAL + _TEST_SERIAL = _pick_serial() + print(f"测试目标设备: {_TEST_SERIAL}") for name, url, body in _KEY_POSTS: + # 占位符换成运行期挑到的真实设备(含嵌套列表) + body = _sub_serial(body) try: r = c.post(url, json=body, headers=H) j = r.get_json() if r.is_json else None