Files
mtgodot-poc/script/live_smoke_test.sh
T
shenandshen c93894313a fix: 装备属性面板避让逻辑 + 多项功能更新
- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧
- inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域
- 包含其他累积的功能开发和测试文件
2026-09-21 16:38:59 -07:00

173 lines
5.3 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 真实 40250 服务器端到端冒烟测试。
#
# 用法:
# ./script/live_smoke_test.sh
# ./script/live_smoke_test.sh --no-build
# ./script/live_smoke_test.sh --no-mutations
# ./script/live_smoke_test.sh --no-reconnect
# MT_SMOKE_PHASE_COMMAND=/logout ./script/live_smoke_test.sh --no-build --no-reconnect
#
# 账号和密码优先从环境变量读取;未提供时安全地交互输入,不写入脚本。
# 服务器地址与客户端一样经 project/net/serverinfo.gd 解析,不在脚本里写死。
# 不要在本脚本中启用 set -x。
set -euo pipefail
set +x
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO="$(cd "$SCRIPT_DIR/.." && pwd)"
APP="${MT_SMOKE_APP:-$REPO/build/export/mtgodot-poc.app}"
EXECUTABLE="$APP/Contents/MacOS/mtgodot-poc"
ARTIFACT_DIR="${MT_SMOKE_OUTPUT:-$REPO/build/live-smoke}"
LOG="$ARTIFACT_DIR/live-smoke.log"
REPORT="$ARTIFACT_DIR/live-smoke-report.json"
CONFIG_FILE="${MT_SMOKE_CONFIG:-$REPO/.env.live-smoke.local}"
BUILD=1
MUTATIONS=1
RECONNECT=1
usage() {
cat <<'EOF'
用法: ./script/live_smoke_test.sh [选项]
选项:
--no-build 使用现有 APP,不重新打包
--no-mutations 只做登录、进游戏和数据读取,不发送移动/聊天/重连包
--no-reconnect 做移动和聊天,但跳过重连
--reconnect-only 只测试登录/主动重连,不发送移动、聊天或施法
--help 显示帮助
环境变量:
MT_ACCOUNT / MT_PASSWORD 可预先提供账号密码,未提供时交互输入
MT_CHAR_SLOT=N 指定角色槽位;不设置时自动选择第一个角色
MT_SMOKE_PHASE_COMMAND=/logout 进场后发送服务器阶段命令并验证 peer-close 后回 LoginPhase
MT_GODOT 解析 serverinfo 用的 godot,默认 godot
EOF
}
while [ "$#" -gt 0 ]; do
case "$1" in
--no-build) BUILD=0 ;;
--no-mutations) MUTATIONS=0; RECONNECT=0 ;;
--no-reconnect) RECONNECT=0 ;;
--reconnect-only) MUTATIONS=0; RECONNECT=1 ;;
--help) usage; exit 0 ;;
*) echo "未知选项: $1" >&2; usage >&2; exit 2 ;;
esac
shift
done
cd "$REPO"
mkdir -p "$ARTIFACT_DIR"
if [ -f "$CONFIG_FILE" ]; then
# shellcheck disable=SC1090
. "$CONFIG_FILE"
fi
if [ -z "${MT_ACCOUNT:-}" ]; then
read -r -s -p "账号: " MT_ACCOUNT
echo
fi
if [ -z "${MT_PASSWORD:-}" ]; then
read -r -s -p "密码: " MT_PASSWORD
echo
fi
if [ -z "${MT_ACCOUNT:-}" ] || [ -z "${MT_PASSWORD:-}" ]; then
echo "账号和密码不能为空" >&2
exit 2
fi
if [ "$BUILD" -eq 1 ]; then
echo "== build release =="
./build-macos-client.sh release
fi
if [ ! -x "$EXECUTABLE" ]; then
echo "找不到可执行 APP$EXECUTABLE" >&2
echo "请先运行 ./build-macos-client.sh release" >&2
exit 2
fi
echo "== check server ports =="
# 登录页默认 server 0 / 第一个频道;与 AppFlow 同一 ServerInfo 解析。
ADDRESS_LINE="$("${MT_GODOT:-godot}" --headless --path project --script print_server_address.gd 2>/dev/null | grep '^SERVER_ADDRESS ' || true)"
if [ -z "$ADDRESS_LINE" ]; then
echo "无法从 serverinfo 解析服务器地址" >&2
exit 2
fi
read -r AUTH_HOST AUTH_PORT GAME_HOST GAME_PORT <<<"$(node -e '
const a = JSON.parse(process.argv[1].slice("SERVER_ADDRESS ".length));
process.stdout.write([a.auth_host, a.auth_port, a.game_host, a.game_port].join(" "));
' "$ADDRESS_LINE")"
for endpoint in "$AUTH_HOST:$AUTH_PORT" "$GAME_HOST:$GAME_PORT"; do
if ! nc -G 3 -z "${endpoint%:*}" "${endpoint##*:}" >/dev/null 2>&1; then
echo "服务器端口不可达:$endpoint" >&2
exit 3
fi
done
if pgrep -x mtgodot-poc >/dev/null; then
echo "已有客户端运行,请先关闭后再执行独立登录测试。" >&2
exit 2
fi
export MT_PROTOCOL=classic
export MT_AUTOLOGIN=1
export MT_TEST_MODE=smoke
export MT_ACCOUNT
export MT_PASSWORD
export MT_SMOKE_MUTATIONS="$MUTATIONS"
export MT_SMOKE_RECONNECT="$RECONNECT"
export MT_TEST_REPORT="$REPORT"
rm -f "$REPORT"
echo "== run live smoke =="
echo "log: $LOG"
echo "report: $REPORT"
set +e
# 日志落盘前脱敏;PIPESTATUS[0] 仍是 APP 的真实退出码。
env -u MT_ASSETS "$EXECUTABLE" 2>&1 | node script/redact_stream.mjs | tee "$LOG"
APP_STATUS=${PIPESTATUS[0]}
set -e
if [ ! -f "$REPORT" ]; then
echo "未生成本次测试报告,APP 可能在测试状态机启动前崩溃。" >&2
echo "LIVE_SMOKE RESULT: FAIL (missing report)" >&2
exit 4
fi
echo "== report =="
if command -v jq >/dev/null 2>&1; then
REPORT_STATUS=$(jq -r '.status // empty' "$REPORT")
jq -r '"status=" + .status, "duration=" + (.duration_seconds|tostring) + "s", ( .failures[]? | "failure=" + . )' "$REPORT"
else
REPORT_STATUS=""
if grep -q '"status"[[:space:]]*:[[:space:]]*"PASS"' "$REPORT"; then
REPORT_STATUS=PASS
fi
grep -E '"status"|"failures"' "$REPORT" || true
fi
if [ "$APP_STATUS" -ne 0 ]; then
echo "LIVE_SMOKE RESULT: FAIL (APP exit=$APP_STATUS)" >&2
echo "最近的崩溃报告:"
ls -1t "$HOME/Library/Logs/DiagnosticReports/mtgodot-poc-"*.ips 2>/dev/null | head -n 3 || true
exit "$APP_STATUS"
fi
# 与 package_render_test.sh / validate_playable_report.mjs 相同的完整日志门禁。
if grep -nE 'SCRIPT ERROR|Parse Error|^ERROR:|leaked at exit|shaders of type .* were never freed' "$LOG"; then
echo "LIVE_SMOKE RESULT: FAIL (log exit gate)" >&2
exit 1
fi
if [ "$REPORT_STATUS" != "PASS" ]; then
echo "LIVE_SMOKE RESULT: FAIL (report status=$REPORT_STATUS)" >&2
exit 1
fi
echo "LIVE_SMOKE RESULT: PASS"