Chromium Code Reviews| 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 logging | 6 import logging |
| 7 import os | 7 import os |
| 8 import posixpath | 8 import posixpath |
| 9 import re | 9 import re |
| 10 import sys | 10 import sys |
| 11 import tempfile | 11 import tempfile |
| 12 import time | 12 import time |
| 13 | 13 |
| 14 from devil.android import crash_handler | 14 from devil.android import crash_handler |
| 15 from devil.android import device_errors | 15 from devil.android import device_errors |
| 16 from devil.android import device_temp_file | 16 from devil.android import device_temp_file |
| 17 from devil.android import flag_changer | 17 from devil.android import flag_changer |
| 18 from devil.android import logcat_monitor | |
| 18 from devil.android.tools import system_app | 19 from devil.android.tools import system_app |
| 19 from devil.utils import reraiser_thread | 20 from devil.utils import reraiser_thread |
| 20 from pylib import valgrind_tools | 21 from pylib import valgrind_tools |
| 21 from pylib.android import logdog_logcat_monitor | |
| 22 from pylib.base import base_test_result | 22 from pylib.base import base_test_result |
| 23 from pylib.base import output_manager | |
| 23 from pylib.constants import host_paths | 24 from pylib.constants import host_paths |
| 24 from pylib.instrumentation import instrumentation_test_instance | 25 from pylib.instrumentation import instrumentation_test_instance |
| 25 from pylib.local.device import local_device_environment | 26 from pylib.local.device import local_device_environment |
| 26 from pylib.local.device import local_device_test_run | 27 from pylib.local.device import local_device_test_run |
| 27 from pylib.utils import google_storage_helper | |
| 28 from pylib.utils import instrumentation_tracing | 28 from pylib.utils import instrumentation_tracing |
| 29 from pylib.utils import logdog_helper | |
| 30 from pylib.utils import shared_preference_utils | 29 from pylib.utils import shared_preference_utils |
| 30 | |
| 31 from py_trace_event import trace_event | 31 from py_trace_event import trace_event |
| 32 from py_utils import contextlib_ext | 32 from py_utils import contextlib_ext |
| 33 from py_utils import tempfile_ext | |
| 34 import tombstones | 33 import tombstones |
| 35 | 34 |
| 36 with host_paths.SysPath( | 35 with host_paths.SysPath( |
| 37 os.path.join(host_paths.DIR_SOURCE_ROOT, 'third_party'), 0): | 36 os.path.join(host_paths.DIR_SOURCE_ROOT, 'third_party'), 0): |
| 38 import jinja2 # pylint: disable=import-error | 37 import jinja2 # pylint: disable=import-error |
| 39 import markupsafe # pylint: disable=import-error,unused-import | 38 import markupsafe # pylint: disable=import-error,unused-import |
| 40 | 39 |
| 41 | 40 |
| 42 _JINJA_TEMPLATE_DIR = os.path.join( | 41 _JINJA_TEMPLATE_DIR = os.path.join( |
| 43 host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'pylib', 'instrumentation') | 42 host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'pylib', 'instrumentation') |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 return False | 105 return False |
| 107 | 106 |
| 108 | 107 |
| 109 _CURRENT_FOCUS_CRASH_RE = re.compile( | 108 _CURRENT_FOCUS_CRASH_RE = re.compile( |
| 110 r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}') | 109 r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}') |
| 111 | 110 |
| 112 | 111 |
| 113 class LocalDeviceInstrumentationTestRun( | 112 class LocalDeviceInstrumentationTestRun( |
| 114 local_device_test_run.LocalDeviceTestRun): | 113 local_device_test_run.LocalDeviceTestRun): |
| 115 def __init__(self, env, test_instance): | 114 def __init__(self, env, test_instance): |
| 116 super(LocalDeviceInstrumentationTestRun, self).__init__(env, test_instance) | 115 super(LocalDeviceInstrumentationTestRun, self).__init__( |
| 116 env, test_instance) | |
| 117 self._flag_changers = {} | 117 self._flag_changers = {} |
| 118 self._ui_capture_dir = dict() | 118 self._ui_capture_dir = dict() |
| 119 self._replace_package_contextmanager = None | 119 self._replace_package_contextmanager = None |
| 120 | 120 |
| 121 #override | 121 #override |
| 122 def TestPackage(self): | 122 def TestPackage(self): |
| 123 return self._test_instance.suite | 123 return self._test_instance.suite |
| 124 | 124 |
| 125 #override | 125 #override |
| 126 def SetUp(self): | 126 def SetUp(self): |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 326 coverage_basename = '%s.ec' % ('%s_group' % test[0]['method'] | 326 coverage_basename = '%s.ec' % ('%s_group' % test[0]['method'] |
| 327 if isinstance(test, list) else test['method']) | 327 if isinstance(test, list) else test['method']) |
| 328 extras['coverage'] = 'true' | 328 extras['coverage'] = 'true' |
| 329 coverage_directory = os.path.join( | 329 coverage_directory = os.path.join( |
| 330 device.GetExternalStoragePath(), 'chrome', 'test', 'coverage') | 330 device.GetExternalStoragePath(), 'chrome', 'test', 'coverage') |
| 331 coverage_device_file = os.path.join( | 331 coverage_device_file = os.path.join( |
| 332 coverage_directory, coverage_basename) | 332 coverage_directory, coverage_basename) |
| 333 extras['coverageFile'] = coverage_device_file | 333 extras['coverageFile'] = coverage_device_file |
| 334 # Save screenshot if screenshot dir is specified (save locally) or if | 334 # Save screenshot if screenshot dir is specified (save locally) or if |
| 335 # a GS bucket is passed (save in cloud). | 335 # a GS bucket is passed (save in cloud). |
| 336 screenshot_device_file = None | 336 screenshot_device_file = device_temp_file.DeviceTempFile( |
| 337 if (self._test_instance.screenshot_dir or | 337 device.adb, suffix='.png', dir=device.GetExternalStoragePath()) |
| 338 self._test_instance.gs_results_bucket): | 338 extras[EXTRA_SCREENSHOT_FILE] = screenshot_device_file.name |
| 339 screenshot_device_file = device_temp_file.DeviceTempFile( | |
| 340 device.adb, suffix='.png', dir=device.GetExternalStoragePath()) | |
| 341 extras[EXTRA_SCREENSHOT_FILE] = screenshot_device_file.name | |
| 342 | 339 |
| 343 extras[EXTRA_UI_CAPTURE_DIR] = self._ui_capture_dir[device] | 340 extras[EXTRA_UI_CAPTURE_DIR] = self._ui_capture_dir[device] |
| 344 | 341 |
| 345 if isinstance(test, list): | 342 if isinstance(test, list): |
| 346 if not self._test_instance.driver_apk: | 343 if not self._test_instance.driver_apk: |
| 347 raise Exception('driver_apk does not exist. ' | 344 raise Exception('driver_apk does not exist. ' |
| 348 'Please build it and try again.') | 345 'Please build it and try again.') |
| 349 if any(t.get('is_junit4') for t in test): | 346 if any(t.get('is_junit4') for t in test): |
| 350 raise Exception('driver apk does not support JUnit4 tests') | 347 raise Exception('driver apk does not support JUnit4 tests') |
| 351 | 348 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 402 self._CreateFlagChangerIfNeeded(device) | 399 self._CreateFlagChangerIfNeeded(device) |
| 403 self._flag_changers[str(device)].PushFlags(add=flags_to_add) | 400 self._flag_changers[str(device)].PushFlags(add=flags_to_add) |
| 404 | 401 |
| 405 time_ms = lambda: int(time.time() * 1e3) | 402 time_ms = lambda: int(time.time() * 1e3) |
| 406 start_ms = time_ms() | 403 start_ms = time_ms() |
| 407 | 404 |
| 408 stream_name = 'logcat_%s_%s_%s' % ( | 405 stream_name = 'logcat_%s_%s_%s' % ( |
| 409 test_name.replace('#', '.'), | 406 test_name.replace('#', '.'), |
| 410 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()), | 407 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()), |
| 411 device.serial) | 408 device.serial) |
| 412 logmon = logdog_logcat_monitor.LogdogLogcatMonitor( | |
| 413 device.adb, stream_name, filter_specs=LOGCAT_FILTERS) | |
| 414 | 409 |
| 415 with contextlib_ext.Optional( | 410 try: |
| 416 logmon, self._test_instance.should_save_logcat): | 411 logcat_file = tempfile.NamedTemporaryFile(delete=False) |
|
jbudorick
2017/08/10 16:27:37
Should this be outside of the try/finally? If temp
| |
| 417 with _LogTestEndpoints(device, test_name): | 412 with logcat_monitor.LogcatMonitor( |
| 418 with contextlib_ext.Optional( | 413 device.adb, filter_specs=LOGCAT_FILTERS, |
| 419 trace_event.trace(test_name), | 414 output_file=logcat_file.name) as logmon: |
| 420 self._env.trace_output): | 415 with _LogTestEndpoints(device, test_name): |
| 421 output = device.StartInstrumentation( | 416 with contextlib_ext.Optional( |
| 422 target, raw=True, extras=extras, timeout=timeout, retries=0) | 417 trace_event.trace(test_name), |
| 418 self._env.trace_output): | |
| 419 output = device.StartInstrumentation( | |
| 420 target, raw=True, extras=extras, timeout=timeout, retries=0) | |
| 421 logmon.Close() | |
| 422 finally: | |
| 423 logcat_url = self._env.output_manager.ArchiveAndDeleteFile( | |
| 424 logcat_file.name, stream_name, 'logcat') | |
| 423 | 425 |
| 424 logcat_url = logmon.GetLogcatURL() | |
| 425 duration_ms = time_ms() - start_ms | 426 duration_ms = time_ms() - start_ms |
| 426 | 427 |
| 427 # TODO(jbudorick): Make instrumentation tests output a JSON so this | 428 # TODO(jbudorick): Make instrumentation tests output a JSON so this |
| 428 # doesn't have to parse the output. | 429 # doesn't have to parse the output. |
| 429 result_code, result_bundle, statuses = ( | 430 result_code, result_bundle, statuses = ( |
| 430 self._test_instance.ParseAmInstrumentRawOutput(output)) | 431 self._test_instance.ParseAmInstrumentRawOutput(output)) |
| 431 results = self._test_instance.GenerateTestResults( | 432 results = self._test_instance.GenerateTestResults( |
| 432 result_code, result_bundle, statuses, start_ms, duration_ms) | 433 result_code, result_bundle, statuses, start_ms, duration_ms) |
| 433 | 434 |
| 434 def restore_flags(): | 435 def restore_flags(): |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 498 if r.GetType() == base_test_result.ResultType.UNKNOWN: | 499 if r.GetType() == base_test_result.ResultType.UNKNOWN: |
| 499 r.SetType(base_test_result.ResultType.CRASH) | 500 r.SetType(base_test_result.ResultType.CRASH) |
| 500 | 501 |
| 501 # Handle failures by: | 502 # Handle failures by: |
| 502 # - optionally taking a screenshot | 503 # - optionally taking a screenshot |
| 503 # - logging the raw output at INFO level | 504 # - logging the raw output at INFO level |
| 504 # - clearing the application state while persisting permissions | 505 # - clearing the application state while persisting permissions |
| 505 if any(r.GetType() not in (base_test_result.ResultType.PASS, | 506 if any(r.GetType() not in (base_test_result.ResultType.PASS, |
| 506 base_test_result.ResultType.SKIP) | 507 base_test_result.ResultType.SKIP) |
| 507 for r in results): | 508 for r in results): |
| 508 with contextlib_ext.Optional( | 509 self._SaveScreenshot(device, screenshot_device_file, test_display_name, |
| 509 tempfile_ext.NamedTemporaryDirectory(), | 510 results) |
| 510 self._test_instance.screenshot_dir is None and | |
| 511 self._test_instance.gs_results_bucket) as screenshot_host_dir: | |
| 512 screenshot_host_dir = ( | |
| 513 self._test_instance.screenshot_dir or screenshot_host_dir) | |
| 514 self._SaveScreenshot(device, screenshot_host_dir, | |
| 515 screenshot_device_file, test_display_name, | |
| 516 results) | |
| 517 | 511 |
| 518 logging.info('detected failure in %s. raw output:', test_display_name) | 512 logging.info('detected failure in %s. raw output:', test_display_name) |
| 519 for l in output: | 513 for l in output: |
| 520 logging.info(' %s', l) | 514 logging.info(' %s', l) |
| 521 if (not self._env.skip_clear_data | 515 if (not self._env.skip_clear_data |
| 522 and self._test_instance.package_info): | 516 and self._test_instance.package_info): |
| 523 permissions = ( | 517 permissions = ( |
| 524 self._test_instance.apk_under_test.GetPermissions() | 518 self._test_instance.apk_under_test.GetPermissions() |
| 525 if self._test_instance.apk_under_test | 519 if self._test_instance.apk_under_test |
| 526 else None) | 520 else None) |
| 527 device.ClearApplicationState(self._test_instance.package_info.package, | 521 device.ClearApplicationState(self._test_instance.package_info.package, |
| 528 permissions=permissions) | 522 permissions=permissions) |
| 529 else: | 523 else: |
| 530 logging.debug('raw output from %s:', test_display_name) | 524 logging.debug('raw output from %s:', test_display_name) |
| 531 for l in output: | 525 for l in output: |
| 532 logging.debug(' %s', l) | 526 logging.debug(' %s', l) |
| 533 if self._test_instance.store_tombstones: | 527 if self._test_instance.store_tombstones: |
| 534 tombstones_url = None | 528 tombstones_url = None |
| 535 for result in results: | 529 for result in results: |
| 536 if result.GetType() == base_test_result.ResultType.CRASH: | 530 if result.GetType() == base_test_result.ResultType.CRASH: |
| 537 if not tombstones_url: | 531 if not tombstones_url: |
| 538 resolved_tombstones = tombstones.ResolveTombstones( | 532 resolved_tombstones = tombstones.ResolveTombstones( |
| 539 device, | 533 device, |
| 540 resolve_all_tombstones=True, | 534 resolve_all_tombstones=True, |
| 541 include_stack_symbols=False, | 535 include_stack_symbols=False, |
| 542 wipe_tombstones=True) | 536 wipe_tombstones=True) |
| 543 stream_name = 'tombstones_%s_%s' % ( | 537 try: |
| 544 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()), | 538 tombstone_file = tempfile.NamedTemporaryFile(delete=False) |
| 545 device.serial) | 539 tombstone_filename = 'tombstones_%s_%s' % ( |
| 546 tombstones_url = logdog_helper.text( | 540 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()), |
| 547 stream_name, '\n'.join(resolved_tombstones)) | 541 device.serial) |
| 548 result.SetLink('tombstones', tombstones_url) | 542 tombstone_file.write('\n'.join(resolved_tombstones)) |
| 549 | 543 tombstone_file.flush() |
| 544 finally: | |
| 545 tombstones_url = self._env.output_manager.ArchiveAndDeleteFile( | |
| 546 tombstone_file.name, tombstone_filename, 'tombstones') | |
| 547 result.SetLink('tombstones', tombstones_url) | |
| 550 if self._env.concurrent_adb: | 548 if self._env.concurrent_adb: |
| 551 post_test_step_thread_group.JoinAll() | 549 post_test_step_thread_group.JoinAll() |
| 552 return results, None | 550 return results, None |
| 553 | 551 |
| 554 def _SaveScreenshot(self, device, screenshot_host_dir, screenshot_device_file, | 552 def _SaveScreenshot(self, device, screenshot_device_file, test_name, results): |
| 555 test_name, results): | 553 screenshot_filename = '%s-%s.png' % ( |
| 556 if screenshot_host_dir: | 554 test_name, time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime())) |
| 557 screenshot_host_file = os.path.join( | |
| 558 screenshot_host_dir, | |
| 559 '%s-%s.png' % ( | |
| 560 test_name, | |
| 561 time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()))) | |
| 562 if device.FileExists(screenshot_device_file.name): | 555 if device.FileExists(screenshot_device_file.name): |
| 563 try: | 556 try: |
| 564 device.PullFile(screenshot_device_file.name, screenshot_host_file) | 557 screenshot_host_file = tempfile.NamedTemporaryFile(delete=False) |
| 558 try: | |
| 559 device.PullFile(screenshot_device_file.name, | |
| 560 screenshot_host_file.name) | |
| 561 finally: | |
| 562 screenshot_device_file.close() | |
| 563 screenshot_host_file.flush() | |
| 565 finally: | 564 finally: |
| 566 screenshot_device_file.close() | 565 screenshot_url = self._env.output_manager.ArchiveAndDeleteFile( |
| 567 | 566 screenshot_host_file.name, screenshot_filename, |
| 568 logging.info( | 567 'screenshot', output_manager.Datatype.IMAGE) |
| 569 'Saved screenshot for %s to %s.', | |
| 570 test_name, screenshot_host_file) | |
| 571 if self._test_instance.gs_results_bucket: | |
| 572 link = google_storage_helper.upload( | |
| 573 google_storage_helper.unique_name( | |
| 574 'screenshot', device=device), | |
| 575 screenshot_host_file, | |
| 576 bucket=('%s/screenshots' % | |
| 577 self._test_instance.gs_results_bucket)) | |
| 578 for result in results: | 568 for result in results: |
| 579 result.SetLink('post_test_screenshot', link) | 569 result.SetLink('post_test_screenshot', screenshot_url) |
| 580 | 570 |
| 581 def _ProcessRenderTestResults( | 571 def _ProcessRenderTestResults( |
| 582 self, device, render_tests_device_output_dir, results): | 572 self, device, render_tests_device_output_dir, results): |
| 583 # If GS results bucket is specified, will archive render result images. | |
| 584 # If render image dir is specified, will pull the render result image from | |
| 585 # the device and leave in the directory. | |
| 586 if not (bool(self._test_instance.gs_results_bucket) or | |
| 587 bool(self._test_instance.render_results_dir)): | |
| 588 return | |
| 589 | 573 |
| 590 failure_images_device_dir = posixpath.join( | 574 failure_images_device_dir = posixpath.join( |
| 591 render_tests_device_output_dir, 'failures') | 575 render_tests_device_output_dir, 'failures') |
| 592 if not device.FileExists(failure_images_device_dir): | 576 if not device.FileExists(failure_images_device_dir): |
| 593 return | 577 return |
| 594 | 578 |
| 595 diff_images_device_dir = posixpath.join( | 579 diff_images_device_dir = posixpath.join( |
| 596 render_tests_device_output_dir, 'diffs') | 580 render_tests_device_output_dir, 'diffs') |
| 597 | 581 |
| 598 golden_images_device_dir = posixpath.join( | 582 golden_images_device_dir = posixpath.join( |
| 599 render_tests_device_output_dir, 'goldens') | 583 render_tests_device_output_dir, 'goldens') |
| 600 | 584 |
| 601 with contextlib_ext.Optional( | 585 for failure_filename in device.ListDirectory(failure_images_device_dir): |
| 602 tempfile_ext.NamedTemporaryDirectory(), | |
| 603 not bool(self._test_instance.render_results_dir)) as render_temp_dir: | |
| 604 render_host_dir = ( | |
| 605 self._test_instance.render_results_dir or render_temp_dir) | |
| 606 | 586 |
| 607 if not os.path.exists(render_host_dir): | 587 try: |
| 608 os.makedirs(render_host_dir) | 588 failure_image_host_file = tempfile.NamedTemporaryFile(delete=False) |
| 589 device.PullFile( | |
| 590 posixpath.join(failure_images_device_dir, failure_filename), | |
| 591 failure_image_host_file) | |
| 592 failure_image_host_file.flush() | |
| 593 finally: | |
| 594 failure_link = self._env.output_manager.ArchiveAndDeleteFile( | |
| 595 failure_image_host_file.name, 'fail_%s' % failure_filename, | |
| 596 'render_tests', output_manager.Datatype.IMAGE) | |
| 609 | 597 |
| 610 # Pull all render test results from device. | 598 if device.PathExists( |
| 611 device.PullFile(failure_images_device_dir, render_host_dir) | 599 posixpath.join(golden_images_device_dir, failure_filename)): |
| 612 | 600 try: |
| 613 if device.FileExists(diff_images_device_dir): | 601 golden_image_host_file = tempfile.NamedTemporaryFile(delete=False) |
| 614 device.PullFile(diff_images_device_dir, render_host_dir) | 602 device.PullFile( |
| 615 else: | 603 posixpath.join(golden_images_device_dir, failure_filename), |
| 616 logging.error('Diff images not found on device.') | 604 golden_image_host_file) |
| 617 | 605 golden_image_host_file.flush() |
| 618 if device.FileExists(golden_images_device_dir): | 606 finally: |
| 619 device.PullFile(golden_images_device_dir, render_host_dir) | 607 golden_link = self._env.output_manager.ArchiveAndDeleteFile( |
| 620 else: | 608 golden_image_host_file.name, 'golden_%s' % failure_filename, |
| 621 logging.error('Golden images not found on device.') | 609 'render_tests', output_manager.Datatype.IMAGE) |
| 622 | |
| 623 # Upload results to Google Storage. | |
| 624 if self._test_instance.gs_results_bucket: | |
| 625 self._UploadRenderTestResults(render_host_dir, results) | |
| 626 | |
| 627 def _UploadRenderTestResults(self, render_host_dir, results): | |
| 628 render_tests_bucket = ( | |
| 629 self._test_instance.gs_results_bucket + '/render_tests') | |
| 630 | |
| 631 for failure_filename in os.listdir( | |
| 632 os.path.join(render_host_dir, 'failures')): | |
| 633 m = RE_RENDER_IMAGE_NAME.match(failure_filename) | |
| 634 if not m: | |
| 635 logging.warning('Unexpected file in render test failures: %s', | |
| 636 failure_filename) | |
| 637 continue | |
| 638 | |
| 639 failure_filepath = os.path.join( | |
| 640 render_host_dir, 'failures', failure_filename) | |
| 641 failure_link = google_storage_helper.upload_content_addressed( | |
| 642 failure_filepath, bucket=render_tests_bucket) | |
| 643 | |
| 644 golden_filepath = os.path.join( | |
| 645 render_host_dir, 'goldens', failure_filename) | |
| 646 if os.path.exists(golden_filepath): | |
| 647 golden_link = google_storage_helper.upload_content_addressed( | |
| 648 golden_filepath, bucket=render_tests_bucket) | |
| 649 else: | 610 else: |
| 650 golden_link = '' | 611 golden_link = '' |
| 651 | 612 |
| 652 diff_filepath = os.path.join( | 613 if device.PathExists( |
| 653 render_host_dir, 'diffs', failure_filename) | 614 posixpath.join(diff_images_device_dir, failure_filename)): |
| 654 if os.path.exists(diff_filepath): | 615 try: |
| 655 diff_link = google_storage_helper.upload_content_addressed( | 616 diff_image_host_file = tempfile.NamedTemporaryFile(delete=False) |
| 656 diff_filepath, bucket=render_tests_bucket) | 617 device.PullFile( |
| 618 posixpath.join(diff_images_device_dir, failure_filename), | |
| 619 diff_image_host_file) | |
| 620 diff_image_host_file.flush() | |
| 621 finally: | |
| 622 diff_link = self._env.output_manager.ArchiveAndDeleteFile( | |
| 623 diff_image_host_file.name, 'diff_%s' % failure_filename, | |
| 624 'render_tests', output_manager.Datatype.IMAGE) | |
| 657 else: | 625 else: |
| 658 diff_link = '' | 626 diff_link = '' |
| 659 | 627 |
| 660 with tempfile.NamedTemporaryFile(suffix='.html') as temp_html: | 628 jinja2_env = jinja2.Environment( |
| 661 jinja2_env = jinja2.Environment( | 629 loader=jinja2.FileSystemLoader(_JINJA_TEMPLATE_DIR), |
| 662 loader=jinja2.FileSystemLoader(_JINJA_TEMPLATE_DIR), | 630 trim_blocks=True) |
| 663 trim_blocks=True) | 631 template = jinja2_env.get_template(_JINJA_TEMPLATE_FILENAME) |
| 664 template = jinja2_env.get_template(_JINJA_TEMPLATE_FILENAME) | 632 # pylint: disable=no-member |
| 665 # pylint: disable=no-member | 633 processed_template_output = template.render( |
| 666 processed_template_output = template.render( | 634 test_name=failure_filename, |
| 667 test_name=failure_filename, | 635 failure_link=failure_link, |
| 668 failure_link=failure_link, | 636 golden_link=golden_link, |
| 669 golden_link=golden_link, | 637 diff_link=diff_link) |
| 670 diff_link=diff_link) | |
| 671 | 638 |
| 672 temp_html.write(processed_template_output) | 639 try: |
| 673 temp_html.flush() | 640 html_results = tempfile.NamedTemporaryFile(delete=False) |
| 674 html_results_link = google_storage_helper.upload_content_addressed( | 641 html_results.write(processed_template_output) |
| 675 temp_html.name, | 642 html_results.flush() |
| 676 bucket=render_tests_bucket, | 643 finally: |
| 677 content_type='text/html') | 644 html_results_link = self._env.output_manager.ArchiveAndDeleteFile( |
| 645 html_results.name, | |
| 646 '%s.html' % failure_filename, 'render_tests', | |
| 647 output_manager.Datatype.HTML) | |
| 678 for result in results: | 648 for result in results: |
| 679 result.SetLink(failure_filename, html_results_link) | 649 result.SetLink(failure_filename, html_results_link) |
| 680 | 650 |
| 681 #override | 651 #override |
| 682 def _ShouldRetry(self, test): | 652 def _ShouldRetry(self, test): |
| 683 if 'RetryOnFailure' in test.get('annotations', {}): | 653 if 'RetryOnFailure' in test.get('annotations', {}): |
| 684 return True | 654 return True |
| 685 | 655 |
| 686 # TODO(jbudorick): Remove this log message once @RetryOnFailure has been | 656 # TODO(jbudorick): Remove this log message once @RetryOnFailure has been |
| 687 # enabled for a while. See crbug.com/619055 for more details. | 657 # enabled for a while. See crbug.com/619055 for more details. |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 713 timeout *= cls._GetTimeoutScaleFromAnnotations(annotations) | 683 timeout *= cls._GetTimeoutScaleFromAnnotations(annotations) |
| 714 | 684 |
| 715 return timeout | 685 return timeout |
| 716 | 686 |
| 717 def _IsRenderTest(test): | 687 def _IsRenderTest(test): |
| 718 """Determines if a test or list of tests has a RenderTest amongst them.""" | 688 """Determines if a test or list of tests has a RenderTest amongst them.""" |
| 719 if not isinstance(test, list): | 689 if not isinstance(test, list): |
| 720 test = [test] | 690 test = [test] |
| 721 return any([RENDER_TEST_FEATURE_ANNOTATION in t['annotations'].get( | 691 return any([RENDER_TEST_FEATURE_ANNOTATION in t['annotations'].get( |
| 722 FEATURE_ANNOTATION, {}).get('value', ()) for t in test]) | 692 FEATURE_ANNOTATION, {}).get('value', ()) for t in test]) |
| OLD | NEW |