Files
xianyan/scripts/test_feed_weight_api.py
Developer 8cd2703a0b chore: 汇总2026-06-08全量功能迭代与修复
此版本包含多项功能更新与问题修复:
1. 新增iOS ShareExtension分享扩展,支持多类型内容分享
2. 修复认证流程日志提示,更新用户名检测逻辑
3. 优化会话列表UI,替换emoji为CupertinoIcons原生图标
4. 修正搜索类型与频道名称映射,新增音频类型支持
5. 调整启动页布局与多语言配置
6. 重构布局约束,修复无界布局崩溃问题
7. 迁移开发者设置到更多设置页,新增日志级别配置
8. 优化TTS健康检查与自动回退逻辑
9. 新增笔记置顶会话跳转功能
10. 更新后端配置与本地化字符串
11. 重构稍后读模块,支持音频内容处理
12. 优化编辑器功能与字体管理页面
13. 新增本地数据库置顶笔记表
14. 修复Android MANAGE_STORAGE权限配置
2026-06-08 07:55:22 +08:00

353 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@name Feed权重管理API测试脚本
@author AI Coder
@date 2026-06-08
@desc 测试Feed权重管理系统的install/sync和channels接口验证44种分类全部可管理
@update 初始创建
"""
import json
import sys
import time
try:
import requests
except ImportError:
print("❌ 需要安装requests库: pip3 install requests")
sys.exit(1)
# ============ 配置 ============
BASE_URL = "https://tools.wktyl.com"
SYNC_TOKEN = "xianyan_feed_sync_2026"
TIMEOUT = 30
# 全部44种数据源类型
ALL_CATEGORIES = [
"poetry", "wisdom", "story", "hitokoto", "riddle", "efs", "brainteaser",
"saying", "lyric", "why", "composition", "couplet", "cs", "drug", "herbal",
"food", "wine", "article", "chengyu", "hanzi", "cidian", "prescription",
"tisana", "joke", "zgjm", "lunyu", "hdnj", "jgj", "mz", "zz", "zuozhuan",
"sj", "sgz", "sbbf", "warring", "illness", "word", "abbr", "surname",
"jieqi", "nation", "wlyh", "jiufang", "bot"
]
def print_header(title):
"""打印分节标题"""
print(f"\n{'='*60}")
print(f" {title}")
print(f"{'='*60}")
def print_result(name, success, detail=""):
"""打印测试结果"""
icon = "" if success else ""
print(f" {icon} {name}", end="")
if detail:
print(f"{detail}")
else:
print()
def test_install_endpoint():
"""测试 install/sync 端点 """
print_header("1. 测试 install 端点 (同步全部分类)")
url = f"{BASE_URL}/api/feed/install"
params = {"token": SYNC_TOKEN}
try:
resp = requests.get(url, params=params, timeout=TIMEOUT)
data = resp.json()
print(f" 📡 响应状态码: {resp.status_code}")
if data.get("code") == 1:
result = data.get("data", {})
added = result.get("added", 0)
updated = result.get("updated", 0)
total = result.get("total_types", 0)
categories = result.get("all_categories", [])
print_result("install接口调用成功", True,
f"新增{added}种, 更新{updated}种, 共{total}")
print_result("分类总数匹配", total == 44,
f"期望44, 实际{total}")
# 检查返回的分类列表是否完整
missing = set(ALL_CATEGORIES) - set(categories)
print_result("全部分类已包含", len(missing) == 0,
f"缺失: {missing}" if missing else "全部44种分类已包含")
return True, result
else:
print_result("install接口调用", False, data.get("msg", "未知错误"))
return False, None
except requests.exceptions.Timeout:
print_result("install接口调用", False, "请求超时")
return False, None
except Exception as e:
print_result("install接口调用", False, str(e))
return False, None
def test_install_without_token():
"""测试无token时install端点的安全校验"""
print_header("2. 测试 install 端点安全校验 (无token)")
url = f"{BASE_URL}/api/feed/install"
try:
resp = requests.get(url, timeout=TIMEOUT)
data = resp.json()
if data.get("code") == 0:
print_result("无token被拒绝", True, data.get("msg", ""))
else:
print_result("无token被拒绝", False, "应该返回错误但返回了成功")
except Exception as e:
print_result("安全校验测试", False, str(e))
def test_channels_endpoint():
"""测试 channels 端点,验证返回的分类列表"""
print_header("3. 测试 channels 端点 (频道列表)")
url = f"{BASE_URL}/api/feed/channels"
try:
resp = requests.get(url, timeout=TIMEOUT)
data = resp.json()
if data.get("code") == 1:
channels = data.get("data", {}).get("channels", [])
channel_keys = [ch["key"] for ch in channels]
print(f" 📊 返回频道数: {len(channels)} (含'all'推荐频道)")
# 检查每个分类是否在channels中
missing = []
for cat in ALL_CATEGORIES:
if cat not in channel_keys:
missing.append(cat)
print_result("全部分类在channels中", len(missing) == 0,
f"缺失: {missing}" if missing else "全部44种分类可见")
# 检查每个channel的结构
for ch in channels:
has_required = all(k in ch for k in ["key", "name", "icon", "count"])
if not has_required:
print_result(f"频道 {ch.get('key', '?')} 结构完整", False)
break
else:
print_result("所有频道结构完整", True,
"均包含key/name/icon/count")
# 打印频道概览
print(f"\n 📋 频道列表:")
for ch in channels:
icon = ch.get("icon", "")
name = ch.get("name", "")
key = ch.get("key", "")
count = ch.get("count", 0)
enabled = ch.get("is_enabled", True)
status = "" if enabled else ""
print(f" {status} {icon} {name} ({key}) — {count}")
return True, channels
else:
print_result("channels接口调用", False, data.get("msg", "未知错误"))
return False, None
except Exception as e:
print_result("channels接口调用", False, str(e))
return False, None
def test_weight_config_endpoint():
"""测试 weight_config 端点,验证权重配置"""
print_header("4. 测试 weight_config 端点 (权重配置)")
url = f"{BASE_URL}/api/feed/weight_config"
try:
resp = requests.get(url, timeout=TIMEOUT)
data = resp.json()
if data.get("code") == 1:
result = data.get("data", {})
config = result.get("config", [])
total_types = result.get("total_types", 0)
enabled_count = result.get("enabled_count", 0)
print(f" 📊 配置总数: {total_types}, 启用数: {enabled_count}")
config_types = [c["type"] for c in config]
# 检查每个分类是否在配置中
missing = set(ALL_CATEGORIES) - set(config_types)
print_result("全部分类有权重配置", len(missing) == 0,
f"缺失: {missing}" if missing else "全部44种分类已配置")
# 检查配置结构
for c in config:
required = ["type", "name", "icon", "weight", "display_weight",
"push_limit", "is_enabled"]
has_all = all(k in c for k in required)
if not has_all:
print_result(f"分类 {c.get('type', '?')} 配置完整", False)
break
else:
print_result("所有配置结构完整", True)
# 打印权重概览
print(f"\n 📋 权重配置 (按权重降序):")
sorted_config = sorted(config, key=lambda x: x["weight"], reverse=True)
for c in sorted_config[:10]:
icon = c.get("icon", "")
name = c.get("name", "")
weight = c.get("weight", 0)
enabled = "" if c.get("is_enabled") else ""
print(f" {enabled} {icon} {name}: 权重={weight}")
if len(sorted_config) > 10:
print(f" ... 还有 {len(sorted_config) - 10} 个分类")
return True, result
else:
print_result("weight_config接口调用", False, data.get("msg", "未知错误"))
return False, None
except Exception as e:
print_result("weight_config接口调用", False, str(e))
return False, None
def test_stats_endpoint():
"""测试 stats 端点"""
print_header("5. 测试 stats 端点 (统计信息)")
url = f"{BASE_URL}/api/feed/stats"
try:
resp = requests.get(url, timeout=TIMEOUT)
data = resp.json()
if data.get("code") == 1:
result = data.get("data", {})
total_content = result.get("total_content", 0)
channel_count = result.get("channel_count", 0)
channels = result.get("channels", [])
print(f" 📊 总内容数: {total_content}, 频道数: {channel_count}")
# 检查启用的频道数
print_result("频道数>=44", channel_count >= 44,
f"实际{channel_count}")
# 检查每个分类是否有统计
stat_types = [ch["key"] for ch in channels]
missing = set(ALL_CATEGORIES) - set(stat_types)
print_result("全部分类有统计", len(missing) == 0,
f"缺失: {missing}" if missing else "全部44种分类有统计")
return True, result
else:
print_result("stats接口调用", False, data.get("msg", "未知错误"))
return False, None
except Exception as e:
print_result("stats接口调用", False, str(e))
return False, None
def test_idempotent_install():
"""测试install端点的幂等性重复调用不会重复插入"""
print_header("6. 测试 install 端点幂等性")
url = f"{BASE_URL}/api/feed/install"
params = {"token": SYNC_TOKEN}
try:
# 第一次调用
resp1 = requests.get(url, params=params, timeout=TIMEOUT)
data1 = resp1.json()
# 第二次调用
resp2 = requests.get(url, params=params, timeout=TIMEOUT)
data2 = resp2.json()
if data1.get("code") == 1 and data2.get("code") == 1:
result1 = data1.get("data", {})
result2 = data2.get("data", {})
added1 = result1.get("added", 0)
added2 = result2.get("added", 0)
print_result("第二次调用added应为0", added2 == 0,
f"第一次added={added1}, 第二次added={added2}")
print_result("两次调用total一致",
result1.get("total_types") == result2.get("total_types"),
f"均为{result1.get('total_types')}")
else:
print_result("幂等性测试", False, "接口返回错误")
except Exception as e:
print_result("幂等性测试", False, str(e))
def main():
"""主测试流程"""
print("🚀 Feed权重管理系统 — 全44分类扩展测试")
print(f" 目标服务器: {BASE_URL}")
print(f" 测试时间: {time.strftime('%Y-%m-%d %H:%M:%S')}")
print(f" 期望分类数: {len(ALL_CATEGORIES)}")
results = {}
# 1. 测试install端点
ok, install_result = test_install_endpoint()
results["install"] = ok
# 2. 测试安全校验
test_install_without_token()
# 3. 测试channels端点
ok, channels_result = test_channels_endpoint()
results["channels"] = ok
# 4. 测试weight_config端点
ok, weight_result = test_weight_config_endpoint()
results["weight_config"] = ok
# 5. 测试stats端点
ok, stats_result = test_stats_endpoint()
results["stats"] = ok
# 6. 测试幂等性
test_idempotent_install()
# 汇总
print_header("测试结果汇总")
total = len(results)
passed = sum(1 for v in results.values() if v)
for name, ok in results.items():
print_result(name, ok)
print(f"\n 📊 通过率: {passed}/{total}")
if passed == total:
print("\n 🎉 全部测试通过44种分类权重管理已就绪。")
else:
print(f"\n ⚠️ 有 {total - passed} 项测试未通过,请检查。")
return 0 if passed == total else 1
if __name__ == "__main__":
sys.exit(main())