test_snuba.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import copy
  2. import time
  3. import uuid
  4. from datetime import datetime, timedelta
  5. from unittest import mock
  6. import pytest
  7. from django.utils import timezone
  8. from snuba_sdk.column import InvalidColumnError
  9. from sentry.testutils import SnubaTestCase, TestCase
  10. from sentry.testutils.helpers.datetime import before_now, iso_format
  11. from sentry.utils import snuba
  12. class SnubaTest(TestCase, SnubaTestCase):
  13. def _insert_event_for_time(self, ts, hash="a" * 32, group_id=None):
  14. self.snuba_insert(
  15. (
  16. 2,
  17. "insert",
  18. {
  19. "event_id": uuid.uuid4().hex,
  20. "primary_hash": hash,
  21. "group_id": group_id if group_id else int(hash[:16], 16),
  22. "project_id": self.project.id,
  23. "message": "message",
  24. "platform": "python",
  25. "datetime": ts.strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
  26. "data": {"received": time.mktime(ts.timetuple())},
  27. },
  28. )
  29. )
  30. def test(self) -> None:
  31. "This is just a simple 'hello, world' example test."
  32. now = datetime.now()
  33. events = [
  34. (
  35. 2,
  36. "insert",
  37. {
  38. "event_id": "a" * 32,
  39. "primary_hash": "1" * 32,
  40. "group_id": 1,
  41. "project_id": self.project.id,
  42. "message": "message",
  43. "platform": "python",
  44. "datetime": now.strftime("%Y-%m-%dT%H:%M:%S.%fZ"),
  45. "data": {"received": time.mktime(now.timetuple())},
  46. },
  47. )
  48. ]
  49. self.snuba_insert(events)
  50. assert (
  51. snuba.query(
  52. start=now - timedelta(days=1),
  53. end=now + timedelta(days=1),
  54. groupby=["project_id"],
  55. filter_keys={"project_id": [self.project.id]},
  56. referrer="testing.test",
  57. )
  58. == {self.project.id: 1}
  59. )
  60. def test_fail(self) -> None:
  61. now = datetime.now()
  62. with pytest.raises(InvalidColumnError):
  63. snuba.query(
  64. start=now - timedelta(days=1),
  65. end=now + timedelta(days=1),
  66. filter_keys={"project_id": [self.project.id]},
  67. groupby=[")("],
  68. referrer="testing.test",
  69. )
  70. def test_organization_retention_respected(self) -> None:
  71. base_time = datetime.utcnow()
  72. self._insert_event_for_time(base_time - timedelta(minutes=1))
  73. self._insert_event_for_time(base_time - timedelta(days=2))
  74. def _get_event_count():
  75. # attempt to query back 90 days
  76. return snuba.query(
  77. start=base_time - timedelta(days=90),
  78. end=base_time + timedelta(days=1),
  79. groupby=["project_id"],
  80. filter_keys={"project_id": [self.project.id]},
  81. referrer="testing.test",
  82. )
  83. assert _get_event_count() == {self.project.id: 2}
  84. with self.options({"system.event-retention-days": 1}):
  85. assert _get_event_count() == {self.project.id: 1}
  86. def test_organization_retention_larger_than_end_date(self) -> None:
  87. base_time = datetime.utcnow()
  88. with self.options({"system.event-retention-days": 1}):
  89. assert (
  90. snuba.query(
  91. start=base_time - timedelta(days=90),
  92. end=base_time - timedelta(days=60),
  93. groupby=["project_id"],
  94. filter_keys={"project_id": [self.project.id]},
  95. referrer="testing.test",
  96. )
  97. == {}
  98. )
  99. class BulkRawQueryTest(TestCase, SnubaTestCase):
  100. def test_simple(self) -> None:
  101. one_min_ago = iso_format(before_now(minutes=1))
  102. event_1 = self.store_event(
  103. data={"fingerprint": ["group-1"], "message": "hello", "timestamp": one_min_ago},
  104. project_id=self.project.id,
  105. )
  106. event_2 = self.store_event(
  107. data={"fingerprint": ["group-2"], "message": "hello", "timestamp": one_min_ago},
  108. project_id=self.project.id,
  109. )
  110. results = snuba.bulk_raw_query(
  111. [
  112. snuba.SnubaQueryParams(
  113. start=timezone.now() - timedelta(days=1),
  114. end=timezone.now(),
  115. selected_columns=["event_id", "group_id", "timestamp"],
  116. filter_keys={"project_id": [self.project.id], "group_id": [event_1.group.id]},
  117. ),
  118. snuba.SnubaQueryParams(
  119. start=timezone.now() - timedelta(days=1),
  120. end=timezone.now(),
  121. selected_columns=["event_id", "group_id", "timestamp"],
  122. filter_keys={"project_id": [self.project.id], "group_id": [event_2.group.id]},
  123. ),
  124. ],
  125. )
  126. assert [{(item["group_id"], item["event_id"]) for item in r["data"]} for r in results] == [
  127. {(event_1.group.id, event_1.event_id)},
  128. {(event_2.group.id, event_2.event_id)},
  129. ]
  130. @mock.patch("sentry.utils.snuba._bulk_snuba_query", side_effect=snuba._bulk_snuba_query)
  131. def test_cache(self, _bulk_snuba_query):
  132. one_min_ago = iso_format(before_now(minutes=1))
  133. event_1 = self.store_event(
  134. data={"fingerprint": ["group-1"], "message": "hello", "timestamp": one_min_ago},
  135. project_id=self.project.id,
  136. )
  137. event_2 = self.store_event(
  138. data={"fingerprint": ["group-2"], "message": "hello", "timestamp": one_min_ago},
  139. project_id=self.project.id,
  140. )
  141. params = [
  142. snuba.SnubaQueryParams(
  143. start=timezone.now() - timedelta(days=1),
  144. end=timezone.now(),
  145. selected_columns=["event_id", "group_id", "timestamp"],
  146. filter_keys={"project_id": [self.project.id], "group_id": [event_1.group.id]},
  147. ),
  148. snuba.SnubaQueryParams(
  149. start=timezone.now() - timedelta(days=1),
  150. end=timezone.now(),
  151. selected_columns=["event_id", "group_id", "timestamp"],
  152. filter_keys={"project_id": [self.project.id], "group_id": [event_2.group.id]},
  153. ),
  154. ]
  155. results = snuba.bulk_raw_query(
  156. copy.deepcopy(params),
  157. use_cache=True,
  158. )
  159. assert [{(item["group_id"], item["event_id"]) for item in r["data"]} for r in results] == [
  160. {(event_1.group.id, event_1.event_id)},
  161. {(event_2.group.id, event_2.event_id)},
  162. ]
  163. assert _bulk_snuba_query.call_count == 1
  164. _bulk_snuba_query.reset_mock()
  165. # # Make sure this doesn't appear in the cached results
  166. self.store_event(
  167. data={"fingerprint": ["group-2"], "message": "hello there", "timestamp": one_min_ago},
  168. project_id=self.project.id,
  169. )
  170. results = snuba.bulk_raw_query(
  171. copy.deepcopy(params),
  172. use_cache=True,
  173. )
  174. assert [{(item["group_id"], item["event_id"]) for item in r["data"]} for r in results] == [
  175. {(event_1.group.id, event_1.event_id)},
  176. {(event_2.group.id, event_2.event_id)},
  177. ]
  178. assert _bulk_snuba_query.call_count == 0