test_responsibilities.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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. quality = validate_matrix(
  41. "device_quality",
  42. [
  43. {
  44. "user_id": USER_A,
  45. "responsibility_role": "asset_manager",
  46. "raci_role": "accountable",
  47. }
  48. ],
  49. )
  50. assert quality[0].user_id == USER_A
  51. def test_responsibility_matrix_rejects_duplicates_and_unknown_values():
  52. from app.core.governance.responsibilities import (
  53. ResponsibilityValidationError,
  54. validate_matrix,
  55. )
  56. duplicate = {
  57. "user_id": USER_A,
  58. "responsibility_role": "asset_manager",
  59. "raci_role": "accountable",
  60. }
  61. with pytest.raises(ResponsibilityValidationError, match="duplicate"):
  62. validate_matrix("device_mapping", [duplicate, duplicate])
  63. with pytest.raises(ResponsibilityValidationError, match="resource type"):
  64. validate_matrix("dashboard", [duplicate])
  65. with pytest.raises(ResponsibilityValidationError, match="responsibility role"):
  66. validate_matrix(
  67. "business_domain",
  68. [
  69. {
  70. "user_id": USER_A,
  71. "responsibility_role": "supervisor",
  72. "raci_role": "accountable",
  73. }
  74. ],
  75. )
  76. def test_replace_is_revision_guarded_and_rejects_inactive_users():
  77. from app.core.governance.responsibilities import (
  78. ResponsibilityConflict,
  79. ResponsibilityService,
  80. ResponsibilityUserUnavailable,
  81. )
  82. class Repository:
  83. def replace(self, **kwargs):
  84. assert kwargs["expected_revision"] == 3
  85. if kwargs["assignments"][0].user_id == USER_B:
  86. raise ResponsibilityUserUnavailable("inactive user")
  87. raise ResponsibilityConflict("revision conflict")
  88. service = ResponsibilityService(Repository())
  89. with pytest.raises(ResponsibilityConflict):
  90. service.replace(
  91. resource_type="device_ontology",
  92. resource_uid="device-domain",
  93. assignments=[
  94. {
  95. "user_id": USER_A,
  96. "responsibility_role": "asset_manager",
  97. "raci_role": "accountable",
  98. }
  99. ],
  100. expected_revision=3,
  101. actor_uid=USER_A,
  102. )
  103. with pytest.raises(ResponsibilityUserUnavailable):
  104. service.replace(
  105. resource_type="device_ontology",
  106. resource_uid="device-domain",
  107. assignments=[
  108. {
  109. "user_id": USER_B,
  110. "responsibility_role": "asset_manager",
  111. "raci_role": "accountable",
  112. }
  113. ],
  114. expected_revision=3,
  115. actor_uid=USER_A,
  116. )