73 lines
2.3 KiB
Python
73 lines
2.3 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
from datetime import UTC, datetime, timedelta
|
|
from uuid import uuid4
|
|
|
|
from packages.hub_core.domain import (
|
|
AuditEvent,
|
|
Operation,
|
|
Scope,
|
|
Workspace,
|
|
)
|
|
from packages.hub_core.errors import InvalidTransition, MissingProjectScope
|
|
from packages.hub_core.state_machines import transition
|
|
|
|
|
|
class DomainContractTests(unittest.TestCase):
|
|
def test_scope_requires_workspace_and_project_scope_is_explicit(self) -> None:
|
|
workspace_id = uuid4()
|
|
scope = Scope.workspace(workspace_id)
|
|
self.assertEqual(scope.workspace_id, workspace_id)
|
|
with self.assertRaises(MissingProjectScope):
|
|
scope.require_project()
|
|
|
|
def test_timestamps_must_be_timezone_aware(self) -> None:
|
|
with self.assertRaises(ValueError):
|
|
Workspace(
|
|
id=uuid4(),
|
|
slug="itworx",
|
|
name="ITWorx",
|
|
created_at=datetime.now(),
|
|
updated_at=datetime.now(),
|
|
)
|
|
|
|
def test_state_machines_reject_invalid_moves(self) -> None:
|
|
self.assertEqual(transition("operation", "requested", "planned"), "planned")
|
|
with self.assertRaises(InvalidTransition):
|
|
transition("operation", "requested", "succeeded")
|
|
|
|
def test_audit_domain_rejects_unknown_fields(self) -> None:
|
|
now = datetime.now(UTC)
|
|
with self.assertRaises(ValueError):
|
|
AuditEvent(
|
|
trace_id="trace",
|
|
workspace_id=uuid4(),
|
|
event_type="test",
|
|
outcome="success",
|
|
occurred_at=now,
|
|
unexpected=True,
|
|
)
|
|
|
|
def test_operation_contract_has_expiry_and_plan_hash(self) -> None:
|
|
now = datetime.now(UTC)
|
|
operation = Operation(
|
|
workspace_id=uuid4(),
|
|
project_id=uuid4(),
|
|
environment_id=uuid4(),
|
|
operation_type="future-write",
|
|
target_ref="target",
|
|
plan_hash="sha256:test",
|
|
requested_by="subject",
|
|
expires_at=now + timedelta(minutes=5),
|
|
created_at=now,
|
|
updated_at=now,
|
|
)
|
|
self.assertEqual(operation.state, "requested")
|
|
self.assertEqual(operation.revision, 1)
|
|
self.assertNotIn("password", operation.model_dump())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|