feat: define policy impact subject contract
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from govoplan_core.core.policy import (
|
||||
CAPABILITY_POLICY_IMPACT_SUBJECT_PREFIX,
|
||||
PolicyImpactPopulationRequest,
|
||||
PolicyImpactSubject,
|
||||
PolicyImpactSubjectBatch,
|
||||
PolicyImpactSubjectProvider,
|
||||
policy_impact_subject_provider,
|
||||
)
|
||||
|
||||
|
||||
class _Provider:
|
||||
provider_id = "example"
|
||||
supported_policy_families = ("view",)
|
||||
|
||||
def collect_policy_impact_subjects(
|
||||
self,
|
||||
session: object | None = None,
|
||||
*,
|
||||
request: PolicyImpactPopulationRequest,
|
||||
) -> PolicyImpactSubjectBatch:
|
||||
del session, request
|
||||
return PolicyImpactSubjectBatch(
|
||||
provider_id=self.provider_id,
|
||||
subjects=(
|
||||
PolicyImpactSubject(
|
||||
module_id="example",
|
||||
resource_type="record",
|
||||
resource_id="record-1",
|
||||
action="view",
|
||||
),
|
||||
),
|
||||
total_available=1,
|
||||
)
|
||||
|
||||
|
||||
class _Registry:
|
||||
def __init__(self, capability: object) -> None:
|
||||
self._capability = capability
|
||||
|
||||
def has_capability(self, name: str) -> bool:
|
||||
return name == f"{CAPABILITY_POLICY_IMPACT_SUBJECT_PREFIX}example"
|
||||
|
||||
def capability(self, name: str) -> object:
|
||||
del name
|
||||
return self._capability
|
||||
|
||||
|
||||
class PolicyImpactContractTests(unittest.TestCase):
|
||||
def test_provider_contract_is_runtime_checkable_and_discoverable(self) -> None:
|
||||
provider = _Provider()
|
||||
self.assertIsInstance(provider, PolicyImpactSubjectProvider)
|
||||
self.assertIs(
|
||||
policy_impact_subject_provider(_Registry(provider), "example"),
|
||||
provider,
|
||||
)
|
||||
|
||||
def test_population_and_provider_batches_are_bounded(self) -> None:
|
||||
with self.assertRaisesRegex(ValueError, "between 1 and 500"):
|
||||
PolicyImpactPopulationRequest(
|
||||
tenant_id="tenant-1",
|
||||
policy_family="view",
|
||||
limit=501,
|
||||
)
|
||||
with self.assertRaisesRegex(ValueError, "at most 500"):
|
||||
PolicyImpactSubjectBatch(
|
||||
provider_id="example",
|
||||
subjects=tuple(
|
||||
PolicyImpactSubject(
|
||||
module_id="example",
|
||||
resource_type="record",
|
||||
resource_id=str(index),
|
||||
action="view",
|
||||
)
|
||||
for index in range(501)
|
||||
),
|
||||
)
|
||||
|
||||
def test_unavailable_batches_explain_the_gap(self) -> None:
|
||||
with self.assertRaisesRegex(ValueError, "need an explanation"):
|
||||
PolicyImpactSubjectBatch(
|
||||
provider_id="example",
|
||||
state="unavailable",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user