81 lines
2.5 KiB
Python
81 lines
2.5 KiB
Python
"""Tests for CER-016 risk guard."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
from fastapi import HTTPException
|
|
from option_mcp_common.risk_guard import (
|
|
enforce_aggregate,
|
|
enforce_leverage,
|
|
enforce_single_notional,
|
|
max_aggregate,
|
|
max_leverage,
|
|
max_notional,
|
|
)
|
|
|
|
|
|
def test_defaults(monkeypatch):
|
|
for k in ("CERBERO_MAX_NOTIONAL", "CERBERO_MAX_AGGREGATE", "CERBERO_MAX_LEVERAGE"):
|
|
monkeypatch.delenv(k, raising=False)
|
|
assert max_notional() == 200.0
|
|
assert max_aggregate() == 1000.0
|
|
assert max_leverage() == 3
|
|
|
|
|
|
def test_env_override(monkeypatch):
|
|
monkeypatch.setenv("CERBERO_MAX_NOTIONAL", "50")
|
|
monkeypatch.setenv("CERBERO_MAX_AGGREGATE", "150")
|
|
monkeypatch.setenv("CERBERO_MAX_LEVERAGE", "2")
|
|
assert max_notional() == 50.0
|
|
assert max_aggregate() == 150.0
|
|
assert max_leverage() == 2
|
|
|
|
|
|
def test_leverage_default_when_none(monkeypatch):
|
|
monkeypatch.delenv("CERBERO_MAX_LEVERAGE", raising=False)
|
|
assert enforce_leverage(None) == 3
|
|
|
|
|
|
def test_leverage_accepts_within_cap(monkeypatch):
|
|
monkeypatch.delenv("CERBERO_MAX_LEVERAGE", raising=False)
|
|
assert enforce_leverage(2) == 2
|
|
assert enforce_leverage(3) == 3
|
|
|
|
|
|
def test_leverage_rejects_above_cap(monkeypatch):
|
|
monkeypatch.delenv("CERBERO_MAX_LEVERAGE", raising=False)
|
|
with pytest.raises(HTTPException) as exc:
|
|
enforce_leverage(50)
|
|
assert exc.value.status_code == 403
|
|
assert exc.value.detail["error"] == "HARD_PROHIBITION"
|
|
|
|
|
|
def test_leverage_rejects_below_one(monkeypatch):
|
|
with pytest.raises(HTTPException):
|
|
enforce_leverage(0)
|
|
|
|
|
|
def test_single_notional_ok(monkeypatch):
|
|
monkeypatch.delenv("CERBERO_MAX_NOTIONAL", raising=False)
|
|
enforce_single_notional(100.0, exchange="deribit", instrument="BTC-PERPETUAL")
|
|
|
|
|
|
def test_single_notional_rejects(monkeypatch):
|
|
monkeypatch.delenv("CERBERO_MAX_NOTIONAL", raising=False)
|
|
with pytest.raises(HTTPException) as exc:
|
|
enforce_single_notional(335.0, exchange="hyperliquid", instrument="ETH")
|
|
assert exc.value.status_code == 403
|
|
assert "335" in exc.value.detail["message"]
|
|
|
|
|
|
def test_aggregate_ok(monkeypatch):
|
|
monkeypatch.delenv("CERBERO_MAX_AGGREGATE", raising=False)
|
|
enforce_aggregate(current_total=500.0, new_notional=200.0)
|
|
|
|
|
|
def test_aggregate_rejects(monkeypatch):
|
|
monkeypatch.delenv("CERBERO_MAX_AGGREGATE", raising=False)
|
|
with pytest.raises(HTTPException) as exc:
|
|
enforce_aggregate(current_total=900.0, new_notional=200.0)
|
|
assert exc.value.status_code == 403
|