普通文本  |  251行  |  8.56 KB

# 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.

import dbus
import dbus.types
import os
import time

from autotest_lib.client.bin import test
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.cros.cellular import mm1_constants
from autotest_lib.client.cros.cellular import test_environment
from autotest_lib.client.cros.networking import pm_proxy

I_ACTIVATION_TEST = 'Interface.CDMAActivationTest'
ACTIVATION_STATE_TIMEOUT = 10
MODEM_STATE_TIMEOUT = 10
TEST_MODEMS_MODULE_PATH = os.path.join(os.path.dirname(__file__), 'files',
                                       'modems.py')

class ActivationTest(object):
    """
    Super class that implements setup code that is common to the individual
    tests.

    """
    def __init__(self, test):
        self.test = test
        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.

        """
        self.pseudomm = pm_proxy.PseudoMMProxy.get_proxy()
        self._run_test()


    def _set_modem_activation_state(self, state):
        self.pseudomm.get_modem().iface_properties.Set(
                mm1_constants.I_MODEM_CDMA,
                'ActivationState',
                dbus.types.UInt32(state))


    def _get_modem_activation_state(self):
        modem = self.pseudomm.get_modem()
        return modem.properties(mm1_constants.I_MODEM_CDMA)['ActivationState']


    def pseudomodem_flags(self):
        """
        Subclasses must override this method to setup the flags map passed to
        pseudomodem to suite their needs.

        """
        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 pseudomodem_flags(self):
        return {'family' : 'CDMA'}


    def _run_test(self):
        self.test.reset_modem()

        # The modem state should be REGISTERED.
        self.test.check_modem_state(mm1_constants.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_constants.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_constants.MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING)
        self.test.check_service_activation_state('activating')

        # Service activation state should change to 'partially-activated'.
        st = mm1_constants.MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED
        self._set_modem_activation_state(st)
        self.test.check_service_activation_state('partially-activated')

        # Service activation state should change to 'activated'.
        self._set_modem_activation_state(
                mm1_constants.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 pseudomodem_flags(self):
        return {'test-module' : TEST_MODEMS_MODULE_PATH,
                'test-modem-class' : 'UnactivatedCdmaModem'}


    def _run_test(self):
        self.test.reset_modem()

        # The modem state should be REGISTERED.
        self.test.check_modem_state(mm1_constants.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.test_env.shill.find_cellular_service_object()
        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 pseudomodem_flags(self):
        return {'test-module' : TEST_MODEMS_MODULE_PATH,
                'test-modem-class' : 'ActivationRetryModem',
                'test-modem-arg' : [self.NUM_ACTIVATE_RETRIES]}


    def _run_test(self):
        self.test.reset_modem()

        # The modem state should be REGISTERED.
        self.test.check_modem_state(mm1_constants.MM_MODEM_STATE_REGISTERED)

        # Service should appear as 'not-activated'.
        self.test.check_service_activation_state('not-activated')

        # Call 'CompleteActivation' on the service.
        service = self.test.test_env.shill.find_cellular_service_object()
        service.CompleteCellularActivation()

        # Wait for shill to retry the failed activations, except the last retry
        # will succeed.
        # NOTE: Don't check for transitory service activation states while this
        # is happening because shill will reset the modem once the activation
        # succeeds which will cause the existing service to get deleted.
        modem = self.pseudomm.get_modem()
        utils.poll_for_condition(
                lambda: (modem.properties(I_ACTIVATION_TEST)['ActivateCount'] ==
                         self.NUM_ACTIVATE_RETRIES),
                exception=error.TestFail(
                        'Shill did not retry failed activation'),
                timeout=10)

        # 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 cellular_ActivateCDMA(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 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 pm_proxy.ModemManager1ProxyError if the modem doesn't
                transition to |expected_state| within |timeout|.

        """
        modem = pm_proxy.PseudoMMProxy.get_proxy().get_modem()
        modem.wait_for_states([expected_state], timeout_seconds=timeout)


    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.

        """
        success, state, _ = self.test_env.shill.wait_for_property_in(
                self.test_env.shill.find_cellular_service_object(),
                'Cellular.ActivationState',
                [expected_state],
                ACTIVATION_STATE_TIMEOUT)
        if not success:
            raise error.TestFail(
                    'Service activation state should be \'%s\', but it is '
                    '\'%s\'.' % (expected_state, state))


    def reset_modem(self):
        """
        Resets the one and only modem in the DUT.

        """
        modem = self.test_env.shill.find_cellular_device_object()
        self.test_env.shill.reset_modem(modem)


    def run_once(self):
        tests = [
            ActivationStateTest(self),
            ActivationSuccessTest(self),
            ActivationFailureRetryTest(self)
        ]

        for test in tests:
            self.test_env = test_environment.CellularPseudoMMTestEnvironment(
                    pseudomm_args=(test.pseudomodem_flags(),))
            with self.test_env:
                test.run()