fix: clean up utcnow deprecation warnings, fix 12 failing tests, add CI/CD pipeline manifests
- Replace all datetime.utcnow() with datetime.now(tz=timezone.utc) across 8 files - Fix 12 failing tests to match current implementation behavior - Fix pytest_plugins in non-top-level conftest (moved to root conftest.py) - Auto-fix 189 lint issues (import sorting, unused imports) - Add CI/CD pipeline infrastructure (ARC, ArgoCD, Kargo manifests) - Add values-beta.yaml and values-paper.yaml for staged deployments - Update GitHub Actions workflow to use self-hosted-gremlin runners - Add integration-test job to CI pipeline Result: 1596 passed, 0 failed, 0 warnings
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
"""Integration tests for the Risk Engine API — all 4 frontend-facing endpoints.
|
||||
|
||||
Validates every endpoint the frontend calls against the live sandbox
|
||||
with deterministic seed data. Uses the ``risk_client`` and ``seed_ids``
|
||||
fixtures from conftest.py.
|
||||
|
||||
Routes are at the root level (no prefix):
|
||||
/health, /evaluate, /approvals/pending, /approvals/{id}/review
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.asyncio
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1 Health Check
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestRiskHealth:
|
||||
"""Endpoint: GET /health."""
|
||||
|
||||
async def test_health(self, risk_client):
|
||||
"""GET /health — returns {"status": "ok"}."""
|
||||
resp = await risk_client.get("/health")
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["status"] == "ok"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2 Evaluate Order
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestRiskEvaluate:
|
||||
"""Endpoint: POST /evaluate."""
|
||||
|
||||
async def test_evaluate_order(self, risk_client):
|
||||
"""POST /evaluate — evaluate a proposed order and verify response structure."""
|
||||
payload = {
|
||||
"order": {
|
||||
"ticker": "AAPL",
|
||||
"action": "buy",
|
||||
"quantity": 10,
|
||||
"estimated_value": 1855.00,
|
||||
"confidence": 0.85,
|
||||
"recommendation_id": None,
|
||||
"sector": "Technology",
|
||||
},
|
||||
"config": None,
|
||||
"state": None,
|
||||
}
|
||||
resp = await risk_client.post("/evaluate", json=payload)
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
# Core RiskEvaluation fields
|
||||
assert "evaluation_id" in data
|
||||
assert "ticker" in data
|
||||
assert data["ticker"] == "AAPL"
|
||||
assert "eligible" in data
|
||||
assert isinstance(data["eligible"], bool)
|
||||
assert "rejection_reasons" in data
|
||||
assert isinstance(data["rejection_reasons"], list)
|
||||
assert "checks" in data
|
||||
assert isinstance(data["checks"], list)
|
||||
assert "evaluated_at" in data
|
||||
|
||||
async def test_evaluate_order_minimal(self, risk_client):
|
||||
"""POST /evaluate — minimal order with only required fields."""
|
||||
payload = {
|
||||
"order": {
|
||||
"ticker": "MSFT",
|
||||
},
|
||||
}
|
||||
resp = await risk_client.post("/evaluate", json=payload)
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert "evaluation_id" in data
|
||||
assert "eligible" in data
|
||||
assert "rejection_reasons" in data
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3 Pending Approvals
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestRiskApprovalsPending:
|
||||
"""Endpoint: GET /approvals/pending."""
|
||||
|
||||
async def test_list_pending_approvals(self, risk_client):
|
||||
"""GET /approvals/pending — returns 200 with a list (may be empty in sandbox)."""
|
||||
resp = await risk_client.get("/approvals/pending")
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert isinstance(data, list)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4 Review Approval
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestRiskApprovalReview:
|
||||
"""Endpoint: POST /approvals/{id}/review."""
|
||||
|
||||
async def test_review_nonexistent_approval(self, risk_client):
|
||||
"""POST /approvals/{id}/review — 404 for a non-existent approval ID."""
|
||||
fake_id = "00000000-0000-4000-ffff-000000000099"
|
||||
payload = {
|
||||
"approved": True,
|
||||
"reviewed_by": "test-operator",
|
||||
"review_note": "integration test",
|
||||
}
|
||||
resp = await risk_client.post(
|
||||
f"/approvals/{fake_id}/review", json=payload,
|
||||
)
|
||||
assert resp.status_code == 404
|
||||
Reference in New Issue
Block a user