Home | History | Annotate | Download | only in network_3GScanningProperty
      1 # Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import dbus
      6 import logging
      7 import os
      8 import time
      9 
     10 from autotest_lib.client.bin import test
     11 from autotest_lib.client.bin import utils
     12 from autotest_lib.client.common_lib import error
     13 from autotest_lib.client.cros.cellular import mm1_constants
     14 from autotest_lib.client.cros.cellular.pseudomodem import pm_constants
     15 from autotest_lib.client.cros.cellular.pseudomodem import pseudomodem_context
     16 from autotest_lib.client.cros.networking import cellular_proxy
     17 
     18 # Used for software message propagation latencies.
     19 SHORT_TIMEOUT_SECONDS = 2
     20 STATE_MACHINE_SCAN = 'ScanMachine'
     21 TEST_MODEMS_MODULE_PATH = os.path.join(os.path.dirname(__file__), 'files',
     22                                        'modems.py')
     23 
     24 class network_3GScanningProperty(test.test):
     25     """
     26     Test that the |Scanning| Property of the shill cellular device object is
     27     updated correctly in the following two scenarios:
     28       (1) When a user requests a network scan using the |ProposeScan| method of
     29           the cellular device.
     30       (2) During the initial modem enable-register-connect sequence.
     31 
     32     """
     33     version = 1
     34 
     35     def _find_mm_modem(self):
     36         """
     37         Find the modemmanager modem object.
     38 
     39         Assumption: There is only one modem in the system.
     40 
     41         @raises: TestError unless exactly one modem is found.
     42 
     43         """
     44         object_manager = dbus.Interface(
     45                 self._bus.get_object(mm1_constants.I_MODEM_MANAGER,
     46                                      mm1_constants.MM1),
     47                 mm1_constants.I_OBJECT_MANAGER)
     48         try:
     49             modems = object_manager.GetManagedObjects()
     50         except dbus.exceptions.DBusException as e:
     51             raise error.TestFail('Failed to list the available modems. '
     52                                  'DBus error: |%s|', repr(e))
     53         if len(modems) != 1:
     54             raise error.TestFail('Expected one modem object, found %d' %
     55                                  len(modems))
     56 
     57         modem_path = modems.keys()[0]
     58         modem_object = self._bus.get_object(mm1_constants.I_MODEM_MANAGER,
     59                                             modem_path)
     60         # Check that this object is valid
     61         try:
     62             modem_object.GetAll(mm1_constants.I_MODEM,
     63                                 dbus_interface=mm1_constants.I_PROPERTIES)
     64         except dbus.exceptions.DBusException as e:
     65             raise error.TestFail('Failed to obtain dbus object for the modem '
     66                                  'DBus error: |%s|', repr(e))
     67 
     68         return dbus.Interface(modem_object, mm1_constants.I_MODEM)
     69 
     70 
     71     def _check_mm_state(self, modem, states):
     72         """
     73         Verify that the modemmanager state is |state|.
     74 
     75         @param modem: A DBus object for the modemmanager modem.
     76         @param states: The expected state of the modem. This is either a single
     77                 state, or a list of states.
     78         @raises: TestError if the state differs.
     79         """
     80         if not isinstance(states, list):
     81             states = [states]
     82         properties = modem.GetAll(mm1_constants.I_MODEM,
     83                                   dbus_interface=mm1_constants.I_PROPERTIES)
     84         actual_state = properties[mm1_constants.MM_MODEM_PROPERTY_NAME_STATE]
     85         if actual_state not in states:
     86             state_names = [mm1_constants.ModemStateToString(x) for x in states]
     87             raise error.TestFail(
     88                     'Expected modemmanager modem state to be one of %s but '
     89                     'found %s' %
     90                     (state_names,
     91                      mm1_constants.ModemStateToString(actual_state)))
     92 
     93 
     94     def _check_shill_property_update(self, cellular_device, property_name,
     95                                      old_state, new_state):
     96         """
     97         Check the value of property of shill.
     98 
     99         @param cellular_device: The DBus proxy object for the cellular device.
    100         @param property_name: Name of the property to check.
    101         @param old_state: old value of property.
    102         @param new_state: new expected value of property.
    103         @raises: TestError if the property fails to enter the given state.
    104 
    105         """
    106         # If we don't expect a change in the value, there is a race between this
    107         # check and a possible (erronous) update of the value. Allow some time
    108         # for the property to be updated before checking.
    109         if old_state == new_state:
    110             time.sleep(SHORT_TIMEOUT_SECONDS)
    111             polling_timeout = 0
    112         else:
    113             polling_timeout = SHORT_TIMEOUT_SECONDS
    114         success, _, _ = self._cellular_proxy.wait_for_property_in(
    115                 cellular_device,
    116                 property_name,
    117                 (new_state,),
    118                 timeout_seconds=polling_timeout)
    119         if not success:
    120             raise error.TestFail('Shill failed to set |%s| to %s.' %
    121                                  (property_name, str(new_state)))
    122 
    123 
    124     def _itesting_machine(self, machine_name, timeout=SHORT_TIMEOUT_SECONDS):
    125         """
    126         Get the testing interface of the given interactive state machine.
    127 
    128         @param machine_name: The name of the interactive state machine.
    129         @return dbus.Interface for the testing interface of
    130                 InteractiveScanningMachine, if found. None otherwise.
    131         @raises utils.TimeoutError if a valid dbus object can't be found.
    132 
    133         """
    134         def _get_machine():
    135             machine = self._bus.get_object(
    136                     mm1_constants.I_MODEM_MANAGER,
    137                     '/'.join([pm_constants.TESTING_PATH, machine_name]))
    138             if machine:
    139                 i_machine = dbus.Interface(machine, pm_constants.I_TESTING_ISM)
    140                 # Only way to know if this DBus object is valid is to call a
    141                 # method on it.
    142                 try:
    143                     i_machine.IsWaiting()  # Ignore result.
    144                     return i_machine
    145                 except dbus.exceptions.DBusException as e:
    146                     logging.debug(e)
    147                     return None
    148 
    149         utils.poll_for_condition(_get_machine, timeout=timeout)
    150         return _get_machine()
    151 
    152 
    153     def test_user_initiated_cellular_scan(self):
    154         """
    155         Test that the |ProposeScan| DBus method exported by shill cellular
    156         object correctly updates the cellular object |Scanning| property while
    157         the scan is in progress.
    158         """
    159         with pseudomodem_context.PseudoModemManagerContext(
    160                 True,
    161                 {'test-module' : TEST_MODEMS_MODULE_PATH,
    162                  'test-modem-class' : 'AsyncScanModem'}):
    163             self._cellular_proxy = cellular_proxy.CellularProxy.get_proxy()
    164             self._bus = dbus.SystemBus()
    165             self._cellular_proxy.set_logging_for_cellular_test()
    166 
    167             logging.info('Sanity check initial values')
    168             utils.poll_for_condition(
    169                     self._cellular_proxy.find_cellular_device_object,
    170                     exception=error.TestFail(
    171                             'Bad initial state: Failed to obtain a cellular '
    172                             'device in pseudomodem context.'),
    173                     timeout=SHORT_TIMEOUT_SECONDS)
    174             device = self._cellular_proxy.find_cellular_device_object()
    175             try:
    176                 self._itesting_machine(STATE_MACHINE_SCAN, 0)
    177                 raise error.TestFail('Bad initial state: scan machine created '
    178                                      'by pseudomodem before scan is proposed.')
    179             except utils.TimeoutError:
    180                 pass
    181 
    182             self._check_shill_property_update(
    183                     device,
    184                     self._cellular_proxy.DEVICE_PROPERTY_SCANNING,
    185                     False,
    186                     False)
    187 
    188             logging.info('Test actions and checks')
    189             device.ProposeScan()
    190             try:
    191                 itesting_scan_machine = self._itesting_machine(
    192                         STATE_MACHINE_SCAN)
    193             except utils.TimeoutError:
    194                 raise error.TestFail('Pseudomodem failed to launch %s' %
    195                                      STATE_MACHINE_SCAN)
    196             utils.poll_for_condition(
    197                     itesting_scan_machine.IsWaiting,
    198                     exception=error.TestFail('Scan machine failed to enter '
    199                                              'scan state'),
    200                     timeout=SHORT_TIMEOUT_SECONDS)
    201             self._check_shill_property_update(
    202                     device,
    203                     self._cellular_proxy.DEVICE_PROPERTY_SCANNING,
    204                     False,
    205                     True)
    206 
    207             itesting_scan_machine.Advance()
    208             utils.poll_for_condition(
    209                     lambda: not itesting_scan_machine.IsWaiting(),
    210                     exception=error.TestFail('Scan machine failed to exit '
    211                                              'scan state'),
    212                     timeout=SHORT_TIMEOUT_SECONDS)
    213             self._check_shill_property_update(
    214                     device,
    215                     self._cellular_proxy.DEVICE_PROPERTY_SCANNING,
    216                     True,
    217                     False)
    218 
    219 
    220     def test_activated_service_states(self):
    221         """
    222         Test that shill |Scanning| property is updated correctly when an
    223         activated 3GPP service connects.
    224         """
    225         with pseudomodem_context.PseudoModemManagerContext(
    226                 True,
    227                 {'test-module' : TEST_MODEMS_MODULE_PATH,
    228                  'test-state-machine-factory-class' :
    229                         'InteractiveStateMachineFactory'}):
    230             self._cellular_proxy = cellular_proxy.CellularProxy.get_proxy()
    231             self._bus = dbus.SystemBus()
    232             self._cellular_proxy.set_logging_for_cellular_test()
    233 
    234             logging.info('Sanity check initial values')
    235             enable_machine = self._itesting_machine(
    236                     pm_constants.STATE_MACHINE_ENABLE)
    237             utils.poll_for_condition(
    238                     enable_machine.IsWaiting,
    239                     exception=error.TestFail(
    240                             'Bad initial state: Pseudomodem did not launch '
    241                             'Enable machine'),
    242                     timeout=SHORT_TIMEOUT_SECONDS)
    243             utils.poll_for_condition(
    244                     self._cellular_proxy.find_cellular_device_object,
    245                     exception=error.TestFail(
    246                             'Bad initial state: Failed to obtain a cellular '
    247                             'device in pseudomodem context.'),
    248                     timeout=SHORT_TIMEOUT_SECONDS)
    249             device = self._cellular_proxy.find_cellular_device_object()
    250             mm_modem = self._find_mm_modem()
    251 
    252             logging.info('Test Connect sequence')
    253             self._check_mm_state(mm_modem,
    254                                  mm1_constants.MM_MODEM_STATE_DISABLED)
    255             self._check_shill_property_update(
    256                     device,
    257                     self._cellular_proxy.DEVICE_PROPERTY_POWERED,
    258                     False,
    259                     False)
    260             self._check_shill_property_update(
    261                     device,
    262                     self._cellular_proxy.DEVICE_PROPERTY_SCANNING,
    263                     False,
    264                     False)
    265             logging.info('Expectation met: |Scanning| is False in MM state '
    266                          'Disabled')
    267             enable_machine.Advance()
    268 
    269             # MM state: Enabling
    270             utils.poll_for_condition(
    271                     enable_machine.IsWaiting,
    272                     exception=error.TestFail('EnableMachine failed to wait in '
    273                                              'Enabling state'),
    274                     timeout=SHORT_TIMEOUT_SECONDS)
    275             self._check_mm_state(mm_modem,
    276                                  mm1_constants.MM_MODEM_STATE_ENABLING)
    277             self._check_shill_property_update(
    278                     device,
    279                     self._cellular_proxy.DEVICE_PROPERTY_SCANNING,
    280                     False,
    281                     True)
    282             logging.info('Expectation met: |Scanning| is True in MM state '
    283                          'Enabling')
    284             enable_machine.Advance()
    285 
    286             # MM state: Enabled
    287             utils.poll_for_condition(
    288                     enable_machine.IsWaiting,
    289                     exception=error.TestFail('EnableMachine failed to wait in '
    290                                              'Enabled state'),
    291                     timeout=SHORT_TIMEOUT_SECONDS)
    292             # Finish the enable call.
    293             enable_machine.Advance()
    294 
    295             self._check_mm_state(mm_modem, mm1_constants.MM_MODEM_STATE_ENABLED)
    296             self._check_shill_property_update(
    297                     device,
    298                     self._cellular_proxy.DEVICE_PROPERTY_POWERED,
    299                     False,
    300                     True)
    301             self._check_shill_property_update(
    302                     device,
    303                     self._cellular_proxy.DEVICE_PROPERTY_SCANNING,
    304                     True,
    305                     True)
    306 
    307             register_machine = self._itesting_machine(
    308                     pm_constants.STATE_MACHINE_REGISTER)
    309             utils.poll_for_condition(
    310                     register_machine.IsWaiting,
    311                     exception=error.TestFail('SearchingMachine failed to wait '
    312                                              'in Enabled state'),
    313                     timeout=SHORT_TIMEOUT_SECONDS)
    314             logging.info('Expectation met: |Scanning| is True in MM state '
    315                          'Enabled')
    316             register_machine.Advance()
    317 
    318             # MM state: Searching
    319             utils.poll_for_condition(
    320                     register_machine.IsWaiting,
    321                     exception=error.TestFail('SearchingMachine failed to wait '
    322                                              'in Searching state'),
    323                     timeout=SHORT_TIMEOUT_SECONDS)
    324             self._check_mm_state(mm_modem,
    325                                  mm1_constants.MM_MODEM_STATE_SEARCHING)
    326             enable_machine.Advance()
    327             self._check_shill_property_update(
    328                     device,
    329                     self._cellular_proxy.DEVICE_PROPERTY_SCANNING,
    330                     True,
    331                     True)
    332             logging.info('Expectation met: |Scanning| is True in MM state '
    333                          'Searching')
    334             register_machine.Advance()
    335 
    336             # MM state: >= Registered
    337             utils.poll_for_condition(
    338                     self._cellular_proxy.find_cellular_service_object,
    339                     error.TestFail('Failed to create Cellular Service for a '
    340                                    'registered modem'),
    341                     timeout=SHORT_TIMEOUT_SECONDS)
    342             self._check_mm_state(mm_modem,
    343                                  [mm1_constants.MM_MODEM_STATE_REGISTERED,
    344                                   mm1_constants.MM_MODEM_STATE_CONNECTING,
    345                                   mm1_constants.MM_MODEM_STATE_CONNECTED])
    346             self._check_shill_property_update(
    347                     device,
    348                     self._cellular_proxy.DEVICE_PROPERTY_SCANNING,
    349                     True,
    350                     False)
    351             logging.info('Expectation met: |Scanning| is False in MM state '
    352                          'Registered')
    353 
    354 
    355     def run_once(self):
    356         """ Autotest entry function """
    357         self.test_user_initiated_cellular_scan()
    358         self.test_activated_service_states()
    359