Home | History | Annotate | Download | only in network_LTEActivate
      1 # Copyright (c) 2013 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 import test_environment
     15 from autotest_lib.client.cros.networking import pm_proxy
     16 
     17 I_ACTIVATION_TEST = 'Interface.LTEActivationTest'
     18 TEST_MODEMS_MODULE_PATH = os.path.join(os.path.dirname(__file__), 'files',
     19                                        'modems.py')
     20 
     21 LONG_TIMEOUT = 20
     22 SHORT_TIMEOUT = 10
     23 
     24 class ActivationTest(object):
     25     """
     26     Super class that implements setup code that is common to the individual
     27     tests.
     28 
     29     """
     30     def __init__(self, test):
     31         self.test = test
     32 
     33 
     34     def Cleanup(self):
     35         """
     36         Makes the modem look like it has been activated to satisfy the test
     37         end condition.
     38 
     39         """
     40         # Set the MDN to a non-zero value, so that shill removes the ICCID from
     41         # activating_iccid_store.profile. This way, individual test runs won't
     42         # interfere with each other.
     43         modem = self.test.pseudomm.wait_for_modem(timeout_seconds=LONG_TIMEOUT)
     44         modem.iface_properties.Set(mm1_constants.I_MODEM,
     45                                    'OwnNumbers',
     46                                    ['1111111111'])
     47         # Put the modem in the unknown subscription state so that the mdn value is
     48         # used to remove the iccid entry
     49         self.test.pseudomm.iface_testing.SetSubscriptionState(
     50                 mm1_constants.MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN,
     51                 mm1_constants.MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN)
     52         time.sleep(5)
     53         self.test.CheckServiceActivationState('activated')
     54 
     55 
     56     def Run(self):
     57         """
     58         Configures the pseudomodem to run with the test modem, runs the test
     59         and cleans up.
     60 
     61         """
     62         self.RunTest()
     63         self.Cleanup()
     64 
     65 
     66     def TestModemClass(self):
     67         """ Returns the name of the custom modem to use for this test. """
     68         raise NotImplementedError()
     69 
     70 
     71     def RunTest(self):
     72         """
     73         Runs the body of the test. Should be implemented by the subclass.
     74 
     75         """
     76         raise NotImplementedError()
     77 
     78 
     79 class ActivationResetTest(ActivationTest):
     80     """
     81     This test verifies that the modem resets after online payment.
     82 
     83     """
     84     def TestModemClass(self):
     85         return 'TestModem'
     86 
     87 
     88     def RunTest(self):
     89         # Service should appear as 'not-activated'.
     90         self.test.CheckServiceActivationState('not-activated')
     91         self.test.CheckResetCalled(False)
     92 
     93         # Call 'CompleteActivation' on the device. The service will become
     94         # 'activating' and the modem should reset immediately.
     95         # Not checking for the intermediate 'activating' state because it makes
     96         # the test too fragile
     97         service = self.test.FindCellularService()
     98         service.CompleteCellularActivation()
     99         time.sleep(SHORT_TIMEOUT)
    100         self.test.CheckResetCalled(True)
    101 
    102 
    103 class ActivationCompleteTest(ActivationTest):
    104     """
    105     This test verifies that the service eventually becomes 'activated' in the
    106     case of a post-payment registration and the modem finally registers
    107     to a network after a reset.
    108 
    109     """
    110     def TestModemClass(self):
    111         return 'ResetRequiredForActivationModem'
    112 
    113 
    114     def RunTest(self):
    115         # Service should appear as 'not-activated'.
    116         self.test.CheckServiceActivationState('not-activated')
    117         self.test.CheckResetCalled(False)
    118 
    119         # Call 'CompleteActivation' on the device. The service will become
    120         # 'activating' and the modem should reset immediately.
    121         # Not checking for the intermediate 'activating' state because it makes
    122         # the test too fragile
    123         service = self.test.FindCellularService()
    124         service.CompleteCellularActivation()
    125         time.sleep(SHORT_TIMEOUT)
    126         self.test.CheckResetCalled(True)
    127 
    128         # The service should register and be marked as 'activated'.
    129         self.test.CheckServiceActivationState('activated')
    130 
    131 
    132 class ActivationDueToMdnTest(ActivationTest):
    133     """
    134     This test verifies that a valid MDN should cause the service to get marked
    135     as 'activated' when the modem is in unknown subscription state.
    136 
    137     """
    138     def TestModemClass(self):
    139         return 'TestModem'
    140 
    141 
    142     def RunTest(self):
    143         # Service should appear as 'not-activated'.
    144         self.test.CheckServiceActivationState('not-activated')
    145 
    146         # Update the MDN. The service should get marked as activated.
    147         modem = self.test.pseudomm.get_modem()
    148         modem.iface_properties.Set(mm1_constants.I_MODEM,
    149                                    'OwnNumbers',
    150                                    ['1111111111'])
    151         # Put the modem in the unknown subscription state so that the mdn value is
    152         # used to determine the service activation status.
    153         self.test.pseudomm.iface_testing.SetSubscriptionState(
    154                 mm1_constants.MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN,
    155                 mm1_constants.MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN)
    156         time.sleep(SHORT_TIMEOUT)
    157         self.test.CheckServiceActivationState('activated')
    158 
    159 
    160 class network_LTEActivate(test.test):
    161     """
    162     After an online payment to activate a network, shill keeps track of service
    163     activation by monitoring changes to network registration and MDN updates
    164     combined with a modem reset. The test checks that the
    165     Cellular.ActivationState property of the service has the correct value
    166     associated with it by simulating possible scenarios using the pseudo modem
    167     manager.
    168 
    169     """
    170     version = 1
    171 
    172     def GetModemState(self):
    173         """Returns the current ModemManager modem state."""
    174         modem = self.pseudomm.get_modem()
    175         props = modem.properties(mm1_constants.I_MODEM)
    176         return props['State']
    177 
    178 
    179     def SetResetCalled(self, value):
    180         """
    181         Sets the value of the "ResetCalled" property of the current
    182         modem.
    183 
    184         @param value: Value to set in the property.
    185 
    186         """
    187         modem = self.pseudomm.get_modem()
    188         if modem is None:
    189             return
    190         modem.iface_properties.Set(
    191                 I_ACTIVATION_TEST,
    192                 'ResetCalled',
    193                 dbus.types.Boolean(value))
    194 
    195 
    196     def GetResetCalled(self, modem):
    197         """
    198         Returns the current value of the "ResetCalled" property of the current
    199         modem.
    200 
    201         @param modem: Modem proxy to send the query to.
    202 
    203         """
    204         return modem.properties(I_ACTIVATION_TEST)['ResetCalled']
    205 
    206 
    207     def _CheckResetCalledHelper(self, expected_value):
    208         modem = self.pseudomm.get_modem()
    209         if modem is None:
    210             return False
    211         try:
    212             return self.GetResetCalled(modem) == expected_value
    213         except dbus.exceptions.DBusException as e:
    214             name = e.get_dbus_name()
    215             if (name == mm1_constants.DBUS_UNKNOWN_METHOD or
    216                 name == mm1_constants.DBUS_UNKNOWN_OBJECT):
    217                 return False
    218             raise e
    219 
    220 
    221     def CheckResetCalled(self, expected_value):
    222         """
    223         Checks that the ResetCalled property on the modem matches the expect
    224         value.
    225 
    226         @param expected_value: The expected value of ResetCalled.
    227 
    228         """
    229         utils.poll_for_condition(
    230             lambda: self._CheckResetCalledHelper(expected_value),
    231             exception=error.TestFail("\"ResetCalled\" did not match: " +
    232                                      str(expected_value)),
    233             timeout=LONG_TIMEOUT)
    234 
    235 
    236     def EnsureModemStateReached(self, expected_state, timeout):
    237         """
    238         Asserts that the underlying modem state becomes |expected_state| within
    239         |timeout|.
    240 
    241         @param expected_state: The expected modem state.
    242         @param timeout: Timeout in which the condition should be met.
    243 
    244         """
    245         utils.poll_for_condition(
    246                 lambda: self.GetModemState() == expected_state,
    247                 exception=error.TestFail(
    248                         'Modem failed to reach state ' +
    249                         mm1_constants.ModemStateToString(expected_state)),
    250                 timeout=timeout)
    251 
    252 
    253     def CheckServiceActivationState(self, expected_state):
    254         """
    255         Asserts that the service activation state matches |expected_state|
    256         within SHORT_TIMEOUT.
    257 
    258         @param expected_state: The expected service activation state.
    259 
    260         """
    261         logging.info('Checking for service activation state: %s',
    262                      expected_state)
    263         service = self.FindCellularService()
    264         success, state, duration = self.test_env.shill.wait_for_property_in(
    265             service,
    266             'Cellular.ActivationState',
    267             [expected_state],
    268             SHORT_TIMEOUT)
    269         if not success and state != expected_state:
    270             raise error.TestError(
    271                 'Service activation state should be \'%s\', but it is \'%s\'.'
    272                 % (expected_state, state))
    273 
    274 
    275     def FindCellularService(self, check_not_none=True):
    276         """
    277         Returns the current cellular service.
    278 
    279         @param check_not_none: If True, an error will be raised if no service
    280                 was found.
    281 
    282         """
    283         if check_not_none:
    284             utils.poll_for_condition(
    285                     lambda: (self.test_env.shill.find_cellular_service_object()
    286                              is not None),
    287                     exception=error.TestError(
    288                             'Could not find cellular service within timeout.'),
    289                     timeout=LONG_TIMEOUT);
    290 
    291         service = self.test_env.shill.find_cellular_service_object()
    292 
    293         # Check once more, to make sure it's valid.
    294         if check_not_none and not service:
    295             raise error.TestError('Could not find cellular service.')
    296         return service
    297 
    298 
    299     def FindCellularDevice(self):
    300         """Returns the current cellular device."""
    301         device = self.test_env.shill.find_cellular_device_object()
    302         if not device:
    303             raise error.TestError('Could not find cellular device.')
    304         return device
    305 
    306 
    307     def ResetCellularDevice(self):
    308         """
    309         Resets all modems, guaranteeing that the operation succeeds and doesn't
    310         fail due to race conditions in pseudomodem start-up and test execution.
    311 
    312         """
    313         self.EnsureModemStateReached(
    314                 mm1_constants.MM_MODEM_STATE_ENABLED, SHORT_TIMEOUT)
    315         self.test_env.shill.reset_modem(self.FindCellularDevice())
    316         self.EnsureModemStateReached(
    317                 mm1_constants.MM_MODEM_STATE_ENABLED, SHORT_TIMEOUT)
    318 
    319 
    320     def run_once(self):
    321         tests = [
    322             ActivationResetTest(self),
    323             ActivationCompleteTest(self),
    324             ActivationDueToMdnTest(self),
    325         ]
    326 
    327         for test in tests:
    328             self.test_env = test_environment.CellularPseudoMMTestEnvironment(
    329                     pseudomm_args = ({'family' : '3GPP',
    330                                       'test-module' : TEST_MODEMS_MODULE_PATH,
    331                                       'test-modem-class' : test.TestModemClass(),
    332                                       'test-sim-class' : 'TestSIM'},))
    333             with self.test_env:
    334                 self.pseudomm = pm_proxy.PseudoMMProxy.get_proxy()
    335                 # Set the reset flag to False explicitly before each test
    336                 # sequence starts to ignore the reset as a part of the test init
    337                 self.SetResetCalled(False)
    338                 test.Run()
    339