1#!/usr/bin/env python3
2#
3#   Copyright 2022 - Google
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17import random
18import time
19
20from acts.libs.utils.multithread import multithread_func
21from acts.test_decorators import test_tracker_info
22from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
23from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
24from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
25from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
26from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
27from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
28from acts_contrib.test_utils.tel.tel_parse_utils import parse_mms
29from acts_contrib.test_utils.tel.tel_parse_utils import parse_sms_delivery_time
30from acts_contrib.test_utils.tel.tel_parse_utils import print_nested_dict
31from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb_for_subscription
32from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte_for_subscription
33from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan_for_subscription
34from acts_contrib.test_utils.tel.tel_subscription_utils import set_message_subid
35from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
36from acts.utils import get_current_epoch_time
37from acts.utils import rand_ascii_str
38
39CALCULATE_EVERY_N_CYCLES = 10
40MAX_FAIL_COUNT = 10
41
42
43class TelLiveRilMessageKpiTest(TelephonyBaseTest):
44    def setup_class(self):
45        TelephonyBaseTest.setup_class(self)
46        self.sms_4g_over_sgs_test_cycle = self.user_params.get(
47            'sms_4g_over_sgs_test_cycle', 1)
48        self.sms_4g_over_ims_test_cycle = self.user_params.get(
49            'sms_4g_over_ims_test_cycle', 1)
50        self.sms_iwlan_test_cycle = self.user_params.get(
51            'sms_iwlan_test_cycle', 1)
52        self.mms_4g_test_cycle = self.user_params.get('mms_4g_test_cycle', 1)
53        self.mms_iwlan_test_cycle = self.user_params.get(
54            'mms_iwlan_test_cycle', 1)
55
56    def sms_test(self, ads):
57        """Send and receive a short SMS with random length and content between
58        two UEs.
59
60        Args:
61            ads: list containing Android objects
62
63        Returns:
64            True if both sending and receiving are successful. Otherwise False.
65        """
66        msg_length = random.randint(5, 160)
67        msg_body = rand_ascii_str(msg_length)
68
69        if not sms_send_receive_verify(self.log, ads[0], ads[1], [msg_body]):
70            ads[0].log.warning('SMS of length %s test failed', msg_length)
71            return False
72        else:
73            ads[0].log.info('SMS of length %s test succeeded', msg_length)
74        return True
75
76    def mms_test(self, ads, expected_result=True):
77        """Send and receive a MMS with random text length and content between
78        two UEs.
79
80        Args:
81            ads: list containing Android objects
82            expected_result: True to expect successful MMS sending and reception.
83                Otherwise False.
84
85        Returns:
86            True if both sending and reception are successful. Otherwise False.
87        """
88        message_length = random.randint(5, 160)
89        message_array = [('Test Message', rand_ascii_str(message_length), None)]
90        if not mms_send_receive_verify(
91                self.log,
92                ads[0],
93                ads[1],
94                message_array,
95                expected_result=expected_result):
96            self.log.warning('MMS of body length %s test failed', message_length)
97            return False
98        else:
99            self.log.info('MMS of body length %s test succeeded', message_length)
100        self.log.info('MMS test of body lengths %s succeeded', message_length)
101        return True
102
103
104    def _test_sms_4g(self, over_iwlan=False, over_ims=False):
105        """ Send/receive SMS over SGs/IMS to measure MO SMS setup time and SMS
106        delivery time.
107
108        Test steps:
109            1. Enable VoLTE when over IMS. Otherwise disable VoLTE.
110            2. Send a SMS from MO UE and receive it by MT UE.
111            3. Parse logcat of both MO and MT UEs to calculate MO SMS setup time
112                and SMS delivery time.
113
114        Args:
115            over_iwlan: True for over Wi-Fi and False for over cellular network
116            over_ims: True for over IMS and False for over SGs
117
118        Returns:
119            True if both sending and reception are successful. Otherwise False.
120        """
121        ad_mo = self.android_devices[0]
122        ad_mt = self.android_devices[1]
123
124        mo_sub_id, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
125            [ad_mo, ad_mt],
126            host_sub_id=None,
127            type="sms")
128        set_message_subid(ad_mt, mt_sub_id)
129
130        cycle = self.sms_4g_over_sgs_test_cycle
131        phone_setup_func = phone_setup_csfb_for_subscription
132        mo_param = (self.log, ad_mo, mo_sub_id)
133        mt_param = (self.log, ad_mt, mt_sub_id)
134        wording = "SGs"
135        parsing = '4g'
136        if over_ims:
137            cycle = self.sms_4g_over_ims_test_cycle
138            phone_setup_func = phone_setup_volte_for_subscription
139            wording = "IMS"
140            parsing = 'iwlan'
141
142        if over_iwlan:
143            cycle = self.sms_iwlan_test_cycle
144            phone_setup_func = phone_setup_iwlan_for_subscription
145
146            mo_param = (
147                self.log,
148                ad_mo,
149                mo_sub_id,
150                True,
151                WFC_MODE_CELLULAR_PREFERRED,
152                self.wifi_network_ssid,
153                self.wifi_network_pass)
154
155            mt_param = (
156                self.log,
157                ad_mt,
158                mt_sub_id,
159                True,
160                WFC_MODE_CELLULAR_PREFERRED,
161                self.wifi_network_ssid,
162                self.wifi_network_pass)
163
164            wording = 'iwlan'
165            parsing = 'iwlan'
166
167        tasks = [
168            (phone_setup_func, mo_param),
169            (phone_setup_func, mt_param)]
170        if not multithread_func(self.log, tasks):
171            self.log.error("Phone Failed to Set Up Properly.")
172            return False
173
174        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
175
176        sms_test_summary = []
177        result = True
178        continuous_fail = 0
179        for attempt in range(cycle):
180            self.log.info(
181                '======> MO/MT SMS over %s %s/%s <======',
182                wording,
183                attempt+1,
184                cycle)
185            res = self.sms_test([ad_mo, ad_mt])
186            sms_test_summary.append(res)
187
188            if not res:
189                continuous_fail += 1
190                if not multithread_func(self.log, tasks):
191                    self.log.error("Phone Failed to Set Up Properly.")
192                    result = False
193                self._take_bug_report(
194                    self.test_name, begin_time=get_current_epoch_time())
195            else:
196                time.sleep(random.randint(3,10))
197
198            if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or (
199                attempt == cycle - 1) or continuous_fail >= MAX_FAIL_COUNT:
200                parse_sms_delivery_time(self.log, ad_mo, ad_mt, rat=parsing)
201                try:
202                    sms_test_fail_rate = sms_test_summary.count(
203                        False)/len(sms_test_summary)
204                    self.log.info(
205                        'Fail rate of SMS test over %s: %s/%s (%.2f)',
206                        wording,
207                        sms_test_summary.count(False),
208                        len(sms_test_summary),
209                        sms_test_fail_rate)
210                except Exception as e:
211                    self.log.error(
212                        'Fail rate of SMS test over %s: ERROR (%s)',
213                        wording,
214                        e)
215
216            if continuous_fail >= MAX_FAIL_COUNT:
217                self.log.error(
218                    'Failed more than %s times in succession. Test is terminated '
219                    'forcedly.',
220                    MAX_FAIL_COUNT)
221                break
222
223        return result
224
225
226    @test_tracker_info(uuid="13d1a53b-66be-4ac1-b5ee-dfe4c5e4e4e1")
227    @TelephonyBaseTest.tel_test_wrap
228    def test_sms_4g_over_sgs(self):
229        """ Send/receive SMS over SGs to measure MO SMS setup time and SMS
230        delivery time.
231
232        Test steps:
233            1. Disable VoLTE.
234            2. Send a SMS from MO UE and receive it by MT UE.
235            3. Parse logcat of both MO and MT UEs to calculate MO SMS setup time
236                and SMS delivery time.
237        """
238        return self._test_sms_4g()
239
240
241    @test_tracker_info(uuid="293e2955-b38b-4329-b686-fb31d9e46868")
242    @TelephonyBaseTest.tel_test_wrap
243    def test_sms_4g_over_ims(self):
244        """ Send/receive SMS over IMS to measure MO SMS setup time and SMS
245        delivery time.
246
247        Test steps:
248            1. Enable VoLTE.
249            2. Send a SMS from MO UE and receive it by MT UE.
250            3. Parse logcat of both MO and MT UEs to calculate MO SMS setup time
251                and SMS delivery time.
252        """
253        return self._test_sms_4g(over_ims=True)
254
255
256    @test_tracker_info(uuid="862fec2d-8e23-482e-b45c-a42cad134022")
257    @TelephonyBaseTest.tel_test_wrap
258    def test_sms_iwlan(self):
259        """ Send/receive SMS on iwlan to measure MO SMS setup time and SMS
260        delivery time.
261
262        Test steps:
263            1. Send a SMS from MO UE and receive it by MT UE.
264            2. Parse logcat of both MO and MT UEs to calculate MO SMS setup time
265                and SMS delivery time.
266        """
267        return self._test_sms_4g(over_iwlan=True, over_ims=True)
268
269
270    def _test_mms_4g(self, over_iwlan=False):
271        """ Send/receive MMS on LTE to measure MO and MT MMS setup time
272
273        Test steps:
274            1. Enable VoLTE when over Wi-Fi (iwlan). Otherwise disable VoLTE.
275            2. Send a MMS from MO UE and receive it by MT UE.
276            3. Parse logcat of both MO and MT UEs to calculate MO and MT MMS
277                setup time.
278
279        Args:
280            over_iwlan: True for over Wi-Fi and False for over cellular network
281
282        Returns:
283            True if both sending and reception are successful. Otherwise False.
284        """
285        ad_mo = self.android_devices[0]
286        ad_mt = self.android_devices[1]
287
288        mo_sub_id, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
289            [ad_mo, ad_mt],
290            host_sub_id=None,
291            type="sms")
292        set_message_subid(ad_mt, mt_sub_id)
293
294        cycle = self.mms_4g_test_cycle
295        phone_setup_func = phone_setup_csfb_for_subscription
296        mo_param = (self.log, ad_mo, mo_sub_id)
297        mt_param = (self.log, ad_mt, mt_sub_id)
298        wording = "LTE"
299        if over_iwlan:
300            cycle = self.mms_iwlan_test_cycle
301            phone_setup_func = phone_setup_iwlan_for_subscription
302            wording = "iwlan"
303
304            mo_param = (
305                self.log,
306                ad_mo,
307                mo_sub_id,
308                True,
309                WFC_MODE_CELLULAR_PREFERRED,
310                self.wifi_network_ssid,
311                self.wifi_network_pass)
312
313            mt_param = (
314                self.log,
315                ad_mt,
316                mt_sub_id,
317                True,
318                WFC_MODE_CELLULAR_PREFERRED,
319                self.wifi_network_ssid,
320                self.wifi_network_pass)
321
322        phone_setup_tasks = [
323            (phone_setup_func, mo_param),
324            (phone_setup_func, mt_param)]
325        if not multithread_func(self.log, phone_setup_tasks):
326            self.log.error("Phone Failed to Set Up Properly.")
327            return False
328
329        if not over_iwlan:
330            wait_for_cell_data_connection_tasks = [
331                (wait_for_cell_data_connection, (self.log, ad_mo, True)),
332                (wait_for_cell_data_connection, (self.log, ad_mt, True))]
333            if not multithread_func(self.log, wait_for_cell_data_connection_tasks):
334                return False
335
336        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
337
338        mms_test_summary = []
339        result = True
340        continuous_fail = 0
341        for attempt in range(cycle):
342            self.log.info(
343                '==================> MO/MT MMS on %s %s/%s <==================',
344                wording,
345                attempt+1,
346                cycle)
347            res = self.mms_test([ad_mo, ad_mt])
348            mms_test_summary.append(res)
349
350            if not res:
351                continuous_fail += 1
352                if not multithread_func(self.log, phone_setup_tasks):
353                    self.log.error("Phone Failed to Set Up Properly.")
354                    result = False
355                    break
356
357                if not over_iwlan:
358                    if not multithread_func(
359                        self.log, wait_for_cell_data_connection_tasks):
360                        result = False
361                        break
362                self._take_bug_report(
363                    self.test_name, begin_time=get_current_epoch_time())
364            else:
365                time.sleep(random.randint(3,10))
366
367            if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or (
368                attempt == cycle - 1) or continuous_fail >= MAX_FAIL_COUNT:
369                (
370                    mo_res,
371                    mo_avg_setup_time,
372                    mt_res, mt_avg_setup_time) = parse_mms(ad_mo, ad_mt)
373
374                ad_mo.log.info('================== Sent MMS ==================')
375                print_nested_dict(ad_mo, mo_res)
376                ad_mt.log.info('================== Received MMS ==================')
377                print_nested_dict(ad_mt, mt_res)
378
379                try:
380                    ad_mo.log.info(
381                        'Average setup time of MO MMS on %s: %.2f sec.',
382                        wording, mo_avg_setup_time)
383                except Exception as e:
384                    ad_mo.log.error(
385                        'Average setup time of MO MMS on %s: ERROR (%s)',
386                        wording, e)
387
388                try:
389                    ad_mt.log.info(
390                        'Average setup time of MT MMS on %s: %.2f sec.',
391                        wording, mt_avg_setup_time)
392                except Exception as e:
393                    ad_mt.log.error(
394                        'Average setup time of MT MMS on %s: ERROR (%s)',
395                        wording, e)
396
397                try:
398                    mms_test_fail_rate = mms_test_summary.count(
399                        False)/len(mms_test_summary)
400                    self.log.info(
401                        'Fail rate of MMS test on LTE: %s/%s (%.2f)',
402                        mms_test_summary.count(False),
403                        len(mms_test_summary),
404                        mms_test_fail_rate)
405                except Exception as e:
406                    self.log.error(
407                        'Fail rate of MMS test on %s: ERROR (%s)', wording, e)
408
409            if continuous_fail >= MAX_FAIL_COUNT:
410                self.log.error(
411                    'Failed more than %s times in succession. Test is terminated '
412                    'forcedly.',
413                    MAX_FAIL_COUNT)
414                break
415
416        return result
417
418
419    @test_tracker_info(uuid="33d11da8-71f1-40d7-8fc7-86fdc83ce266")
420    @TelephonyBaseTest.tel_test_wrap
421    def test_mms_4g(self):
422        """ Send/receive MMS on LTE to measure MO and MT MMS setup time
423
424        Test steps:
425            1. Send a MMS from MO UE and receive it by MT UE.
426            2. Parse logcat of both MO and MT UEs to calculate MO and MT MMS
427                setup time.
428        """
429        return self._test_mms_4g()
430
431
432    @test_tracker_info(uuid="b8a8affa-6559-41d8-9de7-f74406da9ed5")
433    @TelephonyBaseTest.tel_test_wrap
434    def test_mms_iwlan(self):
435        """ Send/receive MMS on iwlan to measure MO and MT MMS setup time
436
437        Test steps:
438            1. Send a MMS from MO UE and receive it by MT UE.
439            2. Parse logcat of both MO and MT UEs to calculate MO and MT MMS
440                setup time.
441        """
442        return self._test_mms_4g(over_iwlan=True)