263 lines
7.9 KiB
Bash
Executable File
263 lines
7.9 KiB
Bash
Executable File
#!/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 '<html>new</html>\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 '<html>old</html>\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" <<EOF
|
|
#!/bin/sh
|
|
if [ "\$1" = "-ef" ]; then
|
|
cat <<'PSOUT'
|
|
UID PID PPID C STIME TTY TIME CMD
|
|
root 99999 1 0 00:00 ? 00:00:00 [java] <defunct> -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" <<EOF
|
|
#!/bin/sh
|
|
if [ "\$1" = "-ef" ]; then
|
|
cat <<'PSOUT'
|
|
UID PID PPID C STIME TTY TIME CMD
|
|
root 88888 1 0 00:00 ? 00:00:00 java -Dloan.pricing.home=$release_dir -jar $release_dir/backend/ruoyi-admin.jar.bak --spring.profiles.active=pro
|
|
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 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 "$@"
|