pespin has submitted this change. ( 
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/36490?usp=email )

Change subject: Introduce Asterisk_Tests testsuite
......................................................................

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
---
M Makefile
A asterisk/Asterisk_Tests.cfg
A asterisk/Asterisk_Tests.default
A asterisk/Asterisk_Tests.ttcn
A asterisk/README.md
A asterisk/expected-results.xml
A asterisk/gen_links.sh
A asterisk/regen_makefile.sh
M library/SIP_Emulation.ttcn
M library/SIP_Templates.ttcn
10 files changed, 414 insertions(+), 1 deletion(-)

Approvals:
  laforge: Looks good to me, but someone else must approve
  fixeria: Looks good to me, approved
  Jenkins Builder: Verified




diff --git a/Makefile b/Makefile
index 51e51ed..bd88ca5 100644
--- a/Makefile
+++ b/Makefile
@@ -14,6 +14,7 @@
 # limitations under the License.

 SUBDIRS= \
+       asterisk \
        bsc \
        bsc-nat \
        bts \
diff --git a/asterisk/Asterisk_Tests.cfg b/asterisk/Asterisk_Tests.cfg
new file mode 100644
index 0000000..a3669f9
--- /dev/null
+++ b/asterisk/Asterisk_Tests.cfg
@@ -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
diff --git a/asterisk/Asterisk_Tests.default b/asterisk/Asterisk_Tests.default
new file mode 100644
index 0000000..a2fda0f
--- /dev/null
+++ b/asterisk/Asterisk_Tests.default
@@ -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]
diff --git a/asterisk/Asterisk_Tests.ttcn b/asterisk/Asterisk_Tests.ttcn
new file mode 100644
index 0000000..5d9754e
--- /dev/null
+++ b/asterisk/Asterisk_Tests.ttcn
@@ -0,0 +1,240 @@
+module Asterisk_Tests {
+
+/* Asterisk test suite in TTCN-3
+ * (C) 2024 by sysmocom - s.f.m.c. GmbH <i...@sysmocom.de>
+ * All rights reserved.
+ * Author: Pau Espin Pedrol <pes...@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() );
+}
+
+}
diff --git a/asterisk/README.md b/asterisk/README.md
new file mode 100644
index 0000000..c034bbb
--- /dev/null
+++ b/asterisk/README.md
@@ -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)"];
+}
+%}
diff --git a/asterisk/expected-results.xml b/asterisk/expected-results.xml
new file mode 100644
index 0000000..c1d9e2e
--- /dev/null
+++ b/asterisk/expected-results.xml
@@ -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>
diff --git a/asterisk/gen_links.sh b/asterisk/gen_links.sh
new file mode 100755
index 0000000..1fd6ecc
--- /dev/null
+++ b/asterisk/gen_links.sh
@@ -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
diff --git a/asterisk/regen_makefile.sh b/asterisk/regen_makefile.sh
new file mode 100755
index 0000000..3995b3d
--- /dev/null
+++ b/asterisk/regen_makefile.sh
@@ -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
diff --git a/library/SIP_Emulation.ttcn b/library/SIP_Emulation.ttcn
index e71c611..41e6975 100644
--- a/library/SIP_Emulation.ttcn
+++ b/library/SIP_Emulation.ttcn
@@ -72,6 +72,13 @@
        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 @@
        payload := *
 }

-
 template SipUrl tr_SIP_Url(template charstring user_or_num,
                           template charstring host := *,
                           template integer portField := *) := {
@@ -286,6 +292,19 @@
                        }
                        }

+               /* 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;
diff --git a/library/SIP_Templates.ttcn b/library/SIP_Templates.ttcn
index f48d137..fc8e23f 100644
--- a/library/SIP_Templates.ttcn
+++ b/library/SIP_Templates.ttcn
@@ -525,6 +525,26 @@
        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

--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/36490?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: I66f776d5df6fb5dc488d9e589b84a6b2385406e8
Gerrit-Change-Number: 36490
Gerrit-PatchSet: 3
Gerrit-Owner: pespin <pes...@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanits...@sysmocom.de>
Gerrit-Reviewer: laforge <lafo...@osmocom.org>
Gerrit-Reviewer: pespin <pes...@sysmocom.de>
Gerrit-MessageType: merged

Reply via email to