Skip to content

Commit

Permalink
#2104 - Update Twilio Error Codes (#2147)
Browse files Browse the repository at this point in the history
  • Loading branch information
k-macmillan authored Nov 27, 2024
1 parent 4919911 commit e69c34f
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 142 deletions.
2 changes: 2 additions & 0 deletions .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,6 @@ fileignoreconfig:
checksum: 4f0f4d7a4113762219e45a51f7b26a7c0cb83f1d8f10c5598533f6cdcf0e0ada
- filename: tests/lambda_functions/vetext_incoming_forwarder_lambda/test_vetext_incoming_forwarder_lambda.py
checksum: 7494eb4321fd2fbc3ff3915d8753d8fec7a936a69dc6ab78f0b532a701f032eb
- filename: tests/app/clients/test_twilio.py
checksum: cad49e634cc5ba56157358aa3dfba2dafe7b9dbd3a0c580ec5cda3072f6a76e5
version: "1.0"
2 changes: 1 addition & 1 deletion app/celery/process_delivery_status_result_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ def sms_status_update(
last_updated_at = notification.updated_at

current_app.logger.info(
'Iniital %s logic | reference: %s | notification_id: %s | status: %s | status_reason: %s',
'Initial %s logic | reference: %s | notification_id: %s | status: %s | status_reason: %s',
sms_status.provider,
sms_status.reference,
notification.id,
Expand Down
48 changes: 30 additions & 18 deletions app/clients/sms/twilio.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@
from twilio.base.exceptions import TwilioRestException

from app.celery.exceptions import NonRetryableException
from app.clients.sms import SmsClient, SmsStatusRecord, UNABLE_TO_TRANSLATE
from app.clients.sms import SmsClient, SmsStatusRecord, OPT_OUT_MESSAGE, UNABLE_TO_TRANSLATE
from app.constants import (
NOTIFICATION_CREATED,
NOTIFICATION_DELIVERED,
NOTIFICATION_PERMANENT_FAILURE,
NOTIFICATION_SENDING,
NOTIFICATION_SENT,
NOTIFICATION_TECHNICAL_FAILURE,
NOTIFICATION_TEMPORARY_FAILURE,
RETRYABLE_STATUS_REASON,
TWILIO_PROVIDER,
)
from app.exceptions import InvalidProviderException
Expand Down Expand Up @@ -50,6 +52,29 @@ def get_twilio_responses(status):
class TwilioSMSClient(SmsClient):
RAW_DLR_DONE_DATE_FMT = '%y%m%d%H%M'

twilio_error_code_map = {
'21268': TwilioStatus(21268, NOTIFICATION_PERMANENT_FAILURE, 'Premium numbers are not permitted'),
'21408': TwilioStatus(21408, NOTIFICATION_PERMANENT_FAILURE, 'Invalid region specified'),
'21610': TwilioStatus(21610, NOTIFICATION_PERMANENT_FAILURE, OPT_OUT_MESSAGE),
'21612': TwilioStatus(21612, NOTIFICATION_PERMANENT_FAILURE, 'Invalid to/from combo'),
'21614': TwilioStatus(21614, NOTIFICATION_PERMANENT_FAILURE, 'Non-mobile number'),
'21635': TwilioStatus(21635, NOTIFICATION_PERMANENT_FAILURE, 'Non-mobile number'),
'30001': TwilioStatus(30001, NOTIFICATION_TEMPORARY_FAILURE, 'Queue overflow'),
'30002': TwilioStatus(30002, NOTIFICATION_PERMANENT_FAILURE, 'Account suspended'),
'30003': TwilioStatus(30003, NOTIFICATION_PERMANENT_FAILURE, 'Unreachable destination handset'),
'30004': TwilioStatus(30004, NOTIFICATION_PERMANENT_FAILURE, 'Message blocked'),
'30005': TwilioStatus(30005, NOTIFICATION_PERMANENT_FAILURE, 'Unknown destination handset'),
'30006': TwilioStatus(30006, NOTIFICATION_PERMANENT_FAILURE, 'Landline or unreachable carrier'),
'30007': TwilioStatus(30007, NOTIFICATION_PERMANENT_FAILURE, 'Message filtered'),
'30008': TwilioStatus(30008, NOTIFICATION_TECHNICAL_FAILURE, 'Unknown error'),
'30009': TwilioStatus(30009, NOTIFICATION_TECHNICAL_FAILURE, 'Missing inbound segment'),
'30010': TwilioStatus(30010, NOTIFICATION_TECHNICAL_FAILURE, 'Message price exceeds max price'),
'30024': TwilioStatus(30024, NOTIFICATION_TECHNICAL_FAILURE, 'Sender not provisioned by carrier'),
'30034': TwilioStatus(30034, NOTIFICATION_PERMANENT_FAILURE, 'Used an unregistered 10DLC Number'),
'30500': TwilioStatus(30500, NOTIFICATION_TEMPORARY_FAILURE, RETRYABLE_STATUS_REASON),
'60005': TwilioStatus(60005, NOTIFICATION_TEMPORARY_FAILURE, 'Carrier error'),
}

def __init__(
self,
account_sid=None,
Expand All @@ -71,20 +96,6 @@ def __init__(
self._auth_token = auth_token
self._client = Client(account_sid, auth_token)

self.twilio_error_code_map = {
'30001': TwilioStatus(30001, NOTIFICATION_TECHNICAL_FAILURE, 'Queue overflow'),
'30002': TwilioStatus(30002, NOTIFICATION_PERMANENT_FAILURE, 'Account suspended'),
'30003': TwilioStatus(30003, NOTIFICATION_PERMANENT_FAILURE, 'Unreachable destination handset'),
'30004': TwilioStatus(30004, NOTIFICATION_PERMANENT_FAILURE, 'Message blocked'),
'30005': TwilioStatus(30005, NOTIFICATION_PERMANENT_FAILURE, 'Unknown destination handset'),
'30006': TwilioStatus(30006, NOTIFICATION_PERMANENT_FAILURE, 'Landline or unreachable carrier'),
'30007': TwilioStatus(30007, NOTIFICATION_PERMANENT_FAILURE, 'Message filtered'),
'30008': TwilioStatus(30008, NOTIFICATION_TECHNICAL_FAILURE, 'Unknown error'),
'30009': TwilioStatus(30009, NOTIFICATION_TECHNICAL_FAILURE, 'Missing inbound segment'),
'30010': TwilioStatus(30010, NOTIFICATION_TECHNICAL_FAILURE, 'Message price exceeds max price'),
'30034': TwilioStatus(30034, NOTIFICATION_PERMANENT_FAILURE, 'Used an unregistered 10DLC Number'),
}

self.twilio_notify_status_map = {
'accepted': TwilioStatus(None, NOTIFICATION_SENDING, None),
'scheduled': TwilioStatus(None, NOTIFICATION_SENDING, None),
Expand Down Expand Up @@ -378,12 +389,13 @@ def _evaluate_status(self, message_sid: str, twilio_delivery_status: str, error_
)
notify_delivery_status: TwilioStatus = self.twilio_notify_status_map[twilio_delivery_status]
else:
# Logic not being changed, just want to log this for now
# Error codes may be retained for new messages, meaning a "sending" could retain a 30005
if error_codes:
self.logger.warning(
'Error code: %s existed but status for message: %s was not failed nor undelivered',
self.logger.info(
'Error code: %s existed but status for message: %s with status: %s',
error_codes[0],
message_sid,
twilio_delivery_status,
)
notify_delivery_status: TwilioStatus = self.twilio_notify_status_map[twilio_delivery_status]

Expand Down
5 changes: 5 additions & 0 deletions app/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,8 @@
JOB_STATUS_SENT_TO_DVLA,
JOB_STATUS_ERROR,
)

# Status reasons
RETRYABLE_STATUS_REASON = (
'Retryable - Notification is unable to be processed at this time. Replay the request to VA Notify.'
)
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def validate_signature_and_body(token, uri, body, signature):
encoded = urlencode(params).encode()

# Turn byte string into a base64 encoded message
msg = base64.b64encode(encoded).decode('utf-8')
msg = base64.b64encode(encoded).decode('utf-8') # noqa: F841 - Util helper. Keeping for understanding

assert signature == new_signature

Expand All @@ -60,18 +60,19 @@ def generate_twilio_signature_and_body(
addons: str = '',
api_version: str = '2010-04-01',
body: str = '',
error_code: str = '',
from_number: str = '+18888888888',
from_city: str = 'LOS ANGELES',
from_country: str = 'US',
from_state: str = 'CA',
from_zip: str = '12345',
message_sid: str = '',
message_status: str = 'received',
message_service_sid: str = '',
num_media: str = '0',
num_segments: str = '1',
sms_message_sid: str = '',
sms_sid: str = '',
sms_status: str = 'received',
to_number: str = '+12345678901',
to_city: str = 'PROVIDENCE',
to_country: str = 'US',
Expand All @@ -89,18 +90,20 @@ def generate_twilio_signature_and_body(
'AddOns': addons or '{"status":"successful","message":null,"code":null,"results":{}}',
'ApiVersion': api_version,
'Body': body or f'test body {uuid4()}',
'ErrorCode': error_code,
'From': from_number,
'FromCity': from_city,
'FromCountry': from_country,
'FromState': from_state,
'FromZip': from_zip,
'MessageSid': message_sid or msg_sid,
'MessageStatus': message_status,
'MessagingServiceSid': message_service_sid or f'MG{uuid4()}'.replace('-', ''),
'NumMedia': num_media,
'NumSegments': num_segments,
'SmsMessageSid': sms_message_sid or msg_sid,
'SmsSid': sms_sid or msg_sid,
'SmsStatus': sms_status,
'SmsStatus': message_status, # Appears deprecated, used in incoming forwarder though
'To': to_number,
'ToCity': to_city,
'ToCountry': to_country,
Expand All @@ -122,12 +125,12 @@ def generate_twilio_signature_and_body(
if __name__ == '__main__':
# How to generate a test body and signature
# To test real events use VEText's token. Ask the Tech Lead or QA. Tokens are not shared with the team.
token = '12345678'
rv = RequestValidator(token)
fake_token = '12345678' # nosec
rv = RequestValidator(fake_token)

uri = 'https://staging-api.va.gov/vanotify/twoway/vettext'

signature, body = generate_twilio_signature_and_body(token, uri)
signature, body = generate_twilio_signature_and_body(fake_token, uri)
print(f'Body: {body}\n, Signature: {signature}')

###################################### For Understanding Each Part of the Process ######################################
Expand All @@ -148,4 +151,4 @@ def generate_twilio_signature_and_body(
new_signature = rv.compute_signature(uri, params)
print(new_signature)

validate_signature_and_body(token, uri, body, signature)
validate_signature_and_body(fake_token, uri, body, signature)
2 changes: 2 additions & 0 deletions tests/app/celery/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,7 @@ def test_should_put_save_email_task_in_research_mode_queue_if_research_mode_serv
)


@pytest.mark.serial
def test_should_save_sms_template_to_and_persist_with_job_id(
notify_db_session,
sample_template,
Expand All @@ -758,6 +759,7 @@ def test_should_save_sms_template_to_and_persist_with_job_id(

notification_id = uuid4()
now = datetime.utcnow()
# serial - Fails intermittently
save_sms(
job.service.id,
notification_id,
Expand Down
147 changes: 31 additions & 116 deletions tests/app/clients/test_twilio.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from app import twilio_sms_client
from app.celery.exceptions import NonRetryableException
from app.clients.sms import SmsStatusRecord
from app.clients.sms.twilio import get_twilio_responses, TwilioSMSClient
from app.clients.sms.twilio import get_twilio_responses, TwilioSMSClient, TwilioStatus
from app.constants import (
NOTIFICATION_DELIVERED,
NOTIFICATION_TECHNICAL_FAILURE,
Expand All @@ -19,9 +19,14 @@
NOTIFICATION_SENT,
)
from app.exceptions import InvalidProviderException
from lambda_functions.vetext_incoming_forwarder_lambda.twilio_signature_utils import generate_twilio_signature_and_body
from tests.app.db import create_service_sms_sender


FAKE_DELIVERY_STATUS_URI = 'https://api.va.gov/sms/deliverystatus'
FAKE_DELIVERY_STATUS_TOKEN = 'unit_test'


class FakeClient:
def __init__(self, **kwargs):
self.messages = self.MessageFactory()
Expand Down Expand Up @@ -173,87 +178,6 @@ def service_sms_sender(request):
}


MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30001 = {
'twilio_status': NOTIFICATION_TECHNICAL_FAILURE,
'message': 'eyJhcmdzIjogW3siTWVzc2FnZSI6IHsiYm9keSI6ICJSYXdEbHJEb25lRGF0ZT0yMzAzMDkyMDIxJkVycm'
'9yQ29kZT0zMDAwMSZTbXNTaWQ9U014eHgmU21zU3RhdHVzPWZhaWxlZCZNZXNzYWdlU3RhdHVzPWZhaWxlZCZUbz0lMk'
'IxMTExMTExMTExMSZNZXNzYWdlU2lkPVNNeXl5JkFjY291bnRTaWQ9QUN6enomRnJvbT0lMkIxMjIyMjIyMjIyMiZBcGl'
'WZXJzaW9uPTIwMTAtMDQtMDEiLCAicHJvdmlkZXIiOiAidHdpbGlvIn19XX0=',
}


MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30002 = {
'twilio_status': NOTIFICATION_PERMANENT_FAILURE,
'message': 'eyJhcmdzIjogW3siTWVzc2FnZSI6IHsiYm9keSI6ICJSYXdEbHJEb25lRGF0ZT0yMzAzMDkyMDIxJkV'
'ycm9yQ29kZT0zMDAwMiZTbXNTaWQ9U014eHgmU21zU3RhdHVzPWZhaWxlZCZNZXNzYWdlU3RhdHVzPWZhaWxlZCZU'
'bz0lMkIxMTExMTExMTExMSZNZXNzYWdlU2lkPVNNeXl5JkFjY291bnRTaWQ9QUN6enomRnJvbT0lMkIxMjIyMjIyM'
'jIyMiZBcGlWZXJzaW9uPTIwMTAtMDQtMDEiLCAicHJvdmlkZXIiOiAidHdpbGlvIn19XX0=',
}


MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30003 = {
'twilio_status': NOTIFICATION_PERMANENT_FAILURE,
'message': 'eyJhcmdzIjogW3siTWVzc2FnZSI6IHsiYm9keSI6ICJSYXdEbHJEb25lRGF0ZT0yMzAzMDkyMDIxJ'
'kVycm9yQ29kZT0zMDAwMyZTbXNTaWQ9U014eHgmU21zU3RhdHVzPWZhaWxlZCZNZXNzYWdlU3RhdHVzPWZhaWxlZ'
'CZUbz0lMkIxMTExMTExMTExMSZNZXNzYWdlU2lkPVNNeXl5JkFjY291bnRTaWQ9QUN6enomRnJvbT0lMkIxMjIyM'
'jIyMjIyMiZBcGlWZXJzaW9uPTIwMTAtMDQtMDEiLCAicHJvdmlkZXIiOiAidHdpbGlvIn19XX0=',
}


MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30004 = {
'twilio_status': NOTIFICATION_PERMANENT_FAILURE,
'message': 'eyJhcmdzIjogW3siTWVzc2FnZSI6IHsiYm9keSI6ICJSYXdEbHJEb25lRGF0ZT0yMzAzMDkyMDIxJkV'
'ycm9yQ29kZT0zMDAwNCZTbXNTaWQ9U014eHgmU21zU3RhdHVzPWZhaWxlZCZNZXNzYWdlU3RhdHVzPWZhaWxlZCZU'
'bz0lMkIxMTExMTExMTExMSZNZXNzYWdlU2lkPVNNeXl5JkFjY291bnRTaWQ9QUN6enomRnJvbT0lMkIxMjIyMjIyMj'
'IyMiZBcGlWZXJzaW9uPTIwMTAtMDQtMDEiLCAicHJvdmlkZXIiOiAidHdpbGlvIn19XX0=',
}


MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30005 = {
'twilio_status': NOTIFICATION_PERMANENT_FAILURE,
'message': 'eyJhcmdzIjogW3siTWVzc2FnZSI6IHsiYm9keSI6ICJSYXdEbHJEb25lRGF0ZT0yMzAzMDkyMDIxJ'
'kVycm9yQ29kZT0zMDAwNSZTbXNTaWQ9U014eHgmU21zU3RhdHVzPWZhaWxlZCZNZXNzYWdlU3RhdHVzPWZhaWxlZC'
'ZUbz0lMkIxMTExMTExMTExMSZNZXNzYWdlU2lkPVNNeXl5JkFjY291bnRTaWQ9QUN6enomRnJvbT0lMkIxMjIyMjI'
'yMjIyMiZBcGlWZXJzaW9uPTIwMTAtMDQtMDEiLCAicHJvdmlkZXIiOiAidHdpbGlvIn19XX0=',
}


MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30006 = {
'twilio_status': NOTIFICATION_PERMANENT_FAILURE,
'message': 'eyJhcmdzIjogW3siTWVzc2FnZSI6IHsiYm9keSI6ICJSYXdEbHJEb25lRGF0ZT0yMzAzMDkyMDIx'
'JkVycm9yQ29kZT0zMDAwNiZTbXNTaWQ9U014eHgmU21zU3RhdHVzPWZhaWxlZCZNZXNzYWdlU3RhdHVzPWZhaWx'
'lZCZUbz0lMkIxMTExMTExMTExMSZNZXNzYWdlU2lkPVNNeXl5JkFjY291bnRTaWQ9QUN6enomRnJvbT0lMkIxMj'
'IyMjIyMjIyMiZBcGlWZXJzaW9uPTIwMTAtMDQtMDEiLCAicHJvdmlkZXIiOiAidHdpbGlvIn19XX0=',
}


MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30007 = {
'twilio_status': NOTIFICATION_PERMANENT_FAILURE,
'message': 'eyJhcmdzIjogW3siTWVzc2FnZSI6IHsiYm9keSI6ICJSYXdEbHJEb25lRGF0ZT0yMzAzMDkyMDIxJk'
'Vycm9yQ29kZT0zMDAwNyZTbXNTaWQ9U014eHgmU21zU3RhdHVzPWZhaWxlZCZNZXNzYWdlU3RhdHVzPWZhaWxlZCZ'
'Ubz0lMkIxMTExMTExMTExMSZNZXNzYWdlU2lkPVNNeXl5JkFjY291bnRTaWQ9QUN6enomRnJvbT0lMkIxMjIyMj'
'IyMjIyMiZBcGlWZXJzaW9uPTIwMTAtMDQtMDEiLCAicHJvdmlkZXIiOiAidHdpbGlvIn19XX0=',
}


MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30008 = {
'twilio_status': NOTIFICATION_TECHNICAL_FAILURE,
'message': 'eyJhcmdzIjogW3siTWVzc2FnZSI6IHsiYm9keSI6ICJSYXdEbHJEb25lRGF0ZT0yMzAzMDkyMDIxJk'
'Vycm9yQ29kZT0zMDAwOCZTbXNTaWQ9U014eHgmU21zU3RhdHVzPWZhaWxlZCZNZXNzYWdlU3RhdHVzPWZhaWxlZ'
'CZUbz0lMkIxMTExMTExMTExMSZNZXNzYWdlU2lkPVNNeXl5JkFjY291bnRTaWQ9QUN6enomRnJvbT0lMkIxMjIyM'
'jIyMjIyMiZBcGlWZXJzaW9uPTIwMTAtMDQtMDEiLCAicHJvdmlkZXIiOiAidHdpbGlvIn19XX0=',
}


MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30009 = {
'twilio_status': NOTIFICATION_TECHNICAL_FAILURE,
'message': 'eyJhcmdzIjogW3siTWVzc2FnZSI6IHsiYm9keSI6ICJSYXdEbHJEb25lRGF0ZT0yMzAzMDkyMDIxJk'
'Vycm9yQ29kZT0zMDAwOSZTbXNTaWQ9U014eHgmU21zU3RhdHVzPWZhaWxlZCZNZXNzYWdlU3RhdHVzPWZhaWxlZCZ'
'Ubz0lMkIxMTExMTExMTExMSZNZXNzYWdlU2lkPVNNeXl5JkFjY291bnRTaWQ9QUN6enomRnJvbT0lMkIxMjIyMjI'
'yMjIyMiZBcGlWZXJzaW9uPTIwMTAtMDQtMDEiLCAicHJvdmlkZXIiOiAidHdpbGlvIn19XX0=',
}


MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30010 = {
'twilio_status': NOTIFICATION_TECHNICAL_FAILURE,
'message': 'eyJhcmdzIjogW3siTWVzc2FnZSI6IHsiYm9keSI6ICJSYXdEbHJEb25lRGF0ZT0yMzAzMDkyMDIx'
Expand All @@ -263,24 +187,6 @@ def service_sms_sender(request):
}


MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30034 = {
'twilio_status': NOTIFICATION_PERMANENT_FAILURE,
'message': 'eyJhcmdzIjogW3siTWVzc2FnZSI6IHsiYm9keSI6ICJSYXdEbHJEb25lRGF0ZT0yMzAzMDkyMDIxJk'
'Vycm9yQ29kZT0zMDAzNCZTbXNTaWQ9U014eHgmU21zU3RhdHVzPWZhaWxlZCZNZXNzYWdlU3RhdHVzPWZhaWxlZCZ'
'Ubz0lMkIxMTExMTExMTExMSZNZXNzYWdlU2lkPVNNeXl5JkFjY291bnRTaWQ9QUN6enomRnJvbT0lMkIxMjIyMjIy'
'MjIyMiZBcGlWZXJzaW9uPTIwMTAtMDQtMDEiLCAicHJvdmlkZXIiOiAidHdpbGlvIn19XX0=',
}


MESSAAGE_BODY_WITH_FAILED_STATUS_AND_INVALID_ERROR_CODE = {
'twilio_status': NOTIFICATION_TECHNICAL_FAILURE,
'message': 'eyJhcmdzIjogW3siTWVzc2FnZSI6IHsiYm9keSI6ICJSYXdEbHJEb25lRGF0ZT0yMzAzMDkyMDIxJ'
'kVycm9yQ29kZT0zMDAxMSZTbXNTaWQ9U014eHgmU21zU3RhdHVzPWZhaWxlZCZNZXNzYWdlU3RhdHVzPWZhaWxlZ'
'CZUbz0lMkIxMTExMTExMTExMSZNZXNzYWdlU2lkPVNNeXl5JkFjY291bnRTaWQ9QUN6enomRnJvbT0lMkIxMjIy'
'MjIyMjIyMiZBcGlWZXJzaW9uPTIwMTAtMDQtMDEiLCAicHJvdmlkZXIiOiAidHdpbGlvIn19XX0=',
}


MESSAGE_BODY_WITH_NO_MESSAGE_STATUS = {
'twilio_status': None,
'message': 'eyJhcmdzIjogW3siTWVzc2FnZSI6IHsiYm9keSI6ICJSYXdEbHJEb25lRGF0ZT0yMzAzMDky'
Expand All @@ -299,6 +205,21 @@ def service_sms_sender(request):
}


@pytest.fixture
def sample_twilio_delivery_status():
"""Take a TwilioStatus mapping and generate a body and signature to match."""

def _wrapper(twilio_status: TwilioStatus):
return generate_twilio_signature_and_body(
token=FAKE_DELIVERY_STATUS_TOKEN,
uri=FAKE_DELIVERY_STATUS_URI,
error_code=str(twilio_status.code),
message_status='failed',
)

yield _wrapper


@pytest.fixture
def twilio_sms_client_mock(mocker):
client = TwilioSMSClient('CREDS', 'CREDS')
Expand Down Expand Up @@ -376,26 +297,20 @@ def test_notification_mapping(event, twilio_sms_client_mock):


@pytest.mark.parametrize(
'event',
'twilio_status',
[
MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30001,
MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30002,
MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30003,
MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30004,
MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30005,
MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30006,
MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30007,
MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30008,
MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30009,
MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30010,
MESSAAGE_BODY_WITH_FAILED_STATUS_AND_ERROR_CODE_30034,
MESSAAGE_BODY_WITH_FAILED_STATUS_AND_INVALID_ERROR_CODE,
*TwilioSMSClient.twilio_error_code_map.values(),
TwilioStatus(-1, NOTIFICATION_TECHNICAL_FAILURE, 'Technical error'),
],
ids=[*TwilioSMSClient.twilio_error_code_map.keys(), 'invalid-error-code'],
)
def test_error_code_mapping(event, twilio_sms_client_mock):
translation: SmsStatusRecord = twilio_sms_client_mock.translate_delivery_status(event['message'])
def test_delivery_status_error_code_mapping(
twilio_status: TwilioStatus, twilio_sms_client_mock, sample_twilio_delivery_status
):
_, msg = sample_twilio_delivery_status(twilio_status)
translation: SmsStatusRecord = twilio_sms_client_mock.translate_delivery_status(msg)

assert translation.status == event['twilio_status']
assert translation.status == twilio_status.status
assert translation.status_reason is not None


Expand Down

0 comments on commit e69c34f

Please sign in to comment.