fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/42360?usp=email )
Change subject: s1gw: add tests for MME registry REST procedures ......................................................................
s1gw: add tests for MME registry REST procedures
Add three test cases exercising the S1GW REST interface for MME pool management. The REST TCs are gated on the mp_rest_enable module parameter in the control block.
TC_rest_mme_list: query the MME pool list via REST and verify it matches the three static entries from the 'mme_pool' section in osmo-s1gw.config (mme0/mme1/mme2 with their respective addresses).
TC_rest_mme_add_del: add a new MME entry at runtime via REST, verify it appears in both the list and individual GET responses, then delete it and confirm it is gone.
TC_rest_mme_del_fallback: delete mme0 from the pool at runtime and verify that a connecting eNB is routed directly to mme1, skipping the deleted entry. The pool is restored to its original state afterwards via f_REST_mme_pool_restore().
Also add: * {ts,tr}_MmeItem templates to S1GW_REST_Types.ttcn * f_REST_mme_find(): returns the integer index of a named entry in a MmeList, or -1 if not found; used for both presence and absence checks * f_REST_mme_pool_restore(): deletes all current entries and re-adds mme0/mme1/mme2 in original order to keep pool state predictable across test cases
Change-Id: I260bc987ab8ae0ecb547d0b69b261fd97c5c9c23 Related: SYS#7052 --- M s1gw/S1GW_REST_Types.ttcn M s1gw/S1GW_Tests.ttcn M s1gw/expected-results.xml 3 files changed, 198 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/60/42360/1
diff --git a/s1gw/S1GW_REST_Types.ttcn b/s1gw/S1GW_REST_Types.ttcn index f182ae9..696df3d 100644 --- a/s1gw/S1GW_REST_Types.ttcn +++ b/s1gw/S1GW_REST_Types.ttcn @@ -157,4 +157,30 @@ external function dec_ErabItem(in octetstring data) return ErabItem with { extension "prototype(convert) decode(JSON)" }
+ +template (value) MmeItem +ts_MmeItem(template (value) charstring name, + template (value) charstring raddr, + template (omit) charstring laddr := omit, + template (omit) Port rport := omit, + template (omit) TacList tac_list := omit) := { + name := name, + laddr := laddr, + raddr := raddr, + rport := rport, + tac_list := tac_list +} +template (present) MmeItem +tr_MmeItem(template (present) charstring name := ?, + template (present) charstring raddr := ?, + template charstring laddr := *, + template Port rport := *, + template TacList tac_list := *) := { + name := name, + laddr := laddr, + raddr := raddr, + rport := rport, + tac_list := tac_list +} + } with { encode "JSON" } diff --git a/s1gw/S1GW_Tests.ttcn b/s1gw/S1GW_Tests.ttcn index d870be8..f2af12a 100644 --- a/s1gw/S1GW_Tests.ttcn +++ b/s1gw/S1GW_Tests.ttcn @@ -1200,6 +1200,167 @@ { S1APSRV_SETUP_ACCEPT }); }
+ +/* Find an MME entry in the list by name; return its index, or -1 if not found */ +private function f_REST_mme_find(MmeList mmes, charstring name) return integer { + for (var integer i := 0; i < lengthof(mmes); i := i + 1) { + if (mmes[i].name == name) { + return i; + } + } + return -1; +} + +/* Restore the MME pool to its original state: delete all current entries and + * re-add the three static pool entries (mme0/mme1/mme2) in their original order. */ +private function f_REST_mme_pool_restore() runs on test_CT { + var MmeList mmes := f_REST_MmeList(); + for (var integer i := 0; i < lengthof(mmes); i := i + 1) { + f_REST_MmeDelete({ name := "name:" & mmes[i].name }); + } + for (var integer i := 0; i < 3; i := i + 1) { + f_REST_MmeAdd(valueof(ts_MmeItem(name := "mme" & int2str(i), + raddr := f_mme_ip(i)))); + } +} + +/* REST test: verify the configured MME pool is correctly reflected via REST */ +testcase TC_rest_mme_list() runs on test_CT { + var template (present) MmeList tr_mmes; + var MmeList mmes; + + f_init(s1apsrv_start := false, upf_start := false); + + /* this resembles the 'mme_pool' section in osmo-s1gw.config */ + for (var integer i := 0; i < 3; i := i + 1) { + tr_mmes[i] := tr_MmeItem(name := "mme" & int2str(i), + raddr := f_mme_ip(i), + laddr := "any", + rport := 36412, + tac_list := { }); + } + + mmes := f_REST_MmeList(); + if (not match(mmes, tr_mmes)) { + setverdict(fail, "Got unexpected MmeList: ", mmes); + } + + setverdict(pass); +} + +/* REST test: add an MME to the pool, verify it appears, then delete it */ +testcase TC_rest_mme_add_del() runs on test_CT { + var MmeList mmes; + var MmeItem mme; + var integer idx; + + var template (value) MmeItem ts_mme_test := ts_MmeItem(name := "mme-test", + raddr := f_mme_ip(9)); + var template (present) MmeItem tr_mme_test := tr_MmeItem(name := "mme-test", + raddr := f_mme_ip(9), + laddr := "any", + rport := 36412, + tac_list := { }); + + f_init(s1apsrv_start := false, upf_start := false); + + /* add the new entry and verify it appears in the list */ + if (not f_REST_MmeAdd(valueof(ts_mme_test))) { + setverdict(fail, "Failed to add mme-test via REST"); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__); + } + mmes := f_REST_MmeList(); + if (lengthof(mmes) != 4) { + setverdict(fail, "Expected 4 MMEs after add, got ", lengthof(mmes)); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__); + } + idx := f_REST_mme_find(mmes, "mme-test"); + if (idx == -1) { + setverdict(fail, "mme-test not found in MmeList after add"); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__); + } + if (not match(mmes[idx], tr_mme_test)) { + setverdict(fail, "mme-test does not match: ", mmes[idx]); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__); + } + + /* also verify via individual GET */ + mme := f_REST_MmeInfo({ name := "name:mme-test" }); + if (not match(mme, tr_mme_test)) { + setverdict(fail, "mme-test does not match: ", mme); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__); + } + + /* delete the entry and verify it's gone */ + if (not f_REST_MmeDelete({ name := "name:mme-test" })) { + setverdict(fail, "Failed to delete mme-test via REST"); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__); + } + mmes := f_REST_MmeList(); + if (lengthof(mmes) != 3) { + setverdict(fail, "Expected 3 MMEs after delete, got ", lengthof(mmes)); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__); + } + if (f_REST_mme_find(mmes, "mme-test") != -1) { + setverdict(fail, "mme-test still present in MmeList after delete"); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__); + } + + setverdict(pass); +} + +/* ConnHdlr body for TC_rest_mme_del_fallback: connect and complete S1 setup via pool */ +private function f_TC_rest_pool_connect_accept(charstring id) runs on ConnHdlr { + f_ConnHdlr_s1ap_connect(mp_enb_bind_ip, mp_s1gw_enb_ip); + f_ConnHdlr_s1ap_setup_pool(g_pars.pool_srvs, g_pars.pool_behaviors); + f_sleep(0.5); + f_ConnHdlr_s1ap_disconnect(); + f_ConnHdlr_s1ap_unregister_from(g_pars.genb_id, g_s1ap_server); +} + +/* REST test: delete an MME from the pool at runtime; eNB must fall back to the + * next available MME without attempting to connect to the deleted entry. */ +testcase TC_rest_mme_del_fallback() runs on test_CT { + var ConnHdlrPars pars; + var ConnHdlr vc_conn; + var MmeList mmes; + + /* start 2 S1AP servers: server[0]=mme0@127.0.2.10, server[1]=mme1@127.0.2.11 */ + f_init(num_mmes := 2); + + /* delete mme0: effective pool becomes [mme1, mme2] */ + if (not f_REST_MmeDelete({ name := "name:mme0" })) { + setverdict(fail, "Failed to delete mme0 via REST"); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__); + } + mmes := f_REST_MmeList(); + if (lengthof(mmes) != 2) { + setverdict(fail, "Expected 2 MMEs after deleting mme0, got ", lengthof(mmes)); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__); + } + if (f_REST_mme_find(mmes, "mme0") != -1) { + setverdict(fail, "mme0 still present in MmeList after delete"); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__); + } + + /* eNB connects: S1GW must select mme1 (server[1]@127.0.2.11) directly */ + pars := valueof(t_ConnHdlrPars); + pars.pool_srvs := { vc_S1APSRVs[1] }; + pars.pool_behaviors := { S1APSRV_SETUP_ACCEPT }; + vc_conn := f_ConnHdlr_spawn(refers(f_TC_rest_pool_connect_accept), pars); + vc_conn.done; + + /* restore original pool state (mme0/mme1/mme2 in order) for subsequent tests */ + f_REST_mme_pool_restore(); + mmes := f_REST_MmeList(); + if (lengthof(mmes) != 3) { + setverdict(fail, "Expected 3 MMEs after pool restore, got ", lengthof(mmes)); + Misc_Helpers.f_shutdown(__BFILE__, __LINE__); + } + + setverdict(pass); +} + control { execute( TC_setup() ); execute( TC_setup_multi() ); @@ -1241,6 +1402,13 @@ execute( TC_mme_pool_all_reject() ); execute( TC_mme_pool_enb_disc_wait_s1setup_req() ); execute( TC_mme_pool_enb_disc_wait_s1setup_rsp() ); + + /* REST interface TCs */ + if (mp_rest_enable) { + execute( TC_rest_mme_list() ); + execute( TC_rest_mme_add_del() ); + execute( TC_rest_mme_del_fallback() ); + } }
} diff --git a/s1gw/expected-results.xml b/s1gw/expected-results.xml index 0769764..b2b6cdb 100644 --- a/s1gw/expected-results.xml +++ b/s1gw/expected-results.xml @@ -1,5 +1,5 @@ <?xml version="1.0"?> -<testsuite name='S1GW_Tests' tests='38' failures='0' errors='0' skipped='0' inconc='0' time='MASKED'> +<testsuite name='S1GW_Tests' tests='41' failures='0' errors='0' skipped='0' inconc='0' time='MASKED'> <testcase classname='S1GW_Tests' name='TC_setup' time='MASKED'/> <testcase classname='S1GW_Tests' name='TC_setup_multi' time='MASKED'/> <testcase classname='S1GW_Tests' name='TC_conn_term_by_mme' time='MASKED'/> @@ -40,4 +40,7 @@ <testcase classname='S1GW_Tests' name='TC_mme_pool_all_reject' time='MASKED'/> <testcase classname='S1GW_Tests' name='TC_mme_pool_enb_disc_wait_s1setup_req' time='MASKED'/> <testcase classname='S1GW_Tests' name='TC_mme_pool_enb_disc_wait_s1setup_rsp' time='MASKED'/> + <testcase classname='S1GW_Tests' name='TC_rest_mme_list' time='MASKED'/> + <testcase classname='S1GW_Tests' name='TC_rest_mme_add_del' time='MASKED'/> + <testcase classname='S1GW_Tests' name='TC_rest_mme_del_fallback' time='MASKED'/> </testsuite>