test_utils.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. import pytest
  2. import responses
  3. from sentry.integrations.slack.utils import get_channel_id
  4. from sentry.integrations.slack.utils.channel import CHANNEL_PREFIX, MEMBER_PREFIX
  5. from sentry.models import Integration
  6. from sentry.shared_integrations.exceptions import ApiRateLimitedError, DuplicateDisplayNameError
  7. from sentry.testutils import TestCase
  8. from sentry.testutils.helpers import install_slack, with_feature
  9. from sentry.utils import json
  10. class GetChannelIdTest(TestCase):
  11. def add_list_response(self, list_type, channels, result_name="channels"):
  12. self.resp = responses.mock
  13. self.resp.add(
  14. method=responses.GET,
  15. url="https://slack.com/api/%s.list" % list_type,
  16. status=200,
  17. content_type="application/json",
  18. body=json.dumps({"ok": "true", result_name: channels}),
  19. )
  20. class GetChannelIdBotTest(GetChannelIdTest):
  21. def setUp(self):
  22. self.resp = responses.mock
  23. self.resp.__enter__()
  24. self.integration = install_slack(self.event.project.organization)
  25. self.add_list_response(
  26. "conversations",
  27. [
  28. {"name": "my-channel", "id": "m-c"},
  29. {"name": "other-chann", "id": "o-c"},
  30. {"name": "my-private-channel", "id": "m-p-c", "is_private": True},
  31. ],
  32. result_name="channels",
  33. )
  34. self.add_list_response(
  35. "users",
  36. [
  37. {"name": "first-morty", "id": "m", "profile": {"display_name": "Morty"}},
  38. {"name": "other-user", "id": "o-u", "profile": {"display_name": "Jimbob"}},
  39. {"name": "better_morty", "id": "bm", "profile": {"display_name": "Morty"}},
  40. ],
  41. result_name="members",
  42. )
  43. def tearDown(self):
  44. self.resp.__exit__(None, None, None)
  45. def run_valid_test(self, channel, expected_prefix, expected_id, timed_out):
  46. assert (expected_prefix, expected_id, timed_out) == get_channel_id(
  47. self.organization, self.integration, channel
  48. )
  49. def test_valid_channel_selected(self):
  50. self.run_valid_test("#My-Channel", CHANNEL_PREFIX, "m-c", False)
  51. def test_valid_private_channel_selected(self):
  52. self.run_valid_test("#my-private-channel", CHANNEL_PREFIX, "m-p-c", False)
  53. def test_valid_member_selected(self):
  54. self.run_valid_test("@first-morty", MEMBER_PREFIX, "m", False)
  55. def test_valid_member_selected_display_name(self):
  56. self.run_valid_test("@Jimbob", MEMBER_PREFIX, "o-u", False)
  57. def test_invalid_member_selected_display_name(self):
  58. with pytest.raises(DuplicateDisplayNameError):
  59. get_channel_id(self.organization, self.integration, "@Morty")
  60. def test_invalid_channel_selected(self):
  61. assert get_channel_id(self.organization, self.integration, "#fake-channel")[1] is None
  62. assert get_channel_id(self.organization, self.integration, "@fake-user")[1] is None
  63. class GetChannelIdErrorBotTest(GetChannelIdTest):
  64. def setUp(self):
  65. self.resp = responses.mock
  66. self.resp.__enter__()
  67. self.integration = Integration.objects.create(
  68. provider="slack",
  69. name="Awesome Team",
  70. external_id="TXXXXXXX1",
  71. metadata={
  72. "access_token": "xoxb-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx",
  73. "installation_type": "born_as_bot",
  74. },
  75. )
  76. self.integration.add_organization(self.event.project.organization, self.user)
  77. def tearDown(self):
  78. self.resp.__exit__(None, None, None)
  79. def test_rate_limiting(self):
  80. """Should handle 429 from Slack when searching for channels"""
  81. self.resp.add(
  82. method=responses.GET,
  83. url="https://slack.com/api/conversations.list",
  84. status=429,
  85. content_type="application/json",
  86. body=json.dumps({"ok": "false", "error": "ratelimited"}),
  87. )
  88. with pytest.raises(ApiRateLimitedError):
  89. get_channel_id(self.organization, self.integration, "@user")
  90. class GetChannelIdFasterTest(GetChannelIdTest):
  91. def setUp(self):
  92. self.resp = responses.mock
  93. self.resp.__enter__()
  94. self.integration = install_slack(self.event.project.organization)
  95. def tearDown(self):
  96. self.resp.__exit__(None, None, None)
  97. def add_msg_response(self, channel_id, result_name="channel"):
  98. if channel_id == "channel_not_found":
  99. bodydict = {"ok": False, "error": "channel_not_found"}
  100. else:
  101. bodydict = {"ok": True, result_name: channel_id, "scheduled_message_id": "Q1298393284"}
  102. self.resp.add(
  103. method=responses.POST,
  104. url="https://slack.com/api/chat.scheduleMessage",
  105. status=200,
  106. content_type="application/json",
  107. body=json.dumps(bodydict),
  108. )
  109. @with_feature("organizations:slack-use-new-lookup")
  110. def run_valid_test(self, channel, expected_prefix, expected_id, timed_out):
  111. assert (expected_prefix, expected_id, timed_out) == get_channel_id(
  112. self.organization, self.integration, channel
  113. )
  114. def test_valid_channel_selected_new(self):
  115. self.add_msg_response("m-c")
  116. self.resp.add(
  117. method=responses.POST,
  118. url="https://slack.com/api/chat.deleteScheduledMessage",
  119. status=200,
  120. content_type="application/json",
  121. body=json.dumps({"ok": True}),
  122. )
  123. self.run_valid_test("#My-Channel", CHANNEL_PREFIX, "m-c", False)
  124. def test_valid_private_channel_selected_new(self):
  125. self.add_msg_response("m-p-c")
  126. self.resp.add(
  127. method=responses.POST,
  128. url="https://slack.com/api/chat.deleteScheduledMessage",
  129. status=200,
  130. content_type="application/json",
  131. body=json.dumps({"ok": True}),
  132. )
  133. self.run_valid_test("#my-private-channel", CHANNEL_PREFIX, "m-p-c", False)
  134. def test_valid_member_selected(self):
  135. self.add_msg_response("channel_not_found")
  136. self.add_list_response(
  137. "users",
  138. [
  139. {"name": "first-morty", "id": "m", "profile": {"display_name": "Morty"}},
  140. {"name": "other-user", "id": "o-u", "profile": {"display_name": "Jimbob"}},
  141. {"name": "better_morty", "id": "bm", "profile": {"display_name": "Morty"}},
  142. ],
  143. result_name="members",
  144. )
  145. self.run_valid_test("@first-morty", MEMBER_PREFIX, "m", False)
  146. def test_valid_member_selected_display_name(self):
  147. self.add_msg_response("channel_not_found")
  148. self.add_list_response(
  149. "users",
  150. [
  151. {"name": "first-morty", "id": "m", "profile": {"display_name": "Morty"}},
  152. {"name": "other-user", "id": "o-u", "profile": {"display_name": "Jimbob"}},
  153. {"name": "better_morty", "id": "bm", "profile": {"display_name": "Morty"}},
  154. ],
  155. result_name="members",
  156. )
  157. self.run_valid_test("@Jimbob", MEMBER_PREFIX, "o-u", False)
  158. @with_feature("organizations:slack-use-new-lookup")
  159. def test_invalid_member_selected_display_name(self):
  160. self.add_msg_response("channel_not_found")
  161. self.add_list_response(
  162. "users",
  163. [
  164. {"name": "first-morty", "id": "m", "profile": {"display_name": "Morty"}},
  165. {"name": "other-user", "id": "o-u", "profile": {"display_name": "Jimbob"}},
  166. {"name": "better_morty", "id": "bm", "profile": {"display_name": "Morty"}},
  167. ],
  168. result_name="members",
  169. )
  170. with pytest.raises(DuplicateDisplayNameError):
  171. get_channel_id(self.organization, self.integration, "@Morty")
  172. @with_feature("organizations:slack-use-new-lookup")
  173. def test_invalid_channel_selected(self):
  174. self.add_msg_response("channel_not_found")
  175. assert get_channel_id(self.organization, self.integration, "#fake-channel")[1] is None
  176. assert get_channel_id(self.organization, self.integration, "@fake-user")[1] is None
  177. @with_feature("organizations:slack-use-new-lookup")
  178. def test_rate_limiting(self):
  179. """Should handle 429 from Slack when searching for channels"""
  180. self.add_msg_response("channel_not_found")
  181. self.resp.add(
  182. method=responses.GET,
  183. url="https://slack.com/api/users.list",
  184. status=429,
  185. content_type="application/json",
  186. body=json.dumps({"ok": False, "error": "ratelimited"}),
  187. )
  188. with pytest.raises(ApiRateLimitedError):
  189. get_channel_id(self.organization, self.integration, "@user")