项目里程碑初步优化

This commit is contained in:
Cheng Zhou
2026-02-27 09:06:06 +08:00
parent 8f3f717e48
commit fd7e3fc948
47 changed files with 2029 additions and 783 deletions
+2 -84
View File
@@ -2,10 +2,8 @@ import asyncio
import json
import os
import sys
import tempfile
import urllib.error
import urllib.request
import uuid
import asyncpg
@@ -40,68 +38,6 @@ def request_json(path: str, *, method: str = "GET", token: str | None = None, pa
return exc.code, body_json
def request_bytes(path: str, *, method: str = "GET", token: str | None = None) -> tuple[int, bytes]:
url = f"{BASE}{path}"
headers = {}
if token:
headers["Authorization"] = f"Bearer {token}"
req = urllib.request.Request(url, method=method, headers=headers)
try:
with urllib.request.urlopen(req, timeout=30) as resp:
return resp.getcode(), resp.read()
except urllib.error.HTTPError as exc:
return exc.code, exc.read()
def request_multipart(
path: str,
*,
token: str,
file_field: str,
file_name: str,
file_content: bytes,
expected_version: int,
) -> tuple[int, dict]:
boundary = f"----ctms-boundary-{uuid.uuid4().hex}"
chunks: list[bytes] = []
chunks.append(
(
f"--{boundary}\r\n"
f'Content-Disposition: form-data; name="expected_version"\r\n\r\n'
f"{expected_version}\r\n"
).encode("utf-8")
)
chunks.append(
(
f"--{boundary}\r\n"
f'Content-Disposition: form-data; name="{file_field}"; filename="{file_name}"\r\n'
f"Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\r\n\r\n"
).encode("utf-8")
)
chunks.append(file_content)
chunks.append(b"\r\n")
chunks.append(f"--{boundary}--\r\n".encode("utf-8"))
body = b"".join(chunks)
url = f"{BASE}{path}"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": f"multipart/form-data; boundary={boundary}",
}
req = urllib.request.Request(url, method="POST", headers=headers, data=body)
try:
with urllib.request.urlopen(req, timeout=30) as resp:
text = resp.read().decode() or "{}"
return resp.getcode(), json.loads(text)
except urllib.error.HTTPError as exc:
text = exc.read().decode() or "{}"
try:
body_json = json.loads(text)
except Exception:
body_json = {"raw": text}
return exc.code, body_json
def assert_or_exit(condition: bool, message: str) -> None:
if not condition:
print(f"[FAIL] {message}")
@@ -440,24 +376,6 @@ def main() -> int:
)
print("[9/12] rollback_ok")
status, exported_bytes = request_bytes(f"/api/v1/studies/{study_id}/setup-config/export-excel", token=token)
assert_or_exit(status == 200 and len(exported_bytes) > 0, f"导出Excel失败 status={status} bytes={len(exported_bytes)}")
with tempfile.NamedTemporaryFile(suffix=".xlsx", delete=False) as tmp:
tmp.write(exported_bytes)
tmp_path = tmp.name
print(f"[10/12] export_excel_ok file={tmp_path}")
status, imported = request_multipart(
f"/api/v1/studies/{study_id}/setup-config/import-excel",
token=token,
file_field="file",
file_name="setup-config-smoke.xlsx",
file_content=exported_bytes,
expected_version=rolled["version"],
)
assert_or_exit(status == 200 and isinstance(imported.get("version"), int), f"导入失败 status={status} body={imported}")
print(f"[11/12] import_excel_ok version={imported['version']}")
status, _ = request_json(f"/api/v1/studies/{study_id}/lock", token=token, method="PATCH", payload={})
assert_or_exit(status == 200, f"锁定失败 status={status}")
try:
@@ -465,10 +383,10 @@ def main() -> int:
f"/api/v1/studies/{study_id}/setup-config",
token=token,
method="PUT",
payload={"expected_version": imported["version"], "data": imported["data"]},
payload={"expected_version": rolled["version"], "data": rolled["data"]},
)
assert_or_exit(status == 403, f"锁定后写入应403,实际 status={status} body={locked_result}")
print("[12/12] lock_403_check_ok")
print("[10/10] lock_403_check_ok")
finally:
unlock_status, unlock_body = request_json(f"/api/v1/studies/{study_id}/unlock", token=token, method="PATCH", payload={})
assert_or_exit(unlock_status == 200, f"解锁失败 status={unlock_status} body={unlock_body}")