Files
taiji-AI-PAD/scripts/test_full_workflow.py
T
2026-01-04 02:09:11 +00:00

464 lines
15 KiB
Python

#!/usr/bin/env python3
"""
完整工作流测试脚本
测试:超级管理员创建渠道、创建计费/运维管理员、创建租户、权限验证
"""
import requests
import sys
import os
import time
import subprocess
from typing import Optional, Dict, Any
BASE_URL = "http://localhost:8002"
# 测试账户信息
SUPER_ADMIN = {
"email": "superadmin@taiji-ai.com",
"password": "Admin@123456",
"role": "super_admin"
}
BILLING_ADMIN = {
"email": "newbilling@test.com",
"password": "Billing@123456",
"role": "billing_admin"
}
OPS_ADMIN = {
"email": "newops@test.com",
"password": "Ops@123456",
"role": "operations_admin"
}
CHANNEL_ADMIN = {
"email": "channel-a@test.com",
"password": "ChannelA@123456",
"role": "channel_admin"
}
def print_header(title: str):
"""打印标题"""
print("\n" + "="*80)
print(f" {title}")
print("="*80)
def print_step(step: str):
"""打印步骤"""
print(f"\n[步骤] {step}")
print("-" * 80)
def wait_for_service(url: str, max_retries: int = 30, delay: int = 2) -> bool:
"""等待服务启动"""
print(f"等待服务启动: {url}")
for i in range(max_retries):
try:
resp = requests.get(f"{url}/health", timeout=2)
if resp.status_code == 200:
print(f" ✓ 服务已启动")
return True
except:
pass
if i < max_retries - 1:
print(f" 等待中... ({i+1}/{max_retries})")
time.sleep(delay)
print(f" ✗ 服务启动超时")
return False
def login(email: str, password: str, role: str = None) -> Optional[str]:
"""登录并获取token"""
try:
data = {"email": email, "password": password}
if role:
data["role"] = role
resp = requests.post(
f"{BASE_URL}/api/auth/login",
json=data,
timeout=10
)
if resp.status_code == 200:
result = resp.json()
token = result.get("data", {}).get("token")
if token:
print(f" ✓ 登录成功: {email}")
return token
else:
print(f" ✗ 登录失败: 响应中未找到token")
return None
else:
error = resp.json().get("detail", resp.text)
print(f" ✗ 登录失败: {error}")
return None
except Exception as e:
print(f" ✗ 登录出错: {e}")
return None
def test_create_channel(token: str) -> Optional[str]:
"""测试创建渠道"""
print_step("测试:超级管理员创建渠道")
channel_data = {
"name": "测试渠道A",
"email": "channel-a-test@test.com",
"password": "Channel@123456",
"commissionRate": 15.0
}
try:
resp = requests.post(
f"{BASE_URL}/api/admin/channels/create",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
},
json=channel_data,
timeout=10
)
if resp.status_code == 200:
result = resp.json()
channel_id = result.get("data", {}).get("id")
print(f" ✓ 渠道创建成功: {channel_data['name']} (ID: {channel_id})")
return channel_id
else:
error = resp.json().get("detail", resp.text)
if "邮箱已被使用" in error or "already exists" in error.lower():
print(f" ⚠ 渠道已存在: {channel_data['email']}")
# 尝试获取已存在的渠道
return get_channel_by_email(token, channel_data["email"])
else:
print(f" ✗ 创建失败: {error}")
return None
except Exception as e:
print(f" ✗ 创建出错: {e}")
return None
def get_channel_by_email(token: str, email: str) -> Optional[str]:
"""通过邮箱获取渠道ID"""
try:
resp = requests.get(
f"{BASE_URL}/api/admin/channels",
headers={"Authorization": f"Bearer {token}"},
timeout=10
)
if resp.status_code == 200:
result = resp.json()
channels = result.get("data", {}).get("channels", [])
for channel in channels:
if channel.get("email") == email:
return channel.get("id")
return None
except:
return None
def test_list_channels(token: str) -> bool:
"""测试获取渠道列表"""
print_step("测试:获取渠道列表")
try:
resp = requests.get(
f"{BASE_URL}/api/admin/channels",
headers={"Authorization": f"Bearer {token}"},
timeout=10
)
if resp.status_code == 200:
result = resp.json()
channels = result.get("data", {}).get("channels", [])
print(f" ✓ 获取成功,共 {len(channels)} 个渠道")
for ch in channels[:3]: # 只显示前3个
print(f" - {ch.get('name')} ({ch.get('email')})")
return True
else:
error = resp.json().get("detail", resp.text)
print(f" ✗ 获取失败: {error}")
return False
except Exception as e:
print(f" ✗ 获取出错: {e}")
return False
def test_create_admin(token: str, admin_info: dict, channel_id: str = None) -> bool:
"""测试创建管理员"""
role_name = {
"billing_admin": "计费管理员",
"operations_admin": "运维管理员"
}.get(admin_info["role"], admin_info["role"])
print_step(f"测试:创建{role_name}")
admin_data = {
"name": admin_info.get("name", role_name),
"email": admin_info["email"],
"password": admin_info["password"],
"role": admin_info["role"]
}
if channel_id:
admin_data["channelId"] = channel_id
try:
resp = requests.post(
f"{BASE_URL}/api/admin/admins/create",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
},
json=admin_data,
timeout=10
)
if resp.status_code == 200:
result = resp.json()
print(f" ✓ {role_name}创建成功: {admin_info['email']}")
return True
else:
error = resp.json().get("detail", resp.text)
if "邮箱已被使用" in error or "already exists" in error.lower():
print(f" ⚠ {role_name}已存在: {admin_info['email']}")
return True # 已存在也算成功
else:
print(f" ✗ 创建失败: {error}")
return False
except Exception as e:
print(f" ✗ 创建出错: {e}")
return False
def test_list_admins(token: str) -> bool:
"""测试获取管理员列表"""
print_step("测试:获取管理员列表")
try:
resp = requests.get(
f"{BASE_URL}/api/admin/admins",
headers={"Authorization": f"Bearer {token}"},
timeout=10
)
if resp.status_code == 200:
result = resp.json()
admins = result.get("data", {}).get("admins", [])
print(f" ✓ 获取成功,共 {len(admins)} 个管理员")
for admin in admins[:5]: # 只显示前5个
print(f" - {admin.get('name')} ({admin.get('email')}) - {admin.get('role')}")
return True
else:
error = resp.json().get("detail", resp.text)
print(f" ✗ 获取失败: {error}")
return False
except Exception as e:
print(f" ✗ 获取出错: {e}")
return False
def test_create_tenant(token: str, channel_token: str = None) -> Optional[str]:
"""测试创建租户"""
print_step("测试:创建租户")
# 使用渠道管理员token或提供的token
use_token = channel_token or token
tenant_data = {
"name": "测试租户A",
"email": "tenant-a@test.com",
"password": "Tenant@123456",
"subscriptionTier": "pro"
}
try:
resp = requests.post(
f"{BASE_URL}/api/channel/tenants/create",
headers={
"Authorization": f"Bearer {use_token}",
"Content-Type": "application/json"
},
json=tenant_data,
timeout=10
)
if resp.status_code == 200:
result = resp.json()
tenant_id = result.get("data", {}).get("id")
print(f" ✓ 租户创建成功: {tenant_data['name']} (ID: {tenant_id})")
return tenant_id
else:
error = resp.json().get("detail", resp.text)
if "邮箱已被使用" in error or "already exists" in error.lower():
print(f" ⚠ 租户已存在: {tenant_data['email']}")
return "existing"
else:
print(f" ✗ 创建失败: {error}")
return None
except Exception as e:
print(f" ✗ 创建出错: {e}")
return None
def test_list_tenants(token: str) -> bool:
"""测试获取租户列表"""
print_step("测试:获取租户列表")
try:
resp = requests.get(
f"{BASE_URL}/api/channel/tenants",
headers={"Authorization": f"Bearer {token}"},
timeout=10
)
if resp.status_code == 200:
result = resp.json()
tenants = result.get("data", {}).get("tenants", [])
print(f" ✓ 获取成功,共 {len(tenants)} 个租户")
for tenant in tenants[:5]: # 只显示前5个
print(f" - {tenant.get('name')} ({tenant.get('email')}) - {tenant.get('subscriptionTier')}")
return True
else:
error = resp.json().get("detail", resp.text)
print(f" ✗ 获取失败: {error}")
return False
except Exception as e:
print(f" ✗ 获取出错: {e}")
return False
def test_permission_verification():
"""测试权限验证"""
print_header("权限验证测试")
# 测试1: 计费管理员不能创建渠道
print_step("测试1: 计费管理员尝试创建渠道(应该失败)")
billing_token = login(BILLING_ADMIN["email"], BILLING_ADMIN["password"], BILLING_ADMIN["role"])
if billing_token:
try:
resp = requests.post(
f"{BASE_URL}/api/admin/channels/create",
headers={
"Authorization": f"Bearer {billing_token}",
"Content-Type": "application/json"
},
json={
"name": "未授权渠道",
"email": "unauthorized@test.com",
"password": "Test@123456",
"commissionRate": 10.0
},
timeout=10
)
if resp.status_code == 403:
print(f" ✓ 权限验证正确:计费管理员无法创建渠道")
else:
print(f" ✗ 权限验证失败:计费管理员不应该能创建渠道")
except Exception as e:
print(f" ✗ 测试出错: {e}")
# 测试2: 运维管理员不能创建租户
print_step("测试2: 运维管理员尝试创建租户(应该失败)")
ops_token = login(OPS_ADMIN["email"], OPS_ADMIN["password"], OPS_ADMIN["role"])
if ops_token:
try:
resp = requests.post(
f"{BASE_URL}/api/channel/tenants/create",
headers={
"Authorization": f"Bearer {ops_token}",
"Content-Type": "application/json"
},
json={
"name": "未授权租户",
"email": "unauthorized-tenant@test.com",
"password": "Test@123456",
"subscriptionTier": "free"
},
timeout=10
)
if resp.status_code == 403:
print(f" ✓ 权限验证正确:运维管理员无法创建租户")
else:
print(f" ✗ 权限验证失败:运维管理员不应该能创建租户")
except Exception as e:
print(f" ✗ 测试出错: {e}")
# 测试3: 计费管理员可以创建租户
print_step("测试3: 计费管理员尝试创建租户(应该成功)")
if billing_token:
tenant_id = test_create_tenant(billing_token, billing_token)
if tenant_id:
print(f" ✓ 权限验证正确:计费管理员可以创建租户")
else:
print(f" ⚠ 创建租户失败(可能是其他原因)")
# 测试4: 超级管理员可以访问所有资源
print_step("测试4: 超级管理员访问所有资源(应该成功)")
super_token = login(SUPER_ADMIN["email"], SUPER_ADMIN["password"], SUPER_ADMIN["role"])
if super_token:
success = True
success = success and test_list_channels(super_token)
success = success and test_list_admins(super_token)
if success:
print(f" ✓ 权限验证正确:超级管理员可以访问所有资源")
else:
print(f" ✗ 部分资源访问失败")
def main():
"""主函数"""
print_header("完整工作流测试")
# 步骤1: 等待服务启动
print_step("等待服务启动")
if not wait_for_service(BASE_URL):
print(" ✗ 服务未启动,请先启动Docker服务")
return
# 步骤2: 登录超级管理员
print_step("登录超级管理员")
super_token = login(SUPER_ADMIN["email"], SUPER_ADMIN["password"], SUPER_ADMIN["role"])
if not super_token:
print(" ✗ 无法登录超级管理员,请先运行 test_cre_admins.py 创建管理员")
return
# 步骤3: 测试创建渠道
channel_id = test_create_channel(super_token)
# 步骤4: 测试获取渠道列表
test_list_channels(super_token)
# 步骤5: 测试创建管理员
if channel_id:
test_create_admin(super_token, BILLING_ADMIN, channel_id)
test_create_admin(super_token, OPS_ADMIN, channel_id)
# 步骤6: 测试获取管理员列表
test_list_admins(super_token)
# 步骤7: 测试创建租户(使用计费管理员)
print_header("租户管理测试")
billing_token = login(BILLING_ADMIN["email"], BILLING_ADMIN["password"], BILLING_ADMIN["role"])
if billing_token:
test_create_tenant(billing_token, billing_token)
test_list_tenants(billing_token)
# 步骤8: 权限验证
test_permission_verification()
# 总结
print_header("测试完成")
print("\n所有测试已完成!")
if __name__ == "__main__":
main()