diff options
-rw-r--r-- | selftest/template_test.ok | 11 | ||||
-rwxr-xr-x | selftest/template_test.py | 13 | ||||
-rw-r--r-- | selftest/template_test/osmo-nitb.cfg.tmpl | 18 | ||||
-rw-r--r-- | src/osmo_gsm_tester/esme.py | 138 | ||||
-rw-r--r-- | src/osmo_gsm_tester/osmo_msc.py | 5 | ||||
-rw-r--r-- | src/osmo_gsm_tester/osmo_nitb.py | 5 | ||||
-rw-r--r-- | src/osmo_gsm_tester/sms.py | 18 | ||||
-rw-r--r-- | src/osmo_gsm_tester/smsc.py | 50 | ||||
-rw-r--r-- | src/osmo_gsm_tester/suite.py | 10 | ||||
-rw-r--r-- | src/osmo_gsm_tester/templates/osmo-msc.cfg.tmpl | 14 | ||||
-rw-r--r-- | src/osmo_gsm_tester/templates/osmo-nitb.cfg.tmpl | 14 | ||||
-rw-r--r-- | src/osmo_gsm_tester/test.py | 6 | ||||
-rwxr-xr-x | suites/aoip_smpp/esme_connect_policy_acceptall.py | 37 | ||||
-rwxr-xr-x | suites/aoip_smpp/esme_connect_policy_closed.py | 57 | ||||
-rwxr-xr-x | suites/aoip_smpp/esme_ms_sms.py | 56 | ||||
-rw-r--r-- | suites/aoip_smpp/suite.conf | 10 | ||||
-rwxr-xr-x | suites/smpp/esme_connect_policy_acceptall.py | 32 | ||||
-rwxr-xr-x | suites/smpp/esme_connect_policy_closed.py | 51 | ||||
-rwxr-xr-x | suites/smpp/esme_ms_sms.py | 49 | ||||
-rw-r--r-- | suites/smpp/suite.conf | 10 |
20 files changed, 574 insertions, 30 deletions
diff --git a/selftest/template_test.ok b/selftest/template_test.ok index 1267dac..688361f 100644 --- a/selftest/template_test.ok +++ b/selftest/template_test.ok @@ -136,10 +136,13 @@ network phys_chan_config val_phys_chan_config_3 smpp local-tcp-ip val_ip_address 2775 - system-id test - policy closed - esme test - password test + system-id test-nitb + policy val_smsc_policy + esme val_system_id_esme0 + password val_password_esme0 + default-route + esme val_system_id_esme1 + no password default-route ctrl bind val_ip_address diff --git a/selftest/template_test.py b/selftest/template_test.py index 45347b6..f8c32a5 100755 --- a/selftest/template_test.py +++ b/selftest/template_test.py @@ -35,6 +35,11 @@ mock_bts = { ) } +mock_esme = { + 'system_id': 'val_system_id', + 'password': 'val_password' +} + def clone_mod(d, val_ext): c = dict(d) for name in c.keys(): @@ -47,6 +52,10 @@ def clone_mod(d, val_ext): mock_bts0 = clone_mod(mock_bts, '_bts0') mock_bts1 = clone_mod(mock_bts, '_bts1') +mock_esme0 = clone_mod(mock_esme, '_esme0') +mock_esme1 = clone_mod(mock_esme, '_esme1') +mock_esme1['password'] = '' + vals = dict(nitb=dict( net=dict( mcc='val_mcc', @@ -59,6 +68,10 @@ vals = dict(nitb=dict( ), ip_address=dict(addr='val_ip_address'), ), + smsc=dict( + policy='val_smsc_policy', + esme_list=(mock_esme0, mock_esme1) + ), ) print(template.render('osmo-nitb.cfg', vals)) diff --git a/selftest/template_test/osmo-nitb.cfg.tmpl b/selftest/template_test/osmo-nitb.cfg.tmpl index 3404b7f..7a76878 100644 --- a/selftest/template_test/osmo-nitb.cfg.tmpl +++ b/selftest/template_test/osmo-nitb.cfg.tmpl @@ -47,12 +47,18 @@ network timer t3119 0 timer t3141 0 smpp - local-tcp-ip ${smpp_bind_ip} 2775 - system-id test - policy closed - esme test - password test - default-route + local-tcp-ip ${nitb.ip_address.addr} 2775 + system-id test-nitb + policy ${smsc.policy} + %for esme in esme_list: + esme ${esme.system_id} + % if esme.password == '': + no password + % else: + password ${esme.password} + % endif + default-route + %endfor ctrl bind ${ctrl_bind_ip} %for bts in bts_list: diff --git a/src/osmo_gsm_tester/esme.py b/src/osmo_gsm_tester/esme.py new file mode 100644 index 0000000..f92863d --- /dev/null +++ b/src/osmo_gsm_tester/esme.py @@ -0,0 +1,138 @@ +# osmo_gsm_tester: SMPP ESME to talk to SMSC +# +# Copyright (C) 2017 by sysmocom - s.f.m.c. GmbH +# +# Author: Pau Espin Pedrol <pespin@sysmocom.de> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import smpplib.gsm +import smpplib.client +import smpplib.consts +import smpplib.exceptions + +from . import log, util, event_loop, sms + +# if you want to know what's happening inside python-smpplib +#import logging +#logging.basicConfig(level='DEBUG') + +MAX_SYS_ID_LEN = 16 +MAX_PASSWD_LEN = 16 + +class Esme(log.Origin): + client = None + smsc = None + + def __init__(self, msisdn): + self.msisdn = msisdn + # Get last characters of msisdn to stay inside MAX_SYS_ID_LEN. Similar to modulus operator. + self.set_system_id('esme-' + self.msisdn[-11:]) + super().__init__(log.C_TST, self.system_id) + self.set_password('esme-pwd') + self.connected = False + self.bound = False + self.listening = False + + def __del__(self): + try: + self.disconnect() + except smpplib.exceptions.ConnectionError: + pass + + def set_smsc(self, smsc): + self.smsc = smsc + + def set_system_id(self, name): + if len(name) > MAX_SYS_ID_LEN: + raise log.Error('Esme system_id too long! %d vs %d', len(name), MAX_SYS_ID_LEN) + self.system_id = name + + def set_password(self, password): + if len(password) > MAX_PASSWD_LEN: + raise log.Error('Esme password too long! %d vs %d', len(password), MAX_PASSWD_LEN) + self.password = password + + def conf_for_smsc(self): + config = { 'system_id': self.system_id, 'password': self.password } + return config + + def poll(self): + self.client.poll() + + def start_listening(self): + self.listening = True + event_loop.register_poll_func(self.poll) + + def stop_listening(self): + if not self.listening: + return + self.listening = False + # Empty the queue before processing the unbind + disconnect PDUs + event_loop.unregister_poll_func(self.poll) + self.poll() + + def connect(self): + host, port = self.smsc.addr_port + if self.client: + self.disconnect() + self.client = smpplib.client.Client(host, port, timeout=None) + self.client.set_message_sent_handler( + lambda pdu: self.dbg('message sent:', repr(pdu)) ) + self.client.set_message_received_handler( + lambda pdu: self.dbg('message received:', repr(pdu)) ) + self.client.connect() + self.connected = True + self.client.bind_transceiver(system_id=self.system_id, password=self.password) + self.bound = True + self.log('Connected and bound successfully. Starting to listen') + self.start_listening() + + def disconnect(self): + self.stop_listening() + if self.bound: + self.client.unbind() + self.bound = False + if self.connected: + self.client.disconnect() + self.connected = False + + def run_method_expect_failure(self, errcode, method, *args): + try: + method(*args) + #it should not succeed, raise an exception: + raise log.Error('SMPP Failure: %s should have failed with SMPP error %d (%s) but succeeded.' % (method, errcode, smpplib.consts.DESCRIPTIONS[errcode])) + except smpplib.exceptions.PDUError as e: + if e.args[1] != errcode: + raise e + + def sms_send(self, sms_obj): + parts, encoding_flag, msg_type_flag = smpplib.gsm.make_parts(str(sms_obj)) + + self.log('Sending SMS "%s" to %s' % (str(sms_obj), sms_obj.dst_msisdn())) + for part in parts: + pdu = self.client.send_message( + source_addr_ton=smpplib.consts.SMPP_TON_INTL, + source_addr_npi=smpplib.consts.SMPP_NPI_ISDN, + source_addr=sms_obj.src_msisdn(), + dest_addr_ton=smpplib.consts.SMPP_TON_INTL, + dest_addr_npi=smpplib.consts.SMPP_NPI_ISDN, + destination_addr=sms_obj.dst_msisdn(), + short_message=part, + data_coding=encoding_flag, + esm_class=smpplib.consts.SMPP_MSGMODE_FORWARD, + registered_delivery=False, + ) + +# vim: expandtab tabstop=4 shiftwidth=4 diff --git a/src/osmo_gsm_tester/osmo_msc.py b/src/osmo_gsm_tester/osmo_msc.py index 063b477..2c9b1e3 100644 --- a/src/osmo_gsm_tester/osmo_msc.py +++ b/src/osmo_gsm_tester/osmo_msc.py @@ -20,7 +20,7 @@ import os import pprint -from . import log, util, config, template, process, osmo_ctrl, pcap_recorder +from . import log, util, config, template, process, osmo_ctrl, pcap_recorder, smsc class OsmoMsc(log.Origin): suite_run = None @@ -30,6 +30,7 @@ class OsmoMsc(log.Origin): process = None hlr = None config = None + smsc = None def __init__(self, suite_run, hlr, mgcpgw, ip_address): super().__init__(log.C_RUN, 'osmo-msc_%s' % ip_address.get('addr')) @@ -37,6 +38,7 @@ class OsmoMsc(log.Origin): self.ip_address = ip_address self.hlr = hlr self.mgcpgw = mgcpgw + self.smsc = smsc.Smsc((ip_address.get('addr'), 2775)) def start(self): self.log('Starting osmo-msc') @@ -73,6 +75,7 @@ class OsmoMsc(log.Origin): config.overlay(values, dict(msc=dict(ip_address=self.ip_address))) config.overlay(values, self.mgcpgw.conf_for_msc()) config.overlay(values, self.hlr.conf_for_msc()) + config.overlay(values, self.smsc.get_config()) self.config = values self.dbg('MSC CONFIG:\n' + pprint.pformat(values)) diff --git a/src/osmo_gsm_tester/osmo_nitb.py b/src/osmo_gsm_tester/osmo_nitb.py index 484358e..3ef5276 100644 --- a/src/osmo_gsm_tester/osmo_nitb.py +++ b/src/osmo_gsm_tester/osmo_nitb.py @@ -21,7 +21,7 @@ import os import re import pprint -from . import log, util, config, template, process, osmo_ctrl, pcap_recorder +from . import log, util, config, template, process, osmo_ctrl, pcap_recorder, smsc class OsmoNitb(log.Origin): suite_run = None @@ -30,12 +30,14 @@ class OsmoNitb(log.Origin): config_file = None process = None bts = None + smsc = None def __init__(self, suite_run, ip_address): super().__init__(log.C_RUN, 'osmo-nitb_%s' % ip_address.get('addr')) self.suite_run = suite_run self.ip_address = ip_address self.bts = [] + self.smsc = smsc.Smsc((ip_address.get('addr'), 2775)) def start(self): self.log('Starting osmo-nitb') @@ -75,6 +77,7 @@ class OsmoNitb(log.Origin): for bts in self.bts: bts_list.append(bts.conf_for_bsc()) config.overlay(values, dict(nitb=dict(net=dict(bts_list=bts_list)))) + config.overlay(values, self.smsc.get_config()) self.config = values self.dbg('NITB CONFIG:\n' + pprint.pformat(values)) diff --git a/src/osmo_gsm_tester/sms.py b/src/osmo_gsm_tester/sms.py index 570ef96..e264b66 100644 --- a/src/osmo_gsm_tester/sms.py +++ b/src/osmo_gsm_tester/sms.py @@ -21,14 +21,16 @@ class Sms: _last_sms_idx = 0 msg = None - def __init__(self, from_msisdn=None, to_msisdn=None, *tokens): + def __init__(self, src_msisdn=None, dst_msisdn=None, *tokens): Sms._last_sms_idx += 1 + self._src_msisdn = src_msisdn + self._dst_msisdn = dst_msisdn msgs = ['message nr. %d' % Sms._last_sms_idx] msgs.extend(tokens) - if from_msisdn: - msgs.append('from %s' % from_msisdn) - if to_msisdn: - msgs.append('to %s' % to_msisdn) + if src_msisdn: + msgs.append('from %s' % src_msisdn) + if dst_msisdn: + msgs.append('to %s' % dst_msisdn) self.msg = ', '.join(msgs) def __str__(self): @@ -42,6 +44,12 @@ class Sms: return self.msg == other.msg return self.msg == other + def src_msisdn(self): + return self._src_msisdn + + def dst_msisdn(self): + return self._dst_msisdn + def matches(self, msg): return self.msg == msg diff --git a/src/osmo_gsm_tester/smsc.py b/src/osmo_gsm_tester/smsc.py new file mode 100644 index 0000000..4837f37 --- /dev/null +++ b/src/osmo_gsm_tester/smsc.py @@ -0,0 +1,50 @@ +# osmo_gsm_tester: smsc interface +# +# Copyright (C) 2016-2017 by sysmocom - s.f.m.c. GmbH +# +# Author: Pau Espin Pedrol <pespin@sysmocom.de> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +from . import log, config, util, template, process + +class Smsc: + esmes = None + + SMSC_POLICY_CLOSED = 'closed' + SMSC_POLICY_ACCEPT_ALL = 'accept-all' + + def __init__(self, smpp_addr_port): + self.addr_port = smpp_addr_port + self.policy = self.SMSC_POLICY_CLOSED + self.esmes = [] + + def get_config(self): + values = { 'smsc': { 'policy': self.policy } } + esme_list = [] + for esme in self.esmes: + esme_list.append(esme.conf_for_smsc()) + config.overlay(values, dict(smsc=dict(esme_list=esme_list))) + return values + + def esme_add(self, esme): + if esme.system_id == '': + raise log.Error('esme system_id cannot be empty') + self.esmes.append(esme) + esme.set_smsc(self) + + def set_smsc_policy(self, smsc_policy): + self.policy = smsc_policy + +# vim: expandtab tabstop=4 shiftwidth=4 diff --git a/src/osmo_gsm_tester/suite.py b/src/osmo_gsm_tester/suite.py index f4b9260..71b8dc7 100644 --- a/src/osmo_gsm_tester/suite.py +++ b/src/osmo_gsm_tester/suite.py @@ -23,7 +23,7 @@ import time import copy import traceback import pprint -from . import config, log, template, util, resource, schema, ofono_client, event_loop +from . import config, log, template, util, resource, schema, ofono_client, event_loop, esme, sms from . import osmo_nitb from . import osmo_hlr, osmo_mgcpgw, osmo_msc, osmo_bsc, osmo_stp from . import test @@ -99,7 +99,7 @@ class Test(log.Origin): log.large_separator(self.suite_run.trial.name(), self.suite_run.name(), self.name(), sublevel=3) self.status = Test.UNKNOWN self.start_timestamp = time.time() - test.setup(self.suite_run, self, ofono_client, sys.modules[__name__], event_loop) + test.setup(self.suite_run, self, ofono_client, sys.modules[__name__], event_loop, sms) with self.redirect_stdout(): util.run_python_file('%s.%s' % (self.suite_run.definition.name(), self.basename), self.path) @@ -363,8 +363,12 @@ class SuiteRun(log.Origin): l.append(self.modem()) return l + def esme(self): + esme_obj = esme.Esme(self.msisdn()) + return esme_obj + def msisdn(self): - msisdn = self.resources_pool.next_msisdn(self.origin) + msisdn = self.resources_pool.next_msisdn(self) self.log('using MSISDN', msisdn) return msisdn diff --git a/src/osmo_gsm_tester/templates/osmo-msc.cfg.tmpl b/src/osmo_gsm_tester/templates/osmo-msc.cfg.tmpl index 247365e..89982e0 100644 --- a/src/osmo_gsm_tester/templates/osmo-msc.cfg.tmpl +++ b/src/osmo_gsm_tester/templates/osmo-msc.cfg.tmpl @@ -23,10 +23,16 @@ ctrl bind ${msc.ip_address.addr} smpp local-tcp-ip ${msc.ip_address.addr} 2775 - system-id test - policy closed - esme test - password test + system-id test-msc + policy ${smsc.policy} +%for esme in smsc.esme_list: + esme ${esme.system_id} +% if esme.password == '': + no password +% else: + password ${esme.password} +% endif default-route +%endfor hlr remote-ip ${hlr.ip_address.addr} diff --git a/src/osmo_gsm_tester/templates/osmo-nitb.cfg.tmpl b/src/osmo_gsm_tester/templates/osmo-nitb.cfg.tmpl index a47ac02..23cc225 100644 --- a/src/osmo_gsm_tester/templates/osmo-nitb.cfg.tmpl +++ b/src/osmo_gsm_tester/templates/osmo-nitb.cfg.tmpl @@ -76,10 +76,16 @@ network %endfor smpp local-tcp-ip ${nitb.ip_address.addr} 2775 - system-id test - policy closed - esme test - password test + system-id test-nitb + policy ${smsc.policy} +%for esme in smsc.esme_list: + esme ${esme.system_id} +% if esme.password == '': + no password +% else: + password ${esme.password} +% endif default-route +%endfor ctrl bind ${nitb.ip_address.addr} diff --git a/src/osmo_gsm_tester/test.py b/src/osmo_gsm_tester/test.py index 2958501..49911b3 100644 --- a/src/osmo_gsm_tester/test.py +++ b/src/osmo_gsm_tester/test.py @@ -33,9 +33,10 @@ sleep = None poll = None prompt = None Timeout = None +Sms = None -def setup(suite_run, _test, ofono_client, suite_module, event_module): - global trial, suite, test, resources, log, dbg, err, wait, wait_no_raise, sleep, poll, prompt, Timeout +def setup(suite_run, _test, ofono_client, suite_module, event_module, sms_module): + global trial, suite, test, resources, log, dbg, err, wait, wait_no_raise, sleep, poll, prompt, Timeout, Sms trial = suite_run.trial suite = suite_run test = _test @@ -49,5 +50,6 @@ def setup(suite_run, _test, ofono_client, suite_module, event_module): poll = event_module.poll prompt = suite_run.prompt Timeout = suite_module.Timeout + Sms = sms_module.Sms # vim: expandtab tabstop=4 shiftwidth=4 diff --git a/suites/aoip_smpp/esme_connect_policy_acceptall.py b/suites/aoip_smpp/esme_connect_policy_acceptall.py new file mode 100755 index 0000000..2a954d5 --- /dev/null +++ b/suites/aoip_smpp/esme_connect_policy_acceptall.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +# This test checks following use-cases while in 'accept-all' policy: +# * SMPP interface of SMSC accepts SMPP clients (ESMEs) which do not appear on +# the config file + +from osmo_gsm_tester.test import * + +hlr = suite.hlr() +bts = suite.bts() # bts not started, only needed for mgcpgw +mgcpgw = suite.mgcpgw(bts_ip=bts.remote_addr()) +msc = suite.msc(hlr, mgcpgw) +smsc = msc.smsc +esme = suite.esme() + +# Here we deliberately omit calling smsc.esme_add() to avoid having it included +# in the smsc config. +smsc.set_smsc_policy(smsc.SMSC_POLICY_ACCEPT_ALL) +esme.set_smsc(smsc) + +hlr.start() +msc.start() +mgcpgw.start() + +# Due to accept-all policy, connect() should work even if we didn't previously +# configure the esme in the smsc, no matter the system_id / password we use. +log('Test connect with non-empty values in system_id and password') +esme.set_system_id('foo') +esme.set_password('bar') +esme.connect() +esme.disconnect() + +log('Test connect with empty values in system_id and password') +esme.set_system_id('') +esme.set_password('') +esme.connect() +esme.disconnect() diff --git a/suites/aoip_smpp/esme_connect_policy_closed.py b/suites/aoip_smpp/esme_connect_policy_closed.py new file mode 100755 index 0000000..29b25d1 --- /dev/null +++ b/suites/aoip_smpp/esme_connect_policy_closed.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 + +# This test checks following use-cases while in 'closed' policy: +# * SMPP interface of SMSC accepts SMPP clients (ESMEs) with password previously +# defined in its configuration file. +# * SMPP interface of SMSC rejects ESMEs with known system id but wrong password. +# * SMPP interface of SMSC rejects ESEMs with unknown system id + +from osmo_gsm_tester.test import * + +SMPP_ESME_RINVPASWD = 0x0000000E +SMPP_ESME_RINVSYSID = 0x0000000F + +hlr = suite.hlr() +bts = suite.bts() +mgcpgw = suite.mgcpgw(bts_ip=bts.remote_addr()) +msc = suite.msc(hlr, mgcpgw) +smsc = msc.smsc + +esme = suite.esme() +esme_no_pwd = suite.esme() +esme_no_pwd.set_password('') + +smsc.set_smsc_policy(smsc.SMSC_POLICY_CLOSED) +smsc.esme_add(esme) +smsc.esme_add(esme_no_pwd) + +hlr.start() +msc.start() +mgcpgw.start() + +log('Test with correct credentials (no password)') +esme_no_pwd.connect() +esme_no_pwd.disconnect() + +log('Test with correct credentials (no password, non empty)') +esme_no_pwd.set_password('foobar') +esme_no_pwd.connect() +esme_no_pwd.disconnect() + +log('Test with correct credentials') +esme.connect() +esme.disconnect() + +log('Test with bad password, checking for failure') +correct_password = esme.password +new_password = 'barfoo' if correct_password == 'foobar' else 'foobar' +esme.set_password(new_password) +esme.run_method_expect_failure(SMPP_ESME_RINVPASWD, esme.connect) +esme.set_password(correct_password) + +log('Test with bad system_id, checking for failure') +correct_system_id = esme.system_id +new_system_id = 'barfoo' if correct_system_id == 'foobar' else 'foobar' +esme.set_system_id(new_system_id) +esme.run_method_expect_failure(SMPP_ESME_RINVSYSID, esme.connect) +esme.set_system_id(correct_system_id) diff --git a/suites/aoip_smpp/esme_ms_sms.py b/suites/aoip_smpp/esme_ms_sms.py new file mode 100755 index 0000000..7f9ef18 --- /dev/null +++ b/suites/aoip_smpp/esme_ms_sms.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 + +# This test checks following use-cases: +# * SMPP interface of SMSC accepts SMPP clients (ESMEs) with password previously +# defined in its configuration file. +# * ESME can send an SMS to an already registered MS when SMSC is in 'forward' mode. + +from osmo_gsm_tester.test import * + +SMPP_ESME_RINVDSTADR = 0x0000000B + +hlr = suite.hlr() +bts = suite.bts() +mgcpgw = suite.mgcpgw(bts_ip=bts.remote_addr()) +msc = suite.msc(hlr, mgcpgw) +bsc = suite.bsc(msc) +stp = suite.stp() +bsc.bts_add(bts) + +ms = suite.modem() +esme = suite.esme() +msc.smsc.esme_add(esme) + +hlr.start() +stp.start() +msc.start() +mgcpgw.start() +bsc.start() +bts.start() + +esme.connect() +hlr.subscriber_add(ms) +ms.connect(msc.mcc_mnc()) + +ms.log_info() +print('waiting for modem to attach...') +wait(ms.is_connected, msc.mcc_mnc()) +wait(msc.subscriber_attached, ms) + +print('sending first sms...') +msg = Sms(esme.msisdn, ms.msisdn, 'smpp send message') +esme.sms_send(msg) +wait(ms.sms_was_received, msg) + +print('sending second sms (unicode chars not in gsm aplhabet)...') +msg = Sms(esme.msisdn, ms.msisdn, 'chars:[кизаçйж]') +esme.sms_send(msg) +wait(ms.sms_was_received, msg) + +# FIXME: This test is not failing with error but succeeds, need to check why: (forward vs store policy?) +# wrong_msisdn = ms.msisdn + esme.msisdn +# print('sending third sms (with wrong msisdn %s)' % wrong_msisdn) +# msg = Sms(esme.msisdn, wrong_msisdn, 'smpp message with wrong dest') +# esme.run_method_expect_failure(SMPP_ESME_RINVDSTADR, esme.sms_send, msg) + +esme.disconnect() diff --git a/suites/aoip_smpp/suite.conf b/suites/aoip_smpp/suite.conf new file mode 100644 index 0000000..46f8d09 --- /dev/null +++ b/suites/aoip_smpp/suite.conf @@ -0,0 +1,10 @@ +resources: + ip_address: + - times: 5 # msc, bsc, hlr, stp, mgw + bts: + - times: 1 + modem: + - times: 1 + +defaults: + timeout: 60s diff --git a/suites/smpp/esme_connect_policy_acceptall.py b/suites/smpp/esme_connect_policy_acceptall.py new file mode 100755 index 0000000..d22703d --- /dev/null +++ b/suites/smpp/esme_connect_policy_acceptall.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 + +# This test checks following use-cases while in 'accept-all' policy: +# * SMPP interface of SMSC accepts SMPP clients (ESMEs) which do not appear on +# the config file + +from osmo_gsm_tester.test import * + +nitb = suite.nitb() +smsc = nitb.smsc +esme = suite.esme() + +# Here we deliberately omit calling smsc.esme_add() to avoid having it included +# in the smsc config. +smsc.set_smsc_policy(smsc.SMSC_POLICY_ACCEPT_ALL) +esme.set_smsc(smsc) + +nitb.start() + +# Due to accept-all policy, connect() should work even if we didn't previously +# configure the esme in the smsc, no matter the system_id / password we use. +log('Test connect with non-empty values in system_id and password') +esme.set_system_id('foo') +esme.set_password('bar') +esme.connect() +esme.disconnect() + +log('Test connect with empty values in system_id and password') +esme.set_system_id('') +esme.set_password('') +esme.connect() +esme.disconnect() diff --git a/suites/smpp/esme_connect_policy_closed.py b/suites/smpp/esme_connect_policy_closed.py new file mode 100755 index 0000000..7fac276 --- /dev/null +++ b/suites/smpp/esme_connect_policy_closed.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +# This test checks following use-cases while in 'closed' policy: +# * SMPP interface of SMSC accepts SMPP clients (ESMEs) with password previously +# defined in its configuration file. +# * SMPP interface of SMSC rejects ESMEs with known system id but wrong password. +# * SMPP interface of SMSC rejects ESEMs with unknown system id + +from osmo_gsm_tester.test import * + +SMPP_ESME_RINVPASWD = 0x0000000E +SMPP_ESME_RINVSYSID = 0x0000000F + +nitb = suite.nitb() +smsc = nitb.smsc +esme = suite.esme() +esme_no_pwd = suite.esme() +esme_no_pwd.set_password('') + +smsc.set_smsc_policy(smsc.SMSC_POLICY_CLOSED) +smsc.esme_add(esme) +smsc.esme_add(esme_no_pwd) + +nitb.start() + +log('Test with correct credentials (no password)') +esme_no_pwd.connect() +esme_no_pwd.disconnect() + +log('Test with correct credentials (no password, non empty)') +esme_no_pwd.set_password('foobar') +esme_no_pwd.connect() +esme_no_pwd.disconnect() + +log('Test with correct credentials') +esme.connect() +esme.disconnect() + +log('Test with bad password, checking for failure') +correct_password = esme.password +new_password = 'barfoo' if correct_password == 'foobar' else 'foobar' +esme.set_password(new_password) +esme.run_method_expect_failure(SMPP_ESME_RINVPASWD, esme.connect) +esme.set_password(correct_password) + +log('Test with bad system_id, checking for failure') +correct_system_id = esme.system_id +new_system_id = 'barfoo' if correct_system_id == 'foobar' else 'foobar' +esme.set_system_id(new_system_id) +esme.run_method_expect_failure(SMPP_ESME_RINVSYSID, esme.connect) +esme.set_system_id(correct_system_id) diff --git a/suites/smpp/esme_ms_sms.py b/suites/smpp/esme_ms_sms.py new file mode 100755 index 0000000..bc9d7d4 --- /dev/null +++ b/suites/smpp/esme_ms_sms.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 + +# This test checks following use-cases: +# * SMPP interface of SMSC accepts SMPP clients (ESMEs) with password previously +# defined in its configuration file. +# * ESME can send an SMS to an already registered MS when SMSC is in 'forward' mode. + +from osmo_gsm_tester.test import * + +SMPP_ESME_RINVDSTADR = 0x0000000B + +nitb = suite.nitb() +bts = suite.bts() +ms = suite.modem() +esme = suite.esme() + +print('start nitb and bts...') +nitb.bts_add(bts) +nitb.smsc.esme_add(esme) +nitb.start() +bts.start() + +esme.connect() +nitb.subscriber_add(ms) +ms.connect(nitb.mcc_mnc()) + +ms.log_info() +print('waiting for modem to attach...') +wait(ms.is_connected, nitb.mcc_mnc()) +wait(nitb.subscriber_attached, ms) + +print('sending first sms...') +msg = Sms(esme.msisdn, ms.msisdn, 'smpp send message') +esme.sms_send(msg) +wait(ms.sms_was_received, msg) + +print('sending second sms (unicode chars not in gsm aplhabet)...') +msg = Sms(esme.msisdn, ms.msisdn, 'chars:[кизаçйж]') +esme.sms_send(msg) +wait(ms.sms_was_received, msg) + + +# FIXME: This test is not failing with error but succeeds, need to check why: (forward vs store policy?) +# wrong_msisdn = ms.msisdn + esme.msisdn +# print('sending third sms (with wrong msisdn %s)' % wrong_msisdn) +# msg = Sms(esme.msisdn, wrong_msisdn, 'smpp message with wrong dest') +# esme.run_method_expect_failure(SMPP_ESME_RINVDSTADR, esme.sms_send, msg) + +esme.disconnect() diff --git a/suites/smpp/suite.conf b/suites/smpp/suite.conf new file mode 100644 index 0000000..eb59abb --- /dev/null +++ b/suites/smpp/suite.conf @@ -0,0 +1,10 @@ +resources: + ip_address: + - times: 1 + bts: + - times: 1 + modem: + - times: 1 + +defaults: + timeout: 60s |