generated from coulomb/repo-seed
Implement ops-hub bootstrap compatibility
This commit is contained in:
@@ -1,8 +1,4 @@
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
PUBLIC_ENDPOINTS = [
|
||||
"/api/v2/hubs",
|
||||
"/api/v2/hub-capability-manifests",
|
||||
CATALOG_ENDPOINTS = [
|
||||
"/api/v2/widget-types",
|
||||
"/api/v2/event-types",
|
||||
"/api/v2/annotation-categories",
|
||||
@@ -12,6 +8,8 @@ PUBLIC_ENDPOINTS = [
|
||||
]
|
||||
|
||||
PROTECTED_ENDPOINTS = [
|
||||
"/api/v2/hubs",
|
||||
"/api/v2/hub-capability-manifests",
|
||||
"/api/v2/api-consumers",
|
||||
"/api/v2/widgets",
|
||||
"/api/v2/interaction-events",
|
||||
@@ -23,33 +21,127 @@ PROTECTED_ENDPOINTS = [
|
||||
"/api/v2/hub-registry",
|
||||
]
|
||||
|
||||
OPERATOR_HEADERS = {"Authorization": "Bearer operator-token"}
|
||||
|
||||
def test_public_api_v2_endpoints_respond(app):
|
||||
client = TestClient(app)
|
||||
|
||||
for endpoint in PUBLIC_ENDPOINTS:
|
||||
def test_catalog_endpoints_respond_without_auth(client):
|
||||
for endpoint in CATALOG_ENDPOINTS:
|
||||
response = client.get(endpoint)
|
||||
assert response.status_code == 200, endpoint
|
||||
|
||||
|
||||
def test_hubs_seed_core_hub(app):
|
||||
response = TestClient(app).get("/api/v2/hubs")
|
||||
|
||||
assert response.status_code == 200
|
||||
assert response.json()[0]["slug"] == "core-hub"
|
||||
|
||||
|
||||
def test_protected_api_v2_endpoints_fail_before_business_logic(app):
|
||||
client = TestClient(app)
|
||||
|
||||
def test_protected_api_v2_endpoints_fail_before_business_logic(client):
|
||||
for endpoint in PROTECTED_ENDPOINTS:
|
||||
response = client.get(endpoint)
|
||||
assert response.status_code == 401, endpoint
|
||||
assert response.json()["detail"]["code"] == "unauthorized"
|
||||
|
||||
|
||||
def test_openapi_contains_compatibility_routes(app):
|
||||
payload = TestClient(app).get("/api/v2/openapi.json").json()
|
||||
def test_openapi_contains_ops_hub_gate_paths(client):
|
||||
payload = client.get("/api/v2/openapi.json").json()
|
||||
|
||||
assert "/api/v2/hubs" in payload["paths"]
|
||||
assert "/api/v2/widgets" in payload["paths"]
|
||||
assert "/hubs" in payload["paths"]
|
||||
assert "/hub-capability-manifests" in payload["paths"]
|
||||
assert "/api-consumers" in payload["paths"]
|
||||
assert "/policy-scopes" in payload["paths"]
|
||||
|
||||
|
||||
def test_ops_hub_bootstrap_sequence(client):
|
||||
hub = client.post(
|
||||
"/api/v2/hubs",
|
||||
headers=OPERATOR_HEADERS,
|
||||
json={
|
||||
"slug": "ops-hub",
|
||||
"name": "Ops Hub",
|
||||
"domain": "ops.coulomb.social",
|
||||
"hubKind": "domain",
|
||||
"hubFamily": "vsm",
|
||||
"vsmFunction": "OPS",
|
||||
"vsmSystem": "1",
|
||||
},
|
||||
)
|
||||
assert hub.status_code == 201
|
||||
hub_record = hub.json()
|
||||
assert hub_record["slug"] == "ops-hub"
|
||||
|
||||
listed_hubs = client.get("/api/v2/hubs", headers=OPERATOR_HEADERS).json()
|
||||
assert listed_hubs["data"][0]["id"] == hub_record["id"]
|
||||
|
||||
manifest = client.post(
|
||||
"/api/v2/hub-capability-manifests",
|
||||
headers=OPERATOR_HEADERS,
|
||||
json={
|
||||
"hubId": hub_record["id"],
|
||||
"manifestVersion": "1.0",
|
||||
"declaredWidgetTypes": ["ops-readiness-gate"],
|
||||
"declaredEventTypes": ["ops-endpoint-verified"],
|
||||
"declaredAnnotationCategories": ["ops-readiness-blocker"],
|
||||
"declaredPolicyScopes": ["ops-registry"],
|
||||
},
|
||||
)
|
||||
assert manifest.status_code == 201
|
||||
manifest_record = manifest.json()
|
||||
|
||||
activated = client.post(
|
||||
f"/api/v2/hub-capability-manifests/{manifest_record['id']}/activate",
|
||||
headers=OPERATOR_HEADERS,
|
||||
)
|
||||
assert activated.status_code == 200
|
||||
assert activated.json()["status"] == "active"
|
||||
|
||||
consumer = client.post(
|
||||
"/api/v2/api-consumers",
|
||||
headers=OPERATOR_HEADERS,
|
||||
json={
|
||||
"name": "ops-hub",
|
||||
"description": "API consumer for the VSM Operations hub",
|
||||
"hubCapabilityManifestId": manifest_record["id"],
|
||||
"rateLimitPerMinute": 120,
|
||||
"quotaPerDay": 50000,
|
||||
},
|
||||
)
|
||||
assert consumer.status_code == 201
|
||||
consumer_record = consumer.json()
|
||||
|
||||
key_response = client.post(
|
||||
f"/api/v2/api-consumers/{consumer_record['id']}/api-keys",
|
||||
headers=OPERATOR_HEADERS,
|
||||
json={"scopes": "framework:read hub:ops-hub:read hub:ops-hub:write"},
|
||||
)
|
||||
assert key_response.status_code == 201
|
||||
runtime_key = key_response.json()["fullKey"]
|
||||
runtime_headers = {"Authorization": f"Bearer {runtime_key}"}
|
||||
|
||||
widget = client.post(
|
||||
"/api/v2/widgets",
|
||||
headers=runtime_headers,
|
||||
json={
|
||||
"hubId": hub_record["id"],
|
||||
"status": "active",
|
||||
"name": "Gitea Registry Readiness",
|
||||
"widgetType": "ops-readiness-gate",
|
||||
"capabilityRef": "ops:readiness:gitea-registry",
|
||||
"viewContext": "ops-hub/readiness/gitea-registry",
|
||||
"policyScope": "ops-registry",
|
||||
},
|
||||
)
|
||||
assert widget.status_code == 201
|
||||
widget_record = widget.json()
|
||||
|
||||
event = client.post(
|
||||
"/api/v2/interaction-events",
|
||||
headers=runtime_headers,
|
||||
json={
|
||||
"widgetId": widget_record["id"],
|
||||
"eventType": "ops-endpoint-verified",
|
||||
"viewContext": "railiance-apps/workplans/RAIL-AP-WP-0001",
|
||||
"metadata": {"expectedStatus": 401},
|
||||
},
|
||||
)
|
||||
assert event.status_code == 201
|
||||
assert event.json()["eventType"] == "ops-endpoint-verified"
|
||||
|
||||
registry = client.get("/api/v2/hub-registry", headers=runtime_headers)
|
||||
assert registry.status_code == 200
|
||||
assert registry.json()["data"]["hubs"][0]["slug"] == "ops-hub"
|
||||
|
||||
Reference in New Issue
Block a user