blob: 2cf504d30b4e7ccfb54f2981b08bbbab8ec68b2d [file] [log] [blame]
Thieu Le98327a42014-08-21 18:11:41 -07001# 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
5import contextlib
6import dbus
7import logging
8import sys
9import traceback
10
11import common
Thieu Lee3b3fcf2014-09-08 13:56:15 -070012from autotest_lib.client.bin import utils
Thieu Le98327a42014-08-21 18:11:41 -070013from autotest_lib.client.common_lib import error
14from autotest_lib.client.cros import backchannel
15from autotest_lib.client.cros.cellular import cell_tools
16from autotest_lib.client.cros.cellular import mm
17from autotest_lib.client.cros.cellular.pseudomodem import pseudomodem_context
18from autotest_lib.client.cros.cellular.wardmodem import wardmodem
19from autotest_lib.client.cros.networking import cellular_proxy
Thieu Le5fe5f512014-09-03 12:52:10 -070020from autotest_lib.client.cros.networking import shill_proxy
Thieu Le98327a42014-08-21 18:11:41 -070021
22# Import 'flimflam_test_path' first in order to import flimflam.
23# pylint: disable=W0611
24from autotest_lib.client.cros import flimflam_test_path
25import flimflam
26
27class CellularTestEnvironment(object):
28 """Setup and verify cellular test environment.
29
30 This context manager configures the following:
31 - Sets up backchannel.
32 - Shuts down other devices except cellular.
33 - Shill and MM logging is enabled appropriately for cellular.
34 - Initializes members that tests should use to access test environment
35 (eg. |shill|, |flimflam|, |modem_manager|, |modem|).
36
37 Then it verifies the following is valid:
38 - The backchannel is using an Ethernet device.
39 - The SIM is inserted and valid.
40 - There is one and only one modem in the device.
41 - The modem is registered to the network.
42 - There is a cellular service in shill and it's not connected.
43
44 Don't use this base class directly, use the appropriate subclass.
45
46 Setup for over-the-air tests:
47 with CellularOTATestEnvironment() as test_env:
48 # Test body
49
50 Setup for pseudomodem tests:
51 with CellularPseudoMMTestEnvironment(
52 pseudomm_args=({'family': '3GPP'})) as test_env:
53 # Test body
54
55 Setup for wardmodem tests:
56 with CellularWardModemTestEnvironment(
57 wardmodem_modem='e362') as test_env:
58 # Test body
59
60 """
61
62 def __init__(self, use_backchannel=True, shutdown_other_devices=True):
63 """
64 @param use_backchannel: Set up the backchannel that can be used to
65 communicate with the DUT.
66 @param shutdown_other_devices: If True, shutdown all devices except
67 cellular.
68
69 """
70 # Tests should use this main loop instead of creating their own.
71 self.mainloop = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
72 self.bus = dbus.SystemBus(mainloop=self.mainloop)
73
74 self.shill = None
75 self.flim = None # Only use this for legacy tests.
76 self.modem_manager = None
77 self.modem = None
78
79 self._context_managers = []
80 if use_backchannel:
81 self._context_managers.append(backchannel.Backchannel())
82 if shutdown_other_devices:
83 self._context_managers.append(
84 cell_tools.OtherDeviceShutdownContext('cellular'))
85
86
87 def __enter__(self):
88 try:
89 self._nested = contextlib.nested(*self._context_managers)
90 self._nested.__enter__()
91
92 self._initialize_components()
93 self._setup_logging()
94
95 self._verify_backchannel()
96 self._verify_sim()
97 self._wait_for_modem_registration()
98 self._verify_cellular_service()
99
100 return self
Thieu Le5fe5f512014-09-03 12:52:10 -0700101 except (error.TestError, dbus.DBusException,
102 shill_proxy.ShillProxyError) as e:
Thieu Le98327a42014-08-21 18:11:41 -0700103 except_type, except_value, except_traceback = sys.exc_info()
104 lines = traceback.format_exception(except_type, except_value,
105 except_traceback)
106 logging.error('Error during test initialization:\n' +
107 ''.join(lines))
108 self.__exit__(*sys.exc_info())
109 raise error.TestError('INIT_ERROR: %s' % str(e))
Thieu Le5fe5f512014-09-03 12:52:10 -0700110 except:
111 self.__exit__(*sys.exc_info())
112 raise
Thieu Le98327a42014-08-21 18:11:41 -0700113
114
115 def __exit__(self, exception, value, traceback):
116 return self._nested.__exit__(exception, value, traceback)
117
118
Thieu Lee3b3fcf2014-09-08 13:56:15 -0700119 def _enable_modem(self):
120 modem_device = self.shill.find_cellular_device_object()
121 if not modem_device:
122 raise error.TestError('Cannot find cellular device in shill. '
123 'Is the modem plugged in?')
124 try:
125 modem_device.Enable()
126 except dbus.DBusException as e:
127 if (e.get_dbus_name() !=
128 shill_proxy.ShillProxy.ERROR_IN_PROGRESS):
129 raise
130
131 utils.poll_for_condition(
132 lambda: modem_device.GetProperties()['Powered'],
133 exception=error.TestError(
134 'Failed to enable modem.'),
135 timeout=shill_proxy.ShillProxy.DEVICE_ENABLE_DISABLE_TIMEOUT)
136
137
Thieu Lea2aeab32014-09-15 14:29:43 -0700138 def _is_unsupported_error(self, e):
139 return (e.get_dbus_name() ==
140 shill_proxy.ShillProxy.ERROR_NOT_SUPPORTED or
141 (e.get_dbus_name() ==
142 shill_proxy.ShillProxy.ERROR_FAILURE and
143 'operation not supported' in e.get_dbus_message()))
144
Thieu Le98327a42014-08-21 18:11:41 -0700145 def _reset_modem(self):
146 modem_device = self.shill.find_cellular_device_object()
147 if not modem_device:
148 raise error.TestError('Cannot find cellular device in shill. '
149 'Is the modem plugged in?')
150 try:
Thieu Lea2aeab32014-09-15 14:29:43 -0700151 # Cromo/MBIM modems do not support being reset.
Thieu Le98327a42014-08-21 18:11:41 -0700152 self.shill.reset_modem(modem_device, expect_service=False)
153 except dbus.DBusException as e:
Thieu Lea2aeab32014-09-15 14:29:43 -0700154 if not self._is_unsupported_error(e):
Thieu Le98327a42014-08-21 18:11:41 -0700155 raise
156
157
158 def _initialize_components(self):
159 """Get access to various test environment components. """
160 # CellularProxy.get_proxy() checks to see if shill is running and
161 # responding to DBus requests. It returns None if that's not the case.
162 self.shill = cellular_proxy.CellularProxy.get_proxy(self.bus)
163 if self.shill is None:
164 raise error.TestError('Cannot connect to shill, is shill running?')
165
166 # Keep this around to support older tests that haven't migrated to
167 # cellular_proxy.
168 self.flim = flimflam.FlimFlam()
169
Thieu Lee3b3fcf2014-09-08 13:56:15 -0700170 # Enable modem first so shill initializes the modemmanager proxies so
171 # we can call reset on it.
172 self._enable_modem()
173 self._reset_modem()
174
Thieu Le98327a42014-08-21 18:11:41 -0700175 # PickOneModem() makes sure there's a modem manager and that there is
176 # one and only one modem.
Thieu Le98327a42014-08-21 18:11:41 -0700177 self.modem_manager, modem_path = mm.PickOneModem('')
178 self.modem = self.modem_manager.GetModem(modem_path)
179 if self.modem is None:
180 raise error.TestError('Cannot get modem object at %s.' % modem_path)
181
182
183 def _setup_logging(self):
184 self.shill.set_logging_for_cellular_test()
185 self.modem_manager.SetDebugLogging()
186
187
188 def _verify_backchannel(self):
189 """Verify backchannel is on an ethernet device.
190
191 @raise error.TestError if backchannel is not on an ethernet device.
192
193 """
Thieu Le8bded2b2014-09-03 15:38:46 -0700194 if not backchannel.is_backchannel_using_ethernet():
195 raise error.TestError('An ethernet connection is required between '
196 'the test server and the device under test.')
Thieu Le98327a42014-08-21 18:11:41 -0700197
198
199 def _verify_sim(self):
200 """Verify SIM is valid.
201
202 @raise error.TestError if SIM does not exist or is invalid.
203
204 """
205 # TODO: Implement this (crbug.com/403155).
206 pass
207
208
209 def _wait_for_modem_registration(self):
210 """Wait for the modem to register with the network.
211
Thieu Le98327a42014-08-21 18:11:41 -0700212 @raise error.TestError if modem is not registered.
213
214 """
Thieu Lee3b3fcf2014-09-08 13:56:15 -0700215 utils.poll_for_condition(
216 self.modem.ModemIsRegistered,
217 exception=error.TestError(
218 'Modem failed to register with the network.'),
219 timeout=cellular_proxy.CellularProxy.SERVICE_REGISTRATION_TIMEOUT)
Thieu Le98327a42014-08-21 18:11:41 -0700220
221
222 def _verify_cellular_service(self):
223 """Make sure a cellular service exists.
224
225 The cellular service should not be connected to the network.
226
227 @raise error.TestError if cellular service does not exist or if
228 there are multiple cellular services.
229
230 """
231 service = self.shill.wait_for_cellular_service_object()
232
233 try:
234 service.Disconnect()
235 except dbus.DBusException as e:
236 if (e.get_dbus_name() !=
237 cellular_proxy.CellularProxy.ERROR_NOT_CONNECTED):
238 raise
Thieu Lee3b3fcf2014-09-08 13:56:15 -0700239 success, state, _ = self.shill.wait_for_property_in(
Thieu Le98327a42014-08-21 18:11:41 -0700240 service,
241 cellular_proxy.CellularProxy.SERVICE_PROPERTY_STATE,
242 ('idle',),
243 cellular_proxy.CellularProxy.SERVICE_DISCONNECT_TIMEOUT)
244 if not success:
245 raise error.TestError(
Thieu Lee3b3fcf2014-09-08 13:56:15 -0700246 'Cellular service needs to start in the "idle" state. '
247 'Current state is "%s". '
248 'Modem disconnect may have failed.' %
249 state)
Thieu Le98327a42014-08-21 18:11:41 -0700250
251
252class CellularOTATestEnvironment(CellularTestEnvironment):
253 """Setup and verify cellular over-the-air (OTA) test environment. """
254 def __init__(self, **kwargs):
255 super(CellularOTATestEnvironment, self).__init__(**kwargs)
256
257
258class CellularPseudoMMTestEnvironment(CellularTestEnvironment):
259 """Setup and verify cellular pseudomodem test environment. """
260 def __init__(self, pseudomm_args=None, **kwargs):
261 """
262 @param pseudomm_args: Tuple of arguments passed to the pseudomodem, see
263 pseudomodem_context.py for description of each argument in the
264 tuple: (flags_map, block_output, bus)
265
266 """
267 super(CellularPseudoMMTestEnvironment, self).__init__(**kwargs)
268 self._context_managers.append(
Thieu Le6724f282014-09-04 15:36:41 -0700269 pseudomodem_context.PseudoModemManagerContext(
270 True, bus=self.bus, *pseudomm_args))
Thieu Le98327a42014-08-21 18:11:41 -0700271
272
273class CellularWardModemTestEnvironment(CellularTestEnvironment):
274 """Setup and verify cellular ward modem test environment. """
275 def __init__(self, wardmodem_modem=None, **kwargs):
276 """
277 @param wardmodem_modem: Customized ward modem to use instead of the
278 default implementation, see wardmodem.py.
279
280 """
281 super(CellularWardModemTestEnvironment, self).__init__(**kwargs)
282 self._context_managers.append(
283 wardmodem.WardModemContext(args=['--modem', wardmodem_modem]))