blob: 9340c6136527f131abc8e4babc02649c0cd63f77 [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
12from autotest_lib.client.common_lib import error
13from autotest_lib.client.cros import backchannel
14from autotest_lib.client.cros.cellular import cell_tools
15from autotest_lib.client.cros.cellular import mm
16from autotest_lib.client.cros.cellular.pseudomodem import pseudomodem_context
17from autotest_lib.client.cros.cellular.wardmodem import wardmodem
18from autotest_lib.client.cros.networking import cellular_proxy
19
20# Import 'flimflam_test_path' first in order to import flimflam.
21# pylint: disable=W0611
22from autotest_lib.client.cros import flimflam_test_path
23import flimflam
24
25class CellularTestEnvironment(object):
26 """Setup and verify cellular test environment.
27
28 This context manager configures the following:
29 - Sets up backchannel.
30 - Shuts down other devices except cellular.
31 - Shill and MM logging is enabled appropriately for cellular.
32 - Initializes members that tests should use to access test environment
33 (eg. |shill|, |flimflam|, |modem_manager|, |modem|).
34
35 Then it verifies the following is valid:
36 - The backchannel is using an Ethernet device.
37 - The SIM is inserted and valid.
38 - There is one and only one modem in the device.
39 - The modem is registered to the network.
40 - There is a cellular service in shill and it's not connected.
41
42 Don't use this base class directly, use the appropriate subclass.
43
44 Setup for over-the-air tests:
45 with CellularOTATestEnvironment() as test_env:
46 # Test body
47
48 Setup for pseudomodem tests:
49 with CellularPseudoMMTestEnvironment(
50 pseudomm_args=({'family': '3GPP'})) as test_env:
51 # Test body
52
53 Setup for wardmodem tests:
54 with CellularWardModemTestEnvironment(
55 wardmodem_modem='e362') as test_env:
56 # Test body
57
58 """
59
60 def __init__(self, use_backchannel=True, shutdown_other_devices=True):
61 """
62 @param use_backchannel: Set up the backchannel that can be used to
63 communicate with the DUT.
64 @param shutdown_other_devices: If True, shutdown all devices except
65 cellular.
66
67 """
68 # Tests should use this main loop instead of creating their own.
69 self.mainloop = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
70 self.bus = dbus.SystemBus(mainloop=self.mainloop)
71
72 self.shill = None
73 self.flim = None # Only use this for legacy tests.
74 self.modem_manager = None
75 self.modem = None
76
77 self._context_managers = []
78 if use_backchannel:
79 self._context_managers.append(backchannel.Backchannel())
80 if shutdown_other_devices:
81 self._context_managers.append(
82 cell_tools.OtherDeviceShutdownContext('cellular'))
83
84
85 def __enter__(self):
86 try:
87 self._nested = contextlib.nested(*self._context_managers)
88 self._nested.__enter__()
89
90 self._initialize_components()
91 self._setup_logging()
92
93 self._verify_backchannel()
94 self._verify_sim()
95 self._wait_for_modem_registration()
96 self._verify_cellular_service()
97
98 return self
99 except (error.TestError, dbus.DBusException) as e:
100 except_type, except_value, except_traceback = sys.exc_info()
101 lines = traceback.format_exception(except_type, except_value,
102 except_traceback)
103 logging.error('Error during test initialization:\n' +
104 ''.join(lines))
105 self.__exit__(*sys.exc_info())
106 raise error.TestError('INIT_ERROR: %s' % str(e))
107
108
109 def __exit__(self, exception, value, traceback):
110 return self._nested.__exit__(exception, value, traceback)
111
112
113 def _reset_modem(self):
114 modem_device = self.shill.find_cellular_device_object()
115 if not modem_device:
116 raise error.TestError('Cannot find cellular device in shill. '
117 'Is the modem plugged in?')
118 try:
119 # Cromo modems do not support being reset.
120 self.shill.reset_modem(modem_device, expect_service=False)
121 except dbus.DBusException as e:
122 if (e.get_dbus_name() !=
123 cellular_proxy.CellularProxy.ERROR_NOT_SUPPORTED):
124 raise
125
126
127 def _initialize_components(self):
128 """Get access to various test environment components. """
129 # CellularProxy.get_proxy() checks to see if shill is running and
130 # responding to DBus requests. It returns None if that's not the case.
131 self.shill = cellular_proxy.CellularProxy.get_proxy(self.bus)
132 if self.shill is None:
133 raise error.TestError('Cannot connect to shill, is shill running?')
134
135 # Keep this around to support older tests that haven't migrated to
136 # cellular_proxy.
137 self.flim = flimflam.FlimFlam()
138
139 # PickOneModem() makes sure there's a modem manager and that there is
140 # one and only one modem.
141 self._reset_modem()
142 self.modem_manager, modem_path = mm.PickOneModem('')
143 self.modem = self.modem_manager.GetModem(modem_path)
144 if self.modem is None:
145 raise error.TestError('Cannot get modem object at %s.' % modem_path)
146
147
148 def _setup_logging(self):
149 self.shill.set_logging_for_cellular_test()
150 self.modem_manager.SetDebugLogging()
151
152
153 def _verify_backchannel(self):
154 """Verify backchannel is on an ethernet device.
155
156 @raise error.TestError if backchannel is not on an ethernet device.
157
158 """
159 # TODO: Implement this (crbug.com/403168).
160 pass
161
162
163 def _verify_sim(self):
164 """Verify SIM is valid.
165
166 @raise error.TestError if SIM does not exist or is invalid.
167
168 """
169 # TODO: Implement this (crbug.com/403155).
170 pass
171
172
173 def _wait_for_modem_registration(self):
174 """Wait for the modem to register with the network.
175
176 The modem should be enabled and registered with the network.
177
178 @raise error.TestError if modem is not registered.
179
180 """
181 # TODO: Implement this (crbug.com/403160).
182 pass
183
184
185 def _verify_cellular_service(self):
186 """Make sure a cellular service exists.
187
188 The cellular service should not be connected to the network.
189
190 @raise error.TestError if cellular service does not exist or if
191 there are multiple cellular services.
192
193 """
194 service = self.shill.wait_for_cellular_service_object()
195
196 try:
197 service.Disconnect()
198 except dbus.DBusException as e:
199 if (e.get_dbus_name() !=
200 cellular_proxy.CellularProxy.ERROR_NOT_CONNECTED):
201 raise
202 success, _, _ = self.shill.wait_for_property_in(
203 service,
204 cellular_proxy.CellularProxy.SERVICE_PROPERTY_STATE,
205 ('idle',),
206 cellular_proxy.CellularProxy.SERVICE_DISCONNECT_TIMEOUT)
207 if not success:
208 raise error.TestError(
209 'Cellular service needs to start in the idle state. '
210 'Modem disconnect may have failed.')
211
212
213class CellularOTATestEnvironment(CellularTestEnvironment):
214 """Setup and verify cellular over-the-air (OTA) test environment. """
215 def __init__(self, **kwargs):
216 super(CellularOTATestEnvironment, self).__init__(**kwargs)
217
218
219class CellularPseudoMMTestEnvironment(CellularTestEnvironment):
220 """Setup and verify cellular pseudomodem test environment. """
221 def __init__(self, pseudomm_args=None, **kwargs):
222 """
223 @param pseudomm_args: Tuple of arguments passed to the pseudomodem, see
224 pseudomodem_context.py for description of each argument in the
225 tuple: (flags_map, block_output, bus)
226
227 """
228 super(CellularPseudoMMTestEnvironment, self).__init__(**kwargs)
229 self._context_managers.append(
230 pseudomodem_context.PseudoModemManagerContext(*pseudomm_args))
231
232
233class CellularWardModemTestEnvironment(CellularTestEnvironment):
234 """Setup and verify cellular ward modem test environment. """
235 def __init__(self, wardmodem_modem=None, **kwargs):
236 """
237 @param wardmodem_modem: Customized ward modem to use instead of the
238 default implementation, see wardmodem.py.
239
240 """
241 super(CellularWardModemTestEnvironment, self).__init__(**kwargs)
242 self._context_managers.append(
243 wardmodem.WardModemContext(args=['--modem', wardmodem_modem]))