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

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

Issue 2737223002: Revert of Add failure screenshots and render test images to results detail. (Closed)
Patch Set: Created 3 years, 9 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
OLDNEW
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 tempfile
10 import time 9 import time
11 10
12 from devil.android import device_errors 11 from devil.android import device_errors
13 from devil.android import flag_changer 12 from devil.android import flag_changer
14 from devil.android.sdk import shared_prefs 13 from devil.android.sdk import shared_prefs
15 from devil.utils import reraiser_thread 14 from devil.utils import reraiser_thread
16 from pylib import valgrind_tools 15 from pylib import valgrind_tools
17 from pylib.android import logdog_logcat_monitor 16 from pylib.android import logdog_logcat_monitor
18 from pylib.constants import host_paths
19 from pylib.base import base_test_result 17 from pylib.base import base_test_result
20 from pylib.instrumentation import instrumentation_test_instance 18 from pylib.instrumentation import instrumentation_test_instance
21 from pylib.local.device import local_device_environment 19 from pylib.local.device import local_device_environment
22 from pylib.local.device import local_device_test_run 20 from pylib.local.device import local_device_test_run
23 from pylib.utils import google_storage_helper
24 from pylib.utils import logdog_helper 21 from pylib.utils import logdog_helper
25 from py_trace_event import trace_event 22 from py_trace_event import trace_event
26 from py_utils import contextlib_ext 23 from py_utils import contextlib_ext
27 from py_utils import tempfile_ext
28 import tombstones 24 import tombstones
29 25
30 try:
31 from PIL import Image # pylint: disable=import-error
32 from PIL import ImageChops # pylint: disable=import-error
33 can_compute_diffs = True
34 except ImportError:
35 can_compute_diffs = False
36
37 _TAG = 'test_runner_py' 26 _TAG = 'test_runner_py'
38 27
39 TIMEOUT_ANNOTATIONS = [ 28 TIMEOUT_ANNOTATIONS = [
40 ('Manual', 10 * 60 * 60), 29 ('Manual', 10 * 60 * 60),
41 ('IntegrationTest', 30 * 60), 30 ('IntegrationTest', 30 * 60),
42 ('External', 10 * 60), 31 ('External', 10 * 60),
43 ('EnormousTest', 10 * 60), 32 ('EnormousTest', 10 * 60),
44 ('LargeTest', 5 * 60), 33 ('LargeTest', 5 * 60),
45 ('MediumTest', 3 * 60), 34 ('MediumTest', 3 * 60),
46 ('SmallTest', 1 * 60), 35 ('SmallTest', 1 * 60),
47 ] 36 ]
48 37
49 _RE_RENDER_IMAGE_NAME = re.compile(
50 r'(?P<test_class>\w+)\.'
51 r'(?P<description>\w+)\.'
52 r'(?P<device_model>\w+)\.'
53 r'(?P<orientation>port|land)\.png')
54
55 RENDER_TESTS_RESULTS_DIR = {
56 'ChromePublicTest': 'chrome/test/data/android/render_tests'
57 }
58 38
59 # TODO(jbudorick): Make this private once the instrumentation test_runner is 39 # TODO(jbudorick): Make this private once the instrumentation test_runner is
60 # deprecated. 40 # deprecated.
61 def DidPackageCrashOnDevice(package_name, device): 41 def DidPackageCrashOnDevice(package_name, device):
62 # Dismiss any error dialogs. Limit the number in case we have an error 42 # Dismiss any error dialogs. Limit the number in case we have an error
63 # loop or we are failing to dismiss. 43 # loop or we are failing to dismiss.
64 try: 44 try:
65 for _ in xrange(10): 45 for _ in xrange(10):
66 package = device.DismissCrashDialogIfNeeded() 46 package = device.DismissCrashDialogIfNeeded()
67 if not package: 47 if not package:
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 # TODO(jbudorick): Make instrumentation tests output a JSON so this 314 # TODO(jbudorick): Make instrumentation tests output a JSON so this
335 # doesn't have to parse the output. 315 # doesn't have to parse the output.
336 result_code, result_bundle, statuses = ( 316 result_code, result_bundle, statuses = (
337 self._test_instance.ParseAmInstrumentRawOutput(output)) 317 self._test_instance.ParseAmInstrumentRawOutput(output))
338 results = self._test_instance.GenerateTestResults( 318 results = self._test_instance.GenerateTestResults(
339 result_code, result_bundle, statuses, start_ms, duration_ms) 319 result_code, result_bundle, statuses, start_ms, duration_ms)
340 for result in results: 320 for result in results:
341 if logcat_url: 321 if logcat_url:
342 result.SetLink('logcat', logcat_url) 322 result.SetLink('logcat', logcat_url)
343 323
344 self._ProcessRenderTestResults(device, results)
345
346 # Update the result name if the test used flags. 324 # Update the result name if the test used flags.
347 if flags: 325 if flags:
348 for r in results: 326 for r in results:
349 if r.GetName() == test_name: 327 if r.GetName() == test_name:
350 r.SetName(test_display_name) 328 r.SetName(test_display_name)
351 329
352 # Add UNKNOWN results for any missing tests. 330 # Add UNKNOWN results for any missing tests.
353 iterable_test = test if isinstance(test, list) else [test] 331 iterable_test = test if isinstance(test, list) else [test]
354 test_names = set(self._GetUniqueTestName(t) for t in iterable_test) 332 test_names = set(self._GetUniqueTestName(t) for t in iterable_test)
355 results_names = set(r.GetName() for r in results) 333 results_names = set(r.GetName() for r in results)
(...skipping 11 matching lines...) Expand all
367 # - optionally taking a screenshot 345 # - optionally taking a screenshot
368 # - logging the raw output at INFO level 346 # - logging the raw output at INFO level
369 # - clearing the application state while persisting permissions 347 # - clearing the application state while persisting permissions
370 if any(r.GetType() not in (base_test_result.ResultType.PASS, 348 if any(r.GetType() not in (base_test_result.ResultType.PASS,
371 base_test_result.ResultType.SKIP) 349 base_test_result.ResultType.SKIP)
372 for r in results): 350 for r in results):
373 if self._test_instance.screenshot_dir: 351 if self._test_instance.screenshot_dir:
374 file_name = '%s-%s.png' % ( 352 file_name = '%s-%s.png' % (
375 test_display_name, 353 test_display_name,
376 time.strftime('%Y%m%dT%H%M%S', time.localtime())) 354 time.strftime('%Y%m%dT%H%M%S', time.localtime()))
377 screenshot_file = device.TakeScreenshot( 355 saved_dir = device.TakeScreenshot(
378 os.path.join(self._test_instance.screenshot_dir, file_name)) 356 os.path.join(self._test_instance.screenshot_dir, file_name))
379 logging.info( 357 logging.info(
380 'Saved screenshot for %s to %s.', 358 'Saved screenshot for %s to %s.',
381 test_display_name, screenshot_file) 359 test_display_name, saved_dir)
382 if self._test_instance.should_save_images:
383 link = google_storage_helper.upload(
384 google_storage_helper.unique_name('screenshot', device=device),
385 screenshot_file,
386 bucket='chromium-render-tests')
387 for result in results:
388 result.SetLink('failure_screenshot', link)
389
390 logging.info('detected failure in %s. raw output:', test_display_name) 360 logging.info('detected failure in %s. raw output:', test_display_name)
391 for l in output: 361 for l in output:
392 logging.info(' %s', l) 362 logging.info(' %s', l)
393 if (not self._env.skip_clear_data 363 if (not self._env.skip_clear_data
394 and self._test_instance.package_info): 364 and self._test_instance.package_info):
395 permissions = ( 365 permissions = (
396 self._test_instance.apk_under_test.GetPermissions() 366 self._test_instance.apk_under_test.GetPermissions()
397 if self._test_instance.apk_under_test 367 if self._test_instance.apk_under_test
398 else None) 368 else None)
399 device.ClearApplicationState(self._test_instance.package_info.package, 369 device.ClearApplicationState(self._test_instance.package_info.package,
400 permissions=permissions) 370 permissions=permissions)
371
401 else: 372 else:
402 logging.debug('raw output from %s:', test_display_name) 373 logging.debug('raw output from %s:', test_display_name)
403 for l in output: 374 for l in output:
404 logging.debug(' %s', l) 375 logging.debug(' %s', l)
405 if self._test_instance.coverage_directory: 376 if self._test_instance.coverage_directory:
406 device.PullFile(coverage_directory, 377 device.PullFile(coverage_directory,
407 self._test_instance.coverage_directory) 378 self._test_instance.coverage_directory)
408 device.RunShellCommand('rm -f %s' % os.path.join(coverage_directory, 379 device.RunShellCommand('rm -f %s' % os.path.join(coverage_directory,
409 '*')) 380 '*'))
410 if self._test_instance.store_tombstones: 381 if self._test_instance.store_tombstones:
411 tombstones_url = None 382 tombstones_url = None
412 for result in results: 383 for result in results:
413 if result.GetType() == base_test_result.ResultType.CRASH: 384 if result.GetType() == base_test_result.ResultType.CRASH:
414 if not tombstones_url: 385 if not tombstones_url:
415 resolved_tombstones = tombstones.ResolveTombstones( 386 resolved_tombstones = tombstones.ResolveTombstones(
416 device, 387 device,
417 resolve_all_tombstones=True, 388 resolve_all_tombstones=True,
418 include_stack_symbols=False, 389 include_stack_symbols=False,
419 wipe_tombstones=True) 390 wipe_tombstones=True)
420 stream_name = 'tombstones_%s_%s' % ( 391 stream_name = 'tombstones_%s_%s' % (
421 time.strftime('%Y%m%dT%H%M%S', time.localtime()), 392 time.strftime('%Y%m%dT%H%M%S', time.localtime()),
422 device.serial) 393 device.serial)
423 tombstones_url = logdog_helper.text( 394 tombstones_url = logdog_helper.text(
424 stream_name, resolved_tombstones) 395 stream_name, resolved_tombstones)
425 result.SetLink('tombstones', tombstones_url) 396 result.SetLink('tombstones', tombstones_url)
426 return results, None 397 return results, None
427 398
428 def _ProcessRenderTestResults(self, device, results):
429 render_results_dir = RENDER_TESTS_RESULTS_DIR.get(self._test_instance.suite)
430 if not render_results_dir:
431 return
432
433 failure_images_device_dir = posixpath.join(
434 device.GetExternalStoragePath(),
435 'chromium_tests_root', render_results_dir, 'failures')
436 if not device.FileExists(failure_images_device_dir):
437 return
438
439 if self._test_instance.should_save_images:
440 with tempfile_ext.NamedTemporaryDirectory() as temp_dir:
441 device.PullFile(failure_images_device_dir, temp_dir)
442 device.RemovePath(failure_images_device_dir, recursive=True)
443
444 for failure_filename in os.listdir(
445 os.path.join(temp_dir, 'failures')):
446
447 m = _RE_RENDER_IMAGE_NAME.match(failure_filename)
448 if not m:
449 logging.warning('Unexpected file in render test failures: %s',
450 failure_filename)
451 continue
452
453 failure_filepath = os.path.join(
454 temp_dir, 'failures', failure_filename)
455 failure_link = google_storage_helper.upload(
456 google_storage_helper.unique_name(
457 failure_filename, device=device),
458 failure_filepath,
459 bucket='chromium-render-tests')
460
461 golden_filepath = os.path.join(
462 host_paths.DIR_SOURCE_ROOT, render_results_dir,
463 failure_filename)
464 if not os.path.exists(golden_filepath):
465 logging.error('Cannot find golden image for %s', failure_filename)
466 continue
467 golden_link = google_storage_helper.upload(
468 google_storage_helper.unique_name(
469 failure_filename, device=device),
470 golden_filepath,
471 bucket='chromium-render-tests')
472
473 if can_compute_diffs:
474 diff_filename = '_diff'.join(
475 os.path.splitext(failure_filename))
476 diff_filepath = os.path.join(temp_dir, diff_filename)
477 (ImageChops.difference(
478 Image.open(failure_filepath), Image.open(golden_filepath))
479 .convert('L')
480 .point(lambda i: 255 if i else 0)
481 .save(diff_filepath))
482 diff_link = google_storage_helper.upload(
483 google_storage_helper.unique_name(
484 diff_filename, device=device),
485 diff_filepath,
486 bucket='chromium-render-tests')
487 else:
488 diff_link = ''
489 logging.error('Error importing PIL library. Image diffs for '
490 'render test results will not be computed.')
491
492 with tempfile.NamedTemporaryFile(suffix='.html') as temp_html:
493 temp_html.write('''
494 <html>
495 <table>
496 <tr>
497 <th>Failure</th>
498 <th>Golden</th>
499 <th>Diff</th>
500 </tr>
501 <tr>
502 <td><img src="%s"/></td>
503 <td><img src="%s"/></td>
504 <td><img src="%s"/></td>
505 </tr>
506 </table>
507 </html>
508 ''' % (failure_link, golden_link, diff_link))
509 html_results_link = google_storage_helper.upload(
510 google_storage_helper.unique_name(
511 'render_html', device=device),
512 temp_html.name,
513 bucket='chromium-render-tests')
514 for result in results:
515 result.SetLink(failure_filename, html_results_link)
516
517 #override 399 #override
518 def _ShouldRetry(self, test): 400 def _ShouldRetry(self, test):
519 if 'RetryOnFailure' in test.get('annotations', {}): 401 if 'RetryOnFailure' in test.get('annotations', {}):
520 return True 402 return True
521 403
522 # TODO(jbudorick): Remove this log message once @RetryOnFailure has been 404 # TODO(jbudorick): Remove this log message once @RetryOnFailure has been
523 # enabled for a while. See crbug.com/619055 for more details. 405 # enabled for a while. See crbug.com/619055 for more details.
524 logging.error('Default retries are being phased out. crbug.com/619055') 406 logging.error('Default retries are being phased out. crbug.com/619055')
525 return False 407 return False
526 408
(...skipping 16 matching lines...) Expand all
543 timeout = v 425 timeout = v
544 break 426 break
545 else: 427 else:
546 logging.warning('Using default 1 minute timeout for %s', test_name) 428 logging.warning('Using default 1 minute timeout for %s', test_name)
547 timeout = 60 429 timeout = 60
548 430
549 timeout *= cls._GetTimeoutScaleFromAnnotations(annotations) 431 timeout *= cls._GetTimeoutScaleFromAnnotations(annotations)
550 432
551 return timeout 433 return timeout
552 434
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698