| OLD | NEW |
| (Empty) |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import logging | |
| 6 import os | |
| 7 import re | |
| 8 import subprocess | |
| 9 import sys | |
| 10 | |
| 11 _logging = logging.getLogger() | |
| 12 | |
| 13 from mopy import android | |
| 14 from mopy.config import Config | |
| 15 from mopy.paths import Paths | |
| 16 from mopy.print_process_error import print_process_error | |
| 17 | |
| 18 | |
| 19 def set_color(): | |
| 20 """Run gtests with color if we're on a TTY (and we're not being told | |
| 21 explicitly what to do).""" | |
| 22 if sys.stdout.isatty() and "GTEST_COLOR" not in os.environ: | |
| 23 _logging.debug("Setting GTEST_COLOR=yes") | |
| 24 os.environ["GTEST_COLOR"] = "yes" | |
| 25 | |
| 26 | |
| 27 def run_test(config, shell_args, apps_and_args=None, context=None, | |
| 28 run_launcher=False): | |
| 29 """Runs a command line and checks the output for signs of gtest failure. | |
| 30 | |
| 31 Args: | |
| 32 config: The mopy.config.Config object for the build. | |
| 33 shell_args: The arguments for mojo_shell. | |
| 34 apps_and_args: A Dict keyed by application URL associated to the | |
| 35 application's specific arguments. | |
| 36 context: Platform specific context. See |mopy.{platform}.Context|. | |
| 37 run_launcher: |True| is mojo_launcher must be used instead of mojo_shell. | |
| 38 """ | |
| 39 apps_and_args = apps_and_args or {} | |
| 40 output = _try_run_test( | |
| 41 config, shell_args, apps_and_args, context, run_launcher) | |
| 42 # Fail on output with gtest's "[ FAILED ]" or a lack of "[ PASSED ]". | |
| 43 # The latter condition ensures failure on broken command lines or output. | |
| 44 # Check output instead of exit codes because mojo_shell always exits with 0. | |
| 45 if (output is None or | |
| 46 (output.find("[ FAILED ]") != -1 or output.find("[ PASSED ]") == -1)): | |
| 47 print "Failed test:" | |
| 48 print_process_error( | |
| 49 _build_command_line(config, shell_args, apps_and_args, run_launcher), | |
| 50 output) | |
| 51 return False | |
| 52 _logging.debug("Succeeded with output:\n%s" % output) | |
| 53 return True | |
| 54 | |
| 55 | |
| 56 def get_fixtures(config, apptest, context): | |
| 57 """Returns the "Test.Fixture" list from an apptest using mojo_shell. | |
| 58 | |
| 59 Tests are listed by running the given apptest in mojo_shell and passing | |
| 60 --gtest_list_tests. The output is parsed and reformatted into a list like | |
| 61 [TestSuite.TestFixture, ... ] | |
| 62 An empty list is returned on failure, with errors logged. | |
| 63 | |
| 64 Args: | |
| 65 config: The mopy.config.Config object for the build. | |
| 66 apptest: The URL of the test application to run. | |
| 67 context: Platform specific context. See |mopy.{platform}.Context|. | |
| 68 """ | |
| 69 | |
| 70 try: | |
| 71 apps_and_args = {apptest: ["--gtest_list_tests"]} | |
| 72 list_output = _run_test(config, [], apps_and_args, context) | |
| 73 _logging.debug("Tests listed:\n%s" % list_output) | |
| 74 return _gtest_list_tests(list_output) | |
| 75 except Exception as e: | |
| 76 print "Failed to get test fixtures:" | |
| 77 print_process_error(_build_command_line(config, [], apps_and_args), e) | |
| 78 return [] | |
| 79 | |
| 80 | |
| 81 def build_shell_arguments(shell_args, apps_and_args, run_apps=True): | |
| 82 """Build the list of arguments for the shell. |shell_args| are the base | |
| 83 arguments, |apps_and_args| is a dictionary that associate each application to | |
| 84 its specific arguments, and |run_apps| is True if the shell must run the | |
| 85 applications in |apps_and_args|. | |
| 86 """ | |
| 87 result = shell_args[:] | |
| 88 if apps_and_args: | |
| 89 for (application, args) in apps_and_args.items(): | |
| 90 result += ["--args-for=%s %s" % (application, " ".join(args))] | |
| 91 if run_apps: | |
| 92 result += apps_and_args.keys() | |
| 93 return result | |
| 94 | |
| 95 | |
| 96 def _get_shell_executable(config, run_launcher): | |
| 97 paths = Paths(config=config) | |
| 98 if config.target_os == Config.OS_ANDROID: | |
| 99 return os.path.join(paths.src_root, "mojo", "tools", | |
| 100 "android_mojo_shell.py") | |
| 101 elif run_launcher: | |
| 102 return paths.mojo_launcher_path | |
| 103 else: | |
| 104 return paths.mojo_shell_path | |
| 105 | |
| 106 | |
| 107 def _build_command_line(config, shell_args, apps_and_args, run_apps=True, | |
| 108 run_launcher=False): | |
| 109 executable = _get_shell_executable(config, run_launcher) | |
| 110 return "%s %s" % (executable, " ".join(["%r" % x for x in | |
| 111 build_shell_arguments(shell_args, | |
| 112 apps_and_args, | |
| 113 run_apps)])) | |
| 114 | |
| 115 | |
| 116 def _run_test_android(shell_args, apps_and_args, context): | |
| 117 """Run the given test on the android device defined in |context|.""" | |
| 118 (r, w) = os.pipe() | |
| 119 with os.fdopen(r, "r") as rf: | |
| 120 with os.fdopen(w, "w") as wf: | |
| 121 arguments = build_shell_arguments(shell_args, apps_and_args) | |
| 122 android.StartShell(context, arguments, wf, wf.close) | |
| 123 return rf.read() | |
| 124 | |
| 125 | |
| 126 def _run_test(config, shell_args, apps_and_args, context, run_launcher=False): | |
| 127 """Run the given test, using mojo_launcher if |run_launcher| is True.""" | |
| 128 if (config.target_os == Config.OS_ANDROID): | |
| 129 return _run_test_android(shell_args, apps_and_args, context) | |
| 130 else: | |
| 131 executable = _get_shell_executable(config, run_launcher) | |
| 132 command = ([executable] + build_shell_arguments(shell_args, apps_and_args)) | |
| 133 return subprocess.check_output(command, stderr=subprocess.STDOUT) | |
| 134 | |
| 135 | |
| 136 def _try_run_test(config, shell_args, apps_and_args, context, run_launcher): | |
| 137 """Returns the output of a command line or an empty string on error.""" | |
| 138 command_line = _build_command_line(config, shell_args, apps_and_args, | |
| 139 run_launcher=run_launcher) | |
| 140 _logging.debug("Running command line: %s" % command_line) | |
| 141 try: | |
| 142 return _run_test(config, shell_args, apps_and_args, context, run_launcher) | |
| 143 except Exception as e: | |
| 144 print_process_error(command_line, e) | |
| 145 return None | |
| 146 | |
| 147 | |
| 148 def _gtest_list_tests(gtest_list_tests_output): | |
| 149 """Returns a list of strings formatted as TestSuite.TestFixture from the | |
| 150 output of running --gtest_list_tests on a GTEST application.""" | |
| 151 | |
| 152 # Remove log lines. | |
| 153 gtest_list_tests_output = ( | |
| 154 re.sub("^\[.*\n", "", gtest_list_tests_output, flags=re.MULTILINE)) | |
| 155 | |
| 156 if not re.match("^(\w*\.\r?\n( \w*\r?\n)+)+", gtest_list_tests_output): | |
| 157 raise Exception("Unrecognized --gtest_list_tests output:\n%s" % | |
| 158 gtest_list_tests_output) | |
| 159 | |
| 160 output_lines = gtest_list_tests_output.split("\n") | |
| 161 | |
| 162 test_list = [] | |
| 163 for line in output_lines: | |
| 164 if not line: | |
| 165 continue | |
| 166 if line[0] != " ": | |
| 167 suite = line.strip() | |
| 168 continue | |
| 169 test_list.append(suite + line.strip()) | |
| 170 | |
| 171 return test_list | |
| OLD | NEW |