#!/bin/sh set -eu ROOT_DIR=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd) SCRIPT_UNDER_TEST="$ROOT_DIR/bin/prod/deploy_from_package.sh" fail() { printf 'FAIL: %s\n' "$1" >&2 exit 1 } assert_file_exists() { file_path="$1" [ -e "$file_path" ] || fail "expected file to exist: $file_path" } assert_grep() { pattern="$1" target="$2" if ! grep -Eq "$pattern" "$target"; then fail "expected pattern [$pattern] in $target" fi } create_fake_java() { fake_java="$1" cat > "$fake_java" <<'EOF' #!/bin/sh set -eu port="" for arg in "$@"; do case "$arg" in --server.port=*) port=${arg#--server.port=} ;; esac done if [ -z "$port" ]; then echo "missing port" >&2 exit 1 fi while :; do sleep 1 done EOF chmod +x "$fake_java" } create_release_zip() { release_dir="$1" release_zip_name="$2" mkdir -p "$release_dir/package/deploy" "$release_dir/package/__MACOSX/deploy" mkdir -p "$release_dir/package/frontend_payload/dist" "$release_dir/package/frontend_payload/__MACOSX/dist" printf 'new-jar\n' > "$release_dir/package/deploy/ruoyi-admin.jar" printf 'macos-meta\n' > "$release_dir/package/__MACOSX/deploy/._ruoyi-admin.jar" printf 'new\n' > "$release_dir/package/frontend_payload/dist/index.html" printf 'macos-meta\n' > "$release_dir/package/frontend_payload/__MACOSX/dist/._index.html" ( cd "$release_dir/package/frontend_payload" zip -qr "$release_dir/package/dist.zip" dist __MACOSX ) mv "$release_dir/package/dist.zip" "$release_dir/package/deploy/dist.zip" ( cd "$release_dir/package" zip -qr "$release_dir/$release_zip_name" deploy __MACOSX ) } find_free_port() { python3 - <<'PY' import socket sock = socket.socket() sock.bind(("127.0.0.1", 0)) print(sock.getsockname()[1]) sock.close() PY } prepare_release_dir() { release_dir="$1" backend_port="$2" mkdir -p "$release_dir/backend" "$release_dir/frontend" "$release_dir/fake-java-bin" printf 'old-jar\n' > "$release_dir/backend/ruoyi-admin.jar" mkdir -p "$release_dir/frontend/dist" printf 'old\n' > "$release_dir/frontend/dist/index.html" create_fake_java "$release_dir/fake-java-bin/java" create_release_zip "$release_dir" "deploy.zip" cp "$SCRIPT_UNDER_TEST" "$release_dir/deploy_from_package.sh" perl -0pi -e "s#JAVA_BIN=\"/home/webapp/env/java/bin/java\"#JAVA_BIN=\"$release_dir/fake-java-bin/java\"#" \ "$release_dir/deploy_from_package.sh" perl -0pi -e "s/BACKEND_PORT=63310/BACKEND_PORT=$backend_port/" \ "$release_dir/deploy_from_package.sh" chmod +x "$release_dir/deploy_from_package.sh" } cleanup_release_dir() { release_dir="$1" if [ -f "$release_dir/backend/backend.pid" ]; then backend_pid=$(cat "$release_dir/backend/backend.pid" 2>/dev/null || true) if [ -n "${backend_pid:-}" ]; then kill "$backend_pid" 2>/dev/null || true wait "$backend_pid" 2>/dev/null || true fi fi rm -rf "$release_dir" } test_deploy_success() { release_dir=$(mktemp -d) backend_port=$(find_free_port) trap 'cleanup_release_dir "$release_dir"' EXIT INT TERM prepare_release_dir "$release_dir" "$backend_port" ( cd "$release_dir" ./deploy_from_package.sh ) assert_file_exists "$release_dir/backend/ruoyi-admin.jar" assert_file_exists "$release_dir/frontend/dist.zip" assert_file_exists "$release_dir/frontend/dist/index.html" assert_file_exists "$release_dir/backend/backend.pid" assert_file_exists "$release_dir/backend/backend-console.log" assert_grep 'new' "$release_dir/frontend/dist/index.html" backup_jar_count=$(find "$release_dir/backend" -maxdepth 1 -type f -name 'ruoyi-admin.jar.*.bak' | wc -l | tr -d ' ') [ "$backup_jar_count" -eq 1 ] || fail "expected one backup jar, got $backup_jar_count" backup_dist_count=$(find "$release_dir/frontend" -maxdepth 1 -type d -name 'dist-*' | wc -l | tr -d ' ') [ "$backup_dist_count" -eq 1 ] || fail "expected one backup dist dir, got $backup_dist_count" backend_pid=$(cat "$release_dir/backend/backend.pid") kill -0 "$backend_pid" 2>/dev/null || fail "expected backend pid to be running" trap - EXIT INT TERM cleanup_release_dir "$release_dir" } test_multiple_release_zip_should_fail() { release_dir=$(mktemp -d) backend_port=$(find_free_port) trap 'cleanup_release_dir "$release_dir"' EXIT INT TERM prepare_release_dir "$release_dir" "$backend_port" cp "$release_dir/deploy.zip" "$release_dir/deploy-copy.zip" if ( cd "$release_dir" ./deploy_from_package.sh >/tmp/deploy_from_package_test.stderr 2>&1 ); then fail "expected deploy_from_package.sh to fail when multiple release zips exist" fi assert_file_exists /tmp/deploy_from_package_test.stderr assert_grep '发布 zip 数量不正确' /tmp/deploy_from_package_test.stderr rm -f /tmp/deploy_from_package_test.stderr trap - EXIT INT TERM cleanup_release_dir "$release_dir" } test_defunct_process_should_be_ignored() { release_dir=$(mktemp -d) backend_port=$(find_free_port) trap 'cleanup_release_dir "$release_dir"' EXIT INT TERM prepare_release_dir "$release_dir" "$backend_port" mkdir -p "$release_dir/fake-ps-bin" cat > "$release_dir/fake-ps-bin/ps" < -Dloan.pricing.home=$release_dir -jar $release_dir/backend/ruoyi-admin.jar PSOUT exit 0 fi /bin/ps "\$@" EOF chmod +x "$release_dir/fake-ps-bin/ps" ( cd "$release_dir" PATH="$release_dir/fake-ps-bin:/usr/bin:/bin" ./deploy_from_package.sh ) backend_pid=$(cat "$release_dir/backend/backend.pid") kill -0 "$backend_pid" 2>/dev/null || fail "expected backend pid to be running when defunct process is ignored" trap - EXIT INT TERM cleanup_release_dir "$release_dir" } test_only_current_project_jar_should_match() { release_dir=$(mktemp -d) backend_port=$(find_free_port) trap 'cleanup_release_dir "$release_dir"' EXIT INT TERM prepare_release_dir "$release_dir" "$backend_port" mkdir -p "$release_dir/fake-ps-bin" cat > "$release_dir/fake-ps-bin/ps" </dev/null || fail "expected backend pid to be running when non-target jar process is ignored" trap - EXIT INT TERM cleanup_release_dir "$release_dir" } test_should_use_ps_ef_for_process_detection() { if rg -n 'pgrep' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then fail "expected deploy_from_package.sh not to depend on pgrep" fi if ! rg -n 'ps -ef' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then fail "expected deploy_from_package.sh to use ps -ef for process detection" fi if rg -n '\b(ss|lsof|netstat|resolve_frontend_source_dir|is_port_listening)\b' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then fail "expected deploy_from_package.sh to remove port detection and unzip compatibility helpers" fi } main() { [ -f "$SCRIPT_UNDER_TEST" ] || fail "script under test not found: $SCRIPT_UNDER_TEST" test_should_use_ps_ef_for_process_detection test_deploy_success test_multiple_release_zip_should_fail test_defunct_process_should_be_ignored test_only_current_project_jar_should_match printf 'PASS: deploy_from_package tests\n' } main "$@"