oncall-engine/engine/apps/twilioapp/tests/test_twilio_provider.py
Innokentii Konstantinov 03ff4c5426
Listen for alert group actions during whole notification call (#5282)
1. Wrap whole message in twiml <Gather>  - that's an actual fix
2. Use twilio helper lib to build twiml queries
3. URLencode twimlquery only once before making a call to reduce code
duplication.

---------

Co-authored-by: Joey Orlando <joey.orlando@grafana.com>
2024-11-22 04:34:40 +00:00

160 lines
6.2 KiB
Python

from unittest import mock
import pytest
from twilio.base.exceptions import TwilioRestException
from apps.phone_notifications.exceptions import FailedToFinishVerification, FailedToMakeCall, FailedToSendSMS
from apps.twilioapp.phone_provider import TwilioPhoneProvider
class MockTwilioCallInstance:
status = "mock_status"
sid = "mock_sid"
class MockTwilioMessageInstance:
status = "mock_status"
sid = "mock_sid"
@pytest.mark.django_db
@mock.patch("apps.twilioapp.phone_provider.TwilioPhoneProvider._call_create", return_value=MockTwilioCallInstance())
@mock.patch(
"apps.twilioapp.phone_provider.TwilioPhoneProvider._message_to_twiml_gather", return_value="twiml_gather_response"
)
def test_make_notification_call(mock_twiml, mock_call_create):
number = "+1234567890"
message = "Hello"
provider = TwilioPhoneProvider()
provider_call = provider.make_notification_call(number, message)
mock_call_create.assert_called_once_with("twiml_gather_response", number, with_callback=True)
assert provider_call is not None
assert provider_call.sid == MockTwilioCallInstance.sid
assert provider_call.id is None # test that provider_call is returned by notification call and NOT saved
@pytest.mark.django_db
@mock.patch("apps.twilioapp.phone_provider.TwilioPhoneProvider._call_create", return_value=MockTwilioCallInstance())
@mock.patch(
"apps.twilioapp.phone_provider.TwilioPhoneProvider._message_to_twiml_say", return_value="twiml_say_response"
)
def test_make_call(mock_twiml, mock_call_create):
number = "+1234567890"
message = "Hello"
provider = TwilioPhoneProvider()
provider_call = provider.make_call(number, message)
assert provider_call is None # test that provider_call is not returned from make_call
mock_call_create.assert_called_once_with("twiml_say_response", number, with_callback=False)
class MockTwilioSMSInstance:
status = "mock_status"
sid = "mock_sid"
@pytest.mark.django_db
@mock.patch("apps.twilioapp.phone_provider.TwilioPhoneProvider._messages_create", return_value=MockTwilioSMSInstance())
def test_send_notification_sms(mock_messages_create):
number = "+1234567890"
message = "Hello"
provider = TwilioPhoneProvider()
provider_sms = provider.send_notification_sms(number, message)
mock_messages_create.assert_called_once_with(number, message, with_callback=True)
assert provider_sms is not None
assert provider_sms.sid == MockTwilioCallInstance.sid
assert provider_sms.id is None # test that provider_call is returned by notification call and NOT saved
@pytest.mark.django_db
@mock.patch("apps.twilioapp.phone_provider.TwilioPhoneProvider._messages_create", return_value=MockTwilioSMSInstance())
def test_send_sms(mock_messages_create):
number = "+1234567890"
message = "Hello"
provider = TwilioPhoneProvider()
provider_sms = provider.send_sms(number, message)
assert provider_sms is None # test that provider_sms is not returned from send_sms
mock_messages_create.assert_called_once_with(number, message, with_callback=False)
TEST_NUMBER = "+1234567890"
TEST_MESSAGE = "Hello"
TEST_CODE = "12345"
@pytest.mark.django_db
@pytest.mark.parametrize(
"twilio_code,expected_exception,graceful_msg,provider_method,mock_method",
[
(60200, FailedToMakeCall, True, lambda p: p.make_call(TEST_NUMBER, TEST_MESSAGE), "_call_create"),
(30808, FailedToMakeCall, False, lambda p: p.make_call(TEST_NUMBER, TEST_MESSAGE), "_call_create"),
(None, FailedToMakeCall, False, lambda p: p.make_call(TEST_NUMBER, TEST_MESSAGE), "_call_create"),
(30410, FailedToMakeCall, True, lambda p: p.make_notification_call(TEST_NUMBER, TEST_MESSAGE), "_call_create"),
(30808, FailedToMakeCall, False, lambda p: p.make_notification_call(TEST_NUMBER, TEST_MESSAGE), "_call_create"),
(None, FailedToMakeCall, False, lambda p: p.make_notification_call(TEST_NUMBER, TEST_MESSAGE), "_call_create"),
(30004, FailedToSendSMS, True, lambda p: p.send_sms(TEST_NUMBER, TEST_MESSAGE), "_messages_create"),
(30808, FailedToSendSMS, False, lambda p: p.send_sms(TEST_NUMBER, TEST_MESSAGE), "_messages_create"),
(None, FailedToSendSMS, False, lambda p: p.send_sms(TEST_NUMBER, TEST_MESSAGE), "_messages_create"),
(
30006,
FailedToSendSMS,
True,
lambda p: p.send_notification_sms(TEST_NUMBER, TEST_MESSAGE),
"_messages_create",
),
(
30808,
FailedToSendSMS,
False,
lambda p: p.send_notification_sms(TEST_NUMBER, TEST_MESSAGE),
"_messages_create",
),
(
None,
FailedToSendSMS,
False,
lambda p: p.send_notification_sms(TEST_NUMBER, TEST_MESSAGE),
"_messages_create",
),
(
60203,
FailedToFinishVerification,
True,
lambda p: p.finish_verification(TEST_NUMBER, TEST_CODE),
"_verify_sender",
),
(
30808,
FailedToFinishVerification,
False,
lambda p: p.finish_verification(TEST_NUMBER, TEST_CODE),
"_verify_sender",
),
(
None,
FailedToFinishVerification,
False,
lambda p: p.finish_verification(TEST_NUMBER, TEST_CODE),
"_verify_sender",
),
],
)
@mock.patch("apps.twilioapp.phone_provider.TwilioPhoneProvider._normalize_phone_number", return_value=(TEST_NUMBER, 1))
def test_twilio_provider_exceptions(
mocked_normalize, twilio_code, expected_exception, graceful_msg, provider_method, mock_method
):
provider = TwilioPhoneProvider()
with mock.patch(f"apps.twilioapp.phone_provider.TwilioPhoneProvider.{mock_method}") as twilio_mock:
twilio_mock.side_effect = TwilioRestException(500, "", code=twilio_code)
with pytest.raises(expected_exception) as exc:
provider_method(provider)
if graceful_msg:
assert len(exc.value.graceful_msg) > 0
else:
assert exc.value.graceful_msg is None
twilio_mock.assert_called_once()
class MockTwilioSMSInstance:
status = "mock_status"
sid = "mock_sid"