blob: f87d451b8e2e93f26daf453108ae318aa833e036 [file] [log] [blame]
The Android Open Source Project6ffae012009-03-18 17:39:43 -07001#!/usr/bin/python2.4
2#
3# Copyright 2008, The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""Command line utility for running a pre-defined test.
18
19Based on previous <androidroot>/development/tools/runtest shell script.
20"""
21
22# Python imports
23import glob
24import optparse
25import os
Niko Catania2e990b92009-04-02 16:52:26 -070026import re
The Android Open Source Project6ffae012009-03-18 17:39:43 -070027from sets import Set
28import sys
29
30# local imports
31import adb_interface
32import android_build
33import coverage
34import errors
35import logger
36import run_command
37import test_defs
38
39
40class TestRunner(object):
41 """Command line utility class for running pre-defined Android test(s)."""
42
Brett Chabotf61f43e2009-04-02 11:52:48 -070043 _TEST_FILE_NAME = "test_defs.xml"
44
The Android Open Source Project6ffae012009-03-18 17:39:43 -070045 # file path to android core platform tests, relative to android build root
46 # TODO move these test data files to another directory
Nicolas Catania97b24c42009-04-22 11:08:32 -070047 _CORE_TEST_PATH = os.path.join("development", "testrunner",
Brett Chabotf61f43e2009-04-02 11:52:48 -070048 _TEST_FILE_NAME)
The Android Open Source Project6ffae012009-03-18 17:39:43 -070049
50 # vendor glob file path patterns to tests, relative to android
51 # build root
52 _VENDOR_TEST_PATH = os.path.join("vendor", "*", "tests", "testinfo",
Brett Chabotf61f43e2009-04-02 11:52:48 -070053 _TEST_FILE_NAME)
The Android Open Source Project6ffae012009-03-18 17:39:43 -070054
55 _RUNTEST_USAGE = (
56 "usage: runtest.py [options] short-test-name[s]\n\n"
57 "The runtest script works in two ways. You can query it "
58 "for a list of tests, or you can launch one or more tests.")
59
Brett Chabot72731f32009-03-31 11:14:05 -070060 def __init__(self):
61 # disable logging of timestamp
Niko Catania2e990b92009-04-02 16:52:26 -070062 self._root_path = android_build.GetTop()
Nicolas Catania97b24c42009-04-22 11:08:32 -070063 logger.SetTimestampLogging(False)
Brett Chabot72731f32009-03-31 11:14:05 -070064
The Android Open Source Project6ffae012009-03-18 17:39:43 -070065 def _ProcessOptions(self):
66 """Processes command-line options."""
67 # TODO error messages on once-only or mutually-exclusive options.
68 user_test_default = os.path.join(os.environ.get("HOME"), ".android",
Brett Chabotf61f43e2009-04-02 11:52:48 -070069 self._TEST_FILE_NAME)
The Android Open Source Project6ffae012009-03-18 17:39:43 -070070
71 parser = optparse.OptionParser(usage=self._RUNTEST_USAGE)
72
73 parser.add_option("-l", "--list-tests", dest="only_list_tests",
74 default=False, action="store_true",
75 help="To view the list of tests")
76 parser.add_option("-b", "--skip-build", dest="skip_build", default=False,
77 action="store_true", help="Skip build - just launch")
78 parser.add_option("-n", "--skip_execute", dest="preview", default=False,
79 action="store_true",
80 help="Do not execute, just preview commands")
81 parser.add_option("-r", "--raw-mode", dest="raw_mode", default=False,
82 action="store_true",
83 help="Raw mode (for output to other tools)")
84 parser.add_option("-a", "--suite-assign", dest="suite_assign_mode",
85 default=False, action="store_true",
86 help="Suite assignment (for details & usage see "
87 "InstrumentationTestRunner)")
88 parser.add_option("-v", "--verbose", dest="verbose", default=False,
89 action="store_true",
90 help="Increase verbosity of %s" % sys.argv[0])
91 parser.add_option("-w", "--wait-for-debugger", dest="wait_for_debugger",
92 default=False, action="store_true",
93 help="Wait for debugger before launching tests")
94 parser.add_option("-c", "--test-class", dest="test_class",
95 help="Restrict test to a specific class")
96 parser.add_option("-m", "--test-method", dest="test_method",
97 help="Restrict test to a specific method")
98 parser.add_option("-u", "--user-tests-file", dest="user_tests_file",
99 metavar="FILE", default=user_test_default,
100 help="Alternate source of user test definitions")
101 parser.add_option("-o", "--coverage", dest="coverage",
102 default=False, action="store_true",
103 help="Generate code coverage metrics for test(s)")
104 parser.add_option("-t", "--all-tests", dest="all_tests",
105 default=False, action="store_true",
106 help="Run all defined tests")
107 parser.add_option("--continuous", dest="continuous_tests",
108 default=False, action="store_true",
109 help="Run all tests defined as part of the continuous "
110 "test set")
111
112 group = optparse.OptionGroup(
113 parser, "Targets", "Use these options to direct tests to a specific "
114 "Android target")
115 group.add_option("-e", "--emulator", dest="emulator", default=False,
116 action="store_true", help="use emulator")
117 group.add_option("-d", "--device", dest="device", default=False,
118 action="store_true", help="use device")
119 group.add_option("-s", "--serial", dest="serial",
120 help="use specific serial")
121 parser.add_option_group(group)
122
123 self._options, self._test_args = parser.parse_args()
124
125 if (not self._options.only_list_tests and not self._options.all_tests
126 and not self._options.continuous_tests and len(self._test_args) < 1):
127 parser.print_help()
128 logger.SilentLog("at least one test name must be specified")
129 raise errors.AbortError
130
131 self._adb = adb_interface.AdbInterface()
132 if self._options.emulator:
133 self._adb.SetEmulatorTarget()
134 elif self._options.device:
135 self._adb.SetDeviceTarget()
136 elif self._options.serial is not None:
137 self._adb.SetTargetSerial(self._options.serial)
138
139 if self._options.verbose:
140 logger.SetVerbose(True)
141
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700142 self._known_tests = self._ReadTests()
143
144 self._coverage_gen = coverage.CoverageGenerator(
145 android_root_path=self._root_path, adb_interface=self._adb)
146
147 def _ReadTests(self):
148 """Parses the set of test definition data.
149
150 Returns:
151 A TestDefinitions object that contains the set of parsed tests.
152 Raises:
153 AbortError: If a fatal error occurred when parsing the tests.
154 """
155 core_test_path = os.path.join(self._root_path, self._CORE_TEST_PATH)
156 try:
157 known_tests = test_defs.TestDefinitions()
158 known_tests.Parse(core_test_path)
Brett Chabot2d85c0e2009-03-31 15:19:13 -0700159 # read all <android root>/vendor/*/tests/testinfo/test_defs.xml paths
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700160 vendor_tests_pattern = os.path.join(self._root_path,
161 self._VENDOR_TEST_PATH)
162 test_file_paths = glob.glob(vendor_tests_pattern)
163 for test_file_path in test_file_paths:
164 known_tests.Parse(test_file_path)
165 if os.path.isfile(self._options.user_tests_file):
166 known_tests.Parse(self._options.user_tests_file)
167 return known_tests
168 except errors.ParseError:
169 raise errors.AbortError
170
171 def _DumpTests(self):
172 """Prints out set of defined tests."""
173 print "The following tests are currently defined:"
174 for test in self._known_tests:
Niko Catania2e990b92009-04-02 16:52:26 -0700175 print "%-15s %s" % (test.GetName(), test.GetDescription())
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700176
177 def _DoBuild(self):
178 logger.SilentLog("Building tests...")
179 target_set = Set()
Niko Cataniaa6dc2ab2009-04-03 14:12:46 -0700180 extra_args_set = Set()
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700181 for test_suite in self._GetTestsToRun():
Niko Cataniaa6dc2ab2009-04-03 14:12:46 -0700182 self._AddBuildTarget(test_suite, target_set, extra_args_set)
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700183
184 if target_set:
185 if self._options.coverage:
186 self._coverage_gen.EnableCoverageBuild()
Brett Chabot2b6643b2009-04-07 18:35:27 -0700187 self._AddBuildTargetPath(self._coverage_gen.GetEmmaBuildPath(),
188 target_set)
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700189 target_build_string = " ".join(list(target_set))
Niko Cataniaa6dc2ab2009-04-03 14:12:46 -0700190 extra_args_string = " ".join(list(extra_args_set))
Brett Chabot2b6643b2009-04-07 18:35:27 -0700191 # log the user-friendly equivalent make command, so developers can
192 # replicate this step
193 logger.Log("mmm %s %s" % (target_build_string, extra_args_string))
194 # mmm cannot be used from python, so perform a similiar operation using
195 # ONE_SHOT_MAKEFILE
Niko Cataniaa6dc2ab2009-04-03 14:12:46 -0700196 cmd = 'ONE_SHOT_MAKEFILE="%s" make -C "%s" files %s' % (
197 target_build_string, self._root_path, extra_args_string)
Niko Cataniaa6dc2ab2009-04-03 14:12:46 -0700198
Brett Chabot72731f32009-03-31 11:14:05 -0700199 if self._options.preview:
200 # in preview mode, just display to the user what command would have been
201 # run
202 logger.Log("adb sync")
203 else:
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700204 run_command.RunCommand(cmd, return_output=False)
205 logger.Log("Syncing to device...")
206 self._adb.Sync()
207
Niko Cataniaa6dc2ab2009-04-03 14:12:46 -0700208 def _AddBuildTarget(self, test_suite, target_set, extra_args_set):
209 build_dir = test_suite.GetBuildPath()
Brett Chabot2b6643b2009-04-07 18:35:27 -0700210 if self._AddBuildTargetPath(build_dir, target_set):
211 extra_args_set.add(test_suite.GetExtraMakeArgs())
212
213 def _AddBuildTargetPath(self, build_dir, target_set):
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700214 if build_dir is not None:
215 build_file_path = os.path.join(build_dir, "Android.mk")
216 if os.path.isfile(os.path.join(self._root_path, build_file_path)):
217 target_set.add(build_file_path)
Brett Chabot2b6643b2009-04-07 18:35:27 -0700218 return True
219 return False
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700220
221 def _GetTestsToRun(self):
222 """Get a list of TestSuite objects to run, based on command line args."""
223 if self._options.all_tests:
224 return self._known_tests.GetTests()
225 if self._options.continuous_tests:
226 return self._known_tests.GetContinuousTests()
227 tests = []
228 for name in self._test_args:
229 test = self._known_tests.GetTest(name)
230 if test is None:
231 logger.Log("Error: Could not find test %s" % name)
232 self._DumpTests()
233 raise errors.AbortError
234 tests.append(test)
235 return tests
236
237 def _RunTest(self, test_suite):
238 """Run the provided test suite.
239
240 Builds up an adb instrument command using provided input arguments.
241
242 Args:
243 test_suite: TestSuite to run
244 """
245
246 test_class = test_suite.GetClassName()
247 if self._options.test_class is not None:
248 test_class = self._options.test_class
249 if self._options.test_method is not None:
250 test_class = "%s#%s" % (test_class, self._options.test_method)
251
252 instrumentation_args = {}
253 if test_class is not None:
254 instrumentation_args["class"] = test_class
255 if self._options.wait_for_debugger:
256 instrumentation_args["debug"] = "true"
257 if self._options.suite_assign_mode:
258 instrumentation_args["suiteAssignment"] = "true"
259 if self._options.coverage:
260 instrumentation_args["coverage"] = "true"
261 if self._options.preview:
262 adb_cmd = self._adb.PreviewInstrumentationCommand(
263 package_name=test_suite.GetPackageName(),
264 runner_name=test_suite.GetRunnerName(),
265 raw_mode=self._options.raw_mode,
266 instrumentation_args=instrumentation_args)
267 logger.Log(adb_cmd)
268 else:
269 self._adb.StartInstrumentationNoResults(
270 package_name=test_suite.GetPackageName(),
271 runner_name=test_suite.GetRunnerName(),
272 raw_mode=self._options.raw_mode,
273 instrumentation_args=instrumentation_args)
274 if self._options.coverage and test_suite.GetTargetName() is not None:
275 coverage_file = self._coverage_gen.ExtractReport(test_suite)
276 if coverage_file is not None:
277 logger.Log("Coverage report generated at %s" % coverage_file)
278
Niko Catania2e990b92009-04-02 16:52:26 -0700279 def _RunNativeTest(self, test_suite):
280 """Run the provided *native* test suite.
281
282 The test_suite must contain a build path where the native test files are.
283 Each test's name must start with 'test_' and have a .cc or .cpp extension.
284 A successful test must return 0. Any other value will be considered
285 as an error.
286
287 Args:
288 test_suite: TestSuite to run
289 """
290 # find all test files, convert unicode names to ascii, take the basename
291 # and drop the .cc/.cpp extension.
292 file_pattern = os.path.join(test_suite.GetBuildPath(), "test_*")
Nicolas Catania97b24c42009-04-22 11:08:32 -0700293 logger.SilentLog("Scanning %s" % test_suite.GetBuildPath())
Niko Catania2e990b92009-04-02 16:52:26 -0700294 file_list = []
295 for f in map(str, glob.glob(file_pattern)):
296 f = os.path.basename(f)
297 f = re.split(".[cp]+$", f)[0]
Nicolas Catania97b24c42009-04-22 11:08:32 -0700298 logger.SilentLog("Found %s" % f)
Niko Catania2e990b92009-04-02 16:52:26 -0700299 file_list.append(f)
300
Nicolas Catania97b24c42009-04-22 11:08:32 -0700301 # Run on the host
302 logger.Log("\nRunning on host")
303 for f in file_list:
304 if run_command.RunHostCommand(f) != 0:
305 logger.Log("%s... failed" % f)
306 else:
307 if run_command.RunHostCommand(f, valgrind=True) == 0:
308 logger.Log("%s... ok\t\t[valgrind: ok]" % f)
309 else:
310 logger.Log("%s... ok\t\t[valgrind: failed]" % f)
311
312 # Run on the device
313 logger.Log("\nRunning on target")
Niko Catania2e990b92009-04-02 16:52:26 -0700314 for f in file_list:
315 full_path = "/system/bin/%s" % f
316
Niko Cataniafa14bd52009-04-09 16:50:54 -0700317 # Single quotes are needed to prevent the shell splitting it.
318 status = self._adb.SendShellCommand("'%s >/dev/null 2>&1;echo -n $?'" %
Niko Catania2e990b92009-04-02 16:52:26 -0700319 full_path)
320 logger.Log("%s... %s" % (f, status == "0" and "ok" or "failed"))
321
322 # Cleanup
323 self._adb.SendShellCommand("rm %s" % full_path)
324
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700325 def RunTests(self):
326 """Main entry method - executes the tests according to command line args."""
327 try:
328 run_command.SetAbortOnError()
329 self._ProcessOptions()
330 if self._options.only_list_tests:
331 self._DumpTests()
332 return
333
Brett Chabot72731f32009-03-31 11:14:05 -0700334 if not self._adb.IsDevicePresent():
335 logger.Log("Error: specified device cannot be found")
336 return
337
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700338 if not self._options.skip_build:
339 self._DoBuild()
340
341 for test_suite in self._GetTestsToRun():
Niko Catania2e990b92009-04-02 16:52:26 -0700342 if test_suite.IsNative():
343 self._RunNativeTest(test_suite)
344 else:
345 self._RunTest(test_suite)
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700346 except KeyboardInterrupt:
347 logger.Log("Exiting...")
348 except errors.AbortError:
349 logger.SilentLog("Exiting due to AbortError...")
350 except errors.WaitForResponseTimedOutError:
351 logger.Log("Timed out waiting for response")
352
353
354def RunTests():
355 runner = TestRunner()
356 runner.RunTests()
357
358if __name__ == "__main__":
359 RunTests()