1*9c5db199SXin Li# Lint as: python2, python3 2*9c5db199SXin Li# Copyright (c) 2014 The Chromium OS Authors. All rights reserved. 3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be 4*9c5db199SXin Li# found in the LICENSE file. 5*9c5db199SXin Li 6*9c5db199SXin Liimport contextlib 7*9c5db199SXin Liimport dbus 8*9c5db199SXin Liimport logging 9*9c5db199SXin Liimport sys 10*9c5db199SXin Liimport time 11*9c5db199SXin Liimport traceback 12*9c5db199SXin Li 13*9c5db199SXin Liimport common 14*9c5db199SXin Lifrom autotest_lib.client.bin import local_host 15*9c5db199SXin Lifrom autotest_lib.client.bin import utils 16*9c5db199SXin Lifrom autotest_lib.client.common_lib import error 17*9c5db199SXin Lifrom autotest_lib.client.common_lib.cros import crash_detector 18*9c5db199SXin Lifrom autotest_lib.client.cros import upstart 19*9c5db199SXin Lifrom autotest_lib.client.cros.cellular import mm 20*9c5db199SXin Lifrom autotest_lib.client.cros.cellular import mm1_constants 21*9c5db199SXin Lifrom autotest_lib.client.cros.networking import cellular_proxy 22*9c5db199SXin Lifrom autotest_lib.client.cros.networking import mm1_proxy 23*9c5db199SXin Lifrom autotest_lib.client.cros.networking import shill_context 24*9c5db199SXin Lifrom autotest_lib.client.cros.networking import shill_proxy 25*9c5db199SXin Li 26*9c5db199SXin Li 27*9c5db199SXin Liclass CellularTestEnvironment(object): 28*9c5db199SXin Li """Setup and verify cellular test environment. 29*9c5db199SXin Li 30*9c5db199SXin Li This context manager configures the following: 31*9c5db199SXin Li - Shuts down other devices except cellular. 32*9c5db199SXin Li - Shill and MM logging is enabled appropriately for cellular. 33*9c5db199SXin Li - Initializes members that tests should use to access test environment 34*9c5db199SXin Li (eg. |shill|, |modem_manager|, |modem|). 35*9c5db199SXin Li - modemfwd is stopped to prevent the modem from rebooting underneath 36*9c5db199SXin Li us. 37*9c5db199SXin Li 38*9c5db199SXin Li Then it verifies the following is valid: 39*9c5db199SXin Li - The SIM is inserted and valid. 40*9c5db199SXin Li - There is one and only one modem in the device. 41*9c5db199SXin Li - The modem is registered to the network. 42*9c5db199SXin Li - There is a cellular service in shill and it's not connected. 43*9c5db199SXin Li 44*9c5db199SXin Li Don't use this base class directly, use the appropriate subclass. 45*9c5db199SXin Li 46*9c5db199SXin Li Setup for over-the-air tests: 47*9c5db199SXin Li with CellularOTATestEnvironment() as test_env: 48*9c5db199SXin Li # Test body 49*9c5db199SXin Li 50*9c5db199SXin Li Setup for pseudomodem tests: 51*9c5db199SXin Li with CellularPseudoMMTestEnvironment( 52*9c5db199SXin Li pseudomm_args=({'family': '3GPP'})) as test_env: 53*9c5db199SXin Li # Test body 54*9c5db199SXin Li 55*9c5db199SXin Li """ 56*9c5db199SXin Li 57*9c5db199SXin Li def __init__(self, 58*9c5db199SXin Li shutdown_other_devices=True, 59*9c5db199SXin Li modem_pattern='', 60*9c5db199SXin Li skip_modem_reset=False, 61*9c5db199SXin Li is_esim_test=False, 62*9c5db199SXin Li enable_temp_containments=True): 63*9c5db199SXin Li """ 64*9c5db199SXin Li @param shutdown_other_devices: If True, shutdown all devices except 65*9c5db199SXin Li cellular. 66*9c5db199SXin Li @param modem_pattern: Search string used when looking for the modem. 67*9c5db199SXin Li @param enable_temp_containments: Enable temporary containments to avoid 68*9c5db199SXin Li failures on tests with known problems. 69*9c5db199SXin Li 70*9c5db199SXin Li """ 71*9c5db199SXin Li # Tests should use this main loop instead of creating their own. 72*9c5db199SXin Li self.mainloop = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 73*9c5db199SXin Li self.bus = dbus.SystemBus(mainloop=self.mainloop) 74*9c5db199SXin Li 75*9c5db199SXin Li self.shill = None 76*9c5db199SXin Li self.modem_manager = None 77*9c5db199SXin Li self.modem = None 78*9c5db199SXin Li self.modem_path = None 79*9c5db199SXin Li 80*9c5db199SXin Li self._modem_pattern = modem_pattern 81*9c5db199SXin Li self._skip_modem_reset = skip_modem_reset 82*9c5db199SXin Li self._is_esim_test = is_esim_test 83*9c5db199SXin Li self._enable_temp_containments = enable_temp_containments 84*9c5db199SXin Li self._system_service_order = '' 85*9c5db199SXin Li self._test_service_order = 'cellular,ethernet' 86*9c5db199SXin Li 87*9c5db199SXin Li self._nested = None 88*9c5db199SXin Li self._context_managers = [] 89*9c5db199SXin Li self.detect_crash = crash_detector.CrashDetector( 90*9c5db199SXin Li local_host.LocalHost()) 91*9c5db199SXin Li self.detect_crash.remove_crash_files() 92*9c5db199SXin Li if shutdown_other_devices: 93*9c5db199SXin Li self._context_managers.append( 94*9c5db199SXin Li shill_context.AllowedTechnologiesContext([ 95*9c5db199SXin Li shill_proxy.ShillProxy.TECHNOLOGY_CELLULAR, 96*9c5db199SXin Li shill_proxy.ShillProxy.TECHNOLOGY_ETHERNET 97*9c5db199SXin Li ])) 98*9c5db199SXin Li 99*9c5db199SXin Li @contextlib.contextmanager 100*9c5db199SXin Li def _disable_shill_autoconnect(self): 101*9c5db199SXin Li self._enable_shill_cellular_autoconnect(False) 102*9c5db199SXin Li yield 103*9c5db199SXin Li self._enable_shill_cellular_autoconnect(True) 104*9c5db199SXin Li 105*9c5db199SXin Li def __enter__(self): 106*9c5db199SXin Li try: 107*9c5db199SXin Li # Wait for system daemons to stabilize before beginning the test. 108*9c5db199SXin Li # Modemfwd, Chrome, Shill and Hermes might be active before the test 109*9c5db199SXin Li # begins, and interrupting them abruptly during test setup might 110*9c5db199SXin Li # lead to flaky tests. The modem might also appear/disappear 111*9c5db199SXin Li # multiple times during this period. Ideally, we would wait for a 112*9c5db199SXin Li # green signal from these daemons before performing test setup. 113*9c5db199SXin Li with open('/proc/uptime') as uptime_file: 114*9c5db199SXin Li uptime = float(uptime_file.readline().split()[0]) 115*9c5db199SXin Li if uptime < 60: 116*9c5db199SXin Li logging.info( 117*9c5db199SXin Li "Waiting %.1f seconds to reach uptime of 1 minute before " 118*9c5db199SXin Li "starting test", 60 - uptime) 119*9c5db199SXin Li time.sleep(60 - uptime) 120*9c5db199SXin Li 121*9c5db199SXin Li if upstart.has_service('modemfwd') and upstart.is_running('modemfwd'): 122*9c5db199SXin Li # Due to b/179796133, stopping modemfwd right after it was 123*9c5db199SXin Li # started by a previous test, can wedge the modem. In many 124*9c5db199SXin Li # devices, a ~1 second delay solves the problem. 125*9c5db199SXin Li time.sleep(4) 126*9c5db199SXin Li upstart.stop_job('modemfwd') 127*9c5db199SXin Li # Temporarily disable shill autoconnect to cellular service while 128*9c5db199SXin Li # the test environment is setup to prevent a race condition 129*9c5db199SXin Li # between disconnecting the modem in _verify_cellular_service() 130*9c5db199SXin Li # and shill autoconnect. 131*9c5db199SXin Li with self._disable_shill_autoconnect(): 132*9c5db199SXin Li try: 133*9c5db199SXin Li from contextlib import nested # Python 2 134*9c5db199SXin Li except ImportError: 135*9c5db199SXin Li from contextlib import ExitStack, contextmanager 136*9c5db199SXin Li 137*9c5db199SXin Li @contextmanager 138*9c5db199SXin Li def nested(*contexts): 139*9c5db199SXin Li """ Implementation of nested for python3""" 140*9c5db199SXin Li with ExitStack() as stack: 141*9c5db199SXin Li for ctx in contexts: 142*9c5db199SXin Li stack.enter_context(ctx) 143*9c5db199SXin Li yield contexts 144*9c5db199SXin Li 145*9c5db199SXin Li self._nested = nested(*self._context_managers) 146*9c5db199SXin Li 147*9c5db199SXin Li self._nested.__enter__() 148*9c5db199SXin Li 149*9c5db199SXin Li self._initialize_shill() 150*9c5db199SXin Li 151*9c5db199SXin Li # Perform SIM verification now to ensure that we can enable the 152*9c5db199SXin Li # modem in _initialize_modem_components(). ModemManager does not 153*9c5db199SXin Li # allow enabling a modem without a SIM. 154*9c5db199SXin Li self._verify_sim() 155*9c5db199SXin Li self._initialize_modem_components() 156*9c5db199SXin Li 157*9c5db199SXin Li self._setup_logging() 158*9c5db199SXin Li 159*9c5db199SXin Li if not self._is_esim_test: 160*9c5db199SXin Li self._wait_for_modem_registration() 161*9c5db199SXin Li self._verify_cellular_service() 162*9c5db199SXin Li 163*9c5db199SXin Li return self 164*9c5db199SXin Li except (error.TestError, dbus.DBusException, 165*9c5db199SXin Li shill_proxy.ShillProxyError) as e: 166*9c5db199SXin Li except_type, except_value, except_traceback = sys.exc_info() 167*9c5db199SXin Li lines = traceback.format_exception(except_type, except_value, 168*9c5db199SXin Li except_traceback) 169*9c5db199SXin Li logging.error('Error during test initialization:\n%s', 170*9c5db199SXin Li ''.join(lines)) 171*9c5db199SXin Li self.__exit__(*sys.exc_info()) 172*9c5db199SXin Li raise error.TestError('INIT_ERROR: %s' % str(e)) 173*9c5db199SXin Li except: 174*9c5db199SXin Li self.__exit__(*sys.exc_info()) 175*9c5db199SXin Li raise 176*9c5db199SXin Li 177*9c5db199SXin Li def __exit__(self, exception, value, traceback): 178*9c5db199SXin Li exception_on_restore_state = None 179*9c5db199SXin Li try: 180*9c5db199SXin Li self._restore_state() 181*9c5db199SXin Li except Exception as ex: 182*9c5db199SXin Li # Exceptions thrown by _restore_state() should be ignored if a 183*9c5db199SXin Li # previous exception exist, otherwise the root cause of the test 184*9c5db199SXin Li # failure will be overwritten by the clean up error in 185*9c5db199SXin Li # _restore_state, and that is not useful. 186*9c5db199SXin Li if exception is None: 187*9c5db199SXin Li exception_on_restore_state = ex 188*9c5db199SXin Li 189*9c5db199SXin Li # If a test fails and a crash is detected, the crash error takes 190*9c5db199SXin Li # priority over the previous failure. 191*9c5db199SXin Li crash_files = self.detect_crash.get_new_crash_files() 192*9c5db199SXin Li if any(cf for cf in crash_files if any(pr in cf for pr in [ 193*9c5db199SXin Li 'ModemManager', 'shill', 'qmi', 'mbim', 'hermes', 'modemfwd' 194*9c5db199SXin Li ])): 195*9c5db199SXin Li logging.info( 196*9c5db199SXin Li 'A crash was encountered. ' 197*9c5db199SXin Li 'Overriding the previous error: %s', value) 198*9c5db199SXin Li raise error.TestError( 199*9c5db199SXin Li 'One or more daemon crashes were detected. ' 200*9c5db199SXin Li 'See crash dumps: {}'.format(crash_files)) 201*9c5db199SXin Li 202*9c5db199SXin Li if exception_on_restore_state is not None: 203*9c5db199SXin Li raise exception_on_restore_state 204*9c5db199SXin Li 205*9c5db199SXin Li if self._nested: 206*9c5db199SXin Li return self._nested.__exit__(exception, value, traceback) 207*9c5db199SXin Li self.shill = None 208*9c5db199SXin Li self.modem_manager = None 209*9c5db199SXin Li self.modem = None 210*9c5db199SXin Li self.modem_path = None 211*9c5db199SXin Li 212*9c5db199SXin Li def _restore_state(self): 213*9c5db199SXin Li """Try to restore the test environment to a good state. 214*9c5db199SXin Li """ 215*9c5db199SXin Li if upstart.has_service('modemfwd'): 216*9c5db199SXin Li upstart.restart_job('modemfwd') 217*9c5db199SXin Li if self.shill: 218*9c5db199SXin Li self._set_service_order(self._system_service_order) 219*9c5db199SXin Li 220*9c5db199SXin Li def _get_shill_cellular_device_object(self): 221*9c5db199SXin Li return utils.poll_for_condition( 222*9c5db199SXin Li lambda: self.shill.find_cellular_device_object(), 223*9c5db199SXin Li exception=error.TestError('Cannot find cellular device in shill. ' 224*9c5db199SXin Li 'Is the modem plugged in?'), 225*9c5db199SXin Li timeout=shill_proxy.ShillProxy.DEVICE_ENUMERATION_TIMEOUT) 226*9c5db199SXin Li 227*9c5db199SXin Li def _get_service_order(self): 228*9c5db199SXin Li """Get the shill service order. 229*9c5db199SXin Li 230*9c5db199SXin Li @return string service order on success, None otherwise. 231*9c5db199SXin Li 232*9c5db199SXin Li """ 233*9c5db199SXin Li return str(self.shill.manager.GetServiceOrder()) 234*9c5db199SXin Li 235*9c5db199SXin Li def _set_service_order(self, order): 236*9c5db199SXin Li """Set the shill service order. 237*9c5db199SXin Li 238*9c5db199SXin Li @param order string comma-delimited service order 239*9c5db199SXin Li (eg. 'cellular,ethernet') 240*9c5db199SXin Li @return bool True on success, False otherwise. 241*9c5db199SXin Li 242*9c5db199SXin Li """ 243*9c5db199SXin Li self.shill.manager.SetServiceOrder(dbus.String(order)) 244*9c5db199SXin Li return True 245*9c5db199SXin Li 246*9c5db199SXin Li def _enable_modem(self): 247*9c5db199SXin Li modem_device = self._get_shill_cellular_device_object() 248*9c5db199SXin Li try: 249*9c5db199SXin Li modem_device.Enable() 250*9c5db199SXin Li except dbus.DBusException as e: 251*9c5db199SXin Li if (e.get_dbus_name() != 252*9c5db199SXin Li shill_proxy.ShillProxy.ERROR_IN_PROGRESS): 253*9c5db199SXin Li raise 254*9c5db199SXin Li 255*9c5db199SXin Li utils.poll_for_condition( 256*9c5db199SXin Li lambda: modem_device.GetProperties()['Powered'], 257*9c5db199SXin Li exception=error.TestError( 258*9c5db199SXin Li 'Failed to enable modem.'), 259*9c5db199SXin Li timeout=shill_proxy.ShillProxy.DEVICE_ENABLE_DISABLE_TIMEOUT) 260*9c5db199SXin Li 261*9c5db199SXin Li def _enable_shill_cellular_autoconnect(self, enable): 262*9c5db199SXin Li shill = cellular_proxy.CellularProxy.get_proxy(self.bus) 263*9c5db199SXin Li shill.manager.SetProperty( 264*9c5db199SXin Li shill_proxy.ShillProxy. 265*9c5db199SXin Li MANAGER_PROPERTY_NO_AUTOCONNECT_TECHNOLOGIES, 266*9c5db199SXin Li '' if enable else 'cellular') 267*9c5db199SXin Li 268*9c5db199SXin Li def _is_unsupported_error(self, e): 269*9c5db199SXin Li return (e.get_dbus_name() == 270*9c5db199SXin Li shill_proxy.ShillProxy.ERROR_NOT_SUPPORTED or 271*9c5db199SXin Li (e.get_dbus_name() == 272*9c5db199SXin Li shill_proxy.ShillProxy.ERROR_FAILURE and 273*9c5db199SXin Li 'operation not supported' in e.get_dbus_message())) 274*9c5db199SXin Li 275*9c5db199SXin Li def _reset_modem(self): 276*9c5db199SXin Li modem_device = self._get_shill_cellular_device_object() 277*9c5db199SXin Li try: 278*9c5db199SXin Li # MBIM modems do not support being reset. 279*9c5db199SXin Li self.shill.reset_modem(modem_device, expect_service=False) 280*9c5db199SXin Li except dbus.DBusException as e: 281*9c5db199SXin Li if not self._is_unsupported_error(e): 282*9c5db199SXin Li raise 283*9c5db199SXin Li 284*9c5db199SXin Li def _initialize_shill(self): 285*9c5db199SXin Li """Get access to shill.""" 286*9c5db199SXin Li # CellularProxy.get_proxy() checks to see if shill is running and 287*9c5db199SXin Li # responding to DBus requests. It returns None if that's not the case. 288*9c5db199SXin Li self.shill = cellular_proxy.CellularProxy.get_proxy(self.bus) 289*9c5db199SXin Li if self.shill is None: 290*9c5db199SXin Li raise error.TestError('Cannot connect to shill, is shill running?') 291*9c5db199SXin Li 292*9c5db199SXin Li self._system_service_order = self._get_service_order() 293*9c5db199SXin Li self._set_service_order(self._test_service_order) 294*9c5db199SXin Li 295*9c5db199SXin Li def _initialize_modem_components(self): 296*9c5db199SXin Li """Reset the modem and get access to modem components.""" 297*9c5db199SXin Li # Enable modem first so shill initializes the modemmanager proxies so 298*9c5db199SXin Li # we can call reset on it. 299*9c5db199SXin Li self._enable_modem() 300*9c5db199SXin Li if not self._skip_modem_reset: 301*9c5db199SXin Li self._reset_modem() 302*9c5db199SXin Li 303*9c5db199SXin Li # PickOneModem() makes sure there's a modem manager and that there is 304*9c5db199SXin Li # one and only one modem. 305*9c5db199SXin Li self.modem_manager, self.modem_path = \ 306*9c5db199SXin Li mm.PickOneModem(self._modem_pattern) 307*9c5db199SXin Li self.modem = self.modem_manager.GetModem(self.modem_path) 308*9c5db199SXin Li if self.modem is None: 309*9c5db199SXin Li raise error.TestError('Cannot get modem object at %s.' % 310*9c5db199SXin Li self.modem_path) 311*9c5db199SXin Li 312*9c5db199SXin Li def _setup_logging(self): 313*9c5db199SXin Li self.shill.set_logging_for_cellular_test() 314*9c5db199SXin Li self.modem_manager.SetDebugLogging() 315*9c5db199SXin Li 316*9c5db199SXin Li def _verify_sim(self): 317*9c5db199SXin Li """Verify SIM is valid. 318*9c5db199SXin Li 319*9c5db199SXin Li Make sure a SIM in inserted and that it is not locked. 320*9c5db199SXin Li 321*9c5db199SXin Li @raise error.TestError if SIM does not exist or is locked. 322*9c5db199SXin Li 323*9c5db199SXin Li """ 324*9c5db199SXin Li # check modem SIM slot and properties and switch slot as needed 325*9c5db199SXin Li modem_proxy = self._check_for_modem_with_sim() 326*9c5db199SXin Li if modem_proxy is None: 327*9c5db199SXin Li raise error.TestError('There is no Modem with non empty SIM path.') 328*9c5db199SXin Li 329*9c5db199SXin Li modem_device = self._get_shill_cellular_device_object() 330*9c5db199SXin Li props = modem_device.GetProperties() 331*9c5db199SXin Li 332*9c5db199SXin Li # No SIM in CDMA modems. 333*9c5db199SXin Li family = props[ 334*9c5db199SXin Li cellular_proxy.CellularProxy.DEVICE_PROPERTY_TECHNOLOGY_FAMILY] 335*9c5db199SXin Li if (family == 336*9c5db199SXin Li cellular_proxy.CellularProxy. 337*9c5db199SXin Li DEVICE_PROPERTY_TECHNOLOGY_FAMILY_CDMA): 338*9c5db199SXin Li return 339*9c5db199SXin Li 340*9c5db199SXin Li # Make sure there is a SIM. 341*9c5db199SXin Li if not props[cellular_proxy.CellularProxy.DEVICE_PROPERTY_SIM_PRESENT]: 342*9c5db199SXin Li raise error.TestError('There is no SIM in the modem.') 343*9c5db199SXin Li 344*9c5db199SXin Li # Make sure SIM is not locked. 345*9c5db199SXin Li lock_status = props.get( 346*9c5db199SXin Li cellular_proxy.CellularProxy.DEVICE_PROPERTY_SIM_LOCK_STATUS, 347*9c5db199SXin Li None) 348*9c5db199SXin Li if lock_status is None: 349*9c5db199SXin Li raise error.TestError('Failed to read SIM lock status.') 350*9c5db199SXin Li locked = lock_status.get( 351*9c5db199SXin Li cellular_proxy.CellularProxy.PROPERTY_KEY_SIM_LOCK_ENABLED, 352*9c5db199SXin Li None) 353*9c5db199SXin Li if locked is None: 354*9c5db199SXin Li raise error.TestError('Failed to read SIM LockEnabled status.') 355*9c5db199SXin Li elif locked: 356*9c5db199SXin Li raise error.TestError( 357*9c5db199SXin Li 'SIM is locked, test requires an unlocked SIM.') 358*9c5db199SXin Li 359*9c5db199SXin Li def _check_for_modem_with_sim(self): 360*9c5db199SXin Li """ 361*9c5db199SXin Li Make sure modem got active SIM and path is not empty 362*9c5db199SXin Li 363*9c5db199SXin Li switch slot to get non empty sim path and active sim slot for modem 364*9c5db199SXin Li 365*9c5db199SXin Li @return active modem object or None 366*9c5db199SXin Li 367*9c5db199SXin Li """ 368*9c5db199SXin Li mm_proxy = mm1_proxy.ModemManager1Proxy.get_proxy() 369*9c5db199SXin Li if mm_proxy is None: 370*9c5db199SXin Li raise error.TestError('Modem manager is not initialized') 371*9c5db199SXin Li 372*9c5db199SXin Li modem_proxy = mm_proxy.wait_for_modem(mm1_constants.MM_MODEM_POLL_TIME) 373*9c5db199SXin Li if modem_proxy is None: 374*9c5db199SXin Li raise error.TestError('Modem not initialized') 375*9c5db199SXin Li 376*9c5db199SXin Li primary_slot = modem_proxy.get_primary_sim_slot() 377*9c5db199SXin Li # Get SIM path from modem SIM properties 378*9c5db199SXin Li modem_props = modem_proxy.properties(mm1_constants.I_MODEM) 379*9c5db199SXin Li sim_path = modem_props['Sim'] 380*9c5db199SXin Li 381*9c5db199SXin Li logging.info('Device SIM values=> path:%s ' 382*9c5db199SXin Li 'primary slot:%d', sim_path, primary_slot) 383*9c5db199SXin Li 384*9c5db199SXin Li def is_usable_sim(path): 385*9c5db199SXin Li """Check if sim at path can be used to establish a connection""" 386*9c5db199SXin Li if path == mm1_constants.MM_EMPTY_SLOT_PATH: 387*9c5db199SXin Li return False 388*9c5db199SXin Li sim_proxy = modem_proxy.get_sim_at_path(path) 389*9c5db199SXin Li sim_props = sim_proxy.properties() 390*9c5db199SXin Li return sim_props[ 391*9c5db199SXin Li 'EsimStatus'] != mm1_constants.MM_SIM_ESIM_STATUS_NO_PROFILES 392*9c5db199SXin Li 393*9c5db199SXin Li # Check current SIM path value and status 394*9c5db199SXin Li if is_usable_sim(sim_path): 395*9c5db199SXin Li return modem_proxy 396*9c5db199SXin Li 397*9c5db199SXin Li slots = modem_props['SimSlots'] 398*9c5db199SXin Li logging.info('Dut not in expected state, ' 399*9c5db199SXin Li 'current sim path:%s slots:%s', sim_path, slots) 400*9c5db199SXin Li 401*9c5db199SXin Li for idx, path in enumerate(slots): 402*9c5db199SXin Li if not is_usable_sim(path): 403*9c5db199SXin Li continue 404*9c5db199SXin Li logging.info('Primary slot does not have a SIM, ' 405*9c5db199SXin Li 'switching slot to %d', idx+1) 406*9c5db199SXin Li 407*9c5db199SXin Li if (primary_slot != idx + 1): 408*9c5db199SXin Li logging.info('setting slot:%d path:%s', idx+1, path) 409*9c5db199SXin Li modem_proxy.set_primary_slot(idx+1) 410*9c5db199SXin Li modem_proxy = \ 411*9c5db199SXin Li mm_proxy.wait_for_modem(mm1_constants.MM_MODEM_POLL_TIME) 412*9c5db199SXin Li return modem_proxy 413*9c5db199SXin Li return None 414*9c5db199SXin Li 415*9c5db199SXin Li def _wait_for_modem_registration(self): 416*9c5db199SXin Li """Wait for the modem to register with the network. 417*9c5db199SXin Li 418*9c5db199SXin Li @raise error.TestError if modem is not registered. 419*9c5db199SXin Li 420*9c5db199SXin Li """ 421*9c5db199SXin Li utils.poll_for_condition( 422*9c5db199SXin Li self.modem.ModemIsRegistered, 423*9c5db199SXin Li exception=error.TestError( 424*9c5db199SXin Li 'Modem failed to register with the network.'), 425*9c5db199SXin Li timeout=cellular_proxy.CellularProxy.SERVICE_REGISTRATION_TIMEOUT) 426*9c5db199SXin Li 427*9c5db199SXin Li def _verify_cellular_service(self): 428*9c5db199SXin Li """Make sure a cellular service exists. 429*9c5db199SXin Li 430*9c5db199SXin Li The cellular service should not be connected to the network. 431*9c5db199SXin Li 432*9c5db199SXin Li @raise error.TestError if cellular service does not exist or if 433*9c5db199SXin Li there are multiple cellular services. 434*9c5db199SXin Li 435*9c5db199SXin Li """ 436*9c5db199SXin Li service = self.shill.wait_for_cellular_service_object() 437*9c5db199SXin Li 438*9c5db199SXin Li try: 439*9c5db199SXin Li service.Disconnect() 440*9c5db199SXin Li except dbus.DBusException as e: 441*9c5db199SXin Li if (e.get_dbus_name() != 442*9c5db199SXin Li cellular_proxy.CellularProxy.ERROR_NOT_CONNECTED): 443*9c5db199SXin Li raise 444*9c5db199SXin Li success, state, _ = self.shill.wait_for_property_in( 445*9c5db199SXin Li service, 446*9c5db199SXin Li cellular_proxy.CellularProxy.SERVICE_PROPERTY_STATE, 447*9c5db199SXin Li ('idle',), 448*9c5db199SXin Li cellular_proxy.CellularProxy.SERVICE_DISCONNECT_TIMEOUT) 449*9c5db199SXin Li if not success: 450*9c5db199SXin Li raise error.TestError( 451*9c5db199SXin Li 'Cellular service needs to start in the "idle" state. ' 452*9c5db199SXin Li 'Current state is "%s". ' 453*9c5db199SXin Li 'Modem disconnect may have failed.' % 454*9c5db199SXin Li state) 455*9c5db199SXin Li 456*9c5db199SXin Li 457*9c5db199SXin Liclass CellularOTATestEnvironment(CellularTestEnvironment): 458*9c5db199SXin Li """Setup and verify cellular over-the-air (OTA) test environment. """ 459*9c5db199SXin Li 460*9c5db199SXin Li def __init__(self, **kwargs): 461*9c5db199SXin Li super(CellularOTATestEnvironment, self).__init__(**kwargs) 462*9c5db199SXin Li 463*9c5db199SXin Li# pseudomodem tests disabled with b/180627893, cleaningup all pseudomodem 464*9c5db199SXin Li# related files and imports through: b/205769777 465*9c5db199SXin Li''' 466*9c5db199SXin Liclass CellularPseudoMMTestEnvironment(CellularTestEnvironment): 467*9c5db199SXin Li """Setup and verify cellular pseudomodem test environment. """ 468*9c5db199SXin Li 469*9c5db199SXin Li def __init__(self, pseudomm_args=None, **kwargs): 470*9c5db199SXin Li """ 471*9c5db199SXin Li @param pseudomm_args: Tuple of arguments passed to the pseudomodem, see 472*9c5db199SXin Li pseudomodem_context.py for description of each argument in the 473*9c5db199SXin Li tuple: (flags_map, block_output, bus) 474*9c5db199SXin Li 475*9c5db199SXin Li """ 476*9c5db199SXin Li kwargs["skip_modem_reset"] = True 477*9c5db199SXin Li super(CellularPseudoMMTestEnvironment, self).__init__(**kwargs) 478*9c5db199SXin Li self._context_managers.append( 479*9c5db199SXin Li pseudomodem_context.PseudoModemManagerContext( 480*9c5db199SXin Li True, bus=self.bus, *pseudomm_args)) 481*9c5db199SXin Li''' 482*9c5db199SXin Li 483*9c5db199SXin Liclass CellularESIMTestEnvironment(CellularTestEnvironment): 484*9c5db199SXin Li """Setup cellular eSIM test environment. """ 485*9c5db199SXin Li 486*9c5db199SXin Li def __init__(self, esim_arguments=None, **kwargs): 487*9c5db199SXin Li kwargs["skip_modem_reset"] = True 488*9c5db199SXin Li kwargs["is_esim_test"] = True 489*9c5db199SXin Li super(CellularESIMTestEnvironment, self).__init__(**kwargs) 490