fix: 修复 episodes + yearly_targets 模型导入缺失,增 DELETE 接口,冒烟 6/6 全绿

This commit is contained in:
simonkoson
2026-05-15 13:05:58 +08:00
parent 773441bb87
commit b3667aa7b9
5 changed files with 244 additions and 65 deletions
+157
View File
@@ -0,0 +1,157 @@
"""
Task 1 冒烟测试脚本 — httpx(幂等版,可重复跑)
确保后端已启动: uvicorn app.main:app --reload
"""
import httpx
import random
BASE = "http://localhost:8000"
HEADERS = {"Content-Type": "application/json"}
def login(username: str, password: str) -> str:
r = httpx.post(f"{BASE}/api/auth/login", json={"username": username, "password": password})
r.raise_for_status()
return r.cookies.get("milsci_session", "")
def step(name: str, expected_status: int, method: str, url: str, **kwargs):
cookies = kwargs.pop("cookies", {})
if method == "GET":
r = httpx.get(url, cookies=cookies, **kwargs)
elif method == "POST":
r = httpx.post(url, cookies=cookies, **kwargs)
elif method == "PATCH":
r = httpx.patch(url, cookies=cookies, **kwargs)
elif method == "DELETE":
r = httpx.delete(url, cookies=cookies, **kwargs)
else:
raise ValueError(method)
status_ok = r.status_code == expected_status
mark = "[OK]" if status_ok else f"[FAIL expected {expected_status} got {r.status_code}]"
print(f"{mark} [{method}] {name}")
if not status_ok:
print(f" Response: {r.text[:300]}")
return r, status_ok
def main():
print("=== Login ===")
session_cookie = login("simonkoson", "liutong65")
if not session_cookie:
print("WARNING: session cookie empty, trying anyway")
session_cookie = ""
cookies = {"milsci_session": session_cookie}
# 使用随机后缀避免与上次数据冲突
suffix = random.randint(1000, 9999)
print("\n=== Step 1: Create zebian account ===")
r, ok = step(
"POST /api/users create zebian",
201,
"POST",
f"{BASE}/api/users",
json={
"username": f"test_zebian_{suffix}",
"display_name": f"Test Zebra {suffix}",
"password": "Test1234",
"role": "zebian",
},
cookies=cookies,
)
zebian_id = r.json().get("id") if ok else None
if ok:
print(f" zebian created, ID={zebian_id}")
print("\n=== Step 2: Create 2026 yearly target (idempotent) ===")
# 先尝试删已存在的(方便重跑)
r_list = httpx.get(f"{BASE}/api/yearly_targets", cookies=cookies)
if r_list.status_code == 200:
for t in r_list.json():
if t.get("year") == 2026:
del_id = t["id"]
httpx.delete(f"{BASE}/api/yearly_targets/{del_id}", cookies=cookies)
print(f" cleaned up existing 2026 target ID={del_id}")
# 再建新的
r, ok = step(
"POST /api/yearly_targets create 2026",
201,
"POST",
f"{BASE}/api/yearly_targets",
json={"year": 2026, "base_target": 0.65, "stretch_target": 0.90},
cookies=cookies,
)
target_2026_id = r.json().get("id") if ok else None
if ok:
print(f" target created, ID={target_2026_id}")
print("\n=== Step 3: Create 2026 again (should be 409) ===")
step(
"POST /api/yearly_targets duplicate 2026",
409,
"POST",
f"{BASE}/api/yearly_targets",
json={"year": 2026, "base_target": 0.70, "stretch_target": 0.95},
cookies=cookies,
)
print("\n=== Step 4: Create episode with editor_id=null (idempotent) ===")
# 先清理 episode_number
r_list = httpx.get(f"{BASE}/api/episodes?limit=100", cookies=cookies)
if r_list.status_code == 200:
for ep in r_list.json():
if ep.get("episode_number") == 9999:
httpx.delete(f"{BASE}/api/episodes/{ep['id']}", cookies=cookies)
print(f" cleaned up existing episode 9999 ID={ep['id']}")
r, ok = step(
"POST /api/episodes editor_id=null",
201,
"POST",
f"{BASE}/api/episodes",
json={
"episode_number": 9999,
"program_name": "Test Episode Smoke",
"air_date": "2026-05-15",
"editor_id": None,
"editor_name_snapshot": "Test Director Zhang",
"audience_share": 0.72,
},
cookies=cookies,
)
episode_9999_id = r.json().get("id") if ok else None
if ok:
print(f" episode created, ID={episode_9999_id}")
print("\n=== Step 5: GET /api/episodes list ===")
step(
"GET /api/episodes list",
200,
"GET",
f"{BASE}/api/episodes?limit=10",
cookies=cookies,
)
print("\n=== Step 6: PATCH yearly_target try to change year ===")
if target_2026_id:
r, ok = step(
"PATCH try to change year field",
200,
"PATCH",
f"{BASE}/api/yearly_targets/{target_2026_id}",
json={"year": 2027, "base_target": 0.65, "stretch_target": 0.90},
cookies=cookies,
)
if ok:
resp_year = r.json().get("year")
if resp_year == 2026:
print(f" [OK] year field unchanged, still 2026 (correct: year blocked)")
else:
print(f" [FAIL] year changed to {resp_year} (should be blocked)")
print("\n=== All steps done ===")
if __name__ == "__main__":
main()