test_issue_event_api.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. import re
  2. from django.test import TestCase
  3. from django.urls import reverse
  4. from model_bakery import baker
  5. from glitchtip.test_utils.test_case import APIPermissionTestCase, GlitchTipTestCaseMixin
  6. def get_list_issue_event_url(issue_id: int) -> str:
  7. return reverse("api:list_issue_event", args=[issue_id])
  8. def get_issue_event_url(issue_id: int, event_id: str) -> str:
  9. return reverse(
  10. "api:get_issue_event",
  11. kwargs={"issue_id": issue_id, "event_id": event_id},
  12. )
  13. def get_latest_issue_event_url(issue_id: int) -> str:
  14. return reverse("api:get_latest_issue_event", kwargs={"issue_id": issue_id})
  15. def get_event_json_url(organization_slug: str, issue_id: int, event_id: str) -> str:
  16. return reverse(
  17. "api:get_event_json",
  18. kwargs={
  19. "organization_slug": organization_slug,
  20. "issue_id": issue_id,
  21. "event_id": event_id,
  22. },
  23. )
  24. class IssueEventAPITestCase(GlitchTipTestCaseMixin, TestCase):
  25. def setUp(self):
  26. super().create_logged_in_user()
  27. def test_multi_page_list(self):
  28. first_event = baker.make("issue_events.IssueEvent", issue__project=self.project)
  29. baker.make(
  30. "issue_events.IssueEvent",
  31. issue__project=self.project,
  32. issue_id=first_event.issue_id,
  33. _quantity=50,
  34. )
  35. last_event = baker.make(
  36. "issue_events.IssueEvent",
  37. issue__project=self.project,
  38. issue_id=first_event.issue_id,
  39. )
  40. url = get_list_issue_event_url(first_event.issue_id)
  41. with self.assertNumQueries(2):
  42. res = self.client.get(url)
  43. self.assertEqual(res.headers.get("X-Hits"), "52")
  44. self.assertIn('rel="previous"; results="false"', res.headers.get("Link"))
  45. self.assertEqual(res.json()[0]["id"], last_event.pk.hex)
  46. self.assertNotContains(res, first_event.pk.hex)
  47. pattern = r"(?<=\<).+?(?=\>)"
  48. links = re.findall(pattern, res.headers.get("Link"))
  49. res = self.client.get(links[1])
  50. self.assertEqual(res.headers.get("X-Hits"), "52")
  51. self.assertIn('rel="previous"; results="true"', res.headers.get("Link"))
  52. self.assertIn('rel="next"; results="false"', res.headers.get("Link"))
  53. self.assertEqual(res.json()[-1]["id"], first_event.pk.hex)
  54. self.assertNotContains(res, last_event.pk.hex)
  55. def test_single_page_list(self):
  56. """
  57. Single page query should not hit DB for count
  58. """
  59. first_event = baker.make("issue_events.IssueEvent", issue__project=self.project)
  60. last_event = baker.make(
  61. "issue_events.IssueEvent",
  62. issue__project=self.project,
  63. issue_id=first_event.issue_id,
  64. )
  65. url = get_list_issue_event_url(first_event.issue_id)
  66. with self.assertNumQueries(1):
  67. res = self.client.get(url)
  68. self.assertEqual(res.headers.get("X-Hits"), "2")
  69. self.assertContains(res, last_event.pk.hex)
  70. self.assertContains(res, first_event.pk.hex)
  71. def test_retrieve(self):
  72. issue = baker.make("issue_events.issue", project=self.project)
  73. baker.make("issue_events.IssueEvent", issue=issue, _quantity=10)
  74. previous_event = baker.make("issue_events.IssueEvent", issue=issue)
  75. latest_event = baker.make("issue_events.IssueEvent", issue=issue)
  76. url = get_issue_event_url(issue.id, "a" * 32)
  77. res = self.client.get(url)
  78. self.assertEqual(res.status_code, 404)
  79. url = get_issue_event_url(issue.id, latest_event.id)
  80. res = self.client.get(url)
  81. self.assertContains(res, latest_event.pk.hex)
  82. url = get_latest_issue_event_url(issue.id)
  83. res = self.client.get(url)
  84. event_details = res.json()
  85. self.assertEqual(event_details["id"], latest_event.pk.hex)
  86. self.assertEqual(event_details["previousEventID"], previous_event.pk.hex)
  87. def test_relative_event_ordering(self):
  88. issue = baker.make("issue_events.issue", project=self.project)
  89. baker.make("issue_events.IssueEvent", issue=issue)
  90. event1 = baker.make("issue_events.IssueEvent", issue=issue)
  91. event2 = baker.make("issue_events.IssueEvent", issue=issue)
  92. event3 = baker.make("issue_events.IssueEvent", issue=issue)
  93. baker.make("issue_events.IssueEvent", issue=issue)
  94. url = get_issue_event_url(issue.id, event2.id)
  95. res = self.client.get(url)
  96. event_details = res.json()
  97. self.assertEqual(event_details["nextEventID"], event3.pk.hex)
  98. self.assertEqual(event_details["previousEventID"], event1.pk.hex)
  99. def test_authentication(self):
  100. url = get_list_issue_event_url(1)
  101. self.client.logout()
  102. res = self.client.get(url)
  103. self.assertEqual(res.status_code, 401)
  104. class IssueEventAPIPermissionTestCase(APIPermissionTestCase):
  105. def setUp(self):
  106. self.create_user_org()
  107. self.set_client_credentials(self.auth_token.token)
  108. self.team = baker.make("teams.Team", organization=self.organization)
  109. self.team.members.add(self.org_user)
  110. self.project = baker.make("projects.Project", organization=self.organization)
  111. self.project.team_set.add(self.team)
  112. self.event = baker.make("issue_events.IssueEvent", issue__project=self.project)
  113. self.list_url = get_list_issue_event_url(self.event.issue_id)
  114. self.project_list_url = reverse(
  115. "api:list_project_issue_event",
  116. kwargs={
  117. "organization_slug": self.organization.slug,
  118. "project_slug": self.project.slug,
  119. },
  120. )
  121. self.detail_url = get_issue_event_url(self.event.issue_id, self.event.pk)
  122. self.project_detail_url = reverse(
  123. "api:get_project_issue_event",
  124. kwargs={
  125. "organization_slug": self.organization.slug,
  126. "project_slug": self.project.slug,
  127. "event_id": self.event.pk.hex,
  128. },
  129. )
  130. self.latest_detail_url = get_latest_issue_event_url(self.event.issue_id)
  131. self.event_json_url = get_event_json_url(
  132. self.organization.slug, self.event.issue_id, self.event.pk
  133. )
  134. def test_list(self):
  135. self.assertGetReqStatusCode(self.list_url, 403)
  136. self.assertGetReqStatusCode(self.project_list_url, 403)
  137. self.auth_token.add_permission("event:read")
  138. self.assertGetReqStatusCode(self.list_url, 200)
  139. self.assertGetReqStatusCode(self.project_list_url, 200)
  140. def test_retrieve(self):
  141. self.assertGetReqStatusCode(self.detail_url, 403)
  142. self.assertGetReqStatusCode(self.project_detail_url, 403)
  143. self.assertGetReqStatusCode(self.latest_detail_url, 403)
  144. self.auth_token.add_permission("event:read")
  145. self.assertGetReqStatusCode(self.detail_url, 200)
  146. self.assertGetReqStatusCode(self.project_detail_url, 200)
  147. self.assertGetReqStatusCode(self.latest_detail_url, 200)
  148. def test_event_json_view(self):
  149. url = self.event_json_url
  150. self.assertGetReqStatusCode(url, 403)
  151. self.auth_token.add_permission("event:read")
  152. self.assertGetReqStatusCode(url, 200)
  153. class CommentsAPIPermissionTests(APIPermissionTestCase):
  154. def setUp(self):
  155. self.create_org_team_project()
  156. self.set_client_credentials(self.auth_token.token)
  157. self.project = baker.make("projects.Project", organization=self.organization)
  158. self.issue = baker.make("issue_events.Issue", project=self.project)
  159. self.comment = baker.make(
  160. "issue_events.Comment", issue=self.issue, user=self.user, text="text"
  161. )
  162. self.list_url = reverse(
  163. "api:list_comments",
  164. kwargs={"issue_id": self.issue.id},
  165. )
  166. def test_list(self):
  167. self.assertGetReqStatusCode(self.list_url, 403)
  168. self.auth_token.add_permission("event:read")
  169. self.assertGetReqStatusCode(self.list_url, 200)
  170. def test_create(self):
  171. self.auth_token.add_permission("event:read")
  172. data = {"data": {"text": "Test"}}
  173. url = reverse(
  174. "api:add_comment",
  175. kwargs={"issue_id": self.issue.id},
  176. )
  177. self.assertPostReqStatusCode(url, data, 403)
  178. self.auth_token.add_permission("event:write")
  179. self.assertPostReqStatusCode(url, data, 201)
  180. def test_destroy(self):
  181. self.auth_token.add_permissions(["event:read", "event:write"])
  182. url = reverse(
  183. "api:delete_comment",
  184. kwargs={"issue_id": self.issue.id, "comment_id": self.comment.id},
  185. )
  186. self.assertDeleteReqStatusCode(url, 403)
  187. self.auth_token.add_permission("event:admin")
  188. self.assertDeleteReqStatusCode(url, 204)
  189. def test_update(self):
  190. self.auth_token.add_permission("event:read")
  191. data = {"data": {"text": "Test"}}
  192. url = reverse(
  193. "api:update_comment",
  194. kwargs={"issue_id": self.issue.id, "comment_id": self.comment.id},
  195. )
  196. self.assertPutReqStatusCode(url, data, 403)
  197. self.auth_token.add_permission("event:write")
  198. self.assertPutReqStatusCode(url, data, 200)