test_seer.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. from dataclasses import asdict
  2. from unittest.mock import patch
  3. from sentry.conf.server import SEER_SIMILARITY_MODEL_VERSION
  4. from sentry.eventstore.models import Event
  5. from sentry.grouping.ingest.seer import get_seer_similar_issues, should_call_seer_for_grouping
  6. from sentry.grouping.result import CalculatedHashes
  7. from sentry.seer.utils import SeerSimilarIssueData
  8. from sentry.testutils.cases import TestCase
  9. from sentry.testutils.helpers import Feature
  10. from sentry.testutils.helpers.eventprocessing import save_new_event
  11. from sentry.testutils.helpers.features import with_feature
  12. from sentry.utils.types import NonNone
  13. class ShouldCallSeerTest(TestCase):
  14. # TODO: Add tests for rate limits, killswitches, etc once those are in place
  15. def test_obeys_seer_similarity_flags(self):
  16. for metadata_flag, grouping_flag, expected_result in [
  17. (False, False, False),
  18. (True, False, True),
  19. (False, True, True),
  20. (True, True, True),
  21. ]:
  22. with Feature(
  23. {
  24. "projects:similarity-embeddings-metadata": metadata_flag,
  25. "projects:similarity-embeddings-grouping": grouping_flag,
  26. }
  27. ):
  28. assert (
  29. should_call_seer_for_grouping(
  30. Event(
  31. project_id=self.project.id,
  32. event_id="11212012123120120415201309082013",
  33. data={"title": "Dogs are great!"},
  34. ),
  35. self.project,
  36. )
  37. is expected_result
  38. ), f"Case ({metadata_flag}, {grouping_flag}) failed."
  39. @with_feature("projects:similarity-embeddings-grouping")
  40. def test_says_no_for_garbage_event(self):
  41. assert (
  42. should_call_seer_for_grouping(
  43. Event(
  44. project_id=self.project.id,
  45. event_id="11212012123120120415201309082013",
  46. data={"title": "<untitled>"},
  47. ),
  48. self.project,
  49. )
  50. is False
  51. )
  52. class GetSeerSimilarIssuesTest(TestCase):
  53. def setUp(self):
  54. self.existing_event = save_new_event({"message": "Dogs are great!"}, self.project)
  55. self.new_event = Event(
  56. project_id=self.project.id,
  57. event_id="11212012123120120415201309082013",
  58. data={"message": "Adopt don't shop"},
  59. )
  60. self.new_event_hashes = CalculatedHashes(
  61. hashes=["20130809201315042012311220122111"],
  62. hierarchical_hashes=[],
  63. tree_labels=[],
  64. variants={},
  65. )
  66. @with_feature({"projects:similarity-embeddings-grouping": False})
  67. def test_returns_metadata_but_no_group_if_seer_grouping_flag_off(self):
  68. seer_result_data = SeerSimilarIssueData(
  69. parent_hash=self.existing_event.get_primary_hash(),
  70. parent_group_id=NonNone(self.existing_event.group_id),
  71. stacktrace_distance=0.01,
  72. message_distance=0.05,
  73. should_group=True,
  74. )
  75. expected_metadata = {
  76. "similarity_model_version": SEER_SIMILARITY_MODEL_VERSION,
  77. "request_hash": self.new_event_hashes.hashes[0],
  78. "results": [asdict(seer_result_data)],
  79. }
  80. with patch(
  81. "sentry.grouping.ingest.seer.get_similarity_data_from_seer",
  82. return_value=[seer_result_data],
  83. ):
  84. assert get_seer_similar_issues(self.new_event, self.new_event_hashes) == (
  85. expected_metadata,
  86. None, # No group returned, even though `should_group` is True
  87. )
  88. @with_feature("projects:similarity-embeddings-grouping")
  89. def test_returns_metadata_and_group_if_sufficiently_close_group_found(self):
  90. seer_result_data = SeerSimilarIssueData(
  91. parent_hash=self.existing_event.get_primary_hash(),
  92. parent_group_id=NonNone(self.existing_event.group_id),
  93. stacktrace_distance=0.01,
  94. message_distance=0.05,
  95. should_group=True,
  96. )
  97. expected_metadata = {
  98. "similarity_model_version": SEER_SIMILARITY_MODEL_VERSION,
  99. "request_hash": self.new_event_hashes.hashes[0],
  100. "results": [asdict(seer_result_data)],
  101. }
  102. with patch(
  103. "sentry.grouping.ingest.seer.get_similarity_data_from_seer",
  104. return_value=[seer_result_data],
  105. ):
  106. assert get_seer_similar_issues(self.new_event, self.new_event_hashes) == (
  107. expected_metadata,
  108. self.existing_event.group,
  109. )
  110. @with_feature("projects:similarity-embeddings-grouping")
  111. def test_returns_metadata_but_no_group_if_similar_group_insufficiently_close(self):
  112. seer_result_data = SeerSimilarIssueData(
  113. parent_hash=self.existing_event.get_primary_hash(),
  114. parent_group_id=NonNone(self.existing_event.group_id),
  115. stacktrace_distance=0.08,
  116. message_distance=0.12,
  117. should_group=False,
  118. )
  119. expected_metadata = {
  120. "similarity_model_version": SEER_SIMILARITY_MODEL_VERSION,
  121. "request_hash": self.new_event_hashes.hashes[0],
  122. "results": [asdict(seer_result_data)],
  123. }
  124. with patch(
  125. "sentry.grouping.ingest.seer.get_similarity_data_from_seer",
  126. return_value=[seer_result_data],
  127. ):
  128. assert get_seer_similar_issues(self.new_event, self.new_event_hashes) == (
  129. expected_metadata,
  130. None,
  131. )
  132. @with_feature("projects:similarity-embeddings-grouping")
  133. def test_returns_no_group_and_empty_metadata_if_no_similar_group_found(self):
  134. expected_metadata = {
  135. "similarity_model_version": SEER_SIMILARITY_MODEL_VERSION,
  136. "request_hash": self.new_event_hashes.hashes[0],
  137. "results": [],
  138. }
  139. with patch(
  140. "sentry.grouping.ingest.seer.get_similarity_data_from_seer",
  141. return_value=[],
  142. ):
  143. assert get_seer_similar_issues(self.new_event, self.new_event_hashes) == (
  144. expected_metadata,
  145. None,
  146. )