### 变更详情 1. 新增密保问题系统,支持8种预置验证问题,多场景支持多验证方式 2. 新增勋章管理模块,包含勋章配置、用户勋章关联管理 3. 新增每日任务系统,支持任务配置和用户进度追踪 4. 新增赛季排行榜功能,支持周/月赛季排行与奖励结算 5. 新增信息流推荐权重配置管理 6. 重构服务路径分层,按设备/网络/数据分类管理服务 7. 优化Feed请求参数截断逻辑,避免URL过长 8. 新增等级工具类,统一处理等级颜色与称号展示 9. 新增屏幕共享共享信令Provider,复用传输服务实例 10. 新增Android/iOS分享适配与桌面小组件支持 11. 清理旧版测试脚本,新增部署维护脚本 12. 完善用户注销关联数据清理逻辑
163 lines
5.8 KiB
Python
163 lines
5.8 KiB
Python
import requests
|
|
import json
|
|
import base64
|
|
import hashlib
|
|
import hmac
|
|
import time
|
|
import os
|
|
import sys
|
|
|
|
BASE = 'https://tools.wktyl.com'
|
|
SECRET = 'Xy7kP9mL2qR4wS8v'
|
|
|
|
TEST_USERNAME = f'rank_test_{int(time.time())}'
|
|
TEST_PASSWORD = '123456'
|
|
TEST_EMAIL = f'rank_test_{int(time.time())}@test.com'
|
|
|
|
PASSED = 0
|
|
FAILED = 0
|
|
token = None
|
|
user_id = None
|
|
|
|
def make_receipt(action, payload_str):
|
|
data = {
|
|
'action': action,
|
|
'payload': hashlib.sha256(payload_str.encode()).hexdigest()[:16],
|
|
'ts': int(time.time()),
|
|
'nonce': os.urandom(4).hex()
|
|
}
|
|
receipt = base64.b64encode(json.dumps(data, ensure_ascii=False).encode()).decode()
|
|
sig = hmac.new(SECRET.encode(), receipt.encode(), hashlib.sha256).hexdigest()
|
|
return {'receipt': receipt, 'sig': sig}
|
|
|
|
def test(name, response, expected_code=1, check_func=None):
|
|
global PASSED, FAILED
|
|
try:
|
|
data = response.json()
|
|
except Exception as e:
|
|
print(f' ❌ {name}: Response parse error: {e}')
|
|
FAILED += 1
|
|
return None
|
|
if data.get('code') == expected_code:
|
|
if check_func and not check_func(data):
|
|
print(f' ❌ {name}: Check failed. Response: {json.dumps(data, ensure_ascii=False)[:200]}')
|
|
FAILED += 1
|
|
return data
|
|
print(f' ✅ {name}')
|
|
PASSED += 1
|
|
else:
|
|
print(f' ❌ {name}: Expected code={expected_code}, got code={data.get("code")}, msg={data.get("msg")}')
|
|
FAILED += 1
|
|
return data
|
|
|
|
print('=' * 60)
|
|
print('赛季排行榜系统全流程测试')
|
|
print(f'测试账号: {TEST_USERNAME}')
|
|
print(f'测试时间: {time.strftime("%Y-%m-%d %H:%M:%S")}')
|
|
print('=' * 60)
|
|
|
|
# ========== 1. 注册 ==========
|
|
print('\n--- 1. 注册测试用户 ---')
|
|
receipt_data = make_receipt('register', TEST_EMAIL)
|
|
r = requests.post(f'{BASE}/api/user_security/register', data={
|
|
'username': TEST_USERNAME,
|
|
'password': TEST_PASSWORD,
|
|
'email': TEST_EMAIL,
|
|
'receipt': receipt_data['receipt'],
|
|
'sig': receipt_data['sig'],
|
|
})
|
|
data = test('register', r)
|
|
if data and data.get('code') == 1:
|
|
token = data['data'].get('token', '')
|
|
user_id = data['data'].get('userinfo', {}).get('id', '')
|
|
print(f' 用户ID: {user_id}')
|
|
|
|
if not token:
|
|
print('❌ 注册失败,终止测试')
|
|
sys.exit(1)
|
|
|
|
headers = {'token': token}
|
|
|
|
# ========== 2. 登录获取token ==========
|
|
print('\n--- 2. 登录获取token ---')
|
|
receipt_data = make_receipt('login', TEST_USERNAME)
|
|
r = requests.post(f'{BASE}/api/user_security/login', data={
|
|
'account': TEST_USERNAME,
|
|
'password': TEST_PASSWORD,
|
|
'receipt': receipt_data['receipt'],
|
|
'sig': receipt_data['sig'],
|
|
})
|
|
data = test('login', r)
|
|
if data and data.get('code') == 1:
|
|
token = data['data'].get('token', '')
|
|
user_id = data['data'].get('userinfo', {}).get('id', '')
|
|
headers = {'token': token}
|
|
print(f' Token: {token[:20]}...')
|
|
|
|
# ========== 3. 获取赛季列表 ==========
|
|
print('\n--- 3. 获取赛季列表 ---')
|
|
r = requests.get(f'{BASE}/api/rank/seasons', headers=headers)
|
|
data = test('seasons list', r, check_func=lambda d: 'data' in d)
|
|
if data and data.get('code') == 1:
|
|
seasons = data['data'].get('seasons', data['data']) if isinstance(data['data'], dict) else data['data']
|
|
if isinstance(seasons, list):
|
|
print(f' 赛季数量: {len(seasons)}')
|
|
for s in seasons[:5]:
|
|
print(f' 🏆 {s.get("name", "?")} | type={s.get("type", "?")} status={s.get("status", "?")}')
|
|
else:
|
|
print(f' 赛季数据: {json.dumps(data["data"], ensure_ascii=False)[:200]}')
|
|
|
|
# ========== 4. 获取排行榜(exp类型) ==========
|
|
print('\n--- 4. 获取排行榜(exp类型) ---')
|
|
r = requests.get(f'{BASE}/api/rank/leaderboard', headers=headers, params={'type': 'exp'})
|
|
data = test('leaderboard (exp)', r, check_func=lambda d: 'data' in d)
|
|
if data and data.get('code') == 1:
|
|
lb = data['data'].get('list', data['data'].get('leaderboard', data['data']))
|
|
if isinstance(lb, list):
|
|
print(f' 排行榜人数: {len(lb)}')
|
|
for item in lb[:3]:
|
|
print(f' 🥇 rank={item.get("rank", "?")} user={item.get("username", item.get("nickname", "?"))} value={item.get("value", "?")}')
|
|
else:
|
|
print(f' 排行榜数据: {json.dumps(data["data"], ensure_ascii=False)[:200]}')
|
|
|
|
# ========== 5. 获取我的排名 ==========
|
|
print('\n--- 5. 获取我的排名 ---')
|
|
r = requests.get(f'{BASE}/api/rank/myRank', headers=headers, params={'type': 'exp'})
|
|
data = test('myRank (exp)', r, check_func=lambda d: 'data' in d)
|
|
if data and data.get('code') == 1:
|
|
my_rank = data['data']
|
|
if isinstance(my_rank, dict):
|
|
print(f' 我的排名: rank={my_rank.get("rank", "?")} value={my_rank.get("value", "?")}')
|
|
else:
|
|
print(f' 排名数据: {json.dumps(data["data"], ensure_ascii=False)[:200]}')
|
|
|
|
# ========== 6. 领取赛季奖励(应失败 - 无效赛季) ==========
|
|
print('\n--- 6. 领取赛季奖励(应失败 - 无效赛季ID=999) ---')
|
|
r = requests.post(f'{BASE}/api/rank/claimReward', headers=headers, data={
|
|
'season_id': 999,
|
|
})
|
|
data = test('claimReward (invalid season, should fail)', r, expected_code=0)
|
|
if data and data.get('code') != 1:
|
|
print(f' 预期失败: {data.get("msg")}')
|
|
|
|
# ========== 7. 申请账号注销 ==========
|
|
print('\n--- 7. 申请账号注销 ---')
|
|
receipt_data = make_receipt('delete_account', str(user_id))
|
|
r = requests.post(f'{BASE}/api/user_security/requestDeletion', headers=headers, data={
|
|
'reason': 'test complete',
|
|
'receipt': receipt_data['receipt'],
|
|
'sig': receipt_data['sig'],
|
|
})
|
|
data = test('requestDeletion', r)
|
|
if data and data.get('code') == 1:
|
|
print(f' 注销申请ID: {data["data"].get("id")}')
|
|
|
|
# ========== 结果汇总 ==========
|
|
print('\n' + '=' * 60)
|
|
print(f'测试完成!通过: {PASSED}, 失败: {FAILED}, 总计: {PASSED + FAILED}')
|
|
print(f'测试账号 {TEST_USERNAME} 已提交注销申请')
|
|
print('=' * 60)
|
|
|
|
if FAILED > 0:
|
|
sys.exit(1)
|