sms: send SMS asynchronously (#21465)

This commit is contained in:
Nicolas Roche 2020-04-26 15:54:47 +02:00
parent b9048993be
commit 115b0bb78c
4 changed files with 60 additions and 20 deletions

View File

@ -77,10 +77,14 @@ class SMSResource(BaseResource):
data['to'] = self.clean_numbers(data['to'])
logging.info('sending SMS to %r from %r', data['to'], data['from'])
stop = not bool('nostop' in request.GET)
# unfortunately it lacks a batch API...
result = {'data': self.send_msg(data['message'], data['from'], data['to'], stop=stop)}
self.add_job('send_job',
text=data['message'], sender=data['from'], destinations=data['to'],
stop=stop)
return {'err': 0}
def send_job(self, *args, **kwargs):
self.send_msg(**kwargs)
SMSLog.objects.create(appname=self.get_connector_slug(), slug=self.slug)
return result
class Meta:
abstract = True

View File

@ -24,7 +24,8 @@ from django.contrib.contenttypes.models import ContentType
from django.utils.encoding import force_text
from passerelle.apps.orange.models import OrangeSMSGateway, OrangeError
from passerelle.base.models import ApiUser, AccessRight
from passerelle.base.models import ApiUser, AccessRight, Job
from passerelle.utils.jsonresponse import APIError
@ -163,13 +164,20 @@ def test_diffusion(app, connector):
def test_send_msg(app, connector):
url = '/%s/%s/send/' % (connector.get_connector_slug(), connector.slug)
with httmock.HTTMock(response_token_ok, response_group_ok, response_diffusion_ok):
resp = app.post_json(url, params=PAYLOAD, status=200)
assert Job.objects.count() == 0
resp = app.post_json(url, params=PAYLOAD, status=200)
assert not resp.json['err']
assert resp.json['data']['status'] == "I'm ok"
assert Job.objects.count() == 1
with httmock.HTTMock(response_token_ok, response_group_ok, response_diffusion_ok):
connector.jobs()
assert Job.objects.all()[0].status == 'completed'
# not 201
resp = app.post_json(url, params=PAYLOAD, status=200)
assert not resp.json['err']
assert Job.objects.count() == 2
with httmock.HTTMock(response_token_ok, response_group_ok, response_500):
resp = app.post_json(url, params=PAYLOAD, status=200)
assert resp.json['err']
assert resp.json['err_desc'] == 'Orange fails to send SMS: 500, my_error'
connector.jobs()
job = Job.objects.all()[1]
assert job.status == 'failed'
assert 'Orange fails to send SMS: 500, my_error' in job.status_details['error_summary']

View File

@ -1,10 +1,12 @@
import isodate
import mock
import pytest
from requests import RequestException
from django.contrib.contenttypes.models import ContentType
from passerelle.apps.ovh.models import OVHSMSGateway
from passerelle.base.models import ApiUser, AccessRight
from passerelle.base.models import ApiUser, AccessRight, Job
from passerelle.sms.models import SMSResource, SMSLog
from passerelle.utils.jsonresponse import APIError
@ -52,7 +54,7 @@ def connector(request, db):
return c
def test_connectors(app, connector):
def test_connectors(app, connector, freezer):
path = '/%s/%s/send/' % (connector.get_connector_slug(), connector.slug)
result = app.post_json(path, params={})
assert result.json['err'] == 1
@ -63,12 +65,34 @@ def test_connectors(app, connector):
'from': '+33699999999',
'to': ['+33688888888', '+33677777777'],
}
for test_vector in getattr(connector, 'TEST_DEFAULTS', {}).get('test_vectors', []):
with utils.mock_url(connector.URL, test_vector['response']):
result = app.post_json(path, params=payload)
for key, value in test_vector['result'].items():
assert key in result.json
assert result.json[key] == value
test_vectors = getattr(connector, 'TEST_DEFAULTS', {}).get('test_vectors', [])
total = len(test_vectors)
nb_failed = 0
assert Job.objects.count() == 0
for test_vector in test_vectors:
# register job
freezer.move_to('2019-01-01 00:00:00')
result = app.post_json(path, params=payload)
assert result.json['err'] == 0
job_id = Job.objects.get(status='registered').id
# perform job
freezer.move_to('2019-01-01 01:00:03')
with utils.mock_url(
connector.URL,
test_vector.get('response', ''),
test_vector.get('status_code', 200)):
connector.jobs()
job = Job.objects.get(id=job_id)
if job.status == 'failed':
assert len(job.status_details['error_summary']) > 0
assert test_vector['result']['err_desc'] in job.status_details['error_summary']
nb_failed += 1
else:
assert job.status == 'completed'
assert Job.objects.count() == total
assert SMSLog.objects.count() == total - nb_failed
def test_manage_views(admin_user, app, connector):
@ -95,7 +119,8 @@ def test_sms_max_message_length(app, connector):
with mock.patch.object(OVHSMSGateway, 'send_msg') as send_function:
send_function.return_value = {}
result = app.post_json(path, params=payload)
assert send_function.call_args[0][0] == 'a' * connector.max_message_length
connector.jobs()
assert send_function.call_args[1]['text'] == 'a' * connector.max_message_length
@pytest.mark.parametrize('connector', [OVHSMSGateway], indirect=True)
@ -111,4 +136,5 @@ def test_sms_log(app, connector):
with mock.patch.object(OVHSMSGateway, 'send_msg') as send_function:
send_function.return_value = {}
result = app.post_json(path, params=payload)
connector.jobs()
assert SMSLog.objects.filter(appname=connector.get_connector_slug(), slug=connector.slug).exists()

View File

@ -32,7 +32,7 @@ class FakedResponse(mock.Mock):
return json_loads(self.content)
def mock_url(url=None, response='', status_code=200, headers=None):
def mock_url(url=None, response='', status_code=200, headers=None, exception=None):
urlmatch_kwargs = {}
if url:
parsed = urlparse.urlparse(url)
@ -46,6 +46,8 @@ def mock_url(url=None, response='', status_code=200, headers=None):
@httmock.urlmatch(**urlmatch_kwargs)
def mocked(url, request):
if exception:
raise exception
return httmock.response(status_code, response, headers, request=request)
return httmock.HTTMock(mocked)