初始化提交

This commit is contained in:
chenxin committed 2026-08-21 16:00:13 +08:00
commit 887c1f449e
963 files changed
+166869

No files matched your search

@@ -0,0 +1,106 @@
"""演化候选审核 API 测试。"""
from collections.abc import AsyncGenerator
import pytest
from httpx import ASGITransport, AsyncClient
from app.db.session import AsyncSessionLocal
from app.main import app
from app.models.big_cycle import BigCycle
from app.models.evolution import EvolutionCandidate
from app.repositories.json_utils import dumps
from app.services.characters import get_active_character_model
@pytest.fixture
async def client() -> AsyncGenerator[AsyncClient, None]:
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as http_client:
yield http_client
async def _seed_cycle_and_candidate(character_id: str, **overrides) -> tuple[str, str]:
base = {
"type": "procedural",
"source": "big_cycle",
"level": "L2",
"scope": "task_scope",
"title": "确认假设",
"proposal": "技术问题先确认前提",
"delta_json": dumps({"title": "确认假设", "content": "先确认前提"}),
"evidence_ids_json": "[]",
"confidence": 0.8,
"benefit_score": 0.7,
"risk_score": 0.2,
"drift_score": 0.0,
"auto_apply_allowed": False,
"status": "pending",
}
base.update(overrides)
async with AsyncSessionLocal() as session:
cycle = BigCycle(
character_id=character_id,
trigger="test",
status="completed",
memory_count_at_trigger=20,
)
session.add(cycle)
await session.flush()
candidate = EvolutionCandidate(character_id=character_id, cycle_id=cycle.id, **base)
session.add(candidate)
await session.commit()
return candidate.id, cycle.id
@pytest.mark.asyncio
async def test_list_evolution_candidates(client: AsyncClient) -> None:
async with AsyncSessionLocal() as session:
character = await get_active_character_model(session)
await _seed_cycle_and_candidate(character.id)
await _seed_cycle_and_candidate(character.id, status="applied")
resp = await client.get(f"/api/v1/characters/{character.id}/evolution-candidates")
assert resp.status_code == 200
data = resp.json()
assert data["total"] == 2
pending = await client.get(
f"/api/v1/characters/{character.id}/evolution-candidates", params={"status": "pending"}
)
assert pending.json()["total"] == 1
@pytest.mark.asyncio
async def test_approve_pending_candidate_applies(client: AsyncClient) -> None:
async with AsyncSessionLocal() as session:
character = await get_active_character_model(session)
cand_id, _ = await _seed_cycle_and_candidate(character.id, type="procedural")
resp = await client.post(f"/api/v1/evolution-candidates/{cand_id}/approve")
assert resp.status_code == 200
data = resp.json()
assert data["status"] == "applied"
assert data["resulting_target_id"] is not None
@pytest.mark.asyncio
async def test_reject_pending_candidate(client: AsyncClient) -> None:
async with AsyncSessionLocal() as session:
character = await get_active_character_model(session)
cand_id, _ = await _seed_cycle_and_candidate(character.id)
resp = await client.post(f"/api/v1/evolution-candidates/{cand_id}/reject")
assert resp.status_code == 200
assert resp.json()["status"] == "rejected"
@pytest.mark.asyncio
async def test_approve_not_implemented_type_returns_error(client: AsyncClient) -> None:
async with AsyncSessionLocal() as session:
character = await get_active_character_model(session)
cand_id, _ = await _seed_cycle_and_candidate(character.id, type="tool_strategy", level="L2")
resp = await client.post(f"/api/v1/evolution-candidates/{cand_id}/approve")
assert resp.status_code in (400, 409, 501)
assert resp.json()["error"]["code"] == "not_implemented"