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