def test_make_firetext_callback(notify_api, rmock, phone_number): endpoint = "http://localhost:6011/notifications/sms/firetext" rmock.request("POST", endpoint, json="some data", status_code=200) send_sms_response("firetext", "1234", phone_number) assert rmock.called assert rmock.request_history[0].url == endpoint assert 'mobile={}'.format(phone_number) in rmock.request_history[0].text
def test_make_twilio_callback(notify_api, rmock, phone_number): notification_id = "1234" endpoint = f"http://localhost:6011/notifications/sms/twilio/{notification_id}" rmock.request("POST", endpoint, json="some data", status_code=200) send_sms_response("twilio", notification_id, phone_number) assert rmock.called assert rmock.request_history[0].url == endpoint assert f'To={phone_number}' in rmock.request_history[0].text
def send_sms_to_provider(notification): service = notification.service if not service.active: technical_failure(notification=notification) return if notification.status == 'created': provider = provider_to_use(SMS_TYPE, notification.international) template_model = dao_get_template_by_id(notification.template_id, notification.template_version) template = SMSMessageTemplate( template_model.__dict__, values=notification.personalisation, prefix=service.name, show_prefix=service.prefix_sms, ) if service.research_mode or notification.key_type == KEY_TYPE_TEST: update_notification_to_sending(notification, provider) send_sms_response(provider.get_name(), str(notification.id), notification.to) else: try: provider.send_sms(to=validate_and_format_phone_number( notification.to, international=notification.international), content=str(template), reference=str(notification.id), sender=notification.reply_to_text) except Exception as e: notification.billable_units = template.fragment_count dao_update_notification(notification) dao_reduce_sms_provider_priority( provider.get_name(), time_threshold=timedelta(minutes=1)) raise e else: notification.billable_units = template.fragment_count update_notification_to_sending(notification, provider) delta_seconds = (datetime.utcnow() - notification.created_at).total_seconds() statsd_client.timing("sms.total-time", delta_seconds) if notification.key_type == KEY_TYPE_TEST: statsd_client.timing("sms.test-key.total-time", delta_seconds) else: statsd_client.timing("sms.live-key.total-time", delta_seconds) if str(service.id) in current_app.config.get( 'HIGH_VOLUME_SERVICE'): statsd_client.timing("sms.live-key.high-volume.total-time", delta_seconds) else: statsd_client.timing("sms.live-key.not-high-volume.total-time", delta_seconds)
def send_sms_to_provider(notification): service = notification.service if not service.active: technical_failure(notification=notification) return if notification.status == 'created': provider = provider_to_use(SMS_TYPE, notification.id, notification.international) current_app.logger.debug( "Starting sending SMS {} to provider at {}".format( notification.id, datetime.utcnow())) template_model = dao_get_template_by_id(notification.template_id, notification.template_version) template = SMSMessageTemplate( template_model.__dict__, values=notification.personalisation, prefix=service.name, show_prefix=service.prefix_sms, ) if service.research_mode or notification.key_type == KEY_TYPE_TEST: notification.billable_units = 0 update_notification(notification, provider) try: send_sms_response(provider.get_name(), str(notification.id), notification.to) except HTTPError: # when we retry, we only do anything if the notification is in created - it's currently in sending, # so set it back so that we actually attempt the callback again notification.sent_at = None notification.sent_by = None notification.status = NOTIFICATION_CREATED dao_update_notification(notification) raise else: try: provider.send_sms(to=validate_and_format_phone_number( notification.to, international=notification.international), content=str(template), reference=str(notification.id), sender=notification.reply_to_text) except Exception as e: dao_toggle_sms_provider(provider.name) raise e else: notification.billable_units = template.fragment_count update_notification(notification, provider, notification.international) current_app.logger.debug("SMS {} sent to provider {} at {}".format( notification.id, provider.get_name(), notification.sent_at)) delta_milliseconds = (datetime.utcnow() - notification.created_at).total_seconds() * 1000 statsd_client.timing("sms.total-time", delta_milliseconds)
def test_make_mmg_callback(notify_api, rmock): endpoint = "http://localhost:6011/notifications/sms/mmg" rmock.request("POST", endpoint, json={"status": "success"}, status_code=200) send_sms_response("mmg", "1234", "07700900001") assert rmock.called assert rmock.request_history[0].url == endpoint assert json.loads(rmock.request_history[0].text)['MSISDN'] == '07700900001'
def test_make_sns_callback(notify_api, rmock): notification_id = "1234" reference = "5678" endpoint = f"http://localhost:6011/notifications/sms/sns" rmock.post(endpoint, json={}, status_code=204) send_sms_response("sns", notification_id, "+16665554444", reference) assert rmock.called assert rmock.request_history[0].url == endpoint assert json.loads(rmock.request_history[0].text )['notification']['messageId'] == reference
def test_make_firetext_callback(notify_api, rmock): endpoint = "http://localhost:6011/notifications/sms/firetext" rmock.request( "POST", endpoint, json="some data", status_code=200) send_sms_response("firetext", "1234", "07811111111") assert rmock.called assert rmock.request_history[0].url == endpoint assert 'mobile=07811111111' in rmock.request_history[0].text
def test_make_mmg_callback(notify_api, rmock): endpoint = "http://localhost:6011/notifications/sms/mmg" rmock.request( "POST", endpoint, json={"status": "success"}, status_code=200) send_sms_response("mmg", "1234", "07811111111") assert rmock.called assert rmock.request_history[0].url == endpoint assert json.loads(rmock.request_history[0].text)['MSISDN'] == '07811111111'
def test_make_sns_success_callback(notify_api, mocker, phone_number, sns_callback, sns_callback_args): mock_task = mocker.patch("app.celery.research_mode_tasks.process_sns_results") some_ref = str(uuid.uuid4()) now = datetime.now() timestamp = now.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3] send_sms_response("sns", phone_number, some_ref) mock_task.apply_async.assert_called_once_with(ANY, queue=QueueNames.RESEARCH_MODE) message_celery = mock_task.apply_async.call_args[0][0][0] sns_callback_args.update({"reference": some_ref, "destination": phone_number, "timestamp": timestamp}) assert message_celery == sns_callback(**sns_callback_args)
def send_sms_to_provider(notification): service = notification.service if not service.active: technical_failure(notification=notification) return if notification.status == 'created': provider = provider_to_use(SMS_TYPE, notification, notification.international) template_model = dao_get_template_by_id(notification.template_id, notification.template_version) template = SMSMessageTemplate( template_model.__dict__, values=notification.personalisation, prefix=service.name, show_prefix=service.prefix_sms, ) if service.research_mode or notification.key_type == KEY_TYPE_TEST: notification.reference = create_uuid() update_notification_to_sending(notification, provider) send_sms_response(provider.get_name(), str(notification.id), notification.to, notification.reference) else: try: reference = provider.send_sms( to=validate_and_format_phone_number( notification.to, international=notification.international), content=str(template), reference=str(notification.id), sender=notification.reply_to_text) except Exception as e: notification.billable_units = template.fragment_count dao_update_notification(notification) dao_toggle_sms_provider(provider.name) raise e else: notification.billable_units = template.fragment_count notification.reference = reference update_notification_to_sending(notification, provider) current_app.logger.info( f"Saved provider reference: {reference} for notification id: {notification.id}" ) delta_milliseconds = (datetime.utcnow() - notification.created_at).total_seconds() * 1000 statsd_client.timing("sms.total-time", delta_milliseconds)
def test_callback_logs_on_api_call_failure(notify_api, rmock, mocker): endpoint = "http://localhost:6011/notifications/sms/mmg" rmock.request( "POST", endpoint, json={"error": "something went wrong"}, status_code=500) mock_logger = mocker.patch('app.celery.tasks.current_app.logger.error') with pytest.raises(HTTPError): send_sms_response("mmg", "1234", "07700900001") assert rmock.called assert rmock.request_history[0].url == endpoint mock_logger.assert_called_once_with( 'API POST request on http://localhost:6011/notifications/sms/mmg failed with status 500' )
def send_sms_to_provider(notification): service = notification.service if not service.active: technical_failure(notification=notification) return if notification.status == "created": provider = provider_to_use( SMS_TYPE, notification.id, notification.international, notification.reply_to_text, ) template_dict = dao_get_template_by_id( notification.template_id, notification.template_version).__dict__ template = SMSMessageTemplate( template_dict, values=notification.personalisation, prefix=service.name, show_prefix=service.prefix_sms, ) if service.research_mode or notification.key_type == KEY_TYPE_TEST: notification.reference = send_sms_response(provider.get_name(), notification.to) update_notification_to_sending(notification, provider) else: try: reference = provider.send_sms( to=validate_and_format_phone_number( notification.to, international=notification.international), content=str(template), reference=str(notification.id), sender=notification.reply_to_text, ) except Exception as e: notification.billable_units = template.fragment_count dao_update_notification(notification) dao_toggle_sms_provider(provider.name) raise e else: notification.reference = reference notification.billable_units = template.fragment_count update_notification_to_sending(notification, provider) # Record StatsD stats to compute SLOs statsd_client.timing_with_dates("sms.total-time", notification.sent_at, notification.created_at) statsd_key = f"sms.process_type-{template_dict['process_type']}" statsd_client.timing_with_dates(statsd_key, notification.sent_at, notification.created_at) statsd_client.incr(statsd_key)
def send_sms_to_provider(notification): service = notification.service if not service.active: technical_failure(notification=notification) return if notification.status == 'created': # TODO: issue is that this does not get the provider based on who owns # the inbound number. The notification.reply_to_text below is the phone # number that we should send from, but we need to look at that and see # who the provider is. # TODO: now that we do get the right provider, the issue is that the # reply to text could be different because the service is able to choose # the sender when sending a message. So we need to check if the sender # ID that was chosen is also an inbound number. provider = None preferred_provider = get_preferred_sms_provider(service) if preferred_provider: provider = get_sms_provider_client(preferred_provider, notification.id) else: provider = provider_to_use(SMS_TYPE, notification.id, notification.international) current_app.logger.debug( "Starting sending SMS {} to provider at {}".format( notification.id, datetime.utcnow())) template_model = dao_get_template_by_id(notification.template_id, notification.template_version) template = SMSMessageTemplate( template_model.__dict__, values=notification.personalisation, prefix=service.name, show_prefix=service.prefix_sms, ) if service.research_mode or notification.key_type == KEY_TYPE_TEST: notification.billable_units = 0 update_notification(notification, provider) try: send_sms_response(provider.get_name(), str(notification.id), notification.to) except HTTPError: # when we retry, we only do anything if the notification is in created - it's currently in sending, # so set it back so that we actually attempt the callback again notification.sent_at = None notification.sent_by = None notification.status = NOTIFICATION_CREATED dao_update_notification(notification) raise else: status = None try: reference, status = provider.send_sms( to=notification.normalised_to, content=str(template), reference=str(notification.id), sender=notification.reply_to_text) notification.reference = reference notification.billable_units = template.fragment_count # An international notification (i.e. a text message with an # abroad recipient phone number) instantly get marked as "sent". # It might later get marked as "delivered" when the provider # status callback is triggered. if notification.international: status = NOTIFICATION_SENT except Exception as e: dao_toggle_sms_provider(provider.name) raise e else: update_notification(notification, provider, status=status) current_app.logger.debug("SMS {} sent to provider {} at {}".format( notification.id, provider.get_name(), notification.sent_at)) delta_milliseconds = (datetime.utcnow() - notification.created_at).total_seconds() * 1000 statsd_client.timing("sms.total-time", delta_milliseconds)