"""全面测试:新增功能验证""" 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 PROVIDERS, _ACTIVE_PROVIDER, _get_provider_config test("默认供应商", _ACTIVE_PROVIDER == "opencode-go") test("opencode-go已配置", "opencode-go" in PROVIDERS) test("nvidia备用存在", "nvidia" in PROVIDERS) cfg = PROVIDERS["opencode-go"] test("opencode-go模型", cfg["model"] == "deepseek-v4-flash") test("opencode-go URL非空", bool(cfg["base_url"])) test("opencode-go Key非空", bool(cfg["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)