railiance-platform/tests/test_consumption_mode.py
codex 34a3123799
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Finish RAILIANCE-WP-0017 consumption-mode enforcement
Read the resource-control open/restricted signal and refuse new orders
that would exceed a restricted entity's published allowance. Open and
missing signals stay unchanged. Safety paths admit with an exception.
2026-08-15 14:56:02 +02:00

139 lines
4.5 KiB
Python

from __future__ import annotations
import importlib.util
import json
import sys
import tempfile
import unittest
from decimal import Decimal
from pathlib import Path
REPO_DIR = Path(__file__).resolve().parents[1]
SPEC = importlib.util.spec_from_file_location(
"consumption_mode", REPO_DIR / "scripts/consumption_mode.py"
)
cm = importlib.util.module_from_spec(SPEC)
assert SPEC.loader is not None
sys.modules[SPEC.name] = cm
SPEC.loader.exec_module(cm)
def restricted(allowance: str = "45.83") -> dict:
return {
"schema_version": "0.1",
"record_type": "consumption_mode",
"financial_entity_id": "entity:coulomb",
"period": "2026-09",
"consumption_mode": "restricted",
"new_transfer_charges_allowed_eur": allowance,
"terms_version": "0.1",
}
class ConsumptionModeTests(unittest.TestCase):
def test_open_entity_unchanged(self) -> None:
signal = restricted()
signal["consumption_mode"] = "open"
signal["new_transfer_charges_allowed_eur"] = None
result = cm.decide(
entity_id="entity:coulomb",
order_class="new-order",
estimate_eur=Decimal("200.00"),
signal=signal,
)
self.assertEqual(result["decision"], "admit")
self.assertEqual(result["reason"], "open")
def test_restricted_cannot_exceed_allowance(self) -> None:
result = cm.decide(
entity_id="entity:coulomb",
order_class="new-order",
estimate_eur=Decimal("45.84"),
signal=restricted(),
)
self.assertEqual(result["decision"], "refuse")
self.assertEqual(result["reason"], "exceeds-allowance")
def test_restricted_within_allowance(self) -> None:
result = cm.decide(
entity_id="entity:coulomb",
order_class="new-order",
estimate_eur=Decimal("45.83"),
signal=restricted(),
)
self.assertEqual(result["decision"], "admit")
self.assertEqual(result["reason"], "within-allowance")
def test_restricted_without_estimate_refused(self) -> None:
result = cm.decide(
entity_id="entity:coulomb",
order_class="elastic",
estimate_eur=None,
signal=restricted(),
)
self.assertEqual(result["decision"], "refuse")
self.assertEqual(result["reason"], "restricted-estimate-required")
def test_safety_admitted_as_exception(self) -> None:
result = cm.decide(
entity_id="entity:coulomb",
order_class="safety",
estimate_eur=Decimal("200.00"),
signal=restricted(),
)
self.assertEqual(result["decision"], "admit")
self.assertTrue(result["exception"])
def test_no_signal_is_not_restricted(self) -> None:
result = cm.decide(
entity_id="entity:coulomb",
order_class="new-order",
estimate_eur=Decimal("999.00"),
signal=None,
)
self.assertEqual(result["decision"], "admit")
self.assertEqual(result["reason"], "no-signal-not-restricted")
def test_railiance_self_use_always_open(self) -> None:
result = cm.decide(
entity_id="entity:railiance",
order_class="new-order",
estimate_eur=Decimal("999.00"),
signal=restricted(),
)
self.assertEqual(result["decision"], "admit")
self.assertEqual(result["reason"], "railiance-self-use")
def test_cli_refuses_restricted_overage(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
path = Path(tmp) / "signal.json"
path.write_text(json.dumps([restricted()]), encoding="utf-8")
code = cm.main(
[
"check",
"--entity",
"entity:coulomb",
"--estimate-eur",
"50",
"--signal",
str(path),
]
)
self.assertEqual(code, 2)
def test_cli_admits_open(self) -> None:
with tempfile.TemporaryDirectory() as tmp:
path = Path(tmp) / "signal.json"
path.write_text("[]", encoding="utf-8")
code = cm.main(
[
"check",
"--entity",
"entity:coulomb",
"--estimate-eur",
"50",
"--signal",
str(path),
]
)
self.assertEqual(code, 0)