forked from ttcn3/osmo-ttcn3-hacks
Introduce Asterisk_Tests testsuite
Add initial infrastructure to run tests against an Asterisk process. An not-yet-finished draft test doing registration is submitted to validate communication towards Asterisk works. The testsuite will be improved in follow-up commits, but this way other people can already start using it and we can set up the dockerized setup + jenkins jobs to run it nightly. Related: SYS#6782 Change-Id: I66f776d5df6fb5dc488d9e589b84a6b2385406e8
This commit is contained in:
parent
fb34d863c3
commit
37ee0ed83c
1
Makefile
1
Makefile
|
@ -14,6 +14,7 @@
|
|||
# limitations under the License.
|
||||
|
||||
SUBDIRS= \
|
||||
asterisk \
|
||||
bsc \
|
||||
bsc-nat \
|
||||
bts \
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
[ORDERED_INCLUDE]
|
||||
# Common configuration, shared between test suites
|
||||
"../Common.cfg"
|
||||
# testsuite specific configuration, not expected to change
|
||||
"./Asterisk_Tests.default"
|
||||
|
||||
# Local configuration below
|
||||
|
||||
[LOGGING]
|
||||
|
||||
[TESTPORT_PARAMETERS]
|
||||
|
||||
[MODULE_PARAMETERS]
|
||||
|
||||
[MAIN_CONTROLLER]
|
||||
|
||||
[EXECUTE]
|
||||
Asterisk_Tests.control
|
|
@ -0,0 +1,18 @@
|
|||
[LOGGING]
|
||||
FileMask := LOG_ALL | TTCN_MATCHING;
|
||||
|
||||
mtc.FileMask := ERROR | WARNING | PARALLEL | VERDICTOP;
|
||||
|
||||
[TESTPORT_PARAMETERS]
|
||||
*.SIP.local_sip_port := "5060"
|
||||
*.SIP.default_local_address := "127.0.0.2"
|
||||
*.SIP.default_sip_protocol := "UDP"
|
||||
*.SIP.default_dest_port := "5060"
|
||||
*.SIP.default_dest_address := "127.0.0.1"
|
||||
|
||||
|
||||
[MODULE_PARAMETERS]
|
||||
|
||||
[MAIN_CONTROLLER]
|
||||
|
||||
[EXECUTE]
|
|
@ -0,0 +1,240 @@
|
|||
module Asterisk_Tests {
|
||||
|
||||
/* Asterisk test suite in TTCN-3
|
||||
* (C) 2024 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
* All rights reserved.
|
||||
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||
*
|
||||
* Released under the terms of GNU General Public License, Version 2 or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import from General_Types all;
|
||||
import from Osmocom_Types all;
|
||||
import from Native_Functions all;
|
||||
import from Misc_Helpers all;
|
||||
|
||||
import from SDP_Types all;
|
||||
import from SDP_Templates all;
|
||||
|
||||
import from SIP_Emulation all;
|
||||
import from SIPmsg_Types all;
|
||||
import from SIP_Templates all;
|
||||
|
||||
modulepar {
|
||||
charstring mp_local_sip_host := "127.0.0.2";
|
||||
integer mp_local_sip_port := 5060;
|
||||
charstring mp_remote_sip_host := "127.0.0.1";
|
||||
integer mp_remote_sip_port := 5060;
|
||||
}
|
||||
|
||||
type component test_CT {
|
||||
var SIP_Emulation_CT vc_SIP;
|
||||
}
|
||||
|
||||
type component ConnHdlr extends SIP_ConnHdlr {
|
||||
var ConnHdlrPars g_pars;
|
||||
timer g_Tguard;
|
||||
var PDU_SIP_Request g_rx_sip_req;
|
||||
var PDU_SIP_Response g_rx_sip_resp;
|
||||
}
|
||||
|
||||
type record ConnHdlrPars {
|
||||
float t_guard,
|
||||
charstring user,
|
||||
SipUrl registrar_sip_url,
|
||||
SipAddr registrar_sip_record,
|
||||
CallidString registrar_sip_call_id,
|
||||
Via registrar_via,
|
||||
integer registrar_sip_seq_nr,
|
||||
SipAddr sip_url_ext,
|
||||
Contact local_contact,
|
||||
CallPars cp optional
|
||||
}
|
||||
|
||||
template (value) ConnHdlrPars t_Pars(charstring user,
|
||||
charstring displayname := "\"Anonymous\"") := {
|
||||
t_guard := 30.0,
|
||||
user := user,
|
||||
registrar_sip_url := valueof(ts_SipUrlHost(mp_remote_sip_host)),
|
||||
registrar_sip_record := ts_SipAddr(ts_HostPort(mp_remote_sip_host),
|
||||
ts_UserInfo(user),
|
||||
displayName := displayname),
|
||||
registrar_sip_call_id := hex2str(f_rnd_hexstring(15)) & "@" & mp_local_sip_host,
|
||||
registrar_via := ts_Via_from(ts_HostPort(mp_local_sip_host, mp_local_sip_port)),
|
||||
registrar_sip_seq_nr := f_sip_rand_seq_nr(),
|
||||
sip_url_ext := ts_SipAddr(ts_HostPort(mp_local_sip_host, mp_local_sip_port),
|
||||
ts_UserInfo(user)),
|
||||
local_contact := valueof(ts_Contact({
|
||||
ts_ContactAddress(
|
||||
ts_Addr_Union_SipUrl(ts_SipUrl(ts_HostPort(
|
||||
mp_local_sip_host,
|
||||
mp_local_sip_port),
|
||||
ts_UserInfo(user))),
|
||||
omit)
|
||||
})),
|
||||
cp := omit
|
||||
}
|
||||
|
||||
function f_init_ConnHdlrPars(integer idx := 1) runs on test_CT return ConnHdlrPars {
|
||||
var ConnHdlrPars pars := valueof(t_Pars(int2str(500 + idx)));
|
||||
return pars;
|
||||
}
|
||||
|
||||
type record CallPars {
|
||||
boolean is_mo,
|
||||
charstring calling,
|
||||
charstring called,
|
||||
|
||||
CallParsComputed comp optional,
|
||||
|
||||
charstring sip_rtp_addr,
|
||||
uint16_t sip_rtp_port,
|
||||
charstring cn_rtp_addr,
|
||||
uint16_t cn_rtp_port
|
||||
}
|
||||
|
||||
type record CallParsComputed {
|
||||
CallidString sip_call_id,
|
||||
charstring sip_body,
|
||||
integer sip_seq_nr
|
||||
}
|
||||
|
||||
private template (value) CallPars t_CallPars(boolean is_mo) := {
|
||||
is_mo := is_mo,
|
||||
calling := "12345",
|
||||
called := "98766",
|
||||
comp := {
|
||||
sip_call_id := hex2str(f_rnd_hexstring(15)),
|
||||
sip_body := "",
|
||||
sip_seq_nr := f_sip_rand_seq_nr()
|
||||
},
|
||||
sip_rtp_addr := "1.2.3.4",
|
||||
sip_rtp_port := 1234,
|
||||
cn_rtp_addr := "5.6.7.8",
|
||||
cn_rtp_port := 5678
|
||||
}
|
||||
|
||||
function f_init() runs on test_CT {
|
||||
f_init_sip(vc_SIP, "Asterisk_Test");
|
||||
log("end of f_init");
|
||||
}
|
||||
|
||||
type function void_fn(charstring id) runs on ConnHdlr;
|
||||
|
||||
function f_start_handler(void_fn fn, ConnHdlrPars pars)
|
||||
runs on test_CT return ConnHdlr {
|
||||
var ConnHdlr vc_conn;
|
||||
var charstring id := testcasename();
|
||||
|
||||
vc_conn := ConnHdlr.create(id);
|
||||
|
||||
connect(vc_conn:SIP, vc_SIP:CLIENT);
|
||||
connect(vc_conn:SIP_PROC, vc_SIP:CLIENT_PROC);
|
||||
|
||||
vc_conn.start(f_handler_init(fn, id, pars));
|
||||
return vc_conn;
|
||||
}
|
||||
|
||||
private altstep as_Tguard() runs on ConnHdlr {
|
||||
[] g_Tguard.timeout {
|
||||
setverdict(fail, "Tguard timeout");
|
||||
mtc.stop;
|
||||
}
|
||||
}
|
||||
|
||||
private function f_handler_init(void_fn fn, charstring id, ConnHdlrPars pars)
|
||||
runs on ConnHdlr {
|
||||
g_pars := pars;
|
||||
g_Tguard.start(pars.t_guard);
|
||||
activate(as_Tguard());
|
||||
|
||||
// Make sure the UA is deregistered before starting the test:
|
||||
// sends REGISTER with Contact = "*" and Expires = 0
|
||||
//f_SIP_deregister();
|
||||
|
||||
/* call the user-supied test case function */
|
||||
fn.apply(id);
|
||||
}
|
||||
|
||||
altstep as_SIP_expect_req(template PDU_SIP_Request sip_expect) runs on ConnHdlr
|
||||
{
|
||||
[] SIP.receive(sip_expect) -> value g_rx_sip_req;
|
||||
[] SIP.receive {
|
||||
log("FAIL: expected SIP message ", sip_expect);
|
||||
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received unexpected SIP message");
|
||||
}
|
||||
}
|
||||
|
||||
altstep as_SIP_expect_resp(template PDU_SIP_Response sip_expect) runs on ConnHdlr
|
||||
{
|
||||
[] SIP.receive(sip_expect) -> value g_rx_sip_resp;
|
||||
[] SIP.receive {
|
||||
log("FAIL: expected SIP message ", sip_expect);
|
||||
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Received unexpected SIP message");
|
||||
}
|
||||
}
|
||||
|
||||
private function f_tr_Via_response(Via via_req) return template (present) Via {
|
||||
template (present) SemicolonParam_List via_resp_params := ?;
|
||||
|
||||
/*via_resp_params := {
|
||||
{ id := "rport", paramValue := int2str(mp_remote_sip_port) },
|
||||
{ id := "received", paramValue := mp_remote_sip_host }
|
||||
}; */
|
||||
return tr_Via_from(via_req.viaBody[0].sentBy,
|
||||
via_resp_params);
|
||||
}
|
||||
|
||||
function f_SIP_register() runs on ConnHdlr return PDU_SIP_Response
|
||||
{
|
||||
var template (present) PDU_SIP_Response exp;
|
||||
|
||||
SIP.send(ts_SIP_REGISTER(g_pars.registrar_sip_url,
|
||||
g_pars.registrar_sip_call_id,
|
||||
g_pars.registrar_sip_record,
|
||||
g_pars.registrar_sip_record,
|
||||
g_pars.registrar_via,
|
||||
g_pars.registrar_sip_seq_nr,
|
||||
g_pars.local_contact,
|
||||
ts_Expires("7200")));
|
||||
|
||||
exp := tr_SIP_Response_REGISTER_Unauthorized(
|
||||
g_pars.registrar_sip_call_id,
|
||||
g_pars.registrar_sip_record,
|
||||
g_pars.registrar_sip_record,
|
||||
f_tr_Via_response(g_pars.registrar_via),
|
||||
*,
|
||||
g_pars.registrar_sip_seq_nr);
|
||||
as_SIP_expect_resp(exp);
|
||||
|
||||
/* Do the registering after calculating the md5 hash, etc. */
|
||||
return g_rx_sip_resp;
|
||||
}
|
||||
|
||||
/* Successful MO Call, which is subsequently released by SIP side */
|
||||
private function f_TC_internal_registration(charstring id) runs on ConnHdlr {
|
||||
|
||||
f_SIP_register();
|
||||
/* now call is fully established */
|
||||
f_sleep(2.0);
|
||||
// f_SIP_deregister();
|
||||
setverdict(pass);
|
||||
}
|
||||
|
||||
testcase TC_internal_registration() runs on test_CT {
|
||||
var ConnHdlrPars pars;
|
||||
var ConnHdlr vc_conn;
|
||||
f_init();
|
||||
pars := f_init_ConnHdlrPars();
|
||||
vc_conn := f_start_handler(refers(f_TC_internal_registration), pars);
|
||||
vc_conn.done;
|
||||
}
|
||||
|
||||
control {
|
||||
execute( TC_internal_registration() );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
* Asterisk_Tests.ttcn
|
||||
|
||||
* external interfaces
|
||||
* SIP (emulates SIP UAs)
|
||||
* VoLTE (emulates IMS server)
|
||||
|
||||
{% dot sip_tests.svg
|
||||
digraph G {
|
||||
rankdir=LR;
|
||||
Asterisk [label="IUT\nAsterisk",shape="box"];
|
||||
ATS [label="ATS\nAsterisk_Tests.ttcn"];
|
||||
|
||||
ATS -> Asterisk [label="SIP"];
|
||||
ATS -> Asterisk [label="VoLTE (IMS)"];
|
||||
}
|
||||
%}
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0"?>
|
||||
<testsuite name='Titan' tests='9' failures='0' errors='0' skipped='0' inconc='0' time='MASKED'>
|
||||
<testcase classname='Asterisk_Tests' name='TC_internal_registration' time='MASKED'/>
|
||||
</testsuite>
|
|
@ -0,0 +1,40 @@
|
|||
#!/bin/bash
|
||||
|
||||
BASEDIR=../deps
|
||||
|
||||
. ../gen_links.sh.inc
|
||||
|
||||
DIR=$BASEDIR/titan.Libraries.TCCUsefulFunctions/src
|
||||
FILES="TCCInterface_Functions.ttcn TCCConversion_Functions.ttcn TCCConversion.cc TCCInterface.cc TCCInterface_ip.h"
|
||||
gen_links $DIR $FILES
|
||||
|
||||
DIR=$BASEDIR/titan.TestPorts.Common_Components.Socket-API/src
|
||||
FILES="Socket_API_Definitions.ttcn"
|
||||
gen_links $DIR $FILES
|
||||
|
||||
# Required by MGCP and IPA
|
||||
DIR=$BASEDIR/titan.TestPorts.IPL4asp/src
|
||||
FILES="IPL4asp_Functions.ttcn IPL4asp_PT.cc IPL4asp_PT.hh IPL4asp_PortType.ttcn IPL4asp_Types.ttcn IPL4asp_discovery.cc IPL4asp_protocol_L234.hh"
|
||||
gen_links $DIR $FILES
|
||||
|
||||
DIR=$BASEDIR/titan.ProtocolModules.SDP/src
|
||||
FILES="SDP_EncDec.cc SDP_Types.ttcn SDP_parse_.tab.c SDP_parse_.tab.h SDP_parse_parser.h SDP_parser.l
|
||||
SDP_parser.y lex.SDP_parse_.c"
|
||||
gen_links $DIR $FILES
|
||||
|
||||
DIR=$BASEDIR/titan.ProtocolModules.RTP/src
|
||||
FILES="RTP_EncDec.cc RTP_Types.ttcn"
|
||||
gen_links $DIR $FILES
|
||||
|
||||
DIR=$BASEDIR/titan.TestPorts.SIPmsg/src
|
||||
FILES="SIP_parse.h SIP_parse.y SIP_parse_.tab.h SIPmsg_PT.hh SIPmsg_Types.ttcn SIP_parse.l SIP_parse_.tab.c SIPmsg_PT.cc SIPmsg_PortType.ttcn lex.SIP_parse_.c"
|
||||
gen_links $DIR $FILES
|
||||
|
||||
DIR=../library
|
||||
FILES="Misc_Helpers.ttcn General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn Native_Functions.ttcn Native_FunctionDefs.cc "
|
||||
FILES+="RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunctDef.cc "
|
||||
FILES+="SDP_Templates.ttcn "
|
||||
FILES+="SIP_Emulation.ttcn SIP_Templates.ttcn "
|
||||
gen_links $DIR $FILES
|
||||
|
||||
ignore_pp_results
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/sh
|
||||
|
||||
NAME=Asterisk_Tests
|
||||
|
||||
FILES="
|
||||
*.c
|
||||
*.ttcn
|
||||
IPL4asp_PT.cc
|
||||
IPL4asp_discovery.cc
|
||||
Native_FunctionDefs.cc
|
||||
RTP_CodecPort_CtrlFunctDef.cc
|
||||
RTP_EncDec.cc
|
||||
SDP_EncDec.cc
|
||||
SIPmsg_PT.cc
|
||||
TCCConversion.cc
|
||||
TCCInterface.cc
|
||||
"
|
||||
|
||||
../regen-makefile.sh -e $NAME $FILES
|
|
@ -72,6 +72,13 @@ template RequestLine tr_ReqLine(template Method method) := {
|
|||
sipVersion := ?
|
||||
}
|
||||
|
||||
private template PDU_SIP_Request tr_SIP_REGISTER := {
|
||||
requestLine := tr_ReqLine(REGISTER_E),
|
||||
msgHeader := t_SIP_msgHeader_any,
|
||||
messageBody := *,
|
||||
payload := *
|
||||
}
|
||||
|
||||
private template PDU_SIP_Request tr_SIP_INVITE := {
|
||||
requestLine := tr_ReqLine(INVITE_E),
|
||||
msgHeader := t_SIP_msgHeader_any,
|
||||
|
@ -79,7 +86,6 @@ private template PDU_SIP_Request tr_SIP_INVITE := {
|
|||
payload := *
|
||||
}
|
||||
|
||||
|
||||
template SipUrl tr_SIP_Url(template charstring user_or_num,
|
||||
template charstring host := *,
|
||||
template integer portField := *) := {
|
||||
|
@ -286,6 +292,19 @@ runs on SIP_Emulation_CT {
|
|||
}
|
||||
}
|
||||
|
||||
/* a ConnHdlr is sending us a SIP REGISTER: Forward to SIP port */
|
||||
[] CLIENT.receive(tr_SIP_REGISTER) -> value sip_req sender vc_conn {
|
||||
var CallidString call_id := sip_req.msgHeader.callId.callid;
|
||||
if (f_call_id_known(call_id)) {
|
||||
/* re-register */
|
||||
vc_conn := f_comp_by_call_id(call_id);
|
||||
} else {
|
||||
/* new REGISTER: add to table */
|
||||
f_call_table_add(vc_conn, call_id);
|
||||
}
|
||||
SIP.send(sip_req);
|
||||
}
|
||||
|
||||
/* a ConnHdlr is sending us a SIP INVITE: Forward to SIP port */
|
||||
[] CLIENT.receive(tr_SIP_INVITE) -> value sip_req sender vc_conn {
|
||||
var CallidString call_id := sip_req.msgHeader.callId.callid;
|
||||
|
|
|
@ -525,6 +525,26 @@ tr_SIP_Response(template CallidString call_id,
|
|||
payload := omit
|
||||
}
|
||||
|
||||
/* Expect during first REGISTER when authorization is required: */
|
||||
template (present) PDU_SIP_Response
|
||||
tr_SIP_Response_REGISTER_Unauthorized(
|
||||
template CallidString call_id,
|
||||
template SipAddr from_addr,
|
||||
template SipAddr to_addr,
|
||||
template (present) Via via := tr_Via_from(?),
|
||||
template Contact contact := *,
|
||||
template integer seq_nr := ?,
|
||||
template charstring method := "REGISTER",
|
||||
template integer status_code := 401,
|
||||
template charstring reason := "Unauthorized",
|
||||
template charstring body := *) := {
|
||||
statusLine := tr_SIP_StatusLine(status_code, reason),
|
||||
msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact,
|
||||
via,
|
||||
method, *, seq_nr),
|
||||
messageBody := body,
|
||||
payload := omit
|
||||
}
|
||||
|
||||
/* RFC 3261 8.1.1.5:
|
||||
* "The sequence number value MUST be expressible as a 32-bit unsigned integer
|
||||
|
|
Loading…
Reference in New Issue