Loading ttcn/AtsNGAP/NGAP_Steps.ttcn +3 −1 Changes for ttcn/AtsNGAP/NGAP_Steps.ttcn: 3 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -906,7 +906,9 @@ module NGAP_Steps { // TODO FSCOM f_xxx_UE_SecurityMode to be mmoved into NAG_NG /** * @brief Leave the real UE in a known state at the end of a test: deregistered, in flight mode. * @details Unless PX_UT_DEREGISTER_TIMEOUT is 0.0: asks the upper tester to switch the modem to flight * mode (DEREGISTER, AT+CFUN=4), without waiting for the confirmation, then serves the * mode (DEREGISTER: AT+CFUN=4, preceded by AT+CGATT=0 with the rm520n-gl modem profile, as * this modem detaches locally, without signalling, on AT+CFUN=4 alone in 5GMM-IDLE), without * waiting for the confirmation, then serves the * deregistration the UE starts on its own (f_await_deregistration_request_send_ue_context_release): * its DEREGISTRATION REQUEST, the DEREGISTRATION ACCEPT unless it is a switch off, and the release * of its UE context. The UE does not stay registered with, or connected to, the gNB between tests, Loading ttcn/LibNGAP/lib_system/LibNGAP_Functions.ttcn +40 −35 Changes for ttcn/LibNGAP/lib_system/LibNGAP_Functions.ttcn: 40 added lines, 35 removed lines. Original line number Diff line number Diff line Loading @@ -1253,7 +1253,6 @@ module LibNGAP_Functions { setverdict(pass, "Received SECURITY_MODE_COMMAND NAS message"); } log("v_message: ", v_message); setverdict(pass, "Received SECURITY_MODE_COMMAND NAS message"); // Await response for SECURITY_MODE_COMPLETE f_recv_NGAP_PDU( Loading Loading @@ -1326,7 +1325,6 @@ module LibNGAP_Functions { setverdict(pass); } log("v_message: ", v_message); setverdict(pass, "Received REGISTRATION_ACCEPT NAS message"); // Await InitialContextSetupResponse f_recv_NGAP_PDU( Loading @@ -1337,7 +1335,7 @@ module LibNGAP_Functions { ))); vc_ueContextReleased := false; setverdict(pass, "Received InitialContextSetupResponse NAS message"); setverdict(pass, "Received InitialContextSetupResponse NGAP message"); log("<<< f_await_initial_context_setup_request_await_initial_context_setup_resonse"); } Loading Loading @@ -1381,7 +1379,6 @@ module LibNGAP_Functions { setverdict(pass); } log("v_message: ", v_message); setverdict(pass, "Received REGISTRATION_ACCEPT NAS message"); // Send InitialContextSetupResponse f_send_NGAP_PDU( Loading Loading @@ -1564,7 +1561,7 @@ module LibNGAP_Functions { ))); vc_ueContextReleased := false; // FIXME FSCOM To be continued setverdict(pass, "Received InitialContextSetupResponse NAS message"); setverdict(pass, "Received InitialContextSetupResponse NGAP message"); log("<<< f_send_initial_context_setup_request_await_initial_context_setup_resonse"); } Loading Loading @@ -1667,7 +1664,7 @@ module LibNGAP_Functions { m_tAI ))))); setverdict(pass, "Sent UplinkNASTransport NAS message"); setverdict(pass, "Sent REGISTRATION_COMPLETE NAS message"); } /** Loading Loading @@ -1696,7 +1693,7 @@ module LibNGAP_Functions { vc_RAN_UE_ID, ? ))); setverdict(pass, "Received UERadioCapabilityInfoIndication NAS message"); setverdict(pass, "Received UERadioCapabilityInfoIndication NGAP message"); } [] N2_gNBaMF_P.check(receive(NGAP_PDU: ?)) { // continue Loading Loading @@ -1933,6 +1930,7 @@ module LibNGAP_Functions { value_ := ? } )); setverdict(pass, "Received UE CONTEXT RELEASE COMMAND NGAP message"); f_recv_NGAP_PDU( mw_ngap_succMsg( Loading @@ -1943,8 +1941,10 @@ module LibNGAP_Functions { } )); if (not f_NGAP_check_received_PDU(mw_ngap_succMsg(mw_n2_UEContextReleaseComplete_conformant), "UE CONTEXT RELEASE COMPLETE")) { log("f_await_ue_context_release_command_await_ue_context_release_complete: verdict set to fail"); setverdict(fail, "Received UE CONTEXT RELEASE COMPLETE NGAP message does not conform to TS 38.413"); return; } setverdict(pass, "Received UE CONTEXT RELEASE COMPLETE NGAP message"); } // End of function f_await_ue_context_release_command_await_ue_context_release_complete /** Loading Loading @@ -2828,7 +2828,7 @@ module LibNGAP_Functions { var NG_PDU_SESSION_RELEASE_COMMAND v_ng_pdu_session_release_command; if (decvalue(v_bs, v_ng_pdu_session_release_command) != 0) { log("f_await_pdu_session_resource_release_command: Failed to decode dl_Nas_Transport payload"); setverdict(inconc); setverdict(inconc, "Failed to decode dl_Nas_Transport payload"); } else { log("f_await_pdu_session_resource_release_command: v_ng_pdu_session_release_command: ", v_ng_pdu_session_release_command); var NG_NAS_DL_Message_Type v_expected_message; Loading @@ -2836,10 +2836,10 @@ module LibNGAP_Functions { if (not(match(v_expected_message, mw_NG_PDU_SESSION_RELEASE_COMMAND(cs_NG_PDU_SessionId(int2oct(vc_pdu_session_resource_setup_list_su_req[0].pDUSessionID, 1), omit))))) { log(match(v_expected_message, mw_NG_PDU_SESSION_RELEASE_COMMAND(cs_NG_PDU_SessionId(int2oct(vc_pdu_session_resource_setup_list_su_req[0].pDUSessionID, 1), omit)))); // Log mismatch log("f_await_pdu_session_resource_release_command: FAIL: NG_PDU_SESSION_RELEASE_COMMAND mismatch."); setverdict(fail); setverdict(fail, "Received NG_PDU_SESSION_RELEASE_COMMAND for PDU session ID " & vc_pdu_session_resource_setup_list_su_req[0].pDUSessionID & " does not match expected"); } else { log("f_await_pdu_session_resource_release_command: PASS: Expected NG_PDU_SESSION_RELEASE_COMMAND"); setverdict(pass); setverdict(pass, "Received NG_PDU_SESSION_RELEASE_COMMAND for PDU session ID " & vc_pdu_session_resource_setup_list_su_req[0].pDUSessionID); } } } Loading Loading @@ -2953,7 +2953,7 @@ module LibNGAP_Functions { setverdict(fail); } else { log("f_await_configuration_update_command: PASS: Expected NG_CONFIGURATION_UPDATE_COMMAND"); setverdict(pass); setverdict(pass, "Received NG_CONFIGURATION_UPDATE_COMMAND with expected time zone, time and daylight saving time"); } log("v_message: ", v_message); Loading @@ -2973,6 +2973,7 @@ module LibNGAP_Functions { vc_AMF_UE_ID, vc_RAN_UE_ID ))); setverdict(pass, "Received INITIAL CONTEXT SETUP FAILURE NGAP message"); } /** Loading @@ -2989,6 +2990,7 @@ module LibNGAP_Functions { vc_RAN_UE_ID, m_cause_radioNetwork(unspecified) ))); setverdict(pass, "Sent INITIAL CONTEXT SETUP FAILURE NGAP message"); } /** Loading @@ -3005,6 +3007,7 @@ module LibNGAP_Functions { mw_ngap_initMsg( mw_n2_UEContextReleaseCommand )); setverdict(pass, "Received UE CONTEXT RELEASE COMMAND NGAP message with cause: " & p_Cause); // Send UEContextReleaseComplete f_send_NGAP_PDU( Loading @@ -3013,12 +3016,7 @@ module LibNGAP_Functions { vc_AMF_UE_ID, vc_RAN_UE_ID ))); // f_send_NGAP_PDU( // m_ngap_succMsg( // m_n2_UEContextReleaseComplete_noPDUSessionResourceSetupListSURes( // vc_AMF_UE_ID, // vc_RAN_UE_ID // ))); setverdict(pass, "Sent UE CONTEXT RELEASE COMPLETE NGAP message"); } /** Loading @@ -3035,6 +3033,7 @@ module LibNGAP_Functions { vc_RAN_UE_ID, m_cause_radioNetwork(unspecified) ))); setverdict(pass, "Received UE CONTEXT RELEASE REQUEST NGAP message"); } /** Loading @@ -3051,6 +3050,7 @@ module LibNGAP_Functions { vc_RAN_UE_ID, m_cause_radioNetwork(unspecified) ))); setverdict(pass, "Sent UE CONTEXT RELEASE REQUEST NGAP message"); } /** Loading @@ -3066,6 +3066,7 @@ module LibNGAP_Functions { vc_AMF_UE_ID, vc_RAN_UE_ID ))); setverdict(pass, "Received UE CONTEXT RELEASE COMPLETE NGAP message"); } /** Loading @@ -3081,12 +3082,7 @@ module LibNGAP_Functions { vc_AMF_UE_ID, vc_RAN_UE_ID ))); // f_send_NGAP_PDU( // m_ngap_succMsg( // m_n2_UEContextReleaseComplete_noPDUSessionResourceSetupListSURes( // vc_AMF_UE_ID, // vc_RAN_UE_ID // ))); setverdict(pass, "Sent UE CONTEXT RELEASE COMPLETE NGAP message"); } /** Loading @@ -3108,6 +3104,8 @@ module LibNGAP_Functions { vc_RAN_UE_ID, p_Cause ))); setverdict(pass, "Sent UE CONTEXT RELEASE REQUEST NGAP message with cause: " & p_Cause); // Await UEContextReleaseCommand f_recv_NGAP_PDU( mw_ngap_initMsg( Loading @@ -3115,6 +3113,8 @@ module LibNGAP_Functions { -, p_Cause ))); setverdict(pass, "Received UE CONTEXT RELEASE COMMAND NGAP message with cause: " & p_Cause); // Send UEContextReleaseComplete f_send_NGAP_PDU( m_ngap_succMsg( Loading @@ -3122,12 +3122,7 @@ module LibNGAP_Functions { vc_AMF_UE_ID, vc_RAN_UE_ID ))); // f_send_NGAP_PDU( // m_ngap_succMsg( // m_n2_UEContextReleaseComplete( // vc_AMF_UE_ID, // vc_RAN_UE_ID // ))); setverdict(pass, "Sent UE CONTEXT RELEASE COMPLETE NGAP message"); } /** Loading @@ -3147,6 +3142,8 @@ module LibNGAP_Functions { vc_RAN_UE_ID, p_Cause ))); setverdict(pass, "Received UE CONTEXT RELEASE REQUEST NGAP message with cause: " & p_Cause); // Await UEContextReleaseCommand f_recv_NGAP_PDU( mw_ngap_initMsg( Loading @@ -3154,6 +3151,8 @@ module LibNGAP_Functions { -, p_Cause ))); setverdict(pass, "Received UE CONTEXT RELEASE COMMAND NGAP message with cause: " & p_Cause); // await UEContextReleaseComplete f_recv_NGAP_PDU( mw_ngap_succMsg( Loading @@ -3161,6 +3160,7 @@ module LibNGAP_Functions { vc_AMF_UE_ID, vc_RAN_UE_ID ))); setverdict(pass, "Received UE CONTEXT RELEASE COMPLETE NGAP message with cause: " & p_Cause); } /** Loading Loading @@ -3212,7 +3212,7 @@ module LibNGAP_Functions { m_tAI ))))); setverdict(pass); setverdict(pass, "Sent NG_DEREGISTRATION_REQUEST_MO NAS message"); } /** Loading @@ -3232,6 +3232,7 @@ module LibNGAP_Functions { f_NASPDU_Get(vc_recvNGAP_PDU) if (match(vc_recvNgNasUl_Msg, mw_NG_DEREGISTRATION_REQUEST_MO)) { log("Received NG_DEREGISTRATION_REQUEST_MO NAS message"); setverdict(pass, "Received NG_DEREGISTRATION_REQUEST_MO NAS message"); } else { log("*** " & __SCOPE__ & ": FAIL: Unexpected NAS message"); setverdict(fail, "*** " & __SCOPE__ & ": FAIL: Unexpected NAS message"); Loading Loading @@ -3265,10 +3266,10 @@ module LibNGAP_Functions { vc_inner_message ) == false) { log("*** " & __SCOPE__ & ": FAIL: mw_NG_DEREGISTRATION_ACCEPT_MO mismatch."); setverdict(fail); setverdict(fail, "Received unexpected NAS message"); } else { log("*** " & __SCOPE__ & ": PASS: Expected mw_NG_DEREGISTRATION_ACCEPT_MO"); setverdict(pass); setverdict(pass, "Received mw_NG_DEREGISTRATION_ACCEPT_MO NAS message"); } log("v_message: ", v_message); } Loading Loading @@ -3300,10 +3301,10 @@ module LibNGAP_Functions { vc_inner_message ) == false) { log("*** " & __SCOPE__ & ": FAIL: mw_NG_DEREGISTRATION_ACCEPT_MO mismatch."); setverdict(fail); setverdict(fail, "Received unexpected NAS message"); } else { log("*** " & __SCOPE__ & ": PASS: Expected mw_NG_DEREGISTRATION_ACCEPT_MO"); setverdict(pass); setverdict(pass, "Received mw_NG_DEREGISTRATION_ACCEPT_MO NAS message"); } log("v_message: ", v_message); Loading @@ -3324,6 +3325,7 @@ module LibNGAP_Functions { mw_n2_ErrorIndication( p_cause ))); setverdict(pass, "Received ERROR INDICATION NGAP message with cause: " & p_cause); } /** Loading @@ -3343,6 +3345,7 @@ module LibNGAP_Functions { vc_RAN_UE_ID, p_cause ))); setverdict(pass, "Received ERROR INDICATION NGAP message with cause: " & p_cause); } /** Loading @@ -3360,6 +3363,7 @@ module LibNGAP_Functions { m_n2_ErrorIndication( p_cause ))); setverdict(pass, "Sent ERROR INDICATION NGAP message with cause: " & p_cause); } /** Loading @@ -3379,6 +3383,7 @@ module LibNGAP_Functions { vc_RAN_UE_ID, p_cause ))); setverdict(pass, "Sent ERROR INDICATION NGAP message with cause: " & p_cause); } /** Loading upper_tester/profiles.py +3 −0 Changes for upper_tester/profiles.py: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -139,6 +139,9 @@ BUILTIN: dict[str, ModemProfile] = { timeouts=(("AT+QNETDEVCTL", 160.0), ("AT+QIACT", 150.0), ("AT+QIDEACT", 40.0)) + _GENERIC_TIMEOUTS, ping_command='AT+QPING={cid},"{host}",{timeout},{count}', dial="qiact", # In 5GMM-IDLE, AT+CFUN=4 alone detaches locally, without any DEREGISTRATION REQUEST: # detach first, which the modem signals to the network mmi={"DEREGISTER": ("AT+CGATT=0", "AT+CFUN=4")}, refused=( (r"AT\+COPS=2", "deregistering with AT+COPS=2 leaves the RM520N-GL in '+CME ERROR: SIM failure'" " until it is power cycled; use AT+CFUN=4 (MMI DEREGISTER) instead"), Loading upper_tester/tests/test_ut.py +15 −2 Changes for upper_tester/tests/test_ut.py: 15 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -108,10 +108,16 @@ class TestServer(Base): self.assertIn("AT+CFUN=1", self.fake.received) async def test_mmi_step_failure(self): self.modem.profile = profiles.load("generic") # DEREGISTER is AT+CFUN=4 alone (mmi.MMI_TABLE) r = await self.call(id=10, type="MMI", cmd="DEREGISTER") self.assertFalse(r["result"]) self.assertEqual(r["result_string"], "AT> AT+CFUN=4 -> +CME ERROR: 3") async def test_rm520n_deregister_detaches_first(self): self.fake.script = {"AT+CGATT=0": ["OK"], "AT+CFUN=4": ["OK"]} self.assertTrue((await self.call(id=16, type="MMI", cmd="DEREGISTER"))["result"]) self.assertEqual(self.fake.received, ["AT+CGATT=0", "AT+CFUN=4"]) async def test_success_keeps_plain_response(self): r = await self.call(id=13, type="MMI", cmd="POWER_ON") self.assertEqual(r["result_string"], "OK") Loading Loading @@ -392,11 +398,18 @@ class TestPing(Base): self.assertIn("AT> (URC +QPING:) -> +QPING: 561,0,0,0,0,0,0", r["result_string"]) self.assertTrue(r["result_string"].endswith("+UT: ping 10.174.19.14 failed: error 561"), r) async def test_ping_without_summary_times_out(self): async def test_ping_without_summary_after_lost_replies_succeeds(self): # The RM520N-GL reports the first lost reply only, and no summary self.fake.script[self.PING] = ["OK", "+QPING: 569"] r = await self.ping() self.assertTrue(r["result"], r) self.assertTrue(r["result_string"].endswith("+UT: ping 10.174.19.14: 1 result(s), no summary from the modem"), r) async def test_ping_without_any_result_fails(self): self.fake.script[self.PING] = ["OK"] r = await self.ping() self.assertFalse(r["result"]) self.assertIn("no summary", r["result_string"]) self.assertIn("no result from the modem", r["result_string"]) async def test_ping_error_code_alone_ends_at_once(self): self.fake.script['AT+QPING=1,"10.174.19.14",10,2'] = ["OK", "+QPING: 561"] Loading upper_tester/userdata.py +8 −2 Changes for upper_tester/userdata.py: 8 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -75,7 +75,10 @@ def ping(modem, params: dict[str, str], timeout: float | None = None, on_written @param timeout Overrides the timeout of the ping command itself (not of the replies). @param on_written Forwarded to modem.AtModem.execute. @return `(result, result_string)`. `result` is true once the modem has run the pings and reported its summary with a final result 0, whether or not replies came back. reported its summary with a final result 0, whether or not replies came back. It is also true when the summary does not come but per-ping results did, without an error code: the RM520N-GL reports only the first `+QPING: 569` when no reply comes back, and no summary, although it sends every echo request. `result_string` holds the response and the `+QPING:` lines, and ends with `+UT: ping <host>: sent=<n> rcvd=<n> lost=<n> min=<ms> max=<ms> avg=<ms>`, or with a `+UT:` line giving the reason of the failure. Loading Loading @@ -110,8 +113,11 @@ def ping(modem, params: dict[str, str], timeout: float | None = None, on_written error = _error(early) if summary is None and error is not None: return False, f"{text}\r\n+UT: ping {host} failed: error {error}" if summary is None and early: log.info("ping %s: %d result(s), no summary", host, len(early)) return True, f"{text}\r\n+UT: ping {host}: {len(early)} result(s), no summary from the modem" if summary is None: return False, f"{text}\r\n+UT: ping {host}: no summary from the modem" return False, f"{text}\r\n+UT: ping {host}: no result from the modem" names = ("sent", "rcvd", "lost", "min", "max", "avg") report = " ".join(f"{n}={v}" for n, v in zip(names, summary[1:])) if summary[0] != "0": Loading Loading
ttcn/AtsNGAP/NGAP_Steps.ttcn +3 −1 Changes for ttcn/AtsNGAP/NGAP_Steps.ttcn: 3 added lines, 1 removed line. Original line number Diff line number Diff line Loading @@ -906,7 +906,9 @@ module NGAP_Steps { // TODO FSCOM f_xxx_UE_SecurityMode to be mmoved into NAG_NG /** * @brief Leave the real UE in a known state at the end of a test: deregistered, in flight mode. * @details Unless PX_UT_DEREGISTER_TIMEOUT is 0.0: asks the upper tester to switch the modem to flight * mode (DEREGISTER, AT+CFUN=4), without waiting for the confirmation, then serves the * mode (DEREGISTER: AT+CFUN=4, preceded by AT+CGATT=0 with the rm520n-gl modem profile, as * this modem detaches locally, without signalling, on AT+CFUN=4 alone in 5GMM-IDLE), without * waiting for the confirmation, then serves the * deregistration the UE starts on its own (f_await_deregistration_request_send_ue_context_release): * its DEREGISTRATION REQUEST, the DEREGISTRATION ACCEPT unless it is a switch off, and the release * of its UE context. The UE does not stay registered with, or connected to, the gNB between tests, Loading
ttcn/LibNGAP/lib_system/LibNGAP_Functions.ttcn +40 −35 Changes for ttcn/LibNGAP/lib_system/LibNGAP_Functions.ttcn: 40 added lines, 35 removed lines. Original line number Diff line number Diff line Loading @@ -1253,7 +1253,6 @@ module LibNGAP_Functions { setverdict(pass, "Received SECURITY_MODE_COMMAND NAS message"); } log("v_message: ", v_message); setverdict(pass, "Received SECURITY_MODE_COMMAND NAS message"); // Await response for SECURITY_MODE_COMPLETE f_recv_NGAP_PDU( Loading Loading @@ -1326,7 +1325,6 @@ module LibNGAP_Functions { setverdict(pass); } log("v_message: ", v_message); setverdict(pass, "Received REGISTRATION_ACCEPT NAS message"); // Await InitialContextSetupResponse f_recv_NGAP_PDU( Loading @@ -1337,7 +1335,7 @@ module LibNGAP_Functions { ))); vc_ueContextReleased := false; setverdict(pass, "Received InitialContextSetupResponse NAS message"); setverdict(pass, "Received InitialContextSetupResponse NGAP message"); log("<<< f_await_initial_context_setup_request_await_initial_context_setup_resonse"); } Loading Loading @@ -1381,7 +1379,6 @@ module LibNGAP_Functions { setverdict(pass); } log("v_message: ", v_message); setverdict(pass, "Received REGISTRATION_ACCEPT NAS message"); // Send InitialContextSetupResponse f_send_NGAP_PDU( Loading Loading @@ -1564,7 +1561,7 @@ module LibNGAP_Functions { ))); vc_ueContextReleased := false; // FIXME FSCOM To be continued setverdict(pass, "Received InitialContextSetupResponse NAS message"); setverdict(pass, "Received InitialContextSetupResponse NGAP message"); log("<<< f_send_initial_context_setup_request_await_initial_context_setup_resonse"); } Loading Loading @@ -1667,7 +1664,7 @@ module LibNGAP_Functions { m_tAI ))))); setverdict(pass, "Sent UplinkNASTransport NAS message"); setverdict(pass, "Sent REGISTRATION_COMPLETE NAS message"); } /** Loading Loading @@ -1696,7 +1693,7 @@ module LibNGAP_Functions { vc_RAN_UE_ID, ? ))); setverdict(pass, "Received UERadioCapabilityInfoIndication NAS message"); setverdict(pass, "Received UERadioCapabilityInfoIndication NGAP message"); } [] N2_gNBaMF_P.check(receive(NGAP_PDU: ?)) { // continue Loading Loading @@ -1933,6 +1930,7 @@ module LibNGAP_Functions { value_ := ? } )); setverdict(pass, "Received UE CONTEXT RELEASE COMMAND NGAP message"); f_recv_NGAP_PDU( mw_ngap_succMsg( Loading @@ -1943,8 +1941,10 @@ module LibNGAP_Functions { } )); if (not f_NGAP_check_received_PDU(mw_ngap_succMsg(mw_n2_UEContextReleaseComplete_conformant), "UE CONTEXT RELEASE COMPLETE")) { log("f_await_ue_context_release_command_await_ue_context_release_complete: verdict set to fail"); setverdict(fail, "Received UE CONTEXT RELEASE COMPLETE NGAP message does not conform to TS 38.413"); return; } setverdict(pass, "Received UE CONTEXT RELEASE COMPLETE NGAP message"); } // End of function f_await_ue_context_release_command_await_ue_context_release_complete /** Loading Loading @@ -2828,7 +2828,7 @@ module LibNGAP_Functions { var NG_PDU_SESSION_RELEASE_COMMAND v_ng_pdu_session_release_command; if (decvalue(v_bs, v_ng_pdu_session_release_command) != 0) { log("f_await_pdu_session_resource_release_command: Failed to decode dl_Nas_Transport payload"); setverdict(inconc); setverdict(inconc, "Failed to decode dl_Nas_Transport payload"); } else { log("f_await_pdu_session_resource_release_command: v_ng_pdu_session_release_command: ", v_ng_pdu_session_release_command); var NG_NAS_DL_Message_Type v_expected_message; Loading @@ -2836,10 +2836,10 @@ module LibNGAP_Functions { if (not(match(v_expected_message, mw_NG_PDU_SESSION_RELEASE_COMMAND(cs_NG_PDU_SessionId(int2oct(vc_pdu_session_resource_setup_list_su_req[0].pDUSessionID, 1), omit))))) { log(match(v_expected_message, mw_NG_PDU_SESSION_RELEASE_COMMAND(cs_NG_PDU_SessionId(int2oct(vc_pdu_session_resource_setup_list_su_req[0].pDUSessionID, 1), omit)))); // Log mismatch log("f_await_pdu_session_resource_release_command: FAIL: NG_PDU_SESSION_RELEASE_COMMAND mismatch."); setverdict(fail); setverdict(fail, "Received NG_PDU_SESSION_RELEASE_COMMAND for PDU session ID " & vc_pdu_session_resource_setup_list_su_req[0].pDUSessionID & " does not match expected"); } else { log("f_await_pdu_session_resource_release_command: PASS: Expected NG_PDU_SESSION_RELEASE_COMMAND"); setverdict(pass); setverdict(pass, "Received NG_PDU_SESSION_RELEASE_COMMAND for PDU session ID " & vc_pdu_session_resource_setup_list_su_req[0].pDUSessionID); } } } Loading Loading @@ -2953,7 +2953,7 @@ module LibNGAP_Functions { setverdict(fail); } else { log("f_await_configuration_update_command: PASS: Expected NG_CONFIGURATION_UPDATE_COMMAND"); setverdict(pass); setverdict(pass, "Received NG_CONFIGURATION_UPDATE_COMMAND with expected time zone, time and daylight saving time"); } log("v_message: ", v_message); Loading @@ -2973,6 +2973,7 @@ module LibNGAP_Functions { vc_AMF_UE_ID, vc_RAN_UE_ID ))); setverdict(pass, "Received INITIAL CONTEXT SETUP FAILURE NGAP message"); } /** Loading @@ -2989,6 +2990,7 @@ module LibNGAP_Functions { vc_RAN_UE_ID, m_cause_radioNetwork(unspecified) ))); setverdict(pass, "Sent INITIAL CONTEXT SETUP FAILURE NGAP message"); } /** Loading @@ -3005,6 +3007,7 @@ module LibNGAP_Functions { mw_ngap_initMsg( mw_n2_UEContextReleaseCommand )); setverdict(pass, "Received UE CONTEXT RELEASE COMMAND NGAP message with cause: " & p_Cause); // Send UEContextReleaseComplete f_send_NGAP_PDU( Loading @@ -3013,12 +3016,7 @@ module LibNGAP_Functions { vc_AMF_UE_ID, vc_RAN_UE_ID ))); // f_send_NGAP_PDU( // m_ngap_succMsg( // m_n2_UEContextReleaseComplete_noPDUSessionResourceSetupListSURes( // vc_AMF_UE_ID, // vc_RAN_UE_ID // ))); setverdict(pass, "Sent UE CONTEXT RELEASE COMPLETE NGAP message"); } /** Loading @@ -3035,6 +3033,7 @@ module LibNGAP_Functions { vc_RAN_UE_ID, m_cause_radioNetwork(unspecified) ))); setverdict(pass, "Received UE CONTEXT RELEASE REQUEST NGAP message"); } /** Loading @@ -3051,6 +3050,7 @@ module LibNGAP_Functions { vc_RAN_UE_ID, m_cause_radioNetwork(unspecified) ))); setverdict(pass, "Sent UE CONTEXT RELEASE REQUEST NGAP message"); } /** Loading @@ -3066,6 +3066,7 @@ module LibNGAP_Functions { vc_AMF_UE_ID, vc_RAN_UE_ID ))); setverdict(pass, "Received UE CONTEXT RELEASE COMPLETE NGAP message"); } /** Loading @@ -3081,12 +3082,7 @@ module LibNGAP_Functions { vc_AMF_UE_ID, vc_RAN_UE_ID ))); // f_send_NGAP_PDU( // m_ngap_succMsg( // m_n2_UEContextReleaseComplete_noPDUSessionResourceSetupListSURes( // vc_AMF_UE_ID, // vc_RAN_UE_ID // ))); setverdict(pass, "Sent UE CONTEXT RELEASE COMPLETE NGAP message"); } /** Loading @@ -3108,6 +3104,8 @@ module LibNGAP_Functions { vc_RAN_UE_ID, p_Cause ))); setverdict(pass, "Sent UE CONTEXT RELEASE REQUEST NGAP message with cause: " & p_Cause); // Await UEContextReleaseCommand f_recv_NGAP_PDU( mw_ngap_initMsg( Loading @@ -3115,6 +3113,8 @@ module LibNGAP_Functions { -, p_Cause ))); setverdict(pass, "Received UE CONTEXT RELEASE COMMAND NGAP message with cause: " & p_Cause); // Send UEContextReleaseComplete f_send_NGAP_PDU( m_ngap_succMsg( Loading @@ -3122,12 +3122,7 @@ module LibNGAP_Functions { vc_AMF_UE_ID, vc_RAN_UE_ID ))); // f_send_NGAP_PDU( // m_ngap_succMsg( // m_n2_UEContextReleaseComplete( // vc_AMF_UE_ID, // vc_RAN_UE_ID // ))); setverdict(pass, "Sent UE CONTEXT RELEASE COMPLETE NGAP message"); } /** Loading @@ -3147,6 +3142,8 @@ module LibNGAP_Functions { vc_RAN_UE_ID, p_Cause ))); setverdict(pass, "Received UE CONTEXT RELEASE REQUEST NGAP message with cause: " & p_Cause); // Await UEContextReleaseCommand f_recv_NGAP_PDU( mw_ngap_initMsg( Loading @@ -3154,6 +3151,8 @@ module LibNGAP_Functions { -, p_Cause ))); setverdict(pass, "Received UE CONTEXT RELEASE COMMAND NGAP message with cause: " & p_Cause); // await UEContextReleaseComplete f_recv_NGAP_PDU( mw_ngap_succMsg( Loading @@ -3161,6 +3160,7 @@ module LibNGAP_Functions { vc_AMF_UE_ID, vc_RAN_UE_ID ))); setverdict(pass, "Received UE CONTEXT RELEASE COMPLETE NGAP message with cause: " & p_Cause); } /** Loading Loading @@ -3212,7 +3212,7 @@ module LibNGAP_Functions { m_tAI ))))); setverdict(pass); setverdict(pass, "Sent NG_DEREGISTRATION_REQUEST_MO NAS message"); } /** Loading @@ -3232,6 +3232,7 @@ module LibNGAP_Functions { f_NASPDU_Get(vc_recvNGAP_PDU) if (match(vc_recvNgNasUl_Msg, mw_NG_DEREGISTRATION_REQUEST_MO)) { log("Received NG_DEREGISTRATION_REQUEST_MO NAS message"); setverdict(pass, "Received NG_DEREGISTRATION_REQUEST_MO NAS message"); } else { log("*** " & __SCOPE__ & ": FAIL: Unexpected NAS message"); setverdict(fail, "*** " & __SCOPE__ & ": FAIL: Unexpected NAS message"); Loading Loading @@ -3265,10 +3266,10 @@ module LibNGAP_Functions { vc_inner_message ) == false) { log("*** " & __SCOPE__ & ": FAIL: mw_NG_DEREGISTRATION_ACCEPT_MO mismatch."); setverdict(fail); setverdict(fail, "Received unexpected NAS message"); } else { log("*** " & __SCOPE__ & ": PASS: Expected mw_NG_DEREGISTRATION_ACCEPT_MO"); setverdict(pass); setverdict(pass, "Received mw_NG_DEREGISTRATION_ACCEPT_MO NAS message"); } log("v_message: ", v_message); } Loading Loading @@ -3300,10 +3301,10 @@ module LibNGAP_Functions { vc_inner_message ) == false) { log("*** " & __SCOPE__ & ": FAIL: mw_NG_DEREGISTRATION_ACCEPT_MO mismatch."); setverdict(fail); setverdict(fail, "Received unexpected NAS message"); } else { log("*** " & __SCOPE__ & ": PASS: Expected mw_NG_DEREGISTRATION_ACCEPT_MO"); setverdict(pass); setverdict(pass, "Received mw_NG_DEREGISTRATION_ACCEPT_MO NAS message"); } log("v_message: ", v_message); Loading @@ -3324,6 +3325,7 @@ module LibNGAP_Functions { mw_n2_ErrorIndication( p_cause ))); setverdict(pass, "Received ERROR INDICATION NGAP message with cause: " & p_cause); } /** Loading @@ -3343,6 +3345,7 @@ module LibNGAP_Functions { vc_RAN_UE_ID, p_cause ))); setverdict(pass, "Received ERROR INDICATION NGAP message with cause: " & p_cause); } /** Loading @@ -3360,6 +3363,7 @@ module LibNGAP_Functions { m_n2_ErrorIndication( p_cause ))); setverdict(pass, "Sent ERROR INDICATION NGAP message with cause: " & p_cause); } /** Loading @@ -3379,6 +3383,7 @@ module LibNGAP_Functions { vc_RAN_UE_ID, p_cause ))); setverdict(pass, "Sent ERROR INDICATION NGAP message with cause: " & p_cause); } /** Loading
upper_tester/profiles.py +3 −0 Changes for upper_tester/profiles.py: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -139,6 +139,9 @@ BUILTIN: dict[str, ModemProfile] = { timeouts=(("AT+QNETDEVCTL", 160.0), ("AT+QIACT", 150.0), ("AT+QIDEACT", 40.0)) + _GENERIC_TIMEOUTS, ping_command='AT+QPING={cid},"{host}",{timeout},{count}', dial="qiact", # In 5GMM-IDLE, AT+CFUN=4 alone detaches locally, without any DEREGISTRATION REQUEST: # detach first, which the modem signals to the network mmi={"DEREGISTER": ("AT+CGATT=0", "AT+CFUN=4")}, refused=( (r"AT\+COPS=2", "deregistering with AT+COPS=2 leaves the RM520N-GL in '+CME ERROR: SIM failure'" " until it is power cycled; use AT+CFUN=4 (MMI DEREGISTER) instead"), Loading
upper_tester/tests/test_ut.py +15 −2 Changes for upper_tester/tests/test_ut.py: 15 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -108,10 +108,16 @@ class TestServer(Base): self.assertIn("AT+CFUN=1", self.fake.received) async def test_mmi_step_failure(self): self.modem.profile = profiles.load("generic") # DEREGISTER is AT+CFUN=4 alone (mmi.MMI_TABLE) r = await self.call(id=10, type="MMI", cmd="DEREGISTER") self.assertFalse(r["result"]) self.assertEqual(r["result_string"], "AT> AT+CFUN=4 -> +CME ERROR: 3") async def test_rm520n_deregister_detaches_first(self): self.fake.script = {"AT+CGATT=0": ["OK"], "AT+CFUN=4": ["OK"]} self.assertTrue((await self.call(id=16, type="MMI", cmd="DEREGISTER"))["result"]) self.assertEqual(self.fake.received, ["AT+CGATT=0", "AT+CFUN=4"]) async def test_success_keeps_plain_response(self): r = await self.call(id=13, type="MMI", cmd="POWER_ON") self.assertEqual(r["result_string"], "OK") Loading Loading @@ -392,11 +398,18 @@ class TestPing(Base): self.assertIn("AT> (URC +QPING:) -> +QPING: 561,0,0,0,0,0,0", r["result_string"]) self.assertTrue(r["result_string"].endswith("+UT: ping 10.174.19.14 failed: error 561"), r) async def test_ping_without_summary_times_out(self): async def test_ping_without_summary_after_lost_replies_succeeds(self): # The RM520N-GL reports the first lost reply only, and no summary self.fake.script[self.PING] = ["OK", "+QPING: 569"] r = await self.ping() self.assertTrue(r["result"], r) self.assertTrue(r["result_string"].endswith("+UT: ping 10.174.19.14: 1 result(s), no summary from the modem"), r) async def test_ping_without_any_result_fails(self): self.fake.script[self.PING] = ["OK"] r = await self.ping() self.assertFalse(r["result"]) self.assertIn("no summary", r["result_string"]) self.assertIn("no result from the modem", r["result_string"]) async def test_ping_error_code_alone_ends_at_once(self): self.fake.script['AT+QPING=1,"10.174.19.14",10,2'] = ["OK", "+QPING: 561"] Loading
upper_tester/userdata.py +8 −2 Changes for upper_tester/userdata.py: 8 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -75,7 +75,10 @@ def ping(modem, params: dict[str, str], timeout: float | None = None, on_written @param timeout Overrides the timeout of the ping command itself (not of the replies). @param on_written Forwarded to modem.AtModem.execute. @return `(result, result_string)`. `result` is true once the modem has run the pings and reported its summary with a final result 0, whether or not replies came back. reported its summary with a final result 0, whether or not replies came back. It is also true when the summary does not come but per-ping results did, without an error code: the RM520N-GL reports only the first `+QPING: 569` when no reply comes back, and no summary, although it sends every echo request. `result_string` holds the response and the `+QPING:` lines, and ends with `+UT: ping <host>: sent=<n> rcvd=<n> lost=<n> min=<ms> max=<ms> avg=<ms>`, or with a `+UT:` line giving the reason of the failure. Loading Loading @@ -110,8 +113,11 @@ def ping(modem, params: dict[str, str], timeout: float | None = None, on_written error = _error(early) if summary is None and error is not None: return False, f"{text}\r\n+UT: ping {host} failed: error {error}" if summary is None and early: log.info("ping %s: %d result(s), no summary", host, len(early)) return True, f"{text}\r\n+UT: ping {host}: {len(early)} result(s), no summary from the modem" if summary is None: return False, f"{text}\r\n+UT: ping {host}: no summary from the modem" return False, f"{text}\r\n+UT: ping {host}: no result from the modem" names = ("sent", "rcvd", "lost", "min", "max", "avg") report = " ".join(f"{n}={v}" for n, v in zip(names, summary[1:])) if summary[0] != "0": Loading