898f89926d
Extends integration test coverage from 108 to 193 tests for the beta gate. New test modules: - test_query_api_extended.py (33 tests): documents, evidence, macro/competitive, ops/admin, agents, analytics - test_registry_write_paths.py (16 tests): write paths, validation, duplicates, competitor/exposure CRUD - test_risk_approval_lifecycle.py (8 tests): evaluation edge cases, full approval lifecycle - test_trading_extended.py (12 tests): config round-trips, decision filtering, override validation - test_cross_service_roundtrip.py (4 tests): cross-service data consistency - test_error_handling.py (12 tests): 404s, 422s, empty states, health checks Seed script extended with watchlists, approvals, lockouts, notifications, ingestion runs, saved queries, and daily risk snapshots.
160 lines
5.8 KiB
Python
160 lines
5.8 KiB
Python
"""Integration tests for cross-service data consistency.
|
|
|
|
These tests validate round-trip behavior: writing data via one service
|
|
and reading it back via another (or the same service on a different path).
|
|
They catch data propagation issues and schema drift between services.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
pytestmark = pytest.mark.asyncio
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Cross-Service: Company creation via Registry → read via Query API
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestCrossServiceCompanyRoundTrip:
|
|
"""Write company via registry, verify visibility in query API."""
|
|
|
|
async def test_create_company_via_registry_read_via_query(
|
|
self, registry_client, query_client,
|
|
):
|
|
"""Create company via registry, read via query API."""
|
|
payload = {
|
|
"ticker": "XRND",
|
|
"legal_name": "Cross Round Trip Corp",
|
|
"exchange": "NYSE",
|
|
"sector": "Technology",
|
|
"industry": "Software",
|
|
"market_cap_bucket": "small",
|
|
}
|
|
create_resp = await registry_client.post("/companies", json=payload)
|
|
assert create_resp.status_code == 201
|
|
|
|
# Read via query API
|
|
query_resp = await query_client.get("/api/companies")
|
|
assert query_resp.status_code == 200
|
|
tickers = {c["ticker"] for c in query_resp.json()}
|
|
assert "XRND" in tickers
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Cross-Service: Exposure profile round-trip via Registry
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestCrossServiceExposureRoundTrip:
|
|
"""PUT exposure via registry, GET via registry on a different path."""
|
|
|
|
async def test_exposure_round_trip(self, registry_client, seed_ids):
|
|
"""PUT exposure via registry → GET via registry."""
|
|
company_id = seed_ids["companies"]["MSFT"]
|
|
payload = {
|
|
"geographic_revenue_mix": {
|
|
"North America": 0.55,
|
|
"Europe": 0.25,
|
|
"Asia": 0.20,
|
|
},
|
|
"supply_chain_regions": ["North America", "Europe"],
|
|
"key_input_commodities": [],
|
|
"regulatory_jurisdictions": ["US", "EU"],
|
|
"market_position_tier": "global_leader",
|
|
"export_dependency_pct": 0.35,
|
|
"source": "manual",
|
|
"confidence": 0.85,
|
|
}
|
|
put_resp = await registry_client.put(
|
|
f"/companies/{company_id}/exposure", json=payload,
|
|
)
|
|
assert put_resp.status_code == 200
|
|
|
|
# Read back
|
|
get_resp = await registry_client.get(
|
|
f"/companies/{company_id}/exposure",
|
|
)
|
|
assert get_resp.status_code == 200
|
|
data = get_resp.json()
|
|
assert data["geographic_revenue_mix"]["North America"] == 0.55
|
|
assert data["market_position_tier"] == "global_leader"
|
|
assert "supply_chain_regions" in data
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Cross-Service: Competitor relationship bidirectional visibility
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestCrossServiceCompetitorBidirectional:
|
|
"""Competitor relationships visible from both sides."""
|
|
|
|
async def test_competitor_bidirectional_visibility(
|
|
self, registry_client, seed_ids,
|
|
):
|
|
"""Competitor visible from both sides."""
|
|
aapl_id = seed_ids["companies"]["AAPL"]
|
|
msft_id = seed_ids["companies"]["MSFT"]
|
|
|
|
# Check from AAPL side
|
|
resp_a = await registry_client.get(
|
|
f"/companies/{aapl_id}/competitors",
|
|
)
|
|
assert resp_a.status_code == 200
|
|
a_partners = set()
|
|
for rel in resp_a.json():
|
|
if rel["company_a_id"] == aapl_id:
|
|
a_partners.add(rel["company_b_id"])
|
|
else:
|
|
a_partners.add(rel["company_a_id"])
|
|
assert msft_id in a_partners
|
|
|
|
# Check from MSFT side
|
|
resp_b = await registry_client.get(
|
|
f"/companies/{msft_id}/competitors",
|
|
)
|
|
assert resp_b.status_code == 200
|
|
b_partners = set()
|
|
for rel in resp_b.json():
|
|
if rel["company_a_id"] == msft_id:
|
|
b_partners.add(rel["company_b_id"])
|
|
else:
|
|
b_partners.add(rel["company_a_id"])
|
|
assert aapl_id in b_partners
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Cross-Service: Risk evaluation schema matches query API recommendations
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestCrossServiceRiskEvaluationSchema:
|
|
"""Risk evaluation schema matches what query API returns for recommendations."""
|
|
|
|
async def test_risk_evaluation_matches_recommendation(
|
|
self, risk_client, query_client, seed_ids,
|
|
):
|
|
"""Risk evaluation schema matches what query API returns for recommendations."""
|
|
# Evaluate via risk engine
|
|
eval_resp = await risk_client.post("/evaluate", json={
|
|
"order": {
|
|
"ticker": "AAPL",
|
|
"action": "buy",
|
|
"quantity": 10,
|
|
"estimated_value": 1855.00,
|
|
"confidence": 0.85,
|
|
},
|
|
})
|
|
assert eval_resp.status_code == 200
|
|
eval_data = eval_resp.json()
|
|
assert "evaluation_id" in eval_data
|
|
assert "eligible" in eval_data
|
|
assert "checks" in eval_data
|
|
|
|
# Query recommendation with risk evaluation
|
|
rec_id = seed_ids["recommendations"]["REC_01"]
|
|
rec_resp = await query_client.get(f"/api/recommendations/{rec_id}")
|
|
assert rec_resp.status_code == 200
|
|
rec_data = rec_resp.json()
|
|
assert "risk_evaluation" in rec_data
|