From d7ee1a1f4e31c410751e50df4c7bed377917bf03 Mon Sep 17 00:00:00 2001 From: veypi Date: Sun, 15 Feb 2026 20:01:51 +0800 Subject: [PATCH] =?UTF-8?q?test:=20=E6=B7=BB=E5=8A=A0=E9=9B=86=E6=88=90?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 scripts/tests/ 目录,包含权限测试脚本: - lib.sh: 公共函数库(API请求、用户/组织操作封装) - 01_basic_auth.sh: 基础认证测试(注册、登录、改密、刷新token) - 02_user_permission.sh: 用户权限测试(admin/user角色、信息修改权限) - 03_org_permission.sh: 组织权限测试(创建组织、成员权限、修改权限) - run_all.sh: 运行所有测试 - README.md: 测试说明文档 删除旧的 test.sh --- agents.md | 7 +- scripts/tests/01_basic_auth.sh | 99 +++++++++++ scripts/tests/02_user_permission.sh | 84 +++++++++ scripts/tests/03_org_permission.sh | 103 +++++++++++ scripts/tests/README.md | 107 +++++++++++ scripts/tests/lib.sh | 263 ++++++++++++++++++++++++++++ scripts/tests/run_all.sh | 77 ++++++++ test.sh | 224 ----------------------- 8 files changed, 737 insertions(+), 227 deletions(-) create mode 100755 scripts/tests/01_basic_auth.sh create mode 100755 scripts/tests/02_user_permission.sh create mode 100755 scripts/tests/03_org_permission.sh create mode 100644 scripts/tests/README.md create mode 100755 scripts/tests/lib.sh create mode 100755 scripts/tests/run_all.sh delete mode 100755 test.sh diff --git a/agents.md b/agents.md index 401da70..ebdc7f3 100644 --- a/agents.md +++ b/agents.md @@ -11,10 +11,11 @@ ```bash //重置数据库 -go run cli/main.go db drop && go run cli/main.go db migrate -go run cli/main.go -p 4000 +rm /tmp/vb.sqlite && go run cli/main.go -db=sqlit -dsn /tmp/vb.sqlite db migrate +go run cli/main.go -db=sqlit -dsn /tmp/vb.sqlite -p 4000 ``` - 可以通过 http://localhost:4000/_api.json 查看接口列表 + +可以通过 查看接口列表 ## UI 界面开发指南 diff --git a/scripts/tests/01_basic_auth.sh b/scripts/tests/01_basic_auth.sh new file mode 100755 index 0000000..ff906ba --- /dev/null +++ b/scripts/tests/01_basic_auth.sh @@ -0,0 +1,99 @@ +#!/bin/bash +# +# 基础认证测试 +# 测试内容:注册、登录、修改信息、改密码、刷新token、登出 +# + +set -e + +# 加载公共库 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/lib.sh" + +# 测试配置 +TEST_USER="basic_user_$TEST_TIMESTAMP" +TEST_PASS="password123" +TEST_EMAIL="$TEST_USER@test.com" + +test_start "基础认证测试" + +# 检查服务 +check_service + +# 1. 用户注册 +step "1. 用户注册" +REGISTER_RES=$(register_user "$TEST_USER" "$TEST_PASS" "$TEST_EMAIL") +echo "注册响应: $REGISTER_RES" +check_http_code "$REGISTER_RES" "200" +check_success "用户注册成功" + +# 2. 用户登录 +step "2. 用户登录" +LOGIN_RES=$(login_user "$TEST_USER" "$TEST_PASS") +echo "登录响应: $LOGIN_RES" +check_http_code "$LOGIN_RES" "200" + +TOKEN=$(get_token "$LOGIN_RES") +USER_ID=$(get_user_id "$LOGIN_RES") +info "Token: ${TOKEN:0:20}..." +info "User ID: $USER_ID" +check_success "用户登录成功" + +# 3. 获取当前用户信息 +step "3. 获取当前用户信息" +ME_RES=$(api_get "/api/auth/me" "$TOKEN") +echo "用户信息: $ME_RES" +check_http_code "$ME_RES" "200" +check_success "获取用户信息成功" + +# 4. 修改自己的信息 +step "4. 修改自己的信息" +UPDATE_RES=$(api_patch "/api/users/$USER_ID" '{"nickname": "Updated Nickname"}' "$TOKEN") +echo "更新响应: $UPDATE_RES" +check_http_code "$UPDATE_RES" "200" +NICKNAME=$(echo "$UPDATE_RES" | jq -r '.nickname') +if [ "$NICKNAME" == "Updated Nickname" ]; then + check_success "修改用户信息成功" +else + error "修改用户信息失败" + exit 1 +fi + +# 5. 修改密码 +step "5. 修改密码" +CHANGE_PW_RES=$(api_post "/api/auth/me/change-password" \ + "{\"old_password\": \"$TEST_PASS\", \"new_password\": \"newpassword123\"}" \ + "$TOKEN") +echo "改密码响应: $CHANGE_PW_RES" +check_http_code "$CHANGE_PW_RES" "200" +check_success "修改密码成功" + +# 6. 使用新密码登录 +step "6. 使用新密码登录" +LOGIN_NEW_RES=$(login_user "$TEST_USER" "newpassword123") +check_http_code "$LOGIN_NEW_RES" "200" +TOKEN=$(get_token "$LOGIN_NEW_RES") +check_success "新密码登录成功" + +# 7. Token 刷新 +step "7. Token 刷新" +REFRESH_RES=$(api_post "/api/auth/refresh" "{}" "$TOKEN") +echo "刷新响应: $REFRESH_RES" +check_http_code "$REFRESH_RES" "200" +NEW_TOKEN=$(echo "$REFRESH_RES" | jq -r '.access_token') +if [ -n "$NEW_TOKEN" ] && [ "$NEW_TOKEN" != "null" ]; then + TOKEN="$NEW_TOKEN" + check_success "Token 刷新成功" +else + error "Token 刷新失败" + exit 1 +fi + +# 8. 用户登出 +step "8. 用户登出" +LOGOUT_RES=$(api_post "/api/auth/logout" "{}" "$TOKEN") +echo "登出响应: $LOGOUT_RES" +check_http_code "$LOGOUT_RES" "200" +check_success "用户登出成功" + +test_end diff --git a/scripts/tests/02_user_permission.sh b/scripts/tests/02_user_permission.sh new file mode 100755 index 0000000..f416f51 --- /dev/null +++ b/scripts/tests/02_user_permission.sh @@ -0,0 +1,84 @@ +#!/bin/bash +# +# 用户权限测试 +# 测试内容: +# - 第一个用户注册为 admin +# - 第二个用户注册为 user +# - user 可以修改自己的信息 +# - user 不能修改 admin 的信息 +# + +set -e + +# 加载公共库 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/lib.sh" + +# 测试用户 +ADMIN_USER="admin_user_$TEST_TIMESTAMP" +ADMIN_PASS="admin123" +ADMIN_EMAIL="$ADMIN_USER@test.com" + +NORMAL_USER="normal_user_$TEST_TIMESTAMP" +NORMAL_PASS="user123" +NORMAL_EMAIL="$NORMAL_USER@test.com" + +test_start "用户权限测试" + +# 检查服务 +check_service + +# 1. 第一个用户注册 (admin) +step "1. 第一个用户注册 (自动成为 admin)" +ADMIN_REG=$(register_user "$ADMIN_USER" "$ADMIN_PASS" "$ADMIN_EMAIL") +echo "Admin 注册响应: $ADMIN_REG" +check_http_code "$ADMIN_REG" "200" +ADMIN_LOGIN=$(login_user "$ADMIN_USER" "$ADMIN_PASS") +ADMIN_TOKEN=$(get_token "$ADMIN_LOGIN") +ADMIN_ID=$(get_user_id "$ADMIN_LOGIN") +info "Admin ID: $ADMIN_ID" +check_success "Admin 注册并登录成功" + +# 2. 第二个用户注册 (user) +step "2. 第二个用户注册 (普通 user)" +USER_REG=$(register_user "$NORMAL_USER" "$NORMAL_PASS" "$NORMAL_EMAIL") +echo "User 注册响应: $USER_REG" +check_http_code "$USER_REG" "200" +USER_LOGIN=$(login_user "$NORMAL_USER" "$NORMAL_PASS") +USER_TOKEN=$(get_token "$USER_LOGIN") +USER_ID=$(get_user_id "$USER_LOGIN") +info "User ID: $USER_ID" +check_success "普通用户注册并登录成功" + +# 3. user 可以修改自己的信息 +step "3. user 可以修改自己的信息" +USER_UPDATE=$(api_patch "/api/users/$USER_ID" '{"nickname": "My Nickname"}' "$USER_TOKEN") +echo "修改自己响应: $USER_UPDATE" +check_http_code "$USER_UPDATE" "200" +check_success "user 可以修改自己的信息" + +# 4. user 不能修改 admin 的信息 +step "4. user 不能修改 admin 的信息 (应该返回 403)" +ADMIN_UPDATE_BY_USER=$(api_patch "/api/users/$ADMIN_ID" '{"nickname": "Hacked"}' "$USER_TOKEN") || true +echo "尝试修改 admin 响应: $ADMIN_UPDATE_BY_USER" +if echo "$ADMIN_UPDATE_BY_USER" | grep -q '"code":403' || echo "$ADMIN_UPDATE_BY_USER" | grep -q '"code":404'; then + check_success "user 不能修改 admin 的信息 (权限控制生效)" +else + error "权限控制失效" + exit 1 +fi + +# 5. admin 可以修改任意用户的信息 +step "5. admin 可以修改任意用户的信息" +USER_UPDATE_BY_ADMIN=$(api_patch "/api/users/$USER_ID" '{"nickname": "Updated By Admin"}' "$ADMIN_TOKEN") +echo "Admin 修改 user 响应: $USER_UPDATE_BY_ADMIN" +check_http_code "$USER_UPDATE_BY_ADMIN" "200" +NICKNAME=$(echo "$USER_UPDATE_BY_ADMIN" | jq -r '.nickname') +if [ "$NICKNAME" == "Updated By Admin" ]; then + check_success "admin 可以修改任意用户的信息" +else + error "admin 修改失败" + exit 1 +fi + +test_end diff --git a/scripts/tests/03_org_permission.sh b/scripts/tests/03_org_permission.sh new file mode 100755 index 0000000..b7e807c --- /dev/null +++ b/scripts/tests/03_org_permission.sh @@ -0,0 +1,103 @@ +#!/bin/bash +# +# 组织权限测试 +# 测试内容: +# - admin 创建组织 +# - user 不能修改他人的组织 +# - admin 邀请 user 加入组织 +# - 普通成员不能修改组织信息 +# + +set -e + +# 加载公共库 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/lib.sh" + +# 测试用户 +ADMIN_USER="org_admin_$TEST_TIMESTAMP" +ADMIN_PASS="admin123" +ADMIN_EMAIL="$ADMIN_USER@test.com" + +NORMAL_USER="org_member_$TEST_TIMESTAMP" +NORMAL_PASS="user123" +NORMAL_EMAIL="$NORMAL_USER@test.com" + +ORG_CODE="test_org_$TEST_TIMESTAMP" +ORG_NAME="Test Organization" + +test_start "组织权限测试" + +# 检查服务 +check_service + +# 1. 创建 admin 用户 +step "1. 创建 admin 用户" +ADMIN_REG=$(register_user "$ADMIN_USER" "$ADMIN_PASS" "$ADMIN_EMAIL") +ADMIN_LOGIN=$(login_user "$ADMIN_USER" "$ADMIN_PASS") +ADMIN_TOKEN=$(get_token "$ADMIN_LOGIN") +ADMIN_ID=$(get_user_id "$ADMIN_LOGIN") +info "Admin ID: $ADMIN_ID" +check_success "admin 用户创建成功" + +# 2. 创建普通用户 +step "2. 创建普通用户" +USER_REG=$(register_user "$NORMAL_USER" "$NORMAL_PASS" "$NORMAL_EMAIL") +USER_LOGIN=$(login_user "$NORMAL_USER" "$NORMAL_PASS") +USER_TOKEN=$(get_token "$USER_LOGIN") +USER_ID=$(get_user_id "$USER_LOGIN") +info "User ID: $USER_ID" +check_success "普通用户创建成功" + +# 3. admin 创建组织 +step "3. admin 创建组织" +ORG_RES=$(create_org "$ADMIN_TOKEN" "$ORG_CODE" "$ORG_NAME" "Test Description") +echo "创建组织响应: $ORG_RES" +check_http_code "$ORG_RES" "200" +ORG_ID=$(echo "$ORG_RES" | jq -r '.id') +info "Org ID: $ORG_ID" +check_success "admin 创建组织成功" + +# 4. user 不能修改他人的组织 +step "4. user 不能修改他人的组织 (应该返回 403)" +USER_UPDATE_ORG=$(update_org "$USER_TOKEN" "$ORG_ID" '{"name": "Hacked Name"}') || true +echo "user 尝试修改组织响应: $USER_UPDATE_ORG" +if echo "$USER_UPDATE_ORG" | grep -q '"code":403' || echo "$USER_UPDATE_ORG" | grep -q '"code":404'; then + check_success "user 不能修改他人的组织 (权限控制生效)" +else + error "权限控制失效" + exit 1 +fi + +# 5. admin 邀请 user 加入组织 +step "5. admin 邀请 user 加入组织 (作为普通成员)" +ADD_MEMBER_RES=$(add_org_member "$ADMIN_TOKEN" "$ORG_ID" "$USER_ID" "member") +echo "添加成员响应: $ADD_MEMBER_RES" +check_http_code "$ADD_MEMBER_RES" "200" +check_success "admin 邀请 user 加入组织成功" + +# 6. 普通成员不能修改组织信息 +step "6. 普通成员不能修改组织信息 (应该返回 403)" +MEMBER_UPDATE_ORG=$(update_org "$USER_TOKEN" "$ORG_ID" '{"name": "Member Hacked"}') || true +echo "普通成员尝试修改组织响应: $MEMBER_UPDATE_ORG" +if echo "$MEMBER_UPDATE_ORG" | grep -q '"code":403' || echo "$MEMBER_UPDATE_ORG" | grep -q '"code":404'; then + check_success "普通成员不能修改组织 (权限控制生效)" +else + error "权限控制失效" + exit 1 +fi + +# 7. admin 可以修改组织 +step "7. admin 可以修改组织" +ADMIN_UPDATE_ORG=$(update_org "$ADMIN_TOKEN" "$ORG_ID" '{"name": "Updated By Admin"}') +echo "admin 修改组织响应: $ADMIN_UPDATE_ORG" +check_http_code "$ADMIN_UPDATE_ORG" "200" +UPDATED_NAME=$(echo "$ADMIN_UPDATE_ORG" | jq -r '.name') +if [ "$UPDATED_NAME" == "Updated By Admin" ]; then + check_success "admin 可以修改组织" +else + error "admin 修改组织失败" + exit 1 +fi + +test_end diff --git a/scripts/tests/README.md b/scripts/tests/README.md new file mode 100644 index 0000000..eefb5c2 --- /dev/null +++ b/scripts/tests/README.md @@ -0,0 +1,107 @@ +# 测试脚本说明 + +本目录包含 VBase 的集成测试脚本,使用 bash + curl 测试 API 功能。 + +## 目录结构 + +``` +scripts/tests/ +├── README.md # 本说明文件 +├── lib.sh # 公共函数库 +├── 01_basic_auth.sh # 基础认证测试 +├── 02_user_permission.sh # 用户权限测试 +├── 03_org_permission.sh # 组织权限测试 +└── run_all.sh # 运行所有测试 +``` + +## 前置条件 + +1. 服务必须已启动: + ```bash + go run cli/main.go -db=sqlite -dsn /tmp/vb.sqlite -p 4000 + ``` + +2. 数据库已初始化: + ```bash + rm /tmp/vb.sqlite && go run cli/main.go -db=sqlite -dsn /tmp/vb.sqlite db migrate + ``` + +3. 依赖工具: + - `curl` + - `jq` (JSON 解析) + +## 测试脚本说明 + +### lib.sh +公共函数库,包含: +- `check_success()` / `check_fail()` - 检查结果 +- `check_http_code()` - 检查 HTTP 状态码 +- `register_user()` - 注册用户 +- `login_user()` - 登录用户 +- `api_get()` / `api_post()` / `api_patch()` / `api_delete()` - API 请求封装 + +### 01_basic_auth.sh +**测试内容**:基础认证流程 +- 用户注册 +- 用户登录 +- 获取当前用户信息 +- 修改自己的用户信息 +- 修改密码 +- Token 刷新 +- 用户登出 + +### 02_user_permission.sh +**测试内容**:用户级权限控制 +- 第一个用户注册(自动成为 admin) +- 第二个用户注册(普通 user) +- user 可以修改自己的信息 +- user **不能**修改 admin 的信息 +- admin 可以修改任意用户信息 + +### 03_org_permission.sh +**测试内容**:组织权限控制 +- admin 创建组织 +- user 不能修改他人创建的组织 +- admin 邀请 user 加入组织 +- 普通成员不能修改组织信息 +- 只有 admin/owner 可以修改组织 + +### run_all.sh +**功能**:运行所有测试 +- 按顺序执行所有测试脚本 +- 遇到错误时停止 +- 输出测试摘要 + +## 使用方法 + +### 运行单个测试 +```bash +# 基础认证测试 +cd scripts/tests +bash 01_basic_auth.sh + +# 用户权限测试 +bash 02_user_permission.sh + +# 组织权限测试 +bash 03_org_permission.sh +``` + +### 运行所有测试 +```bash +cd scripts/tests +bash run_all.sh +``` + +## 测试环境变量 + +| 变量 | 默认值 | 说明 | +|------|--------|------| +| `BASE_URL` | `http://localhost:4000` | API 基础地址 | +| `TEST_TIMESTAMP` | 自动生成 | 测试时间戳,用于生成唯一用户名 | + +## 注意事项 + +1. 测试脚本会创建真实数据,建议在测试数据库上运行 +2. 测试失败时会立即退出(`set -e`) +3. 每次运行使用不同的时间戳,避免用户名冲突 diff --git a/scripts/tests/lib.sh b/scripts/tests/lib.sh new file mode 100755 index 0000000..97f7dc8 --- /dev/null +++ b/scripts/tests/lib.sh @@ -0,0 +1,263 @@ +#!/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" +} + +# 检查上一个命令是否成功 +check_success() { + if [ $? -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 + + # 提取 code 字段,如果不存在则认为是 200 + code=$(echo "$response" | jq -r '.code // 200') + + if [ "$code" == "$expected" ]; then + return 0 + else + error "期望状态码: $expected, 实际: $code" + info "响应: $response" + return 1 + fi +} + +# 检查服务是否运行 +check_service() { + if ! curl -s "$BASE_URL/_api.json" > /dev/null 2>&1; then + error "服务未启动,请先启动服务" + info "运行: go run cli/main.go -db=sqlite -dsn /tmp/vb.sqlite -p 4000" + exit 1 + fi + success "服务正在运行" +} + +# ======================================== +# API 请求封装 +# ======================================== + +# GET 请求 +api_get() { + local path="$1" + local token="${2:-}" + local headers="" + + if [ -n "$token" ]; then + headers="-H Authorization: Bearer $token" + fi + + curl -s -X GET "$BASE_URL$path" $headers +} + +# POST 请求 +api_post() { + local path="$1" + local data="$2" + local token="${3:-}" + local extra_headers="${4:-}" + local headers="-H Content-Type: application/json" + + if [ -n "$token" ]; then + headers="$headers -H Authorization: Bearer $token" + fi + + if [ -n "$extra_headers" ]; then + headers="$headers $extra_headers" + fi + + curl -s -X POST "$BASE_URL$path" $headers -d "$data" +} + +# PATCH 请求 +api_patch() { + local path="$1" + local data="$2" + local token="${3:-}" + local extra_headers="${4:-}" + local headers="-H Content-Type: application/json" + + if [ -n "$token" ]; then + headers="$headers -H Authorization: Bearer $token" + fi + + if [ -n "$extra_headers" ]; then + headers="$headers $extra_headers" + fi + + curl -s -X PATCH "$BASE_URL$path" $headers -d "$data" +} + +# DELETE 请求 +api_delete() { + local path="$1" + local token="$2" + local extra_headers="${3:-}" + local headers="" + + if [ -n "$token" ]; then + headers="-H Authorization: Bearer $token" + fi + + if [ -n "$extra_headers" ]; then + headers="$headers $extra_headers" + fi + + curl -s -X DELETE "$BASE_URL$path" $headers +} + +# ======================================== +# 用户相关操作 +# ======================================== + +# 注册用户 +# 返回: 注册响应 +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\"}" +} + +# 提取 token +get_token() { + local login_response="$1" + echo "$login_response" | jq -r '.access_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 "========================================" +} + +# 测试步骤 +step() { + echo "" + info "$1" +} + +# 测试结束 +test_end() { + echo "" + success "测试完成" +} diff --git a/scripts/tests/run_all.sh b/scripts/tests/run_all.sh new file mode 100755 index 0000000..e2ea5ee --- /dev/null +++ b/scripts/tests/run_all.sh @@ -0,0 +1,77 @@ +#!/bin/bash +# +# 运行所有测试 +# + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +# 颜色 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +echo "========================================" +echo -e "${BLUE}VBase 集成测试套件${NC}" +echo "========================================" +echo "" + +# 生成统一的时间戳(所有测试使用相同时间戳,避免冲突) +export TEST_TIMESTAMP=$(date +%s) +echo "测试时间戳: $TEST_TIMESTAMP" +echo "" + +# 测试脚本列表 +TESTS=( + "01_basic_auth.sh:基础认证测试" + "02_user_permission.sh:用户权限测试" + "03_org_permission.sh:组织权限测试" +) + +PASSED=0 +FAILED=0 + +# 运行每个测试 +for test_info in "${TESTS[@]}"; do + script="${test_info%%:*}" + name="${test_info##*:}" + + echo "" + echo "========================================" + echo -e "${YELLOW}运行: $name${NC}" + echo "========================================" + + if bash "$script"; then + echo -e "${GREEN}✓ $name 通过${NC}" + ((PASSED++)) + else + echo -e "${RED}✗ $name 失败${NC}" + ((FAILED++)) + echo "" + echo -e "${RED}测试中止${NC}" + break + fi +done + +# 测试摘要 +echo "" +echo "========================================" +echo -e "${BLUE}测试摘要${NC}" +echo "========================================" +echo -e "通过: ${GREEN}$PASSED${NC}" +echo -e "失败: ${RED}$FAILED${NC}" +echo "总计: ${#TESTS[@]}" + +if [ $FAILED -eq 0 ]; then + echo "" + echo -e "${GREEN}所有测试通过!${NC}" + exit 0 +else + echo "" + echo -e "${RED}存在失败的测试${NC}" + exit 1 +fi diff --git a/test.sh b/test.sh deleted file mode 100755 index aaf6143..0000000 --- a/test.sh +++ /dev/null @@ -1,224 +0,0 @@ -#!/bin/bash - -# Configuration -BASE_URL="http://localhost:4000" -TIMESTAMP=$(date +%s) -USERNAME="user_$TIMESTAMP" -PASSWORD="password123" -EMAIL="${USERNAME}@example.com" -ORG_CODE="org_$TIMESTAMP" -ORG_NAME="Org $TIMESTAMP" - -echo "Testing against $BASE_URL" -echo "User: $USERNAME" -echo "Org: $ORG_CODE" - -# Helper function to check for errors -check_error() { - if [ $? -ne 0 ]; then - echo "Error: $1" - exit 1 - fi -} - -check_http_code() { - RESPONSE=$1 - EXPECTED=$2 - - if [ -z "$RESPONSE" ] || [ "$RESPONSE" == "null" ]; then - if [ "$EXPECTED" == "200" ]; then - return 0 - else - echo "Expected code $EXPECTED, got empty response" - exit 1 - fi - fi - - # Check if .code exists and is a number. If not, assume 200. - CODE=$(echo "$RESPONSE" | jq -r 'if (.code | type) == "number" then .code else 200 end') - - if [ "$CODE" != "$EXPECTED" ] && [ "$EXPECTED" != "200" ]; then - echo "Expected code $EXPECTED, got $CODE" - echo "Response: $RESPONSE" - exit 1 - fi - # Handle implicit 200 (when code field is missing or not a number) - if [ "$EXPECTED" == "200" ] && [ "$CODE" != "200" ] && [ "$CODE" != "0" ]; then - echo "Expected code 200, got $CODE" - echo "Response: $RESPONSE" - exit 1 - fi -} - -echo "==================================================" -echo "1. Registering User..." -REGISTER_RES=$(curl -s -X POST "$BASE_URL/api/auth/register" \ - -H "Content-Type: application/json" \ - -d "{\"username\": \"$USERNAME\", \"password\": \"$PASSWORD\", \"email\": \"$EMAIL\"}") -echo "Register Response: $REGISTER_RES" -check_http_code "$REGISTER_RES" 200 - -echo "==================================================" -echo "2. Logging in..." -LOGIN_RES=$(curl -s -X POST "$BASE_URL/api/auth/login" \ - -H "Content-Type: application/json" \ - -d "{\"username\": \"$USERNAME\", \"password\": \"$PASSWORD\"}") -echo "Login Response: $LOGIN_RES" -check_http_code "$LOGIN_RES" 200 - -ACCESS_TOKEN=$(echo "$LOGIN_RES" | jq -r '.access_token') -REFRESH_TOKEN=$(echo "$LOGIN_RES" | jq -r '.refresh_token') - -if [ -z "$ACCESS_TOKEN" ] || [ "$ACCESS_TOKEN" == "null" ]; then - echo "Failed to get access token" - exit 1 -fi - -echo "Got Access Token" - -echo "==================================================" -echo "3. Get User Info (Me)..." -ME_RES=$(curl -s -X GET "$BASE_URL/api/auth/me" \ - -H "Authorization: Bearer $ACCESS_TOKEN") -echo "Me Response: $ME_RES" -check_http_code "$ME_RES" 200 -USER_ID=$(echo "$ME_RES" | jq -r '.id') -echo "User ID: $USER_ID" - -echo "==================================================" -echo "4. Update User Info (Patch Me)..." -UPDATE_ME_RES=$(curl -s -X PATCH "$BASE_URL/api/auth/me" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"nickname\": \"Updated Nickname\"}") -echo "Update Me Response: $UPDATE_ME_RES" -check_http_code "$UPDATE_ME_RES" 200 -NEW_NICKNAME=$(echo "$UPDATE_ME_RES" | jq -r '.nickname') -if [ "$NEW_NICKNAME" != "Updated Nickname" ]; then - echo "Nickname update failed" - exit 1 -fi - -echo "==================================================" -echo "5. Change Password..." -CHANGE_PW_RES=$(curl -s -X POST "$BASE_URL/api/auth/me/change-password" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"old_password\": \"$PASSWORD\", \"new_password\": \"newpassword123\"}") -echo "Change Password Response: $CHANGE_PW_RES" -check_http_code "$CHANGE_PW_RES" 200 - -# Verify login with new password -echo "Verifying new password..." -LOGIN_NEW_RES=$(curl -s -X POST "$BASE_URL/api/auth/login" \ - -H "Content-Type: application/json" \ - -d "{\"username\": \"$USERNAME\", \"password\": \"newpassword123\"}") -check_http_code "$LOGIN_NEW_RES" 200 -echo "Login with new password successful" - -# Get new token -ACCESS_TOKEN=$(echo "$LOGIN_NEW_RES" | jq -r '.access_token') -REFRESH_TOKEN=$(echo "$LOGIN_NEW_RES" | jq -r '.refresh_token') - -echo "==================================================" -echo "6. Refresh Token..." -REFRESH_RES=$(curl -s -X POST "$BASE_URL/api/auth/refresh" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"refresh_token\": \"$REFRESH_TOKEN\"}") -echo "Refresh Response: $REFRESH_RES" -check_http_code "$REFRESH_RES" 200 -NEW_ACCESS_TOKEN=$(echo "$REFRESH_RES" | jq -r '.access_token') -if [ -z "$NEW_ACCESS_TOKEN" ] || [ "$NEW_ACCESS_TOKEN" == "null" ]; then - echo "Failed to refresh token" - exit 1 -fi -ACCESS_TOKEN=$NEW_ACCESS_TOKEN -echo "Token Refreshed" - -echo "==================================================" -echo "7. Create Organization..." -CREATE_ORG_RES=$(curl -s -X POST "$BASE_URL/api/orgs" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"name\": \"$ORG_NAME\", \"code\": \"$ORG_CODE\", \"description\": \"Test Description\"}") -echo "Create Org Response: $CREATE_ORG_RES" -check_http_code "$CREATE_ORG_RES" 200 -ORG_ID=$(echo "$CREATE_ORG_RES" | jq -r '.id') -echo "Org ID: $ORG_ID" - -echo "==================================================" -echo "8. Get Organization..." -GET_ORG_RES=$(curl -s -X GET "$BASE_URL/api/orgs/$ORG_ID" \ - -H "Authorization: Bearer $ACCESS_TOKEN") -# Need to pass X-Org-ID or use context? -# The get endpoint logic: Router.Get("/{org_id}", ..., setOrgID, auth.VBaseAuth.Perm("org:read"), get) -# setOrgID sets org_id from path param. -# Perm checks permission for that org_id. -# User should have admin role in that org. -echo "Get Org Response: $GET_ORG_RES" -check_http_code "$GET_ORG_RES" 200 - -echo "==================================================" -echo "9. Update Organization..." -UPDATE_ORG_RES=$(curl -s -X PATCH "$BASE_URL/api/orgs/$ORG_ID" \ - -H "Authorization: Bearer $ACCESS_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"name\": \"${ORG_NAME}_Updated\"}") -echo "Update Org Response: $UPDATE_ORG_RES" -check_http_code "$UPDATE_ORG_RES" 200 -UPDATED_NAME=$(echo "$UPDATE_ORG_RES" | jq -r '.name') -if [ "$UPDATED_NAME" != "${ORG_NAME}_Updated" ]; then - echo "Failed to update organization name" - exit 1 -fi - -echo "==================================================" -echo "10. List Org Members..." -MEMBERS_RES=$(curl -s -X GET "$BASE_URL/api/orgs/$ORG_ID/members" \ - -H "Authorization: Bearer $ACCESS_TOKEN") -echo "List Members Response: $MEMBERS_RES" -check_http_code "$MEMBERS_RES" 200 - -# Verify member count is at least 1 (the owner) -TOTAL=$(echo "$MEMBERS_RES" | jq -r '.total') -if [ "$TOTAL" -lt 1 ]; then - echo "Expected at least 1 member, got $TOTAL" - exit 1 -fi - - -echo "==================================================" -echo "11. List Users..." -USERS_RES=$(curl -s -X GET "$BASE_URL/api/users" \ - -H "Authorization: Bearer $ACCESS_TOKEN") -echo "List Users Response: $USERS_RES" -check_http_code "$USERS_RES" 200 - -echo "==================================================" -echo "12. Delete Organization..." -DELETE_ORG_RES=$(curl -s -X DELETE "$BASE_URL/api/orgs/$ORG_ID" \ - -H "Authorization: Bearer $ACCESS_TOKEN") -echo "Delete Org Response: $DELETE_ORG_RES" -check_http_code "$DELETE_ORG_RES" 200 - -# Verify deletion -VERIFY_RES=$(curl -s -X GET "$BASE_URL/api/orgs/$ORG_ID" \ - -H "Authorization: Bearer $ACCESS_TOKEN") -echo "Verify Delete Response: $VERIFY_RES" -# Expect 404 -CODE=$(echo "$VERIFY_RES" | jq -r '.code') -if [ "$CODE" != "404" ]; then - echo "Organization not deleted properly, got code $CODE" - exit 1 -fi - -echo "==================================================" -echo "13. Logout..." -LOGOUT_RES=$(curl -s -X POST "$BASE_URL/api/auth/logout" \ - -H "Authorization: Bearer $ACCESS_TOKEN") -echo "Logout Response: $LOGOUT_RES" -check_http_code "$LOGOUT_RES" 200 - -echo "==================================================" -echo "All Tests Passed Successfully!"