s1gw: add first testcases TC_setup and TC_setup_multi

Change-Id: Ia2fc53306ac09064c071fd9ff86cf7ccfc42fcec
Related: SYS#6772
diff --git a/s1gw/S1GW_Tests.default b/s1gw/S1GW_Tests.default
index 1c220d8..ceca1b2 100644
--- a/s1gw/S1GW_Tests.default
+++ b/s1gw/S1GW_Tests.default
@@ -1,5 +1,6 @@
 [LOGGING]
 FileMask := LOG_ALL | TTCN_MATCHING;
+ConsoleMask := ERROR | WARNING | PARALLEL | VERDICTOP | USER;
 mtc.FileMask := ERROR | WARNING | PARALLEL | VERDICTOP;
 
 [TESTPORT_PARAMETERS]
diff --git a/s1gw/S1GW_Tests.ttcn b/s1gw/S1GW_Tests.ttcn
index 7f9bd44..ad42a59 100644
--- a/s1gw/S1GW_Tests.ttcn
+++ b/s1gw/S1GW_Tests.ttcn
@@ -14,18 +14,180 @@
 module S1GW_Tests {
 
 import from General_Types all;
+import from Osmocom_Types all;
 import from Native_Functions all;
 import from IPL4asp_Types all;
 import from Misc_Helpers all;
+
+import from S1AP_CodecPort all;
+import from S1AP_CodecPort_CtrlFunct all;
 import from S1AP_Types all;
 import from S1AP_Templates all;
 import from S1AP_PDU_Descriptions all;
 import from S1AP_IEs all;
 import from S1AP_PDU_Contents all;
 import from S1AP_Constants all;
-import from Osmocom_Types all;
+
+import from S1AP_Server all;
+
+modulepar {
+	charstring mp_s1gw_ip := "127.0.1.1";
+	charstring mp_mme_bind_ip := "127.0.2.10";
+}
+
+private type record of ConnHdlr ConnHdlrList;
+
+type component ConnHdlr extends S1APSRV_ConnHdlr {
+	port S1AP_CODEC_PT S1AP_ENB;
+	var ConnectionId g_s1ap_conn_id := -1;
+};
+
+type component test_CT {
+	var S1AP_Server_CT vc_S1APSRV;
+};
+
+template Global_ENB_ID
+ts_Global_ENB_ID(integer enb_id := 0,
+		 OCT3 plmn_id := '00f110'O) := {
+	pLMNidentity := plmn_id,
+	eNB_ID := {
+		macroENB_ID := int2bit(enb_id, 20)
+	},
+	iE_Extensions := omit
+}
+
+function f_init_s1ap_srv() runs on test_CT {
+	var S1APSRV_ConnParams cpars := {
+		local_ip := mp_mme_bind_ip,
+		local_port := 36412
+	};
+
+	vc_S1APSRV := S1AP_Server_CT.create("S1APSRV-" & testcasename());
+	vc_S1APSRV.start(S1AP_Server.main(cpars));
+}
+
+type union ConnHdlrPars {
+	integer seed
+};
+
+type function void_fn(ConnHdlrPars pars) runs on ConnHdlr;
+
+function f_ConnHdlr_spawn(void_fn fn, ConnHdlrPars pars)
+runs on test_CT return ConnHdlr {
+	var ConnHdlr vc_conn;
+
+	vc_conn := ConnHdlr.create("ConnHdlr-" & testcasename());
+	connect(vc_conn:S1AP_CONN, vc_S1APSRV:S1AP_CLIENT);
+	connect(vc_conn:S1AP_PROC, vc_S1APSRV:S1AP_PROC);
+	vc_conn.start(derefers(fn)(pars));
+
+	return vc_conn;
+}
+
+function f_ConnHdlr_connect() runs on ConnHdlr {
+	var Result res;
+
+	map(self:S1AP_ENB, system:S1AP_CODEC_PT);
+	res := S1AP_CodecPort_CtrlFunct.f_IPL4_connect(S1AP_ENB,
+						       mp_s1gw_ip, 36412,
+						       "0.0.0.0", 0, -1,
+						       { sctp := valueof(ts_SCTP) });
+	if (not ispresent(res.connId)) {
+		setverdict(fail, "Could not create an S1AP socket, check your configuration");
+		mtc.stop;
+	}
+	g_s1ap_conn_id := res.connId;
+
+	log("eNB connection established");
+}
+
+function f_ConnHdlr_disconnect() runs on ConnHdlr {
+	var Result res;
+
+	S1AP_CodecPort_CtrlFunct.f_IPL4_close(S1AP_ENB, g_s1ap_conn_id,
+					      { sctp := valueof(ts_SCTP) });
+	g_s1ap_conn_id := -1;
+	unmap(self:S1AP_ENB, system:S1AP_CODEC_PT);
+
+	S1AP_CONN.receive(S1APSRV_Event:S1APSRV_EVENT_CONN_DOWN);
+
+	log("eNB connection closed");
+}
+
+function f_ConnHdlr_setup(Global_ENB_ID genb_id) runs on ConnHdlr {
+	var S1AP_PDU pdu;
+	timer T;
+
+	var SupportedTAs supported_tas_dummy := {
+		{
+			tAC := '0000'O,
+			broadcastPLMNs := { '00f000'O },
+			iE_Extensions := omit
+		}
+	};
+
+	S1AP_ENB.send(t_S1AP_Send(g_s1ap_conn_id,
+				  ts_S1AP_SetupReq(genb_id,
+						   supported_tas_dummy,
+						   v32)));
+	T.start(1.0);
+	alt {
+	[] S1AP_CONN.receive(S1APSRV_Event:S1APSRV_EVENT_CONN_UP) { repeat; }
+	[] S1AP_CONN.receive(tr_S1AP_SetupReq) {
+		setverdict(pass);
+		T.stop;
+		}
+	[] S1AP_CONN.receive(S1AP_PDU:?) -> value pdu {
+		setverdict(fail, "Rx unexpected S1AP PDU: ", pdu);
+		T.stop;
+		}
+	[] T.timeout {
+		setverdict(fail, "Timeout waiting for S1AP SetupReq");
+		}
+	}
+}
+
+
+function f_TC_setup(ConnHdlrPars pars) runs on ConnHdlr {
+	var Global_ENB_ID genb_id := valueof(ts_Global_ENB_ID(pars.seed));
+
+	f_ConnHdlr_register(genb_id);
+
+	f_ConnHdlr_connect();
+	f_ConnHdlr_setup(genb_id);
+	f_sleep(0.5); /* keep the connection idle for some time */
+	f_ConnHdlr_disconnect();
+
+	f_ConnHdlr_unregister(genb_id);
+}
+testcase TC_setup() runs on test_CT {
+	var ConnHdlrPars pars := { seed := 0 };
+	var ConnHdlr vc_conn;
+
+	f_init_s1ap_srv();
+
+	vc_conn := f_ConnHdlr_spawn(refers(f_TC_setup), pars);
+	vc_conn.done;
+}
+testcase TC_setup_multi() runs on test_CT {
+	var ConnHdlrList vc_conns := { };
+
+	f_init_s1ap_srv();
+
+	for (var integer i := 0; i < 42; i := i + 1) {
+		var ConnHdlrPars pars := { seed := i };
+		var ConnHdlr vc_conn := f_ConnHdlr_spawn(refers(f_TC_setup), pars);
+		vc_conns := vc_conns & { vc_conn };
+	}
+
+	for (var integer i := 0; i < 42; i := i + 1) {
+		vc_conns[i].done;
+	}
+}
 
 control {
+	execute( TC_setup() );
+	execute( TC_setup_multi() );
 }
 
 }