test_group.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. from __future__ import annotations
  2. import uuid
  3. from collections.abc import Sequence
  4. from datetime import datetime
  5. from unittest.mock import patch
  6. from snuba_sdk import Column, Condition, Op
  7. from sentry.eventstore.models import GroupEvent
  8. from sentry.issues.grouptype import PerformanceNPlusOneGroupType, ProfileFileIOGroupType
  9. from sentry.models.group import Group
  10. from sentry.testutils.cases import PerformanceIssueTestCase, SnubaTestCase, TestCase
  11. from sentry.testutils.helpers.datetime import before_now, freeze_time
  12. from sentry.utils.samples import load_data
  13. from tests.sentry.issues.test_utils import OccurrenceTestMixin
  14. def _get_recommended_non_null(g: Group) -> GroupEvent:
  15. ret = g.get_recommended_event_for_environments()
  16. assert ret is not None
  17. return ret
  18. def _get_latest_non_null(g: Group, environments: Sequence[str] = ()) -> GroupEvent:
  19. ret = g.get_latest_event_for_environments(environments)
  20. assert ret is not None
  21. return ret
  22. def _get_oldest_non_null(g: Group, environments: Sequence[str] = ()) -> GroupEvent:
  23. ret = g.get_oldest_event_for_environments(environments)
  24. assert ret is not None
  25. return ret
  26. class GroupTestSnuba(TestCase, SnubaTestCase, PerformanceIssueTestCase, OccurrenceTestMixin):
  27. def test_get_oldest_latest_for_environments(self):
  28. project = self.create_project()
  29. self.store_event(
  30. data={
  31. "event_id": "a" * 32,
  32. "environment": "production",
  33. "timestamp": before_now(minutes=3).isoformat(),
  34. "fingerprint": ["group-1"],
  35. },
  36. project_id=project.id,
  37. )
  38. self.store_event(
  39. data={
  40. "event_id": "b" * 32,
  41. "environment": "production",
  42. "timestamp": before_now(minutes=2).isoformat(),
  43. "fingerprint": ["group-1"],
  44. },
  45. project_id=project.id,
  46. )
  47. self.store_event(
  48. data={
  49. "event_id": "c" * 32,
  50. "timestamp": before_now(minutes=1).isoformat(),
  51. "fingerprint": ["group-1"],
  52. },
  53. project_id=project.id,
  54. )
  55. group = Group.objects.get()
  56. assert _get_latest_non_null(group).event_id == "c" * 32
  57. assert group.get_latest_event_for_environments(["staging"]) is None
  58. assert _get_latest_non_null(group, ["production"]).event_id == "b" * 32
  59. assert _get_oldest_non_null(group).event_id == "a" * 32
  60. assert _get_oldest_non_null(group, ["staging", "production"]).event_id == "a" * 32
  61. assert group.get_oldest_event_for_environments(["staging"]) is None
  62. def test_error_issue_get_helpful_for_environments(self):
  63. project = self.create_project()
  64. replay_id = uuid.uuid4().hex
  65. event_all_helpful_params = self.store_event(
  66. data={
  67. "event_id": "a" * 32,
  68. "timestamp": before_now(minutes=3).isoformat(),
  69. "fingerprint": ["group-1"],
  70. "contexts": {
  71. "replay": {"replay_id": replay_id},
  72. "trace": {
  73. "sampled": True,
  74. "span_id": "babaae0d4b7512d9",
  75. "trace_id": "a7d67cf796774551a95be6543cacd459",
  76. },
  77. },
  78. "errors": [],
  79. },
  80. project_id=project.id,
  81. assert_no_errors=False,
  82. )
  83. self.store_event(
  84. data={
  85. "event_id": "b" * 32,
  86. "timestamp": before_now(minutes=2).isoformat(),
  87. "fingerprint": ["group-1"],
  88. "contexts": {
  89. "replay": {"replay_id": replay_id},
  90. },
  91. "errors": [{"type": "one"}, {"type": "two"}],
  92. },
  93. project_id=project.id,
  94. assert_no_errors=False,
  95. )
  96. event_none_helpful_params = self.store_event(
  97. data={
  98. "event_id": "c" * 32,
  99. "timestamp": before_now(minutes=1).isoformat(),
  100. "fingerprint": ["group-1"],
  101. },
  102. project_id=project.id,
  103. )
  104. group = Group.objects.get()
  105. assert _get_recommended_non_null(group).event_id == event_all_helpful_params.event_id
  106. assert _get_latest_non_null(group).event_id == event_none_helpful_params.event_id
  107. assert _get_oldest_non_null(group).event_id == event_all_helpful_params.event_id
  108. @patch("sentry.quotas.backend.get_event_retention")
  109. def test_get_recommended_event_for_environments_retention_limit(self, mock_get_event_retention):
  110. """
  111. If last_seen is outside of the retention limit, falls back to the latest event behavior.
  112. """
  113. mock_get_event_retention.return_value = 90
  114. project = self.create_project()
  115. outside_retention_date = before_now(days=91)
  116. event = self.store_event(
  117. data={
  118. "event_id": "a" * 32,
  119. "timestamp": outside_retention_date.isoformat(),
  120. "fingerprint": ["group-1"],
  121. "contexts": {},
  122. "errors": [],
  123. },
  124. project_id=project.id,
  125. assert_no_errors=False,
  126. )
  127. group = Group.objects.get()
  128. group.last_seen = before_now(days=91)
  129. assert _get_recommended_non_null(group).event_id == event.event_id
  130. def _get_recommended(
  131. g: Group,
  132. conditions: Sequence[Condition] | None = None,
  133. start: datetime | None = None,
  134. end: datetime | None = None,
  135. ) -> GroupEvent:
  136. ret = g.get_recommended_event(conditions=conditions, start=start, end=end)
  137. assert ret is not None
  138. return ret
  139. def _get_latest(
  140. g: Group,
  141. conditions: Sequence[Condition] | None = None,
  142. start: datetime | None = None,
  143. end: datetime | None = None,
  144. ) -> GroupEvent:
  145. ret = g.get_latest_event(conditions=conditions, start=start, end=end)
  146. assert ret is not None
  147. return ret
  148. def _get_oldest(
  149. g: Group,
  150. conditions: Sequence[Condition] | None = None,
  151. start: datetime | None = None,
  152. end: datetime | None = None,
  153. ) -> GroupEvent:
  154. ret = g.get_oldest_event(conditions=conditions, start=start, end=end)
  155. assert ret is not None
  156. return ret
  157. @freeze_time()
  158. class GroupTestSnubaErrorIssue(TestCase, SnubaTestCase):
  159. def setUp(self):
  160. super().setUp()
  161. self.project = self.create_project()
  162. self.event_a = self.store_event(
  163. data={
  164. "event_id": "a" * 32,
  165. "timestamp": before_now(minutes=1).isoformat(),
  166. "environment": "staging",
  167. "fingerprint": ["group-1"],
  168. "message": "Error: Division by zero",
  169. },
  170. project_id=self.project.id,
  171. )
  172. self.event_b = self.store_event(
  173. data={
  174. "event_id": "b" * 32,
  175. "timestamp": before_now(minutes=2).isoformat(),
  176. "fingerprint": ["group-1"],
  177. "environment": "production",
  178. "contexts": {
  179. "replay": {"replay_id": uuid.uuid4().hex},
  180. "trace": {
  181. "sampled": True,
  182. "span_id": "babaae0d4b7512d9",
  183. "trace_id": "a7d67cf796774551a95be6543cacd459",
  184. },
  185. },
  186. "message": "Error: Division by zero",
  187. },
  188. project_id=self.project.id,
  189. )
  190. self.event_c = self.store_event(
  191. data={
  192. "event_id": "c" * 32,
  193. "timestamp": before_now(minutes=3).isoformat(),
  194. "fingerprint": ["group-1"],
  195. "tags": {"organization.slug": "sentry"},
  196. "environment": "staging",
  197. "contexts": {
  198. "trace": {
  199. "sampled": True,
  200. "span_id": "babaae0d4b7512d9",
  201. "trace_id": "a7d67cf796774551a95be6543cacd459",
  202. },
  203. },
  204. "message": "Error: Division by zero",
  205. },
  206. project_id=self.project.id,
  207. )
  208. self.group: Group = Group.objects.get()
  209. assert isinstance(self.group, Group)
  210. def test_recommended_event(self):
  211. # No filter
  212. assert _get_recommended(self.group).event_id == self.event_b.event_id
  213. # Filter by environment
  214. conditions = [Condition(Column("environment"), Op.IN, ["staging"])]
  215. assert _get_recommended(self.group, conditions=conditions).event_id == self.event_c.event_id
  216. conditions = [Condition(Column("environment"), Op.IN, ["production"])]
  217. assert _get_recommended(self.group, conditions=conditions).event_id == self.event_b.event_id
  218. conditions = [Condition(Column("environment"), Op.IN, ["development"])]
  219. assert self.group.get_recommended_event(conditions=conditions) is None
  220. # Filter by query
  221. conditions = [Condition(Column("tags[organization.slug]"), Op.EQ, "sentry")]
  222. assert _get_recommended(self.group, conditions=conditions).event_id == self.event_c.event_id
  223. conditions = [Condition(Column("trace_id"), Op.IS_NULL)]
  224. assert _get_recommended(self.group, conditions=conditions).event_id == self.event_a.event_id
  225. # Filter by date range
  226. assert (
  227. _get_recommended(
  228. self.group, start=before_now(seconds=120), end=before_now(seconds=30)
  229. ).event_id
  230. == self.event_b.event_id
  231. )
  232. assert (
  233. _get_recommended(
  234. self.group, start=before_now(hours=1), end=before_now(seconds=90)
  235. ).event_id
  236. == self.event_b.event_id
  237. )
  238. def test_latest_event(self):
  239. # No filter
  240. assert _get_latest(self.group).event_id == self.event_a.event_id
  241. # Filter by environment
  242. conditions = [Condition(Column("environment"), Op.IN, ["staging"])]
  243. assert _get_latest(self.group, conditions=conditions).event_id == self.event_a.event_id
  244. conditions = [Condition(Column("environment"), Op.IN, ["production"])]
  245. assert _get_latest(self.group, conditions=conditions).event_id == self.event_b.event_id
  246. conditions = [Condition(Column("environment"), Op.IN, ["development"])]
  247. assert self.group.get_latest_event(conditions=conditions) is None
  248. # Filter by query
  249. conditions = [Condition(Column("tags[organization.slug]"), Op.EQ, "sentry")]
  250. assert _get_latest(self.group, conditions=conditions).event_id == self.event_c.event_id
  251. conditions = [Condition(Column("trace_id"), Op.IS_NULL)]
  252. assert _get_latest(self.group, conditions=conditions).event_id == self.event_a.event_id
  253. # Filter by date range
  254. assert (
  255. _get_latest(
  256. self.group, start=before_now(seconds=120), end=before_now(seconds=30)
  257. ).event_id
  258. == self.event_a.event_id
  259. )
  260. assert (
  261. _get_latest(self.group, start=before_now(hours=1), end=before_now(seconds=90)).event_id
  262. == self.event_b.event_id
  263. )
  264. def test_oldest_event(self):
  265. # No filter
  266. assert _get_oldest(self.group).event_id == self.event_c.event_id
  267. # Filter by environment
  268. conditions = [Condition(Column("environment"), Op.IN, ["staging"])]
  269. assert _get_oldest(self.group, conditions=conditions).event_id == self.event_c.event_id
  270. conditions = [Condition(Column("environment"), Op.IN, ["production"])]
  271. assert _get_oldest(self.group, conditions=conditions).event_id == self.event_b.event_id
  272. conditions = [Condition(Column("environment"), Op.IN, ["development"])]
  273. assert self.group.get_oldest_event(conditions=conditions) is None
  274. # Filter by query
  275. conditions = [Condition(Column("tags[organization.slug]"), Op.EQ, "sentry")]
  276. assert _get_oldest(self.group, conditions=conditions).event_id == self.event_c.event_id
  277. conditions = [Condition(Column("trace_id"), Op.IS_NULL)]
  278. assert _get_oldest(self.group, conditions=conditions).event_id == self.event_a.event_id
  279. # Filter by date range
  280. assert (
  281. _get_oldest(
  282. self.group, start=before_now(seconds=150), end=before_now(seconds=30)
  283. ).event_id
  284. == self.event_b.event_id
  285. )
  286. assert (
  287. _get_oldest(self.group, start=before_now(hours=1), end=before_now(seconds=90)).event_id
  288. == self.event_c.event_id
  289. )
  290. @freeze_time()
  291. class GroupTestSnubaPerformanceIssue(TestCase, SnubaTestCase, PerformanceIssueTestCase):
  292. def setUp(self):
  293. super().setUp()
  294. self.project = self.create_project()
  295. group_fingerprint = f"{PerformanceNPlusOneGroupType.type_id}-group1"
  296. event_data_a = load_data(
  297. "transaction-n-plus-one",
  298. fingerprint=[group_fingerprint],
  299. timestamp=before_now(minutes=1),
  300. start_timestamp=before_now(minutes=1, seconds=1),
  301. event_id="a" * 32,
  302. )
  303. event_data_a["environment"] = "staging"
  304. event_data_b = load_data(
  305. "transaction-n-plus-one",
  306. fingerprint=[group_fingerprint],
  307. timestamp=before_now(minutes=2),
  308. start_timestamp=before_now(minutes=2, seconds=1),
  309. event_id="b" * 32,
  310. )
  311. event_data_b["environment"] = "production"
  312. event_data_b["contexts"].update(
  313. {
  314. "replay": {"replay_id": uuid.uuid4().hex},
  315. "profile": {"profile_id": uuid.uuid4().hex},
  316. }
  317. )
  318. event_data_c = load_data(
  319. "transaction-n-plus-one",
  320. fingerprint=[group_fingerprint],
  321. timestamp=before_now(minutes=3),
  322. start_timestamp=before_now(minutes=3, seconds=1),
  323. event_id="c" * 32,
  324. )
  325. event_data_c["environment"] = "staging"
  326. event_data_c["contexts"].update({"profile": {"profile_id": uuid.uuid4().hex}})
  327. event_data_c["tags"] = {"organization.slug": "sentry"}
  328. self.event_a = self.create_performance_issue(
  329. event_data=event_data_a, fingerprint=group_fingerprint
  330. )
  331. self.event_b = self.create_performance_issue(
  332. event_data=event_data_b, fingerprint=group_fingerprint
  333. )
  334. self.event_c = self.create_performance_issue(
  335. event_data=event_data_c, fingerprint=group_fingerprint
  336. )
  337. self.group: Group = Group.objects.get()
  338. assert isinstance(self.group, Group)
  339. def test_recommended_event(self):
  340. # No filter
  341. assert _get_recommended(self.group).event_id == self.event_b.event_id
  342. # Filter by environment
  343. conditions = [Condition(Column("environment"), Op.IN, ["staging"])]
  344. assert _get_recommended(self.group, conditions=conditions).event_id == self.event_c.event_id
  345. conditions = [Condition(Column("environment"), Op.IN, ["production"])]
  346. assert _get_recommended(self.group, conditions=conditions).event_id == self.event_b.event_id
  347. conditions = [Condition(Column("environment"), Op.IN, ["development"])]
  348. assert self.group.get_recommended_event(conditions=conditions) is None
  349. # Filter by query
  350. conditions = [Condition(Column("tags[organization.slug]"), Op.EQ, "sentry")]
  351. assert _get_recommended(self.group, conditions=conditions).event_id == self.event_c.event_id
  352. conditions = [Condition(Column("profile_id"), Op.IS_NULL)]
  353. assert _get_recommended(self.group, conditions=conditions).event_id == self.event_a.event_id
  354. # Filter by date range
  355. assert (
  356. _get_recommended(
  357. self.group, start=before_now(seconds=120), end=before_now(seconds=30)
  358. ).event_id
  359. == self.event_b.event_id
  360. )
  361. assert (
  362. _get_recommended(
  363. self.group, start=before_now(hours=1), end=before_now(seconds=90)
  364. ).event_id
  365. == self.event_b.event_id
  366. )
  367. def test_latest_event(self):
  368. # No filter
  369. assert _get_latest(self.group).event_id == self.event_a.event_id
  370. # Filter by environment
  371. conditions = [Condition(Column("environment"), Op.IN, ["staging"])]
  372. assert _get_latest(self.group, conditions=conditions).event_id == self.event_a.event_id
  373. conditions = [Condition(Column("environment"), Op.IN, ["production"])]
  374. assert _get_latest(self.group, conditions=conditions).event_id == self.event_b.event_id
  375. conditions = [Condition(Column("environment"), Op.IN, ["development"])]
  376. assert self.group.get_latest_event(conditions=conditions) is None
  377. # Filter by query
  378. conditions = [Condition(Column("tags[organization.slug]"), Op.EQ, "sentry")]
  379. assert _get_latest(self.group, conditions=conditions).event_id == self.event_c.event_id
  380. conditions = [Condition(Column("profile_id"), Op.IS_NULL)]
  381. assert _get_latest(self.group, conditions=conditions).event_id == self.event_a.event_id
  382. # Filter by date range
  383. assert (
  384. _get_latest(
  385. self.group, start=before_now(seconds=120), end=before_now(seconds=30)
  386. ).event_id
  387. == self.event_a.event_id
  388. )
  389. assert (
  390. _get_latest(self.group, start=before_now(hours=1), end=before_now(seconds=90)).event_id
  391. == self.event_b.event_id
  392. )
  393. def test_oldest_event(self):
  394. # No filter
  395. assert _get_oldest(self.group).event_id == self.event_c.event_id
  396. # Filter by environment
  397. conditions = [Condition(Column("environment"), Op.IN, ["staging"])]
  398. assert _get_oldest(self.group, conditions=conditions).event_id == self.event_c.event_id
  399. conditions = [Condition(Column("environment"), Op.IN, ["production"])]
  400. assert _get_oldest(self.group, conditions=conditions).event_id == self.event_b.event_id
  401. conditions = [Condition(Column("environment"), Op.IN, ["development"])]
  402. assert self.group.get_oldest_event(conditions=conditions) is None
  403. # Filter by query
  404. conditions = [Condition(Column("tags[organization.slug]"), Op.EQ, "sentry")]
  405. assert _get_oldest(self.group, conditions=conditions).event_id == self.event_c.event_id
  406. conditions = [Condition(Column("profile_id"), Op.IS_NULL)]
  407. assert _get_oldest(self.group, conditions=conditions).event_id == self.event_a.event_id
  408. # Filter by date range
  409. assert (
  410. _get_oldest(
  411. self.group, start=before_now(seconds=150), end=before_now(seconds=30)
  412. ).event_id
  413. == self.event_b.event_id
  414. )
  415. assert (
  416. _get_oldest(self.group, start=before_now(hours=1), end=before_now(seconds=90)).event_id
  417. == self.event_c.event_id
  418. )
  419. @freeze_time()
  420. class GroupTestSnubaOccurrenceIssue(TestCase, SnubaTestCase, OccurrenceTestMixin):
  421. def setUp(self):
  422. super().setUp()
  423. self.project = self.create_project()
  424. self.issue_occ_a, _ = self.process_occurrence(
  425. project_id=self.project.id,
  426. event_id="a" * 32,
  427. event_data={
  428. "timestamp": before_now(minutes=1).isoformat(),
  429. "fingerprint": ["group-1"],
  430. "environment": "staging",
  431. "contexts": {
  432. "profile": {"profile_id": uuid.uuid4().hex},
  433. },
  434. },
  435. )
  436. self.issue_occ_b, _ = self.process_occurrence(
  437. project_id=self.project.id,
  438. event_id="b" * 32,
  439. event_data={
  440. "timestamp": before_now(minutes=2).isoformat(),
  441. "fingerprint": ["group-1"],
  442. "environment": "production",
  443. "contexts": {
  444. "profile": {"profile_id": uuid.uuid4().hex},
  445. "replay": {"replay_id": uuid.uuid4().hex},
  446. "trace": {
  447. "sampled": True,
  448. "span_id": "babaae0d4b7512d9",
  449. "trace_id": "a7d67cf796774551a95be6543cacd459",
  450. },
  451. },
  452. },
  453. )
  454. self.issue_occ_c, _ = self.process_occurrence(
  455. project_id=self.project.id,
  456. event_id="c" * 32,
  457. event_data={
  458. "timestamp": before_now(minutes=3).isoformat(),
  459. "fingerprint": ["group-1"],
  460. "environment": "staging",
  461. "tags": {"organization.slug": "sentry"},
  462. "contexts": {
  463. "profile": {"profile_id": uuid.uuid4().hex},
  464. "replay": {"replay_id": uuid.uuid4().hex},
  465. },
  466. },
  467. )
  468. self.group: Group = Group.objects.get()
  469. self.group.update(type=ProfileFileIOGroupType.type_id)
  470. assert isinstance(self.group, Group)
  471. assert self.group.type == ProfileFileIOGroupType.type_id
  472. def test_recommended_event(self):
  473. # No filter
  474. self.assert_occurrences_identical(_get_recommended(self.group).occurrence, self.issue_occ_b)
  475. # Filter by environment
  476. conditions = [Condition(Column("environment"), Op.IN, ["staging"])]
  477. assert (
  478. _get_recommended(self.group, conditions=conditions).event_id
  479. == self.issue_occ_c.event_id
  480. )
  481. conditions = [Condition(Column("environment"), Op.IN, ["production"])]
  482. assert (
  483. _get_recommended(self.group, conditions=conditions).event_id
  484. == self.issue_occ_b.event_id
  485. )
  486. conditions = [Condition(Column("environment"), Op.IN, ["development"])]
  487. assert self.group.get_recommended_event(conditions=conditions) is None
  488. # Filter by query
  489. conditions = [Condition(Column("tags[organization.slug]"), Op.EQ, "sentry")]
  490. assert (
  491. _get_recommended(self.group, conditions=conditions).event_id
  492. == self.issue_occ_c.event_id
  493. )
  494. conditions = [Condition(Column("replay_id"), Op.IS_NULL)]
  495. assert (
  496. _get_recommended(self.group, conditions=conditions).event_id
  497. == self.issue_occ_a.event_id
  498. )
  499. # Filter by date range
  500. assert (
  501. _get_recommended(
  502. self.group, start=before_now(seconds=150), end=before_now(seconds=30)
  503. ).event_id
  504. == self.issue_occ_b.event_id
  505. )
  506. assert (
  507. _get_recommended(
  508. self.group, start=before_now(hours=1), end=before_now(seconds=90)
  509. ).event_id
  510. == self.issue_occ_b.event_id
  511. )
  512. def test_latest_event(self):
  513. # No filter
  514. self.assert_occurrences_identical(_get_latest(self.group).occurrence, self.issue_occ_a)
  515. # Filter by environment
  516. conditions = [Condition(Column("environment"), Op.IN, ["staging"])]
  517. assert _get_latest(self.group, conditions=conditions).event_id == self.issue_occ_a.event_id
  518. conditions = [Condition(Column("environment"), Op.IN, ["production"])]
  519. assert _get_latest(self.group, conditions=conditions).event_id == self.issue_occ_b.event_id
  520. conditions = [Condition(Column("environment"), Op.IN, ["development"])]
  521. assert self.group.get_latest_event(conditions=conditions) is None
  522. # Filter by query
  523. conditions = [Condition(Column("tags[organization.slug]"), Op.EQ, "sentry")]
  524. assert _get_latest(self.group, conditions=conditions).event_id == self.issue_occ_c.event_id
  525. conditions = [Condition(Column("replay_id"), Op.IS_NULL)]
  526. assert _get_latest(self.group, conditions=conditions).event_id == self.issue_occ_a.event_id
  527. # Filter by date range
  528. assert (
  529. _get_latest(
  530. self.group, start=before_now(seconds=120), end=before_now(seconds=30)
  531. ).event_id
  532. == self.issue_occ_a.event_id
  533. )
  534. assert (
  535. _get_latest(self.group, start=before_now(hours=1), end=before_now(seconds=90)).event_id
  536. == self.issue_occ_b.event_id
  537. )
  538. def test_oldest_event(self):
  539. # No filter
  540. self.assert_occurrences_identical(_get_oldest(self.group).occurrence, self.issue_occ_c)
  541. # Filter by environment
  542. conditions = [Condition(Column("environment"), Op.IN, ["staging"])]
  543. assert _get_oldest(self.group, conditions=conditions).event_id == self.issue_occ_c.event_id
  544. conditions = [Condition(Column("environment"), Op.IN, ["production"])]
  545. assert _get_oldest(self.group, conditions=conditions).event_id == self.issue_occ_b.event_id
  546. conditions = [Condition(Column("environment"), Op.IN, ["development"])]
  547. assert self.group.get_oldest_event(conditions=conditions) is None
  548. # Filter by query
  549. conditions = [Condition(Column("tags[organization.slug]"), Op.EQ, "sentry")]
  550. assert _get_oldest(self.group, conditions=conditions).event_id == self.issue_occ_c.event_id
  551. conditions = [Condition(Column("replay_id"), Op.IS_NULL)]
  552. assert _get_oldest(self.group, conditions=conditions).event_id == self.issue_occ_a.event_id
  553. # Filter by date range
  554. assert (
  555. _get_oldest(
  556. self.group, start=before_now(seconds=150), end=before_now(seconds=30)
  557. ).event_id
  558. == self.issue_occ_b.event_id
  559. )
  560. assert (
  561. _get_oldest(self.group, start=before_now(hours=1), end=before_now(seconds=90)).event_id
  562. == self.issue_occ_c.event_id
  563. )