Files
govoplan-core/tests/test_governance_projection_contract.py

62 lines
1.9 KiB
Python

from __future__ import annotations
import unittest
from govoplan_core.core.access import (
AccessGovernanceProjectionV1,
GovernanceProjectionBatch,
GovernanceProjectionCommand,
GovernanceProjectionResult,
GovernanceTemplateMaterialization,
)
def _command(assignment_id: str) -> GovernanceProjectionCommand:
return GovernanceProjectionCommand(
assignment_id=assignment_id,
operation="upsert",
template=GovernanceTemplateMaterialization(
template_id="template-1",
kind="role",
tenant_id=f"tenant-{assignment_id}",
slug="reader",
name="Reader",
),
provenance={"source": "contract-test"},
)
class _Projection:
def reconcile(self, session: object, batch: GovernanceProjectionBatch) -> GovernanceProjectionResult:
del session
return GovernanceProjectionResult(
operation_id=batch.operation_id,
outcomes=(),
dry_run=batch.dry_run,
)
class GovernanceProjectionContractTests(unittest.TestCase):
def test_protocol_is_runtime_checkable(self) -> None:
self.assertIsInstance(_Projection(), AccessGovernanceProjectionV1)
def test_batch_rejects_duplicate_assignment_ids(self) -> None:
with self.assertRaisesRegex(ValueError, "unique"):
GovernanceProjectionBatch(
operation_id="duplicate",
commands=(_command("same"), _command("same")),
)
def test_batch_enforces_bounds(self) -> None:
with self.assertRaisesRegex(ValueError, "between 1 and 500"):
GovernanceProjectionBatch(operation_id="empty", commands=())
with self.assertRaisesRegex(ValueError, "between 1 and 500"):
GovernanceProjectionBatch(
operation_id="large",
commands=tuple(_command(str(index)) for index in range(501)),
)
if __name__ == "__main__":
unittest.main()