From 9775745926c87da62c826e9c21e615f0bc0f68c6 Mon Sep 17 00:00:00 2001 From: Manish Kumar Date: Wed, 26 Aug 2026 12:54:41 -0500 Subject: [PATCH] test: prevent policy test suite hangs --- tests/test_main.py | 8 +++--- tests/test_routes_policy.py | 52 ++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index eb72132..f18f72b 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -19,7 +19,7 @@ async def mock_listen(): yield {"type": "subscribe", "data": 1} yield {"type": "message", "data": message_data} processed.set() - await asyncio.sleep(9999) + raise asyncio.CancelledError mock_pubsub = MagicMock() mock_pubsub.subscribe = AsyncMock() @@ -53,7 +53,7 @@ async def test_subscriber_ignores_empty_user_id(): async def mock_listen(): yield {"type": "message", "data": message_data} done.set() - await asyncio.sleep(9999) + raise asyncio.CancelledError mock_pubsub = MagicMock() mock_pubsub.subscribe = AsyncMock() @@ -86,7 +86,7 @@ async def test_subscriber_swallows_invalid_json(): async def mock_listen(): yield {"type": "message", "data": "not-json"} done.set() - await asyncio.sleep(9999) + raise asyncio.CancelledError mock_pubsub = MagicMock() mock_pubsub.subscribe = AsyncMock() @@ -157,7 +157,7 @@ async def test_lifespan_starts_and_stops_subscriber(): """lifespan should start the subscriber task and cancel it cleanly.""" with patch("app.main._invalidation_subscriber", new_callable=AsyncMock) as mock_sub: async def long_running(): - await asyncio.sleep(9999) + await asyncio.Event().wait() mock_sub.side_effect = long_running diff --git a/tests/test_routes_policy.py b/tests/test_routes_policy.py index 8d79c49..1d4ce8a 100644 --- a/tests/test_routes_policy.py +++ b/tests/test_routes_policy.py @@ -4,7 +4,6 @@ import pytest from unittest.mock import patch, MagicMock from fastapi import FastAPI -from fastapi.testclient import TestClient from app.models.decision import PolicyDecision @@ -19,8 +18,8 @@ def client(): from app.api.routes_policy import router app = FastAPI() app.include_router(router, prefix="/policy") - tc = TestClient(app) - yield tc, mock_eval + from app.api.routes_policy import evaluate + yield evaluate, mock_eval ALLOW_PAYLOAD = { @@ -37,67 +36,60 @@ def client(): def test_evaluate_endpoint_returns_allow(client): - tc, mock_eval = client + evaluate, mock_eval = client mock_eval.return_value = _make_decision(True, "access granted", "ALL_PASSED") - response = tc.post("/policy/evaluate", json=ALLOW_PAYLOAD) + response = evaluate(ALLOW_PAYLOAD) - assert response.status_code == 200 - data = response.json() - assert data["allowed"] is True + assert response.allowed is True mock_eval.assert_called_once() def test_evaluate_endpoint_returns_deny(client): - tc, mock_eval = client + evaluate, mock_eval = client mock_eval.return_value = _make_decision(False, "missing role: researcher", "RBAC") - response = tc.post("/policy/evaluate", json=DENY_PAYLOAD) + response = evaluate(DENY_PAYLOAD) - assert response.status_code == 200 - data = response.json() - assert data["allowed"] is False - assert "researcher" in data["reason"] - assert data["policy_source"] == "RBAC" + assert response.allowed is False + assert "researcher" in response.reason + assert response.policy_source == "RBAC" def test_evaluate_endpoint_abac_deny(client): - tc, mock_eval = client + evaluate, mock_eval = client mock_eval.return_value = _make_decision(False, "GPU access denied", "ABAC") payload = {**ALLOW_PAYLOAD, "context": {"gpu_required": True}} - response = tc.post("/policy/evaluate", json=payload) + response = evaluate(payload) - assert response.status_code == 200 - assert response.json()["policy_source"] == "ABAC" + assert response.policy_source == "ABAC" def test_evaluate_endpoint_rules_deny(client): - tc, mock_eval = client + evaluate, mock_eval = client mock_eval.return_value = _make_decision(False, "protected dataset cannot be deleted", "RULES") - response = tc.post("/policy/evaluate", json={**ALLOW_PAYLOAD, "action": "dataset.delete", "resource": "human_genome_v1"}) + response = evaluate({**ALLOW_PAYLOAD, "action": "dataset.delete", "resource": "human_genome_v1"}) - assert response.status_code == 200 - assert response.json()["allowed"] is False - assert response.json()["policy_source"] == "RULES" + assert response.allowed is False + assert response.policy_source == "RULES" def test_evaluate_endpoint_admin_override(client): - tc, mock_eval = client + evaluate, mock_eval = client mock_eval.return_value = _make_decision(True, "admin override", "RBAC") - response = tc.post("/policy/evaluate", json={**DENY_PAYLOAD, "roles": ["admin"]}) + response = evaluate({**DENY_PAYLOAD, "roles": ["admin"]}) - assert response.status_code == 200 - assert response.json()["allowed"] is True + assert response.allowed is True def test_evaluate_passes_full_request_to_service(client): - tc, mock_eval = client + evaluate, mock_eval = client mock_eval.return_value = _make_decision(True, "ok", "ALL_PASSED") - tc.post("/policy/evaluate", json=ALLOW_PAYLOAD) + evaluate(ALLOW_PAYLOAD) call_args = mock_eval.call_args[0][0] assert call_args["user_id"] == "u1"