test_plugin.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. from functools import cached_property
  2. from urllib.parse import parse_qs
  3. import responses
  4. from sentry.models import Rule
  5. from sentry.plugins.base import Notification
  6. from sentry.testutils 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. self.assertDictEqual(
  61. form.clean(),
  62. {
  63. "auth_token": "foo",
  64. "sms_to": "+13305093095,+14045550144",
  65. "sms_from": "+13305093095",
  66. "account_sid": "bar",
  67. },
  68. )
  69. def test_invalid_form(self):
  70. form = TwilioConfigurationForm(data={"sms_from": "foobar", "sms_to": "911"})
  71. self.assertFalse(form.is_valid())
  72. errors = form.errors.as_data()
  73. # extracting the message from django.forms.ValidationError
  74. # is the easiest and simplest way I've found to assert as_data
  75. for e in errors:
  76. errors[e] = list(map(lambda x: x.message, errors[e]))
  77. self.assertDictEqual(
  78. errors,
  79. {
  80. "auth_token": ["This field is required."],
  81. "account_sid": ["This field is required."],
  82. "sms_from": ["foobar is not a valid phone number."],
  83. "sms_to": ["911 is not a valid phone number."],
  84. },
  85. )
  86. class TwilioPluginTest(PluginTestCase):
  87. @cached_property
  88. def plugin(self):
  89. return TwilioPlugin()
  90. def test_conf_key(self):
  91. assert self.plugin.conf_key == "twilio"
  92. def test_entry_point(self):
  93. self.assertPluginInstalled("twilio", self.plugin)
  94. def test_is_configured(self):
  95. for o in ("account_sid", "auth_token", "sms_from", "sms_to"):
  96. assert self.plugin.is_configured(self.project) is False
  97. self.plugin.set_option(o, "foo", self.project)
  98. assert self.plugin.is_configured(self.project) is True
  99. @responses.activate
  100. def test_simple_notification(self):
  101. responses.add("POST", "https://api.twilio.com/2010-04-01/Accounts/abcdef/Messages.json")
  102. self.plugin.set_option("account_sid", "abcdef", self.project)
  103. self.plugin.set_option("auth_token", "abcd", self.project)
  104. self.plugin.set_option("sms_from", "4158675309", self.project)
  105. self.plugin.set_option("sms_to", "4154444444", self.project)
  106. event = self.store_event(
  107. data={
  108. "message": "Hello world",
  109. "level": "warning",
  110. "platform": "python",
  111. "culprit": "foo.bar",
  112. },
  113. project_id=self.project.id,
  114. )
  115. rule = Rule.objects.create(project=self.project, label="my rule")
  116. notification = Notification(event=event, rule=rule)
  117. with self.options({"system.url-prefix": "http://example.com"}):
  118. self.plugin.notify(notification)
  119. request = responses.calls[0].request
  120. payload = parse_qs(request.body)
  121. assert payload == {
  122. "To": ["+14154444444"],
  123. "From": ["+14158675309"],
  124. "Body": ["Sentry [%s] WARNING: Hello world" % self.project.slug.title()],
  125. }