test_group_stream.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. import time
  2. from datetime import timedelta
  3. from unittest import mock
  4. from django.utils import timezone
  5. from sentry.api.serializers import serialize
  6. from sentry.api.serializers.models.group_stream import StreamGroupSerializerSnuba, snuba_tsdb
  7. from sentry.models import Environment
  8. from sentry.testutils import APITestCase, SnubaTestCase
  9. from sentry.testutils.helpers.datetime import iso_format
  10. from sentry.testutils.silo import region_silo_test
  11. from sentry.utils.cache import cache
  12. from sentry.utils.hashlib import hash_values
  13. @region_silo_test
  14. class StreamGroupSerializerTestCase(APITestCase, SnubaTestCase):
  15. def test_environment(self):
  16. group = self.group
  17. environment = Environment.get_or_create(group.project, "production")
  18. with mock.patch(
  19. "sentry.api.serializers.models.group_stream.snuba_tsdb.get_range",
  20. side_effect=snuba_tsdb.get_range,
  21. ) as get_range:
  22. serialize(
  23. [group],
  24. serializer=StreamGroupSerializerSnuba(
  25. environment_ids=[environment.id], stats_period="14d"
  26. ),
  27. )
  28. assert get_range.call_count == 1
  29. for args, kwargs in get_range.call_args_list:
  30. assert kwargs["environment_ids"] == [environment.id]
  31. with mock.patch(
  32. "sentry.api.serializers.models.group.snuba_tsdb.get_range",
  33. side_effect=snuba_tsdb.get_range,
  34. ) as get_range:
  35. serialize(
  36. [group],
  37. serializer=StreamGroupSerializerSnuba(environment_ids=None, stats_period="14d"),
  38. )
  39. assert get_range.call_count == 1
  40. for args, kwargs in get_range.call_args_list:
  41. assert kwargs["environment_ids"] is None
  42. def test_session_count(self):
  43. group = self.group
  44. environment = Environment.get_or_create(group.project, "prod")
  45. dev_environment = Environment.get_or_create(group.project, "dev")
  46. no_sessions_environment = Environment.get_or_create(group.project, "no_sessions")
  47. self.received = time.time()
  48. self.session_started = time.time() // 60 * 60
  49. self.session_release = "foo@1.0.0"
  50. self.session_crashed_release = "foo@2.0.0"
  51. self.store_session(
  52. {
  53. "session_id": "5d52fd05-fcc9-4bf3-9dc9-267783670341",
  54. "distinct_id": "39887d89-13b2-4c84-8c23-5d13d2102667",
  55. "status": "ok",
  56. "seq": 0,
  57. "release": self.session_release,
  58. "environment": "dev",
  59. "retention_days": 90,
  60. "org_id": self.project.organization_id,
  61. "project_id": self.project.id,
  62. "duration": 1,
  63. "errors": 0,
  64. "started": self.session_started - 120,
  65. "received": self.received - 120,
  66. }
  67. )
  68. self.store_session(
  69. {
  70. "session_id": "5e910c1a-6941-460e-9843-24103fb6a63c",
  71. "distinct_id": "39887d89-13b2-4c84-8c23-5d13d2102668",
  72. "status": "ok",
  73. "seq": 0,
  74. "release": self.session_release,
  75. "environment": "prod",
  76. "retention_days": 90,
  77. "org_id": self.project.organization_id,
  78. "project_id": self.project.id,
  79. "duration": 60.0,
  80. "errors": 0,
  81. "started": self.session_started - 240,
  82. "received": self.received - 240,
  83. }
  84. )
  85. self.store_session(
  86. {
  87. "session_id": "5e910c1a-6941-460e-9843-24103fb6a63c",
  88. "distinct_id": "39887d89-13b2-4c84-8c23-5d13d2102669",
  89. "status": "exited",
  90. "seq": 1,
  91. "release": self.session_release,
  92. "environment": "prod",
  93. "retention_days": 90,
  94. "org_id": self.project.organization_id,
  95. "project_id": self.project.id,
  96. "duration": 30.0,
  97. "errors": 0,
  98. "started": self.session_started,
  99. "received": self.received,
  100. }
  101. )
  102. self.store_session(
  103. {
  104. "session_id": "a148c0c5-06a2-423b-8901-6b43b812cf82",
  105. "distinct_id": "39887d89-13b2-4c84-8c23-5d13d2102660",
  106. "status": "crashed",
  107. "seq": 0,
  108. "release": self.session_crashed_release,
  109. "environment": "prod",
  110. "retention_days": 90,
  111. "org_id": self.project.organization_id,
  112. "project_id": self.project.id,
  113. "duration": 60.0,
  114. "errors": 0,
  115. "started": self.session_started,
  116. "received": self.received,
  117. }
  118. )
  119. result = serialize(
  120. [group],
  121. serializer=StreamGroupSerializerSnuba(stats_period="14d"),
  122. )
  123. assert "sessionCount" not in result[0]
  124. result = serialize(
  125. [group],
  126. serializer=StreamGroupSerializerSnuba(
  127. stats_period="14d",
  128. expand=["sessions"],
  129. ),
  130. )
  131. assert result[0]["sessionCount"] == 3
  132. result = serialize(
  133. [group],
  134. serializer=StreamGroupSerializerSnuba(
  135. environment_ids=[environment.id], stats_period="14d", expand=["sessions"]
  136. ),
  137. )
  138. assert result[0]["sessionCount"] == 2
  139. result = serialize(
  140. [group],
  141. serializer=StreamGroupSerializerSnuba(
  142. environment_ids=[no_sessions_environment.id],
  143. stats_period="14d",
  144. expand=["sessions"],
  145. ),
  146. )
  147. assert result[0]["sessionCount"] is None
  148. result = serialize(
  149. [group],
  150. serializer=StreamGroupSerializerSnuba(
  151. environment_ids=[dev_environment.id], stats_period="14d", expand=["sessions"]
  152. ),
  153. )
  154. assert result[0]["sessionCount"] == 1
  155. self.store_session(
  156. {
  157. "session_id": "a148c0c5-06a2-423b-8901-6b43b812cf83",
  158. "distinct_id": "39887d89-13b2-4c84-8c23-5d13d2102627",
  159. "status": "ok",
  160. "seq": 0,
  161. "release": self.session_release,
  162. "environment": "dev",
  163. "retention_days": 90,
  164. "org_id": self.project.organization_id,
  165. "project_id": self.project.id,
  166. "duration": 60.0,
  167. "errors": 0,
  168. "started": self.session_started - 1590061, # approximately 18 days
  169. "received": self.received - 1590061, # approximately 18 days
  170. }
  171. )
  172. result = serialize(
  173. [group],
  174. serializer=StreamGroupSerializerSnuba(
  175. environment_ids=[dev_environment.id],
  176. stats_period="14d",
  177. expand=["sessions"],
  178. start=timezone.now() - timedelta(days=30),
  179. end=timezone.now() - timedelta(days=15),
  180. ),
  181. )
  182. assert result[0]["sessionCount"] == 1
  183. # Delete the cache from the query we did above, else this result comes back as 1 instead of 0.5
  184. key_hash = hash_values([group.project.id, "", "", f"{dev_environment.id}"])
  185. cache.delete(f"w-s:{key_hash}")
  186. project2 = self.create_project(
  187. organization=self.organization, teams=[self.team], name="Another project"
  188. )
  189. data = {
  190. "fingerprint": ["meow"],
  191. "timestamp": iso_format(timezone.now()),
  192. "type": "error",
  193. "exception": [{"type": "Foo"}],
  194. }
  195. event = self.store_event(data=data, project_id=project2.id)
  196. self.store_event(data=data, project_id=project2.id)
  197. self.store_event(data=data, project_id=project2.id)
  198. result = serialize(
  199. [group, event.group],
  200. serializer=StreamGroupSerializerSnuba(
  201. environment_ids=[dev_environment.id],
  202. stats_period="14d",
  203. expand=["sessions"],
  204. ),
  205. )
  206. assert result[0]["sessionCount"] == 2
  207. # No sessions in project2
  208. assert result[1]["sessionCount"] is None