sccp: Introduce test TC_cr_timeout_cc_too_late

Related: SYS#6602
Change-Id: If4b53565f1fa19894ca24fa71e02ae7b1941411e
diff --git a/library/SCCP_Templates.ttcn b/library/SCCP_Templates.ttcn
index a87ef5c..6c977ac 100644
--- a/library/SCCP_Templates.ttcn
+++ b/library/SCCP_Templates.ttcn
@@ -113,6 +113,39 @@
 	return ret;
 }
 
+template (present) PDU_SCCP tr_SCCP_CR(template (present) OCT3 source_lref := ?,
+				       template (present) SCCP_PAR_Address called := ?,
+				       template (present) SCCP_PAR_Address calling := ?) := {
+	connrequest := {
+			messageType := cr,
+			sourceLocRef := source_lref,
+			protClass := c_class2,
+			pointer1 := ?,
+			pointer2 := ?,
+			calledPAddress := tr_Addr(called),
+			optionalPart := {
+				credit := omit,
+				callingPAddress := tr_Addr_opt(calling),
+				data := omit,
+				hopCounter := *,
+				importance := *
+			},
+			eop := *
+	}
+}
+
+template (value) PDU_SCCP ts_SCCP_CC(OCT3 source_lref, OCT3 dest_lref) := {
+	connconfirm := {
+		messageType := cc,
+		destLocRef := dest_lref,
+		sourceLocRef := source_lref,
+		protClass := c_class2,
+		pointer1 := 0, /* overwritten */
+		optionalPart := omit,
+		eop := { paramName:= con_SCCP_eop }
+	}
+}
+
 template (present) PDU_SCCP tr_SCCP_CC(template (present) OCT3 source_lref,
 				       template (present) OCT3 dest_lref) := {
 	connconfirm := {
@@ -135,6 +168,25 @@
 	}
 }
 
+private function tr_Addr_opt(template SCCP_PAR_Address addr := *)
+return template SCCP_param_CPartyAddressEnc_opt {
+	if (istemplatekind(addr, "omit")) {
+		return omit;
+	} else if (istemplatekind(addr, "*")) {
+		return *;
+	} else if (istemplatekind(addr, "?")) {
+		return ?;
+	} else {
+		var SCCP_param_CPartyAddressEnc enc := ConvertASPAddressToEncodedAddress_itu(valueof(addr));
+		var SCCP_param_CPartyAddressEnc_opt enc_opt := {
+			paramName := con_SCCP_cgPA,
+			paramLength := enc.paramLength, /* overwritten */
+			addr := enc.addr
+		};
+		return enc_opt;
+	}
+}
+
 template (value) PDU_SCCP ts_SCCP_UDT(SCCP_PAR_Address calling, SCCP_PAR_Address called,
 				      template (value) octetstring data,
 				      template (value) BIT4 msg_hdl := '0000'B) := {
diff --git a/sccp/SCCP_Tests_RAW.ttcn b/sccp/SCCP_Tests_RAW.ttcn
index 1c81d98..5849dad 100644
--- a/sccp/SCCP_Tests_RAW.ttcn
+++ b/sccp/SCCP_Tests_RAW.ttcn
@@ -69,6 +69,18 @@
 			  "sccp-timer iar " & int2str(g_demo_sccp_timer_iar)});
 }
 
+function f_vty_cmd_connect_req(integer conn_id) runs on SCCP_Test_RAW_CT {
+	f_vty_transceive(SCCP_DEMO_USER_VTY, "sccp-user");
+	f_vty_transceive(SCCP_DEMO_USER_VTY, "connect-req " & int2str(conn_id));
+	f_vty_transceive(SCCP_DEMO_USER_VTY, "end");
+}
+
+function f_vty_cmd_disconnect_req(integer conn_id) runs on SCCP_Test_RAW_CT {
+	f_vty_transceive(SCCP_DEMO_USER_VTY, "sccp-user");
+	f_vty_transceive(SCCP_DEMO_USER_VTY, "disconnect-req " & int2str(conn_id));
+	f_vty_transceive(SCCP_DEMO_USER_VTY, "end");
+}
+
 private function f_init_raw(SCCP_Configuration cfg) runs on SCCP_Test_RAW_CT {
 	g_param := {
 		sio := {
@@ -483,6 +495,37 @@
 }
 
 
+/* Test user initiating a conn (eg RUA), which triggers SCCP CR. While waiting
+ * for CC, user decides it timed out (eg. RUA side timeout) which makes it move to
+ * WAIT_CONN_CONF state. In that state, wait for CC and then submit an RLSD and
+ * wait for ack. */
+testcase TC_cr_timeout_cc_too_late() runs on SCCP_Test_RAW_CT {
+	var SCCP_MTP3_TRANSFERind mtp3_rx;
+	var integer conn_id := 1234;
+	var OCT3 remote_lref;
+
+	f_init_raw(mp_sccp_cfg[0]);
+	f_sleep(1.0);
+
+	f_vty_cmd_connect_req(conn_id);
+	mtp3_rx := f_exp_sccp(tr_SCCP_CR(?, ?, ?));
+
+	/* Emulate disconnection from the user: */
+	f_vty_cmd_disconnect_req(conn_id);
+	remote_lref := mtp3_rx.data.connrequest.sourceLocRef;
+
+	/* Now send CC, user should send RLSD to us: */
+	f_send_sccp(ts_SCCP_CC(g_own_lref, remote_lref));
+	log("Waiting for RLSD");
+	 /* Cause set hardcoded by osmo_sccp_demo_user VTY code, nothing to test here: */
+	var template (present) integer cause := ?;
+	f_exp_sccp(tr_SCCP_RLSD(remote_lref, g_own_lref, cause));
+	f_send_sccp(ts_SCCP_RLC(g_own_lref, remote_lref));
+
+	setverdict(pass);
+}
+
+
 control {
 	execute( TC_cr_cc() );
 	execute( TC_udt_without_cr_cc() );
@@ -496,6 +539,7 @@
 	execute( TC_scmg_sst_ssn_invalid() );
 
 	execute( TC_callingparty_ssn_only() );
+	execute( TC_cr_timeout_cc_too_late() );
 }