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 time 18from datetime import datetime 19 20from acts import signals 21from acts.libs.proc import job 22from acts.libs.utils.multithread import multithread_func 23from acts.test_decorators import test_tracker_info 24from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult 25from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger 26from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest 27from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID 28from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED 29from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED 30from acts_contrib.test_utils.tel.tel_data_utils import reboot_test 31from acts_contrib.test_utils.tel.tel_ims_utils import toggle_wfc_for_subscription 32from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode_for_subscription 33from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled 34from acts_contrib.test_utils.tel.tel_logging_utils import start_pixellogger_always_on_logging 35from acts_contrib.test_utils.tel.tel_parse_utils import check_ims_cst_reg 36from acts_contrib.test_utils.tel.tel_parse_utils import parse_cst_reg 37from acts_contrib.test_utils.tel.tel_parse_utils import print_nested_dict 38from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle 39from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_on_rat 40from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id 41from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id 42from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid 43from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index 44from acts_contrib.test_utils.tel.tel_subscription_utils import set_voice_sub_id 45from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot 46from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad 47from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection 48from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_on_rat 49from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_msim_for_slot 50from acts.utils import set_location_service 51from acts.utils import get_current_epoch_time 52 53WAIT_FOR_CST_REG_TIMEOUT = 120 54CALCULATE_EVERY_N_CYCLES = 10 55 56CallResult = TelephonyVoiceTestResult.CallResult.Value 57 58 59class TelLiveRilCstVoiceTest(TelephonyBaseTest): 60 def setup_class(self): 61 TelephonyBaseTest.setup_class(self) 62 start_pixellogger_always_on_logging(self.android_devices[0]) 63 self.tel_logger = TelephonyMetricLogger.for_test_case() 64 65 66 def teardown_test(self): 67 self.enable_cst(self.android_devices[0], None, False) 68 self.force_roaming(self.android_devices[0], None, 0) 69 ensure_phones_idle(self.log, self.android_devices) 70 71 72 def enable_cst(self, ad, slot=0, enable=True): 73 """Enable/disable Cross SIM Calling by SL4A API at given slot 74 75 Args: 76 ad: Android object 77 slot: 0 for pSIM and 1 for eSIM 78 enable: True fo enabling and False for disabling 79 80 Raises: 81 TestFailure if False is returned by 82 imsMmTelIsCrossSimCallingEnabled. 83 """ 84 if slot is None: 85 slots = [0, 1] 86 else: 87 slots = [slot] 88 89 for slot in slots: 90 sub_id = get_subid_from_slot_index(self.log, ad, slot) 91 if ad.droid.imsMmTelIsCrossSimCallingEnabled(sub_id) == enable: 92 ad.log.info( 93 'Status of backup calling at slot %s is already %s.', 94 slot, enable) 95 else: 96 ad.droid.imsMmTelSetCrossSimCallingEnabled(sub_id, enable) 97 time.sleep(3) 98 if ad.droid.imsMmTelIsCrossSimCallingEnabled(sub_id) == enable: 99 ad.log.info( 100 'Backup calling at slot %s is set to %s successfully.', 101 slot, enable) 102 else: 103 ad.log.error( 104 'Backup calling at slot %s is NOT set to %s.', 105 slot, enable) 106 raise signals.TestFailure( 107 "Failed", 108 extras={"fail_reason": "Failed to set Backup calling."}) 109 110 111 def get_force_roaming_state(self, ad, slot=0): 112 """Get the value of the property: 113 getprop persist.vendor.radio.force_roaming 114 115 Args: 116 ad: Android object 117 slot: 0 for pSIM and 1 for eSIM 118 119 Returns: 120 0 for not roaming and 1 for roaming 121 """ 122 cmd = 'adb -s %s shell getprop persist.vendor.radio.force_roaming%s' % ( 123 ad.serial, slot) 124 result = job.run(cmd) 125 return result.stdout 126 127 128 def force_roaming(self, ad, slot=0, roaming=0): 129 """Force assigned slot to roam ot not to roam by setting specific property 130 131 Args: 132 ad: Android object 133 slot: 0 for pSIM and 1 for eSIM 134 roaming: 1 to force to roam. Otherwise 0. 135 136 Returns: 137 True or False 138 """ 139 if slot is None: 140 slots = [0, 1] 141 else: 142 slots = [slot] 143 144 need_reboot = 0 145 for slot in slots: 146 roamimg_state = self.get_force_roaming_state(ad, slot) 147 if roamimg_state: 148 if roamimg_state == str(roaming): 149 if roaming: 150 ad.log.info('Slot %s is already roaming.' % slot) 151 else: 152 ad.log.info('Slot %s is already on home network.' % slot) 153 else: 154 cmd = 'adb -s %s shell setprop persist.vendor.radio.force_roaming%s %s' % (ad.serial, slot, roaming) 155 result = job.run(cmd) 156 self.log.info(result) 157 need_reboot = 1 158 159 if not need_reboot: 160 return True 161 else: 162 result = True 163 if reboot_test(self.log, ad): 164 for slot in slots: 165 roamimg_state = self.get_force_roaming_state(ad, slot) 166 if roamimg_state == str(roaming): 167 if roaming: 168 ad.log.info('Slot %s is now roaming.' % slot) 169 else: 170 ad.log.info('Slot %s is now on home network.' % slot) 171 else: 172 if roaming: 173 ad.log.error( 174 'Slot %s is expected to be roaming (roamimg state: %s).' % roamimg_state) 175 else: 176 ad.log.error( 177 'Slot %s is expected to be on home network (roamimg state: %s).' % roamimg_state) 178 result = False 179 return result 180 181 182 def msim_cst_registration( 183 self, 184 cst_slot, 185 rat=["", ""], 186 wfc_mode=WFC_MODE_WIFI_PREFERRED, 187 force_roaming=False, 188 test_cycles=1): 189 """Make MO/MT voice call at specific slot in specific RAT with DDS at 190 specific slot. 191 192 Test step: 193 1. Get sub IDs of specific slots of both MO and MT devices. 194 2. Switch DDS to specific slot. 195 3. Check HTTP connection after DDS switch. 196 4. Set up phones in desired RAT. 197 198 Args: 199 cst_slot: Slot at which CST registered 200 rat: RAT for both slots 201 wfc_mode: cullelar-preferred or wifi-preferred 202 force_roaming: True for fake roaming by setprop 203 test_cycles: Amount of the test cycles 204 205 Returns: 206 True in the end. Otherwise the exception TestFailure will be raised. 207 208 Raises: 209 TestFailure if: 210 1. Invalid sub ID is returned. 211 2. DDS cannot be switched successfully. 212 3. Http connection cannot be verified. 213 """ 214 ads = self.android_devices 215 set_location_service(ads[0], True) 216 test_cycles = int(test_cycles) 217 cst_reg_search_intervals = [] 218 cst_reg_fail = 0 219 exit_due_to_high_fail_rate = False 220 for attempt in range(test_cycles): 221 self.log.info( 222 '======> Test cycle %s/%s <======', attempt + 1, test_cycles) 223 cst_reg_begin_time = datetime.now() 224 cst_slot_sub_id = get_subid_from_slot_index( 225 self.log, ads[0], cst_slot) 226 if cst_slot_sub_id == INVALID_SUB_ID: 227 ads[0].log.warning( 228 "Failed to get sub ID ar slot %s.", cst_slot) 229 raise signals.TestFailure( 230 'Failed', 231 extras={ 232 'fail_reason': 'Slot ID %s at slot %s is invalid.' % ( 233 cst_slot_sub_id, cst_slot)}) 234 other_sub_id = get_subid_from_slot_index( 235 self.log, ads[0], 1-cst_slot) 236 self.enable_cst(ads[0], slot=cst_slot, enable=True) 237 238 self.log.info("Step 1: Switch DDS.") 239 if not set_dds_on_slot(ads[0], 1 - cst_slot): 240 ads[0].log.warning("Failed to set DDS to slot %s.", 1 - cst_slot) 241 raise signals.TestFailure( 242 'Failed', 243 extras={ 244 'fail_reason': 'Failed to set DDS to slot %s.' % 1 - cst_slot}) 245 246 self.log.info("Step 2: Check HTTP connection after DDS switch.") 247 if not verify_http_connection(self.log, 248 ads[0], 249 url="https://www.google.com", 250 retry=5, 251 retry_interval=15, 252 expected_state=True): 253 self.log.error("Failed to verify http connection.") 254 raise signals.TestFailure( 255 'Failed', 256 extras={ 257 'fail_reason': 'Failed to verify http connection.'}) 258 else: 259 self.log.info("Verify http connection successfully.") 260 261 self.log.info("Step 3: Set up phones in desired RAT.") 262 phone_setup_on_rat( 263 self.log, 264 ads[0], 265 rat[1-cst_slot], 266 other_sub_id) 267 268 phone_setup_on_rat( 269 self.log, 270 ads[0], 271 rat[cst_slot], 272 cst_slot_sub_id, 273 False, 274 wfc_mode) 275 276 if toggle_wfc_for_subscription( 277 self.log, ads[0], True, cst_slot_sub_id): 278 if set_wfc_mode_for_subscription( 279 ads[0], wfc_mode, cst_slot_sub_id): 280 pass 281 282 if force_roaming: 283 self.force_roaming(ads[0], cst_slot, 1) 284 285 if not wait_for_wfc_enabled(self.log, ads[0]): 286 cst_reg_fail += 1 287 if cst_reg_fail >= test_cycles/10: 288 exit_due_to_high_fail_rate = True 289 290 cst_reg_end_time = datetime.now() 291 ims_cst_reg_res = check_ims_cst_reg( 292 ads[0], 293 cst_slot, 294 search_interval=[cst_reg_begin_time, cst_reg_end_time]) 295 296 while not ims_cst_reg_res: 297 if (datetime.now() - cst_reg_end_time).total_seconds() > WAIT_FOR_CST_REG_TIMEOUT: 298 break 299 time.sleep(1) 300 ims_cst_reg_res = check_ims_cst_reg( 301 ads[0], 302 cst_slot, 303 search_interval=[cst_reg_begin_time, datetime.now()]) 304 305 if not ims_cst_reg_res: 306 ads[0].log.error('IMS radio tech is NOT CrossStackEpdg.') 307 cst_reg_fail += 1 308 if cst_reg_fail >= test_cycles/10: 309 exit_due_to_high_fail_rate = True 310 311 if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or ( 312 attempt == test_cycles - 1) or exit_due_to_high_fail_rate: 313 314 parsing_fail = parse_cst_reg( 315 ads[0], cst_slot, cst_reg_search_intervals) 316 ads[0].log.info('====== Failed cycles of CST registration ======') 317 for each_dict in parsing_fail: 318 print_nested_dict(ads[0], each_dict) 319 320 self.enable_cst(ads[0], None, False) 321 322 if exit_due_to_high_fail_rate: 323 ads[0].log.error( 324 'Test case is stopped due to fail rate is greater than 10%.') 325 break 326 327 return True 328 329 330 def msim_cst_call_voice( 331 self, 332 mo_slot, 333 mt_slot, 334 mo_rat=["", ""], 335 mt_rat=["", ""], 336 call_direction="mo", 337 wfc_mode=WFC_MODE_WIFI_PREFERRED, 338 force_roaming=False, 339 test_cycles=1, 340 call_cycles=1): 341 """Make MO/MT voice call at specific slot in specific RAT with DDS at 342 specific slot. 343 344 Test step: 345 1. Get sub IDs of specific slots of both MO and MT devices. 346 2. Switch DDS to specific slot. 347 3. Check HTTP connection after DDS switch. 348 4. Set up phones in desired RAT. 349 5. Make voice call. 350 351 Args: 352 mo_slot: Slot making MO call (0 or 1) 353 mt_slot: Slot receiving MT call (0 or 1) 354 mo_rat: RAT for both slots of MO device 355 mt_rat: RAT for both slots of MT device 356 call_direction: "mo" or "mt" 357 358 Returns: 359 True in the end. Otherwise the exception TestFailure will be raised. 360 361 Raises: 362 TestFailure if: 363 1. Invalid sub ID is returned. 364 2. DDS cannot be switched successfully. 365 3. Http connection cannot be verified. 366 """ 367 ads = self.android_devices 368 if call_direction == "mo": 369 ad_mo = ads[0] 370 ad_mt = ads[1] 371 else: 372 ad_mo = ads[1] 373 ad_mt = ads[0] 374 375 test_cycles = int(test_cycles) 376 call_cycles = int(call_cycles) 377 set_location_service(ads[0], True) 378 cst_reg_search_intervals = [] 379 cst_reg_fail = 0 380 exit_due_to_high_fail_rate = False 381 dialed_call_amount = 0 382 call_result_list = [] 383 call_result_cycle_list = [] 384 for attempt in range(test_cycles): 385 self.log.info( 386 '======> Test cycle %s/%s <======', attempt + 1, test_cycles) 387 cst_reg_begin_time = datetime.now() 388 if mo_slot is not None: 389 mo_sub_id = get_subid_from_slot_index(self.log, ad_mo, mo_slot) 390 if mo_sub_id == INVALID_SUB_ID: 391 ad_mo.log.warning( 392 "Failed to get sub ID ar slot %s.", mo_slot) 393 raise signals.TestFailure( 394 'Failed', 395 extras={ 396 'fail_reason': 'Slot ID %s at slot %s is invalid.' % ( 397 mo_sub_id, mo_slot)}) 398 mo_other_sub_id = get_subid_from_slot_index( 399 self.log, ad_mo, 1-mo_slot) 400 set_voice_sub_id(ad_mo, mo_sub_id) 401 self.enable_cst(ads[0], slot=mo_slot, enable=True) 402 else: 403 _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(ads) 404 if mo_sub_id == INVALID_SUB_ID: 405 ad_mo.log.warning( 406 "Failed to get sub ID ar slot %s.", mo_slot) 407 raise signals.TestFailure( 408 'Failed', 409 extras={ 410 'fail_reason': 'Slot ID %s at slot %s is invalid.' % ( 411 mo_sub_id, mo_slot)}) 412 mo_slot = "auto" 413 set_voice_sub_id(ad_mo, mo_sub_id) 414 ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", 415 mo_slot, get_outgoing_voice_sub_id(ad_mo)) 416 417 if mt_slot is not None and mt_slot is not 'auto': 418 mt_sub_id = get_subid_from_slot_index( 419 self.log, ad_mt, mt_slot) 420 if mt_sub_id == INVALID_SUB_ID: 421 ad_mt.log.warning( 422 "Failed to get sub ID at slot %s.", mt_slot) 423 raise signals.TestFailure( 424 'Failed', 425 extras={ 426 'fail_reason': 'Slot ID %s at slot %s is invalid.' % ( 427 mt_sub_id, mt_slot)}) 428 mt_other_sub_id = get_subid_from_slot_index( 429 self.log, ad_mt, 1-mt_slot) 430 set_voice_sub_id(ad_mt, mt_sub_id) 431 self.enable_cst(ads[0], slot=mt_slot, enable=True) 432 else: 433 _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(ads) 434 if mt_sub_id == INVALID_SUB_ID: 435 ad_mt.log.warning( 436 "Failed to get sub ID at slot %s.", mt_slot) 437 raise signals.TestFailure( 438 'Failed', 439 extras={ 440 'fail_reason': 'Slot ID %s at slot %s is invalid.' % ( 441 mt_sub_id, mt_slot)}) 442 mt_slot = "auto" 443 set_voice_sub_id(ad_mt, mt_sub_id) 444 ad_mt.log.info("Sub ID for incoming call at slot %s: %s", mt_slot, 445 get_incoming_voice_sub_id(ad_mt)) 446 447 self.log.info("Step 1: Switch DDS.") 448 449 dds_slot = 1 450 if call_direction == "mo": 451 dds_slot = 1 - get_slot_index_from_subid(ad_mo, mo_sub_id) 452 else: 453 dds_slot = 1 - get_slot_index_from_subid(ad_mt, mt_sub_id) 454 455 if not set_dds_on_slot(ads[0], dds_slot): 456 ads[0].log.warning("Failed to set DDS to slot %s.", dds_slot) 457 raise signals.TestFailure( 458 'Failed', 459 extras={ 460 'fail_reason': 'Failed to set DDS to slot %s.' % dds_slot}) 461 462 self.log.info("Step 2: Check HTTP connection after DDS switch.") 463 if not verify_http_connection(self.log, 464 ads[0], 465 url="https://www.google.com", 466 retry=5, 467 retry_interval=15, 468 expected_state=True): 469 self.log.error("Failed to verify http connection.") 470 raise signals.TestFailure( 471 'Failed', 472 extras={ 473 'fail_reason': 'Failed to verify http connection.'}) 474 else: 475 self.log.info("Verify http connection successfully.") 476 477 if mo_slot == 0 or mo_slot == 1: 478 phone_setup_on_rat( 479 self.log, 480 ad_mo, 481 mo_rat[1-mo_slot], 482 mo_other_sub_id) 483 484 mo_phone_setup_argv = ( 485 self.log, 486 ad_mo, 487 mo_rat[mo_slot], 488 mo_sub_id, 489 False, 490 wfc_mode) 491 492 is_mo_in_call = is_phone_in_call_on_rat( 493 self.log, ad_mo, mo_rat[mo_slot], only_return_fn=True) 494 else: 495 mo_phone_setup_argv = (self.log, ad_mo, 'general') 496 is_mo_in_call = is_phone_in_call_on_rat( 497 self.log, ad_mo, 'general', only_return_fn=True) 498 499 if mt_slot == 0 or mt_slot == 1: 500 phone_setup_on_rat( 501 self.log, 502 ad_mt, 503 mt_rat[1-mt_slot], 504 mt_other_sub_id) 505 506 mt_phone_setup_argv = ( 507 self.log, 508 ad_mt, 509 mt_rat[mt_slot], 510 mt_sub_id, 511 False, 512 wfc_mode) 513 514 is_mt_in_call = is_phone_in_call_on_rat( 515 self.log, ad_mt, mt_rat[mt_slot], only_return_fn=True) 516 else: 517 mt_phone_setup_argv = (self.log, ad_mt, 'general') 518 is_mt_in_call = is_phone_in_call_on_rat( 519 self.log, ad_mt, 'general', only_return_fn=True) 520 521 self.log.info("Step 3: Set up phones in desired RAT.") 522 523 tasks = [(phone_setup_on_rat, mo_phone_setup_argv), 524 (phone_setup_on_rat, mt_phone_setup_argv)] 525 if not multithread_func(self.log, tasks): 526 self.log.error("Phone Failed to Set Up Properly.") 527 self.tel_logger.set_result(CallResult("CALL_SETUP_FAILURE")) 528 raise signals.TestFailure("Failed", 529 extras={"fail_reason": "Phone Failed to Set Up Properly."}) 530 531 if toggle_wfc_for_subscription(self.log, ad_mo, True, mo_sub_id): 532 if set_wfc_mode_for_subscription(ad_mo, wfc_mode, mo_sub_id): 533 pass 534 535 if force_roaming: 536 self.force_roaming(ads[0], 1-dds_slot, 1) 537 538 if not wait_for_wfc_enabled(self.log, ads[0]): 539 cst_reg_fail += 1 540 if cst_reg_fail >= test_cycles/10: 541 exit_due_to_high_fail_rate = True 542 543 cst_reg_end_time = datetime.now() 544 ims_cst_reg_res = check_ims_cst_reg( 545 ads[0], 546 1-dds_slot, 547 search_interval=[cst_reg_begin_time, cst_reg_end_time]) 548 549 while not ims_cst_reg_res: 550 if (datetime.now() - cst_reg_end_time).total_seconds() > WAIT_FOR_CST_REG_TIMEOUT: 551 break 552 time.sleep(1) 553 ims_cst_reg_res = check_ims_cst_reg( 554 ads[0], 555 1-dds_slot, 556 search_interval=[cst_reg_begin_time, datetime.now()]) 557 558 if not ims_cst_reg_res: 559 ads[0].log.error('IMS radio tech is NOT CrossStackEpdg.') 560 cst_reg_fail += 1 561 if cst_reg_fail >= test_cycles/10: 562 exit_due_to_high_fail_rate = True 563 564 if ims_cst_reg_res and not exit_due_to_high_fail_rate: 565 self.log.info("Step 4: Make voice call.") 566 for cycle in range( 567 dialed_call_amount, dialed_call_amount+call_cycles): 568 self.log.info( 569 '======> CST voice call %s/%s <======', 570 cycle + 1, 571 dialed_call_amount+call_cycles) 572 result = two_phone_call_msim_for_slot( 573 self.log, 574 ad_mo, 575 get_slot_index_from_subid(ad_mo, mo_sub_id), 576 None, 577 is_mo_in_call, 578 ad_mt, 579 get_slot_index_from_subid(ad_mt, mt_sub_id), 580 None, 581 is_mt_in_call) 582 self.tel_logger.set_result(result.result_value) 583 584 if not result: 585 self.log.error( 586 "Failed to make MO call from %s slot %s to %s slot %s", 587 ad_mo.serial, mo_slot, ad_mt.serial, mt_slot) 588 call_result_list.append(False) 589 call_result_cycle_list.append(cycle + 1) 590 self._take_bug_report( 591 self.test_name, begin_time=get_current_epoch_time()) 592 else: 593 call_result_list.append(True) 594 dialed_call_amount = dialed_call_amount + call_cycles 595 596 if (attempt+1) % CALCULATE_EVERY_N_CYCLES == 0 or ( 597 attempt == test_cycles - 1) or exit_due_to_high_fail_rate: 598 599 parsing_fail = parse_cst_reg( 600 ad_mo, 1-dds_slot, cst_reg_search_intervals) 601 ads[0].log.info('====== Failed cycles of CST registration ======') 602 for each_dict in parsing_fail: 603 print_nested_dict(ads[0], each_dict) 604 605 ads[0].log.info('====== Failed cycles of CST voice call ======') 606 for index, value in enumerate(call_result_list): 607 if not value: 608 ads[0].log.warning( 609 'CST voice call cycle %s failed.', index+1) 610 611 try: 612 fail_rate = ( 613 len(call_result_list) - call_result_list.count(True))/len( 614 call_result_list) 615 ads[0].log.info('====== Summary ======') 616 ads[0].log.info( 617 'Total CST calls: %s', 618 len(call_result_list)) 619 ads[0].log.warning( 620 'Total failed CST calls: %s', 621 call_result_list.count(False)) 622 ads[0].log.info( 623 'Fail rate of CST voice call: %s', fail_rate) 624 except Exception as e: 625 ads[0].log.error( 626 'Fail rate of CST voice call: ERROR (%s)', e) 627 628 self.enable_cst(ads[0], None, False) 629 630 if exit_due_to_high_fail_rate: 631 ads[0].log.error( 632 'Test case is stopped due to fail rate is greater than 10%.') 633 break 634 635 return True 636 637 638 @test_tracker_info(uuid="5475514a-8897-4dd4-900f-1dd435191d0b") 639 @TelephonyBaseTest.tel_test_wrap 640 def test_msim_psim_mo_cst_call_wifi_preferred(self): 641 return self.msim_cst_call_voice( 642 0, 643 None, 644 mo_rat=["2g", "general"], 645 call_direction="mo", 646 test_cycles=self.user_params.get( 647 "psim_mo_cst_call_wifi_preferred_test_cycle", 1), 648 call_cycles=self.user_params.get("cst_call_cycle", 1)) 649 650 651 @test_tracker_info(uuid="40c182b7-af25-428a-bae5-9203eed949d8") 652 @TelephonyBaseTest.tel_test_wrap 653 def test_msim_psim_mo_cst_call_cellular_preferred(self): 654 return self.msim_cst_call_voice( 655 0, 656 None, 657 mo_rat=["2g", "general"], 658 call_direction="mo", 659 wfc_mode=WFC_MODE_CELLULAR_PREFERRED, 660 test_cycles=self.user_params.get( 661 "psim_mo_cst_call_cellular_preferred_test_cycle", 1), 662 call_cycles=self.user_params.get("cst_call_cycle", 1))