test_group_events.py 14 KB

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