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 device_temp_file |
12 from devil.android import flag_changer | 13 from devil.android import flag_changer |
13 from devil.android.sdk import shared_prefs | 14 from devil.android.sdk import shared_prefs |
14 from devil.utils import reraiser_thread | 15 from devil.utils import reraiser_thread |
15 from pylib import valgrind_tools | 16 from pylib import valgrind_tools |
16 from pylib.android import logdog_logcat_monitor | 17 from pylib.android import logdog_logcat_monitor |
17 from pylib.base import base_test_result | 18 from pylib.base import base_test_result |
18 from pylib.instrumentation import instrumentation_test_instance | 19 from pylib.instrumentation import instrumentation_test_instance |
19 from pylib.local.device import local_device_environment | 20 from pylib.local.device import local_device_environment |
20 from pylib.local.device import local_device_test_run | 21 from pylib.local.device import local_device_test_run |
21 from pylib.utils import google_storage_helper | 22 from pylib.utils import google_storage_helper |
(...skipping 10 matching lines...) Expand all Loading... |
32 ('IntegrationTest', 30 * 60), | 33 ('IntegrationTest', 30 * 60), |
33 ('External', 10 * 60), | 34 ('External', 10 * 60), |
34 ('EnormousTest', 10 * 60), | 35 ('EnormousTest', 10 * 60), |
35 ('LargeTest', 5 * 60), | 36 ('LargeTest', 5 * 60), |
36 ('MediumTest', 3 * 60), | 37 ('MediumTest', 3 * 60), |
37 ('SmallTest', 1 * 60), | 38 ('SmallTest', 1 * 60), |
38 ] | 39 ] |
39 | 40 |
40 LOGCAT_FILTERS = ['*:e', 'chromium:v', 'cr_*:v'] | 41 LOGCAT_FILTERS = ['*:e', 'chromium:v', 'cr_*:v'] |
41 | 42 |
| 43 EXTRA_SCREENSHOT_FILE = ( |
| 44 'org.chromium.base.test.ScreenshotOnFailureStatement.ScreenshotFile') |
42 | 45 |
43 # TODO(jbudorick): Make this private once the instrumentation test_runner is | 46 # TODO(jbudorick): Make this private once the instrumentation test_runner is |
44 # deprecated. | 47 # deprecated. |
45 def DidPackageCrashOnDevice(package_name, device): | 48 def DidPackageCrashOnDevice(package_name, device): |
46 # Dismiss any error dialogs. Limit the number in case we have an error | 49 # Dismiss any error dialogs. Limit the number in case we have an error |
47 # loop or we are failing to dismiss. | 50 # loop or we are failing to dismiss. |
48 try: | 51 try: |
49 for _ in xrange(10): | 52 for _ in xrange(10): |
50 package = device.DismissCrashDialogIfNeeded() | 53 package = device.DismissCrashDialogIfNeeded() |
51 if not package: | 54 if not package: |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 def set_debug_app(): | 128 def set_debug_app(): |
126 # Set debug app in order to enable reading command line flags on user | 129 # Set debug app in order to enable reading command line flags on user |
127 # builds | 130 # builds |
128 if self._test_instance.flags: | 131 if self._test_instance.flags: |
129 if not self._test_instance.package_info: | 132 if not self._test_instance.package_info: |
130 logging.error("Couldn't set debug app: no package info") | 133 logging.error("Couldn't set debug app: no package info") |
131 elif not self._test_instance.package_info.package: | 134 elif not self._test_instance.package_info.package: |
132 logging.error("Couldn't set debug app: no package defined") | 135 logging.error("Couldn't set debug app: no package defined") |
133 else: | 136 else: |
134 dev.RunShellCommand(['am', 'set-debug-app', '--persistent', | 137 dev.RunShellCommand(['am', 'set-debug-app', '--persistent', |
135 self._test_instance.package_info.package], | 138 self._test_instance.package_info.package], |
136 check_return=True) | 139 check_return=True) |
137 @trace_event.traced | 140 @trace_event.traced |
138 def edit_shared_prefs(): | 141 def edit_shared_prefs(): |
139 for pref in self._test_instance.edit_shared_prefs: | 142 for pref in self._test_instance.edit_shared_prefs: |
140 prefs = shared_prefs.SharedPrefs(dev, pref['package'], | 143 prefs = shared_prefs.SharedPrefs(dev, pref['package'], |
141 pref['filename']) | 144 pref['filename']) |
142 prefs.Load() | 145 prefs.Load() |
143 for key in pref.get('remove', []): | 146 for key in pref.get('remove', []): |
144 try: | 147 try: |
145 prefs.Remove(key) | 148 prefs.Remove(key) |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 test_timeout_scale = None | 253 test_timeout_scale = None |
251 if self._test_instance.coverage_directory: | 254 if self._test_instance.coverage_directory: |
252 coverage_basename = '%s.ec' % ('%s_group' % test[0]['method'] | 255 coverage_basename = '%s.ec' % ('%s_group' % test[0]['method'] |
253 if isinstance(test, list) else test['method']) | 256 if isinstance(test, list) else test['method']) |
254 extras['coverage'] = 'true' | 257 extras['coverage'] = 'true' |
255 coverage_directory = os.path.join( | 258 coverage_directory = os.path.join( |
256 device.GetExternalStoragePath(), 'chrome', 'test', 'coverage') | 259 device.GetExternalStoragePath(), 'chrome', 'test', 'coverage') |
257 coverage_device_file = os.path.join( | 260 coverage_device_file = os.path.join( |
258 coverage_directory, coverage_basename) | 261 coverage_directory, coverage_basename) |
259 extras['coverageFile'] = coverage_device_file | 262 extras['coverageFile'] = coverage_device_file |
| 263 # Save screenshot if screenshot dir is specified (save locally) or if |
| 264 # a GS bucket is passed (save in cloud). |
| 265 screenshot_device_file = None |
| 266 if (self._test_instance.screenshot_dir or |
| 267 self._test_instance.gs_results_bucket): |
| 268 screenshot_device_file = device_temp_file.DeviceTempFile( |
| 269 device.adb, suffix='.png', dir=device.GetExternalStoragePath()) |
| 270 extras[EXTRA_SCREENSHOT_FILE] = screenshot_device_file.name |
260 | 271 |
261 if isinstance(test, list): | 272 if isinstance(test, list): |
262 if not self._test_instance.driver_apk: | 273 if not self._test_instance.driver_apk: |
263 raise Exception('driver_apk does not exist. ' | 274 raise Exception('driver_apk does not exist. ' |
264 'Please build it and try again.') | 275 'Please build it and try again.') |
265 if any(t.get('is_junit4') for t in test): | 276 if any(t.get('is_junit4') for t in test): |
266 raise Exception('driver apk does not support JUnit4 tests') | 277 raise Exception('driver apk does not support JUnit4 tests') |
267 | 278 |
268 def name_and_timeout(t): | 279 def name_and_timeout(t): |
269 n = instrumentation_test_instance.GetTestName(t) | 280 n = instrumentation_test_instance.GetTestName(t) |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 # - clearing the application state while persisting permissions | 390 # - clearing the application state while persisting permissions |
380 if any(r.GetType() not in (base_test_result.ResultType.PASS, | 391 if any(r.GetType() not in (base_test_result.ResultType.PASS, |
381 base_test_result.ResultType.SKIP) | 392 base_test_result.ResultType.SKIP) |
382 for r in results): | 393 for r in results): |
383 with contextlib_ext.Optional( | 394 with contextlib_ext.Optional( |
384 tempfile_ext.NamedTemporaryDirectory(), | 395 tempfile_ext.NamedTemporaryDirectory(), |
385 self._test_instance.screenshot_dir is None and | 396 self._test_instance.screenshot_dir is None and |
386 self._test_instance.gs_results_bucket) as screenshot_host_dir: | 397 self._test_instance.gs_results_bucket) as screenshot_host_dir: |
387 screenshot_host_dir = ( | 398 screenshot_host_dir = ( |
388 self._test_instance.screenshot_dir or screenshot_host_dir) | 399 self._test_instance.screenshot_dir or screenshot_host_dir) |
389 if screenshot_host_dir: | 400 self._SaveScreenshot(device, screenshot_host_dir, |
390 file_name = '%s-%s.png' % ( | 401 screenshot_device_file, test_display_name, |
391 test_display_name, | 402 results) |
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 | 403 |
406 logging.info('detected failure in %s. raw output:', test_display_name) | 404 logging.info('detected failure in %s. raw output:', test_display_name) |
407 for l in output: | 405 for l in output: |
408 logging.info(' %s', l) | 406 logging.info(' %s', l) |
409 if (not self._env.skip_clear_data | 407 if (not self._env.skip_clear_data |
410 and self._test_instance.package_info): | 408 and self._test_instance.package_info): |
411 permissions = ( | 409 permissions = ( |
412 self._test_instance.apk_under_test.GetPermissions() | 410 self._test_instance.apk_under_test.GetPermissions() |
413 if self._test_instance.apk_under_test | 411 if self._test_instance.apk_under_test |
414 else None) | 412 else None) |
(...skipping 20 matching lines...) Expand all Loading... |
435 include_stack_symbols=False, | 433 include_stack_symbols=False, |
436 wipe_tombstones=True) | 434 wipe_tombstones=True) |
437 stream_name = 'tombstones_%s_%s' % ( | 435 stream_name = 'tombstones_%s_%s' % ( |
438 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()), | 436 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()), |
439 device.serial) | 437 device.serial) |
440 tombstones_url = logdog_helper.text( | 438 tombstones_url = logdog_helper.text( |
441 stream_name, '\n'.join(resolved_tombstones)) | 439 stream_name, '\n'.join(resolved_tombstones)) |
442 result.SetLink('tombstones', tombstones_url) | 440 result.SetLink('tombstones', tombstones_url) |
443 return results, None | 441 return results, None |
444 | 442 |
| 443 def _SaveScreenshot(self, device, screenshot_host_dir, screenshot_device_file, |
| 444 test_name, results): |
| 445 if screenshot_host_dir: |
| 446 screenshot_host_file = os.path.join( |
| 447 screenshot_host_dir, |
| 448 '%s-%s.png' % ( |
| 449 test_name, |
| 450 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()))) |
| 451 if device.FileExists(screenshot_device_file.name): |
| 452 try: |
| 453 device.PullFile(screenshot_device_file.name, screenshot_host_file) |
| 454 finally: |
| 455 screenshot_device_file.close() |
| 456 |
| 457 logging.info( |
| 458 'Saved screenshot for %s to %s.', |
| 459 test_name, screenshot_host_file) |
| 460 if self._test_instance.gs_results_bucket: |
| 461 link = google_storage_helper.upload( |
| 462 google_storage_helper.unique_name( |
| 463 'screenshot', device=device), |
| 464 screenshot_host_file, |
| 465 bucket=('%s/screenshots' % |
| 466 self._test_instance.gs_results_bucket)) |
| 467 for result in results: |
| 468 result.SetLink('post_test_screenshot', link) |
| 469 |
445 #override | 470 #override |
446 def _ShouldRetry(self, test): | 471 def _ShouldRetry(self, test): |
447 if 'RetryOnFailure' in test.get('annotations', {}): | 472 if 'RetryOnFailure' in test.get('annotations', {}): |
448 return True | 473 return True |
449 | 474 |
450 # TODO(jbudorick): Remove this log message once @RetryOnFailure has been | 475 # TODO(jbudorick): Remove this log message once @RetryOnFailure has been |
451 # enabled for a while. See crbug.com/619055 for more details. | 476 # enabled for a while. See crbug.com/619055 for more details. |
452 logging.error('Default retries are being phased out. crbug.com/619055') | 477 logging.error('Default retries are being phased out. crbug.com/619055') |
453 return False | 478 return False |
454 | 479 |
(...skipping 15 matching lines...) Expand all Loading... |
470 if k in annotations: | 495 if k in annotations: |
471 timeout = v | 496 timeout = v |
472 break | 497 break |
473 else: | 498 else: |
474 logging.warning('Using default 1 minute timeout for %s', test_name) | 499 logging.warning('Using default 1 minute timeout for %s', test_name) |
475 timeout = 60 | 500 timeout = 60 |
476 | 501 |
477 timeout *= cls._GetTimeoutScaleFromAnnotations(annotations) | 502 timeout *= cls._GetTimeoutScaleFromAnnotations(annotations) |
478 | 503 |
479 return timeout | 504 return timeout |
OLD | NEW |