Commit 19c6e97b authored by Yann Garcia's avatar Yann Garcia
Browse files

Enhance UT to support ICMP on user data plane

parent a199ad4f
Loading
Loading
Loading
Loading
+3 −1
Changes for ttcn/AtsNGAP/NGAP_Steps.ttcn: 3 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -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,
+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
@@ -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(
@@ -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(
@@ -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");
    }
@@ -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(
@@ -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");
    }
@@ -1667,7 +1664,7 @@ module LibNGAP_Functions {
                                                                                                                                                   m_tAI
                        )))));

        setverdict(pass, "Sent UplinkNASTransport NAS message");
        setverdict(pass, "Sent REGISTRATION_COMPLETE NAS message");
    }

    /**
@@ -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
@@ -1933,6 +1930,7 @@ module LibNGAP_Functions {
                                            value_        := ?
                                        }
                        ));
        setverdict(pass, "Received UE CONTEXT RELEASE COMMAND NGAP message");

        f_recv_NGAP_PDU(
                        mw_ngap_succMsg(
@@ -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

    /**
@@ -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;
@@ -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);
                }
            }
        }
@@ -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);

@@ -2973,6 +2973,7 @@ module LibNGAP_Functions {
                                                                                                                        vc_AMF_UE_ID,
                                                                                                                        vc_RAN_UE_ID
                        )));
        setverdict(pass, "Received INITIAL CONTEXT SETUP FAILURE NGAP message");
    }

    /**
@@ -2989,6 +2990,7 @@ module LibNGAP_Functions {
                                                                                                                      vc_RAN_UE_ID,
                                                                                                                      m_cause_radioNetwork(unspecified)
                        )));
        setverdict(pass, "Sent INITIAL CONTEXT SETUP FAILURE NGAP message");
    }

    /**
@@ -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(
@@ -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");
    }

    /**
@@ -3035,6 +3033,7 @@ module LibNGAP_Functions {
                                                                      vc_RAN_UE_ID,
                                                                      m_cause_radioNetwork(unspecified)
                        )));
        setverdict(pass, "Received UE CONTEXT RELEASE REQUEST NGAP message");
    }

    /**
@@ -3051,6 +3050,7 @@ module LibNGAP_Functions {
                                                                    vc_RAN_UE_ID,
                                                                    m_cause_radioNetwork(unspecified)
                        )));
        setverdict(pass, "Sent UE CONTEXT RELEASE REQUEST NGAP message");
    }

    /**
@@ -3066,6 +3066,7 @@ module LibNGAP_Functions {
                                                                         vc_AMF_UE_ID,
                                                                         vc_RAN_UE_ID
                        )));
        setverdict(pass, "Received UE CONTEXT RELEASE COMPLETE NGAP message");
    }

    /**
@@ -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");
    }

    /**
@@ -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(
@@ -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(
@@ -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");
    }

    /**
@@ -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(
@@ -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(
@@ -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);
    }

    /**
@@ -3212,7 +3212,7 @@ module LibNGAP_Functions {
                                                                                                                                                   m_tAI
                        )))));

        setverdict(pass);
        setverdict(pass, "Sent NG_DEREGISTRATION_REQUEST_MO NAS message");
    }

    /**
@@ -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");
@@ -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);
    }
@@ -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);
    
@@ -3324,6 +3325,7 @@ module LibNGAP_Functions {
                                        mw_n2_ErrorIndication(
                                                              p_cause
                        )));
        setverdict(pass, "Received ERROR INDICATION NGAP message with cause: " & p_cause);
    }

    /**
@@ -3343,6 +3345,7 @@ module LibNGAP_Functions {
                                                                  vc_RAN_UE_ID,
                                                                  p_cause
                        )));
        setverdict(pass, "Received ERROR INDICATION NGAP message with cause: " & p_cause);
    }

    /**
@@ -3360,6 +3363,7 @@ module LibNGAP_Functions {
                                       m_n2_ErrorIndication(
                                                            p_cause
                        )));
        setverdict(pass, "Sent ERROR INDICATION NGAP message with cause: " & p_cause);
    }

    /**
@@ -3379,6 +3383,7 @@ module LibNGAP_Functions {
                                                                vc_RAN_UE_ID,
                                                                p_cause
                        )));
        setverdict(pass, "Sent ERROR INDICATION NGAP message with cause: " & p_cause);
    }

    /**
+3 −0
Changes for upper_tester/profiles.py: 3 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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"),
+15 −2
Changes for upper_tester/tests/test_ut.py: 15 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -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")
@@ -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"]
+8 −2
Changes for upper_tester/userdata.py: 8 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -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.
@@ -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":