Files
yu-zhi-ran/tests/test_new_features.py
T
Yuzhiran Dev 499c511140 chore: opencode冗余清理 + LLM任务级模型选择 + systemd服务化
- 删除 opencode_search.py / mcp_search_server.py 及所有 MCP 引用
- 移除搜索缓存定时任务(scheduled_refresh_search_cache)
- 清理前后端所有 opencode/MCP 代码和注释
- LLM 提供商量换:opencode-go→nvidia(默认)+sensenova(合规审查)
- llm_configs 新增 is_default 字段,API 层互斥逻辑
- 所有定时任务支持独立 LLM 模型选择(LLM_TASK_PROVIDER env)
- compliance_optimizer.py 修复:import os / 解硬编码 / 关键词过滤
- Scheduler 日志修复:始终 INSERT,避免僵尸 running 行
- Systemd 服务化:Restart=always / 单 worker / Type=exec
- 搜索提供商:替换 opencode→360/搜狗/微信(免 Key)
- 更新 AGENTS.md / PROGRESS.md
2026-06-02 15:38:16 +08:00

151 lines
5.8 KiB
Python

"""全面测试:新增功能验证"""
import uvicorn, time, threading, requests, json, os, sys
from pathlib import Path
# Setup
os.environ.setdefault("DATABASE_URL", "sqlite:///../../automation/data/test.db")
os.environ.setdefault("USE_POSTGRES", "false")
backend_dir = str(Path(__file__).parent.parent / "platform" / "backend")
sys.path.insert(0, backend_dir)
os.chdir(backend_dir)
results = {"pass": 0, "fail": 0}
def test(name, ok, detail=""):
status = chr(10003) if ok else chr(10007)
results["pass" if ok else "fail"] += 1
print(f" {status} {name}")
if detail:
print(f" {detail}")
# 1. Python compile check
print("=== 1. Python 编译检查 ===")
files = [
"platform/backend/app/models.py",
"platform/backend/app/api/collector_mgmt.py",
"platform/backend/app/core/nvidia_client.py",
"platform/backend/app/core/scheduler.py",
"platform/backend/app/initial_data.py",
"platform/backend/app/main.py",
"scripts/collector.py",
"scripts/db_helper.py",
]
root = Path(__file__).parent.parent
for f in files:
try:
src = (root / f).read_text()
compile(src, f, "exec")
test(f" {f}", True)
except SyntaxError as e:
test(f" {f}", False, str(e))
# 2. Start server
print("\n=== 2. API 服务启动 ===")
def start_server():
uvicorn.run("app.main:app", host="127.0.0.1", port=18503, log_level="error")
t = threading.Thread(target=start_server, daemon=True)
t.start()
time.sleep(4)
base = "http://127.0.0.1:18503"
try:
r = requests.get(f"{base}/api/system/status", timeout=5)
test("服务可访问", r.status_code == 200)
except Exception as e:
test("服务可访问", False, str(e))
exit(1)
# 3. Login
print("\n=== 3. 登录认证 ===")
r = requests.post(f"{base}/api/auth/login", json={"username": "admin", "password": "admin123"}, timeout=5)
token = r.json().get("token", "") if r.status_code == 200 else ""
test("管理员登录", r.status_code == 200 and bool(token))
if not token:
exit(1)
auth = {"Authorization": f"Bearer {token}"}
# 4. System status
print("\n=== 4. 系统状态 ===")
r = requests.get(f"{base}/api/system/status", headers=auth, timeout=5)
test("GET /api/system/status", r.status_code == 200 and "stats" in r.json())
# 5. Collector categories CRUD
print("\n=== 5. 采集类别 CRUD ===")
r = requests.get(f"{base}/api/admin/collector/categories", headers=auth, timeout=5)
test("GET 类别列表", r.status_code == 200)
initial_count = len(r.json())
test(f"初始类别数>0", initial_count > 0, f"{initial_count}")
r = requests.post(f"{base}/api/admin/collector/categories", headers=auth,
json={"name": "新类别Z", "search_query": "新类别 2026", "sort_order": 99}, timeout=5)
test("POST 新增类别", r.status_code == 201)
new_id = r.json().get("id")
test("返回ID", bool(new_id))
r = requests.put(f"{base}/api/admin/collector/categories/{new_id}", headers=auth,
json={"description": "测试编辑"}, timeout=5)
test("PUT 编辑类别", r.status_code == 200 and r.json().get("description") == "测试编辑")
r = requests.delete(f"{base}/api/admin/collector/categories/{new_id}", headers=auth, timeout=5)
test("DELETE 删除类别", r.status_code == 200)
r = requests.get(f"{base}/api/admin/collector/categories", headers=auth, timeout=5)
test("删除后列表数恢复", len(r.json()) == initial_count)
# 6. Collector sources CRUD
print("\n=== 6. 信息源 CRUD ===")
r = requests.get(f"{base}/api/admin/collector/sources", headers=auth, timeout=5)
test("GET 源列表", r.status_code == 200)
src_count = len(r.json())
test(f"初始源数>0", src_count > 0, f"{src_count}")
r = requests.post(f"{base}/api/admin/collector/sources", headers=auth,
json={"name": "新源Z", "source_type": "web_search", "query": "新查询 2026"}, timeout=5)
test("POST 新增源", r.status_code == 201)
new_src_id = r.json().get("id")
r = requests.put(f"{base}/api/admin/collector/sources/{new_src_id}", headers=auth,
json={"focus": "测试领域"}, timeout=5)
test("PUT 编辑源", r.status_code == 200)
r = requests.delete(f"{base}/api/admin/collector/sources/{new_src_id}", headers=auth, timeout=5)
test("DELETE 删除源", r.status_code == 200)
# 7. LLM provider config
print("\n=== 7. LLM多供应商 ===")
sys.path.insert(0, str(root / "platform" / "backend"))
from app.core.nvidia_client import _get_active_provider, _get_provider_config
test("默认供应商存在", _get_active_provider() in ["opencode-go", "nvidia", "sensenova"])
cfg = _get_provider_config("opencode-go")
test("opencode-go已配置", cfg is not None)
cfg_nv = _get_provider_config("nvidia")
test("nvidia备用存在", cfg_nv is not None)
test("opencode-go模型非空", bool(cfg and cfg.get("model")))
test("opencode-go URL非空", bool(cfg and cfg.get("base_url")))
test("opencode-go Key非空", bool(cfg and cfg.get("api_key")))
# 8. Collector DB loading
print("\n=== 8. 采集器DB加载 ===")
sys.path.insert(0, str(root / "scripts"))
from collector import SustainabilityCollector
collector = SustainabilityCollector()
cats = collector.config.get("sustainability_categories", [])
test("从DB加载类别", len(cats) > 0, f"{len(cats)}个类别: {cats}")
test("从DB加载源", len(collector.sources) > 0, f"{len(collector.sources)}个源")
# 9. API auth protection
print("\n=== 9. API鉴权保护 ===")
r = requests.get(f"{base}/api/admin/collector/categories", timeout=5)
test("未认证访问被拒绝", r.status_code != 200, f"实际状态码: {r.status_code}")
r = requests.post(f"{base}/api/admin/collector/sources", timeout=5,
json={"name": "x", "source_type": "rss"})
test("未认证POST被拒绝", r.status_code != 200, f"实际状态码: {r.status_code}")
# Summary
total = results["pass"] + results["fail"]
print(f"\n{'='*40}")
print(f"总计: {results['pass']}/{total} 通过, {results['fail']} 失败")
if results["fail"] > 0:
exit(1)