120 lines
5.7 KiB
Python
120 lines
5.7 KiB
Python
"""bre 其余模块 create 链路冒烟(TestClient)。
|
|||
|
|
|
||
|
|
覆盖 full_tc 未写入的模块: group/plan/trait/trial/trial_study/treatment/trial_study_entry/
|
||
|
|
pedigree/pollination/seed_treatment/planting/seedling/tree_photo/selection_result/selection_rule。
|
||
|
|
逐一 create 断言 200,并按依赖逆序清理。
|
||
|
|
|
||
|
|
运行:
|
||
|
|
cd d:\dpb\dpb\backend
|
||
|
|
C:\ai\miniconda3\envs\dpb\python.exe -X utf8 scripts/test_bre_create_chain_tc.py
|
||
|
|
"""
|
||
|
|
import os
|
||
|
|
os.environ["ENVIRONMENT"] = "dev"
|
||
|
|
os.environ["PYTHONUTF8"] = "1"
|
||
|
|
|
||
|
|
import sys
|
||
|
|
sys.path.insert(0, r"d:\dpb\dpb\backend")
|
||
|
|
|
||
|
|
import main
|
||
|
|
from fastapi.testclient import TestClient
|
||
|
|
|
||
|
|
create_app = main.create_app
|
||
|
|
TOKEN = None
|
||
|
|
|
||
|
|
|
||
|
|
def login(client):
|
||
|
|
global TOKEN
|
||
|
|
d = {"username": "super", "password": "123456", "grant_type": "password", "login_type": "PC端"}
|
||
|
|
r = client.post("/api/v1/system/auth/login", data=d)
|
||
|
|
b = r.json()
|
||
|
|
if r.status_code == 200 and b.get("code") == 0:
|
||
|
|
TOKEN = b["data"]["access_token"]; return
|
||
|
|
key = client.get("/api/v1/system/auth/captcha/get").json()["data"]["key"]
|
||
|
|
client.post("/api/v1/system/auth/captcha/slider/complete", json={"captcha_key": key})
|
||
|
|
d["captcha_key"] = key
|
||
|
|
r = client.post("/api/v1/system/auth/login", data=d)
|
||
|
|
assert r.status_code == 200 and r.json().get("code") == 0, f"LOGIN FAIL {r.text[:200]}"
|
||
|
|
TOKEN = r.json()["data"]["access_token"]
|
||
|
|
|
||
|
|
|
||
|
|
def auth():
|
||
|
|
return {"Authorization": f"Bearer {TOKEN}"}
|
||
|
|
|
||
|
|
|
||
|
|
def main_():
|
||
|
|
with TestClient(create_app()) as client:
|
||
|
|
login(client)
|
||
|
|
RUN = __import__("datetime").datetime.now().strftime("%H%M%S")
|
||
|
|
created: list[tuple[str, int]] = [] # (domain, id),清理按此逆序
|
||
|
|
|
||
|
|
def c(name, domain, payload):
|
||
|
|
r = client.post(f"/api/v1/bre/{domain}/create", headers=auth(), json=payload)
|
||
|
|
ok = r.status_code == 200
|
||
|
|
print(f"[{'OK ' if ok else 'FAIL'}] create {name} -> HTTP {r.status_code}")
|
||
|
|
if not ok:
|
||
|
|
print(" BODY:", str(r.text)[:400]); sys.exit(1)
|
||
|
|
obj = r.json()["data"]
|
||
|
|
created.append((domain, obj["id"]))
|
||
|
|
return obj
|
||
|
|
|
||
|
|
site = c("site", "site", {"site_name": f"链基地{RUN}"})
|
||
|
|
plot = c("plot", "plot", {"site_id": site["id"], "plot_code": f"链{RUN}"})
|
||
|
|
target = c("target", "target", {"target_name": f"链目标{RUN}"})
|
||
|
|
g1 = c("germplasm f", "germplasm", {"cultivar_name": f"链父{RUN}"})
|
||
|
|
g2 = c("germplasm m", "germplasm", {"cultivar_name": f"链母{RUN}"})
|
||
|
|
personnel = c("personnel", "personnel", {"name": f"链人员{RUN}"})
|
||
|
|
combo = c("cross_combination", "cross_combination", {
|
||
|
|
"combination_code": f"CC-{RUN}", "bre_target_id": target["id"],
|
||
|
|
"female_parent_id": g1["id"], "male_parent_id": g2["id"],
|
||
|
|
"cross_method": "artificial", "cross_year": 2026})
|
||
|
|
tree = c("tree", "tree", {
|
||
|
|
"combination_id": combo["id"], "plot_id": plot["id"], "tree_no": f"T{RUN}",
|
||
|
|
"row_no": 1, "col_no": 1, "planted_date": "2026-03-15", "status": "alive",
|
||
|
|
"bre_personnel_id": personnel["id"]})
|
||
|
|
|
||
|
|
# 独立模块
|
||
|
|
group = c("group", "group", {"group_name": f"链组{RUN}"})
|
||
|
|
plan = c("plan", "plan", {"plan_code": f"PL{RUN}", "plan_name": f"链计划{RUN}"})
|
||
|
|
trait = c("trait", "trait", {"trait_code": f"tr_{RUN}", "trait_name": f"链性状{RUN}"})
|
||
|
|
|
||
|
|
# 试验链路
|
||
|
|
trial = c("trial", "trial", {"trial_name": f"链试验{RUN}"})
|
||
|
|
study = c("trial_study", "trial_study", {"trial_id": trial["id"], "study_name": f"链研究点{RUN}"})
|
||
|
|
treatment = c("treatment", "treatment", {"trial_study_id": study["id"], "factor": "肥", "level": "高"})
|
||
|
|
entry = c("trial_study_entry", "trial_study_entry", {
|
||
|
|
"trial_study_id": study["id"], "entry_number": 1, "germplasm_id": g1["id"]})
|
||
|
|
|
||
|
|
# 育种流程子模块
|
||
|
|
c("pedigree", "pedigree", {"combination_id": combo["id"], "child_code": f"C{RUN}"})
|
||
|
|
c("pollination", "pollination", {"combination_id": combo["id"], "pollination_date": "2026-04-01"})
|
||
|
|
c("seed_treatment", "seed_treatment", {"combination_id": combo["id"], "treatment_method": "stratify"})
|
||
|
|
c("planting", "planting", {"combination_id": combo["id"], "plot_id": plot["id"], "planting_date": "2026-03-10"})
|
||
|
|
c("seedling", "seedling", {"combination_id": combo["id"]})
|
||
|
|
c("tree_photo", "tree_photo", {"combination_id": combo["id"], "tree_id": tree["id"], "photo_type": "whole"})
|
||
|
|
c("selection_result", "selection_result", {
|
||
|
|
"combination_id": combo["id"], "tree_id": tree["id"], "is_selected": "primary"})
|
||
|
|
c("selection_rule", "selection_rule", {
|
||
|
|
"target_id": target["id"], "rule_name": f"链规则{RUN}",
|
||
|
|
"conditions_json": "{}"})
|
||
|
|
|
||
|
|
print("\n=== 清理(依赖逆序) ===")
|
||
|
|
ORDER = ["tree_photo", "selection_result", "seedling", "planting", "seed_treatment",
|
||
|
|
"pollination", "pedigree", "trait_observation", "tree", "tree_evaluation",
|
||
|
|
"cross_combination", "trial_study_entry", "treatment", "trial_study", "trial",
|
||
|
|
"selection_rule", "plan", "group", "germplasm", "personnel", "target", "trait",
|
||
|
|
"plot", "site"]
|
||
|
|
for domain in ORDER:
|
||
|
|
ids = [o[1] for o in created if o[0] == domain]
|
||
|
|
if not ids:
|
||
|
|
continue
|
||
|
|
r = client.request("DELETE", f"/api/v1/bre/{domain}/delete", headers=auth(), json=ids)
|
||
|
|
status = "OK " if r.status_code in (200, 409) else "FAIL"
|
||
|
|
print(f"[{status}] delete {domain} x{len(ids)} -> HTTP {r.status_code}")
|
||
|
|
if r.status_code not in (200, 409):
|
||
|
|
print(" BODY:", str(r.text)[:300])
|
||
|
|
print("\nALL CREATE CHAIN PASS ✅")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main_()
|