from __future__ import annotations from fastapi.testclient import TestClient from agents.credit_risk.schema import CreditRiskOutput from agents.kyc_identity.schema import KycIdentityOutput from agents.risk_consultant.schema import RiskConsultantOutput from agents.sanctions_pep.schema import SanctionsPepOutput from agents.transaction_fraud.schema import TransactionFraudOutput from api import app client = TestClient(app) ORIGIN = {"Origin": "https://example.com"} VALID_FRAUD = { "transaction_id": "api-fraud-001", "amount": 9500.0, "hour_of_day": 3, "is_international": True, "merchant_category": "electronics", "transaction_velocity_1h": 8, "amount_vs_avg_ratio": 4.5, "is_new_device": True, "distance_from_home_km": 650.0, "failed_attempts_before": 2, "account_age_days": 15, } VALID_CREDIT = { "applicant_id": "api-credit-001", "credit_score": 720, "debt_to_income_ratio": 0.24, "employment_months": 48, "num_open_accounts": 5, "payment_history_missed": 0, "loan_amount": 26000.0, "revolving_utilization": 0.28, "recent_hard_inquiries": 1, "collateral_value": 32000.0, "loan_purpose": "auto", } VALID_KYC = { "application_id": "api-kyc-001", "id_document_age_days": 365, "address_match_score": 0.95, "name_vs_id_match_score": 0.97, "selfie_liveness_score": 0.96, "num_accounts_same_address": 1, "phone_age_days": 400, "email_domain_risk": 3, "ip_country_vs_id_country_match": True, "velocity_applications_7d": 1, } VALID_SANCTIONS = {"query_name": "John Smith", "country": ""} VALID_CONSULTANT = {"question": "What velocity rules are most effective for card fraud?"} def test_valid_agent_endpoints_and_cors() -> None: fraud_response = client.post("/api/v1/fraud/predict", json=VALID_FRAUD, headers=ORIGIN) credit_response = client.post("/api/v1/credit/predict", json=VALID_CREDIT, headers=ORIGIN) kyc_response = client.post("/api/v1/kyc/predict", json=VALID_KYC, headers=ORIGIN) sanctions_response = client.post("/api/v1/sanctions/screen", json=VALID_SANCTIONS, headers=ORIGIN) consultant_response = client.post("/api/v1/consultant/ask", json=VALID_CONSULTANT, headers=ORIGIN) assert fraud_response.status_code == 200 assert credit_response.status_code == 200 assert kyc_response.status_code == 200 assert sanctions_response.status_code == 200 assert consultant_response.status_code == 200 TransactionFraudOutput.model_validate(fraud_response.json()) CreditRiskOutput.model_validate(credit_response.json()) KycIdentityOutput.model_validate(kyc_response.json()) SanctionsPepOutput.model_validate(sanctions_response.json()) RiskConsultantOutput.model_validate(consultant_response.json()) assert fraud_response.headers["access-control-allow-origin"] in {"*", "https://example.com"} def test_validation_errors_and_health() -> None: fraud_bad = client.post("/api/v1/fraud/predict", json={"transaction_id": "missing-fields"}) credit_bad = client.post("/api/v1/credit/predict", json={"applicant_id": "missing-fields"}) kyc_bad = client.post("/api/v1/kyc/predict", json={"application_id": "missing-fields"}) sanctions_bad = client.post("/api/v1/sanctions/screen", json={}) consultant_bad = client.post("/api/v1/consultant/ask", json={}) assert fraud_bad.status_code == 422 assert credit_bad.status_code == 422 assert kyc_bad.status_code == 422 assert sanctions_bad.status_code == 422 assert consultant_bad.status_code == 422 root_health = client.get("/health") fraud_schema = client.get("/api/v1/fraud/schema") assert root_health.status_code == 200 assert root_health.json() == {"status": "ok", "agents": ["fraud", "credit", "kyc", "sanctions", "consultant"]} assert fraud_schema.status_code == 200 assert any(field["name"] == "transaction_id" for field in fraud_schema.json()["fields"])