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

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

Issue 2933993002: Add local results details pages.
Patch Set: Fix pydeps Created 3 years, 4 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 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
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
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
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
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
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
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])
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698