test_responsibility_api.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. from __future__ import annotations
  2. USER_A = "01900000-0000-7000-8000-000000000101"
  3. class FakeService:
  4. def __init__(self):
  5. self.calls = []
  6. def get(self, resource_type, resource_uid):
  7. self.calls.append(("get", resource_type, resource_uid))
  8. return {
  9. "resource_type": resource_type,
  10. "resource_uid": resource_uid,
  11. "revision": 2,
  12. "assignments": [],
  13. }
  14. def replace(self, **kwargs):
  15. self.calls.append(("replace", kwargs))
  16. return {
  17. "resource_type": kwargs["resource_type"],
  18. "resource_uid": kwargs["resource_uid"],
  19. "revision": kwargs["expected_revision"] + 1,
  20. "assignments": [
  21. {
  22. **item,
  23. "username": "asset_admin",
  24. "display_name": "设备资产管理员",
  25. }
  26. for item in kwargs["assignments"]
  27. ],
  28. }
  29. def _headers(role: str, **extra):
  30. return {"Authorization": f"Bearer {role}", **extra}
  31. def test_responsibility_matrix_is_readable_but_only_admin_can_replace(monkeypatch):
  32. from app import create_app
  33. from app.api.system import responsibilities
  34. service = FakeService()
  35. monkeypatch.setattr(responsibilities, "_service", lambda: service)
  36. monkeypatch.setattr(
  37. "app.core.system.auth.load_identity_from_token",
  38. lambda token, secret: (
  39. {"id": USER_A, "username": token, "roles": [token]}
  40. if token in {"viewer", "editor", "admin"}
  41. else None
  42. ),
  43. )
  44. app = create_app()
  45. app.config.update(TESTING=True)
  46. client = app.test_client()
  47. readable = client.get(
  48. "/api/system/responsibilities/device_asset/device-1",
  49. headers=_headers("viewer"),
  50. )
  51. assert readable.status_code == 200
  52. assert readable.headers["ETag"] == '"2"'
  53. payload = {
  54. "assignments": [
  55. {
  56. "user_id": USER_A,
  57. "responsibility_role": "asset_manager",
  58. "raci_role": "accountable",
  59. }
  60. ]
  61. }
  62. forbidden = client.put(
  63. "/api/system/responsibilities/device_asset/device-1",
  64. json=payload,
  65. headers=_headers("editor", **{"If-Match": '"2"'}),
  66. )
  67. assert forbidden.status_code == 403
  68. missing_revision = client.put(
  69. "/api/system/responsibilities/device_asset/device-1",
  70. json=payload,
  71. headers=_headers("admin"),
  72. )
  73. assert missing_revision.status_code == 428
  74. updated = client.put(
  75. "/api/system/responsibilities/device_asset/device-1",
  76. json=payload,
  77. headers=_headers("admin", **{"If-Match": '"2"'}),
  78. )
  79. assert updated.status_code == 200
  80. assert updated.headers["ETag"] == '"3"'
  81. assert service.calls[-1][1]["actor_uid"] == USER_A
  82. def test_responsibility_paths_have_dedicated_permissions():
  83. from app.core.system.permissions import (
  84. RESPONSIBILITIES_MANAGE,
  85. RESPONSIBILITIES_READ,
  86. permission_for_request,
  87. )
  88. path = "/api/system/responsibilities/device_asset/device-1"
  89. assert permission_for_request(path, "GET") == (RESPONSIBILITIES_READ,)
  90. assert permission_for_request(path, "PUT") == (RESPONSIBILITIES_MANAGE,)