def test_jsonex(self): """ Test de/coding messages """ ### OutgoingMessage om_in = OutgoingMessage('+123', 'Test', '+987', 'fwd') om_in.options(allow_reply=True) # Encode, Decode j = jsonex_dumps(om_in) om_out = jsonex_loads(j) """ :type om_out: OutgoingMessage """ # Check self.assertEqual(om_out.dst, '123') self.assertEqual(om_out.src, om_in.src) self.assertEqual(om_out.body, om_in.body) self.assertEqual(om_out.provider, om_in.provider) self.assertEqual(om_out.meta, None) self.assertEqual(om_out.provider_options.allow_reply, om_in.provider_options.allow_reply) self.assertEqual(om_out.provider_params, {}) ### IncomingMessage im_in = IncomingMessage('+123', 'Test', 'abc123def', '+987', datetime(2019,1,1,15,0,0,875), {'a':1}) # Encode, Decode j = jsonex_dumps(im_in) im_out = jsonex_loads(j) """ :type im_out: IncomingMessage """ # Check self.assertEqual(im_out.src, im_in.src) self.assertEqual(im_out.body, im_in.body) self.assertEqual(im_out.msgid, im_in.msgid) self.assertEqual(im_out.dst, im_in.dst) self.assertEqual(im_out.rtime, im_in.rtime) self.assertEqual(im_out.meta, im_in.meta)
def test_jsonex(self): """ Test de/coding messages """ ### OutgoingMessage om_in = OutgoingMessage('+123', 'Test', '+987', 'fwd') om_in.options(allow_reply=True) # Encode, Decode j = jsonex_dumps(om_in) om_out = jsonex_loads(j) """ :type om_out: OutgoingMessage """ # Check self.assertEqual(om_out.dst, '123') self.assertEqual(om_out.src, om_in.src) self.assertEqual(om_out.body, om_in.body) self.assertEqual(om_out.provider, om_in.provider) self.assertEqual(om_out.meta, None) self.assertEqual(om_out.provider_options.allow_reply, om_in.provider_options.allow_reply) self.assertEqual(om_out.provider_params, {}) ### IncomingMessage im_in = IncomingMessage('+123', 'Test', 'abc123def', '+987', datetime(2019, 1, 1, 15, 0, 0, 875), {'a': 1}) # Encode, Decode j = jsonex_dumps(im_in) im_out = jsonex_loads(j) """ :type im_out: IncomingMessage """ # Check self.assertEqual(im_out.src, im_in.src) self.assertEqual(im_out.body, im_in.body) self.assertEqual(im_out.msgid, im_in.msgid) self.assertEqual(im_out.dst, im_in.dst) self.assertEqual(im_out.rtime, im_in.rtime) self.assertEqual(im_out.meta, im_in.meta)
def test_senderId(self): gw = self.gw self._mock_response(200) # OK message = OutgoingMessage('+123456', 'hey', provider='main') message.options(senderId='Fake sender') gw.send(message) request = self.requests.pop() self.assertEqual('Fake sender', request['SND'])
def test_send(self): """ Test message send """ gw = self.gw # OK self._mock_response(200) message = OutgoingMessage('+123456', 'hey', provider='main') message = gw.send(message) self.assertEqual(message.msgid, None) # Should fail with E001 self._mock_response(500) self.assertRaises(error.E001, gw.send, OutgoingMessage('+123456', 'hey', provider='main'))
def test_error_send(self): """ Test message send """ gw = self.gw bad_json = { 'msg': 'Required parameter has format error', 'code': 2, 'detail': 'Format the parameter by prompt.' } responses.add( responses.POST, 'https://sms.yunpian.com/v2/sms/single_send.json', json=bad_json, status=200, ) try: message = gw.send( OutgoingMessage('+123456', 'hey', src='dignio', provider='main')) assert False except Exception as e: self.assertIn('2 Required parameter has format error', str(e)) self.assertEqual(len(responses.calls), 1) self.assertIn('my_api_key1234', responses.calls[0].request.body)
def test_events(self): """ Test events """ # Counters self.recv = 0 self.send = 0 self.status = 0 def inc_recv(message): self.recv += 1 def inc_send(message): self.send += 1 def inc_status(message): self.status += 1 # Hooks self.gw.onReceive += inc_recv self.gw.onSend += inc_send self.gw.onStatus += inc_status # Emit some events provider = self.gw.get_provider('one') self.gw.send(OutgoingMessage('', '')) provider._receive_message(IncomingMessage('', '')) provider._receive_status(MessageStatus('')) # Check self.assertEqual(self.recv, 1) self.assertEqual(self.send, 1) self.assertEqual(self.status, 1)
def testSend(self): """ Send messages """ # Send a message om = OutgoingMessage( '+1234', 'Hi man!').options(senderId='me').params(a=1).route(1, 2, 3) rom = self.gw_client.send(om) # Check traffic traffic = self.lo.get_traffic() self.assertEqual(len(traffic), 1) tom = traffic.pop() for m in (om, rom, tom): self.assertEqual(m.src, None) self.assertEqual(m.dst, '1234') self.assertEqual(m.body, 'Hi man!') self.assertEqual(m.provider, 'lo') # Remote provider should be exposed self.assertEqual(m.provider_options.senderId, 'me') self.assertEqual(m.provider_params, {'a': 1}) self.assertEqual(m.routing_values, [1, 2, 3]) self.assertEqual(m.msgid, '1') self.assertEqual(m.meta, None)
def test_send_success(self): """Test a successful AfricasTalking SMS send""" message_out = OutgoingMessage( '+254789789789', 'Hello Kenya', provider='africas_talking').params(target_country='KE') message_back = self.gw.send(message_out) self.assertEqual(message_back.msgid, '001')
def test_send_failure(self): """Test a failing AfricasTalking SMS send""" message_out = OutgoingMessage( '+254789789789', 'Hello Kenya', provider='africas_talking').params(target_country='KE') self.assertRaises(AfricasTalkingProviderError, self.gw.send, message_out)
def testStatus(self): """ Receive statuses """ # Status receiver statuses = [] def onStatus(status): statuses.append(status) self.gw_client.onStatus += onStatus # Subscriber incoming = [] def subscriber(message): incoming.append(message) self.lo.subscribe('1234', subscriber) # Send a message, request status report om = OutgoingMessage('+1234', 'Hi man!').options(status_report=True) rom = self.gw_client.send(om) # Check self.assertEqual(len(statuses), 1) status = statuses.pop() ':type: MessageStatus' self.assertEqual(status.msgid, '1') self.assertIsInstance(status.rtime, datetime) self.assertEqual(status.provider, 'lo') self.assertEqual(status.accepted, True) self.assertEqual(status.delivered, True) self.assertEqual(status.expired, False) self.assertEqual(status.error, False) self.assertEqual(status.status_code, None) self.assertEqual(status.status, 'OK') self.assertEqual(status.meta, {})
def test_send(self): """ Test message send """ gw = self.gw ok_json = { 'code': 0, 'msg': 'OK', 'count': 1, 'fee': 0.05, 'unit': 'RMB', 'mobile': '123456', 'sid': 16741236146 } responses.add( responses.POST, 'https://sms.yunpian.com/v2/sms/single_send.json', json=ok_json, status=200, ) message = gw.send( OutgoingMessage('+123456', 'hey', src='dignio', provider='main')) self.assertEqual(len(responses.calls), 1) self.assertIn('my_api_key1234', responses.calls[0].request.body) self.assertIn('Google', responses.calls[0].request.body) self.assertEqual(message.msgid, 16741236146)
def test_missing_number(self): """ Send to a missing number """ msg = self.gw.send(OutgoingMessage('+0', 'you there?')) self.assertListEqual(self.provider.get_traffic(), [msg]) # traffic works self.assertListEqual(self.events_log, [msg]) self.assertEqual(self.subscriber_log, []) # no log as there was no subscriber
def testServerError(self): """ Test how errors are transferred from the server """ # Erroneous subscribers def tired_subscriber(message): raise OverflowError('Tired') self.lo.subscribe('1234', tired_subscriber) def offline_subscriber(message): raise exc.ServerError('Offline') self.lo.subscribe('5678', offline_subscriber) # Send: 1 om = OutgoingMessage('+1234', 'Hi man!') self.assertRaises(RuntimeError, self.gw_client.send, om) # Unknown error classes are converted to RuntimeError # Send: 2 om = OutgoingMessage('+5678', 'Hi man!') self.assertRaises(exc.ServerError, self.gw_client.send, om) # Known errors: as is
def test_gsm7_encoding_invalid_character(self): message = OutgoingMessage('+123456', u'Vamos a aprender chino \u73a9.', provider='main') self._mock_response(200) self.gw.send(message) self.assertIn('is_hex', message.provider_params) request = self.requests.pop() self.assertEqual(CT_UCS2, request['CT']) message = OutgoingMessage('+123456', u'\u05de\u05d4 \u05e7\u05d5\u05e8\u05d4?', provider='main') self._mock_response(200) self.gw.send(message) request = self.requests.pop() self.assertEquals(CT_UCS2, request['CT']) self.assertEquals(b'05de05d4002005e705d505e805d4003f', request['HEX'])
def test_subscriber3_noreply(self): """ Test replying subscriber with disabled replies """ msg = self.gw.send( OutgoingMessage('3', 'hi!').options(status_report=True, allow_reply=False)) self.assertListEqual(self.provider.get_traffic(), [msg]) self.assertEqual(len(self.events_log), 2) self.assertIsInstance(self.events_log[0], MessageDelivered) # delivered self.assertIs(self.events_log[1], msg) self.assertEqual(self.subscriber_log, ['3:None:hi!'])
def test_routing(self): """ Test routing """ # Sends through 'one' msg = self.gw.send(OutgoingMessage('', '').route('main', '')) self.assertEqual(msg.provider, 'one') # Sends through 'two' msg = self.gw.send(OutgoingMessage('', '').route('', 'alarm')) self.assertEqual(msg.provider, 'two') # Sends through 'three' msg = self.gw.send(OutgoingMessage('', '').route('', '')) self.assertEqual(msg.provider, 'three') # Send through 'one' (explicitly set) msg = self.gw.send( OutgoingMessage('', '', provider='one').route('', '')) self.assertEqual(msg.provider, 'one') # No routing specified: using the default route msg = self.gw.send(OutgoingMessage('', '', provider='one')) self.assertEqual(msg.provider, 'one') # Wrong provider specified self.assertRaises(AssertionError, self.gw.send, OutgoingMessage('', '', provider='zzz'))
def test_send_message(self): """ Test outgoing message """ # 1. Simple message with self._stubber() as st: st.add_response('publish', expected_params={ 'PhoneNumber': '+1999', 'Message': 'test 1', 'MessageAttributes': {} }, service_response={'MessageId': '1'}) self.assertEqual( '1', self.gw.send(OutgoingMessage('+1999', 'test 1')).msgid) # 2. Transactional message with self._stubber() as st: # 2. Transactional message with SenderId st.add_response('publish', expected_params={ 'PhoneNumber': '+1999', 'Message': 'test 2', 'MessageAttributes': { 'AWS.SNS.SMS.SenderID': { 'DataType': 'String', 'StringValue': 'kolypto' }, 'AWS.SNS.SMS.SMSType': { 'DataType': 'String', 'StringValue': 'Transactional' }, } }, service_response={'MessageId': '2'}) self.assertEqual( '2', self.gw.send( OutgoingMessage('+1999', 'test 2').options(senderId='kolypto', escalate=True)).msgid)
def test_subscriber1(self): """ Test delivering a message to a subscriber """ msg = self.gw.send( OutgoingMessage('+1', 'hi!').options(status_report=True)) self.assertListEqual(self.provider.get_traffic(), [msg]) self.assertEqual(len(self.events_log), 2) self.assertIsInstance(self.events_log[0], MessageDelivered) # delivered self.assertSetEqual(self.events_log[0].states, {'accepted', 'delivered'}) self.assertIs(self.events_log[1], msg) self.assertEqual(self.subscriber_log, ['1:None:hi!'])
def test_missing_number_status(self): """ Send to a missing number with status report request """ msg = self.gw.send( OutgoingMessage('+0', 'you there?').options(status_report=True)) self.assertListEqual(self.provider.get_traffic(), [msg]) # traffic works self.assertEqual(len(self.events_log), 2) self.assertIsInstance(self.events_log[0], MessageAccepted) # accepted, but not delivered self.assertSetEqual(self.events_log[0].states, {'accepted'}) self.assertIs(self.events_log[1], msg) self.assertEqual(self.subscriber_log, []) # no log as there was no subscriber
def test_gsm7_valid_characters(self): self._mock_response(200) sent_message = self.gw.send( OutgoingMessage('+654321', u'Æ E A Å Edø.', provider='main')) self.assertNotIn('is_hex', sent_message.provider_params) request_1 = self.requests.pop() self.assertEquals(b'\xc6 E A \xc5 Ed\xf8.', request_1['TXT']) self._mock_response(200) sent_message_2 = self.gw.send( OutgoingMessage( '+654321', u'RaLejaLe hemmat i høssølæssom å naumøLa spikkjipørse.', provider='main')) # The modified OutgoingMessage will be returned in the http response. # Ensure that OutgoingMessage.body can still be jsonified: sent_message_2.body.encode('utf-8') request_2 = self.requests.pop() self.assertEquals(CT_PLAIN_TEXT, request_2['CT']) self.assertEquals( b'RaLejaLe hemmat i h\xf8ss\xf8l\xe6ssom \xe5 naum\xf8La spikkjip\xf8rse.', request_2['TXT']) self._mock_response(200) sent_message_3 = self.gw.send( OutgoingMessage( '+654321', u'Ñoño Yáñez come ñame en las mañanas con el niño.', provider='main')) self.assertNotIn('is_hex', sent_message_3.provider_params) request_3 = self.requests.pop() self.assertEquals( b'\xd1o\xf1o Y\xe1\xf1ez come \xf1ame en las ma\xf1anas con el ni\xf1o.', request_3['TXT'])
def test_subscriber3(self): """ Test replying subscriber """ msg = self.gw.send(OutgoingMessage('++3', 'hi!').options()) traffic = self.provider.get_traffic() self.assertIs(traffic[0], msg) self.assertIsInstance(traffic[1], IncomingMessage) self.assertEqual(traffic[1].src, '3') self.assertEqual(traffic[1].dst, None) self.assertEqual(traffic[1].body, 'hello') self.assertEqual(len(self.events_log), 2) self.assertIs( self.events_log[1], msg) # onSend is only emitted once the Provider has finished self.assertEqual(self.events_log[0].body, 'hello') # the reply self.assertEqual(self.subscriber_log, ['3:None:hi!'])
def test_send(self): """ Test send SMS """ with Mocker() as m: m.post( 'https://studio.twilio.com/v1/Flows/sid/Executions', request_headers={ 'Authorization': 'Basic ZGFnOnNlY3JldA==', # dag:secret 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', }, status_code=200, headers={}, json={ 'url': 'https://studio.twilio.com/v1/Flows/sid/Executions/FN0000', # ... many more fields. See: https://www.twilio.com/docs/studio/rest-api/execution }) om = self.gw.send(OutgoingMessage('+1999', 'Test')) self.assertEqual(om.msgid, 'Flows/sid/Executions/FN0000')
def send_message(cls, package, message_type, to_number, referer=None, email=None): message = cls(package=package, message_type=cls.types_by_name[message_type], recipient_number=to_number, content=cls.render_message(message_type, package, referer)) try: if not settings.TEST: if settings.SMS_PLATFORM == 'Twilio': client = cls.get_twilio_client() if client: twilio_msg = client.messages.create( body=message.content, to=to_number, from_=settings.TWILIO['SENDER_NR']) message.twilio_sid = twilio_msg.sid elif settings.SMS_PLATFORM == 'GatewayAPI': gateway.send(OutgoingMessage(to_number, message.content)) if email: from_email = settings.EMAIL_HOST_USER or '*****@*****.**' send_mail(cls.subjects_by_name[message_type], message.content, from_email, [email]) except Exception as e: if settings.DEBUG: print(e) else: capture_exception(e) message.save()
def test_send(self): """ Test message send """ gw = self.gw # Mock the Target365 Api response. # See - https://generator.swagger.io/?url=https%3A%2F%2Ftest.target365.io%2Fapi%2Fswagger.json def send_callback(request): payload = json.loads(request.body) headers = { 'Location': '/api/out-messages/{}'.format(payload['transactionId']) } return (201, headers, '') responses.add_callback(responses.POST, 'https://target365.api/api/out-messages', callback=send_callback) # For the target365 src is mandatory message = gw.send( OutgoingMessage('+123456', 'hey', src='dignio', provider='main')) self.assertEqual(len(responses.calls), 1) self.assertTrue(message.msgid)
def test_bad_number_failure(self): """Test a failing AfricasTalking SMS send (bad phone number)""" message_out = OutgoingMessage( '+254789789789', 'Hello Rwanda', provider='africas_talking').params(target_country='RW') self.assertRaises(InvalidNumberError, self.gw.send, message_out)
def test_basic_send(self): with LogCapture() as l: msg = self.gw.send(OutgoingMessage('+1234', 'body')) l.check(('smsframework.providers.log', 'INFO', 'Sent SMS to {}: {}'.format(msg.dst, msg.body)), )
def send_sms(recipients, message): '''Send SMS to recipients with message''' for pnumber in recipients: GATEWAY.send(OutgoingMessage(pnumber, message))