| OLD | NEW |
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 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 logging | 5 import logging |
| 6 import os | 6 import os |
| 7 import posixpath | 7 import posixpath |
| 8 import re | 8 import re |
| 9 import time | 9 import time |
| 10 | 10 |
| 11 from devil.android import device_errors | 11 from devil.android import device_errors |
| 12 from devil.android import flag_changer | 12 from devil.android import flag_changer |
| 13 from devil.android.sdk import shared_prefs | 13 from devil.android.sdk import shared_prefs |
| 14 from devil.utils import reraiser_thread | 14 from devil.utils import reraiser_thread |
| 15 from pylib import valgrind_tools | 15 from pylib import valgrind_tools |
| 16 from pylib.android import logdog_logcat_monitor | 16 from pylib.android import logdog_logcat_monitor |
| 17 from pylib.base import base_test_result | 17 from pylib.base import base_test_result |
| 18 from pylib.instrumentation import instrumentation_test_instance | 18 from pylib.instrumentation import instrumentation_test_instance |
| 19 from pylib.local.device import local_device_environment | 19 from pylib.local.device import local_device_environment |
| 20 from pylib.local.device import local_device_test_run | 20 from pylib.local.device import local_device_test_run |
| 21 from pylib.utils import google_storage_helper |
| 21 from pylib.utils import logdog_helper | 22 from pylib.utils import logdog_helper |
| 22 from py_trace_event import trace_event | 23 from py_trace_event import trace_event |
| 23 from py_utils import contextlib_ext | 24 from py_utils import contextlib_ext |
| 25 from py_utils import tempfile_ext |
| 24 import tombstones | 26 import tombstones |
| 25 | 27 |
| 26 _TAG = 'test_runner_py' | 28 _TAG = 'test_runner_py' |
| 27 | 29 |
| 28 TIMEOUT_ANNOTATIONS = [ | 30 TIMEOUT_ANNOTATIONS = [ |
| 29 ('Manual', 10 * 60 * 60), | 31 ('Manual', 10 * 60 * 60), |
| 30 ('IntegrationTest', 30 * 60), | 32 ('IntegrationTest', 30 * 60), |
| 31 ('External', 10 * 60), | 33 ('External', 10 * 60), |
| 32 ('EnormousTest', 10 * 60), | 34 ('EnormousTest', 10 * 60), |
| 33 ('LargeTest', 5 * 60), | 35 ('LargeTest', 5 * 60), |
| 34 ('MediumTest', 3 * 60), | 36 ('MediumTest', 3 * 60), |
| 35 ('SmallTest', 1 * 60), | 37 ('SmallTest', 1 * 60), |
| 36 ] | 38 ] |
| 37 | 39 |
| 38 LOGCAT_FILTERS = ['*:e', 'chromium:v', 'cr_*:v'] | 40 LOGCAT_FILTERS = ['*:e', 'chromium:v', 'cr_*:v'] |
| 39 | 41 |
| 42 |
| 40 # TODO(jbudorick): Make this private once the instrumentation test_runner is | 43 # TODO(jbudorick): Make this private once the instrumentation test_runner is |
| 41 # deprecated. | 44 # deprecated. |
| 42 def DidPackageCrashOnDevice(package_name, device): | 45 def DidPackageCrashOnDevice(package_name, device): |
| 43 # Dismiss any error dialogs. Limit the number in case we have an error | 46 # Dismiss any error dialogs. Limit the number in case we have an error |
| 44 # loop or we are failing to dismiss. | 47 # loop or we are failing to dismiss. |
| 45 try: | 48 try: |
| 46 for _ in xrange(10): | 49 for _ in xrange(10): |
| 47 package = device.DismissCrashDialogIfNeeded() | 50 package = device.DismissCrashDialogIfNeeded() |
| 48 if not package: | 51 if not package: |
| 49 return False | 52 return False |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 | 312 |
| 310 try: | 313 try: |
| 311 device.RunShellCommand( | 314 device.RunShellCommand( |
| 312 ['log', '-p', 'i', '-t', _TAG, 'START %s' % test_name], | 315 ['log', '-p', 'i', '-t', _TAG, 'START %s' % test_name], |
| 313 check_return=True) | 316 check_return=True) |
| 314 time_ms = lambda: int(time.time() * 1e3) | 317 time_ms = lambda: int(time.time() * 1e3) |
| 315 start_ms = time_ms() | 318 start_ms = time_ms() |
| 316 | 319 |
| 317 stream_name = 'logcat_%s_%s_%s' % ( | 320 stream_name = 'logcat_%s_%s_%s' % ( |
| 318 test_name.replace('#', '.'), | 321 test_name.replace('#', '.'), |
| 319 time.strftime('%Y%m%dT%H%M%S', time.localtime()), | 322 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()), |
| 320 device.serial) | 323 device.serial) |
| 321 logmon = logdog_logcat_monitor.LogdogLogcatMonitor( | 324 logmon = logdog_logcat_monitor.LogdogLogcatMonitor( |
| 322 device.adb, stream_name, filter_specs=LOGCAT_FILTERS) | 325 device.adb, stream_name, filter_specs=LOGCAT_FILTERS) |
| 323 | 326 |
| 324 with contextlib_ext.Optional( | 327 with contextlib_ext.Optional( |
| 325 logmon, self._test_instance.should_save_logcat): | 328 logmon, self._test_instance.should_save_logcat): |
| 326 with contextlib_ext.Optional( | 329 with contextlib_ext.Optional( |
| 327 trace_event.trace(test_name), | 330 trace_event.trace(test_name), |
| 328 self._env.trace_output): | 331 self._env.trace_output): |
| 329 output = device.StartInstrumentation( | 332 output = device.StartInstrumentation( |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 370 if r.GetType() == base_test_result.ResultType.UNKNOWN: | 373 if r.GetType() == base_test_result.ResultType.UNKNOWN: |
| 371 r.SetType(base_test_result.ResultType.CRASH) | 374 r.SetType(base_test_result.ResultType.CRASH) |
| 372 | 375 |
| 373 # Handle failures by: | 376 # Handle failures by: |
| 374 # - optionally taking a screenshot | 377 # - optionally taking a screenshot |
| 375 # - logging the raw output at INFO level | 378 # - logging the raw output at INFO level |
| 376 # - clearing the application state while persisting permissions | 379 # - clearing the application state while persisting permissions |
| 377 if any(r.GetType() not in (base_test_result.ResultType.PASS, | 380 if any(r.GetType() not in (base_test_result.ResultType.PASS, |
| 378 base_test_result.ResultType.SKIP) | 381 base_test_result.ResultType.SKIP) |
| 379 for r in results): | 382 for r in results): |
| 380 if self._test_instance.screenshot_dir: | 383 with contextlib_ext.Optional( |
| 381 file_name = '%s-%s.png' % ( | 384 tempfile_ext.NamedTemporaryDirectory(), |
| 382 test_display_name, | 385 self._test_instance.screenshot_dir is None and |
| 383 time.strftime('%Y%m%dT%H%M%S', time.localtime())) | 386 self._test_instance.gs_results_bucket) as screenshot_host_dir: |
| 384 saved_dir = device.TakeScreenshot( | 387 screenshot_host_dir = ( |
| 385 os.path.join(self._test_instance.screenshot_dir, file_name)) | 388 self._test_instance.screenshot_dir or screenshot_host_dir) |
| 386 logging.info( | 389 if screenshot_host_dir: |
| 387 'Saved screenshot for %s to %s.', | 390 file_name = '%s-%s.png' % ( |
| 388 test_display_name, saved_dir) | 391 test_display_name, |
| 392 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime())) |
| 393 screenshot_file = device.TakeScreenshot( |
| 394 os.path.join(screenshot_host_dir, file_name)) |
| 395 logging.info( |
| 396 'Saved screenshot for %s to %s.', |
| 397 test_display_name, screenshot_file) |
| 398 if self._test_instance.gs_results_bucket: |
| 399 link = google_storage_helper.upload( |
| 400 google_storage_helper.unique_name('screenshot', device=device), |
| 401 screenshot_file, |
| 402 bucket=self._test_instance.gs_results_bucket + '/screenshots') |
| 403 for result in results: |
| 404 result.SetLink('post_test_screenshot', link) |
| 405 |
| 389 logging.info('detected failure in %s. raw output:', test_display_name) | 406 logging.info('detected failure in %s. raw output:', test_display_name) |
| 390 for l in output: | 407 for l in output: |
| 391 logging.info(' %s', l) | 408 logging.info(' %s', l) |
| 392 if (not self._env.skip_clear_data | 409 if (not self._env.skip_clear_data |
| 393 and self._test_instance.package_info): | 410 and self._test_instance.package_info): |
| 394 permissions = ( | 411 permissions = ( |
| 395 self._test_instance.apk_under_test.GetPermissions() | 412 self._test_instance.apk_under_test.GetPermissions() |
| 396 if self._test_instance.apk_under_test | 413 if self._test_instance.apk_under_test |
| 397 else None) | 414 else None) |
| 398 device.ClearApplicationState(self._test_instance.package_info.package, | 415 device.ClearApplicationState(self._test_instance.package_info.package, |
| 399 permissions=permissions) | 416 permissions=permissions) |
| 400 | |
| 401 else: | 417 else: |
| 402 logging.debug('raw output from %s:', test_display_name) | 418 logging.debug('raw output from %s:', test_display_name) |
| 403 for l in output: | 419 for l in output: |
| 404 logging.debug(' %s', l) | 420 logging.debug(' %s', l) |
| 405 if self._test_instance.coverage_directory: | 421 if self._test_instance.coverage_directory: |
| 406 device.PullFile(coverage_directory, | 422 device.PullFile(coverage_directory, |
| 407 self._test_instance.coverage_directory) | 423 self._test_instance.coverage_directory) |
| 408 device.RunShellCommand( | 424 device.RunShellCommand( |
| 409 'rm -f %s' % posixpath.join(coverage_directory, '*'), | 425 'rm -f %s' % posixpath.join(coverage_directory, '*'), |
| 410 check_return=True, shell=True) | 426 check_return=True, shell=True) |
| 411 if self._test_instance.store_tombstones: | 427 if self._test_instance.store_tombstones: |
| 412 tombstones_url = None | 428 tombstones_url = None |
| 413 for result in results: | 429 for result in results: |
| 414 if result.GetType() == base_test_result.ResultType.CRASH: | 430 if result.GetType() == base_test_result.ResultType.CRASH: |
| 415 if not tombstones_url: | 431 if not tombstones_url: |
| 416 resolved_tombstones = tombstones.ResolveTombstones( | 432 resolved_tombstones = tombstones.ResolveTombstones( |
| 417 device, | 433 device, |
| 418 resolve_all_tombstones=True, | 434 resolve_all_tombstones=True, |
| 419 include_stack_symbols=False, | 435 include_stack_symbols=False, |
| 420 wipe_tombstones=True) | 436 wipe_tombstones=True) |
| 421 stream_name = 'tombstones_%s_%s' % ( | 437 stream_name = 'tombstones_%s_%s' % ( |
| 422 time.strftime('%Y%m%dT%H%M%S', time.localtime()), | 438 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()), |
| 423 device.serial) | 439 device.serial) |
| 424 tombstones_url = logdog_helper.text( | 440 tombstones_url = logdog_helper.text( |
| 425 stream_name, '\n'.join(resolved_tombstones)) | 441 stream_name, '\n'.join(resolved_tombstones)) |
| 426 result.SetLink('tombstones', tombstones_url) | 442 result.SetLink('tombstones', tombstones_url) |
| 427 return results, None | 443 return results, None |
| 428 | 444 |
| 429 #override | 445 #override |
| 430 def _ShouldRetry(self, test): | 446 def _ShouldRetry(self, test): |
| 431 if 'RetryOnFailure' in test.get('annotations', {}): | 447 if 'RetryOnFailure' in test.get('annotations', {}): |
| 432 return True | 448 return True |
| (...skipping 21 matching lines...) Expand all Loading... |
| 454 if k in annotations: | 470 if k in annotations: |
| 455 timeout = v | 471 timeout = v |
| 456 break | 472 break |
| 457 else: | 473 else: |
| 458 logging.warning('Using default 1 minute timeout for %s', test_name) | 474 logging.warning('Using default 1 minute timeout for %s', test_name) |
| 459 timeout = 60 | 475 timeout = 60 |
| 460 | 476 |
| 461 timeout *= cls._GetTimeoutScaleFromAnnotations(annotations) | 477 timeout *= cls._GetTimeoutScaleFromAnnotations(annotations) |
| 462 | 478 |
| 463 return timeout | 479 return timeout |
| OLD | NEW |