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.
This commit is contained in:
parent
bf8c26cd61
commit
34a3123799
8 changed files with 437 additions and 4 deletions
139
tests/test_consumption_mode.py
Normal file
139
tests/test_consumption_mode.py
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue