2018-02-07 17:49:15 +00:00
import pytest
2016-07-05 12:37:27 +01:00
from flask import json
2020-03-17 15:15:43 +00:00
from app.notifications.notifications_sms_callback import validate_callback_data
2016-07-05 12:37:27 +01:00
2017-09-26 10:59:09 +01:00
def firetext_post ( client , data ):
return client . post (
path = '/notifications/sms/firetext' ,
data = data ,
headers = [
( 'Content-Type' , 'application/x-www-form-urlencoded' ),
2017-12-01 22:24:53 +00:00
( 'X-Forwarded-For' , '203.0.113.195, 70.41.3.18, 150.172.238.178' ) # fake IPs
2017-09-26 10:59:09 +01:00
])
def mmg_post ( client , data ):
return client . post (
path = '/notifications/sms/mmg' ,
data = data ,
headers = [
( 'Content-Type' , 'application/json' ),
2017-12-01 22:24:53 +00:00
( 'X-Forwarded-For' , '203.0.113.195, 70.41.3.18, 150.172.238.178' ) # fake IPs
2017-09-26 10:59:09 +01:00
])
def dvla_post ( client , data ):
return client . post (
2017-04-25 14:56:16 +01:00
path = '/notifications/letter/dvla' ,
data = data ,
2017-05-15 11:12:31 +01:00
headers = [( 'Content-Type' , 'application/json' )]
)
2017-09-26 10:59:09 +01:00
def test_dvla_callback_returns_400_with_invalid_request ( client ):
data = json . dumps ({ "foo" : "bar" })
response = dvla_post ( client , data )
2017-05-15 11:12:31 +01:00
assert response . status_code == 400
def test_dvla_callback_autoconfirms_subscription ( client , mocker ):
autoconfirm_mock = mocker . patch ( 'app.notifications.notifications_letter_callback.autoconfirm_subscription' )
2017-11-17 14:25:59 +00:00
data = _sns_confirmation_callback ()
2017-09-26 10:59:09 +01:00
response = dvla_post ( client , data )
2017-04-25 14:56:16 +01:00
assert response . status_code == 200
2017-05-15 11:12:31 +01:00
assert autoconfirm_mock . called
def test_dvla_callback_autoconfirm_does_not_call_update_letter_notifications_task ( client , mocker ):
autoconfirm_mock = mocker . patch ( 'app.notifications.notifications_letter_callback.autoconfirm_subscription' )
update_task = \
mocker . patch ( 'app.notifications.notifications_letter_callback.update_letter_notifications_statuses.apply_async' )
2017-11-17 14:25:59 +00:00
data = _sns_confirmation_callback ()
2017-09-26 10:59:09 +01:00
response = dvla_post ( client , data )
2017-05-15 11:12:31 +01:00
assert response . status_code == 200
assert autoconfirm_mock . called
assert not update_task . called
2018-01-15 14:09:46 +00:00
def test_dvla_callback_calls_does_not_update_letter_notifications_task_with_invalid_file_type ( client , mocker ):
2017-05-15 11:12:31 +01:00
update_task = \
mocker . patch ( 'app.notifications.notifications_letter_callback.update_letter_notifications_statuses.apply_async' )
2018-01-15 14:09:46 +00:00
data = _sample_sns_s3_callback ( "bar.txt" )
response = dvla_post ( client , data )
assert response . status_code == 200
assert not update_task . called
2019-03-25 15:30:48 +00:00
@pytest.mark.parametrize ( "filename" ,
[ 'Notify-20170411153023-rs.txt' , 'Notify-20170411153023-rsp.txt' ])
def test_dvla_rs_and_rsp_txt_file_callback_calls_update_letter_notifications_task ( client , mocker , filename ):
update_task = mocker . patch (
'app.notifications.notifications_letter_callback.update_letter_notifications_statuses.apply_async' )
daily_sorted_counts_task = mocker . patch (
'app.notifications.notifications_letter_callback.record_daily_sorted_counts.apply_async' )
data = _sample_sns_s3_callback ( filename )
2017-09-26 10:59:09 +01:00
response = dvla_post ( client , data )
2017-05-15 11:12:31 +01:00
assert response . status_code == 200
assert update_task . called
2019-03-25 15:30:48 +00:00
update_task . assert_called_with ([ filename ], queue = 'notify-internal-tasks' )
daily_sorted_counts_task . assert_called_with ([ filename ], queue = 'notify-internal-tasks' )
2017-05-04 10:33:44 +01:00
2018-01-12 19:24:36 +00:00
def test_dvla_ack_calls_does_not_call_letter_notifications_task ( client , mocker ):
2019-03-25 15:30:48 +00:00
update_task = mocker . patch (
'app.notifications.notifications_letter_callback.update_letter_notifications_statuses.apply_async' )
daily_sorted_counts_task = mocker . patch (
'app.notifications.notifications_letter_callback.record_daily_sorted_counts.apply_async' )
2018-01-15 14:09:46 +00:00
data = _sample_sns_s3_callback ( 'bar.ack.txt' )
2017-09-26 10:59:09 +01:00
response = dvla_post ( client , data )
2017-05-16 10:29:27 +01:00
assert response . status_code == 200
2018-01-12 19:24:36 +00:00
update_task . assert_not_called ()
2019-03-25 15:30:48 +00:00
daily_sorted_counts_task . assert_not_called ()
2017-05-16 10:29:27 +01:00
2017-01-25 14:37:11 +00:00
def test_firetext_callback_should_not_need_auth ( client , mocker ):
2020-03-17 15:15:43 +00:00
mocker . patch ( 'app.notifications.notifications_sms_callback.process_sms_client_response' )
data = 'mobile=441234123123&status=0&reference=notification_id&time=2016-03-10 14:17:00'
2016-07-05 12:37:27 +01:00
2017-09-26 10:59:09 +01:00
response = firetext_post ( client , data )
2017-01-25 14:37:11 +00:00
assert response . status_code == 200
2016-07-05 12:37:27 +01:00
2017-01-25 14:37:11 +00:00
def test_firetext_callback_should_return_400_if_empty_reference ( client , mocker ):
2017-09-26 10:59:09 +01:00
data = 'mobile=441234123123&status=0&reference=&time=2016-03-10 14:17:00'
response = firetext_post ( client , data )
2016-07-05 12:37:27 +01:00
2017-01-25 14:37:11 +00:00
json_resp = json . loads ( response . get_data ( as_text = True ))
assert response . status_code == 400
assert json_resp [ 'result' ] == 'error'
assert json_resp [ 'message' ] == [ 'Firetext callback failed: reference missing' ]
2016-07-05 12:37:27 +01:00
2017-01-25 14:37:11 +00:00
def test_firetext_callback_should_return_400_if_no_reference ( client , mocker ):
2017-09-26 10:59:09 +01:00
data = 'mobile=441234123123&status=0&time=2016-03-10 14:17:00'
response = firetext_post ( client , data )
2017-01-25 14:37:11 +00:00
json_resp = json . loads ( response . get_data ( as_text = True ))
assert response . status_code == 400
assert json_resp [ 'result' ] == 'error'
assert json_resp [ 'message' ] == [ 'Firetext callback failed: reference missing' ]
2016-07-05 12:37:27 +01:00
2017-01-25 14:37:11 +00:00
def test_firetext_callback_should_return_400_if_no_status ( client , mocker ):
2020-03-17 15:15:43 +00:00
data = 'mobile=441234123123&time=2016-03-10 14:17:00&reference=notification_id'
2017-09-26 10:59:09 +01:00
response = firetext_post ( client , data )
2017-01-25 14:37:11 +00:00
json_resp = json . loads ( response . get_data ( as_text = True ))
assert response . status_code == 400
assert json_resp [ 'result' ] == 'error'
assert json_resp [ 'message' ] == [ 'Firetext callback failed: status missing' ]
2016-07-05 12:37:27 +01:00
2020-03-17 15:15:43 +00:00
def test_firetext_callback_should_return_200_and_call_task_with_valid_data ( client , mocker ):
mock_celery = mocker . patch (
'app.notifications.notifications_sms_callback.process_sms_client_response.apply_async' )
2016-07-05 12:37:27 +01:00
2020-03-17 15:15:43 +00:00
data = 'mobile=441234123123&status=0&time=2016-03-10 14:17:00&reference=notification_id'
2017-09-26 10:59:09 +01:00
response = firetext_post ( client , data )
2017-01-25 14:37:11 +00:00
json_resp = json . loads ( response . get_data ( as_text = True ))
assert response . status_code == 200
assert json_resp [ 'result' ] == 'success'
2016-07-05 12:37:27 +01:00
2020-03-17 15:15:43 +00:00
mock_celery . assert_called_once_with (
2020-04-14 15:55:17 +01:00
[ '0' , 'notification_id' , 'Firetext' , None ],
2020-03-17 15:15:43 +00:00
queue = 'sms-callbacks' ,
2017-12-01 20:30:53 +00:00
)
2016-07-05 12:37:27 +01:00
2020-04-16 13:14:29 +01:00
def test_firetext_callback_including_a_code_should_return_200_and_call_task_with_valid_data ( client , mocker ):
mock_celery = mocker . patch (
'app.notifications.notifications_sms_callback.process_sms_client_response.apply_async' )
data = 'mobile=441234123123&status=1&code=101&time=2016-03-10 14:17:00&reference=notification_id'
response = firetext_post ( client , data )
json_resp = json . loads ( response . get_data ( as_text = True ))
assert response . status_code == 200
assert json_resp [ 'result' ] == 'success'
mock_celery . assert_called_once_with (
[ '1' , 'notification_id' , 'Firetext' , '101' ],
queue = 'sms-callbacks' ,
)
2020-03-17 15:15:43 +00:00
def test_mmg_callback_should_not_need_auth ( client , mocker , sample_notification ):
mocker . patch ( 'app.notifications.notifications_sms_callback.process_sms_client_response' )
2017-01-25 14:37:11 +00:00
data = json . dumps ({ "reference" : "mmg_reference" ,
2019-10-31 15:02:30 +00:00
"CID" : str ( sample_notification . id ),
2017-01-25 14:37:11 +00:00
"MSISDN" : "447777349060" ,
"status" : "3" ,
"deliverytime" : "2016-04-05 16:01:07" })
2017-09-26 10:59:09 +01:00
response = mmg_post ( client , data )
2017-01-25 14:37:11 +00:00
assert response . status_code == 200
def test_process_mmg_response_returns_400_for_malformed_data ( client ):
data = json . dumps ({ "reference" : "mmg_reference" ,
"monkey" : 'random thing' ,
"MSISDN" : "447777349060" ,
"no_status" : 00 ,
"deliverytime" : "2016-04-05 16:01:07" })
2017-09-26 10:59:09 +01:00
response = mmg_post ( client , data )
2017-01-25 14:37:11 +00:00
assert response . status_code == 400
json_data = json . loads ( response . data )
assert json_data [ 'result' ] == 'error'
assert len ( json_data [ 'message' ]) == 2
assert " {} callback failed: {} missing" . format ( 'MMG' , 'status' ) in json_data [ 'message' ]
assert " {} callback failed: {} missing" . format ( 'MMG' , 'CID' ) in json_data [ 'message' ]
2020-03-17 15:15:43 +00:00
def test_mmg_callback_should_return_200_and_call_task_with_valid_data ( client , mocker ):
mock_celery = mocker . patch (
'app.notifications.notifications_sms_callback.process_sms_client_response.apply_async' )
data = json . dumps ({ "reference" : "mmg_reference" ,
"CID" : "notification_id" ,
"MSISDN" : "447777349060" ,
"status" : "3" ,
2020-05-27 18:03:55 +01:00
"substatus" : "5" ,
2020-03-17 15:15:43 +00:00
"deliverytime" : "2016-04-05 16:01:07" })
2017-01-25 14:37:11 +00:00
2017-09-26 10:59:09 +01:00
response = mmg_post ( client , data )
2020-03-17 15:15:43 +00:00
2017-01-25 14:37:11 +00:00
assert response . status_code == 200
2020-03-17 15:15:43 +00:00
json_data = json . loads ( response . data )
assert json_data [ 'result' ] == 'success'
mock_celery . assert_called_once_with (
2020-05-27 18:03:55 +01:00
[ '3' , 'notification_id' , 'MMG' , '5' ],
2020-03-17 15:15:43 +00:00
queue = 'sms-callbacks' ,
)
2017-01-25 14:37:11 +00:00
2020-03-17 15:15:43 +00:00
def test_validate_callback_data_returns_none_when_valid ():
form = { 'status' : 'good' ,
'reference' : 'send-sms-code' }
fields = [ 'status' , 'reference' ]
client_name = 'sms client'
2018-02-12 12:06:43 +00:00
2020-03-17 15:15:43 +00:00
assert validate_callback_data ( form , fields , client_name ) is None
2018-02-12 12:06:43 +00:00
2020-03-17 15:15:43 +00:00
def test_validate_callback_data_return_errors_when_fields_are_empty ():
form = { 'monkey' : 'good' }
fields = [ 'status' , 'cid' ]
client_name = 'sms client'
2017-01-25 14:37:11 +00:00
2020-03-17 15:15:43 +00:00
errors = validate_callback_data ( form , fields , client_name )
assert len ( errors ) == 2
assert " {} callback failed: {} missing" . format ( client_name , 'status' ) in errors
assert " {} callback failed: {} missing" . format ( client_name , 'cid' ) in errors
2016-07-05 12:37:27 +01:00
2020-03-17 15:15:43 +00:00
def test_validate_callback_data_can_handle_integers ():
form = { 'status' : 00 , 'cid' : 'fsdfadfsdfas' }
fields = [ 'status' , 'cid' ]
client_name = 'sms client'
2017-01-25 14:37:11 +00:00
2020-03-17 15:15:43 +00:00
result = validate_callback_data ( form , fields , client_name )
assert result is None
2016-09-13 13:57:06 +01:00
2016-07-05 12:37:27 +01:00
2020-03-17 15:15:43 +00:00
def test_validate_callback_data_returns_error_for_empty_string ():
form = { 'status' : '' , 'cid' : 'fsdfadfsdfas' }
fields = [ 'status' , 'cid' ]
client_name = 'sms client'
result = validate_callback_data ( form , fields , client_name )
assert result is not None
assert " {} callback failed: {} missing" . format ( client_name , 'status' ) in result
2016-07-05 12:37:27 +01:00
2018-01-15 14:09:46 +00:00
def _sample_sns_s3_callback ( filename ):
message_contents = '''{"Records":[{"eventVersion":"2.0","eventSource":"aws:s3","awsRegion":"eu-west-1","eventTime":"2017-05-16T11:38:41.073Z","eventName":"ObjectCreated:Put","userIdentity":{"principalId":"some-p-id"},"requestParameters":{"sourceIPAddress":"8.8.8.8"},"responseElements":{"x-amz-request-id":"some-r-id","x-amz-id-2":"some-x-am-id"},"s3":{"s3SchemaVersion":"1.0","configurationId":"some-c-id","bucket":{"name":"some-bucket","ownerIdentity":{"principalId":"some-p-id"},"arn":"some-bucket-arn"},
"object":{"key":" %s "}}}]}''' % ( filename ) # noqa
2017-05-15 11:12:31 +01:00
return json . dumps ({
"SigningCertURL" : "foo.pem" ,
"UnsubscribeURL" : "bar" ,
"Signature" : "some-signature" ,
"Type" : "Notification" ,
"Timestamp" : "2016-05-03T08:35:12.884Z" ,
"SignatureVersion" : "1" ,
"MessageId" : "6adbfe0a-d610-509a-9c47-af894e90d32d" ,
"Subject" : "Amazon S3 Notification" ,
"TopicArn" : "sample-topic-arn" ,
2018-01-15 14:09:46 +00:00
"Message" : message_contents
2018-01-12 16:10:09 +00:00
})
2017-11-17 14:25:59 +00:00
def _sns_confirmation_callback ():
return b '{ \n "Type": "SubscriptionConfirmation", \n "MessageId": "165545c9-2a5c-472c-8df2-7ff2be2b3b1b", \n "Token": "2336412f37fb687f5d51e6e241d09c805a5a57b30d712f794cc5f6a988666d92768dd60a747ba6f3beb71854e285d6ad02428b09ceece29417f1f02d609c582afbacc99c583a916b9981dd2728f4ae6fdb82efd087cc3b7849e05798d2d2785c03b0879594eeac82c01f235d0e717736", \n "TopicArn": "arn:aws:sns:us-west-2:123456789012:MyTopic", \n "Message": "You have chosen to subscribe to the topic arn:aws:sns:us-west-2:123456789012:MyTopic. \\ nTo confirm the subscription, visit the SubscribeURL included in this message.", \n "SubscribeURL": "https://sns.us-west-2.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:us-west-2:123456789012:MyTopic&Token=2336412f37fb687f5d51e6e241d09c805a5a57b30d712f794cc5f6a988666d92768dd60a747ba6f3beb71854e285d6ad02428b09ceece29417f1f02d609c582afbacc99c583a916b9981dd2728f4ae6fdb82efd087cc3b7849e05798d2d2785c03b0879594eeac82c01f235d0e717736", \n "Timestamp": "2012-04-26T20:45:04.751Z", \n "SignatureVersion": "1", \n "Signature": "EXAMPLEpH+DcEwjAPg8O9mY8dReBSwksfg2S7WKQcikcNKWLQjwu6A4VbeS0QHVCkhRS7fUQvi2egU3N858fiTDN6bkkOxYDVrY0Ad8L10Hs3zH81mtnPk5uvvolIC1CXGu43obcgFxeL3khZl8IKvO61GWB6jI9b5+gLPoBc1Q=", \n "SigningCertURL": "https://sns.us-west-2.amazonaws.com/SimpleNotificationService-f3ecfb7224c7233fe7bb5f59f96de52f.pem" \n }' # noqa