Files
xiaoxia-saas/scripts/smoke_public_boundary_flow.py
T
API文档维护Agent e3fb518ab2
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
refactor: remove all workspace_id references from codebase
- Remove workspace_id from Pydantic models in project_management routes
- Remove workspace_id from SQLAlchemy and SQLite project management repos
- Remove workspace_id from worker tasks (storage keys, entity creation)
- Remove workspace_id from video dedup and title usage modules
- Remove workspace_id from generation and ingest worker tasks
- Clean workspace_id from all test files and scripts
- Remove workspace-specific test files (list_workspaces, workspace repos)

Task: #14 workspace_id 残留清理
2026-06-27 22:52:09 +08:00

199 lines
6.6 KiB
Python

from __future__ import annotations
import io
import time
import uuid
import os
import requests
BASE_URL = "https://saas.xiaoxiajianji.com/api/v1"
PASSWORD = os.environ.get("SMOKE_TEST_PASSWORD", "changeme")
def _json_or_raise(name: str, response: requests.Response) -> dict:
print(f"{name}={response.status_code}")
if response.status_code >= 400:
print(response.text[:500])
response.raise_for_status()
return response.json() if response.content else {}
def _register_login(session: requests.Session, label: str) -> dict:
suffix = uuid.uuid4().hex[:10]
email = f"smoke-boundary-{label}-{suffix}@example.com"
username = f"smoke_boundary_{label}_{suffix}"
_json_or_raise(
f"{label}_register",
session.post(
f"{BASE_URL}/auth/register",
json={"email": email, "username": username, "password": PASSWORD, "full_name": "Boundary Smoke"},
timeout=30,
),
)
login = _json_or_raise(
f"{label}_login",
session.post(f"{BASE_URL}/auth/login", json={"email": email, "password": PASSWORD}, timeout=30),
)
return {"Authorization": f"Bearer {login['access_token']}"}
def main() -> None:
owner = requests.Session()
intruder = requests.Session()
owner_headers = _register_login(owner, "owner")
intruder_headers = _register_login(intruder, "intruder")
workspace = _json_or_raise(
"owner_workspace",
owner.post(f"{BASE_URL}/workspaces", json={"name": "Boundary Workspace"}, headers=owner_headers, timeout=30),
)
project = _json_or_raise(
"owner_project",
owner.post(
f"{BASE_URL}/projects",
headers=owner_headers,
timeout=30,
),
)
project_id = project["id"]
library = _json_or_raise(
"owner_library",
owner.post(
f"{BASE_URL}/asset-libraries",
headers=owner_headers,
timeout=30,
),
)
library_id = library["id"]
upload = _json_or_raise(
"owner_upload",
owner.post(
f"{BASE_URL}/upload",
files={"file": ("boundary.mp4", io.BytesIO(b"boundary-owner"), "video/mp4")},
headers=owner_headers,
timeout=60,
),
)
ingest_id = upload.get("ingest_job_id")
for index in range(5):
if not ingest_id:
break
ingest = owner.get(f"{BASE_URL}/ingest-jobs/{ingest_id}", headers=owner_headers, timeout=30)
print(f"owner_ingest_{index}={ingest.status_code}")
if ingest.status_code == 200 and ingest.json().get("result_asset_id"):
break
time.sleep(1)
task = _json_or_raise(
"owner_generation_create",
owner.post(
f"{BASE_URL}/generation/tasks",
headers=owner_headers,
timeout=30,
),
)
task_id = task["id"]
video_id = ""
for index in range(8):
task_response = owner.get(f"{BASE_URL}/generation/tasks/{task_id}", headers=owner_headers, timeout=30)
print(f"owner_generation_{index}={task_response.status_code}")
results_response = owner.get(
f"{BASE_URL}/generation/tasks/{task_id}/results", headers=owner_headers, timeout=30
)
print(f"owner_generation_results_{index}={results_response.status_code}")
if results_response.status_code == 200:
items = results_response.json().get("items", [])
if items:
video_id = items[0]["id"]
break
time.sleep(2)
checks = [
("anon_me", requests.get(f"{BASE_URL}/auth/me", timeout=30).status_code, {401, 403}),
("anon_workspaces", requests.get(f"{BASE_URL}/workspaces", timeout=30).status_code, {401, 403}),
(
"anon_project_get",
requests.get(f"{BASE_URL}/projects/{project_id}", timeout=30).status_code,
{401, 403, 404},
),
(
"intruder_project_get",
intruder.get(f"{BASE_URL}/projects/{project_id}", headers=intruder_headers, timeout=30).status_code,
{403, 404},
),
(
"intruder_library_get",
intruder.get(f"{BASE_URL}/asset-libraries/{library_id}", headers=intruder_headers, timeout=30).status_code,
{403, 404},
),
(
"anon_assets",
requests.get(f"{BASE_URL}/assets", params={"library_id": library_id}, timeout=30).status_code,
{401, 403, 404},
),
(
"intruder_assets",
intruder.get(
f"{BASE_URL}/assets", params={"library_id": library_id}, headers=intruder_headers, timeout=30
).status_code,
{403, 404},
),
(
"anon_generation_task",
requests.get(f"{BASE_URL}/generation/tasks/{task_id}", timeout=30).status_code,
{401, 403, 404},
),
(
"intruder_generation_task",
intruder.get(f"{BASE_URL}/generation/tasks/{task_id}", headers=intruder_headers, timeout=30).status_code,
{403, 404},
),
(
"intruder_generation_results",
intruder.get(
f"{BASE_URL}/generation/tasks/{task_id}/results", headers=intruder_headers, timeout=30
).status_code,
{403, 404},
),
]
if video_id:
checks.extend(
[
(
"intruder_video_get",
intruder.get(
f"{BASE_URL}/generated-videos/{video_id}", headers=intruder_headers, timeout=30
).status_code,
{403, 404},
),
(
"intruder_video_download",
intruder.get(
f"{BASE_URL}/generated-videos/{video_id}/download-url", headers=intruder_headers, timeout=30
).status_code,
{403, 404},
),
]
)
upload_response = intruder.post(
f"{BASE_URL}/upload",
files={"file": ("boundary.txt", io.BytesIO(b"boundary"), "text/plain")},
headers=intruder_headers,
timeout=60,
)
checks.append(("intruder_upload", upload_response.status_code, {403, 404}))
failed = []
for name, status_code, expected in checks:
print(f"{name}={status_code}")
if status_code not in expected:
failed.append(f"{name} expected {sorted(expected)} got {status_code}")
if failed:
raise RuntimeError("; ".join(failed))
print("public_boundary_flow=ok")
if __name__ == "__main__":
main()