blob: ca03a6d61ce016b45c42da549d803c87924597bf [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 Le98327a42014-08-21 18:11:41 -0700138 def _reset_modem(self):
139 modem_device = self.shill.find_cellular_device_object()
140 if not modem_device:
141 raise error.TestError('Cannot find cellular device in shill. '
142 'Is the modem plugged in?')
143 try:
144 # Cromo modems do not support being reset.
145 self.shill.reset_modem(modem_device, expect_service=False)
146 except dbus.DBusException as e:
147 if (e.get_dbus_name() !=
148 cellular_proxy.CellularProxy.ERROR_NOT_SUPPORTED):
149 raise
150
151
152 def _initialize_components(self):
153 """Get access to various test environment components. """
154 # CellularProxy.get_proxy() checks to see if shill is running and
155 # responding to DBus requests. It returns None if that's not the case.
156 self.shill = cellular_proxy.CellularProxy.get_proxy(self.bus)
157 if self.shill is None:
158 raise error.TestError('Cannot connect to shill, is shill running?')
159
160 # Keep this around to support older tests that haven't migrated to
161 # cellular_proxy.
162 self.flim = flimflam.FlimFlam()
163
Thieu Lee3b3fcf2014-09-08 13:56:15 -0700164 # Enable modem first so shill initializes the modemmanager proxies so
165 # we can call reset on it.
166 self._enable_modem()
167 self._reset_modem()
168
Thieu Le98327a42014-08-21 18:11:41 -0700169 # PickOneModem() makes sure there's a modem manager and that there is
170 # one and only one modem.
Thieu Le98327a42014-08-21 18:11:41 -0700171 self.modem_manager, modem_path = mm.PickOneModem('')
172 self.modem = self.modem_manager.GetModem(modem_path)
173 if self.modem is None:
174 raise error.TestError('Cannot get modem object at %s.' % modem_path)
175
176
177 def _setup_logging(self):
178 self.shill.set_logging_for_cellular_test()
179 self.modem_manager.SetDebugLogging()
180
181
182 def _verify_backchannel(self):
183 """Verify backchannel is on an ethernet device.
184
185 @raise error.TestError if backchannel is not on an ethernet device.
186
187 """
Thieu Le8bded2b2014-09-03 15:38:46 -0700188 if not backchannel.is_backchannel_using_ethernet():
189 raise error.TestError('An ethernet connection is required between '
190 'the test server and the device under test.')
Thieu Le98327a42014-08-21 18:11:41 -0700191
192
193 def _verify_sim(self):
194 """Verify SIM is valid.
195
196 @raise error.TestError if SIM does not exist or is invalid.
197
198 """
199 # TODO: Implement this (crbug.com/403155).
200 pass
201
202
203 def _wait_for_modem_registration(self):
204 """Wait for the modem to register with the network.
205
Thieu Le98327a42014-08-21 18:11:41 -0700206 @raise error.TestError if modem is not registered.
207
208 """
Thieu Lee3b3fcf2014-09-08 13:56:15 -0700209 utils.poll_for_condition(
210 self.modem.ModemIsRegistered,
211 exception=error.TestError(
212 'Modem failed to register with the network.'),
213 timeout=cellular_proxy.CellularProxy.SERVICE_REGISTRATION_TIMEOUT)
Thieu Le98327a42014-08-21 18:11:41 -0700214
215
216 def _verify_cellular_service(self):
217 """Make sure a cellular service exists.
218
219 The cellular service should not be connected to the network.
220
221 @raise error.TestError if cellular service does not exist or if
222 there are multiple cellular services.
223
224 """
225 service = self.shill.wait_for_cellular_service_object()
226
227 try:
228 service.Disconnect()
229 except dbus.DBusException as e:
230 if (e.get_dbus_name() !=
231 cellular_proxy.CellularProxy.ERROR_NOT_CONNECTED):
232 raise
Thieu Lee3b3fcf2014-09-08 13:56:15 -0700233 success, state, _ = self.shill.wait_for_property_in(
Thieu Le98327a42014-08-21 18:11:41 -0700234 service,
235 cellular_proxy.CellularProxy.SERVICE_PROPERTY_STATE,
236 ('idle',),
237 cellular_proxy.CellularProxy.SERVICE_DISCONNECT_TIMEOUT)
238 if not success:
239 raise error.TestError(
Thieu Lee3b3fcf2014-09-08 13:56:15 -0700240 'Cellular service needs to start in the "idle" state. '
241 'Current state is "%s". '
242 'Modem disconnect may have failed.' %
243 state)
Thieu Le98327a42014-08-21 18:11:41 -0700244
245
246class CellularOTATestEnvironment(CellularTestEnvironment):
247 """Setup and verify cellular over-the-air (OTA) test environment. """
248 def __init__(self, **kwargs):
249 super(CellularOTATestEnvironment, self).__init__(**kwargs)
250
251
252class CellularPseudoMMTestEnvironment(CellularTestEnvironment):
253 """Setup and verify cellular pseudomodem test environment. """
254 def __init__(self, pseudomm_args=None, **kwargs):
255 """
256 @param pseudomm_args: Tuple of arguments passed to the pseudomodem, see
257 pseudomodem_context.py for description of each argument in the
258 tuple: (flags_map, block_output, bus)
259
260 """
261 super(CellularPseudoMMTestEnvironment, self).__init__(**kwargs)
262 self._context_managers.append(
Thieu Le6724f282014-09-04 15:36:41 -0700263 pseudomodem_context.PseudoModemManagerContext(
264 True, bus=self.bus, *pseudomm_args))
Thieu Le98327a42014-08-21 18:11:41 -0700265
266
267class CellularWardModemTestEnvironment(CellularTestEnvironment):
268 """Setup and verify cellular ward modem test environment. """
269 def __init__(self, wardmodem_modem=None, **kwargs):
270 """
271 @param wardmodem_modem: Customized ward modem to use instead of the
272 default implementation, see wardmodem.py.
273
274 """
275 super(CellularWardModemTestEnvironment, self).__init__(**kwargs)
276 self._context_managers.append(
277 wardmodem.WardModemContext(args=['--modem', wardmodem_modem]))