add install package smoke test
This commit is contained in:
178
scripts/test-personal-install-packages.sh
Executable file
178
scripts/test-personal-install-packages.sh
Executable file
@@ -0,0 +1,178 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
ROOT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
|
||||||
|
DIRECT_COMPOSE="$ROOT_DIR/packages/reactive-resume-personal-direct/compose.yml"
|
||||||
|
DIRECT_ENV="$ROOT_DIR/packages/reactive-resume-personal-direct/.env"
|
||||||
|
QNAP_COMPOSE="$ROOT_DIR/packages/reactive-resume-personal-qnap-nas/compose-Nas.yml"
|
||||||
|
QNAP_PATCH_DIR="$ROOT_DIR/packages/reactive-resume-personal-qnap-nas/patches"
|
||||||
|
DIRECT_PATCH_DIR="$ROOT_DIR/packages/reactive-resume-personal-direct/patches"
|
||||||
|
QNAP_ZIP="$ROOT_DIR/dist/reactive-resume-personal-qnap-nas-20260520.zip"
|
||||||
|
DIRECT_ZIP="$ROOT_DIR/dist/reactive-resume-personal-direct-20260520.zip"
|
||||||
|
IMAGE="amruthpillai/reactive-resume:latest"
|
||||||
|
PROJECT="reactive-resume-personal"
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '\n[TEST] %s\n' "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
printf '\n[FAIL] %s\n' "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_direct() {
|
||||||
|
docker compose -f "$DIRECT_COMPOSE" --env-file "$DIRECT_ENV" down -v >/dev/null 2>&1 || true
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_tmp() {
|
||||||
|
if [ -n "${TMP_DIR:-}" ] && [ -d "$TMP_DIR" ]; then
|
||||||
|
rm -rf "$TMP_DIR"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_all() {
|
||||||
|
cleanup_direct
|
||||||
|
cleanup_tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup_all HUP INT TERM EXIT
|
||||||
|
|
||||||
|
cd "$ROOT_DIR"
|
||||||
|
|
||||||
|
log "检查补丁脚本语法"
|
||||||
|
sh -n "$QNAP_PATCH_DIR/reactive-resume-runtime-patch.sh"
|
||||||
|
sh -n "$QNAP_PATCH_DIR/reactive-resume-entrypoint.sh"
|
||||||
|
sh -n "$DIRECT_PATCH_DIR/reactive-resume-runtime-patch.sh"
|
||||||
|
sh -n "$DIRECT_PATCH_DIR/reactive-resume-entrypoint.sh"
|
||||||
|
|
||||||
|
log "检查 Compose 配置可解析"
|
||||||
|
docker compose -f "$QNAP_COMPOSE" config >/tmp/reactive-resume-qnap-compose-test.yml
|
||||||
|
docker compose -f "$DIRECT_COMPOSE" --env-file "$DIRECT_ENV" config >/tmp/reactive-resume-direct-compose-test.yml
|
||||||
|
grep -q 'reactive-resume-entrypoint.sh' /tmp/reactive-resume-qnap-compose-test.yml
|
||||||
|
grep -q 'reactive-resume-entrypoint.sh' /tmp/reactive-resume-direct-compose-test.yml
|
||||||
|
|
||||||
|
log "检查 zip 安装包内容"
|
||||||
|
unzip -t "$QNAP_ZIP" >/dev/null
|
||||||
|
unzip -t "$DIRECT_ZIP" >/dev/null
|
||||||
|
unzip -l "$QNAP_ZIP" | grep -q 'reactive_resume/compose-Nas.yml'
|
||||||
|
unzip -l "$QNAP_ZIP" | grep -q 'reactive_resume/patches/reactive-resume-entrypoint.sh'
|
||||||
|
unzip -l "$QNAP_ZIP" | grep -q 'reactive_resume/patches/reactive-resume-runtime-patch.sh'
|
||||||
|
unzip -l "$DIRECT_ZIP" | grep -q 'reactive-resume-personal-direct/compose.yml'
|
||||||
|
unzip -l "$DIRECT_ZIP" | grep -q 'reactive-resume-personal-direct/patches/reactive-resume-entrypoint.sh'
|
||||||
|
|
||||||
|
if unzip -p "$QNAP_ZIP" 'reactive_resume/*' 2>/dev/null | grep -E 'isiseg|10004|Reactive_Resume_Personal|/share/Container/Reactive_Resume_Personal' >/dev/null; then
|
||||||
|
fail "QNAP zip 中仍有旧域名、旧端口或旧路径"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "真实启动 direct 包并检查健康状态"
|
||||||
|
cleanup_direct
|
||||||
|
docker compose -f "$DIRECT_COMPOSE" --env-file "$DIRECT_ENV" up -d postgres reactive-resume seed
|
||||||
|
|
||||||
|
attempt=0
|
||||||
|
until curl -fsS "http://127.0.0.1:3004/api/health" >/tmp/reactive-resume-health.json 2>/dev/null; do
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
if [ "$attempt" -ge 60 ]; then
|
||||||
|
docker logs "$PROJECT-reactive-resume-1" --tail 200 >&2 || true
|
||||||
|
fail "direct 包启动后 /api/health 未在 60 秒内就绪"
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
docker wait "$PROJECT-seed-1" >/tmp/reactive-resume-seed-exit
|
||||||
|
seed_status="$(docker inspect "$PROJECT-seed-1" --format '{{.State.ExitCode}}' 2>/dev/null || printf 'missing')"
|
||||||
|
[ "$seed_status" = "0" ] || fail "seed 容器退出码不是 0:$seed_status"
|
||||||
|
|
||||||
|
attempt=0
|
||||||
|
until curl -fsS -I "http://127.0.0.1:3004/audience/resume" >/tmp/reactive-resume-audience.headers 2>/dev/null \
|
||||||
|
&& grep -q '200 OK' /tmp/reactive-resume-audience.headers; do
|
||||||
|
attempt=$((attempt + 1))
|
||||||
|
if [ "$attempt" -ge 30 ]; then
|
||||||
|
docker logs "$PROJECT-reactive-resume-1" --tail 200 >&2 || true
|
||||||
|
fail "seed 完成后 /audience/resume 未在 30 秒内返回 200"
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
docker logs "$PROJECT-reactive-resume-1" --tail 200 >/tmp/reactive-resume-direct.log 2>&1 || true
|
||||||
|
if grep -E 'Cannot find module|Buffer is not defined|Unexpected end of input' /tmp/reactive-resume-direct.log >/dev/null; then
|
||||||
|
cat /tmp/reactive-resume-direct.log >&2
|
||||||
|
fail "direct 包日志仍包含已知启动或前端错误"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "离线检查 arm64/QNAP 镜像布局"
|
||||||
|
ARM64_DIGEST="$(
|
||||||
|
docker manifest inspect "$IMAGE" \
|
||||||
|
| node -e '
|
||||||
|
let source = "";
|
||||||
|
process.stdin.on("data", (chunk) => source += chunk);
|
||||||
|
process.stdin.on("end", () => {
|
||||||
|
const manifest = JSON.parse(source);
|
||||||
|
const arm = manifest.manifests.find((item) => item.platform?.os === "linux" && item.platform?.architecture === "arm64");
|
||||||
|
if (!arm) process.exit(2);
|
||||||
|
process.stdout.write(arm.digest);
|
||||||
|
});
|
||||||
|
'
|
||||||
|
)"
|
||||||
|
|
||||||
|
TMP_DIR="$(mktemp -d)"
|
||||||
|
CID="$(docker create --platform linux/arm64 "$IMAGE@$ARM64_DIGEST" 2>/dev/null || true)"
|
||||||
|
[ -n "$CID" ] || fail "无法创建 arm64 镜像容器用于离线检查"
|
||||||
|
docker export "$CID" -o "$TMP_DIR/arm64-root.tar"
|
||||||
|
docker rm "$CID" >/dev/null
|
||||||
|
mkdir -p "$TMP_DIR/arm64-root"
|
||||||
|
tar -xf "$TMP_DIR/arm64-root.tar" -C "$TMP_DIR/arm64-root"
|
||||||
|
|
||||||
|
[ -f "$TMP_DIR/arm64-root/app/apps/server/dist/index.mjs" ] || fail "arm64 镜像中未找到 /app/apps/server/dist/index.mjs"
|
||||||
|
[ -d "$TMP_DIR/arm64-root/app/apps/web/dist/assets" ] || fail "arm64 镜像中未找到 /app/apps/web/dist/assets"
|
||||||
|
|
||||||
|
perl -0pe "
|
||||||
|
s#/app/apps#$TMP_DIR/arm64-root/app/apps#g;
|
||||||
|
s#for candidate in $TMP_DIR/arm64-root/app/apps/web /app#for candidate in $TMP_DIR/arm64-root/app/apps/web $TMP_DIR/arm64-root/app#g;
|
||||||
|
s#find /app#find $TMP_DIR/arm64-root/app#g;
|
||||||
|
s#APP_DIR=\"/app\"#APP_DIR=\"$TMP_DIR/arm64-root/app\"#g;
|
||||||
|
s#under /app#under $TMP_DIR/arm64-root/app#g;
|
||||||
|
" "$QNAP_PATCH_DIR/reactive-resume-runtime-patch.sh" > "$TMP_DIR/runtime-patch-arm64-test.sh"
|
||||||
|
sh "$TMP_DIR/runtime-patch-arm64-test.sh" >/tmp/reactive-resume-arm64-runtime.log 2>&1 || {
|
||||||
|
cat /tmp/reactive-resume-arm64-runtime.log >&2
|
||||||
|
fail "arm64 离线运行 runtime patch 失败"
|
||||||
|
}
|
||||||
|
|
||||||
|
grep -R 'rr-browser-buffer-polyfill' "$TMP_DIR/arm64-root/app/apps/web/dist/assets" >/dev/null \
|
||||||
|
|| fail "arm64 public PDF bundle 未注入 Buffer polyfill"
|
||||||
|
grep -R -F 'replace(/[\\/:*?"<>|]/g' "$TMP_DIR/arm64-root/app/apps/web/dist/assets" >/dev/null \
|
||||||
|
|| fail "arm64 文件名 bundle 未改为按标题下载"
|
||||||
|
grep -q 'function generateFilename(prefix, extension)' "$TMP_DIR/arm64-root/app/apps/server/dist/index.mjs" \
|
||||||
|
|| fail "arm64 server entry 未包含 generateFilename"
|
||||||
|
grep -F 'filename.replace(/[\\/:*?"<>|]/g' "$TMP_DIR/arm64-root/app/apps/server/dist/index.mjs" >/dev/null \
|
||||||
|
|| fail "arm64 server entry 未改为按标题生成下载文件名"
|
||||||
|
|
||||||
|
perl -0pe "
|
||||||
|
s#/app/apps#$TMP_DIR/arm64-root/app/apps#g;
|
||||||
|
s#cd /app#cd $TMP_DIR/arm64-root/app#g;
|
||||||
|
s#find /app#find $TMP_DIR/arm64-root/app#g;
|
||||||
|
s#under /app#under $TMP_DIR/arm64-root/app#g;
|
||||||
|
" "$QNAP_PATCH_DIR/reactive-resume-entrypoint.sh" > "$TMP_DIR/entrypoint-arm64-test.sh"
|
||||||
|
mkdir -p "$TMP_DIR/fakebin"
|
||||||
|
{
|
||||||
|
printf '#!/bin/sh\n'
|
||||||
|
printf 'printf "PWD=%%s\\n" "$PWD" > "%s/entrypoint-result.txt"\n' "$TMP_DIR"
|
||||||
|
printf 'printf "ARGS=%%s\\n" "$*" >> "%s/entrypoint-result.txt"\n' "$TMP_DIR"
|
||||||
|
} > "$TMP_DIR/fakebin/docker-entrypoint.sh"
|
||||||
|
chmod +x "$TMP_DIR/fakebin/docker-entrypoint.sh"
|
||||||
|
PATH="$TMP_DIR/fakebin:$PATH" sh "$TMP_DIR/entrypoint-arm64-test.sh" >/tmp/reactive-resume-arm64-entrypoint.log 2>&1 || {
|
||||||
|
cat /tmp/reactive-resume-arm64-entrypoint.log >&2
|
||||||
|
fail "arm64 entrypoint 选择测试失败"
|
||||||
|
}
|
||||||
|
|
||||||
|
grep -q "PWD=$TMP_DIR/arm64-root/app" "$TMP_DIR/entrypoint-result.txt" \
|
||||||
|
|| fail "arm64 entrypoint 未切换到 /app"
|
||||||
|
grep -q "ARGS=node apps/server/dist/index.mjs" "$TMP_DIR/entrypoint-result.txt" \
|
||||||
|
|| fail "arm64 entrypoint 未选择 apps/server/dist/index.mjs"
|
||||||
|
|
||||||
|
log "清理 direct 测试容器"
|
||||||
|
cleanup_direct
|
||||||
|
|
||||||
|
log "全部测试通过"
|
||||||
|
printf 'direct health: %s\n' "$(cat /tmp/reactive-resume-health.json)"
|
||||||
|
printf 'arm64 digest: %s\n' "$ARM64_DIGEST"
|
||||||
Reference in New Issue
Block a user