blob: c13fb4cc959384822bde4fe36e0c2778a8db8813 [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
Brett Chabotf61f43e2009-04-02 11:52:48 -070047 _CORE_TEST_PATH = os.path.join("development", "testrunner",
48 _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()
Brett Chabot72731f32009-03-31 11:14:05 -070063 logger.SetTimestampLogging(False)
64
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()
187 self._AddBuildTarget(self._coverage_gen.GetEmmaBuildPath(), target_set)
188 target_build_string = " ".join(list(target_set))
Niko Cataniaa6dc2ab2009-04-03 14:12:46 -0700189 extra_args_string = " ".join(list(extra_args_set))
190 cmd = 'ONE_SHOT_MAKEFILE="%s" make -C "%s" files %s' % (
191 target_build_string, self._root_path, extra_args_string)
192 logger.Log(cmd)
193
Brett Chabot72731f32009-03-31 11:14:05 -0700194 if self._options.preview:
195 # in preview mode, just display to the user what command would have been
196 # run
197 logger.Log("adb sync")
198 else:
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700199 run_command.RunCommand(cmd, return_output=False)
200 logger.Log("Syncing to device...")
201 self._adb.Sync()
202
Niko Cataniaa6dc2ab2009-04-03 14:12:46 -0700203 def _AddBuildTarget(self, test_suite, target_set, extra_args_set):
204 build_dir = test_suite.GetBuildPath()
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700205 if build_dir is not None:
206 build_file_path = os.path.join(build_dir, "Android.mk")
207 if os.path.isfile(os.path.join(self._root_path, build_file_path)):
208 target_set.add(build_file_path)
Niko Cataniaa6dc2ab2009-04-03 14:12:46 -0700209 extra_args_set.add(test_suite.GetExtraMakeArgs())
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700210
211 def _GetTestsToRun(self):
212 """Get a list of TestSuite objects to run, based on command line args."""
213 if self._options.all_tests:
214 return self._known_tests.GetTests()
215 if self._options.continuous_tests:
216 return self._known_tests.GetContinuousTests()
217 tests = []
218 for name in self._test_args:
219 test = self._known_tests.GetTest(name)
220 if test is None:
221 logger.Log("Error: Could not find test %s" % name)
222 self._DumpTests()
223 raise errors.AbortError
224 tests.append(test)
225 return tests
226
227 def _RunTest(self, test_suite):
228 """Run the provided test suite.
229
230 Builds up an adb instrument command using provided input arguments.
231
232 Args:
233 test_suite: TestSuite to run
234 """
235
236 test_class = test_suite.GetClassName()
237 if self._options.test_class is not None:
238 test_class = self._options.test_class
239 if self._options.test_method is not None:
240 test_class = "%s#%s" % (test_class, self._options.test_method)
241
242 instrumentation_args = {}
243 if test_class is not None:
244 instrumentation_args["class"] = test_class
245 if self._options.wait_for_debugger:
246 instrumentation_args["debug"] = "true"
247 if self._options.suite_assign_mode:
248 instrumentation_args["suiteAssignment"] = "true"
249 if self._options.coverage:
250 instrumentation_args["coverage"] = "true"
251 if self._options.preview:
252 adb_cmd = self._adb.PreviewInstrumentationCommand(
253 package_name=test_suite.GetPackageName(),
254 runner_name=test_suite.GetRunnerName(),
255 raw_mode=self._options.raw_mode,
256 instrumentation_args=instrumentation_args)
257 logger.Log(adb_cmd)
258 else:
259 self._adb.StartInstrumentationNoResults(
260 package_name=test_suite.GetPackageName(),
261 runner_name=test_suite.GetRunnerName(),
262 raw_mode=self._options.raw_mode,
263 instrumentation_args=instrumentation_args)
264 if self._options.coverage and test_suite.GetTargetName() is not None:
265 coverage_file = self._coverage_gen.ExtractReport(test_suite)
266 if coverage_file is not None:
267 logger.Log("Coverage report generated at %s" % coverage_file)
268
Niko Catania2e990b92009-04-02 16:52:26 -0700269 def _RunNativeTest(self, test_suite):
270 """Run the provided *native* test suite.
271
272 The test_suite must contain a build path where the native test files are.
273 Each test's name must start with 'test_' and have a .cc or .cpp extension.
274 A successful test must return 0. Any other value will be considered
275 as an error.
276
277 Args:
278 test_suite: TestSuite to run
279 """
280 # find all test files, convert unicode names to ascii, take the basename
281 # and drop the .cc/.cpp extension.
282 file_pattern = os.path.join(test_suite.GetBuildPath(), "test_*")
283 file_list = []
284 for f in map(str, glob.glob(file_pattern)):
285 f = os.path.basename(f)
286 f = re.split(".[cp]+$", f)[0]
287 file_list.append(f)
288
289 for f in file_list:
290 full_path = "/system/bin/%s" % f
291
292 # Run
293 status = self._adb.SendShellCommand("%s >/dev/null 2>&1;echo -n $?" %
294 full_path)
295 logger.Log("%s... %s" % (f, status == "0" and "ok" or "failed"))
296
297 # Cleanup
298 self._adb.SendShellCommand("rm %s" % full_path)
299
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700300 def RunTests(self):
301 """Main entry method - executes the tests according to command line args."""
302 try:
303 run_command.SetAbortOnError()
304 self._ProcessOptions()
305 if self._options.only_list_tests:
306 self._DumpTests()
307 return
308
Brett Chabot72731f32009-03-31 11:14:05 -0700309 if not self._adb.IsDevicePresent():
310 logger.Log("Error: specified device cannot be found")
311 return
312
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700313 if not self._options.skip_build:
314 self._DoBuild()
315
316 for test_suite in self._GetTestsToRun():
Niko Catania2e990b92009-04-02 16:52:26 -0700317 if test_suite.IsNative():
318 self._RunNativeTest(test_suite)
319 else:
320 self._RunTest(test_suite)
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700321 except KeyboardInterrupt:
322 logger.Log("Exiting...")
323 except errors.AbortError:
324 logger.SilentLog("Exiting due to AbortError...")
325 except errors.WaitForResponseTimedOutError:
326 logger.Log("Timed out waiting for response")
327
328
329def RunTests():
330 runner = TestRunner()
331 runner.RunTests()
332
333if __name__ == "__main__":
334 RunTests()