"""应用级 API 冒烟测试。 使用 FastAPI TestClient 验证健康检查、静态页面、节点注册校验以及 节点生命周期与手动调用等真实链路。 """ import json from pathlib import Path from fastapi.testclient import TestClient from app.main import app WORKSPACE = Path(__file__).resolve().parent.parent.parent # 直接读取 Echo 节点 manifest 作为注册测试的真实数据。 ECHO_MANIFEST = json.loads( (WORKSPACE / "wov-node-echo" / "node.manifest.json").read_text(encoding="utf-8") ) def test_health() -> None: """验证静态首页、OpenAPI 文档与健康探针均可访问。""" with TestClient(app) as client: root = client.get("/", follow_redirects=False) assert root.status_code == 200 assert "WOV 应用中心" in root.text docs = client.get("/docs") assert docs.status_code == 200 response = client.get("/health") assert response.status_code == 200 assert response.json()["service"] == "wov-api" def test_register_validation_errors() -> None: """验证非法节点注册请求会被 Pydantic 或协议校验拒绝。""" with TestClient(app) as client: assert client.post("/api/admin/nodes", json={}).status_code == 422 invalid = dict(ECHO_MANIFEST, id="") assert client.post("/api/admin/nodes", json=invalid).status_code == 422 invalid = dict(ECHO_MANIFEST, repo_dir="") assert client.post("/api/admin/nodes", json=invalid).status_code == 422 invalid = dict(ECHO_MANIFEST, max_concurrency=0) assert client.post("/api/admin/nodes", json=invalid).status_code == 422 def test_node_lifecycle_and_invoke() -> None: """验证注册、查询、调用、停止与删除节点的完整生命周期。""" with TestClient(app) as client: registered = client.post("/api/admin/nodes", json=ECHO_MANIFEST) assert registered.status_code == 200 assert registered.json()["id"] == "echo" nodes = client.get("/api/admin/nodes") assert nodes.status_code == 200 assert [node["id"] for node in nodes.json()] == ["echo"] node = client.get("/api/admin/nodes/echo") assert node.status_code == 200 assert node.json()["capability"] == "echo" assert client.get("/api/admin/nodes/missing").status_code == 404 invoked = client.post( "/api/admin/nodes/echo/invoke", json={ "run_id": "run_api", "inputs": {"text": "api test"}, "params": {}, }, ) assert invoked.status_code == 200 assert invoked.json()["status"] == "completed" assert invoked.json()["outputs"]["text"] == "api test" invoked_default = client.post( "/api/admin/nodes/echo/invoke", json={"inputs": {}}, ) assert invoked_default.status_code == 200 assert invoked_default.json()["status"] == "completed" assert invoked_default.json()["outputs"]["text"] == "echo" instances = client.get("/api/admin/node-instances") assert instances.status_code == 200 assert len(instances.json()) >= 1 instance_id = instances.json()[0]["id"] node_instances = client.get("/api/admin/nodes/echo/instances") assert node_instances.status_code == 200 assert node_instances.json()[0]["id"] == instance_id assert client.get("/api/admin/nodes/missing/instances").status_code == 404 stopped = client.post(f"/api/admin/node-instances/{instance_id}/stop") assert stopped.status_code == 200 assert stopped.json()["stopped"] == instance_id assert client.post("/api/admin/node-instances/missing/stop").status_code == 404 deleted = client.delete("/api/admin/nodes/echo") assert deleted.status_code == 200 assert deleted.json()["deleted"] == "echo" assert client.get("/api/admin/nodes/echo").status_code == 404 assert client.delete("/api/admin/nodes/echo").status_code == 404