def test_mt_sms_queue_full(self): smpp_helper = yield self.get_smpp_helper() transport_config = smpp_helper.transport.get_static_config() msg = self.tx_helper.make_outbound('hello world') yield self.tx_helper.dispatch_outbound(msg) [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1) yield smpp_helper.handle_pdu( SubmitSMResp(sequence_number=seq_no(submit_sm_pdu), message_id='foo', command_status='ESME_RMSGQFUL')) self.clock.advance(transport_config.throttle_delay) [submit_sm_pdu_retry] = yield smpp_helper.wait_for_pdus(1) yield smpp_helper.handle_pdu( SubmitSMResp(sequence_number=seq_no(submit_sm_pdu_retry), message_id='bar', command_status='ESME_ROK')) self.assertTrue(seq_no(submit_sm_pdu_retry) > seq_no(submit_sm_pdu)) self.assertEqual(short_message(submit_sm_pdu), 'hello world') self.assertEqual(short_message(submit_sm_pdu_retry), 'hello world') [event] = yield self.tx_helper.wait_for_dispatched_events(1) self.assertEqual(event['event_type'], 'ack') self.assertEqual(event['user_message_id'], msg['message_id'])
def assert_udh_parts(self, pdus, texts, encoding): pdu_header = lambda pdu: short_message(pdu)[:6] pdu_text = lambda pdu: short_message(pdu)[6:].decode(encoding) udh_header = lambda i: '\x05\x00\x03\x03\x07' + chr(i) self.assertEqual( [(pdu_header(pdu), pdu_text(pdu)) for pdu in pdus], [(udh_header(i + 1), text) for i, text in enumerate(texts)])
def assert_udh_parts(self, pdus, texts, encoding): pdu_header = lambda pdu: short_message(pdu)[:6] pdu_text = lambda pdu: short_message(pdu)[6:].decode(encoding) udh_header = lambda i: '\x05\x00\x03\x03\x07' + chr(i) self.assertEqual([(pdu_header(pdu), pdu_text(pdu)) for pdu in pdus], [(udh_header(i + 1), text) for i, text in enumerate(texts)])
def test_mt_sms_multipart_udh(self): smpp_helper = yield self.get_smpp_helper( config={ 'submit_short_message_processor_config': { 'send_multipart_udh': True, } }) content = '1' * 161 msg = self.tx_helper.make_outbound(content) yield self.tx_helper.dispatch_outbound(msg) [submit_sm1, submit_sm2] = yield smpp_helper.wait_for_pdus(2) udh_hlen, udh_tag, udh_len, udh_ref, udh_tot, udh_seq = [ ord(octet) for octet in short_message(submit_sm1)[:6] ] self.assertEqual(5, udh_hlen) self.assertEqual(0, udh_tag) self.assertEqual(3, udh_len) self.assertEqual(udh_tot, 2) self.assertEqual(udh_seq, 1) _, _, _, ref_to_udh_ref, _, udh_seq = [ ord(octet) for octet in short_message(submit_sm2)[:6] ] self.assertEqual(ref_to_udh_ref, udh_ref) self.assertEqual(udh_seq, 2)
def test_startup_with_backlog(self): smpp_helper = yield self.get_smpp_helper(bind=False) for i in range(2): msg = self.tx_helper.make_outbound('hello world %s' % (i, )) yield self.tx_helper.dispatch_outbound(msg) yield self.create_smpp_bind(smpp_helper.transport) [submit_sm1, submit_sm2] = yield smpp_helper.wait_for_pdus(2) self.assertEqual(short_message(submit_sm1), 'hello world 0') self.assertEqual(short_message(submit_sm2), 'hello world 1')
def test_startup_with_backlog(self): smpp_helper = yield self.get_smpp_helper(bind=False) for i in range(2): msg = self.tx_helper.make_outbound('hello world %s' % (i,)) yield self.tx_helper.dispatch_outbound(msg) yield self.create_smpp_bind(smpp_helper.transport) [submit_sm1, submit_sm2] = yield smpp_helper.wait_for_pdus(2) self.assertEqual(short_message(submit_sm1), 'hello world 0') self.assertEqual(short_message(submit_sm2), 'hello world 1')
def test_mt_sms_throttle_while_throttled(self): smpp_helper = yield self.get_smpp_helper() transport_config = smpp_helper.transport.get_static_config() msg1 = self.tx_helper.make_outbound('hello world 1') msg2 = self.tx_helper.make_outbound('hello world 2') yield self.tx_helper.dispatch_outbound(msg1) yield self.tx_helper.dispatch_outbound(msg2) [ssm_pdu1, ssm_pdu2] = yield smpp_helper.wait_for_pdus(2) yield smpp_helper.handle_pdu( SubmitSMResp(sequence_number=seq_no(ssm_pdu1), message_id='foo1', command_status='ESME_RTHROTTLED')) yield smpp_helper.handle_pdu( SubmitSMResp(sequence_number=seq_no(ssm_pdu2), message_id='foo2', command_status='ESME_RTHROTTLED')) # Advance clock, still throttled. self.clock.advance(transport_config.throttle_delay) [ssm_pdu1_retry1] = yield smpp_helper.wait_for_pdus(1) yield smpp_helper.handle_pdu( SubmitSMResp(sequence_number=seq_no(ssm_pdu1_retry1), message_id='bar1', command_status='ESME_RTHROTTLED')) # Advance clock, message no longer throttled. self.clock.advance(transport_config.throttle_delay) [ssm_pdu2_retry1] = yield smpp_helper.wait_for_pdus(1) yield smpp_helper.handle_pdu( SubmitSMResp(sequence_number=seq_no(ssm_pdu2_retry1), message_id='bar2', command_status='ESME_ROK')) # Prod clock, message no longer throttled. self.clock.advance(0) [ssm_pdu1_retry2] = yield smpp_helper.wait_for_pdus(1) yield smpp_helper.handle_pdu( SubmitSMResp(sequence_number=seq_no(ssm_pdu1_retry2), message_id='baz1', command_status='ESME_ROK')) self.assertEqual(short_message(ssm_pdu1), 'hello world 1') self.assertEqual(short_message(ssm_pdu2), 'hello world 2') self.assertEqual(short_message(ssm_pdu1_retry1), 'hello world 1') self.assertEqual(short_message(ssm_pdu2_retry1), 'hello world 2') self.assertEqual(short_message(ssm_pdu1_retry2), 'hello world 1') [event2, event1] = yield self.tx_helper.wait_for_dispatched_events(2) self.assertEqual(event1['event_type'], 'ack') self.assertEqual(event1['user_message_id'], msg1['message_id']) self.assertEqual(event2['event_type'], 'ack') self.assertEqual(event2['user_message_id'], msg2['message_id'])
def test_submit_sm_multipart_udh_ucs2(self): message = ( "A cup is a small, open container used for carrying and " "drinking drinks. It may be made of wood, plastic, glass, " "clay, metal, stone, china or other materials, and may have " "a stem, handles or other adornments. Cups are used for " "drinking across a wide range of cultures and social classes, " "and different styles of cups may be used for different liquids " "or in different situations. Cups have been used for thousands " "of years for the ...Reply 1 for more") yield self.get_transport() yield self.tx_helper.make_dispatch_outbound(message, to_addr='msisdn') pdus = yield self.fake_smsc.await_pdus(7) self.assert_udh_parts(pdus, [ ("A cup is a small, open container used" " for carrying and drinking d"), ("rinks. It may be made of wood, plastic," " glass, clay, metal, stone"), (", china or other materials, and may have" " a stem, handles or other"), (" adornments. Cups are used for drinking" " across a wide range of cu"), ("ltures and social classes, and different" " styles of cups may be us"), ("ed for different liquids or in different" " situations. Cups have be"), ("en used for thousands of years for the ...Reply 1 for more"), ], encoding='utf-16be') # utf-16be is close enough to UCS2 for pdu in pdus: self.assertTrue(len(short_message(pdu)) < 140)
def test_mt_sms(self): smpp_helper = yield self.get_smpp_helper() msg = self.tx_helper.make_outbound('hello world') yield self.tx_helper.dispatch_outbound(msg) [pdu] = yield smpp_helper.wait_for_pdus(1) self.assertEqual(command_id(pdu), 'submit_sm') self.assertEqual(short_message(pdu), 'hello world')
def test_submit_sm_multipart_udh_ucs2(self): message = ( "A cup is a small, open container used for carrying and " "drinking drinks. It may be made of wood, plastic, glass, " "clay, metal, stone, china or other materials, and may have " "a stem, handles or other adornments. Cups are used for " "drinking across a wide range of cultures and social classes, " "and different styles of cups may be used for different liquids " "or in different situations. Cups have been used for thousands " "of years for the ...Reply 1 for more") yield self.get_transport() yield self.tx_helper.make_dispatch_outbound(message, to_addr='msisdn') pdus = yield self.fake_smsc.await_pdus(7) self.assert_udh_parts( pdus, [ ("A cup is a small, open container used" " for carrying and drinking d"), ("rinks. It may be made of wood, plastic," " glass, clay, metal, stone"), (", china or other materials, and may have" " a stem, handles or other"), (" adornments. Cups are used for drinking" " across a wide range of cu"), ("ltures and social classes, and different" " styles of cups may be us"), ("ed for different liquids or in different" " situations. Cups have be"), ("en used for thousands of years for the ...Reply 1 for more"), ], encoding='utf-16be') # utf-16be is close enough to UCS2 for pdu in pdus: self.assertTrue(len(short_message(pdu)) < 140)
def test_sar_ref_num_limit(self): transport, protocol = yield self.setup_bind(config={ 'send_multipart_udh': True, }) # forward until we go past 0xFFFF yield protocol.sequence_generator.advance(0xFFFF) long_message = 'This is a long message.' * 20 seq_numbers = yield protocol.submit_csm_udh( 'abc123', 'dest_addr', short_message=long_message) pdus = yield wait_for_pdus(transport, 4) self.assertEqual(len(seq_numbers), 4) self.assertTrue(all([sn > 0xFF for sn in seq_numbers])) msg_refs = [] for pdu in pdus: msg = short_message(pdu) _, _, _, udh_ref, _, _ = [ord(octet) for octet in msg[:6]] msg_refs.append(udh_ref) self.assertEqual(1, len(set(msg_refs))) self.assertTrue(all([msg_ref < 0xFFFF for msg_ref in msg_refs]))
def test_mt_sms_unicode(self): smpp_helper = yield self.get_smpp_helper() msg = self.tx_helper.make_outbound(u'Zoë') yield self.tx_helper.dispatch_outbound(msg) [pdu] = yield smpp_helper.wait_for_pdus(1) self.assertEqual(command_id(pdu), 'submit_sm') self.assertEqual(short_message(pdu), 'Zo\xc3\xab')
def test_mt_sms_submit_sm_encoding(self): smpp_helper = yield self.get_smpp_helper(config={ 'submit_short_message_processor_config': { 'submit_sm_encoding': 'latin1', } }) yield self.tx_helper.make_dispatch_outbound(u'Zoë destroyer of Ascii!') [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1) self.assertEqual( short_message(submit_sm_pdu), u'Zoë destroyer of Ascii!'.encode('latin-1'))
def test_mt_sms_submit_sm_encoding(self): smpp_helper = yield self.get_smpp_helper( config={ 'submit_short_message_processor_config': { 'submit_sm_encoding': 'latin1', } }) yield self.tx_helper.make_dispatch_outbound(u'Zoë destroyer of Ascii!') [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1) self.assertEqual(short_message(submit_sm_pdu), u'Zoë destroyer of Ascii!'.encode('latin-1'))
def test_mt_sms_multipart_udh(self): smpp_helper = yield self.get_smpp_helper(config={ 'submit_short_message_processor_config': { 'send_multipart_udh': True, } }) content = '1' * 161 msg = self.tx_helper.make_outbound(content) yield self.tx_helper.dispatch_outbound(msg) [submit_sm1, submit_sm2] = yield smpp_helper.wait_for_pdus(2) udh_hlen, udh_tag, udh_len, udh_ref, udh_tot, udh_seq = [ ord(octet) for octet in short_message(submit_sm1)[:6]] self.assertEqual(5, udh_hlen) self.assertEqual(0, udh_tag) self.assertEqual(3, udh_len) self.assertEqual(udh_tot, 2) self.assertEqual(udh_seq, 1) _, _, _, ref_to_udh_ref, _, udh_seq = [ ord(octet) for octet in short_message(submit_sm2)[:6]] self.assertEqual(ref_to_udh_ref, udh_ref) self.assertEqual(udh_seq, 2)
def test_mt_sms_throttled(self): smpp_helper = yield self.get_smpp_helper() transport_config = smpp_helper.transport.get_static_config() msg = self.tx_helper.make_outbound('hello world') yield self.tx_helper.dispatch_outbound(msg) [submit_sm_pdu] = yield smpp_helper.wait_for_pdus(1) with LogCatcher(message="Throttling outbound messages.") as lc: yield smpp_helper.handle_pdu( SubmitSMResp(sequence_number=seq_no(submit_sm_pdu), message_id='foo', command_status='ESME_RTHROTTLED')) [logmsg] = lc.logs self.assertEqual(logmsg['logLevel'], logging.WARNING) self.clock.advance(transport_config.throttle_delay) [submit_sm_pdu_retry] = yield smpp_helper.wait_for_pdus(1) yield smpp_helper.handle_pdu( SubmitSMResp(sequence_number=seq_no(submit_sm_pdu_retry), message_id='bar', command_status='ESME_ROK')) self.assertTrue(seq_no(submit_sm_pdu_retry) > seq_no(submit_sm_pdu)) self.assertEqual(short_message(submit_sm_pdu), 'hello world') self.assertEqual(short_message(submit_sm_pdu_retry), 'hello world') [event] = yield self.tx_helper.wait_for_dispatched_events(1) self.assertEqual(event['event_type'], 'ack') self.assertEqual(event['user_message_id'], msg['message_id']) # We're still throttled until our next attempt to unthrottle finds no # messages to retry. with LogCatcher(message="No longer throttling outbound") as lc: self.clock.advance(transport_config.throttle_delay) [logmsg] = lc.logs self.assertEqual(logmsg['logLevel'], logging.WARNING)
def test_mt_sms_tps_limits(self): smpp_helper = yield self.get_smpp_helper(config={ 'mt_tps': 2, }) transport = smpp_helper.transport with LogCatcher(message="Throttling outbound messages.") as lc: yield self.tx_helper.make_dispatch_outbound('hello world 1') yield self.tx_helper.make_dispatch_outbound('hello world 2') [logmsg] = lc.logs self.assertEqual(logmsg['logLevel'], logging.INFO) self.assertTrue(transport.throttled) [submit_sm_pdu1] = yield smpp_helper.wait_for_pdus(1) self.assertEqual(short_message(submit_sm_pdu1), 'hello world 1') with LogCatcher(message="No longer throttling outbound") as lc: self.clock.advance(1) [logmsg] = lc.logs self.assertEqual(logmsg['logLevel'], logging.INFO) self.assertFalse(transport.throttled) [submit_sm_pdu2] = yield smpp_helper.wait_for_pdus(1) self.assertEqual(short_message(submit_sm_pdu2), 'hello world 2')
def test_partial_pdu_data_received(self): calls = [] self.patch(EsmeTransceiver, 'handle_deliver_sm', lambda p, pdu: calls.append(pdu)) transport, protocol = yield self.setup_bind() deliver_sm = DeliverSM(sequence_number=1, short_message='foo') pdu = deliver_sm.get_bin() half = len(pdu) / 2 pdu_part1, pdu_part2 = pdu[:half], pdu[half:] protocol.dataReceived(pdu_part1) self.assertEqual([], calls) protocol.dataReceived(pdu_part2) [handled_pdu] = calls self.assertEqual(command_id(handled_pdu), 'deliver_sm') self.assertEqual(seq_no(handled_pdu), 1) self.assertEqual(short_message(handled_pdu), 'foo')
def test_partial_pdu_data_received(self): protocol = yield self.get_protocol() calls = [] protocol.handle_deliver_sm = calls.append yield self.fake_smsc.bind() deliver_sm = DeliverSM(1, short_message='foo') pdu = deliver_sm.get_bin() half = len(pdu) / 2 pdu_part1, pdu_part2 = pdu[:half], pdu[half:] yield self.fake_smsc.send_bytes(pdu_part1) self.assertEqual([], calls) yield self.fake_smsc.send_bytes(pdu_part2) [handled_pdu] = calls self.assertEqual(command_id(handled_pdu), 'deliver_sm') self.assertEqual(seq_no(handled_pdu), 1) self.assertEqual(short_message(handled_pdu), 'foo')
def test_submit_csm_sar_single_part(self): """ If the content fits in a single message, all the multipart madness is avoided. """ service = yield self.get_service({'send_multipart_sar': True}) yield self.fake_smsc.bind() content = 'a' * 160 seq_numbers = yield service.submit_csm_sar( 'abc123', 'dest_addr', short_message=content) self.assertEqual(len(seq_numbers), 1) submit_sm_pdu = yield self.fake_smsc.await_pdu() self.assertEqual(command_id(submit_sm_pdu), 'submit_sm') self.assertEqual(short_message(submit_sm_pdu), content) self.assertEqual(unpacked_pdu_opts(submit_sm_pdu), {})
def test_submit_csm_sar_single_part(self): """ If the content fits in a single message, all the multipart madness is avoided. """ service = yield self.get_service({'send_multipart_sar': True}) yield self.fake_smsc.bind() content = 'a' * 160 seq_numbers = yield service.submit_csm_sar('abc123', 'dest_addr', short_message=content) self.assertEqual(len(seq_numbers), 1) submit_sm_pdu = yield self.fake_smsc.await_pdu() self.assertEqual(command_id(submit_sm_pdu), 'submit_sm') self.assertEqual(short_message(submit_sm_pdu), content) self.assertEqual(unpacked_pdu_opts(submit_sm_pdu), {})
def test_submit_csm_udh_single_part(self): """ If the content fits in a single message, all the multipart madness is avoided. """ service = yield self.get_service({'send_multipart_udh': True}) yield self.fake_smsc.bind() content = 'a' * 160 seq_numbers = yield service.submit_csm_udh( 'abc123', 'dest_addr', short_message=content) self.assertEqual(len(seq_numbers), 1) submit_sm_pdu = yield self.fake_smsc.await_pdu() self.assertEqual(command_id(submit_sm_pdu), 'submit_sm') self.assertEqual(short_message(submit_sm_pdu), content) self.assertEqual( submit_sm_pdu['body']['mandatory_parameters']['esm_class'], 0)
def test_submit_csm_udh_single_part(self): """ If the content fits in a single message, all the multipart madness is avoided. """ service = yield self.get_service({'send_multipart_udh': True}) yield self.fake_smsc.bind() content = 'a' * 160 seq_numbers = yield service.submit_csm_udh('abc123', 'dest_addr', short_message=content) self.assertEqual(len(seq_numbers), 1) submit_sm_pdu = yield self.fake_smsc.await_pdu() self.assertEqual(command_id(submit_sm_pdu), 'submit_sm') self.assertEqual(short_message(submit_sm_pdu), content) self.assertEqual( submit_sm_pdu['body']['mandatory_parameters']['esm_class'], 0)
def pdu_text(pdu): return short_message(pdu)[6:].decode(encoding)
def pdu_header(pdu): return short_message(pdu)[:6]