| OLD | NEW |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 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 io | 5 import io |
| 6 import json | 6 import json |
| 7 import logging | 7 import logging |
| 8 import os | 8 import os |
| 9 import pickle | 9 import pickle |
| 10 import shutil | 10 import shutil |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 self._timer.cancel() | 54 self._timer.cancel() |
| 55 self._running = False | 55 self._running = False |
| 56 | 56 |
| 57 def _LogMessage(self): | 57 def _LogMessage(self): |
| 58 logging.info('Currently working on test %s', self._shard.current_test) | 58 logging.info('Currently working on test %s', self._shard.current_test) |
| 59 self._timer = threading.Timer(self._wait_time, self._LogMessage) | 59 self._timer = threading.Timer(self._wait_time, self._LogMessage) |
| 60 self._timer.start() | 60 self._timer.start() |
| 61 | 61 |
| 62 | 62 |
| 63 class TestShard(object): | 63 class TestShard(object): |
| 64 def __init__( | 64 def __init__(self, env, test_instance, tests, retries=3, timeout=None): |
| 65 self, env, test_instance, device, index, tests, retries=3, timeout=None): | 65 logging.info('Create shard for the following tests:') |
| 66 logging.info('Create shard %s for device %s to run the following tests:', | |
| 67 index, device) | |
| 68 for t in tests: | 66 for t in tests: |
| 69 logging.info(' %s', t) | 67 logging.info(' %s', t) |
| 70 self._battery = battery_utils.BatteryUtils(device) | |
| 71 self._current_test = None | 68 self._current_test = None |
| 72 self._device = device | |
| 73 self._env = env | 69 self._env = env |
| 74 self._index = index | 70 self._heart_beat = HeartBeat(self) |
| 71 self._index = None |
| 75 self._output_dir = None | 72 self._output_dir = None |
| 76 self._retries = retries | 73 self._retries = retries |
| 77 self._test_instance = test_instance | 74 self._test_instance = test_instance |
| 78 self._tests = tests | 75 self._tests = tests |
| 79 self._timeout = timeout | 76 self._timeout = timeout |
| 80 self._heart_beat = HeartBeat(self) | |
| 81 | |
| 82 @local_device_environment.handle_shard_failures | |
| 83 def RunTestsOnShard(self): | |
| 84 results = base_test_result.TestRunResults() | |
| 85 for test in self._tests: | |
| 86 tries_left = self._retries | |
| 87 result_type = None | |
| 88 while (result_type != base_test_result.ResultType.PASS | |
| 89 and tries_left > 0): | |
| 90 try: | |
| 91 self._TestSetUp(test) | |
| 92 result_type = self._RunSingleTest(test) | |
| 93 except device_errors.CommandTimeoutError: | |
| 94 result_type = base_test_result.ResultType.TIMEOUT | |
| 95 except device_errors.CommandFailedError: | |
| 96 logging.exception('Exception when executing %s.', test) | |
| 97 result_type = base_test_result.ResultType.FAIL | |
| 98 finally: | |
| 99 self._TestTearDown() | |
| 100 if result_type != base_test_result.ResultType.PASS: | |
| 101 try: | |
| 102 device_recovery.RecoverDevice(self._device, self._env.blacklist) | |
| 103 except device_errors.CommandTimeoutError: | |
| 104 logging.exception( | |
| 105 'Device failed to recover after failing %s.', test) | |
| 106 tries_left = tries_left - 1 | |
| 107 | |
| 108 results.AddResult(base_test_result.BaseTestResult(test, result_type)) | |
| 109 return results | |
| 110 | 77 |
| 111 def _TestSetUp(self, test): | 78 def _TestSetUp(self, test): |
| 112 if not self._device.IsOnline(): | |
| 113 msg = 'Device %s is unresponsive.' % str(self._device) | |
| 114 raise device_errors.DeviceUnreachableError(msg) | |
| 115 | |
| 116 logging.info('Charge level: %s%%', | |
| 117 str(self._battery.GetBatteryInfo().get('level'))) | |
| 118 if self._test_instance.min_battery_level: | |
| 119 self._battery.ChargeDeviceToLevel(self._test_instance.min_battery_level) | |
| 120 | |
| 121 logging.info('temperature: %s (0.1 C)', | |
| 122 str(self._battery.GetBatteryInfo().get('temperature'))) | |
| 123 if self._test_instance.max_battery_temp: | |
| 124 self._battery.LetBatteryCoolToTemperature( | |
| 125 self._test_instance.max_battery_temp) | |
| 126 | |
| 127 if not self._device.IsScreenOn(): | |
| 128 self._device.SetScreen(True) | |
| 129 | |
| 130 if (self._test_instance.collect_chartjson_data | 79 if (self._test_instance.collect_chartjson_data |
| 131 or self._tests[test].get('archive_output_dir')): | 80 or self._tests[test].get('archive_output_dir')): |
| 132 self._output_dir = tempfile.mkdtemp() | 81 self._output_dir = tempfile.mkdtemp() |
| 133 | 82 |
| 134 self._current_test = test | 83 self._current_test = test |
| 135 self._heart_beat.Start() | 84 self._heart_beat.Start() |
| 136 | 85 |
| 137 def _RunSingleTest(self, test): | 86 def _RunSingleTest(self, test): |
| 138 self._test_instance.WriteBuildBotJson(self._output_dir) | 87 self._test_instance.WriteBuildBotJson(self._output_dir) |
| 139 | 88 |
| 140 timeout = self._tests[test].get('timeout', self._timeout) | 89 timeout = self._tests[test].get('timeout', self._timeout) |
| 141 cmd = self._CreateCmd(test) | 90 cmd = self._CreateCmd(test) |
| 142 cwd = os.path.abspath(host_paths.DIR_SOURCE_ROOT) | 91 cwd = os.path.abspath(host_paths.DIR_SOURCE_ROOT) |
| 143 | 92 |
| 144 logging.debug("Running %s with command '%s' on shard %d with timeout %d", | 93 self._LogTest(test, cmd, timeout) |
| 145 test, cmd, self._index, timeout) | |
| 146 | 94 |
| 147 try: | 95 try: |
| 148 start_time = time.time() | 96 start_time = time.time() |
| 149 exit_code, output = cmd_helper.GetCmdStatusAndOutputWithTimeout( | 97 exit_code, output = cmd_helper.GetCmdStatusAndOutputWithTimeout( |
| 150 cmd, timeout, cwd=cwd, shell=True) | 98 cmd, timeout, cwd=cwd, shell=True) |
| 151 end_time = time.time() | 99 end_time = time.time() |
| 152 json_output = self._test_instance.ReadChartjsonOutput(self._output_dir) | 100 json_output = self._test_instance.ReadChartjsonOutput(self._output_dir) |
| 153 if exit_code == 0: | 101 if exit_code == 0: |
| 154 result_type = base_test_result.ResultType.PASS | 102 result_type = base_test_result.ResultType.PASS |
| 155 else: | 103 else: |
| 156 result_type = base_test_result.ResultType.FAIL | 104 result_type = base_test_result.ResultType.FAIL |
| 157 except cmd_helper.TimeoutError as e: | 105 except cmd_helper.TimeoutError as e: |
| 158 end_time = time.time() | 106 end_time = time.time() |
| 159 exit_code = -1 | 107 exit_code = -1 |
| 160 output = e.output | 108 output = e.output |
| 161 json_output = '' | 109 json_output = '' |
| 162 result_type = base_test_result.ResultType.TIMEOUT | 110 result_type = base_test_result.ResultType.TIMEOUT |
| 163 | 111 |
| 164 return self._ProcessTestResult(test, cmd, start_time, end_time, exit_code, | 112 return self._ProcessTestResult(test, cmd, start_time, end_time, exit_code, |
| 165 output, json_output, result_type) | 113 output, json_output, result_type) |
| 166 | 114 |
| 167 def _CreateCmd(self, test): | 115 def _CreateCmd(self, test): |
| 168 cmd = '%s --device %s' % (self._tests[test]['cmd'], str(self._device)) | 116 cmd = [] |
| 117 if self._test_instance.dry_run: |
| 118 cmd.append('echo') |
| 119 cmd.append(self._tests[test]['cmd']) |
| 169 if self._output_dir: | 120 if self._output_dir: |
| 170 cmd = cmd + ' --output-dir=%s' % self._output_dir | 121 cmd.append('--output-dir=%s' % self._output_dir) |
| 171 if self._test_instance.dry_run: | 122 return ' '.join(self._ExtendCmd(cmd)) |
| 172 cmd = 'echo %s' % cmd | 123 |
| 124 def _ExtendCmd(self, cmd): # pylint: disable=no-self-use |
| 173 return cmd | 125 return cmd |
| 174 | 126 |
| 127 def _LogTest(self, _test, _cmd, _timeout): |
| 128 raise NotImplementedError |
| 129 |
| 130 def _LogTestExit(self, test, exit_code, duration): |
| 131 # pylint: disable=no-self-use |
| 132 logging.info('%s : exit_code=%d in %d secs.', test, exit_code, duration) |
| 133 |
| 134 def _ExtendPersistedResult(self, persisted_result): |
| 135 raise NotImplementedError |
| 136 |
| 175 def _ProcessTestResult(self, test, cmd, start_time, end_time, exit_code, | 137 def _ProcessTestResult(self, test, cmd, start_time, end_time, exit_code, |
| 176 output, json_output, result_type): | 138 output, json_output, result_type): |
| 177 if exit_code is None: | 139 if exit_code is None: |
| 178 exit_code = -1 | 140 exit_code = -1 |
| 179 logging.info('%s : exit_code=%d in %d secs on device %s', | 141 |
| 180 test, exit_code, end_time - start_time, | 142 self._LogTestExit(test, exit_code, end_time - start_time) |
| 181 str(self._device)) | |
| 182 | 143 |
| 183 actual_exit_code = exit_code | 144 actual_exit_code = exit_code |
| 184 if (self._test_instance.flaky_steps | 145 if (self._test_instance.flaky_steps |
| 185 and test in self._test_instance.flaky_steps): | 146 and test in self._test_instance.flaky_steps): |
| 186 exit_code = 0 | 147 exit_code = 0 |
| 187 archive_bytes = (self._ArchiveOutputDir() | 148 archive_bytes = (self._ArchiveOutputDir() |
| 188 if self._tests[test].get('archive_output_dir') | 149 if self._tests[test].get('archive_output_dir') |
| 189 else None) | 150 else None) |
| 190 persisted_result = { | 151 persisted_result = { |
| 191 'name': test, | 152 'name': test, |
| 192 'output': [output], | 153 'output': [output], |
| 193 'chartjson': json_output, | 154 'chartjson': json_output, |
| 194 'archive_bytes': archive_bytes, | 155 'archive_bytes': archive_bytes, |
| 195 'exit_code': exit_code, | 156 'exit_code': exit_code, |
| 196 'actual_exit_code': actual_exit_code, | 157 'actual_exit_code': actual_exit_code, |
| 197 'result_type': result_type, | 158 'result_type': result_type, |
| 198 'start_time': start_time, | 159 'start_time': start_time, |
| 199 'end_time': end_time, | 160 'end_time': end_time, |
| 200 'total_time': end_time - start_time, | 161 'total_time': end_time - start_time, |
| 201 'device': str(self._device), | |
| 202 'cmd': cmd, | 162 'cmd': cmd, |
| 203 } | 163 } |
| 164 self._ExtendPersistedResult(persisted_result) |
| 204 self._SaveResult(persisted_result) | 165 self._SaveResult(persisted_result) |
| 205 return result_type | 166 return result_type |
| 206 | 167 |
| 207 def _ArchiveOutputDir(self): | 168 def _ArchiveOutputDir(self): |
| 208 """Archive all files in the output dir, and return as compressed bytes.""" | 169 """Archive all files in the output dir, and return as compressed bytes.""" |
| 209 with io.BytesIO() as archive: | 170 with io.BytesIO() as archive: |
| 210 with zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED) as contents: | 171 with zipfile.ZipFile(archive, 'w', zipfile.ZIP_DEFLATED) as contents: |
| 211 num_files = 0 | 172 num_files = 0 |
| 212 for absdir, _, files in os.walk(self._output_dir): | 173 for absdir, _, files in os.walk(self._output_dir): |
| 213 reldir = os.path.relpath(absdir, self._output_dir) | 174 reldir = os.path.relpath(absdir, self._output_dir) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 230 with file(pickled, 'r') as f: | 191 with file(pickled, 'r') as f: |
| 231 previous = pickle.loads(f.read()) | 192 previous = pickle.loads(f.read()) |
| 232 result['output'] = previous['output'] + result['output'] | 193 result['output'] = previous['output'] + result['output'] |
| 233 with file(pickled, 'w') as f: | 194 with file(pickled, 'w') as f: |
| 234 f.write(pickle.dumps(result)) | 195 f.write(pickle.dumps(result)) |
| 235 | 196 |
| 236 def _TestTearDown(self): | 197 def _TestTearDown(self): |
| 237 if self._output_dir: | 198 if self._output_dir: |
| 238 shutil.rmtree(self._output_dir, ignore_errors=True) | 199 shutil.rmtree(self._output_dir, ignore_errors=True) |
| 239 self._output_dir = None | 200 self._output_dir = None |
| 201 self._heart_beat.Stop() |
| 202 self._current_test = None |
| 203 |
| 204 @property |
| 205 def current_test(self): |
| 206 return self._current_test |
| 207 |
| 208 |
| 209 class DeviceTestShard(TestShard): |
| 210 def __init__( |
| 211 self, env, test_instance, device, index, tests, retries=3, timeout=None): |
| 212 super(DeviceTestShard, self).__init__( |
| 213 env, test_instance, tests, retries, timeout) |
| 214 self._battery = battery_utils.BatteryUtils(device) if device else None |
| 215 self._device = device |
| 216 self._index = index |
| 217 |
| 218 @local_device_environment.handle_shard_failures |
| 219 def RunTestsOnShard(self): |
| 220 results = base_test_result.TestRunResults() |
| 221 for test in self._tests: |
| 222 tries_left = self._retries |
| 223 result_type = None |
| 224 while (result_type != base_test_result.ResultType.PASS |
| 225 and tries_left > 0): |
| 226 try: |
| 227 self._TestSetUp(test) |
| 228 result_type = self._RunSingleTest(test) |
| 229 except device_errors.CommandTimeoutError: |
| 230 result_type = base_test_result.ResultType.TIMEOUT |
| 231 except device_errors.CommandFailedError: |
| 232 logging.exception('Exception when executing %s.', test) |
| 233 result_type = base_test_result.ResultType.FAIL |
| 234 finally: |
| 235 self._TestTearDown() |
| 236 if result_type != base_test_result.ResultType.PASS: |
| 237 try: |
| 238 device_recovery.RecoverDevice(self._device, self._env.blacklist) |
| 239 except device_errors.CommandTimeoutError: |
| 240 logging.exception( |
| 241 'Device failed to recover after failing %s.', test) |
| 242 tries_left = tries_left - 1 |
| 243 |
| 244 results.AddResult(base_test_result.BaseTestResult(test, result_type)) |
| 245 return results |
| 246 |
| 247 def _LogTestExit(self, test, exit_code, duration): |
| 248 logging.info('%s : exit_code=%d in %d secs on device %s', |
| 249 test, exit_code, duration, str(self._device)) |
| 250 |
| 251 def _TestSetUp(self, test): |
| 252 if not self._device.IsOnline(): |
| 253 msg = 'Device %s is unresponsive.' % str(self._device) |
| 254 raise device_errors.DeviceUnreachableError(msg) |
| 255 |
| 256 logging.info('Charge level: %s%%', |
| 257 str(self._battery.GetBatteryInfo().get('level'))) |
| 258 if self._test_instance.min_battery_level: |
| 259 self._battery.ChargeDeviceToLevel(self._test_instance.min_battery_level) |
| 260 |
| 261 logging.info('temperature: %s (0.1 C)', |
| 262 str(self._battery.GetBatteryInfo().get('temperature'))) |
| 263 if self._test_instance.max_battery_temp: |
| 264 self._battery.LetBatteryCoolToTemperature( |
| 265 self._test_instance.max_battery_temp) |
| 266 |
| 267 if not self._device.IsScreenOn(): |
| 268 self._device.SetScreen(True) |
| 269 |
| 270 super(DeviceTestShard, self)._TestSetUp(test) |
| 271 |
| 272 def _LogTest(self, test, cmd, timeout): |
| 273 logging.debug("Running %s with command '%s' on shard %s with timeout %d", |
| 274 test, cmd, str(self._index), timeout) |
| 275 |
| 276 def _ExtendCmd(self, cmd): |
| 277 cmd.extend(['--device=%s' % str(self._device)]) |
| 278 return cmd |
| 279 |
| 280 def _ExtendPersistedResult(self, persisted_result): |
| 281 persisted_result['host_test'] = False |
| 282 persisted_result['device'] = str(self._device) |
| 283 |
| 284 def _TestTearDown(self): |
| 240 try: | 285 try: |
| 241 logging.info('Unmapping device ports for %s.', self._device) | 286 logging.info('Unmapping device ports for %s.', self._device) |
| 242 forwarder.Forwarder.UnmapAllDevicePorts(self._device) | 287 forwarder.Forwarder.UnmapAllDevicePorts(self._device) |
| 243 except Exception: # pylint: disable=broad-except | 288 except Exception: # pylint: disable=broad-except |
| 244 logging.exception('Exception when resetting ports.') | 289 logging.exception('Exception when resetting ports.') |
| 245 finally: | 290 finally: |
| 246 self._heart_beat.Stop() | 291 super(DeviceTestShard, self)._TestTearDown() |
| 247 self._current_test = None | |
| 248 | 292 |
| 249 @property | 293 class HostTestShard(TestShard): |
| 250 def current_test(self): | 294 def __init__(self, env, test_instance, tests, retries=3, timeout=None): |
| 251 return self._current_test | 295 super(HostTestShard, self).__init__( |
| 296 env, test_instance, tests, retries, timeout) |
| 297 |
| 298 @local_device_environment.handle_shard_failures |
| 299 def RunTestsOnShard(self): |
| 300 results = base_test_result.TestRunResults() |
| 301 for test in self._tests: |
| 302 tries_left = self._retries |
| 303 result_type = None |
| 304 while (result_type != base_test_result.ResultType.PASS |
| 305 and tries_left > 0): |
| 306 try: |
| 307 self._TestSetUp(test) |
| 308 result_type = self._RunSingleTest(test) |
| 309 finally: |
| 310 self._TestTearDown() |
| 311 results.AddResult(base_test_result.BaseTestResult(test, result_type)) |
| 312 return results |
| 313 |
| 314 def _LogTest(self, test, cmd, timeout): |
| 315 logging.debug("Running %s with command '%s' on host shard with timeout %d", |
| 316 test, cmd, timeout) |
| 317 |
| 318 def _ExtendPersistedResult(self, persisted_result): |
| 319 persisted_result['host_test'] = True |
| 320 |
| 252 | 321 |
| 253 class LocalDevicePerfTestRun(local_device_test_run.LocalDeviceTestRun): | 322 class LocalDevicePerfTestRun(local_device_test_run.LocalDeviceTestRun): |
| 254 | 323 |
| 255 _DEFAULT_TIMEOUT = 60 * 60 | 324 _DEFAULT_TIMEOUT = 60 * 60 |
| 256 _CONFIG_VERSION = 1 | 325 _CONFIG_VERSION = 1 |
| 257 | 326 |
| 258 def __init__(self, env, test_instance): | 327 def __init__(self, env, test_instance): |
| 259 super(LocalDevicePerfTestRun, self).__init__(env, test_instance) | 328 super(LocalDevicePerfTestRun, self).__init__(env, test_instance) |
| 260 self._devices = None | 329 self._devices = None |
| 261 self._env = env | 330 self._env = env |
| 331 self._no_device_tests = {} |
| 262 self._test_buckets = [] | 332 self._test_buckets = [] |
| 263 self._test_instance = test_instance | 333 self._test_instance = test_instance |
| 264 self._timeout = None if test_instance.no_timeout else self._DEFAULT_TIMEOUT | 334 self._timeout = None if test_instance.no_timeout else self._DEFAULT_TIMEOUT |
| 265 | 335 |
| 266 def SetUp(self): | 336 def SetUp(self): |
| 267 self._devices = self._GetAllDevices(self._env.devices, | 337 self._devices = self._GetAllDevices(self._env.devices, |
| 268 self._test_instance.known_devices_file) | 338 self._test_instance.known_devices_file) |
| 269 | 339 |
| 270 if os.path.exists(constants.PERF_OUTPUT_DIR): | 340 if os.path.exists(constants.PERF_OUTPUT_DIR): |
| 271 shutil.rmtree(constants.PERF_OUTPUT_DIR) | 341 shutil.rmtree(constants.PERF_OUTPUT_DIR) |
| (...skipping 25 matching lines...) Expand all Loading... |
| 297 raise PerfTestRunGetStepsError( | 367 raise PerfTestRunGetStepsError( |
| 298 'Neither single_step or steps set in test_instance.') | 368 'Neither single_step or steps set in test_instance.') |
| 299 | 369 |
| 300 def _SplitTestsByAffinity(self): | 370 def _SplitTestsByAffinity(self): |
| 301 # This splits tests by their device affinity so that the same tests always | 371 # This splits tests by their device affinity so that the same tests always |
| 302 # run on the same devices. This is important for perf tests since different | 372 # run on the same devices. This is important for perf tests since different |
| 303 # devices might yield slightly different performance results. | 373 # devices might yield slightly different performance results. |
| 304 test_dict = self._GetStepsFromDict() | 374 test_dict = self._GetStepsFromDict() |
| 305 for test, test_config in test_dict['steps'].iteritems(): | 375 for test, test_config in test_dict['steps'].iteritems(): |
| 306 try: | 376 try: |
| 307 affinity = test_config['device_affinity'] | 377 affinity = test_config.get('device_affinity') |
| 308 if len(self._test_buckets) < affinity + 1: | 378 if affinity is None: |
| 309 while len(self._test_buckets) != affinity + 1: | 379 self._no_device_tests[test] = test_config |
| 310 self._test_buckets.append({}) | 380 else: |
| 311 self._test_buckets[affinity][test] = test_config | 381 if len(self._test_buckets) < affinity + 1: |
| 382 while len(self._test_buckets) != affinity + 1: |
| 383 self._test_buckets.append({}) |
| 384 self._test_buckets[affinity][test] = test_config |
| 312 except KeyError: | 385 except KeyError: |
| 313 logging.exception( | 386 logging.exception( |
| 314 'Test config for %s is bad.\n Config:%s', test, str(test_config)) | 387 'Test config for %s is bad.\n Config:%s', test, str(test_config)) |
| 315 | 388 |
| 316 @staticmethod | 389 @staticmethod |
| 317 def _GetAllDevices(active_devices, devices_path): | 390 def _GetAllDevices(active_devices, devices_path): |
| 318 try: | 391 try: |
| 319 if devices_path: | 392 if devices_path: |
| 320 devices = [device_utils.DeviceUtils(s) | 393 devices = [device_utils.DeviceUtils(s) |
| 321 for s in device_list.GetPersistentDeviceList(devices_path)] | 394 for s in device_list.GetPersistentDeviceList(devices_path)] |
| 322 if not devices and active_devices: | 395 if not devices and active_devices: |
| 323 logging.warning('%s is empty. Falling back to active devices.', | 396 logging.warning('%s is empty. Falling back to active devices.', |
| 324 devices_path) | 397 devices_path) |
| 325 devices = active_devices | 398 devices = active_devices |
| 326 else: | 399 else: |
| 327 logging.warning('Known devices file path not being passed. For device ' | 400 logging.warning('Known devices file path not being passed. For device ' |
| 328 'affinity to work properly, it must be passed.') | 401 'affinity to work properly, it must be passed.') |
| 329 devices = active_devices | 402 devices = active_devices |
| 330 except IOError as e: | 403 except IOError as e: |
| 331 logging.error('Unable to find %s [%s]', devices_path, e) | 404 logging.error('Unable to find %s [%s]', devices_path, e) |
| 332 devices = active_devices | 405 devices = active_devices |
| 333 return sorted(devices) | 406 return sorted(devices) |
| 334 | 407 |
| 335 #override | 408 #override |
| 336 def RunTests(self): | 409 def RunTests(self): |
| 337 # Affinitize the tests. | 410 # Affinitize the tests. |
| 338 self._SplitTestsByAffinity() | 411 self._SplitTestsByAffinity() |
| 339 if not self._test_buckets: | 412 if not self._test_buckets and not self._no_device_tests: |
| 340 raise local_device_test_run.NoTestsError() | 413 raise local_device_test_run.NoTestsError() |
| 341 | 414 |
| 342 def run_perf_tests(shard_id): | 415 def run_perf_tests(shard_id): |
| 343 if device_status.IsBlacklisted( | 416 if shard_id is None: |
| 344 str(self._devices[shard_id]), self._env.blacklist): | 417 s = HostTestShard(self._env, self._test_instance, self._no_device_tests, |
| 345 logging.warning('Device %s is not active. Will not create shard %s.', | 418 retries=3, timeout=self._timeout) |
| 346 str(self._devices[shard_id]), shard_id) | 419 else: |
| 347 return None | 420 if device_status.IsBlacklisted( |
| 348 s = TestShard(self._env, self._test_instance, self._devices[shard_id], | 421 str(self._devices[shard_id]), self._env.blacklist): |
| 349 shard_id, self._test_buckets[shard_id], | 422 logging.warning('Device %s is not active. Will not create shard %s.', |
| 350 retries=self._env.max_tries, timeout=self._timeout) | 423 str(self._devices[shard_id]), shard_id) |
| 424 return None |
| 425 s = DeviceTestShard(self._env, self._test_instance, |
| 426 self._devices[shard_id], shard_id, |
| 427 self._test_buckets[shard_id], |
| 428 retries=self._env.max_tries, timeout=self._timeout) |
| 351 return s.RunTestsOnShard() | 429 return s.RunTestsOnShard() |
| 352 | 430 |
| 353 device_indices = range(min(len(self._devices), len(self._test_buckets))) | 431 device_indices = range(min(len(self._devices), len(self._test_buckets))) |
| 432 if self._no_device_tests: |
| 433 device_indices.append(None) |
| 354 shards = parallelizer.Parallelizer(device_indices).pMap(run_perf_tests) | 434 shards = parallelizer.Parallelizer(device_indices).pMap(run_perf_tests) |
| 355 return [x for x in shards.pGet(self._timeout) if x is not None] | 435 return [x for x in shards.pGet(self._timeout) if x is not None] |
| 356 | 436 |
| 357 # override | 437 # override |
| 358 def TestPackage(self): | 438 def TestPackage(self): |
| 359 return 'perf' | 439 return 'perf' |
| 360 | 440 |
| 361 # override | 441 # override |
| 362 def _CreateShards(self, _tests): | 442 def _CreateShards(self, _tests): |
| 363 raise NotImplementedError | 443 raise NotImplementedError |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 417 # override | 497 # override |
| 418 def _RunTest(self, _device, _test): | 498 def _RunTest(self, _device, _test): |
| 419 raise NotImplementedError | 499 raise NotImplementedError |
| 420 | 500 |
| 421 | 501 |
| 422 class TestDictVersionError(Exception): | 502 class TestDictVersionError(Exception): |
| 423 pass | 503 pass |
| 424 | 504 |
| 425 class PerfTestRunGetStepsError(Exception): | 505 class PerfTestRunGetStepsError(Exception): |
| 426 pass | 506 pass |
| OLD | NEW |