Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: build/android/pylib/remote/device/remote_device_environment.py

Issue 1415533007: [Android] Add sharding for AMP instrumentation tests. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Environment setup and teardown for remote devices.""" 5 """Environment setup and teardown for remote devices."""
6 6
7 import distutils.version 7 import distutils.version
8 import json 8 import json
9 import logging 9 import logging
10 import os 10 import os
11 import random
12 import sys 11 import sys
13 12
14 from devil.utils import reraiser_thread 13 from devil.utils import reraiser_thread
15 from devil.utils import timeout_retry 14 from devil.utils import timeout_retry
16 from pylib.base import environment 15 from pylib.base import environment
16 from pylib.remote.device import appurify_constants
17 from pylib.remote.device import appurify_sanitized 17 from pylib.remote.device import appurify_sanitized
18 from pylib.remote.device import remote_device_helper 18 from pylib.remote.device import remote_device_helper
19 19
20 class RemoteDeviceEnvironment(environment.Environment): 20 class RemoteDeviceEnvironment(environment.Environment):
21 """An environment for running on remote devices.""" 21 """An environment for running on remote devices."""
22 22
23 _ENV_KEY = 'env'
24 _DEVICE_KEY = 'device'
25 _DEFAULT_RETRIES = 0 23 _DEFAULT_RETRIES = 0
24 _DEFAULT_SHARD_COUNT = 6
26 25
27 def __init__(self, args, error_func): 26 def __init__(self, args, error_func):
28 """Constructor. 27 """Constructor.
29 28
30 Args: 29 Args:
31 args: Command line arguments. 30 args: Command line arguments.
32 error_func: error to show when using bad command line arguments. 31 error_func: error to show when using bad command line arguments.
33 """ 32 """
34 super(RemoteDeviceEnvironment, self).__init__() 33 super(RemoteDeviceEnvironment, self).__init__()
35 self._access_token = None 34 self._access_token = None
36 self._device = None 35 self._devices = []
37 self._device_type = args.device_type 36 self._device_type = args.device_type
38 self._verbose_count = args.verbose_count 37 self._verbose_count = args.verbose_count
39 self._timeouts = { 38 self._timeouts = {
40 'queueing': 60 * 10, 39 'queueing': 60 * 10,
41 'installing': 60 * 10, 40 'installing': 60 * 10,
42 'in-progress': 60 * 30, 41 'in-progress': 60 * 30,
43 'unknown': 60 * 5 42 'unknown': 60 * 5,
44 } 43 }
45 # Example config file: 44 # Example config file:
46 # { 45 # {
47 # "remote_device": ["Galaxy S4", "Galaxy S3"], 46 # "remote_device": ["Galaxy S4", "Galaxy S3"],
48 # "remote_device_os": ["4.4.2", "4.4.4"], 47 # "remote_device_os": ["4.4.2", "4.4.4"],
49 # "remote_device_minimum_os": "4.4.2", 48 # "remote_device_minimum_os": "4.4.2",
50 # "api_address": "www.example.com", 49 # "api_address": "www.example.com",
51 # "api_port": "80", 50 # "api_port": "80",
52 # "api_protocol": "http", 51 # "api_protocol": "http",
53 # "api_secret": "apisecret", 52 # "api_secret": "apisecret",
(...skipping 12 matching lines...) Expand all
66 device_json = {} 65 device_json = {}
67 66
68 self._api_address = device_json.get('api_address', None) 67 self._api_address = device_json.get('api_address', None)
69 self._api_key = device_json.get('api_key', None) 68 self._api_key = device_json.get('api_key', None)
70 self._api_port = device_json.get('api_port', None) 69 self._api_port = device_json.get('api_port', None)
71 self._api_protocol = device_json.get('api_protocol', None) 70 self._api_protocol = device_json.get('api_protocol', None)
72 self._api_secret = device_json.get('api_secret', None) 71 self._api_secret = device_json.get('api_secret', None)
73 self._device_oem = device_json.get('device_oem', None) 72 self._device_oem = device_json.get('device_oem', None)
74 self._device_type = device_json.get('device_type', 'Android') 73 self._device_type = device_json.get('device_type', 'Android')
75 self._network_config = device_json.get('network_config', None) 74 self._network_config = device_json.get('network_config', None)
75 self._num_shards = device_json.get('num_shards', None)
76 self._pcap_config = device_json.get('pcap_config', 0)
77 self._profiler_config = device_json.get('profiler_config', 0)
76 self._remote_device = device_json.get('remote_device', None) 78 self._remote_device = device_json.get('remote_device', None)
77 self._remote_device_minimum_os = device_json.get( 79 self._remote_device_minimum_os = device_json.get(
78 'remote_device_minimum_os', None) 80 'remote_device_minimum_os', None)
79 self._remote_device_os = device_json.get('remote_device_os', None) 81 self._remote_device_os = device_json.get('remote_device_os', None)
80 self._remote_device_timeout = device_json.get( 82 self._remote_device_timeout = device_json.get(
81 'remote_device_timeout', None) 83 'remote_device_timeout', None)
82 self._results_path = device_json.get('results_path', None) 84 self._results_dir = device_json.get('results_dir', None)
83 self._runner_package = device_json.get('runner_package', None) 85 self._runner_package = device_json.get('runner_package', None)
84 self._runner_type = device_json.get('runner_type', None) 86 self._test_framework = device_json.get('test_framework', None)
85 self._timeouts.update(device_json.get('timeouts', {})) 87 self._timeouts.update(device_json.get('timeouts', {}))
88 self._videocapture_config = device_json.get('videocapture_config', 0)
86 89
87 def command_line_override( 90 def command_line_override(
88 file_value, cmd_line_value, desc, print_value=True): 91 file_value, cmd_line_value, desc, print_value=True):
89 if cmd_line_value: 92 if cmd_line_value:
90 if file_value and file_value != cmd_line_value: 93 if file_value and file_value != cmd_line_value:
91 if print_value: 94 if print_value:
92 logging.info('Overriding %s from %s to %s', 95 logging.info('Overriding %s from %s to %s',
93 desc, file_value, cmd_line_value) 96 desc, file_value, cmd_line_value)
94 else: 97 else:
95 logging.info('overriding %s', desc) 98 logging.info('overriding %s', desc)
96 return cmd_line_value 99 return cmd_line_value
97 return file_value 100 return file_value
98 101
99 self._api_address = command_line_override( 102 self._api_address = command_line_override(
100 self._api_address, args.api_address, 'api_address') 103 self._api_address, args.api_address, 'api_address')
101 self._api_port = command_line_override( 104 self._api_port = command_line_override(
102 self._api_port, args.api_port, 'api_port') 105 self._api_port, args.api_port, 'api_port')
103 self._api_protocol = command_line_override( 106 self._api_protocol = command_line_override(
104 self._api_protocol, args.api_protocol, 'api_protocol') 107 self._api_protocol, args.api_protocol, 'api_protocol')
105 self._device_oem = command_line_override( 108 self._device_oem = command_line_override(
106 self._device_oem, args.device_oem, 'device_oem') 109 self._device_oem, args.device_oem, 'device_oem')
107 self._device_type = command_line_override( 110 self._device_type = command_line_override(
108 self._device_type, args.device_type, 'device_type') 111 self._device_type, args.device_type, 'device_type')
109 self._network_config = command_line_override( 112 self._network_config = command_line_override(
110 self._network_config, args.network_config, 'network_config') 113 self._network_config, args.network_config, 'network_config')
114 self._num_shards = command_line_override(
115 self._num_shards, args.num_shards, 'num_shards')
111 self._remote_device = command_line_override( 116 self._remote_device = command_line_override(
112 self._remote_device, args.remote_device, 'remote_device') 117 self._remote_device, args.remote_device, 'remote_device')
113 self._remote_device_minimum_os = command_line_override( 118 self._remote_device_minimum_os = command_line_override(
114 self._remote_device_minimum_os, args.remote_device_minimum_os, 119 self._remote_device_minimum_os, args.remote_device_minimum_os,
115 'remote_device_minimum_os') 120 'remote_device_minimum_os')
116 self._remote_device_os = command_line_override( 121 self._remote_device_os = command_line_override(
117 self._remote_device_os, args.remote_device_os, 'remote_device_os') 122 self._remote_device_os, args.remote_device_os, 'remote_device_os')
118 self._remote_device_timeout = command_line_override( 123 self._remote_device_timeout = command_line_override(
119 self._remote_device_timeout, args.remote_device_timeout, 124 self._remote_device_timeout, args.remote_device_timeout,
120 'remote_device_timeout') 125 'remote_device_timeout')
121 self._results_path = command_line_override( 126 self._results_dir = command_line_override(
122 self._results_path, args.results_path, 'results_path') 127 self._results_dir, args.results_dir, 'results_dir')
123 self._runner_package = command_line_override( 128 self._runner_package = command_line_override(
124 self._runner_package, args.runner_package, 'runner_package') 129 self._runner_package, args.runner_package, 'runner_package')
125 self._runner_type = command_line_override(
126 self._runner_type, args.runner_type, 'runner_type')
127 self._timeouts["in-progress"] = command_line_override( 130 self._timeouts["in-progress"] = command_line_override(
128 self._timeouts["in-progress"], args.test_timeout, 'test_timeout') 131 self._timeouts["in-progress"], args.test_timeout, 'test_timeout')
132 self._test_framework = command_line_override(
133 self._test_framework, args.test_framework, 'test_framework')
129 134
130 if args.api_key_file: 135 if args.api_key_file:
131 with open(args.api_key_file) as api_key_file: 136 with open(args.api_key_file) as api_key_file:
132 temp_key = api_key_file.read().strip() 137 temp_key = api_key_file.read().strip()
133 self._api_key = command_line_override( 138 self._api_key = command_line_override(
134 self._api_key, temp_key, 'api_key', print_value=False) 139 self._api_key, temp_key, 'api_key', print_value=False)
135 self._api_key = command_line_override( 140 self._api_key = command_line_override(
136 self._api_key, args.api_key, 'api_key', print_value=False) 141 self._api_key, args.api_key, 'api_key', print_value=False)
137 142
138 if args.api_secret_file: 143 if args.api_secret_file:
(...skipping 23 matching lines...) Expand all
162 logging.info('Api address: %s', self._api_address) 167 logging.info('Api address: %s', self._api_address)
163 logging.info('Api port: %s', self._api_port) 168 logging.info('Api port: %s', self._api_port)
164 logging.info('Api protocol: %s', self._api_protocol) 169 logging.info('Api protocol: %s', self._api_protocol)
165 logging.info('Remote device: %s', self._remote_device) 170 logging.info('Remote device: %s', self._remote_device)
166 logging.info('Remote device minimum OS: %s', 171 logging.info('Remote device minimum OS: %s',
167 self._remote_device_minimum_os) 172 self._remote_device_minimum_os)
168 logging.info('Remote device OS: %s', self._remote_device_os) 173 logging.info('Remote device OS: %s', self._remote_device_os)
169 logging.info('Remote device OEM: %s', self._device_oem) 174 logging.info('Remote device OEM: %s', self._device_oem)
170 logging.info('Remote device type: %s', self._device_type) 175 logging.info('Remote device type: %s', self._device_type)
171 logging.info('Remote device timout: %s', self._remote_device_timeout) 176 logging.info('Remote device timout: %s', self._remote_device_timeout)
172 logging.info('Results Path: %s', self._results_path) 177 logging.info('Results directory: %s', self._results_dir)
173 logging.info('Runner package: %s', self._runner_package) 178 logging.info('Runner package: %s', self._runner_package)
174 logging.info('Runner type: %s', self._runner_type) 179 logging.info('Test framework: %s', self._test_framework)
175 logging.info('Timeouts: %s', self._timeouts) 180 logging.info('Timeouts: %s', self._timeouts)
176 181
177 if not args.trigger and not args.collect: 182 if not args.trigger and not args.collect:
178 self._trigger = True 183 self._trigger = True
179 self._collect = True 184 self._collect = True
180 else: 185 else:
181 self._trigger = args.trigger 186 self._trigger = args.trigger
182 self._collect = args.collect 187 self._collect = args.collect
183 188
184 def SetUp(self): 189 def SetUp(self):
185 """Set up the test environment.""" 190 """Set up the test environment."""
186 os.environ['APPURIFY_API_PROTO'] = self._api_protocol 191 os.environ['APPURIFY_API_PROTO'] = self._api_protocol
187 os.environ['APPURIFY_API_HOST'] = self._api_address 192 os.environ['APPURIFY_API_HOST'] = self._api_address
188 os.environ['APPURIFY_API_PORT'] = self._api_port 193 os.environ['APPURIFY_API_PORT'] = self._api_port
189 os.environ['APPURIFY_STATUS_BASE_URL'] = 'none' 194 os.environ['APPURIFY_STATUS_BASE_URL'] = 'none'
190 self._GetAccessToken() 195 self._GetAccessToken()
191 if self._trigger: 196 if self._trigger:
192 self._SelectDevice() 197 self._SelectDevices()
193 198
194 def TearDown(self): 199 def TearDown(self):
195 """Teardown the test environment.""" 200 """Teardown the test environment."""
196 self._RevokeAccessToken() 201 self._RevokeAccessToken()
197 202
198 def __enter__(self): 203 def __enter__(self):
199 """Set up the test run when used as a context manager.""" 204 """Set up the test run when used as a context manager."""
200 try: 205 try:
201 self.SetUp() 206 self.SetUp()
202 return self 207 return self
203 except: 208 except:
204 self.__exit__(*sys.exc_info()) 209 self.__exit__(*sys.exc_info())
205 raise 210 raise
206 211
207 def __exit__(self, exc_type, exc_val, exc_tb): 212 def __exit__(self, exc_type, exc_val, exc_tb):
208 """Tears down the test run when used as a context manager.""" 213 """Tears down the test run when used as a context manager."""
209 self.TearDown() 214 self.TearDown()
210 215
211 def DumpTo(self, persisted_data):
212 env_data = {
213 self._DEVICE_KEY: self._device,
214 }
215 persisted_data[self._ENV_KEY] = env_data
216
217 def LoadFrom(self, persisted_data):
218 env_data = persisted_data[self._ENV_KEY]
219 self._device = env_data[self._DEVICE_KEY]
220
221 def _GetAccessToken(self): 216 def _GetAccessToken(self):
222 """Generates access token for remote device service.""" 217 """Generates access token for remote device service."""
223 logging.info('Generating remote service access token') 218 logging.info('Generating remote service access token')
224 with appurify_sanitized.SanitizeLogging(self._verbose_count, 219 with appurify_sanitized.SanitizeLogging(self._verbose_count,
225 logging.WARNING): 220 logging.WARNING):
226 access_token_results = appurify_sanitized.api.access_token_generate( 221 access_token_results = appurify_sanitized.api.access_token_generate(
227 self._api_key, self._api_secret) 222 api_key=self._api_key, api_secret=self._api_secret)
rnephew (Wrong account) 2015/11/04 22:22:02 These feel unnecessary. Having them be keyword arg
mikecase (-- gone --) 2015/11/05 23:17:41 Done.
228 remote_device_helper.TestHttpResponse(access_token_results, 223 remote_device_helper.TestHttpResponse(access_token_results,
229 'Unable to generate access token.') 224 'Unable to generate access token.')
230 self._access_token = access_token_results.json()['response']['access_token'] 225 self._access_token = access_token_results.json()['response']['access_token']
231 226
232 def _RevokeAccessToken(self): 227 def _RevokeAccessToken(self):
233 """Destroys access token for remote device service.""" 228 """Destroys access token for remote device service."""
234 logging.info('Revoking remote service access token') 229 logging.info('Revoking remote service access token')
235 with appurify_sanitized.SanitizeLogging(self._verbose_count, 230 with appurify_sanitized.SanitizeLogging(self._verbose_count,
236 logging.WARNING): 231 logging.WARNING):
237 revoke_token_results = appurify_sanitized.api.access_token_revoke( 232 revoke_token_results = appurify_sanitized.api.access_token_revoke(
238 self._access_token) 233 access_token=self._access_token)
rnephew (Wrong account) 2015/11/04 22:22:02 Same.
mikecase (-- gone --) 2015/11/05 23:17:41 Done.
239 remote_device_helper.TestHttpResponse(revoke_token_results, 234 remote_device_helper.TestHttpResponse(revoke_token_results,
240 'Unable to revoke access token.') 235 'Unable to revoke access token.')
241 236
242 def _SelectDevice(self): 237 def _SelectDevices(self):
243 if self._remote_device_timeout: 238 if self._remote_device_timeout:
244 try: 239 try:
245 timeout_retry.Run(self._FindDeviceWithTimeout, 240 timeout_retry.Run(self._FindDevicesWithTimeout,
246 self._remote_device_timeout, self._DEFAULT_RETRIES) 241 self._remote_device_timeout, self._DEFAULT_RETRIES)
247 except reraiser_thread.TimeoutError: 242 except reraiser_thread.TimeoutError:
248 self._NoDeviceFound() 243 self._NoDeviceFound()
249 else: 244 else:
250 if not self._FindDevice(): 245 if not self._FindDevices():
251 self._NoDeviceFound() 246 self._NoDeviceFound()
252 247
253 def _FindDevice(self): 248 def _FindDevices(self):
254 """Find which device to use.""" 249 """Find which devices to use.
255 logging.info('Finding device to run tests on.') 250
251 Returns:
252 False if no devices were found and True otherwise.
253 """
254 logging.info('Finding devices to run tests on.')
256 device_list = self._GetDeviceList() 255 device_list = self._GetDeviceList()
257 random.shuffle(device_list)
rnephew (Wrong account) 2015/11/04 22:22:02 This was here so that we weren't selecting the sam
mikecase (-- gone --) 2015/11/05 23:17:41 Yes, this logic is still present, but got moved in
258 for device in device_list: 256 for device in device_list:
259 if device['os_name'] != self._device_type: 257 if device['os_name'] != self._device_type:
260 continue 258 continue
261 if self._remote_device and device['name'] not in self._remote_device: 259 if self._remote_device and device['name'] not in self._remote_device:
262 continue 260 continue
263 if (self._remote_device_os 261 if (self._remote_device_os
264 and device['os_version'] not in self._remote_device_os): 262 and device['os_version'] not in self._remote_device_os):
265 continue 263 continue
266 if self._device_oem and device['brand'] not in self._device_oem: 264 if self._device_oem and device['brand'] not in self._device_oem:
267 continue 265 continue
268 if (self._remote_device_minimum_os 266 if (self._remote_device_minimum_os
269 and distutils.version.LooseVersion(device['os_version']) 267 and distutils.version.LooseVersion(device['os_version'])
270 < distutils.version.LooseVersion(self._remote_device_minimum_os)): 268 < distutils.version.LooseVersion(self._remote_device_minimum_os)):
271 continue 269 continue
272 if device['has_available_device']: 270 if device['has_available_device']:
273 logging.info('Found device: %s %s', 271 logging.info('Found %s available %s %s',
272 device['available_devices_count'],
274 device['name'], device['os_version']) 273 device['name'], device['os_version'])
275 self._device = device 274 self._devices.append(device)
276 return True 275 return True if self._devices else False
277 return False
278 276
279 def _FindDeviceWithTimeout(self): 277 def _FindDevicesWithTimeout(self):
280 """Find which device to use with timeout.""" 278 """Find which device to use with timeout."""
281 timeout_retry.WaitFor(self._FindDevice, wait_period=1) 279 timeout_retry.WaitFor(self._FindDevices, wait_period=1)
282 280
283 def _PrintAvailableDevices(self, device_list): 281 def _PrintAvailableDevices(self, device_list):
284 def compare_devices(a, b): 282 def compare_devices(a, b):
285 for key in ('os_version', 'name'): 283 for key in ('os_version', 'name'):
286 c = cmp(a[key], b[key]) 284 c = cmp(a[key], b[key])
287 if c: 285 if c:
288 return c 286 return c
289 return 0 287 return 0
290 288
291 logging.critical('Available %s Devices:', self._device_type) 289 logging.critical('Available %s Devices:', self._device_type)
(...skipping 10 matching lines...) Expand all
302 ' %s %s %s %s %s', 300 ' %s %s %s %s %s',
303 d['os_version'].ljust(10), 301 d['os_version'].ljust(10),
304 d['name'].ljust(30), 302 d['name'].ljust(30),
305 str(d['available_devices_count']).ljust(10), 303 str(d['available_devices_count']).ljust(10),
306 str(d['busy_devices_count']).ljust(10), 304 str(d['busy_devices_count']).ljust(10),
307 str(d['all_devices_count']).ljust(10)) 305 str(d['all_devices_count']).ljust(10))
308 306
309 def _GetDeviceList(self): 307 def _GetDeviceList(self):
310 with appurify_sanitized.SanitizeLogging(self._verbose_count, 308 with appurify_sanitized.SanitizeLogging(self._verbose_count,
311 logging.WARNING): 309 logging.WARNING):
312 dev_list_res = appurify_sanitized.api.devices_list(self._access_token) 310 device_list_response = appurify_sanitized.api.devices_list(
313 remote_device_helper.TestHttpResponse(dev_list_res, 311 access_token=self._access_token)
314 'Unable to generate access token.') 312 remote_device_helper.TestHttpResponse(device_list_response,
315 return dev_list_res.json()['response'] 313 'Unable to generate access token.')
314 return device_list_response.json()['response']
316 315
317 def _NoDeviceFound(self): 316 def _NoDeviceFound(self):
318 self._PrintAvailableDevices(self._GetDeviceList()) 317 self._PrintAvailableDevices(self._GetDeviceList())
319 raise remote_device_helper.RemoteDeviceError( 318 raise remote_device_helper.RemoteDeviceError(
320 'No device found.', is_infra_error=True) 319 'No device found.', is_infra_error=True)
321 320
322 @property 321 @property
323 def collect(self): 322 def collect(self):
324 return self._collect 323 return self._collect
325 324
326 @property 325 @property
327 def device_type_id(self): 326 def device_type(self):
328 return self._device['device_type_id'] 327 return self._device_type
328
329 @property
330 def device_ids(self):
331 device_ids = []
332 for d in self._devices:
333 device_ids.extend([d['device_type_id']]*d['available_devices_count'])
334 return device_ids
329 335
330 @property 336 @property
331 def network_config(self): 337 def network_config(self):
332 return self._network_config 338 """Config to specify the network environment."""
339 return self._network_config or appurify_constants.NETWORK.WIFI_1_BAR
333 340
334 @property 341 @property
335 def results_path(self): 342 def num_shards(self):
336 return self._results_path 343 return self._num_shards or self._DEFAULT_SHARD_COUNT
344
345 @property
346 def pcap_config(self):
347 """Config to record the of network traffic from the device."""
348 return self._pcap_config
349
350 @property
351 def profiler_config(self):
352 """Config to record CPU, memory, and network transfer usage."""
353 return self._profiler_config
354
355 @property
356 def results_dir(self):
357 return self._results_dir
337 358
338 @property 359 @property
339 def runner_package(self): 360 def runner_package(self):
340 return self._runner_package 361 return self._runner_package
341 362
342 @property 363 @property
343 def runner_type(self): 364 def test_framework(self):
344 return self._runner_type 365 return self._test_framework
345 366
346 @property 367 @property
347 def timeouts(self): 368 def timeouts(self):
348 return self._timeouts 369 return self._timeouts
349 370
350 @property 371 @property
351 def token(self): 372 def token(self):
352 return self._access_token 373 return self._access_token
353 374
354 @property 375 @property
355 def trigger(self): 376 def trigger(self):
356 return self._trigger 377 return self._trigger
357 378
358 @property 379 @property
359 def verbose_count(self): 380 def verbose_count(self):
360 return self._verbose_count 381 return self._verbose_count
361 382
362 @property 383 @property
363 def device_type(self): 384 def videocapture_config(self):
364 return self._device_type 385 """Config to set video capture during the tests."""
386 return self._videocapture_config
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698