From 69488f6d8ae8e7a82c4b136bd0408c6c7d59378b Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Tue, 7 Apr 2020 16:40:41 +0200 Subject: Move suites/ dir inside example/ example/paths.conf and documentation are updated accordingly. Test suites should have been moved a long time ago, since the they are user or setup-specific based on what needs to be tested. Change-Id: I154b19979b545deba8b232b60172903f63fd9e28 --- example/paths.conf | 2 +- example/suites/4g/iperf3_dl.py | 49 +++++++ example/suites/4g/iperf3_ul.py | 49 +++++++ example/suites/4g/ping.py | 25 ++++ example/suites/4g/suite.conf | 12 ++ example/suites/debug/interactive.py | 163 +++++++++++++++++++++ example/suites/debug/suite.conf | 7 + example/suites/dynts/suite.conf | 10 ++ example/suites/dynts/switch_tch_pdch.py | 98 +++++++++++++ example/suites/encryption/lib/testlib.py | 54 +++++++ example/suites/encryption/register_a5_0_authopt.py | 8 + example/suites/encryption/register_a5_0_authreq.py | 8 + example/suites/encryption/register_a5_1_authreq.py | 8 + example/suites/encryption/register_a5_3_authreq.py | 8 + example/suites/encryption/suite.conf | 16 ++ example/suites/gprs/cs_paging_gprs_active.py | 38 +++++ example/suites/gprs/iperf3.py | 8 + example/suites/gprs/iperf3m4.py | 8 + example/suites/gprs/lib/testlib.py | 116 +++++++++++++++ example/suites/gprs/ping.py | 71 +++++++++ example/suites/gprs/ping_idle_ping.py | 81 ++++++++++ example/suites/gprs/suite.conf | 13 ++ example/suites/nitb_debug/error.py | 5 + example/suites/nitb_debug/fail.py | 5 + example/suites/nitb_debug/fail_raise.py | 8 + example/suites/nitb_debug/interactive.py | 111 ++++++++++++++ example/suites/nitb_debug/pass.py | 5 + example/suites/nitb_debug/suite.conf | 10 ++ example/suites/nitb_netreg/register.py | 22 +++ example/suites/nitb_netreg/register_default.py | 22 +++ example/suites/nitb_netreg/suite.conf | 10 ++ .../nitb_netreg_mass/register_default_mass.py | 53 +++++++ example/suites/nitb_netreg_mass/suite.conf | 11 ++ .../nitb_smpp/esme_connect_policy_acceptall.py | 32 ++++ .../suites/nitb_smpp/esme_connect_policy_closed.py | 51 +++++++ .../suites/nitb_smpp/esme_ms_sms_storeforward.py | 53 +++++++ .../suites/nitb_smpp/esme_ms_sms_transaction.py | 49 +++++++ example/suites/nitb_smpp/suite.conf | 12 ++ example/suites/nitb_sms/mo_mt_sms.py | 30 ++++ example/suites/nitb_sms/suite.conf | 12 ++ example/suites/nitb_ussd/assert_extension.py | 37 +++++ example/suites/nitb_ussd/suite.conf | 12 ++ .../suites/smpp/esme_connect_policy_acceptall.py | 38 +++++ example/suites/smpp/esme_connect_policy_closed.py | 59 ++++++++ example/suites/smpp/esme_ms_sms_storeforward.py | 69 +++++++++ example/suites/smpp/esme_ms_sms_transaction.py | 59 ++++++++ example/suites/smpp/suite.conf | 12 ++ example/suites/sms/mo_mt_sms.py | 41 ++++++ example/suites/sms/suite.conf | 9 ++ example/suites/ussd/assert_extension.py | 50 +++++++ example/suites/ussd/suite.conf | 9 ++ example/suites/voice/lib/testlib.py | 68 +++++++++ example/suites/voice/mo_mt_call.py | 8 + example/suites/voice/mo_mt_call_osmux.py | 8 + example/suites/voice/suite.conf | 9 ++ 55 files changed, 1840 insertions(+), 1 deletion(-) create mode 100755 example/suites/4g/iperf3_dl.py create mode 100755 example/suites/4g/iperf3_ul.py create mode 100755 example/suites/4g/ping.py create mode 100644 example/suites/4g/suite.conf create mode 100755 example/suites/debug/interactive.py create mode 100644 example/suites/debug/suite.conf create mode 100644 example/suites/dynts/suite.conf create mode 100755 example/suites/dynts/switch_tch_pdch.py create mode 100644 example/suites/encryption/lib/testlib.py create mode 100755 example/suites/encryption/register_a5_0_authopt.py create mode 100755 example/suites/encryption/register_a5_0_authreq.py create mode 100755 example/suites/encryption/register_a5_1_authreq.py create mode 100755 example/suites/encryption/register_a5_3_authreq.py create mode 100644 example/suites/encryption/suite.conf create mode 100755 example/suites/gprs/cs_paging_gprs_active.py create mode 100755 example/suites/gprs/iperf3.py create mode 100755 example/suites/gprs/iperf3m4.py create mode 100644 example/suites/gprs/lib/testlib.py create mode 100755 example/suites/gprs/ping.py create mode 100755 example/suites/gprs/ping_idle_ping.py create mode 100644 example/suites/gprs/suite.conf create mode 100644 example/suites/nitb_debug/error.py create mode 100644 example/suites/nitb_debug/fail.py create mode 100644 example/suites/nitb_debug/fail_raise.py create mode 100755 example/suites/nitb_debug/interactive.py create mode 100644 example/suites/nitb_debug/pass.py create mode 100644 example/suites/nitb_debug/suite.conf create mode 100755 example/suites/nitb_netreg/register.py create mode 100755 example/suites/nitb_netreg/register_default.py create mode 100644 example/suites/nitb_netreg/suite.conf create mode 100644 example/suites/nitb_netreg_mass/register_default_mass.py create mode 100644 example/suites/nitb_netreg_mass/suite.conf create mode 100755 example/suites/nitb_smpp/esme_connect_policy_acceptall.py create mode 100755 example/suites/nitb_smpp/esme_connect_policy_closed.py create mode 100755 example/suites/nitb_smpp/esme_ms_sms_storeforward.py create mode 100755 example/suites/nitb_smpp/esme_ms_sms_transaction.py create mode 100644 example/suites/nitb_smpp/suite.conf create mode 100755 example/suites/nitb_sms/mo_mt_sms.py create mode 100644 example/suites/nitb_sms/suite.conf create mode 100755 example/suites/nitb_ussd/assert_extension.py create mode 100644 example/suites/nitb_ussd/suite.conf create mode 100755 example/suites/smpp/esme_connect_policy_acceptall.py create mode 100755 example/suites/smpp/esme_connect_policy_closed.py create mode 100755 example/suites/smpp/esme_ms_sms_storeforward.py create mode 100755 example/suites/smpp/esme_ms_sms_transaction.py create mode 100644 example/suites/smpp/suite.conf create mode 100755 example/suites/sms/mo_mt_sms.py create mode 100644 example/suites/sms/suite.conf create mode 100755 example/suites/ussd/assert_extension.py create mode 100644 example/suites/ussd/suite.conf create mode 100644 example/suites/voice/lib/testlib.py create mode 100755 example/suites/voice/mo_mt_call.py create mode 100755 example/suites/voice/mo_mt_call_osmux.py create mode 100644 example/suites/voice/suite.conf (limited to 'example') diff --git a/example/paths.conf b/example/paths.conf index 554d942..27c5818 100644 --- a/example/paths.conf +++ b/example/paths.conf @@ -1,3 +1,3 @@ state_dir: '/var/tmp/osmo-gsm-tester/state' -suites_dir: '../suites' +suites_dir: './suites' scenarios_dir: './scenarios' diff --git a/example/suites/4g/iperf3_dl.py b/example/suites/4g/iperf3_dl.py new file mode 100755 index 0000000..88ae82d --- /dev/null +++ b/example/suites/4g/iperf3_dl.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +def print_result_node(result, node_str): + sent = result['end']['sum_sent'] + recv = result['end']['sum_received'] + print("Result %s:" % node_str) + print("\tSEND: %d KB, %d kbps, %d seconds (%s retrans)" % (sent['bytes']/1000, sent['bits_per_second']/1000, sent['seconds'], str(sent.get('retransmits', 'unknown')))) + print("\tRECV: %d KB, %d kbps, %d seconds" % (recv['bytes']/1000, recv['bits_per_second']/1000, recv['seconds'])) + +def print_results(cli_res, srv_res): + print_result_node(cli_res, 'client') + print_result_node(srv_res, 'server') + +epc = suite.epc() +enb = suite.enb() +ue = suite.modem() +iperf3srv = suite.iperf3srv({'addr': epc.tun_addr()}) +iperf3srv.set_run_node(epc.run_node()) +iperf3cli = iperf3srv.create_client() +iperf3cli.set_run_node(ue.run_node()) + +epc.subscriber_add(ue) +epc.start() +enb.ue_add(ue) +enb.start(epc) + +print('waiting for ENB to connect to EPC...') +wait(epc.enb_is_connected, enb) +print('ENB is connected to EPC') + +ue.connect(enb) + +iperf3srv.start() +proc = iperf3cli.prepare_test_proc(True, ue.netns()) + +print('waiting for UE to attach...') +wait(ue.is_connected, None) +print('UE is attached') + +print("Running iperf3 client to %s through %s" % (str(iperf3cli), ue.netns())) +proc.launch_sync() +iperf3srv.stop() +print_results(iperf3cli.get_results(), iperf3srv.get_results()) + +max_rate = enb.ue_max_rate(downlink=True) +res_str = ue.verify_metric(max_rate * 0.8, operation='avg', metric='dl_brate', criterion='gt') +print(res_str) +test.set_report_stdout(res_str) diff --git a/example/suites/4g/iperf3_ul.py b/example/suites/4g/iperf3_ul.py new file mode 100755 index 0000000..597b50d --- /dev/null +++ b/example/suites/4g/iperf3_ul.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +def print_result_node(result, node_str): + sent = result['end']['sum_sent'] + recv = result['end']['sum_received'] + print("Result %s:" % node_str) + print("\tSEND: %d KB, %d kbps, %d seconds (%s retrans)" % (sent['bytes']/1000, sent['bits_per_second']/1000, sent['seconds'], str(sent.get('retransmits', 'unknown')))) + print("\tRECV: %d KB, %d kbps, %d seconds" % (recv['bytes']/1000, recv['bits_per_second']/1000, recv['seconds'])) + +def print_results(cli_res, srv_res): + print_result_node(cli_res, 'client') + print_result_node(srv_res, 'server') + +epc = suite.epc() +enb = suite.enb() +ue = suite.modem() +iperf3srv = suite.iperf3srv({'addr': epc.tun_addr()}) +iperf3srv.set_run_node(epc.run_node()) +iperf3cli = iperf3srv.create_client() +iperf3cli.set_run_node(ue.run_node()) + +epc.subscriber_add(ue) +epc.start() +enb.ue_add(ue) +enb.start(epc) + +print('waiting for ENB to connect to EPC...') +wait(epc.enb_is_connected, enb) +print('ENB is connected to EPC') + +ue.connect(enb) + +iperf3srv.start() +proc = iperf3cli.prepare_test_proc(False, ue.netns()) + +print('waiting for UE to attach...') +wait(ue.is_connected, None) +print('UE is attached') + +print("Running iperf3 client to %s through %s" % (str(iperf3cli), ue.netns())) +proc.launch_sync() +iperf3srv.stop() +print_results(iperf3cli.get_results(), iperf3srv.get_results()) + +max_rate = enb.ue_max_rate(downlink=False) +res_str = ue.verify_metric(max_rate * 0.8, operation='avg', metric='ul_brate', criterion='gt') +print(res_str) +test.set_report_stdout(res_str) diff --git a/example/suites/4g/ping.py b/example/suites/4g/ping.py new file mode 100755 index 0000000..17eee78 --- /dev/null +++ b/example/suites/4g/ping.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +epc = suite.epc() +enb = suite.enb() +ue = suite.modem() + +epc.subscriber_add(ue) +epc.start() +enb.ue_add(ue) +enb.start(epc) + +print('waiting for ENB to connect to EPC...') +wait(epc.enb_is_connected, enb) +print('ENB is connected to EPC') + +ue.connect(enb) +print('waiting for UE to attach...') +wait(ue.is_connected, None) +print('UE is attached') + +proc = ue.run_netns_wait('ping', ('ping', '-c', '10', epc.tun_addr())) +output = proc.get_stdout() +print(output) +test.set_report_stdout(output) diff --git a/example/suites/4g/suite.conf b/example/suites/4g/suite.conf new file mode 100644 index 0000000..e439e99 --- /dev/null +++ b/example/suites/4g/suite.conf @@ -0,0 +1,12 @@ +resources: + run_node: # for EPC + - times: 1 + enb: + - times: 1 + modem: + - times: 1 + features: + - 4g + +defaults: + timeout: 180s diff --git a/example/suites/debug/interactive.py b/example/suites/debug/interactive.py new file mode 100755 index 0000000..89f967f --- /dev/null +++ b/example/suites/debug/interactive.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * +hlr = suite.hlr() +bts = suite.bts() +pcu = bts.pcu() +mgw_msc = suite.mgw() +mgw_bsc = suite.mgw() +stp = suite.stp() +ggsn = suite.ggsn() +sgsn = suite.sgsn(hlr, ggsn) +msc = suite.msc(hlr, mgw_msc, stp) +bsc = suite.bsc(msc, mgw_bsc, stp) + +modems = suite.modems(int(prompt('How many modems?'))) + +bsc.bts_add(bts) +sgsn.bts_add(bts) + +hlr.start() +stp.start() +ggsn.start() +sgsn.start() +msc.start() +mgw_msc.start() +mgw_bsc.start() +bsc.start() + +bts.start() +print('Waiting for bts to connect to bsc...') +wait(bsc.bts_is_connected, bts) +print('Waiting for bts to be ready...') +wait(bts.ready_for_pcu) +pcu.start() + +for m in modems: + hlr.subscriber_add(m) + m.connect(msc.mcc_mnc()) + +while True: + cmd = prompt('Enter command: (q)uit (d)ebug (s)ms (g)et-registered (w)ait-registered, call-list [], call-dial , call-wait-incoming , call-answer , call-hangup , ussd , data-attach, data-wait, data-detach, data-activate') + cmd = cmd.strip().lower() + + if not cmd: + continue + + params = cmd.split() + + if 'quit'.startswith(cmd): + break + + elif 'debug'.startswith(cmd): + import pdb; pdb.set_trace() + + elif 'wait-registered'.startswith(cmd): + try: + for m in modems: + wait(m.is_connected, msc.mcc_mnc()) + wait(msc.subscriber_attached, *modems) + except Timeout: + print('Timeout while waiting for registration.') + + elif 'get-registered'.startswith(cmd): + print(msc.imsi_list_attached()) + print('RESULT: %s' % + ('All modems are registered.' if msc.subscriber_attached(*modems) + else 'Some modem(s) not registered yet.')) + + elif 'sms'.startswith(cmd): + for mo in modems: + for mt in modems: + mo.sms_send(mt.msisdn, 'to ' + mt.name()) + + elif cmd.startswith('call-list'): + if len(params) != 1 and len(params) != 2: + print('wrong format') + continue + for ms in modems: + if len(params) == 1 or str(ms.msisdn) == params[1]: + print('call-list: %r %r' % (ms.name(), ms.call_id_list())) + + elif cmd.startswith('call-dial'): + if len(params) != 3: + print('wrong format') + continue + src_msisdn, dst_msisdn = params[1:] + for mo in modems: + if str(mo.msisdn) == src_msisdn: + print('dialing %s->%s' % (src_msisdn, dst_msisdn)) + call_id = mo.call_dial(dst_msisdn) + print('dial success: call_id=%r' % call_id) + + elif cmd.startswith('call-wait-incoming'): + if len(params) != 3: + print('wrong format') + continue + src_msisdn, dst_msisdn = params[1:] + for mt in modems: + if str(mt.msisdn) == dst_msisdn: + print('waiting for incoming %s->%s' % (src_msisdn, dst_msisdn)) + call_id = mt.call_wait_incoming(src_msisdn) + print('incoming call success: call_id=%r' % call_id) + + elif cmd.startswith('call-answer'): + if len(params) != 3: + print('wrong format') + continue + mt_msisdn, call_id = params[1:] + for mt in modems: + if str(mt.msisdn) == mt_msisdn: + print('answering %s %r' % (mt.name(), call_id)) + mt.call_answer(call_id) + + elif cmd.startswith('call-hangup'): + if len(params) != 3: + print('wrong format') + continue + ms_msisdn, call_id = params[1:] + for ms in modems: + if str(ms.msisdn) == ms_msisdn: + print('hanging up %s %r' % (ms.name(), call_id)) + ms.call_hangup(call_id) + + elif cmd.startswith('ussd'): + if len(params) != 2: + print('wrong format') + continue + ussd_cmd = params[1] + for ms in modems: + print('modem %s: ussd %s' % (ms.name(), ussd_cmd)) + response = ms.ussd_send(ussd_cmd) + print('modem %s: response=%r' % (ms.name(), response)) + + elif cmd.startswith('data-attach'): + if len(params) != 1: + print('wrong format') + continue + for ms in modems: + print('modem %s: attach' % ms.name()) + ms.attach() + wait(ms.is_attached) + print('modem %s: attached' % ms.name()) + + elif cmd.startswith('data-detach'): + if len(params) != 1: + print('wrong format') + continue + for ms in modems: + print('modem %s: detach' % ms.name()) + ms.attach() + wait(lambda: not ms.is_attached()) + print('modem %s: detached' % ms.name()) + + elif cmd.startswith('data-activate'): + if len(params) != 1: + print('wrong format') + continue + for ms in modems: + print('modem %s: activate' % ms.name()) + response = ms.activate_context() + print('modem %s: response=%r' % (ms.name(), response)) + + else: + print('Unknown command: %s' % cmd) diff --git a/example/suites/debug/suite.conf b/example/suites/debug/suite.conf new file mode 100644 index 0000000..2f36e1d --- /dev/null +++ b/example/suites/debug/suite.conf @@ -0,0 +1,7 @@ +resources: + ip_address: + - times: 8 + bts: + - times: 1 + modem: + - times: 4 diff --git a/example/suites/dynts/suite.conf b/example/suites/dynts/suite.conf new file mode 100644 index 0000000..3b32480 --- /dev/null +++ b/example/suites/dynts/suite.conf @@ -0,0 +1,10 @@ +resources: + ip_address: + - times: 8 # msc, bsc, hlr, stp, mgw*2, sgsn, ggsn + bts: + - times: 1 + modem: + - times: 2 + features: + - gprs + - voice diff --git a/example/suites/dynts/switch_tch_pdch.py b/example/suites/dynts/switch_tch_pdch.py new file mode 100755 index 0000000..f0bbd38 --- /dev/null +++ b/example/suites/dynts/switch_tch_pdch.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + + +def activate_pdp(ms_mo, ms_mt): + # We need to use inet46 since ofono qmi only uses ipv4v6 eua (OS#2713) + ctx_id_v4_mo = ms_mo.activate_context(apn='inet46', protocol=ms_mo.CTX_PROT_IPv4) + print('ms_mo pdp ctx %r activated' % repr(ctx_id_v4_mo)) + ctx_id_v4_mt = ms_mt.activate_context(apn='inet46', protocol=ms_mt.CTX_PROT_IPv4) + print('ms_mt pdp ctx %r activated' % repr(ctx_id_v4_mt)) + sleep(5) + ms_mo.deactivate_context(ctx_id_v4_mo) + ms_mt.deactivate_context(ctx_id_v4_mt) + +def make_call(ms_mo, ms_mt): + assert len(ms_mo.call_id_list()) == 0 and len(ms_mt.call_id_list()) == 0 + mo_cid = ms_mo.call_dial(ms_mt) + mt_cid = ms_mt.call_wait_incoming(ms_mo) + print('dial success') + + assert not ms_mo.call_is_active(mo_cid) and not ms_mt.call_is_active(mt_cid) + ms_mt.call_answer(mt_cid) + wait(ms_mo.call_is_active, mo_cid) + wait(ms_mt.call_is_active, mt_cid) + print('answer success, call established and ongoing') + + sleep(5) # maintain the call active for 5 seconds + + assert ms_mo.call_is_active(mo_cid) and ms_mt.call_is_active(mt_cid) + ms_mo.call_hangup(mo_cid) + ms_mt.call_hangup(mt_cid) + wait(lambda: len(ms_mo.call_id_list()) == 0 and len(ms_mt.call_id_list()) == 0) + print('hangup success') + +hlr = suite.hlr() +bts = suite.bts() +pcu = bts.pcu() +mgw_msc = suite.mgw() +mgw_bsc = suite.mgw() +stp = suite.stp() +ggsn = suite.ggsn() +sgsn = suite.sgsn(hlr, ggsn) +msc = suite.msc(hlr, mgw_msc, stp) +bsc = suite.bsc(msc, mgw_bsc, stp) +ms_mo = suite.modem() +ms_mt = suite.modem() + +bsc.bts_add(bts) +sgsn.bts_add(bts) + +print('start network...') +hlr.start() +stp.start() +ggsn.start() +sgsn.start() +msc.start() +mgw_msc.start() +mgw_bsc.start() +bsc.start() + +bts.start() +wait(bsc.bts_is_connected, bts) +print('Waiting for bts to be ready...') +wait(bts.ready_for_pcu) +pcu.start() + +hlr.subscriber_add(ms_mo) +hlr.subscriber_add(ms_mt) + +ms_mo.connect(msc.mcc_mnc()) +ms_mt.connect(msc.mcc_mnc()) +ms_mo.attach() +ms_mt.attach() + +ms_mo.log_info() +ms_mt.log_info() + +print('waiting for modems to attach...') +wait(ms_mo.is_connected, msc.mcc_mnc()) +wait(ms_mt.is_connected, msc.mcc_mnc()) +wait(msc.subscriber_attached, ms_mo) +wait(msc.subscriber_attached, ms_mt) + +print('waiting for modems to attach to data services...') +wait(ms_mo.is_attached) +wait(ms_mt.is_attached) + +print('1: activate_pdp') +activate_pdp(ms_mo, ms_mt) +print('2: make_call') +make_call(ms_mo, ms_mt) +print('3: Wait 30 seconds to let PCU handle the PDCH channels again') +sleep(30) +print('3: activate_pdp') +activate_pdp(ms_mo, ms_mt) +print('4: make_call') +make_call(ms_mo, ms_mt) +print('Done!') diff --git a/example/suites/encryption/lib/testlib.py b/example/suites/encryption/lib/testlib.py new file mode 100644 index 0000000..3948941 --- /dev/null +++ b/example/suites/encryption/lib/testlib.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +def encryption_test_setup_run(enable_auth, algo): + hlr = suite.hlr() + bts = suite.bts() + mgw_msc = suite.mgw() + mgw_bsc = suite.mgw() + stp = suite.stp() + msc = suite.msc(hlr, mgw_msc, stp) + bsc = suite.bsc(msc, mgw_bsc, stp) + ms = suite.modem() + + print('start network...') + msc.set_authentication(enable_auth) + msc.set_encryption(algo) + bsc.set_encryption(algo) + hlr.start() + stp.start() + msc.start() + mgw_msc.start() + mgw_bsc.start() + bsc.bts_add(bts) + bsc.start() + bts.start() + wait(bsc.bts_is_connected, bts) + + ms.log_info() + good_ki = ms.ki() + bad_ki = ("%1X" % (int(good_ki[0], 16) ^ 0x01)) + good_ki[1:] + + print('KI changed: ' + good_ki + " => " + bad_ki) + ms.set_ki(bad_ki) + hlr.subscriber_add(ms) + if enable_auth: + print('Attempt connection with wrong KI...') + ms.connect(msc.mcc_mnc()) + + sleep(40) # TODO: read pcap or CTRL interface and look for Rejected? (gsm_a.dtap.msg_mm_type == 0x04) + print('Asserting modem did not register') + # FIXME: this can fail because ofono qmi signals registered before being accepted by network. See OS#2458 + # assert not ms.is_connected(msc.mcc_mnc()) + assert not msc.subscriber_attached(ms) + + hlr.subscriber_delete(ms) + print('KI changed: ' + bad_ki + " => " + good_ki) + ms.set_ki(good_ki) + hlr.subscriber_add(ms, ms.msisdn) + print('Attempt connection with correct KI...') + else: + print('Attempt connection with wrong KI, should work as it is not used...') + ms.connect(msc.mcc_mnc()) + wait(ms.is_connected, msc.mcc_mnc()) + wait(msc.subscriber_attached, ms) diff --git a/example/suites/encryption/register_a5_0_authopt.py b/example/suites/encryption/register_a5_0_authopt.py new file mode 100755 index 0000000..1b7f471 --- /dev/null +++ b/example/suites/encryption/register_a5_0_authopt.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +import testlib +suite.test_import_modules_register_for_cleanup(testlib) +from testlib import encryption_test_setup_run + +encryption_test_setup_run(False, 'a5_0') diff --git a/example/suites/encryption/register_a5_0_authreq.py b/example/suites/encryption/register_a5_0_authreq.py new file mode 100755 index 0000000..feca525 --- /dev/null +++ b/example/suites/encryption/register_a5_0_authreq.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +import testlib +suite.test_import_modules_register_for_cleanup(testlib) +from testlib import encryption_test_setup_run + +encryption_test_setup_run(True, 'a5_0') diff --git a/example/suites/encryption/register_a5_1_authreq.py b/example/suites/encryption/register_a5_1_authreq.py new file mode 100755 index 0000000..077819b --- /dev/null +++ b/example/suites/encryption/register_a5_1_authreq.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +import testlib +suite.test_import_modules_register_for_cleanup(testlib) +from testlib import encryption_test_setup_run + +encryption_test_setup_run(True, 'a5_1') diff --git a/example/suites/encryption/register_a5_3_authreq.py b/example/suites/encryption/register_a5_3_authreq.py new file mode 100755 index 0000000..219c109 --- /dev/null +++ b/example/suites/encryption/register_a5_3_authreq.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +import testlib +suite.test_import_modules_register_for_cleanup(testlib) +from testlib import encryption_test_setup_run + +encryption_test_setup_run(True, 'a5_3') diff --git a/example/suites/encryption/suite.conf b/example/suites/encryption/suite.conf new file mode 100644 index 0000000..18e94a3 --- /dev/null +++ b/example/suites/encryption/suite.conf @@ -0,0 +1,16 @@ +resources: + ip_address: + - times: 6 # msc, bsc, hlr, stp, mgw*2 + bts: + - times: 1 + ciphers: + - a5_0 + - a5_1 + modem: + - times: 1 + ciphers: + - a5_0 + - a5_1 + +defaults: + timeout: 120s diff --git a/example/suites/gprs/cs_paging_gprs_active.py b/example/suites/gprs/cs_paging_gprs_active.py new file mode 100755 index 0000000..b7dead2 --- /dev/null +++ b/example/suites/gprs/cs_paging_gprs_active.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 + +# Following test verifies CS paging works when MS is GPRS attached. +# See OS#2204 for more information. + +from osmo_gsm_tester.testenv import * + +import testlib +suite.test_import_modules_register_for_cleanup(testlib) +from testlib import setup_run_iperf3_test_parallel + +def ready_cb_place_voicecall(ms_li): + print('waiting a few secs to make sure iperf3 test is running') + sleep(2) + # At this point in time, TBF should be enabled on both MS since they are sending/receiving data. + print('iperf3 running, let\'s place a call') + ms_mo = ms_li[0] + ms_mt = ms_li[1] + assert len(ms_mo.call_id_list()) == 0 and len(ms_mt.call_id_list()) == 0 + mo_cid = ms_mo.call_dial(ms_mt) + mt_cid = ms_mt.call_wait_incoming(ms_mo) + print('dial success') + + assert not ms_mo.call_is_active(mo_cid) and not ms_mt.call_is_active(mt_cid) + ms_mt.call_answer(mt_cid) + wait(ms_mo.call_is_active, mo_cid) + wait(ms_mt.call_is_active, mt_cid) + print('answer success, call established and ongoing') + + sleep(5) # maintain the call active for 5 seconds + + assert ms_mo.call_is_active(mo_cid) and ms_mt.call_is_active(mt_cid) + ms_mt.call_hangup(mt_cid) + wait(lambda: len(ms_mo.call_id_list()) == 0 and len(ms_mt.call_id_list()) == 0) + print('hangup success') + + +setup_run_iperf3_test_parallel(2, ready_cb=ready_cb_place_voicecall) diff --git a/example/suites/gprs/iperf3.py b/example/suites/gprs/iperf3.py new file mode 100755 index 0000000..e25519a --- /dev/null +++ b/example/suites/gprs/iperf3.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +import testlib +suite.test_import_modules_register_for_cleanup(testlib) +from testlib import setup_run_iperf3_test_parallel + +setup_run_iperf3_test_parallel(1) diff --git a/example/suites/gprs/iperf3m4.py b/example/suites/gprs/iperf3m4.py new file mode 100755 index 0000000..1cc27ed --- /dev/null +++ b/example/suites/gprs/iperf3m4.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +import testlib +suite.test_import_modules_register_for_cleanup(testlib) +from testlib import setup_run_iperf3_test_parallel + +setup_run_iperf3_test_parallel(4) diff --git a/example/suites/gprs/lib/testlib.py b/example/suites/gprs/lib/testlib.py new file mode 100644 index 0000000..c1a1bc1 --- /dev/null +++ b/example/suites/gprs/lib/testlib.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +def print_result_node(result, node_str): + sent = result['end']['sum_sent'] + recv = result['end']['sum_received'] + print("Result %s:" % node_str) + print("\tSEND: %d KB, %d kbps, %d seconds (%s retrans)" % (sent['bytes']/1000, sent['bits_per_second']/1000, sent['seconds'], str(sent.get('retransmits', 'unknown')))) + print("\tRECV: %d KB, %d kbps, %d seconds" % (recv['bytes']/1000, recv['bits_per_second']/1000, recv['seconds'])) + +def print_results(cli_res, srv_res): + print_result_node(cli_res, 'client') + print_result_node(srv_res, 'server') + +def run_iperf3_cli_parallel(iperf3clients, ms_li, ready_cb): + assert len(iperf3clients) == len(ms_li) + procs = [] + for i in range(len(iperf3clients)): + print("Running iperf3 client to %s through %r" % (str(iperf3clients[i]), repr(ms_li[i].tmp_ctx_id))) + procs.append(iperf3clients[i].prepare_test_proc(False, ms_li[i].netns())) + try: + for proc in procs: + proc.launch() + if ready_cb: + ready_cb(ms_li) + for proc in procs: + proc.wait() + except Exception as e: + for proc in procs: + try: + proc.terminate() + except Exception: + print("Exception while terminating process %r" % repr(process)) + raise e + + +def setup_run_iperf3_test_parallel(num_ms, ready_cb=None): + hlr = suite.hlr() + bts = suite.bts() + pcu = bts.pcu() + mgw_msc = suite.mgw() + mgw_bsc = suite.mgw() + stp = suite.stp() + ggsn = suite.ggsn() + sgsn = suite.sgsn(hlr, ggsn) + msc = suite.msc(hlr, mgw_msc, stp) + bsc = suite.bsc(msc, mgw_bsc, stp) + + iperf3srv_addr = suite.ip_address() + servers = [] + clients = [] + ms_li = [] + for i in range(num_ms): + iperf3srv = suite.iperf3srv(iperf3srv_addr) + iperf3srv.set_port(iperf3srv.DEFAULT_SRV_PORT + i) + servers.append(iperf3srv) + + iperf3cli = iperf3srv.create_client() + clients.append(iperf3cli) + + ms = suite.modem() + ms_li.append(ms) + + bsc.bts_add(bts) + sgsn.bts_add(bts) + + for iperf3srv in servers: + print('start iperfv3 server %s...' % str(iperf3srv) ) + iperf3srv.start() + + print('start network...') + hlr.start() + stp.start() + ggsn.start() + sgsn.start() + msc.start() + mgw_msc.start() + mgw_bsc.start() + bsc.start() + + bts.start() + wait(bsc.bts_is_connected, bts) + print('Waiting for bts to be ready...') + wait(bts.ready_for_pcu) + pcu.start() + + for ms in ms_li: + hlr.subscriber_add(ms) + ms.connect(msc.mcc_mnc()) + ms.attach() + ms.log_info() + + print('waiting for modems to attach...') + for ms in ms_li: + wait(ms.is_connected, msc.mcc_mnc()) + wait(msc.subscriber_attached, *ms_li) + + print('waiting for modems to attach to data services...') + for ms in ms_li: + wait(ms.is_attached) + # We need to use inet46 since ofono qmi only uses ipv4v6 eua (OS#2713) + ctx_id_v4 = ms.activate_context(apn='inet46', protocol=ms.CTX_PROT_IPv4) + print("Setting up data plan for %r" % repr(ctx_id_v4)) + ms.setup_context_data_plane(ctx_id_v4) + setattr(ms, 'tmp_ctx_id', ctx_id_v4) + + run_iperf3_cli_parallel(clients, ms_li, ready_cb) + + for i in range(num_ms): + servers[i].stop() + print("Results for %s through %r" % (str(servers[i]), repr(ms_li[i].tmp_ctx_id))) + print_results(clients[i].get_results(), servers[i].get_results()) + + for ms in ms_li: + ms.deactivate_context(ms.tmp_ctx_id) + delattr(ms, 'tmp_ctx_id') diff --git a/example/suites/gprs/ping.py b/example/suites/gprs/ping.py new file mode 100755 index 0000000..22fe80a --- /dev/null +++ b/example/suites/gprs/ping.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +hlr = suite.hlr() +bts = suite.bts() +pcu = bts.pcu() +mgw_msc = suite.mgw() +mgw_bsc = suite.mgw() +stp = suite.stp() +ggsn = suite.ggsn() +sgsn = suite.sgsn(hlr, ggsn) +msc = suite.msc(hlr, mgw_msc, stp) +bsc = suite.bsc(msc, mgw_bsc, stp) +ms = suite.modem() + +bsc.bts_add(bts) +sgsn.bts_add(bts) + +print('start network...') +hlr.start() +stp.start() +ggsn.start() +sgsn.start() +msc.start() +mgw_msc.start() +mgw_bsc.start() +bsc.start() + +bts.start() +wait(bsc.bts_is_connected, bts) +print('Waiting for bts to be ready...') +wait(bts.ready_for_pcu) +pcu.start() + +hlr.subscriber_add(ms) + +ms.connect(msc.mcc_mnc()) +ms.attach() + +ms.log_info() + +print('waiting for modems to attach...') +wait(ms.is_connected, msc.mcc_mnc()) +wait(msc.subscriber_attached, ms) + +print('waiting for modems to attach to data services...') +wait(ms.is_attached) + +# We need to use inet46 since ofono qmi only uses ipv4v6 eua (OS#2713) +ctx_id_v4 = ms.activate_context(apn='inet46', protocol=ms.CTX_PROT_IPv4) +print("Setting up data plan for %r" % repr(ctx_id_v4)) +ms.setup_context_data_plane(ctx_id_v4) +print("Running 10 ping requests for %r" % repr(ctx_id_v4)) +proc = ms.run_netns_wait('ping', ('ping', '-c', '10', ggsn.addr())) +output = proc.get_stdout() +ms.deactivate_context(ctx_id_v4) + +# We need to use inet46 since ofono qmi only uses ipv4v6 eua (OS#2713) +ctx_id_v6 = ms.activate_context(apn='inet46', protocol=ms.CTX_PROT_IPv6) +sleep(5) +# TODO: send ping to server or open TCP conn with a socket in python +ms.deactivate_context(ctx_id_v6) + +# IPv46 (dual) not supported in ofono qmi: org.ofono.Error.Failed: Operation failed (36) +# ctx_id_v46 = ms.activate_context(apn='inet46', protocol=ms.CTX_PROT_IPv46) +# sleep(5) +# TODO: send ping to server or open TCP conn with a socket in python +# ms.deactivate_context(ctx_id_v46) + +print(output) +test.set_report_stdout(output) diff --git a/example/suites/gprs/ping_idle_ping.py b/example/suites/gprs/ping_idle_ping.py new file mode 100755 index 0000000..02e2cdf --- /dev/null +++ b/example/suites/gprs/ping_idle_ping.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 + +# Following test verifies GPRS works fine after MS stays idle (no data +# sent/received) for a long while. +# See OS#3678 and OS#2455 for more information. + +from osmo_gsm_tester.testenv import * + +hlr = suite.hlr() +bts = suite.bts() +pcu = bts.pcu() +mgw_msc = suite.mgw() +mgw_bsc = suite.mgw() +stp = suite.stp() +ggsn = suite.ggsn() +sgsn = suite.sgsn(hlr, ggsn) +msc = suite.msc(hlr, mgw_msc, stp) +bsc = suite.bsc(msc, mgw_bsc, stp) +ms = suite.modem() + +bsc.bts_add(bts) +sgsn.bts_add(bts) + +print('start network...') +hlr.start() +stp.start() +ggsn.start() +sgsn.start() +msc.start() +mgw_msc.start() +mgw_bsc.start() +bsc.start() + +bts.start() +wait(bsc.bts_is_connected, bts) +print('Waiting for bts to be ready...') +wait(bts.ready_for_pcu) +pcu.start() + +hlr.subscriber_add(ms) + +ms.connect(msc.mcc_mnc()) +ms.attach() + +ms.log_info() + +print('waiting for modems to attach...') +wait(ms.is_connected, msc.mcc_mnc()) +wait(msc.subscriber_attached, ms) + +print('waiting for modems to attach to data services...') +wait(ms.is_attached) + +# We need to use inet46 since ofono qmi only uses ipv4v6 eua (OS#2713) +ctx_id_v4 = ms.activate_context(apn='inet46', protocol=ms.CTX_PROT_IPv4) +print("Setting up data plane for %r" % repr(ctx_id_v4)) +ms.setup_context_data_plane(ctx_id_v4) +str = "[1] Running 10 ping requests for %r" % repr(ctx_id_v4) +output = str + '\n' +print(str) +proc = ms.run_netns_wait('ping1', ('ping', '-c', '10', ggsn.addr())) +str = proc.get_stdout() +output += str +print(str) + +str = "Sleeping for 60 seconds" +output += str + '\n' +print(str) +sleep(60) + +str = "[2] Running 10 ping requests for %r" % repr(ctx_id_v4) +output += str + '\n' +print(str) +proc = ms.run_netns_wait('ping2', ('ping', '-c', '10', ggsn.addr())) +str = proc.get_stdout() +output += str +print(str) + +ms.deactivate_context(ctx_id_v4) + +test.set_report_stdout(output) diff --git a/example/suites/gprs/suite.conf b/example/suites/gprs/suite.conf new file mode 100644 index 0000000..d40c1e5 --- /dev/null +++ b/example/suites/gprs/suite.conf @@ -0,0 +1,13 @@ +resources: + ip_address: + - times: 9 # msc, bsc, hlr, stp, mgw*2, sgsn, ggsn, iperf3srv + bts: + - times: 1 + modem: + - times: 2 + features: + - gprs + - voice + - times: 2 + features: + - gprs diff --git a/example/suites/nitb_debug/error.py b/example/suites/nitb_debug/error.py new file mode 100644 index 0000000..032e26c --- /dev/null +++ b/example/suites/nitb_debug/error.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +# This can be used to verify that a test error is reported properly. +assert False diff --git a/example/suites/nitb_debug/fail.py b/example/suites/nitb_debug/fail.py new file mode 100644 index 0000000..a2d9e3a --- /dev/null +++ b/example/suites/nitb_debug/fail.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +# This can be used to verify that a test failure is reported properly. +test.set_fail('ExpectedFail', 'This failure is expected') diff --git a/example/suites/nitb_debug/fail_raise.py b/example/suites/nitb_debug/fail_raise.py new file mode 100644 index 0000000..c30a4f5 --- /dev/null +++ b/example/suites/nitb_debug/fail_raise.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +class ExpectedExn(Exception): + pass + +# This can be used to verify that a test failure is reported properly. +raise ExpectedExn('This failure is expected') diff --git a/example/suites/nitb_debug/interactive.py b/example/suites/nitb_debug/interactive.py new file mode 100755 index 0000000..595cfd9 --- /dev/null +++ b/example/suites/nitb_debug/interactive.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +print('use resources...') +nitb = suite.nitb() +bts = suite.bts() +modems = suite.modems(int(prompt('How many modems?'))) + +print('start nitb and bts...') +nitb.bts_add(bts) +nitb.start() +bts.start() +wait(nitb.bts_is_connected, bts) + +for m in modems: + nitb.subscriber_add(m) + m.connect(nitb.mcc_mnc()) + +while True: + cmd = prompt('Enter command: (q)uit (s)ms (g)et-registered (w)ait-registered, call-list [], call-dial , call-wait-incoming , call-answer , call-hangup , ussd ') + cmd = cmd.strip().lower() + + if not cmd: + continue + + params = cmd.split() + + if 'quit'.startswith(cmd): + break + + elif 'wait-registered'.startswith(cmd): + try: + for m in modems: + wait(m.is_connected, nitb.mcc_mnc()) + wait(nitb.subscriber_attached, *modems) + except Timeout: + print('Timeout while waiting for registration.') + + elif 'get-registered'.startswith(cmd): + print(nitb.imsi_list_attached()) + print('RESULT: %s' % + ('All modems are registered.' if nitb.subscriber_attached(*modems) + else 'Some modem(s) not registered yet.')) + + elif 'sms'.startswith(cmd): + for mo in modems: + for mt in modems: + mo.sms_send(mt.msisdn, 'to ' + mt.name()) + + elif cmd.startswith('call-list'): + if len(params) != 1 and len(params) != 2: + print('wrong format') + continue + for ms in modems: + if len(params) == 1 or str(ms.msisdn) == params[1]: + print('call-list: %r %r' % (ms.name(), ms.call_id_list())) + + elif cmd.startswith('call-dial'): + if len(params) != 3: + print('wrong format') + continue + src_msisdn, dst_msisdn = params[1:] + for mo in modems: + if str(mo.msisdn) == src_msisdn: + print('dialing %s->%s' % (src_msisdn, dst_msisdn)) + call_id = mo.call_dial(dst_msisdn) + print('dial success: call_id=%r' % call_id) + + elif cmd.startswith('call-wait-incoming'): + if len(params) != 3: + print('wrong format') + continue + src_msisdn, dst_msisdn = params[1:] + for mt in modems: + if str(mt.msisdn) == dst_msisdn: + print('waiting for incoming %s->%s' % (src_msisdn, dst_msisdn)) + call_id = mt.call_wait_incoming(src_msisdn) + print('incoming call success: call_id=%r' % call_id) + + elif cmd.startswith('call-answer'): + if len(params) != 3: + print('wrong format') + continue + mt_msisdn, call_id = params[1:] + for mt in modems: + if str(mt.msisdn) == mt_msisdn: + print('answering %s %r' % (mt.name(), call_id)) + mt.call_answer(call_id) + + elif cmd.startswith('call-hangup'): + if len(params) != 3: + print('wrong format') + continue + ms_msisdn, call_id = params[1:] + for ms in modems: + if str(ms.msisdn) == ms_msisdn: + print('hanging up %s %r' % (ms.name(), call_id)) + ms.call_hangup(call_id) + + elif cmd.startswith('ussd'): + if len(params) != 2: + print('wrong format') + continue + ussd_cmd = params[1] + for ms in modems: + print('modem %s: ussd %s' % (ms.name(), ussd_cmd)) + response = ms.ussd_send(ussd_cmd) + print('modem %s: response=%r' % (ms.name(), response)) + + else: + print('Unknown command: %s' % cmd) diff --git a/example/suites/nitb_debug/pass.py b/example/suites/nitb_debug/pass.py new file mode 100644 index 0000000..c07f079 --- /dev/null +++ b/example/suites/nitb_debug/pass.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +# This can be used to verify that a test passes correctly. +pass diff --git a/example/suites/nitb_debug/suite.conf b/example/suites/nitb_debug/suite.conf new file mode 100644 index 0000000..adfc161 --- /dev/null +++ b/example/suites/nitb_debug/suite.conf @@ -0,0 +1,10 @@ +resources: + ip_address: + - times: 1 + bts: + - times: 1 + modem: + - times: 4 + +defaults: + timeout: 60s diff --git a/example/suites/nitb_netreg/register.py b/example/suites/nitb_netreg/register.py new file mode 100755 index 0000000..d5fbeb7 --- /dev/null +++ b/example/suites/nitb_netreg/register.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +print('use resources...') +nitb = suite.nitb() +bts = suite.bts() +ms = suite.modem() + +print('start nitb and bts...') +nitb.bts_add(bts) +nitb.start() +bts.start() +wait(nitb.bts_is_connected, bts) + +nitb.subscriber_add(ms) + +ms.connect(nitb.mcc_mnc()) + +print(ms.info()) + +wait(ms.is_connected, nitb.mcc_mnc()) +wait(nitb.subscriber_attached, ms) diff --git a/example/suites/nitb_netreg/register_default.py b/example/suites/nitb_netreg/register_default.py new file mode 100755 index 0000000..545525d --- /dev/null +++ b/example/suites/nitb_netreg/register_default.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +print('use resources...') +nitb = suite.nitb() +bts = suite.bts() +ms = suite.modem() + +print('start nitb and bts...') +nitb.bts_add(bts) +nitb.start() +bts.start() +wait(nitb.bts_is_connected, bts) + +nitb.subscriber_add(ms) + +ms.connect() + +print(ms.info()) + +wait(ms.is_connected) +wait(nitb.subscriber_attached, ms) diff --git a/example/suites/nitb_netreg/suite.conf b/example/suites/nitb_netreg/suite.conf new file mode 100644 index 0000000..1bb1dbb --- /dev/null +++ b/example/suites/nitb_netreg/suite.conf @@ -0,0 +1,10 @@ +resources: + ip_address: + - times: 1 + bts: + - times: 1 + modem: + - times: 1 + +defaults: + timeout: 40s diff --git a/example/suites/nitb_netreg_mass/register_default_mass.py b/example/suites/nitb_netreg_mass/register_default_mass.py new file mode 100644 index 0000000..262b271 --- /dev/null +++ b/example/suites/nitb_netreg_mass/register_default_mass.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +""" +Runs a network registration with a 'massive' amount of MS +using the ms_driver infrastructure. +""" +from osmo_gsm_tester.testenv import * +from datetime import timedelta + +print('Claiming resources for the test') +nitb = suite.nitb() +bts = suite.bts() +ms_driver = suite.ms_driver() +ul = ms_driver.add_test('ul_test') +modems = suite.all_resources(suite.modem) + +print('Launching a simple network') +nitb.bts_add(bts) +nitb.start() +bts.start() +wait(nitb.bts_is_connected, bts) + +# Configure all MS that are available to this test. +for modem in modems: + nitb.subscriber_add(modem) + ms_driver.subscriber_add(modem) + +# Run the base test. +ms_driver.run_test() + +# Print the stats of the run. +ms_driver.print_stats() + +# Evaluate if this run was successful or not. Our initial acceptance criteria +# is quite basic but it should allow us to scale to a larger number of MS and +# reasons (e.g. have a full BCCH). +# +# 99% of LUs should complete +# 99% of successful LUs should complete within 10s. +stats = ul.get_stats() +if len(modems) > 0 and stats.num_completed < 1: + raise Exception("No run completed.") +completion_ratio = stats.num_completed / stats.num_attempted + +# Verify that 99% of LUs completed. +if completion_ratio < 0.99: + raise Exception("Completion ratio of %f%% lower than threshold." % (completion_ratio * 100.0)) + +# Check how many results are below our threshold. +acceptable_delay = timedelta(seconds=30) +quick_enough = len(ul.lus_less_than(acceptable_delay)) +latency_ratio = quick_enough / stats.num_attempted +if latency_ratio < 0.99: + raise Exception("Latency ratio of %f%% lower than threshold." % (latency_ratio * 100.0)) diff --git a/example/suites/nitb_netreg_mass/suite.conf b/example/suites/nitb_netreg_mass/suite.conf new file mode 100644 index 0000000..bb1585b --- /dev/null +++ b/example/suites/nitb_netreg_mass/suite.conf @@ -0,0 +1,11 @@ +resources: + ip_address: + - times: 1 + bts: + - type: osmo-bts-virtual + modem: + - times: 100 + type: osmo-mobile + +defaults: + timeout: 50s diff --git a/example/suites/nitb_smpp/esme_connect_policy_acceptall.py b/example/suites/nitb_smpp/esme_connect_policy_acceptall.py new file mode 100755 index 0000000..904226b --- /dev/null +++ b/example/suites/nitb_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.testenv 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/example/suites/nitb_smpp/esme_connect_policy_closed.py b/example/suites/nitb_smpp/esme_connect_policy_closed.py new file mode 100755 index 0000000..eaabb3d --- /dev/null +++ b/example/suites/nitb_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.testenv 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/example/suites/nitb_smpp/esme_ms_sms_storeforward.py b/example/suites/nitb_smpp/esme_ms_sms_storeforward.py new file mode 100755 index 0000000..391a040 --- /dev/null +++ b/example/suites/nitb_smpp/esme_ms_sms_storeforward.py @@ -0,0 +1,53 @@ +#!/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. +# * When SMS is sent in 'store & forward' mode, ESME fails to send an SMS to non registered MS. +# * When SMS is sent in 'store & forward' mode, ESME can send an SMS to a not yet registered MS. +# * When SMS is sent in 'store & forward' mode, ESME can send an SMS to an already registered MS. +# * When SMS is sent in 'store & forward' mode, ESME receives a SMS receipt if it asked for it. + +from osmo_gsm_tester.testenv 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() +wait(nitb.bts_is_connected, bts) + +esme.connect() +nitb.subscriber_add(ms) + +wrong_msisdn = ms.msisdn + esme.msisdn +print('sending sms with wrong msisdn %s, it will fail' % wrong_msisdn) +msg = Sms(esme.msisdn, wrong_msisdn, 'smpp message with wrong dest') +esme.run_method_expect_failure(SMPP_ESME_RINVDSTADR, esme.sms_send_wait_resp, msg, esme.MSGMODE_STOREFORWARD) + +print('sending sms, it will be stored...') +msg = Sms(esme.msisdn, ms.msisdn, 'smpp send not-yet-registered message') +umref = esme.sms_send_wait_resp(msg, esme.MSGMODE_STOREFORWARD, receipt=True) + +print('MS registers and will receive the SMS...') +ms.connect(nitb.mcc_mnc()) +wait(ms.is_connected, nitb.mcc_mnc()) +wait(nitb.subscriber_attached, ms) +wait(ms.sms_was_received, msg) +print('Waiting to receive and consume sms receipt with reference', umref) +wait(esme.receipt_was_received, umref) + +print('checking MS can receive SMS while registered...') +msg = Sms(esme.msisdn, ms.msisdn, 'smpp send already-registered message') +umref = esme.sms_send_wait_resp(msg, esme.MSGMODE_STOREFORWARD, receipt=True) +wait(ms.sms_was_received, msg) +print('Waiting to receive and consume sms receipt with reference', umref) +wait(esme.receipt_was_received, umref) +esme.disconnect() diff --git a/example/suites/nitb_smpp/esme_ms_sms_transaction.py b/example/suites/nitb_smpp/esme_ms_sms_transaction.py new file mode 100755 index 0000000..adc9dae --- /dev/null +++ b/example/suites/nitb_smpp/esme_ms_sms_transaction.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. +# * When SMS is sent in 'transaction' mode, ESME can send an SMS to an already registered MS. +# * When SMS is sent in 'transaction' mode, ESME fails to send an SMS to non registered MS. + +from osmo_gsm_tester.testenv 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() +wait(nitb.bts_is_connected, bts) + +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, esme.MSGMODE_TRANSACTION) +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, esme.MSGMODE_TRANSACTION) +wait(ms.sms_was_received, msg) + +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_wait_resp, msg, esme.MSGMODE_TRANSACTION) + +esme.disconnect() diff --git a/example/suites/nitb_smpp/suite.conf b/example/suites/nitb_smpp/suite.conf new file mode 100644 index 0000000..eb5dc01 --- /dev/null +++ b/example/suites/nitb_smpp/suite.conf @@ -0,0 +1,12 @@ +resources: + ip_address: + - times: 1 + bts: + - times: 1 + modem: + - times: 1 + features: + - sms + +defaults: + timeout: 60s diff --git a/example/suites/nitb_sms/mo_mt_sms.py b/example/suites/nitb_sms/mo_mt_sms.py new file mode 100755 index 0000000..10897ff --- /dev/null +++ b/example/suites/nitb_sms/mo_mt_sms.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +nitb = suite.nitb() +bts = suite.bts() +ms_mo = suite.modem() +ms_mt = suite.modem() + +print('start nitb and bts...') +nitb.bts_add(bts) +nitb.start() +bts.start() +wait(nitb.bts_is_connected, bts) + +nitb.subscriber_add(ms_mo) +nitb.subscriber_add(ms_mt) + +ms_mo.connect(nitb.mcc_mnc()) +ms_mt.connect(nitb.mcc_mnc()) + +ms_mo.log_info() +ms_mt.log_info() + +print('waiting for modems to attach...') +wait(ms_mo.is_connected, nitb.mcc_mnc()) +wait(ms_mt.is_connected, nitb.mcc_mnc()) +wait(nitb.subscriber_attached, ms_mo, ms_mt) + +sms = ms_mo.sms_send(ms_mt) +wait(ms_mt.sms_was_received, sms) diff --git a/example/suites/nitb_sms/suite.conf b/example/suites/nitb_sms/suite.conf new file mode 100644 index 0000000..485402b --- /dev/null +++ b/example/suites/nitb_sms/suite.conf @@ -0,0 +1,12 @@ +resources: + ip_address: + - times: 1 + bts: + - times: 1 + modem: + - times: 2 + features: + - sms + +defaults: + timeout: 60s diff --git a/example/suites/nitb_ussd/assert_extension.py b/example/suites/nitb_ussd/assert_extension.py new file mode 100755 index 0000000..8ccab2d --- /dev/null +++ b/example/suites/nitb_ussd/assert_extension.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +USSD_COMMAND_GET_EXTENSION = '*#100#' + +nitb = suite.nitb() +bts = suite.bts() +ms = suite.modem() + +print('start nitb and bts...') +nitb.bts_add(bts) +nitb.start() +bts.start() +wait(nitb.bts_is_connected, bts) + +nitb.subscriber_add(ms) + +ms.connect(nitb.mcc_mnc()) +ms.log_info() + +print('waiting for modems to attach...') +wait(ms.is_connected, nitb.mcc_mnc()) +wait(nitb.subscriber_attached, ms) + +# ofono (qmi) currently changes state to 'registered' jut after sending +# 'Location Update Request', but before receiving 'Location Updating Accept'. +# Which means we can reach lines below and send USSD code while still not being +# attached, which will then fail. See OsmoGsmTester #2239 for more detailed +# information. +# Until we find an ofono fix or a better way to workaround this, let's just +# sleep for a while in order to receive the 'Location Updating Accept' message +# before attemting to send the USSD. +sleep(10) + +print('Sending ussd code %s' % USSD_COMMAND_GET_EXTENSION) +response = ms.ussd_send(USSD_COMMAND_GET_EXTENSION) +assert ' ' + ms.msisdn + '\r' in response diff --git a/example/suites/nitb_ussd/suite.conf b/example/suites/nitb_ussd/suite.conf new file mode 100644 index 0000000..232a5d8 --- /dev/null +++ b/example/suites/nitb_ussd/suite.conf @@ -0,0 +1,12 @@ +resources: + ip_address: + - times: 1 + bts: + - times: 1 + modem: + - times: 1 + features: + - ussd + +defaults: + timeout: 60s diff --git a/example/suites/smpp/esme_connect_policy_acceptall.py b/example/suites/smpp/esme_connect_policy_acceptall.py new file mode 100755 index 0000000..168b4f3 --- /dev/null +++ b/example/suites/smpp/esme_connect_policy_acceptall.py @@ -0,0 +1,38 @@ +#!/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.testenv import * + +hlr = suite.hlr() +mgw_msc = suite.mgw() +stp = suite.stp() +msc = suite.msc(hlr, mgw_msc, stp) +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) + +stp.start() +hlr.start() +msc.start() +mgw_msc.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/example/suites/smpp/esme_connect_policy_closed.py b/example/suites/smpp/esme_connect_policy_closed.py new file mode 100755 index 0000000..487e5a4 --- /dev/null +++ b/example/suites/smpp/esme_connect_policy_closed.py @@ -0,0 +1,59 @@ +#!/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.testenv import * + +SMPP_ESME_RINVPASWD = 0x0000000E +SMPP_ESME_RINVSYSID = 0x0000000F + +hlr = suite.hlr() +bts = suite.bts() +mgw_msc = suite.mgw() +stp = suite.stp() +msc = suite.msc(hlr, mgw_msc, stp) +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) + +stp.start() +hlr.start() +msc.start() +mgw_msc.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/example/suites/smpp/esme_ms_sms_storeforward.py b/example/suites/smpp/esme_ms_sms_storeforward.py new file mode 100755 index 0000000..681bc29 --- /dev/null +++ b/example/suites/smpp/esme_ms_sms_storeforward.py @@ -0,0 +1,69 @@ +#!/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. +# * When SMS is sent in 'store & forward' mode, ESME fails to send an SMS to non registered MS. +# * When SMS is sent in 'store & forward' mode, ESME can send an SMS to a not yet registered MS. +# * When SMS is sent in 'store & forward' mode, ESME can send an SMS to an already registered MS. +# * When SMS is sent in 'store & forward' mode, ESME receives a SMS receipt if it asked for it. + +from osmo_gsm_tester.testenv import * + +SMPP_ESME_RINVDSTADR = 0x0000000B + +hlr = suite.hlr() +bts = suite.bts() +mgw_msc = suite.mgw() +mgw_bsc = suite.mgw() +stp = suite.stp() +msc = suite.msc(hlr, mgw_msc, stp) +bsc = suite.bsc(msc, mgw_bsc, stp) +bsc.bts_add(bts) + +ms = suite.modem() +esme = suite.esme() +msc.smsc.esme_add(esme) + +hlr.start() +stp.start() +msc.start() +mgw_msc.start() +mgw_bsc.start() +bsc.start() +bts.start() +wait(bsc.bts_is_connected, bts) + +esme.connect() +hlr.subscriber_add(ms) + +wrong_msisdn = ms.msisdn + esme.msisdn +print('sending sms with wrong msisdn %s, it will be stored but not delivered' % wrong_msisdn) +msg = Sms(esme.msisdn, wrong_msisdn, 'smpp message with wrong dest') +# Since osmo-msc 1e67fea7ba5c6336, we accept all sms in store&forward mode without looking at HLR +# esme.run_method_expect_failure(SMPP_ESME_RINVDSTADR, esme.sms_send_wait_resp, msg, esme.MSGMODE_STOREFORWARD) +umref_wrong = esme.sms_send_wait_resp(msg, esme.MSGMODE_STOREFORWARD, receipt=True) + +print('sending sms, it will be stored...') +msg = Sms(esme.msisdn, ms.msisdn, 'smpp send not-yet-registered message') +umref = esme.sms_send_wait_resp(msg, esme.MSGMODE_STOREFORWARD, receipt=True) + +print('MS registers and will receive the SMS...') +ms.connect(msc.mcc_mnc()) +wait(ms.is_connected, msc.mcc_mnc()) +wait(msc.subscriber_attached, ms) +wait(ms.sms_was_received, msg) +print('Waiting to receive and consume sms receipt with reference', umref) +wait(esme.receipt_was_received, umref) + +print('checking MS can receive SMS while registered...') +msg = Sms(esme.msisdn, ms.msisdn, 'smpp send already-registered message') +umref = esme.sms_send_wait_resp(msg, esme.MSGMODE_STOREFORWARD, receipt=True) +wait(ms.sms_was_received, msg) +print('Waiting to receive and consume sms receipt with reference', umref) +wait(esme.receipt_was_received, umref) + +print('Asserting the sms with wrong msisdn was not delivered', umref_wrong) +assert not esme.receipt_was_received(umref_wrong) + +esme.disconnect() diff --git a/example/suites/smpp/esme_ms_sms_transaction.py b/example/suites/smpp/esme_ms_sms_transaction.py new file mode 100755 index 0000000..16b01cc --- /dev/null +++ b/example/suites/smpp/esme_ms_sms_transaction.py @@ -0,0 +1,59 @@ +#!/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. +# * When SMS is sent in 'transaction' mode, ESME can send an SMS to an already registered MS. +# * When SMS is sent in 'transaction' mode, ESME fails to send an SMS to non registered MS. + +from osmo_gsm_tester.testenv import * + +SMPP_ESME_RINVDSTADR = 0x0000000B + +hlr = suite.hlr() +bts = suite.bts() +mgw_msc = suite.mgw() +mgw_bsc = suite.mgw() +stp = suite.stp() +msc = suite.msc(hlr, mgw_msc, stp) +bsc = suite.bsc(msc, mgw_bsc, stp) +bsc.bts_add(bts) + +ms = suite.modem() +esme = suite.esme() +msc.smsc.esme_add(esme) + +hlr.start() +stp.start() +msc.start() +mgw_msc.start() +mgw_bsc.start() +bsc.start() +bts.start() +wait(bsc.bts_is_connected, bts) + +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, esme.MSGMODE_TRANSACTION) +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, esme.MSGMODE_TRANSACTION) +wait(ms.sms_was_received, msg) + +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_wait_resp, msg, esme.MSGMODE_TRANSACTION) + +esme.disconnect() diff --git a/example/suites/smpp/suite.conf b/example/suites/smpp/suite.conf new file mode 100644 index 0000000..61e7015 --- /dev/null +++ b/example/suites/smpp/suite.conf @@ -0,0 +1,12 @@ +resources: + ip_address: + - times: 6 # msc, bsc, hlr, stp, mgw*2 + bts: + - times: 1 + modem: + - times: 1 + features: + - sms + +defaults: + timeout: 60s diff --git a/example/suites/sms/mo_mt_sms.py b/example/suites/sms/mo_mt_sms.py new file mode 100755 index 0000000..7654ea6 --- /dev/null +++ b/example/suites/sms/mo_mt_sms.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +hlr = suite.hlr() +bts = suite.bts() +mgw_msc = suite.mgw() +mgw_bsc = suite.mgw() +stp = suite.stp() +msc = suite.msc(hlr, mgw_msc, stp) +bsc = suite.bsc(msc, mgw_bsc, stp) +ms_mo = suite.modem() +ms_mt = suite.modem() + +hlr.start() +stp.start() +msc.start() +mgw_msc.start() +mgw_bsc.start() + +bsc.bts_add(bts) +bsc.start() + +bts.start() +wait(bsc.bts_is_connected, bts) + +hlr.subscriber_add(ms_mo) +hlr.subscriber_add(ms_mt) + +ms_mo.connect(msc.mcc_mnc()) +ms_mt.connect(msc.mcc_mnc()) + +ms_mo.log_info() +ms_mt.log_info() + +print('waiting for modems to attach...') +wait(ms_mo.is_connected, msc.mcc_mnc()) +wait(ms_mt.is_connected, msc.mcc_mnc()) +wait(msc.subscriber_attached, ms_mo, ms_mt) + +sms = ms_mo.sms_send(ms_mt) +wait(ms_mt.sms_was_received, sms) diff --git a/example/suites/sms/suite.conf b/example/suites/sms/suite.conf new file mode 100644 index 0000000..28a81ea --- /dev/null +++ b/example/suites/sms/suite.conf @@ -0,0 +1,9 @@ +resources: + ip_address: + - times: 6 # msc, bsc, hlr, stp, mgw*2 + bts: + - times: 1 + modem: + - times: 2 + features: + - sms diff --git a/example/suites/ussd/assert_extension.py b/example/suites/ussd/assert_extension.py new file mode 100755 index 0000000..475de09 --- /dev/null +++ b/example/suites/ussd/assert_extension.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +USSD_COMMAND_GET_EXTENSION = '*#100#' + +hlr = suite.hlr() +bts = suite.bts() +mgw_msc = suite.mgw() +mgw_bsc = suite.mgw() +stp = suite.stp() +msc = suite.msc(hlr, mgw_msc, stp) +bsc = suite.bsc(msc, mgw_bsc, stp) +ms = suite.modem() + +hlr.start() +stp.start() +msc.start() +mgw_msc.start() +mgw_bsc.start() + +bsc.bts_add(bts) +bsc.start() + +bts.start() +wait(bsc.bts_is_connected, bts) + +hlr.subscriber_add(ms) + +ms.connect(msc.mcc_mnc()) + +ms.log_info() + +print('waiting for modems to attach...') +wait(ms.is_connected, msc.mcc_mnc()) +wait(msc.subscriber_attached, ms) + +# ofono (qmi) currently changes state to 'registered' jut after sending +# 'Location Update Request', but before receiving 'Location Updating Accept'. +# Which means we can reach lines below and send USSD code while still not being +# attached, which will then fail. See OsmoGsmTester #2239 for more detailed +# information. +# Until we find an ofono fix or a better way to workaround this, let's just +# sleep for a while in order to receive the 'Location Updating Accept' message +# before attemting to send the USSD. +sleep(10) + +print('Sending ussd code %s' % USSD_COMMAND_GET_EXTENSION) +response = ms.ussd_send(USSD_COMMAND_GET_EXTENSION) +log('got ussd response: %r' % repr(response)) +assert response.endswith(' ' + ms.msisdn) diff --git a/example/suites/ussd/suite.conf b/example/suites/ussd/suite.conf new file mode 100644 index 0000000..460147a --- /dev/null +++ b/example/suites/ussd/suite.conf @@ -0,0 +1,9 @@ +resources: + ip_address: + - times: 6 # msc, bsc, hlr, stp, mgw*2 + bts: + - times: 1 + modem: + - times: 1 + features: + - ussd diff --git a/example/suites/voice/lib/testlib.py b/example/suites/voice/lib/testlib.py new file mode 100644 index 0000000..7d934f1 --- /dev/null +++ b/example/suites/voice/lib/testlib.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +def test_mo_mt_call(use_osmux=False, force_osmux=False): + hlr = suite.hlr() + bts = suite.bts() + mgw_msc = suite.mgw() + mgw_bsc = suite.mgw() + stp = suite.stp() + msc = suite.msc(hlr, mgw_msc, stp) + bsc = suite.bsc(msc, mgw_bsc, stp) + ms_mo = suite.modem() + ms_mt = suite.modem() + + hlr.start() + stp.start() + + msc.set_use_osmux(use_osmux, force_osmux) + msc.start() + + # osmo-msc still doesn't support linking 2 internal leg calls through Osmux + # if both calls are using Osmux. Currently, RTP is always used between the 2 + # endpoints of the MGW. See OS#4065. + mgw_msc.set_use_osmux(use_osmux, False) + mgw_msc.start() + + # We don't want to force Osmux in BSC_MGW since in MGW BTS-side is still RTP. + mgw_bsc.set_use_osmux(use_osmux, False) + mgw_bsc.start() + + bsc.set_use_osmux(use_osmux, force_osmux) + bsc.bts_add(bts) + bsc.start() + + bts.start() + wait(bsc.bts_is_connected, bts) + + hlr.subscriber_add(ms_mo) + hlr.subscriber_add(ms_mt) + + ms_mo.connect(msc.mcc_mnc()) + ms_mt.connect(msc.mcc_mnc()) + + ms_mo.log_info() + ms_mt.log_info() + + print('waiting for modems to attach...') + wait(ms_mo.is_connected, msc.mcc_mnc()) + wait(ms_mt.is_connected, msc.mcc_mnc()) + wait(msc.subscriber_attached, ms_mo, ms_mt) + + assert len(ms_mo.call_id_list()) == 0 and len(ms_mt.call_id_list()) == 0 + mo_cid = ms_mo.call_dial(ms_mt) + mt_cid = ms_mt.call_wait_incoming(ms_mo) + print('dial success') + + assert not ms_mo.call_is_active(mo_cid) and not ms_mt.call_is_active(mt_cid) + ms_mt.call_answer(mt_cid) + wait(ms_mo.call_is_active, mo_cid) + wait(ms_mt.call_is_active, mt_cid) + print('answer success, call established and ongoing') + + sleep(5) # maintain the call active for 5 seconds + + assert ms_mo.call_is_active(mo_cid) and ms_mt.call_is_active(mt_cid) + ms_mt.call_hangup(mt_cid) + wait(lambda: len(ms_mo.call_id_list()) == 0 and len(ms_mt.call_id_list()) == 0) + print('hangup success') diff --git a/example/suites/voice/mo_mt_call.py b/example/suites/voice/mo_mt_call.py new file mode 100755 index 0000000..740b1fe --- /dev/null +++ b/example/suites/voice/mo_mt_call.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +import testlib +suite.test_import_modules_register_for_cleanup(testlib) +from testlib import test_mo_mt_call + +test_mo_mt_call(False, False) diff --git a/example/suites/voice/mo_mt_call_osmux.py b/example/suites/voice/mo_mt_call_osmux.py new file mode 100755 index 0000000..acf7d71 --- /dev/null +++ b/example/suites/voice/mo_mt_call_osmux.py @@ -0,0 +1,8 @@ +#!/usr/bin/env python3 +from osmo_gsm_tester.testenv import * + +import testlib +suite.test_import_modules_register_for_cleanup(testlib) +from testlib import test_mo_mt_call + +test_mo_mt_call(True, True) diff --git a/example/suites/voice/suite.conf b/example/suites/voice/suite.conf new file mode 100644 index 0000000..522b1ca --- /dev/null +++ b/example/suites/voice/suite.conf @@ -0,0 +1,9 @@ +resources: + ip_address: + - times: 6 # msc, bsc, hlr, stp, mgw*2 + bts: + - times: 1 + modem: + - times: 2 + features: + - voice -- cgit v1.2.3