module MME_Tests_SGsAP {

/* Osmocom MME test suite in in TTCN-3, SGsAP related procedures (3GPP TS 29.118, 3GPP TS 23.272)
 * (C) 2019 Harald Welte <laforge@gnumonks.org>
 * All rights reserved.
 *
 * 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 SGsAP_Types all;
import from SGsAP_Templates all;
import from SGsAP_Emulation all;

import from General_Types all;
import from Osmocom_Types all;
import from Misc_Helpers all;
import from L3_Templates all;
import from DNS_Helpers all;
import from MME_Tests all;

import from NAS_EPS_Templates all;

import from ConnHdlr all;

/* performa SGs reset procedure */
function f_sgsap_vlr_reset() runs on MTC_CT {
	var octetstring vlr_name := f_enc_dns_hostname(mp_vlr_name);
	var octetstring mme_name := f_enc_dns_hostname(mp_mme_name);
	var PDU_SGsAP rx_msg;

	SGsAP_UNIT.send(ts_SGsAP_RESET_IND_VLR(vlr_name));
	alt {
	[] SGsAP_UNIT.receive(tr_SGsAP_RESET_ACK_MME(mme_name)) {
		setverdict(pass);
		}
	[] SGsAP_UNIT.receive(tr_SGsAP_RESET_ACK_MME(?)) -> value rx_msg {
		setverdict(fail, "Received unexpected MME name in SGsAP RESET ACK ", rx_msg, " vs exp ", tr_SGsAP_RESET_ACK_MME(mme_name));
		}
	[] SGsAP_UNIT.receive(PDU_SGsAP:?) -> value rx_msg {
		setverdict(fail, "Received unexpected response to SGsAP RESET ", rx_msg, " vs exp ", tr_SGsAP_RESET_ACK_MME(mme_name));
		}
	[] SGsAP_UNIT.receive(SGsAPEM_Event:?) {
		setverdict(fail, "Received unexpected event while waiting for response to SGsAP RESET");
		}
	}
}

/* Test if MME responds to VLR-originated RESET procedure as expected */
testcase TC_sgsap_vlr_reset() runs on MTC_CT {
	f_init(1001, init_sgsap := true);
	f_sgsap_vlr_reset();
}

/* Page known subscriber for SMS
 * 3GPP TS 23.272 8.2.4 Mobile terminating SMS in idle mode */
private function f_TC_sgsap_paging_sms() runs on ConnHdlr {
	f_attach('010'B /*= Combined EPS IMSI Attach*/, exp_sgsap_lu := true);
	f_sgsap_page_sms(omit, omit);
}
testcase TC_sgsap_paging_sms() runs on MTC_CT {
	f_init(1002, init_diameter := true, init_gtpv2c_s11 := true, init_sgsap := true);
	f_s1ap_setup(0);

	var ConnHdlrPars pars := f_init_pars(ue_idx := 0);
	var ConnHdlr vc_conn := f_start_handler_with_pars(refers(f_TC_sgsap_paging_sms), pars);
	vc_conn.done;
}

/* Page known subscriber for CS call
 * 3GPP TS 23.272 7.3 Mobile Terminating call in Active Mode */
private function f_TC_sgsap_paging_cs() runs on ConnHdlr {
	f_attach('010'B /*= Combined EPS IMSI Attach*/, exp_sgsap_lu := true);
	f_sgsap_page_cs(omit, omit);
}
testcase TC_sgsap_paging_cs() runs on MTC_CT {
	f_init(1003, init_diameter := true, init_gtpv2c_s11 := true, init_sgsap := true);
	f_s1ap_setup(0);

	var ConnHdlrPars pars := f_init_pars(ue_idx := 0);
	var ConnHdlr vc_conn := f_start_handler_with_pars(refers(f_TC_sgsap_paging_cs), pars);
	vc_conn.done;
}


/* Page unknown subscriber; expect PAGING REJECT from MME */
private function f_TC_sgsap_paging_reject() runs on ConnHdlr {
	f_sgsap_page_sms(omit, IMSI_unknown);
}
testcase TC_sgsap_paging_reject() runs on MTC_CT {
	f_init(1004, init_sgsap := true);
	f_s1ap_setup(0);

	var ConnHdlrPars pars := f_init_pars(ue_idx := 0);
	var ConnHdlr vc_conn := f_start_handler_with_pars(refers(f_TC_sgsap_paging_reject), pars);
	vc_conn.done;
}

/* Send ALERT-REQ to MME; perform S1AP activity; expect ALERT-ACK on SGs */
private function f_TC_sgsap_alert() runs on ConnHdlr {
	f_attach('010'B /*= Combined EPS IMSI Attach*/, exp_sgsap_lu := true);
	f_sgsap_alert(omit);

	/* Do something on S1 triggering UE ACT IND. non-combined TAU shouldn't
	 * trigger a non-EPS-related procedure and hence a SGsAP-UE-ACTIVITY-IND
	 * should be sent: */
	f_tau(c_EPS_UPD_TYPE_TA_UPD_PERIODIC, exp_sgsap_lu := false);

	timer T := 5.0;
	T.start;
	alt {
	[] SGsAP.receive(tr_SGsAP_UE_ACT_IND(g_pars.ue_pars.imsi)) {
		setverdict(pass);
		}
	[] T.timeout {
		Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
					log2str("Rx no SGsAP-UE-ACTIVITY-INDICATION from MME!"));
		}
	};
}
testcase TC_sgsap_alert() runs on MTC_CT {
	f_init(1005, init_diameter := true, init_gtpv2c_s11 := true, init_sgsap := true);
	f_s1ap_setup(0);

	var ConnHdlrPars pars := f_init_pars(ue_idx := 0);
	var ConnHdlr vc_conn := f_start_handler_with_pars(refers(f_TC_sgsap_alert), pars);
	vc_conn.done;
}

/* Send ALERT-REQ to MME for unidentified IMSI; expect ALERT-REJ on SGs */
private function f_TC_sgsap_alert_rej() runs on ConnHdlr {
	/* IMSI doesn't register and is hence unknown */
	f_sgsap_alert(IMSI_unknown);
}
testcase TC_sgsap_alert_rej() runs on MTC_CT {
	f_init(1006, init_sgsap := true);
	f_s1ap_setup(0);

	var ConnHdlrPars pars := f_init_pars(ue_idx := 0);
	var ConnHdlr vc_conn := f_start_handler_with_pars(refers(f_TC_sgsap_alert_rej), pars);
	vc_conn.done;
}

/* TODO: check for scenarios in sequence charts of 3GPP TS 23.272 */

/* Test SGsAP-DOWNLINK-UNITDATA (SGs -> S1) */
/* Test SGsAP-UPLINK-UNITDATA (S1 -> SGs)*/
/* Test SGSAP-DETACH-IND; detach on S1; expect DETACH-IND on SGs; send DETACH-ACK */
/* Test SGsAP-LU-REQ; perform combined attach on S1; expect LU-REQ; acknowlege it */
/* Test SGsAP-LU-REQ; perform combined attach on S1; expect LU-REQ; reject it */
/* Test SGsAP-MMINFO-REQ; establish SGs association; send it on SGs; expect on S1 */

/* Test MT SERVICE ABORT; send PAGING; expect SERVICE REQ; send SERVICE ABORT */

/* Test EPS DETACH */
/* Test IMSI DETACH */

control {
	execute( TC_sgsap_vlr_reset() );
	execute( TC_sgsap_paging_sms() );
	execute( TC_sgsap_paging_cs() );
	execute( TC_sgsap_paging_reject() );
	execute( TC_sgsap_alert() );
	execute( TC_sgsap_alert_rej() );
}

}
