test_responsibilities.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. from __future__ import annotations
  2. import pytest
  3. USER_A = "01900000-0000-7000-8000-000000000101"
  4. USER_B = "01900000-0000-7000-8000-000000000102"
  5. def test_device_scope_requires_one_accountable_asset_manager():
  6. from app.core.governance.responsibilities import (
  7. ResponsibilityValidationError,
  8. validate_matrix,
  9. )
  10. with pytest.raises(
  11. ResponsibilityValidationError,
  12. match="one accountable asset manager",
  13. ):
  14. validate_matrix(
  15. "device_asset",
  16. [
  17. {
  18. "user_id": USER_A,
  19. "responsibility_role": "data_steward",
  20. "raci_role": "responsible",
  21. }
  22. ],
  23. )
  24. validated = validate_matrix(
  25. "device_asset",
  26. [
  27. {
  28. "user_id": USER_A,
  29. "responsibility_role": "asset_manager",
  30. "raci_role": "accountable",
  31. },
  32. {
  33. "user_id": USER_B,
  34. "responsibility_role": "data_steward",
  35. "raci_role": "responsible",
  36. },
  37. ],
  38. )
  39. assert [item.user_id for item in validated] == [USER_A, USER_B]
  40. def test_responsibility_matrix_rejects_duplicates_and_unknown_values():
  41. from app.core.governance.responsibilities import (
  42. ResponsibilityValidationError,
  43. validate_matrix,
  44. )
  45. duplicate = {
  46. "user_id": USER_A,
  47. "responsibility_role": "asset_manager",
  48. "raci_role": "accountable",
  49. }
  50. with pytest.raises(ResponsibilityValidationError, match="duplicate"):
  51. validate_matrix("device_mapping", [duplicate, duplicate])
  52. with pytest.raises(ResponsibilityValidationError, match="resource type"):
  53. validate_matrix("dashboard", [duplicate])
  54. with pytest.raises(ResponsibilityValidationError, match="responsibility role"):
  55. validate_matrix(
  56. "business_domain",
  57. [
  58. {
  59. "user_id": USER_A,
  60. "responsibility_role": "supervisor",
  61. "raci_role": "accountable",
  62. }
  63. ],
  64. )
  65. def test_replace_is_revision_guarded_and_rejects_inactive_users():
  66. from app.core.governance.responsibilities import (
  67. ResponsibilityConflict,
  68. ResponsibilityService,
  69. ResponsibilityUserUnavailable,
  70. )
  71. class Repository:
  72. def replace(self, **kwargs):
  73. assert kwargs["expected_revision"] == 3
  74. if kwargs["assignments"][0].user_id == USER_B:
  75. raise ResponsibilityUserUnavailable("inactive user")
  76. raise ResponsibilityConflict("revision conflict")
  77. service = ResponsibilityService(Repository())
  78. with pytest.raises(ResponsibilityConflict):
  79. service.replace(
  80. resource_type="device_ontology",
  81. resource_uid="device-domain",
  82. assignments=[
  83. {
  84. "user_id": USER_A,
  85. "responsibility_role": "asset_manager",
  86. "raci_role": "accountable",
  87. }
  88. ],
  89. expected_revision=3,
  90. actor_uid=USER_A,
  91. )
  92. with pytest.raises(ResponsibilityUserUnavailable):
  93. service.replace(
  94. resource_type="device_ontology",
  95. resource_uid="device-domain",
  96. assignments=[
  97. {
  98. "user_id": USER_B,
  99. "responsibility_role": "asset_manager",
  100. "raci_role": "accountable",
  101. }
  102. ],
  103. expected_revision=3,
  104. actor_uid=USER_A,
  105. )