1# Copyright (c) 2012 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
5import dbus
6import logging
7
8from autotest_lib.client.bin import test
9from autotest_lib.client.common_lib import error
10from autotest_lib.client.cros.cellular.pseudomodem import modem_3gpp
11from autotest_lib.client.cros.cellular.pseudomodem import modem_cdma
12from autotest_lib.client.cros.cellular.pseudomodem import pm_errors
13from autotest_lib.client.cros.cellular.pseudomodem import utils as pm_utils
14from autotest_lib.client.cros.networking import cellular_proxy
15from autotest_lib.client.cros.networking import shill_proxy
16
17
18def _GetModemSuperClass(family):
19    """
20    Obtains the correct Modem base class to use for the given family.
21
22    @param family: The modem family. Should be one of |3GPP|/|CDMA|.
23    @returns: The relevant Modem base class.
24    @raises error.TestError, if |family| is not one of '3GPP' or 'CDMA'.
25
26    """
27    if family == '3GPP':
28        return modem_3gpp.Modem3gpp
29    elif family == 'CDMA':
30        return modem_cdma.ModemCdma
31    else:
32        raise error.TestError('Invalid pseudomodem family: %s', family)
33
34
35def GetFailConnectModem(family):
36    """
37    Returns the correct modem subclass based on |family|.
38
39    @param family: A string containing either '3GPP' or 'CDMA'.
40
41    """
42    modem_class = _GetModemSuperClass(family)
43
44    class FailConnectModem(modem_class):
45        """Custom fake Modem that always fails to connect."""
46        @pm_utils.log_dbus_method(return_cb_arg='return_cb',
47                                  raise_cb_arg='raise_cb')
48        def Connect(self, properties, return_cb, raise_cb):
49            logging.info('Connect call will fail.')
50            raise_cb(pm_errors.MMCoreError(pm_errors.MMCoreError.FAILED))
51
52    return FailConnectModem()
53
54
55class network_3GFailedConnect(test.test):
56    """
57    Tests that 3G connect failures are handled by shill properly.
58
59    This test will fail if a connect failure does not immediately cause the
60    service to enter the Failed state.
61
62    """
63    version = 1
64
65    def _connect_to_3g_network(self, config_timeout):
66        """
67        Attempts to connect to a 3G network using shill.
68
69        @param config_timeout: Timeout (in seconds) before giving up on
70                               connect.
71
72        @raises: error.TestFail if connection fails.
73
74        """
75        service = self.test_env.shill.find_cellular_service_object()
76
77        try:
78            service.Connect()
79        except dbus.DBusException as e:
80            logging.info('Expected error: %s', e)
81
82        _, state, _ = self.test_env.shill.wait_for_property_in(
83                service,
84                shill_proxy.ShillProxy.SERVICE_PROPERTY_STATE,
85                ('ready', 'portal', 'online', 'failure'),
86                config_timeout)
87
88        if state != 'failure':
89            raise error.TestFail('Service state should be failure not %s' %
90                                 state)
91
92
93    def run_once(self, test_env, connect_count=4):
94        with test_env:
95            self.test_env = test_env
96            for count in xrange(connect_count):
97                logging.info('Connect attempt %d', count + 1)
98                self._connect_to_3g_network(config_timeout=
99                        cellular_proxy.CellularProxy.SERVICE_CONNECT_TIMEOUT)
100