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

Side by Side Diff: build/android/pylib/local/device/local_device_environment.py

Issue 2144823003: [Android] Blacklist devices on failures during environment set up + tear down. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 months 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
« no previous file with comments | « no previous file | build/android/pylib/local/device/local_device_gtest_run.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 import datetime 5 import datetime
6 import functools
6 import logging 7 import logging
7 import os 8 import os
8 import shutil 9 import shutil
9 import tempfile 10 import tempfile
10 import threading 11 import threading
11 12
13 from devil import base_error
12 from devil.android import device_blacklist 14 from devil.android import device_blacklist
13 from devil.android import device_errors 15 from devil.android import device_errors
14 from devil.android import device_list 16 from devil.android import device_list
15 from devil.android import device_utils 17 from devil.android import device_utils
16 from devil.android import logcat_monitor 18 from devil.android import logcat_monitor
17 from devil.utils import file_utils 19 from devil.utils import file_utils
18 from devil.utils import parallelizer 20 from devil.utils import parallelizer
19 from pylib import constants 21 from pylib import constants
20 from pylib.base import environment 22 from pylib.base import environment
21 23
22 24
23 def _DeviceCachePath(device): 25 def _DeviceCachePath(device):
24 file_name = 'device_cache_%s.json' % device.adb.GetDeviceSerial() 26 file_name = 'device_cache_%s.json' % device.adb.GetDeviceSerial()
25 return os.path.join(constants.GetOutDirectory(), file_name) 27 return os.path.join(constants.GetOutDirectory(), file_name)
26 28
27 29
30 def handle_shard_failures(f):
31 """A decorator that handles device failures for per-device functions.
32
33 Args:
34 f: the function being decorated. The function must take at least one
35 argument, and that argument must be the device.
36 """
37 return handle_shard_failures_with(None)(f)
38
39
40 # TODO(jbudorick): Refactor this to work as a decorator or context manager.
41 def handle_shard_failures_with(on_failure):
42 """A decorator that handles device failures for per-device functions.
43
44 This calls on_failure in the event of a failure.
45
46 Args:
47 f: the function being decorated. The function must take at least one
48 argument, and that argument must be the device.
49 on_failure: A binary function to call on failure.
50 """
51 def decorator(f):
52 @functools.wraps(f)
53 def wrapper(dev, *args, **kwargs):
54 try:
55 return f(dev, *args, **kwargs)
56 except device_errors.CommandTimeoutError:
57 logging.exception('Shard timed out: %s(%s)', f.__name__, str(dev))
58 except device_errors.DeviceUnreachableError:
59 logging.exception('Shard died: %s(%s)', f.__name__, str(dev))
60 except base_error.BaseError:
61 logging.exception('Shard failed: %s(%s)', f.__name__, str(dev))
62 except SystemExit:
63 logging.exception('Shard killed: %s(%s)', f.__name__, str(dev))
64 raise
65 if on_failure:
66 on_failure(dev, f.__name__)
67 return None
68
69 return wrapper
70
71 return decorator
72
73
28 class LocalDeviceEnvironment(environment.Environment): 74 class LocalDeviceEnvironment(environment.Environment):
29 75
30 def __init__(self, args, _error_func): 76 def __init__(self, args, _error_func):
31 super(LocalDeviceEnvironment, self).__init__() 77 super(LocalDeviceEnvironment, self).__init__()
32 self._blacklist = (device_blacklist.Blacklist(args.blacklist_file) 78 self._blacklist = (device_blacklist.Blacklist(args.blacklist_file)
33 if args.blacklist_file 79 if args.blacklist_file
34 else None) 80 else None)
35 self._device_serial = args.test_device 81 self._device_serial = args.test_device
36 self._devices_lock = threading.Lock() 82 self._devices_lock = threading.Lock()
37 self._devices = [] 83 self._devices = []
(...skipping 22 matching lines...) Expand all
60 'Read device list %s from target devices file.', str(device_arg)) 106 'Read device list %s from target devices file.', str(device_arg))
61 elif self._device_serial: 107 elif self._device_serial:
62 device_arg = self._device_serial 108 device_arg = self._device_serial
63 109
64 self._devices = device_utils.DeviceUtils.HealthyDevices( 110 self._devices = device_utils.DeviceUtils.HealthyDevices(
65 self._blacklist, enable_device_files_cache=self._enable_device_cache, 111 self._blacklist, enable_device_files_cache=self._enable_device_cache,
66 default_retries=self._max_tries - 1, device_arg=device_arg) 112 default_retries=self._max_tries - 1, device_arg=device_arg)
67 if not self._devices: 113 if not self._devices:
68 raise device_errors.NoDevicesError 114 raise device_errors.NoDevicesError
69 115
70 if self._enable_device_cache: 116 if self._logcat_output_file:
71 for d in self._devices: 117 self._logcat_output_dir = tempfile.mkdtemp()
118
119 @handle_shard_failures_with(on_failure=self.BlacklistDevice)
120 def prepare_device(d):
121 if self._enable_device_cache:
72 cache_path = _DeviceCachePath(d) 122 cache_path = _DeviceCachePath(d)
73 if os.path.exists(cache_path): 123 if os.path.exists(cache_path):
74 logging.info('Using device cache: %s', cache_path) 124 logging.info('Using device cache: %s', cache_path)
75 with open(cache_path) as f: 125 with open(cache_path) as f:
76 d.LoadCacheData(f.read()) 126 d.LoadCacheData(f.read())
77 # Delete cached file so that any exceptions cause it to be cleared. 127 # Delete cached file so that any exceptions cause it to be cleared.
78 os.unlink(cache_path) 128 os.unlink(cache_path)
79 if self._logcat_output_file: 129
80 self._logcat_output_dir = tempfile.mkdtemp() 130 if self._logcat_output_dir:
81 if self._logcat_output_dir:
82 for d in self._devices:
83 logcat_file = os.path.join( 131 logcat_file = os.path.join(
84 self._logcat_output_dir, 132 self._logcat_output_dir,
85 '%s_%s' % (d.adb.GetDeviceSerial(), 133 '%s_%s' % (d.adb.GetDeviceSerial(),
86 datetime.datetime.utcnow().strftime('%Y%m%dT%H%M%S'))) 134 datetime.datetime.utcnow().strftime('%Y%m%dT%H%M%S')))
87 monitor = logcat_monitor.LogcatMonitor( 135 monitor = logcat_monitor.LogcatMonitor(
88 d.adb, clear=True, output_file=logcat_file) 136 d.adb, clear=True, output_file=logcat_file)
89 self._logcat_monitors.append(monitor) 137 self._logcat_monitors.append(monitor)
90 monitor.Start() 138 monitor.Start()
91 139
140 self.parallel_devices.pMap(prepare_device)
141
142
rnephew (Reviews Here) 2016/07/13 20:12:26 nit: one line
jbudorick 2016/07/13 20:43:09 Done.
92 @property 143 @property
93 def blacklist(self): 144 def blacklist(self):
94 return self._blacklist 145 return self._blacklist
95 146
96 @property 147 @property
97 def concurrent_adb(self): 148 def concurrent_adb(self):
98 return self._concurrent_adb 149 return self._concurrent_adb
99 150
100 @property 151 @property
101 def devices(self): 152 def devices(self):
(...skipping 12 matching lines...) Expand all
114 @property 165 @property
115 def skip_clear_data(self): 166 def skip_clear_data(self):
116 return self._skip_clear_data 167 return self._skip_clear_data
117 168
118 @property 169 @property
119 def tool(self): 170 def tool(self):
120 return self._tool_name 171 return self._tool_name
121 172
122 #override 173 #override
123 def TearDown(self): 174 def TearDown(self):
124 # Write the cache even when not using it so that it will be ready the first 175 @handle_shard_failures_with(on_failure=self.BlacklistDevice)
125 # time that it is enabled. Writing it every time is also necessary so that 176 def tear_down_device(d):
126 # an invalid cache can be flushed just by disabling it for one run. 177 # Write the cache even when not using it so that it will be ready the
127 for d in self._devices: 178 # first time that it is enabled. Writing it every time is also necessary
179 # so that an invalid cache can be flushed just by disabling it for one
180 # run.
128 cache_path = _DeviceCachePath(d) 181 cache_path = _DeviceCachePath(d)
129 with open(cache_path, 'w') as f: 182 with open(cache_path, 'w') as f:
130 f.write(d.DumpCacheData()) 183 f.write(d.DumpCacheData())
131 logging.info('Wrote device cache: %s', cache_path) 184 logging.info('Wrote device cache: %s', cache_path)
185
186 self.parallel_devices.pMap(tear_down_device)
187
132 for m in self._logcat_monitors: 188 for m in self._logcat_monitors:
133 m.Stop() 189 try:
134 m.Close() 190 m.Stop()
191 m.Close()
192 except base_error.BaseError:
193 logging.exception('Failed to stop logcat monitor for %s',
194 m.adb.GetDeviceSerial())
195
135 if self._logcat_output_file: 196 if self._logcat_output_file:
136 file_utils.MergeFiles( 197 file_utils.MergeFiles(
137 self._logcat_output_file, 198 self._logcat_output_file,
138 [m.output_file for m in self._logcat_monitors]) 199 [m.output_file for m in self._logcat_monitors])
139 shutil.rmtree(self._logcat_output_dir) 200 shutil.rmtree(self._logcat_output_dir)
140 201
141 def BlacklistDevice(self, device, reason='local_device_failure'): 202 def BlacklistDevice(self, device, reason='local_device_failure'):
142 device_serial = device.adb.GetDeviceSerial() 203 device_serial = device.adb.GetDeviceSerial()
143 if self._blacklist: 204 if self._blacklist:
144 self._blacklist.Extend([device_serial], reason=reason) 205 self._blacklist.Extend([device_serial], reason=reason)
145 with self._devices_lock: 206 with self._devices_lock:
146 self._devices = [d for d in self._devices if str(d) != device_serial] 207 self._devices = [d for d in self._devices if str(d) != device_serial]
147 208
OLDNEW
« no previous file with comments | « no previous file | build/android/pylib/local/device/local_device_gtest_run.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698