test_plugin.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. from functools import cached_property
  2. from urllib.parse import parse_qs
  3. import responses
  4. from sentry.models.rule import Rule
  5. from sentry.plugins.base import Notification
  6. from sentry.testutils.cases import PluginTestCase, TestCase
  7. from sentry_plugins.twilio.plugin import TwilioConfigurationForm, TwilioPlugin, split_sms_to
  8. class TwilioPluginSMSSplitTest(TestCase):
  9. def test_valid_split_sms_to(self):
  10. to = "330-509-3095, (330)-509-3095, +13305093095, 4045550144"
  11. expected = {"330-509-3095", "(330)-509-3095", "+13305093095", "4045550144"}
  12. actual = split_sms_to(to)
  13. assert expected == actual
  14. def test_valid_split_sms_to_with_extra_spaces(self):
  15. to = "330-509-3095 , (330)-509-3095, +13305093095, 4045550144"
  16. expected = {"330-509-3095", "(330)-509-3095", "+13305093095", "4045550144"}
  17. actual = split_sms_to(to)
  18. assert expected == actual
  19. def test_valid_split_sms_to_with_just_spaces(self):
  20. to = "330-509-3095 (330)-509-3095 +13305093095 4045550144"
  21. expected = {"330-509-3095", "(330)-509-3095", "+13305093095", "4045550144"}
  22. actual = split_sms_to(to)
  23. assert expected == actual
  24. def test_valid_split_sms_to_with_no_whitespace(self):
  25. to = "330-509-3095,(330)-509-3095,+13305093095,4045550144"
  26. expected = {"330-509-3095", "(330)-509-3095", "+13305093095", "4045550144"}
  27. actual = split_sms_to(to)
  28. assert expected == actual
  29. def test_split_sms_to_with_single_number(self):
  30. to = "555-555-5555"
  31. expected = {"555-555-5555"}
  32. actual = split_sms_to(to)
  33. assert expected == actual
  34. def test_valid_split_sms_to_newline(self):
  35. to = "330-509-3095,\n(330)-509-3095\n,+13305093095\n,\n4045550144"
  36. expected = {"330-509-3095", "(330)-509-3095", "+13305093095", "4045550144"}
  37. actual = split_sms_to(to)
  38. assert expected == actual
  39. def test_valid_split_sms_to_with_just_newlines(self):
  40. to = "330-509-3095\n(330)-509-3095\n+13305093095\n\n4045550144"
  41. expected = {"330-509-3095", "(330)-509-3095", "+13305093095", "4045550144"}
  42. actual = split_sms_to(to)
  43. assert expected == actual
  44. def test_valid_split_sms_to_with_extra_newlines(self):
  45. to = "330-509-3095\n\n\n\n\n,\n\n\n\n\n\n\n\n\n(330)-509-3095,\n\n\n\n+13305093095,\n\n4045550144"
  46. expected = {"330-509-3095", "(330)-509-3095", "+13305093095", "4045550144"}
  47. actual = split_sms_to(to)
  48. assert expected == actual
  49. class TwilioConfigurationFormTest(TestCase):
  50. def test_valid_form(self):
  51. form = TwilioConfigurationForm(
  52. data={
  53. "sms_from": "3305093095",
  54. "sms_to": "330-509-3095, (330)-509-3095, +13305093095, 4045550144",
  55. "auth_token": "foo",
  56. "account_sid": "bar",
  57. }
  58. )
  59. self.assertTrue(form.is_valid())
  60. cleaned = form.clean()
  61. assert cleaned is not None
  62. self.assertDictEqual(
  63. cleaned,
  64. {
  65. "auth_token": "foo",
  66. "sms_to": "+13305093095,+14045550144",
  67. "sms_from": "+13305093095",
  68. "account_sid": "bar",
  69. },
  70. )
  71. def test_invalid_form(self):
  72. form = TwilioConfigurationForm(data={"sms_from": "foobar", "sms_to": "911"})
  73. self.assertFalse(form.is_valid())
  74. errors = form.errors.as_data()
  75. error_msgs = {k: [e.message for e in v] for k, v in errors.items()}
  76. self.assertDictEqual(
  77. error_msgs,
  78. {
  79. "auth_token": ["This field is required."],
  80. "account_sid": ["This field is required."],
  81. "sms_from": ["foobar is not a valid phone number."],
  82. "sms_to": ["911 is not a valid phone number."],
  83. },
  84. )
  85. class TwilioPluginTest(PluginTestCase):
  86. @cached_property
  87. def plugin(self):
  88. return TwilioPlugin()
  89. def test_conf_key(self):
  90. assert self.plugin.conf_key == "twilio"
  91. def test_entry_point(self):
  92. self.assertPluginInstalled("twilio", self.plugin)
  93. def test_is_configured(self):
  94. for o in ("account_sid", "auth_token", "sms_from", "sms_to"):
  95. assert self.plugin.is_configured(self.project) is False
  96. self.plugin.set_option(o, "foo", self.project)
  97. assert self.plugin.is_configured(self.project) is True
  98. @responses.activate
  99. def test_simple_notification(self):
  100. responses.add("POST", "https://api.twilio.com/2010-04-01/Accounts/abcdef/Messages.json")
  101. self.plugin.set_option("account_sid", "abcdef", self.project)
  102. self.plugin.set_option("auth_token", "abcd", self.project)
  103. self.plugin.set_option("sms_from", "4158675309", self.project)
  104. self.plugin.set_option("sms_to", "4154444444", self.project)
  105. event = self.store_event(
  106. data={
  107. "message": "Hello world",
  108. "level": "warning",
  109. "platform": "python",
  110. "culprit": "foo.bar",
  111. },
  112. project_id=self.project.id,
  113. )
  114. rule = Rule.objects.create(project=self.project, label="my rule")
  115. notification = Notification(event=event, rule=rule)
  116. with self.options({"system.url-prefix": "http://example.com"}):
  117. self.plugin.notify(notification)
  118. request = responses.calls[0].request
  119. payload = parse_qs(request.body)
  120. assert payload == {
  121. "To": ["+14154444444"],
  122. "From": ["+14158675309"],
  123. "Body": ["Sentry [%s] WARNING: Hello world" % self.project.slug.title()],
  124. }