| # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from autotest_lib.client.bin import site_utils, test |
| from autotest_lib.client.common_lib import error |
| |
| import dbus |
| import dbus.types |
| import gobject |
| import time |
| |
| from autotest_lib.client.cros import backchannel, network, flimflam_test_path |
| from autotest_lib.client.cros.cellular import cell_tools |
| from autotest_lib.client.cros.cellular import mm |
| from autotest_lib.client.cros.cellular.pseudomodem import mm1 |
| from autotest_lib.client.cros.cellular.pseudomodem import modem_cdma |
| from autotest_lib.client.cros.cellular.pseudomodem import pseudomodem |
| import flimflam |
| |
| I_ACTIVATION_TEST = 'Interface.CDMAActivationTest' |
| ACTIVATION_STATE_TIMEOUT = 10 |
| MODEM_STATE_TIMEOUT = 10 |
| |
| class ActivationTest(object): |
| """ |
| Super class that implements setup code that is common to the individual |
| tests. |
| |
| """ |
| def __init__(self, pmm_context, test): |
| self.pmm_context = pmm_context |
| self.test = test |
| self.test_modem = self._setup_test_modem() |
| self.modem_properties_interface = None |
| |
| def run(self): |
| """ |
| Restarts the pseudomodem with the modem object to be used for this |
| test and runs the test. |
| |
| """ |
| if not self.test_modem: |
| raise test.TestFail('Uninitialized test modem') |
| self.pmm_context.SetModem(self.test_modem) |
| self._run_test() |
| |
| def _get_modem_properties_interface(self): |
| if not self.modem_properties_interface: |
| self.modem_properties_interface = \ |
| self.test.modem().PropertiesInterface() |
| return self.modem_properties_interface |
| |
| def _set_modem_activation_state(self, state): |
| interface = self._get_modem_properties_interface() |
| interface.Set( |
| mm1.I_MODEM_CDMA, 'ActivationState', dbus.types.UInt32(state)) |
| |
| def _get_modem_activation_state(self): |
| interface = self._get_modem_properties_interface() |
| return interface.Get(mm1.I_MODEM_CDMA, 'ActivationState') |
| |
| def _setup_test_modem(self): |
| raise NotImplementedError() |
| |
| def _run_test(self): |
| raise NotImplementedError() |
| |
| class ActivationStateTest(ActivationTest): |
| """ |
| This test verifies that the service "ActivationState" property matches the |
| cdma activation state exposed by ModemManager. |
| |
| """ |
| def _setup_test_modem(self): |
| return modem_cdma.ModemCdma() |
| |
| def _run_test(self): |
| network.ResetAllModems(self.test.flim) |
| |
| # The modem state should be REGISTERED. |
| self.test.check_modem_state(mm1.MM_MODEM_STATE_REGISTERED) |
| |
| # Service should appear as 'activated'. |
| self.test.check_service_activation_state('activated') |
| |
| # Service activation state should change to 'not-activated'. |
| self._set_modem_activation_state( |
| mm1.MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED) |
| self.test.check_service_activation_state('not-activated') |
| |
| # Service activation state should change to 'activating'. |
| self._set_modem_activation_state( |
| mm1.MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING) |
| self.test.check_service_activation_state('activating') |
| |
| # Service activation state should change to 'partially-activated'. |
| self._set_modem_activation_state( |
| mm1.MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED) |
| self.test.check_service_activation_state('partially-activated') |
| |
| # Service activation state should change to 'activated'. |
| self._set_modem_activation_state( |
| mm1.MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED) |
| self.test.check_service_activation_state('activated') |
| |
| class ActivationSuccessTest(ActivationTest): |
| """ |
| This test verifies that the service finally bacomes "activated" when the |
| service is told to initiate OTASP activation. |
| |
| """ |
| def _setup_test_modem(self): |
| return modem_cdma.ModemCdma( |
| modem_cdma.ModemCdma.CdmaNetwork(activated=False)) |
| |
| def _run_test(self): |
| network.ResetAllModems(self.test.flim) |
| |
| # The modem state should be REGISTERED. |
| self.test.check_modem_state(mm1.MM_MODEM_STATE_REGISTERED) |
| |
| # Service should appear as 'not-activated'. |
| self.test.check_service_activation_state('not-activated') |
| |
| # Call 'CompleteActivation' on the service. The service should become |
| # 'activating'. |
| service = self.test.find_cellular_service() |
| service.CompleteCellularActivation() |
| self.test.check_service_activation_state('activating') |
| |
| # The modem should reset in 5 seconds. Wait 5 more seconds to make sure |
| # a new service gets created. |
| time.sleep(10) |
| self.test.check_service_activation_state('activated') |
| |
| class ActivationFailureRetryTest(ActivationTest): |
| """ |
| This test verifies that if "ActivateAutomatic" fails, a retry will be |
| scheduled. |
| |
| """ |
| NUM_ACTIVATE_RETRIES = 5 |
| def _setup_test_modem(self): |
| class TestModem(modem_cdma.ModemCdma): |
| """ |
| TestModem to test that shill retries OTASP activation until it |
| succeeds. |
| |
| """ |
| def __init__(self): |
| self.activate_count = 0 |
| modem_cdma.ModemCdma.__init__(self, |
| modem_cdma.ModemCdma.CdmaNetwork(activated=False)) |
| |
| def _InitializeProperties(self): |
| props = modem_cdma.ModemCdma._InitializeProperties(self) |
| |
| # For the purposes of this test, introduce a property that |
| # stores how many times "Activate" has been called on this |
| # modem. |
| props[I_ACTIVATION_TEST] = { |
| 'ActivateCount' : dbus.types.UInt32(self.activate_count) |
| } |
| return props |
| |
| def _IncrementActivateCount(self): |
| self.activate_count += 1 |
| self.Set(I_ACTIVATION_TEST, |
| 'ActivateCount', |
| self.activate_count) |
| |
| def Activate(self, carrier, return_cb, raise_cb): |
| """ |
| Activation will only succeed on the NUM_ACTIVATE_RETRIESth try. |
| |
| """ |
| self._IncrementActivateCount() |
| if self.activate_count == \ |
| ActivationFailureRetryTest.NUM_ACTIVATE_RETRIES: |
| modem_cdma.ModemCdma.Activate( |
| self, carrier, return_cb, raise_cb) |
| else: |
| def _raise_activation_error(): |
| raise_cb(mm1.MMCdmaActivationError( |
| mm1.MMCdmaActivationError.START_FAILED)) |
| gobject.idle_add(_raise_activation_error) |
| return TestModem() |
| |
| def _run_test(self): |
| network.ResetAllModems(self.test.flim) |
| |
| # The modem state should be REGISTERED. |
| self.test.check_modem_state(mm1.MM_MODEM_STATE_REGISTERED) |
| |
| # Service should appear as 'not-activated'. |
| self.test.check_service_activation_state('not-activated') |
| |
| # Call 'CompleteActivation' on the service. The service should remain |
| # 'not-activated'. |
| service = self.test.find_cellular_service() |
| service.CompleteCellularActivation() |
| |
| modem_props = self._get_modem_properties_interface() |
| while modem_props.Get(I_ACTIVATION_TEST, 'ActivateCount') < \ |
| self.NUM_ACTIVATE_RETRIES: |
| self.test.check_service_activation_state('not-activated') |
| |
| # Activation should succeed after the latest retry. |
| self.test.check_service_activation_state('activating') |
| |
| # The modem should reset in 5 seconds. Wait 5 more seconds to make sure |
| # a new service gets created. |
| time.sleep(10) |
| self.test.check_service_activation_state('activated') |
| |
| class network_CDMAActivate(test.test): |
| """ |
| Tests various scenarios that may arise during the post-payment CDMA |
| activation process when shill accesses the modem via ModemManager. |
| |
| """ |
| version = 1 |
| |
| def modem(self): |
| """ |
| Returns a D-Bus proxy for the current modem object exposed by the |
| modem manager. |
| |
| @return A dbus.service.Object instance. |
| |
| """ |
| manager, modem_path = mm.PickOneModem('') |
| return manager.GetModem(modem_path) |
| |
| def modem_state(self): |
| """ |
| Gets the current modem state from the current modem manager. |
| |
| @return The modem state, as a uint32 value. |
| |
| """ |
| modem = self.modem() |
| props = modem.GetAll(mm1.I_MODEM) |
| return props['State'] |
| |
| def check_modem_state(self, expected_state, timeout=MODEM_STATE_TIMEOUT): |
| """ |
| Polls until the modem has the expected state within |timeout| seconds. |
| |
| @param expected_state: The modem state the modem is expected to be in. |
| @param timeout: The timeout interval for polling. |
| |
| @raises error.TestFail, if the modem doesn't transition to |
| |expected_state| within |timeout|. |
| |
| """ |
| site_utils.poll_for_condition( |
| lambda: self.modem_state() == expected_state, |
| exception=error.TestFail('Timed out waiting for modem state ' + |
| str(expected_state)), |
| timeout=timeout); |
| |
| def find_cellular_service(self): |
| """ |
| Searches for a cellular service and returns it. |
| |
| @return A dbus.service.Object instance. |
| @raises error.TestFail, if no cellular service is found. |
| |
| """ |
| service = self.flim.FindCellularService() |
| if not service: |
| raise error.TestFail('Could not find cellular service.') |
| return service |
| |
| def check_service_activation_state(self, expected_state): |
| """ |
| Waits until the current cellular service has the expected activation |
| state within ACTIVATION_STATE_TIMEOUT seconds. |
| |
| @param expected_state: The activation state the service is expected to |
| be in. |
| @raises error.TestFail, if no cellular service is found or the service |
| activation state doesn't match |expected_state| within timeout. |
| |
| """ |
| service = self.find_cellular_service() |
| state = self.flim.WaitForServiceState( |
| service=service, |
| expected_states=[expected_state], |
| timeout=ACTIVATION_STATE_TIMEOUT, |
| property_name='Cellular.ActivationState')[0] |
| if state != expected_state: |
| raise error.TestFail( |
| 'Service activation state should be \'%s\', but it is ' |
| '\'%s\'.' % (expected_state, state)) |
| |
| def run_once(self): |
| with backchannel.Backchannel(): |
| with pseudomodem.TestModemManagerContext(True, 'CDMA') as tmmc: |
| self.flim = flimflam.FlimFlam() |
| self.device_manager = flimflam.DeviceManager(self.flim) |
| self.flim.SetDebugTags( |
| 'dbus+service+device+modem+cellular+portal+network+' |
| 'manager+dhcp') |
| |
| tests = [ |
| ActivationStateTest(tmmc.GetPseudoModemManager(), self), |
| ActivationSuccessTest(tmmc.GetPseudoModemManager(), self), |
| ActivationFailureRetryTest( |
| tmmc.GetPseudoModemManager(), self) |
| ] |
| |
| with cell_tools.OtherDeviceShutdownContext('cellular'): |
| for test in tests: |
| test.run() |