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 contextlib | 5 import contextlib |
6 import hashlib | 6 import hashlib |
7 import json | 7 import json |
8 import logging | 8 import logging |
9 import os | 9 import os |
10 import posixpath | 10 import posixpath |
11 import re | 11 import re |
12 import sys | 12 import sys |
13 import tempfile | |
14 import time | 13 import time |
15 | 14 |
16 from devil.android import crash_handler | 15 from devil.android import crash_handler |
17 from devil.android import device_errors | 16 from devil.android import device_errors |
18 from devil.android import device_temp_file | 17 from devil.android import device_temp_file |
19 from devil.android import flag_changer | 18 from devil.android import flag_changer |
20 from devil.android.sdk import shared_prefs | 19 from devil.android.sdk import shared_prefs |
| 20 from devil.android import logcat_monitor |
21 from devil.android.tools import system_app | 21 from devil.android.tools import system_app |
22 from devil.utils import reraiser_thread | 22 from devil.utils import reraiser_thread |
23 from incremental_install import installer | 23 from incremental_install import installer |
24 from pylib import valgrind_tools | 24 from pylib import valgrind_tools |
25 from pylib.android import logdog_logcat_monitor | |
26 from pylib.base import base_test_result | 25 from pylib.base import base_test_result |
| 26 from pylib.base import output_manager |
27 from pylib.constants import host_paths | 27 from pylib.constants import host_paths |
28 from pylib.instrumentation import instrumentation_test_instance | 28 from pylib.instrumentation import instrumentation_test_instance |
29 from pylib.local.device import local_device_environment | 29 from pylib.local.device import local_device_environment |
30 from pylib.local.device import local_device_test_run | 30 from pylib.local.device import local_device_test_run |
31 from pylib.utils import google_storage_helper | |
32 from pylib.utils import instrumentation_tracing | 31 from pylib.utils import instrumentation_tracing |
33 from pylib.utils import logdog_helper | |
34 from pylib.utils import shared_preference_utils | 32 from pylib.utils import shared_preference_utils |
| 33 |
35 from py_trace_event import trace_event | 34 from py_trace_event import trace_event |
36 from py_trace_event import trace_time | 35 from py_trace_event import trace_time |
37 from py_utils import contextlib_ext | 36 from py_utils import contextlib_ext |
38 from py_utils import tempfile_ext | 37 from py_utils import tempfile_ext |
39 import tombstones | 38 import tombstones |
40 | 39 |
41 with host_paths.SysPath( | 40 with host_paths.SysPath( |
42 os.path.join(host_paths.DIR_SOURCE_ROOT, 'third_party'), 0): | 41 os.path.join(host_paths.DIR_SOURCE_ROOT, 'third_party'), 0): |
43 import jinja2 # pylint: disable=import-error | 42 import jinja2 # pylint: disable=import-error |
44 import markupsafe # pylint: disable=import-error,unused-import | 43 import markupsafe # pylint: disable=import-error,unused-import |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
118 return False | 117 return False |
119 | 118 |
120 | 119 |
121 _CURRENT_FOCUS_CRASH_RE = re.compile( | 120 _CURRENT_FOCUS_CRASH_RE = re.compile( |
122 r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}') | 121 r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}') |
123 | 122 |
124 | 123 |
125 class LocalDeviceInstrumentationTestRun( | 124 class LocalDeviceInstrumentationTestRun( |
126 local_device_test_run.LocalDeviceTestRun): | 125 local_device_test_run.LocalDeviceTestRun): |
127 def __init__(self, env, test_instance): | 126 def __init__(self, env, test_instance): |
128 super(LocalDeviceInstrumentationTestRun, self).__init__(env, test_instance) | 127 super(LocalDeviceInstrumentationTestRun, self).__init__( |
| 128 env, test_instance) |
129 self._flag_changers = {} | 129 self._flag_changers = {} |
130 self._ui_capture_dir = dict() | 130 self._ui_capture_dir = dict() |
131 self._replace_package_contextmanager = None | 131 self._replace_package_contextmanager = None |
132 | 132 |
133 #override | 133 #override |
134 def TestPackage(self): | 134 def TestPackage(self): |
135 return self._test_instance.suite | 135 return self._test_instance.suite |
136 | 136 |
137 #override | 137 #override |
138 def SetUp(self): | 138 def SetUp(self): |
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 coverage_basename = '%s.ec' % ('%s_group' % test[0]['method'] | 355 coverage_basename = '%s.ec' % ('%s_group' % test[0]['method'] |
356 if isinstance(test, list) else test['method']) | 356 if isinstance(test, list) else test['method']) |
357 extras['coverage'] = 'true' | 357 extras['coverage'] = 'true' |
358 coverage_directory = os.path.join( | 358 coverage_directory = os.path.join( |
359 device.GetExternalStoragePath(), 'chrome', 'test', 'coverage') | 359 device.GetExternalStoragePath(), 'chrome', 'test', 'coverage') |
360 coverage_device_file = os.path.join( | 360 coverage_device_file = os.path.join( |
361 coverage_directory, coverage_basename) | 361 coverage_directory, coverage_basename) |
362 extras['coverageFile'] = coverage_device_file | 362 extras['coverageFile'] = coverage_device_file |
363 # Save screenshot if screenshot dir is specified (save locally) or if | 363 # Save screenshot if screenshot dir is specified (save locally) or if |
364 # a GS bucket is passed (save in cloud). | 364 # a GS bucket is passed (save in cloud). |
365 screenshot_device_file = None | 365 screenshot_device_file = device_temp_file.DeviceTempFile( |
366 if (self._test_instance.screenshot_dir or | 366 device.adb, suffix='.png', dir=device.GetExternalStoragePath()) |
367 self._test_instance.gs_results_bucket): | 367 extras[EXTRA_SCREENSHOT_FILE] = screenshot_device_file.name |
368 screenshot_device_file = device_temp_file.DeviceTempFile( | |
369 device.adb, suffix='.png', dir=device.GetExternalStoragePath()) | |
370 extras[EXTRA_SCREENSHOT_FILE] = screenshot_device_file.name | |
371 | 368 |
372 extras[EXTRA_UI_CAPTURE_DIR] = self._ui_capture_dir[device] | 369 extras[EXTRA_UI_CAPTURE_DIR] = self._ui_capture_dir[device] |
373 | 370 |
374 if self._env.trace_output: | 371 if self._env.trace_output: |
375 trace_device_file = device_temp_file.DeviceTempFile( | 372 trace_device_file = device_temp_file.DeviceTempFile( |
376 device.adb, suffix='.json', dir=device.GetExternalStoragePath()) | 373 device.adb, suffix='.json', dir=device.GetExternalStoragePath()) |
377 extras[EXTRA_TRACE_FILE] = trace_device_file.name | 374 extras[EXTRA_TRACE_FILE] = trace_device_file.name |
378 | 375 |
379 if isinstance(test, list): | 376 if isinstance(test, list): |
380 if not self._test_instance.driver_apk: | 377 if not self._test_instance.driver_apk: |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 self._CreateFlagChangerIfNeeded(device) | 434 self._CreateFlagChangerIfNeeded(device) |
438 self._flag_changers[str(device)].PushFlags(add=flags_to_add) | 435 self._flag_changers[str(device)].PushFlags(add=flags_to_add) |
439 | 436 |
440 time_ms = lambda: int(time.time() * 1e3) | 437 time_ms = lambda: int(time.time() * 1e3) |
441 start_ms = time_ms() | 438 start_ms = time_ms() |
442 | 439 |
443 stream_name = 'logcat_%s_%s_%s' % ( | 440 stream_name = 'logcat_%s_%s_%s' % ( |
444 test_name.replace('#', '.'), | 441 test_name.replace('#', '.'), |
445 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()), | 442 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()), |
446 device.serial) | 443 device.serial) |
447 logmon = logdog_logcat_monitor.LogdogLogcatMonitor( | |
448 device.adb, stream_name, filter_specs=LOGCAT_FILTERS) | |
449 | 444 |
450 with contextlib_ext.Optional( | 445 with self._env.output_manager.ArchivedTempfile( |
451 logmon, self._test_instance.should_save_logcat): | 446 stream_name, 'logcat') as logcat_file: |
452 with _LogTestEndpoints(device, test_name): | 447 with logcat_monitor.LogcatMonitor( |
453 with contextlib_ext.Optional( | 448 device.adb, filter_specs=LOGCAT_FILTERS, |
454 trace_event.trace(test_name), | 449 output_file=logcat_file.name) as logmon: |
455 self._env.trace_output): | 450 with _LogTestEndpoints(device, test_name): |
456 output = device.StartInstrumentation( | 451 with contextlib_ext.Optional( |
457 target, raw=True, extras=extras, timeout=timeout, retries=0) | 452 trace_event.trace(test_name), |
| 453 self._env.trace_output): |
| 454 output = device.StartInstrumentation( |
| 455 target, raw=True, extras=extras, timeout=timeout, retries=0) |
| 456 logmon.Close() |
458 | 457 |
459 logcat_url = logmon.GetLogcatURL() | |
460 duration_ms = time_ms() - start_ms | 458 duration_ms = time_ms() - start_ms |
461 | 459 |
462 if self._env.trace_output: | 460 if self._env.trace_output: |
463 self._SaveTraceData(trace_device_file, device, test['class']) | 461 self._SaveTraceData(trace_device_file, device, test['class']) |
464 | 462 |
465 # TODO(jbudorick): Make instrumentation tests output a JSON so this | 463 # TODO(jbudorick): Make instrumentation tests output a JSON so this |
466 # doesn't have to parse the output. | 464 # doesn't have to parse the output. |
467 result_code, result_bundle, statuses = ( | 465 result_code, result_bundle, statuses = ( |
468 self._test_instance.ParseAmInstrumentRawOutput(output)) | 466 self._test_instance.ParseAmInstrumentRawOutput(output)) |
469 results = self._test_instance.GenerateTestResults( | 467 results = self._test_instance.GenerateTestResults( |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
507 handle_coverage_data, handle_render_test_data] | 505 handle_coverage_data, handle_render_test_data] |
508 if self._env.concurrent_adb: | 506 if self._env.concurrent_adb: |
509 post_test_step_thread_group = reraiser_thread.ReraiserThreadGroup( | 507 post_test_step_thread_group = reraiser_thread.ReraiserThreadGroup( |
510 reraiser_thread.ReraiserThread(f) for f in post_test_steps) | 508 reraiser_thread.ReraiserThread(f) for f in post_test_steps) |
511 post_test_step_thread_group.StartAll(will_block=True) | 509 post_test_step_thread_group.StartAll(will_block=True) |
512 else: | 510 else: |
513 for step in post_test_steps: | 511 for step in post_test_steps: |
514 step() | 512 step() |
515 | 513 |
516 for result in results: | 514 for result in results: |
517 if logcat_url: | 515 if logcat_file: |
518 result.SetLink('logcat', logcat_url) | 516 result.SetLink('logcat', logcat_file.Link()) |
519 | 517 |
520 # Update the result name if the test used flags. | 518 # Update the result name if the test used flags. |
521 if flags_to_add: | 519 if flags_to_add: |
522 for r in results: | 520 for r in results: |
523 if r.GetName() == test_name: | 521 if r.GetName() == test_name: |
524 r.SetName(test_display_name) | 522 r.SetName(test_display_name) |
525 | 523 |
526 # Add UNKNOWN results for any missing tests. | 524 # Add UNKNOWN results for any missing tests. |
527 iterable_test = test if isinstance(test, list) else [test] | 525 iterable_test = test if isinstance(test, list) else [test] |
528 test_names = set(self._GetUniqueTestName(t) for t in iterable_test) | 526 test_names = set(self._GetUniqueTestName(t) for t in iterable_test) |
529 results_names = set(r.GetName() for r in results) | 527 results_names = set(r.GetName() for r in results) |
530 results.extend( | 528 results.extend( |
531 base_test_result.BaseTestResult(u, base_test_result.ResultType.UNKNOWN) | 529 base_test_result.BaseTestResult(u, base_test_result.ResultType.UNKNOWN) |
532 for u in test_names.difference(results_names)) | 530 for u in test_names.difference(results_names)) |
533 | 531 |
534 # Update the result type if we detect a crash. | 532 # Update the result type if we detect a crash. |
535 if DidPackageCrashOnDevice(self._test_instance.test_package, device): | 533 if DidPackageCrashOnDevice(self._test_instance.test_package, device): |
536 for r in results: | 534 for r in results: |
537 if r.GetType() == base_test_result.ResultType.UNKNOWN: | 535 if r.GetType() == base_test_result.ResultType.UNKNOWN: |
538 r.SetType(base_test_result.ResultType.CRASH) | 536 r.SetType(base_test_result.ResultType.CRASH) |
539 | 537 |
540 # Handle failures by: | 538 # Handle failures by: |
541 # - optionally taking a screenshot | 539 # - optionally taking a screenshot |
542 # - logging the raw output at INFO level | 540 # - logging the raw output at INFO level |
543 # - clearing the application state while persisting permissions | 541 # - clearing the application state while persisting permissions |
544 if any(r.GetType() not in (base_test_result.ResultType.PASS, | 542 if any(r.GetType() not in (base_test_result.ResultType.PASS, |
545 base_test_result.ResultType.SKIP) | 543 base_test_result.ResultType.SKIP) |
546 for r in results): | 544 for r in results): |
547 with contextlib_ext.Optional( | 545 self._SaveScreenshot(device, screenshot_device_file, test_display_name, |
548 tempfile_ext.NamedTemporaryDirectory(), | 546 results) |
549 self._test_instance.screenshot_dir is None and | |
550 self._test_instance.gs_results_bucket) as screenshot_host_dir: | |
551 screenshot_host_dir = ( | |
552 self._test_instance.screenshot_dir or screenshot_host_dir) | |
553 self._SaveScreenshot(device, screenshot_host_dir, | |
554 screenshot_device_file, test_display_name, | |
555 results) | |
556 | 547 |
557 logging.info('detected failure in %s. raw output:', test_display_name) | 548 logging.info('detected failure in %s. raw output:', test_display_name) |
558 for l in output: | 549 for l in output: |
559 logging.info(' %s', l) | 550 logging.info(' %s', l) |
560 if (not self._env.skip_clear_data | 551 if (not self._env.skip_clear_data |
561 and self._test_instance.package_info): | 552 and self._test_instance.package_info): |
562 permissions = ( | 553 permissions = ( |
563 self._test_instance.apk_under_test.GetPermissions() | 554 self._test_instance.apk_under_test.GetPermissions() |
564 if self._test_instance.apk_under_test | 555 if self._test_instance.apk_under_test |
565 else None) | 556 else None) |
566 device.ClearApplicationState(self._test_instance.package_info.package, | 557 device.ClearApplicationState(self._test_instance.package_info.package, |
567 permissions=permissions) | 558 permissions=permissions) |
568 else: | 559 else: |
569 logging.debug('raw output from %s:', test_display_name) | 560 logging.debug('raw output from %s:', test_display_name) |
570 for l in output: | 561 for l in output: |
571 logging.debug(' %s', l) | 562 logging.debug(' %s', l) |
572 if self._test_instance.store_tombstones: | 563 if self._test_instance.store_tombstones: |
573 tombstones_url = None | 564 tombstones_url = None |
574 for result in results: | 565 for result in results: |
575 if result.GetType() == base_test_result.ResultType.CRASH: | 566 if result.GetType() == base_test_result.ResultType.CRASH: |
576 if not tombstones_url: | 567 if not tombstones_url: |
577 resolved_tombstones = tombstones.ResolveTombstones( | 568 resolved_tombstones = tombstones.ResolveTombstones( |
578 device, | 569 device, |
579 resolve_all_tombstones=True, | 570 resolve_all_tombstones=True, |
580 include_stack_symbols=False, | 571 include_stack_symbols=False, |
581 wipe_tombstones=True, | 572 wipe_tombstones=True, |
582 tombstone_symbolizer=self._test_instance.symbolizer) | 573 tombstone_symbolizer=self._test_instance.symbolizer) |
583 stream_name = 'tombstones_%s_%s' % ( | 574 tombstone_filename = 'tombstones_%s_%s' % ( |
584 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()), | 575 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()), |
585 device.serial) | 576 device.serial) |
586 tombstones_url = logdog_helper.text( | 577 with self._env.output_manager.ArchivedTempfile( |
587 stream_name, '\n'.join(resolved_tombstones)) | 578 tombstone_filename, 'tombstones') as tombstone_file: |
588 result.SetLink('tombstones', tombstones_url) | 579 tombstone_file.write('\n'.join(resolved_tombstones)) |
589 | 580 result.SetLink('tombstones', tombstone_file.Link()) |
590 if self._env.concurrent_adb: | 581 if self._env.concurrent_adb: |
591 post_test_step_thread_group.JoinAll() | 582 post_test_step_thread_group.JoinAll() |
592 return results, None | 583 return results, None |
593 | 584 |
594 def _GetTestsFromRunner(self): | 585 def _GetTestsFromRunner(self): |
595 test_apk_path = self._test_instance.test_apk.path | 586 test_apk_path = self._test_instance.test_apk.path |
596 pickle_path = '%s-runner.pickle' % test_apk_path | 587 pickle_path = '%s-runner.pickle' % test_apk_path |
597 try: | 588 try: |
598 return instrumentation_test_instance.GetTestsFromPickle( | 589 return instrumentation_test_instance.GetTestsFromPickle( |
599 pickle_path, test_apk_path) | 590 pickle_path, test_apk_path) |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
691 | 682 |
692 with open(trace_host_file, 'r') as host_handle: | 683 with open(trace_host_file, 'r') as host_handle: |
693 host_contents = host_handle.readline() | 684 host_contents = host_handle.readline() |
694 | 685 |
695 if host_contents: | 686 if host_contents: |
696 java_trace_json = ',%s' % java_trace_json.lstrip(' [') | 687 java_trace_json = ',%s' % java_trace_json.lstrip(' [') |
697 | 688 |
698 with open(trace_host_file, 'a') as host_handle: | 689 with open(trace_host_file, 'a') as host_handle: |
699 host_handle.write(java_trace_json) | 690 host_handle.write(java_trace_json) |
700 | 691 |
701 def _SaveScreenshot(self, device, screenshot_host_dir, screenshot_device_file, | 692 def _SaveScreenshot(self, device, screenshot_device_file, test_name, results): |
702 test_name, results): | 693 screenshot_filename = '%s-%s.png' % ( |
703 if screenshot_host_dir: | 694 test_name, time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime())) |
704 screenshot_host_file = os.path.join( | |
705 screenshot_host_dir, | |
706 '%s-%s.png' % ( | |
707 test_name, | |
708 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()))) | |
709 if device.FileExists(screenshot_device_file.name): | 695 if device.FileExists(screenshot_device_file.name): |
710 try: | 696 with self._env.output_manager.ArchivedTempfile( |
711 device.PullFile(screenshot_device_file.name, screenshot_host_file) | 697 screenshot_filename, 'screenshot', |
712 finally: | 698 output_manager.Datatype.IMAGE) as screenshot_host_file: |
713 screenshot_device_file.close() | 699 try: |
714 | 700 device.PullFile(screenshot_device_file.name, |
715 logging.info( | 701 screenshot_host_file.name) |
716 'Saved screenshot for %s to %s.', | 702 finally: |
717 test_name, screenshot_host_file) | 703 screenshot_device_file.close() |
718 if self._test_instance.gs_results_bucket: | 704 for result in results: |
719 link = google_storage_helper.upload( | 705 result.SetLink('post_test_screenshot', screenshot_host_file.Link()) |
720 google_storage_helper.unique_name( | |
721 'screenshot', device=device), | |
722 screenshot_host_file, | |
723 bucket=('%s/screenshots' % | |
724 self._test_instance.gs_results_bucket)) | |
725 for result in results: | |
726 result.SetLink('post_test_screenshot', link) | |
727 | 706 |
728 def _ProcessRenderTestResults( | 707 def _ProcessRenderTestResults( |
729 self, device, render_tests_device_output_dir, results): | 708 self, device, render_tests_device_output_dir, results): |
730 # If GS results bucket is specified, will archive render result images. | |
731 # If render image dir is specified, will pull the render result image from | |
732 # the device and leave in the directory. | |
733 if not (bool(self._test_instance.gs_results_bucket) or | |
734 bool(self._test_instance.render_results_dir)): | |
735 return | |
736 | 709 |
737 failure_images_device_dir = posixpath.join( | 710 failure_images_device_dir = posixpath.join( |
738 render_tests_device_output_dir, 'failures') | 711 render_tests_device_output_dir, 'failures') |
739 if not device.FileExists(failure_images_device_dir): | 712 if not device.FileExists(failure_images_device_dir): |
740 return | 713 return |
741 | 714 |
742 diff_images_device_dir = posixpath.join( | 715 diff_images_device_dir = posixpath.join( |
743 render_tests_device_output_dir, 'diffs') | 716 render_tests_device_output_dir, 'diffs') |
744 | 717 |
745 golden_images_device_dir = posixpath.join( | 718 golden_images_device_dir = posixpath.join( |
746 render_tests_device_output_dir, 'goldens') | 719 render_tests_device_output_dir, 'goldens') |
747 | 720 |
748 with contextlib_ext.Optional( | 721 for failure_filename in device.ListDirectory(failure_images_device_dir): |
749 tempfile_ext.NamedTemporaryDirectory(), | |
750 not bool(self._test_instance.render_results_dir)) as render_temp_dir: | |
751 render_host_dir = ( | |
752 self._test_instance.render_results_dir or render_temp_dir) | |
753 | 722 |
754 if not os.path.exists(render_host_dir): | 723 with self._env.output_manager.ArchivedTempfile( |
755 os.makedirs(render_host_dir) | 724 'fail_%s' % failure_filename, 'render_tests', |
| 725 output_manager.Datatype.IMAGE) as failure_image_host_file: |
| 726 device.PullFile( |
| 727 posixpath.join(failure_images_device_dir, failure_filename), |
| 728 failure_image_host_file) |
| 729 failure_link = failure_image_host_file.Link() |
756 | 730 |
757 # Pull all render test results from device. | 731 golden_image_device_file = posixpath.join( |
758 device.PullFile(failure_images_device_dir, render_host_dir) | 732 golden_images_device_dir, failure_filename) |
759 | 733 if device.PathExists(golden_image_device_file): |
760 if device.FileExists(diff_images_device_dir): | 734 with self._env.output_manager.ArchivedTempfile( |
761 device.PullFile(diff_images_device_dir, render_host_dir) | 735 'golden_%s' % failure_filename, 'render_tests', |
762 else: | 736 output_manager.Datatype.IMAGE) as golden_image_host_file: |
763 logging.error('Diff images not found on device.') | 737 device.PullFile( |
764 | 738 golden_image_device_file, golden_image_host_file) |
765 if device.FileExists(golden_images_device_dir): | 739 golden_link = golden_image_host_file.Link() |
766 device.PullFile(golden_images_device_dir, render_host_dir) | |
767 else: | |
768 logging.error('Golden images not found on device.') | |
769 | |
770 # Upload results to Google Storage. | |
771 if self._test_instance.gs_results_bucket: | |
772 self._UploadRenderTestResults(render_host_dir, results) | |
773 | |
774 def _UploadRenderTestResults(self, render_host_dir, results): | |
775 render_tests_bucket = ( | |
776 self._test_instance.gs_results_bucket + '/render_tests') | |
777 | |
778 for failure_filename in os.listdir( | |
779 os.path.join(render_host_dir, 'failures')): | |
780 m = RE_RENDER_IMAGE_NAME.match(failure_filename) | |
781 if not m: | |
782 logging.warning('Unexpected file in render test failures: %s', | |
783 failure_filename) | |
784 continue | |
785 | |
786 failure_filepath = os.path.join( | |
787 render_host_dir, 'failures', failure_filename) | |
788 failure_link = google_storage_helper.upload_content_addressed( | |
789 failure_filepath, bucket=render_tests_bucket) | |
790 | |
791 golden_filepath = os.path.join( | |
792 render_host_dir, 'goldens', failure_filename) | |
793 if os.path.exists(golden_filepath): | |
794 golden_link = google_storage_helper.upload_content_addressed( | |
795 golden_filepath, bucket=render_tests_bucket) | |
796 else: | 740 else: |
797 golden_link = '' | 741 golden_link = '' |
798 | 742 |
799 diff_filepath = os.path.join( | 743 diff_image_device_file = posixpath.join( |
800 render_host_dir, 'diffs', failure_filename) | 744 diff_images_device_dir, failure_filename) |
801 if os.path.exists(diff_filepath): | 745 if device.PathExists(diff_image_device_file): |
802 diff_link = google_storage_helper.upload_content_addressed( | 746 with self._env.output_manager.ArchivedTempfile( |
803 diff_filepath, bucket=render_tests_bucket) | 747 'diff_%s' % failure_filename, 'render_tests', |
| 748 output_manager.Datatype.IMAGE) as diff_image_host_file: |
| 749 device.PullFile( |
| 750 diff_image_device_file, diff_image_host_file) |
| 751 diff_link = diff_image_host_file.Link() |
804 else: | 752 else: |
805 diff_link = '' | 753 diff_link = '' |
806 | 754 |
807 with tempfile.NamedTemporaryFile(suffix='.html') as temp_html: | 755 jinja2_env = jinja2.Environment( |
808 jinja2_env = jinja2.Environment( | 756 loader=jinja2.FileSystemLoader(_JINJA_TEMPLATE_DIR), |
809 loader=jinja2.FileSystemLoader(_JINJA_TEMPLATE_DIR), | 757 trim_blocks=True) |
810 trim_blocks=True) | 758 template = jinja2_env.get_template(_JINJA_TEMPLATE_FILENAME) |
811 template = jinja2_env.get_template(_JINJA_TEMPLATE_FILENAME) | 759 # pylint: disable=no-member |
812 # pylint: disable=no-member | 760 processed_template_output = template.render( |
813 processed_template_output = template.render( | 761 test_name=failure_filename, |
814 test_name=failure_filename, | 762 failure_link=failure_link, |
815 failure_link=failure_link, | 763 golden_link=golden_link, |
816 golden_link=golden_link, | 764 diff_link=diff_link) |
817 diff_link=diff_link) | |
818 | 765 |
819 temp_html.write(processed_template_output) | 766 with self._env.output_manager.ArchivedTempfile( |
820 temp_html.flush() | 767 '%s.html' % failure_filename, 'render_tests', |
821 html_results_link = google_storage_helper.upload_content_addressed( | 768 output_manager.Datatype.HTML) as html_results: |
822 temp_html.name, | 769 html_results.write(processed_template_output) |
823 bucket=render_tests_bucket, | 770 html_results.flush() |
824 content_type='text/html') | 771 for result in results: |
825 for result in results: | 772 result.SetLink(failure_filename, html_results.Link()) |
826 result.SetLink(failure_filename, html_results_link) | |
827 | 773 |
828 #override | 774 #override |
829 def _ShouldRetry(self, test, result): | 775 def _ShouldRetry(self, test, result): |
830 def not_run(res): | 776 def not_run(res): |
831 if isinstance(res, list): | 777 if isinstance(res, list): |
832 return any(not_run(r) for r in res) | 778 return any(not_run(r) for r in res) |
833 return res.GetType() == base_test_result.ResultType.NOTRUN | 779 return res.GetType() == base_test_result.ResultType.NOTRUN |
834 | 780 |
835 if 'RetryOnFailure' in test.get('annotations', {}) or not_run(result): | 781 if 'RetryOnFailure' in test.get('annotations', {}) or not_run(result): |
836 return True | 782 return True |
(...skipping 28 matching lines...) Expand all Loading... |
865 timeout *= cls._GetTimeoutScaleFromAnnotations(annotations) | 811 timeout *= cls._GetTimeoutScaleFromAnnotations(annotations) |
866 | 812 |
867 return timeout | 813 return timeout |
868 | 814 |
869 def _IsRenderTest(test): | 815 def _IsRenderTest(test): |
870 """Determines if a test or list of tests has a RenderTest amongst them.""" | 816 """Determines if a test or list of tests has a RenderTest amongst them.""" |
871 if not isinstance(test, list): | 817 if not isinstance(test, list): |
872 test = [test] | 818 test = [test] |
873 return any([RENDER_TEST_FEATURE_ANNOTATION in t['annotations'].get( | 819 return any([RENDER_TEST_FEATURE_ANNOTATION in t['annotations'].get( |
874 FEATURE_ANNOTATION, {}).get('value', ()) for t in test]) | 820 FEATURE_ANNOTATION, {}).get('value', ()) for t in test]) |
OLD | NEW |