#!/usr/bin/env bash # PAM 测试脚本(Shell 入口)。 set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # 复用部署脚本中的函数供测试脚本调用。 # shellcheck source=./deploy.sh source "${SCRIPT_DIR}/deploy.sh" TEST_MODE="full" SKIP_ROLLBACK="false" MAX_IPS=0 TEST_RESULTS=() HAS_FAILURE=0 test_usage() { cat <<'EOF' 用法: ./test_deploy.sh [--config /path/to/config.txt] [--mode smoke|full] [--skip-rollback] [--max-ips N] 模式: smoke 仅测试配置、Token、Node 和在线 IP 查询 full 按部署顺序测试全部接口 说明: - full 模式会测试建版、上传、发布、Node 下载、升级、启动、校验和日志下载 - rollback 默认会额外测试一次 - 如果不希望测试脚本改变部署状态,可加 --skip-rollback - --max-ips 可限制参与接口测试的在线 IP 数量 EOF } add_test_result() { local step="$1" local status="$2" local detail="$3" TEST_RESULTS+=("${step}|${status}|${detail}") if [[ "$status" == "FAIL" ]]; then HAS_FAILURE=1 fi case "$status" in PASS) printf '[PASS] %s | %s\n' "$step" "$detail" ;; FAIL) printf '[FAIL] %s | %s\n' "$step" "$detail" >&2 ;; SKIP) printf '[SKIP] %s | %s\n' "$step" "$detail" ;; esac } print_test_report() { local pass_count=0 local fail_count=0 local skip_count=0 for row in "${TEST_RESULTS[@]}"; do IFS='|' read -r _step _status _detail <<< "$row" case "$_status" in PASS) pass_count=$((pass_count + 1)) ;; FAIL) fail_count=$((fail_count + 1)) ;; SKIP) skip_count=$((skip_count + 1)) ;; esac done printf '\n====================== API TEST REPORT ======================\n' printf 'PASS: %s\n' "$pass_count" printf 'FAIL: %s\n' "$fail_count" printf 'SKIP: %s\n\n' "$skip_count" printf '%-28s %-8s %s\n' "STEP" "STATUS" "DETAIL" for row in "${TEST_RESULTS[@]}"; do IFS='|' read -r step status detail <<< "$row" printf '%-28s %-8s %s\n' "$step" "$status" "$detail" done } run_smoke_test() { load_config "$1" ensure_dependencies if ensure_zip_file; then add_test_result "ZIP_FILE" "PASS" "$ZIP_FILE_PATH" else add_test_result "ZIP_FILE" "FAIL" "$ZIP_FILE_PATH" print_test_report return 1 fi if get_token; then add_test_result "TOKEN" "PASS" "token length=${#TOKEN}" else add_test_result "TOKEN" "FAIL" "token request failed" print_test_report return 1 fi if get_node_url; then add_test_result "TARGET_NODE" "PASS" "$NODE_URL" else add_test_result "TARGET_NODE" "FAIL" "node lookup failed" print_test_report return 1 fi if get_online_ips; then add_test_result "ONLINE_IPS" "PASS" "${ONLINE_IPS[*]}" else add_test_result "ONLINE_IPS" "FAIL" "online ip lookup failed" print_test_report return 1 fi print_test_report } run_full_test() { local config_path="$1" local rollback_tested="false" local -a test_ips=() load_config "$config_path" ensure_dependencies if ensure_zip_file; then add_test_result "ZIP_FILE" "PASS" "$ZIP_FILE_PATH" else add_test_result "ZIP_FILE" "FAIL" "$ZIP_FILE_PATH" print_test_report return 1 fi if get_token; then add_test_result "TOKEN" "PASS" "token length=${#TOKEN}" else add_test_result "TOKEN" "FAIL" "token request failed" print_test_report return 1 fi if create_version; then add_test_result "CREATE_VERSION" "PASS" "$VERSION_NUMBER" else add_test_result "CREATE_VERSION" "FAIL" "$VERSION_NUMBER" print_test_report return 1 fi if upload_package; then add_test_result "UPLOAD_PACKAGE" "PASS" "$HASH_CODE" else add_test_result "UPLOAD_PACKAGE" "FAIL" "upload failed" print_test_report return 1 fi if publish_version; then add_test_result "PUBLISH_VERSION" "PASS" "$AIRPORT_CODE" else add_test_result "PUBLISH_VERSION" "FAIL" "publish failed" print_test_report return 1 fi if get_node_url; then add_test_result "TARGET_NODE" "PASS" "$NODE_URL" else add_test_result "TARGET_NODE" "FAIL" "node lookup failed" print_test_report return 1 fi if get_online_ips; then add_test_result "ONLINE_IPS" "PASS" "${ONLINE_IPS[*]}" else add_test_result "ONLINE_IPS" "FAIL" "online ip lookup failed" print_test_report return 1 fi if download_cloud_to_node; then add_test_result "DOWNLOAD_TO_NODE" "PASS" "$VERSION_NUMBER" else add_test_result "DOWNLOAD_TO_NODE" "FAIL" "node download failed" print_test_report return 1 fi test_ips=("${ONLINE_IPS[@]}") if (( MAX_IPS > 0 )) && (( ${#test_ips[@]} > MAX_IPS )); then test_ips=("${test_ips[@]:0:MAX_IPS}") fi for ip in "${test_ips[@]}"; do local upgrade_response="" local upgrade_success="" local upgrade_message="" local verify_response="" local verify_success="" local verify_message="" local log_file="" local rollback_result="" if upgrade_response="$(upgrade_ip "$ip")"; then if response_indicates_failure "$upgrade_response"; then upgrade_message="$(response_message "$upgrade_response")" [[ -z "$upgrade_message" ]] && upgrade_message="task creation failed" add_test_result "UPGRADE [$ip]" "FAIL" "$upgrade_message" else add_test_result "UPGRADE [$ip]" "PASS" "task created" if poll_upgrade_progress "$ip"; then add_test_result "UPGRADE_PROGRESS [$ip]" "PASS" "rateOfProgress=${UPGRADE_PROGRESS_RATE}" else upgrade_message="$UPGRADE_PROGRESS_MESSAGE" [[ -z "$upgrade_message" ]] && upgrade_message="$UPGRADE_PROGRESS_MSG" [[ -z "$upgrade_message" ]] && upgrade_message="progress polling failed" add_test_result "UPGRADE_PROGRESS [$ip]" "FAIL" "$upgrade_message" fi fi else add_test_result "UPGRADE [$ip]" "FAIL" "request failed" fi if start_application "$ip"; then add_test_result "START [$ip]" "PASS" "request completed" else add_test_result "START [$ip]" "FAIL" "request failed" fi if verify_response="$(verify_ip "$ip")"; then verify_success="$(json_value "$verify_response" '.success')" verify_message="$(json_value "$verify_response" '.message')" if [[ "$verify_success" == "true" ]]; then add_test_result "VERIFY [$ip]" "PASS" "success=true" else [[ -z "$verify_message" ]] && verify_message="success != true" add_test_result "VERIFY [$ip]" "FAIL" "$verify_message" fi else add_test_result "VERIFY [$ip]" "FAIL" "request failed" fi if log_file="$(download_log "$ip")"; then add_test_result "LOG_DOWNLOAD [$ip]" "PASS" "$log_file" else add_test_result "LOG_DOWNLOAD [$ip]" "FAIL" "log download failed: ${log_file}" fi if [[ "$SKIP_ROLLBACK" == "false" && "$rollback_tested" == "false" ]]; then rollback_result="$(rollback_ip "$ip" "true")" if [[ "$rollback_result" == "ROLLBACK_SUCCESS" ]]; then add_test_result "ROLLBACK [$ip]" "PASS" "$rollback_result" else add_test_result "ROLLBACK [$ip]" "FAIL" "$rollback_result" fi rollback_tested="true" fi done if [[ "$SKIP_ROLLBACK" == "true" ]]; then add_test_result "ROLLBACK" "SKIP" "skipped by parameter" elif [[ "$rollback_tested" == "false" ]]; then add_test_result "ROLLBACK" "SKIP" "no IP available for rollback test" fi print_test_report if (( HAS_FAILURE != 0 )); then return 1 fi } main() { local config_path="$DEFAULT_CONFIG_PATH" while (($#)); do case "$1" in --config) [[ $# -lt 2 ]] && { log_error "--config 缺少路径"; exit 1; } config_path="$2" shift 2 ;; --mode) [[ $# -lt 2 ]] && { log_error "--mode 缺少取值"; exit 1; } TEST_MODE="$2" shift 2 ;; --skip-rollback) SKIP_ROLLBACK="true" shift ;; --max-ips) [[ $# -lt 2 ]] && { log_error "--max-ips 缺少取值"; exit 1; } MAX_IPS="$2" shift 2 ;; -h|--help) test_usage exit 0 ;; *) log_error "未知参数: $1" test_usage exit 1 ;; esac done case "$TEST_MODE" in smoke) run_smoke_test "$config_path" ;; full) run_full_test "$config_path" ;; *) log_error "不支持的测试模式: $TEST_MODE" exit 1 ;; esac } if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then main "$@" fi