Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # | 2 # |
| 3 # Copyright 2013 The Chromium Authors. All rights reserved. | 3 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 """Runs all types of tests from one unified interface.""" | 7 """Runs all types of tests from one unified interface.""" |
| 8 | 8 |
| 9 import argparse | 9 import argparse |
| 10 import collections | 10 import collections |
| 11 import contextlib | 11 import contextlib |
| 12 import itertools | 12 import itertools |
| 13 import logging | 13 import logging |
| 14 import os | 14 import os |
| 15 import shutil | 15 import shutil |
| 16 import signal | 16 import signal |
| 17 import sys | 17 import sys |
| 18 import tempfile | |
| 18 import threading | 19 import threading |
| 19 import traceback | 20 import traceback |
| 20 import unittest | 21 import unittest |
| 21 | 22 |
| 22 # Import _strptime before threaded code. datetime.datetime.strptime is | 23 # Import _strptime before threaded code. datetime.datetime.strptime is |
| 23 # threadsafe except for the initial import of the _strptime module. | 24 # threadsafe except for the initial import of the _strptime module. |
| 24 # See http://crbug.com/724524 and https://bugs.python.org/issue7980. | 25 # See http://crbug.com/724524 and https://bugs.python.org/issue7980. |
| 25 import _strptime # pylint: disable=unused-import | 26 import _strptime # pylint: disable=unused-import |
| 26 | 27 |
| 27 from pylib.constants import host_paths | 28 from pylib.constants import host_paths |
| 28 | 29 |
| 29 if host_paths.DEVIL_PATH not in sys.path: | 30 if host_paths.DEVIL_PATH not in sys.path: |
| 30 sys.path.append(host_paths.DEVIL_PATH) | 31 sys.path.append(host_paths.DEVIL_PATH) |
| 31 | 32 |
| 32 from devil import base_error | 33 from devil import base_error |
| 33 from devil.utils import reraiser_thread | 34 from devil.utils import reraiser_thread |
| 34 from devil.utils import run_tests_helper | 35 from devil.utils import run_tests_helper |
| 35 | 36 |
| 36 from pylib import constants | 37 from pylib import constants |
| 37 from pylib.base import base_test_result | 38 from pylib.base import base_test_result |
| 38 from pylib.base import environment_factory | 39 from pylib.base import environment_factory |
| 39 from pylib.base import test_instance_factory | 40 from pylib.base import test_instance_factory |
| 40 from pylib.base import test_run_factory | 41 from pylib.base import test_run_factory |
| 41 from pylib.results import json_results | 42 from pylib.results import json_results |
| 42 from pylib.results import report_results | 43 from pylib.results import report_results |
| 44 from pylib.results.presentation import test_results_presentation | |
| 43 from pylib.utils import logdog_helper | 45 from pylib.utils import logdog_helper |
| 44 from pylib.utils import logging_utils | 46 from pylib.utils import logging_utils |
| 47 from pylib.utils import test_output_saver_factory | |
| 45 | 48 |
| 46 from py_utils import contextlib_ext | 49 from py_utils import contextlib_ext |
| 47 | 50 |
| 48 | 51 |
| 49 _DEVIL_STATIC_CONFIG_FILE = os.path.abspath(os.path.join( | 52 _DEVIL_STATIC_CONFIG_FILE = os.path.abspath(os.path.join( |
| 50 host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'devil_config.json')) | 53 host_paths.DIR_SOURCE_ROOT, 'build', 'android', 'devil_config.json')) |
| 51 | 54 |
| 52 | 55 |
| 53 def AddTestLauncherOptions(parser): | 56 def AddTestLauncherOptions(parser): |
| 54 """Adds arguments mirroring //base/test/launcher. | 57 """Adds arguments mirroring //base/test/launcher. |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 134 help='Run the test scripts in platform mode, which ' | 137 help='Run the test scripts in platform mode, which ' |
| 135 'conceptually separates the test runner from the ' | 138 'conceptually separates the test runner from the ' |
| 136 '"device" (local or remote, real or emulated) on ' | 139 '"device" (local or remote, real or emulated) on ' |
| 137 'which the tests are running. [experimental]') | 140 'which the tests are running. [experimental]') |
| 138 | 141 |
| 139 parser.add_argument( | 142 parser.add_argument( |
| 140 '-e', '--environment', | 143 '-e', '--environment', |
| 141 default='local', choices=constants.VALID_ENVIRONMENTS, | 144 default='local', choices=constants.VALID_ENVIRONMENTS, |
| 142 help='Test environment to run in (default: %(default)s).') | 145 help='Test environment to run in (default: %(default)s).') |
| 143 | 146 |
| 147 parser.add_argument( | |
| 148 '--local-output', action='store_true', | |
| 149 help='Whether to archive test output locally and generate ' | |
| 150 'a local results detail page.') | |
| 151 | |
| 144 class FastLocalDevAction(argparse.Action): | 152 class FastLocalDevAction(argparse.Action): |
| 145 def __call__(self, parser, namespace, values, option_string=None): | 153 def __call__(self, parser, namespace, values, option_string=None): |
| 146 namespace.verbose_count = max(namespace.verbose_count, 1) | 154 namespace.verbose_count = max(namespace.verbose_count, 1) |
| 147 namespace.num_retries = 0 | 155 namespace.num_retries = 0 |
| 148 namespace.enable_device_cache = True | 156 namespace.enable_device_cache = True |
| 149 namespace.enable_concurrent_adb = True | 157 namespace.enable_concurrent_adb = True |
| 150 namespace.skip_clear_data = True | 158 namespace.skip_clear_data = True |
| 151 namespace.extract_test_list_from_filter = True | 159 namespace.extract_test_list_from_filter = True |
| 152 | 160 |
| 153 parser.add_argument( | 161 parser.add_argument( |
| (...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 778 logging.critical( | 786 logging.critical( |
| 779 'Logcat: %s', logdog_helper.get_viewer_url('unified_logcats')) | 787 'Logcat: %s', logdog_helper.get_viewer_url('unified_logcats')) |
| 780 | 788 |
| 781 | 789 |
| 782 logcats_uploader = contextlib_ext.Optional( | 790 logcats_uploader = contextlib_ext.Optional( |
| 783 upload_logcats_file(), | 791 upload_logcats_file(), |
| 784 'upload_logcats_file' in args and args.upload_logcats_file) | 792 'upload_logcats_file' in args and args.upload_logcats_file) |
| 785 | 793 |
| 786 ### Set up test objects. | 794 ### Set up test objects. |
| 787 | 795 |
| 796 test_output_saver = test_output_saver_factory.CreateTestOutputSaver(args) | |
| 788 env = environment_factory.CreateEnvironment(args, infra_error) | 797 env = environment_factory.CreateEnvironment(args, infra_error) |
| 789 test_instance = test_instance_factory.CreateTestInstance(args, infra_error) | 798 test_instance = test_instance_factory.CreateTestInstance(args, infra_error) |
| 790 test_run = test_run_factory.CreateTestRun( | 799 test_run = test_run_factory.CreateTestRun( |
| 791 args, env, test_instance, infra_error) | 800 args, env, test_instance, test_output_saver, infra_error) |
| 792 | 801 |
| 793 ### Run. | 802 ### Run. |
| 794 | 803 |
| 795 with json_writer, logcats_uploader, env, test_instance, test_run: | 804 with json_writer, logcats_uploader, env, test_instance, test_run: |
| 796 | 805 |
| 797 repetitions = (xrange(args.repeat + 1) if args.repeat >= 0 | 806 repetitions = (xrange(args.repeat + 1) if args.repeat >= 0 |
| 798 else itertools.count()) | 807 else itertools.count()) |
| 799 result_counts = collections.defaultdict( | 808 result_counts = collections.defaultdict( |
| 800 lambda: collections.defaultdict(int)) | 809 lambda: collections.defaultdict(int)) |
| 801 iteration_count = 0 | 810 iteration_count = 0 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 845 all_pass += 1 | 854 all_pass += 1 |
| 846 | 855 |
| 847 logging.critical('%s of %s tests passed in all %s runs', | 856 logging.critical('%s of %s tests passed in all %s runs', |
| 848 str(all_pass), | 857 str(all_pass), |
| 849 str(tot_tests), | 858 str(tot_tests), |
| 850 str(iteration_count)) | 859 str(iteration_count)) |
| 851 | 860 |
| 852 if args.command == 'perf' and (args.steps or args.single_step): | 861 if args.command == 'perf' and (args.steps or args.single_step): |
| 853 return 0 | 862 return 0 |
| 854 | 863 |
| 864 if args.local_output: | |
|
jbudorick
2017/06/20 14:12:55
We won't write local output on exception w/ this.
mikecase (-- gone --)
2017/07/10 17:11:11
Like, if the test_runner itself throws an exceptio
| |
| 865 result_html_string = test_results_presentation.result_details( | |
| 866 json_path=args.json_results_file, | |
| 867 test_name=args.command, | |
| 868 cs_base_url='http://cs.chromium.org', | |
| 869 local_output=True) | |
| 870 with tempfile.NamedTemporaryFile() as html_tmp: | |
| 871 html_tmp.write(result_html_string) | |
| 872 html_tmp.flush() | |
| 873 link = test_output_saver.Save( | |
| 874 html_tmp.name, | |
| 875 'test_results_presentation.html', | |
| 876 'test_results_presentation', | |
| 877 test_output_saver_factory.Datatype.HTML) | |
| 878 logging.critical('TEST RESULTS: %s', link) | |
| 879 | |
| 855 return (0 if all(r.DidRunPass() for r in all_iteration_results) | 880 return (0 if all(r.DidRunPass() for r in all_iteration_results) |
| 856 else constants.ERROR_EXIT_CODE) | 881 else constants.ERROR_EXIT_CODE) |
| 857 | 882 |
| 858 | 883 |
| 859 def DumpThreadStacks(_signal, _frame): | 884 def DumpThreadStacks(_signal, _frame): |
| 860 for thread in threading.enumerate(): | 885 for thread in threading.enumerate(): |
| 861 reraiser_thread.LogThreadStack(thread) | 886 reraiser_thread.LogThreadStack(thread) |
| 862 | 887 |
| 863 | 888 |
| 864 def main(): | 889 def main(): |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 934 if e.is_infra_error: | 959 if e.is_infra_error: |
| 935 return constants.INFRA_EXIT_CODE | 960 return constants.INFRA_EXIT_CODE |
| 936 return constants.ERROR_EXIT_CODE | 961 return constants.ERROR_EXIT_CODE |
| 937 except: # pylint: disable=W0702 | 962 except: # pylint: disable=W0702 |
| 938 logging.exception('Unrecognized error occurred.') | 963 logging.exception('Unrecognized error occurred.') |
| 939 return constants.ERROR_EXIT_CODE | 964 return constants.ERROR_EXIT_CODE |
| 940 | 965 |
| 941 | 966 |
| 942 if __name__ == '__main__': | 967 if __name__ == '__main__': |
| 943 sys.exit(main()) | 968 sys.exit(main()) |
| OLD | NEW |