- FastAPI backend with SQLModel, Alembic migrations, AgentScope agents - Next.js 15 frontend with React 19, Tailwind, Zustand, React Flow - Multi-provider AI system (DashScope, Kling, MiniMax, Volcengine, OpenAI, etc.) - All HTTP clients migrated from sync requests to async httpx - Admin-managed API keys via environment variables - SSRF vulnerability fixed in ensure_url()
105 lines
4.5 KiB
Python
105 lines
4.5 KiB
Python
"""
|
|
集成测试 - 模型配置 API (Task 5.6)
|
|
|
|
测试模型配置 API 端点的集成测试:
|
|
1. 测试 `/api/v1/models` 返回按类型分组的 HashMap
|
|
2. 测试每个模型对象包含完整字段
|
|
3. 测试 HashMap key 与 id 字段一致
|
|
"""
|
|
import pytest
|
|
import sys
|
|
import os
|
|
|
|
# 添加项目根目录到路径
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
|
|
|
from fastapi.testclient import TestClient
|
|
from src.main import app
|
|
|
|
client = TestClient(app)
|
|
|
|
|
|
class TestModelsAPI:
|
|
"""模型配置 API 集成测试"""
|
|
|
|
def test_models_api_returns_grouped_hashmap(self):
|
|
"""测试 /api/v1/models 返回按类型分组的 HashMap 结构"""
|
|
response = client.get("/api/v1/config/models")
|
|
|
|
# 应该返回 200
|
|
assert response.status_code == 200, f"Expected 200, got {response.status_code}: {response.text}"
|
|
|
|
data = response.json()
|
|
assert "data" in data, f"Response missing 'data' field: {data}"
|
|
|
|
models_data = data["data"]
|
|
|
|
# 验证按类型分组的结构
|
|
expected_types = ["image", "video", "audio", "llm"]
|
|
for model_type in expected_types:
|
|
assert model_type in models_data, f"Missing model type '{model_type}' in response"
|
|
assert isinstance(models_data[model_type], dict), \
|
|
f"Model type '{model_type}' should be a HashMap (dict), got {type(models_data[model_type])}"
|
|
|
|
def test_model_objects_contain_complete_fields(self):
|
|
"""测试每个模型对象包含完整的必需字段"""
|
|
response = client.get("/api/v1/config/models")
|
|
|
|
assert response.status_code == 200, f"Expected 200, got {response.status_code}: {response.text}"
|
|
|
|
data = response.json()
|
|
models_data = data["data"]
|
|
|
|
# 必需字段列表
|
|
required_fields = ["id", "name", "type", "provider"]
|
|
|
|
# 检查每个类型的每个模型
|
|
for model_type, models_map in models_data.items():
|
|
assert len(models_map) > 0, f"Model type '{model_type}' should have at least one model"
|
|
|
|
for model_id, model_config in models_map.items():
|
|
# 验证必需字段存在
|
|
for field in required_fields:
|
|
assert field in model_config, \
|
|
f"Model '{model_id}' missing required field '{field}'. Config: {model_config}"
|
|
|
|
# 验证字段值不为空
|
|
assert model_config["id"], f"Model '{model_id}' has empty 'id' field"
|
|
assert model_config["name"], f"Model '{model_id}' has empty 'name' field"
|
|
assert model_config["type"], f"Model '{model_id}' has empty 'type' field"
|
|
assert model_config["provider"], f"Model '{model_id}' has empty 'provider' field"
|
|
|
|
# 验证 type 字段与分组一致
|
|
assert model_config["type"] == model_type, \
|
|
f"Model '{model_id}' type mismatch: config.type='{model_config['type']}' but grouped under '{model_type}'"
|
|
|
|
def test_hashmap_key_matches_id_field(self):
|
|
"""测试 HashMap 的 key 与模型对象的 id 字段一致"""
|
|
response = client.get("/api/v1/config/models")
|
|
|
|
assert response.status_code == 200, f"Expected 200, got {response.status_code}: {response.text}"
|
|
|
|
data = response.json()
|
|
models_data = data["data"]
|
|
|
|
# 检查每个类型的每个模型
|
|
for model_type, models_map in models_data.items():
|
|
for map_key, model_config in models_map.items():
|
|
# HashMap 的 key 必须与模型对象的 id 字段完全一致
|
|
assert map_key == model_config["id"], \
|
|
f"HashMap key '{map_key}' does not match model id '{model_config['id']}' in type '{model_type}'"
|
|
|
|
# 验证 id 是复合 ID 格式 (provider/model_key)
|
|
assert "/" in model_config["id"], \
|
|
f"Model id '{model_config['id']}' should be in composite format 'provider/model_key'"
|
|
|
|
# 验证 provider 与 id 中的 provider 部分一致
|
|
id_provider = model_config["id"].split("/", 1)[0]
|
|
assert model_config["provider"] == id_provider, \
|
|
f"Model '{model_config['id']}' provider mismatch: " \
|
|
f"config.provider='{model_config['provider']}' but id contains '{id_provider}'"
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__, "-v", "--tb=short"])
|