#!/bin/bash # # 测试公共函数库 # # 注意:不在库文件中设置 set -e,由调用脚本控制 # 配置 BASE_URL="${BASE_URL:-http://localhost:4000}" TEST_TIMESTAMP="${TEST_TIMESTAMP:-$(date +%s)}" # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # ======================================== # 辅助函数 # ======================================== # 打印带颜色的信息 info() { echo -e "${BLUE}[INFO]${NC} $1" } success() { echo -e "${GREEN}[PASS]${NC} $1" } error() { echo -e "${RED}[FAIL]${NC} $1" } warn() { echo -e "${YELLOW}[WARN]${NC} $1" } # 检查上一个命令是否成功(传递状态码) # $1: 描述 # $2: 状态码(可选,默认使用 $?) check_success() { local status=${2:-$?} if [ $status -eq 0 ]; then success "$1" return 0 else error "$1" return 1 fi } # 检查上一个命令是否失败(用于测试权限拒绝) check_fail() { if [ $? -ne 0 ]; then success "$1 (预期失败)" return 0 else error "$1 (应该失败但没有)" return 1 fi } # 检查HTTP响应码 # $1: 响应内容 # $2: 期望状态码(默认 200) check_http_code() { local response="$1" local expected="${2:-200}" local code # 处理空响应(成功时可能返回空体) if [ -z "$response" ]; then code="200" else # 提取 code 字段,如果不存在则认为是 200 local json_code json_code=$(echo "$response" | jq -r '.code // empty') if [ -z "$json_code" ] || [ "$json_code" = "empty" ]; then code="200" elif [[ "$json_code" =~ ^[0-9]+$ ]]; then code="$json_code" else # code 字段存在但不是数字(可能是业务字段,如 org.code),视为成功 200 code="200" fi fi if [ "$code" = "$expected" ]; then return 0 else error "期望状态码: $expected, 实际: $code" info "响应: $response" return 1 fi } # 检查服务是否运行 check_service() { if ! curl -s "$BASE_URL/api/auth/login-methods" > /dev/null 2>&1; then error "服务未启动,请先启动服务" info "运行: go run cli/main.go -db.type=sqlite -db.dsn /tmp/vb.sqlite -p 4000" exit 1 fi success "服务正在运行" } # ======================================== # API 请求封装 # ======================================== # GET 请求 api_get() { local path="$1" local token="${2:-}" local curl_opts=("-s" "-X" "GET") if [ -n "$token" ]; then curl_opts+=("-H" "Authorization: Bearer $token") fi curl "${curl_opts[@]}" "$BASE_URL$path" } # POST 请求 api_post() { local path="$1" local data="$2" local token="${3:-}" local extra_headers="${4:-}" local curl_opts=("-s" "-X" "POST" "-H" "Content-Type: application/json") if [ -n "$token" ]; then curl_opts+=("-H" "Authorization: Bearer $token") fi if [ -n "$extra_headers" ]; then # 将 extra_headers 按空格分割添加到数组 for header in $extra_headers; do curl_opts+=("-H" "$header") done fi curl "${curl_opts[@]}" "$BASE_URL$path" -d "$data" } # PATCH 请求 api_patch() { local path="$1" local data="$2" local token="${3:-}" local extra_headers="${4:-}" local curl_opts=("-s" "-X" "PATCH" "-H" "Content-Type: application/json") if [ -n "$token" ]; then curl_opts+=("-H" "Authorization: Bearer $token") fi if [ -n "$extra_headers" ]; then for header in $extra_headers; do curl_opts+=("-H" "$header") done fi curl "${curl_opts[@]}" "$BASE_URL$path" -d "$data" } # DELETE 请求 api_delete() { local path="$1" local token="${2:-}" local extra_headers="${3:-}" local curl_opts=("-s" "-X" "DELETE") if [ -n "$token" ]; then curl_opts+=("-H" "Authorization: Bearer $token") fi if [ -n "$extra_headers" ]; then for header in $extra_headers; do curl_opts+=("-H" "$header") done fi curl "${curl_opts[@]}" "$BASE_URL$path" } # ======================================== # 用户相关操作 # ======================================== # 注册用户 # 返回: 注册响应 register_user() { local username="$1" local password="$2" local email="$3" api_post "/api/auth/register" \ "{\"username\": \"$username\", \"password\": \"$password\", \"email\": \"$email\"}" } # 登录用户 # 返回: 登录响应 login_user() { local username="$1" local password="$2" api_post "/api/auth/login" \ "{\"username\": \"$username\", \"password\": \"$password\"}" } # 提取 access_token get_token() { local login_response="$1" echo "$login_response" | jq -r '.access_token' } # 提取 refresh_token get_refresh_token() { local login_response="$1" echo "$login_response" | jq -r '.refresh_token' } # 提取用户ID get_user_id() { local login_response="$1" echo "$login_response" | jq -r '.user.id' } # ======================================== # 组织相关操作 # ======================================== # 创建组织 create_org() { local token="$1" local code="$2" local name="$3" local desc="${4:-}" api_post "/api/orgs" \ "{\"code\": \"$code\", \"name\": \"$name\", \"description\": \"$desc\"}" \ "$token" } # 更新组织 update_org() { local token="$1" local org_id="$2" local data="$3" api_patch "/api/orgs/$org_id" "$data" "$token" "-H X-Org-ID: $org_id" } # 添加组织成员 add_org_member() { local token="$1" local org_id="$2" local user_id="$3" local role="${4:-member}" api_post "/api/orgs/$org_id/members" \ "{\"user_id\": \"$user_id\", \"role\": \"$role\"}" \ "$token" \ "-H X-Org-ID: $org_id" } # ======================================== # 测试框架 # ======================================== # 测试开始 test_start() { local name="$1" echo "" echo "========================================" echo "测试: $name" echo "BASE_URL: $BASE_URL" echo "========================================" } # 测试步骤 step() { echo "" info "$1" } # 测试结束 test_end() { echo "" success "测试完成" }