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 |