import pandas as pd import pytest from app.config import settings from app.scoring import build_feature_row, load_model_bundle, risk_tier, score_transaction EMPTY_HISTORY = pd.DataFrame( columns=[ "step", "type", "amount", "nameOrig", "oldbalanceOrg", "newbalanceOrig", "nameDest", "oldbalanceDest", "newbalanceDest", ] ) @pytest.fixture(scope="module") def bundle(): return load_model_bundle(settings.MODEL_PATH) def test_risk_tier_bands(): assert risk_tier(0.1) == "low" assert risk_tier(0.3) == "medium" assert risk_tier(0.69) == "medium" assert risk_tier(0.7) == "high" assert risk_tier(0.99) == "high" def test_fraud_drain_pattern_scores_high(bundle): raw = { "step": 5, "type": "TRANSFER", "amount": 181.0, "nameOrig": "CFRAUD1", "oldbalanceOrg": 181.0, "newbalanceOrig": 0.0, "nameDest": "CFRAUD2", "oldbalanceDest": 0.0, "newbalanceDest": 0.0, } row = build_feature_row(EMPTY_HISTORY, raw) result = score_transaction(bundle, row) assert result["risk_tier"] == "high" assert result["probability"] > 0.5 assert len(result["top_features"]) == 5 assert result["model_version"] def test_legit_payment_scores_low(bundle): raw = { "step": 5, "type": "PAYMENT", "amount": 50.0, "nameOrig": "CLEGIT1", "oldbalanceOrg": 5000.0, "newbalanceOrig": 4950.0, "nameDest": "MMERCHANT1", "oldbalanceDest": 0.0, "newbalanceDest": 0.0, } row = build_feature_row(EMPTY_HISTORY, raw) result = score_transaction(bundle, row) assert result["risk_tier"] == "low" assert result["probability"] < 0.3 def test_build_feature_row_uses_prior_history_for_velocity(bundle): history = pd.DataFrame( [ { "step": 1, "type": "PAYMENT", "amount": 10.0, "nameOrig": "CVEL1", "oldbalanceOrg": 100.0, "newbalanceOrig": 90.0, "nameDest": "MVEL1", "oldbalanceDest": 0.0, "newbalanceDest": 0.0, }, { "step": 2, "type": "PAYMENT", "amount": 10.0, "nameOrig": "CVEL1", "oldbalanceOrg": 90.0, "newbalanceOrig": 80.0, "nameDest": "MVEL1", "oldbalanceDest": 0.0, "newbalanceDest": 0.0, }, ] ) raw = { "step": 3, "type": "PAYMENT", "amount": 10.0, "nameOrig": "CVEL1", "oldbalanceOrg": 80.0, "newbalanceOrig": 70.0, "nameDest": "MVEL1", "oldbalanceDest": 0.0, "newbalanceDest": 0.0, } row = build_feature_row(history, raw) assert row.iloc[0]["orig_prior_txn_count"] == 2