pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/36711?usp=email )
Change subject: asterisk: Introduce AMI_Adapter_CT ......................................................................
asterisk: Introduce AMI_Adapter_CT
This allows to keep string handling totally internal to the AMI_Adapter component, which also means now the CLIENT port acts asynchronously on full AMI messages. This allows for instance using activated altsteps to ignore events or answer to them.
Change-Id: Ibf230d2302fecf443f34e1c4d4acfd4802f4cc79 --- M asterisk/AMI_Functions.ttcn M asterisk/Asterisk_Tests.ttcn 2 files changed, 126 insertions(+), 48 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/11/36711/1
diff --git a/asterisk/AMI_Functions.ttcn b/asterisk/AMI_Functions.ttcn index 72420e1..6e0b8d0 100644 --- a/asterisk/AMI_Functions.ttcn +++ b/asterisk/AMI_Functions.ttcn @@ -167,6 +167,58 @@ tr_AMI_Field_ActionId(action_id) );
+ +/*********************** + * Adapter: + ***********************/ + +type port AMI_Msg_PT message { + inout AMI_Msg; +} with { extension "internal" }; + +type component AMI_Adapter_CT { + port TELNETasp_PT AMI; + port AMI_Msg_PT CLIENT; +} + +function f_AMI_Adapter_main() runs on AMI_Adapter_CT { + var AMI_Msg msg; + + var charstring rx, buf := ""; + var integer fd; + + map(self:AMI, system:AMI); + + while (true) { + + alt { + [] AMI.receive(pattern "\n") { + buf := buf & "\n"; + msg := dec_AMI_Msg(buf); + buf := ""; + CLIENT.send(msg); + }; + [] AMI.receive(charstring:?) -> value rx { + buf := buf & rx; + }; + [] AMI.receive(integer:?) -> value fd { + if (fd == -1) { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + "AMI Telnet Connection Failure: " & int2str(fd)); + } else { + /* telnet connection succeeded */ + } + } + [] CLIENT.receive(AMI_Msg:?) -> value msg { + /* TODO: in the future, queue Action if there's already one Action in transit, to fullfill AMI requirements. */ + var charstring tx_txt := enc_AMI_Msg(msg); + AMI.send(tx_txt); + } + } + } +} + + /* * Functions: */ @@ -223,62 +275,66 @@ return field.val; }
-private function f_ami_wait_for_prompt_str(TELNETasp_PT pt, charstring log_label := "(?)") -return charstring { - var charstring rx, buf := ""; - var integer fd; +function f_ami_transceive_ret(AMI_Msg_PT pt, template (value) AMI_Msg tx_msg, float rx_timeout := 10.0) return AMI_Msg { + var AMI_Msg rx_msg; timer T;
- T.start(mp_ami_prompt_timeout); + T.start(rx_timeout); + pt.send(tx_msg); alt { - [] pt.receive(pattern "\n") { buf := buf & "\n" }; - [] pt.receive(charstring:?) -> value rx { buf := buf & rx; repeat }; - [] pt.receive(integer:?) -> value fd { - if (fd == -1) { - Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, - "AMI Telnet Connection Failure: " & log_label); - } else { - repeat; /* telnet connection succeeded */ - } - } + [] pt.receive(AMI_Msg:?) -> value rx_msg; [] T.timeout { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, - "AMI Timeout for prompt: " & log_label); - }; + log2str("AMI Response timeout: ", tx_msg)); + } } T.stop; - return buf; + return rx_msg; + }
-function f_ami_wait_for_prompt(TELNETasp_PT pt, charstring log_label := "(?)") return AMI_Msg { - var charstring buf := f_ami_wait_for_prompt_str(pt, log_label); - var AMI_Msg msg := dec_AMI_Msg(buf); - return msg; -} - -/* send a AMI command and obtain response until prompt is received */ -private function f_ami_transceive_ret_str(TELNETasp_PT pt, charstring tx) return charstring { - pt.send(tx); - return f_ami_wait_for_prompt_str(pt, tx); -} - -function f_ami_transceive_ret(TELNETasp_PT pt, template (value) AMI_Msg tx_msg) return AMI_Msg { - var charstring tx_txt := enc_AMI_Msg(valueof(tx_msg)); - var charstring resp_txt := f_ami_transceive_ret_str(pt, tx_txt); - return dec_AMI_Msg(resp_txt); -} - -function f_ami_transceive_match(TELNETasp_PT pt, - template (value) AMI_Msg tx_msg, - template (present) AMI_Msg exp_ret := ?) { - var AMI_Msg ret := f_ami_transceive_ret(pt, tx_msg); - if (not match(ret, exp_ret)) { +private altstep as_ami_rx_fail(AMI_Msg_PT pt, template AMI_Msg exp_msg := *) +{ + var AMI_Msg msg; + [] pt.receive(AMI_Msg:?) -> value msg { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, - log2str("Non-matching AMI response: ", ret, " vs exp: ", exp_ret)); + log2str("Received unexpected AMI message := ", msg, "\nvs exp := ", exp_msg)); } }
-function f_ami_transceive_match_response_success(TELNETasp_PT pt, +altstep as_ami_expect_msg(AMI_Msg_PT pt, template (present) AMI_Msg msg_expect, boolean fail_others := true) +{ + [] pt.receive(msg_expect); + [fail_others] as_ami_rx_fail(pt, msg_expect); +} + +function f_ami_transceive_match(AMI_Msg_PT pt, + template (value) AMI_Msg tx_msg, + template (present) AMI_Msg exp_ret := ?, + boolean fail_others := true, + float rx_timeout := 10.0) return AMI_Msg { + var AMI_Msg rx_msg; + timer T; + + T.start(rx_timeout); + pt.send(tx_msg); + alt { + [] pt.receive(exp_ret) -> value rx_msg; + [not fail_others] pt.receive(AMI_Msg:?) -> value rx_msg { + log("AMI: Ignoring Rx msg ", rx_msg); + repeat; + } + [fail_others] as_ami_rx_fail(pt, exp_ret); + [] T.timeout { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str("AMI Response timeout: ", tx_msg)); + } + } + T.stop; + return rx_msg; +} + +function f_ami_transceive_match_response_success(AMI_Msg_PT pt, template (value) AMI_Msg tx_msg) { var template (present) AMI_Msg exp_resp; var template (omit) charstring action_id := f_ami_msg_get_value(valueof(tx_msg), AMI_FIELD_ACTION_ID); @@ -290,11 +346,11 @@ f_ami_transceive_match(pt, tx_msg, exp_resp); }
-function f_ami_action_login(TELNETasp_PT pt, charstring username, charstring secret) { +function f_ami_action_login(AMI_Msg_PT pt, charstring username, charstring secret) { f_ami_transceive_match_response_success(pt, ts_AMI_Action_Login(username, secret)); }
-function f_ami_action_PJSIPRegister(TELNETasp_PT pt, charstring register) { +function f_ami_action_PJSIPRegister(AMI_Msg_PT pt, charstring register) { var charstring reg_action_id := f_gen_action_id(); f_ami_transceive_match_response_success(pt, ts_AMI_Action_PJSIPRegister(register, reg_action_id)); } diff --git a/asterisk/Asterisk_Tests.ttcn b/asterisk/Asterisk_Tests.ttcn index c94f97f..d2fc0d5 100644 --- a/asterisk/Asterisk_Tests.ttcn +++ b/asterisk/Asterisk_Tests.ttcn @@ -49,7 +49,9 @@ /* Manages the IMS server Asterisk connects to: */ var SIP_Emulation_CT vc_IMS;
- port TELNETasp_PT AMI; + /* Connection towards Asterisk AMI iface: */ + var AMI_Adapter_CT vc_AMI; + port AMI_Msg_PT AMI_CLIENT;
port Coord_PT COORD; port IMSCoord_PT IMS_COORD; @@ -70,8 +72,13 @@
/* Initialize connection towards Asterisk AMI */ private function f_init_ami() runs on test_CT { - map(self:AMI, system:AMI); - f_ami_action_login(AMI, mp_ami_user, mp_ami_secret); + var charstring id := "Asterisk_Tests_AMI_EMU"; + vc_AMI := AMI_Adapter_CT.create(id); + connect(self:AMI_CLIENT, vc_AMI:CLIENT); + vc_AMI.start(f_AMI_Adapter_main()); + + + f_ami_action_login(AMI_CLIENT, mp_ami_user, mp_ami_secret); }
/* Local SIP UAs */