test_group_events.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. from datetime import timedelta
  2. from django.utils import timezone
  3. from freezegun import freeze_time
  4. from sentry.testutils import APITestCase, SnubaTestCase
  5. from sentry.testutils.helpers.datetime import before_now, iso_format
  6. from sentry.utils.compat import map
  7. class GroupEventsTest(APITestCase, SnubaTestCase):
  8. def setUp(self):
  9. super().setUp()
  10. self.min_ago = before_now(minutes=1)
  11. def test_simple(self):
  12. self.login_as(user=self.user)
  13. event_1 = self.store_event(
  14. data={
  15. "event_id": "a" * 32,
  16. "fingerprint": ["1"],
  17. "timestamp": iso_format(self.min_ago),
  18. },
  19. project_id=self.project.id,
  20. )
  21. event_2 = self.store_event(
  22. data={
  23. "event_id": "b" * 32,
  24. "fingerprint": ["1"],
  25. "timestamp": iso_format(self.min_ago),
  26. },
  27. project_id=self.project.id,
  28. )
  29. url = f"/api/0/issues/{event_1.group.id}/events/"
  30. response = self.client.get(url, format="json")
  31. assert response.status_code == 200, response.content
  32. assert len(response.data) == 2
  33. assert sorted(map(lambda x: x["eventID"], response.data)) == sorted(
  34. [str(event_1.event_id), str(event_2.event_id)]
  35. )
  36. def test_tags(self):
  37. self.login_as(user=self.user)
  38. event_1 = self.store_event(
  39. data={
  40. "event_id": "a" * 32,
  41. "fingerprint": ["1"],
  42. "tags": {"foo": "baz", "bar": "buz"},
  43. "timestamp": iso_format(self.min_ago),
  44. },
  45. project_id=self.project.id,
  46. )
  47. event_2 = self.store_event(
  48. data={
  49. "event_id": "b" * 32,
  50. "fingerprint": ["1"],
  51. "tags": {"bar": "biz"},
  52. "timestamp": iso_format(before_now(seconds=61)),
  53. },
  54. project_id=self.project.id,
  55. )
  56. url = f"/api/0/issues/{event_1.group.id}/events/"
  57. response = self.client.get(url + "?query=foo:baz", format="json")
  58. assert response.status_code == 200, response.content
  59. assert len(response.data) == 1
  60. assert response.data[0]["eventID"] == str(event_1.event_id)
  61. response = self.client.get(url + "?query=!foo:baz", format="json")
  62. assert response.status_code == 200, response.content
  63. assert len(response.data) == 1
  64. assert response.data[0]["eventID"] == str(event_2.event_id)
  65. response = self.client.get(url + "?query=bar:biz", format="json")
  66. assert response.status_code == 200, response.content
  67. assert len(response.data) == 1
  68. assert response.data[0]["eventID"] == str(event_2.event_id)
  69. response = self.client.get(url + "?query=bar:biz%20foo:baz", format="json")
  70. assert response.status_code == 200, response.content
  71. assert len(response.data) == 0
  72. response = self.client.get(url + "?query=bar:buz%20foo:baz", format="json")
  73. assert response.status_code == 200, response.content
  74. assert len(response.data) == 1
  75. assert response.data[0]["eventID"] == str(event_1.event_id)
  76. response = self.client.get(url + "?query=bar:baz", format="json")
  77. assert response.status_code == 200, response.content
  78. assert len(response.data) == 0
  79. response = self.client.get(url + "?query=a:b", format="json")
  80. assert response.status_code == 200, response.content
  81. assert len(response.data) == 0
  82. response = self.client.get(url + "?query=bar:b", format="json")
  83. assert response.status_code == 200, response.content
  84. assert len(response.data) == 0
  85. response = self.client.get(url + "?query=bar:baz", format="json")
  86. assert response.status_code == 200, response.content
  87. assert len(response.data) == 0
  88. response = self.client.get(url + "?query=!bar:baz", format="json")
  89. assert response.status_code == 200, response.content
  90. assert len(response.data) == 2
  91. assert {e["eventID"] for e in response.data} == {event_1.event_id, event_2.event_id}
  92. def test_search_event_by_id(self):
  93. self.login_as(user=self.user)
  94. event_1 = self.store_event(
  95. data={
  96. "event_id": "a" * 32,
  97. "fingerprint": ["group-1"],
  98. "timestamp": iso_format(self.min_ago),
  99. },
  100. project_id=self.project.id,
  101. )
  102. self.store_event(
  103. data={
  104. "event_id": "b" * 32,
  105. "fingerprint": ["group-1"],
  106. "timestamp": iso_format(self.min_ago),
  107. },
  108. project_id=self.project.id,
  109. )
  110. url = f"/api/0/issues/{event_1.group.id}/events/?query={event_1.event_id}"
  111. response = self.client.get(url, format="json")
  112. assert response.status_code == 200, response.content
  113. assert len(response.data) == 1
  114. assert response.data[0]["eventID"] == event_1.event_id
  115. def test_search_event_by_message(self):
  116. self.login_as(user=self.user)
  117. event_1 = self.store_event(
  118. data={
  119. "event_id": "a" * 32,
  120. "fingerprint": ["group-1"],
  121. "message": "foo bar hello world",
  122. "timestamp": iso_format(self.min_ago),
  123. },
  124. project_id=self.project.id,
  125. )
  126. group = event_1.group
  127. event_2 = self.store_event(
  128. data={
  129. "event_id": "b" * 32,
  130. "fingerprint": ["group-1"],
  131. "message": "this bar hello world",
  132. "timestamp": iso_format(self.min_ago),
  133. },
  134. project_id=self.project.id,
  135. )
  136. assert group == event_2.group
  137. query_1 = "foo"
  138. query_2 = "hello+world"
  139. # Single Word Query
  140. url = f"/api/0/issues/{group.id}/events/?query={query_1}"
  141. response = self.client.get(url, format="json")
  142. assert response.status_code == 200, response.content
  143. assert len(response.data) == 1
  144. assert response.data[0]["eventID"] == event_1.event_id
  145. # Multiple Word Query
  146. url = f"/api/0/issues/{group.id}/events/?query={query_2}"
  147. response = self.client.get(url, format="json")
  148. assert response.status_code == 200, response.content
  149. assert len(response.data) == 2
  150. assert sorted(map(lambda x: x["eventID"], response.data)) == sorted(
  151. [str(event_1.event_id), str(event_2.event_id)]
  152. )
  153. def test_search_by_release(self):
  154. self.login_as(user=self.user)
  155. self.create_release(self.project, version="first-release")
  156. event_1 = self.store_event(
  157. data={
  158. "event_id": "a" * 32,
  159. "fingerprint": ["group-1"],
  160. "timestamp": iso_format(self.min_ago),
  161. "release": "first-release",
  162. },
  163. project_id=self.project.id,
  164. )
  165. url = f"/api/0/issues/{event_1.group.id}/events/?query=release:latest"
  166. response = self.client.get(url, format="json")
  167. assert response.status_code == 200, response.content
  168. assert len(response.data) == 1
  169. assert response.data[0]["eventID"] == event_1.event_id
  170. def test_environment(self):
  171. self.login_as(user=self.user)
  172. events = {}
  173. for name in ["production", "development"]:
  174. events[name] = self.store_event(
  175. data={
  176. "fingerprint": ["put-me-in-group1"],
  177. "timestamp": iso_format(self.min_ago),
  178. "environment": name,
  179. },
  180. project_id=self.project.id,
  181. )
  182. # Asserts that all are in the same group
  183. (group_id,) = {e.group.id for e in events.values()}
  184. url = f"/api/0/issues/{group_id}/events/"
  185. response = self.client.get(url + "?environment=production", format="json")
  186. assert response.status_code == 200, response.content
  187. assert set(map(lambda x: x["eventID"], response.data)) == {
  188. str(events["production"].event_id)
  189. }
  190. response = self.client.get(
  191. url, data={"environment": ["production", "development"]}, format="json"
  192. )
  193. assert response.status_code == 200, response.content
  194. assert set(map(lambda x: x["eventID"], response.data)) == {
  195. str(event.event_id) for event in events.values()
  196. }
  197. response = self.client.get(url + "?environment=invalid", format="json")
  198. assert response.status_code == 200, response.content
  199. assert response.data == []
  200. response = self.client.get(
  201. url + "?environment=production&query=environment:development", format="json"
  202. )
  203. assert response.status_code == 200, response.content
  204. assert response.data == []
  205. def test_filters_based_on_retention(self):
  206. self.login_as(user=self.user)
  207. self.store_event(
  208. data={"fingerprint": ["group_1"], "timestamp": iso_format(before_now(days=2))},
  209. project_id=self.project.id,
  210. )
  211. event_2 = self.store_event(
  212. data={"fingerprint": ["group_1"], "timestamp": iso_format(self.min_ago)},
  213. project_id=self.project.id,
  214. )
  215. group = event_2.group
  216. with self.options({"system.event-retention-days": 1}):
  217. response = self.client.get(f"/api/0/issues/{group.id}/events/")
  218. assert response.status_code == 200, response.content
  219. assert len(response.data) == 1
  220. assert sorted(map(lambda x: x["eventID"], response.data)) == sorted([str(event_2.event_id)])
  221. def test_search_event_has_tags(self):
  222. self.login_as(user=self.user)
  223. event = self.store_event(
  224. data={
  225. "timestamp": iso_format(self.min_ago),
  226. "message": "foo",
  227. "tags": {"logger": "python"},
  228. },
  229. project_id=self.project.id,
  230. )
  231. response = self.client.get(f"/api/0/issues/{event.group.id}/events/")
  232. assert response.status_code == 200, response.content
  233. assert len(response.data) == 1
  234. assert {"key": "logger", "value": "python"} in response.data[0]["tags"]
  235. @freeze_time()
  236. def test_date_filters(self):
  237. self.login_as(user=self.user)
  238. event_1 = self.store_event(
  239. data={"timestamp": iso_format(before_now(days=5)), "fingerprint": ["group-1"]},
  240. project_id=self.project.id,
  241. )
  242. event_2 = self.store_event(
  243. data={"timestamp": iso_format(before_now(days=1)), "fingerprint": ["group-1"]},
  244. project_id=self.project.id,
  245. )
  246. group = event_1.group
  247. assert group == event_2.group
  248. response = self.client.get(f"/api/0/issues/{group.id}/events/", data={"statsPeriod": "6d"})
  249. assert response.status_code == 200, response.content
  250. assert len(response.data) == 2
  251. assert sorted(map(lambda x: x["eventID"], response.data)) == sorted(
  252. [str(event_1.event_id), str(event_2.event_id)]
  253. )
  254. response = self.client.get(f"/api/0/issues/{group.id}/events/", data={"statsPeriod": "2d"})
  255. assert response.status_code == 200, response.content
  256. assert len(response.data) == 1
  257. assert response.data[0]["eventID"] == str(event_2.event_id)
  258. def test_invalid_period(self):
  259. self.login_as(user=self.user)
  260. first_seen = timezone.now() - timedelta(days=5)
  261. group = self.create_group(first_seen=first_seen)
  262. response = self.client.get(f"/api/0/issues/{group.id}/events/", data={"statsPeriod": "lol"})
  263. assert response.status_code == 400
  264. def test_invalid_query(self):
  265. self.login_as(user=self.user)
  266. first_seen = timezone.now() - timedelta(days=5)
  267. group = self.create_group(first_seen=first_seen)
  268. response = self.client.get(
  269. f"/api/0/issues/{group.id}/events/",
  270. data={"statsPeriod": "7d", "query": "foo(bar"},
  271. )
  272. assert response.status_code == 400
  273. def test_multiple_group(self):
  274. self.login_as(user=self.user)
  275. event_1 = self.store_event(
  276. data={
  277. "fingerprint": ["group_1"],
  278. "event_id": "a" * 32,
  279. "message": "foo",
  280. "timestamp": iso_format(self.min_ago),
  281. },
  282. project_id=self.project.id,
  283. )
  284. event_2 = self.store_event(
  285. data={
  286. "fingerprint": ["group_2"],
  287. "event_id": "b" * 32,
  288. "message": "group2",
  289. "timestamp": iso_format(self.min_ago),
  290. },
  291. project_id=self.project.id,
  292. )
  293. for event in (event_1, event_2):
  294. url = f"/api/0/issues/{event.group.id}/events/"
  295. response = self.client.get(url, format="json")
  296. assert response.status_code == 200, response.content
  297. assert len(response.data) == 1, response.data
  298. assert map(lambda x: x["eventID"], response.data) == [str(event.event_id)]