blob: 8d365913017c80168be37efe9fb7437af1132af3 [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
26from sets import Set
27import sys
28
29# local imports
30import adb_interface
31import android_build
32import coverage
33import errors
34import logger
35import run_command
36import test_defs
37
38
39class TestRunner(object):
40 """Command line utility class for running pre-defined Android test(s)."""
41
42 # file path to android core platform tests, relative to android build root
43 # TODO move these test data files to another directory
Brett Chabot2d85c0e2009-03-31 15:19:13 -070044 _CORE_TEST_PATH = os.path.join("development", "testrunner", "test_defs.xml")
The Android Open Source Project6ffae012009-03-18 17:39:43 -070045
46 # vendor glob file path patterns to tests, relative to android
47 # build root
48 _VENDOR_TEST_PATH = os.path.join("vendor", "*", "tests", "testinfo",
Brett Chabot2d85c0e2009-03-31 15:19:13 -070049 "test_defs.xml")
The Android Open Source Project6ffae012009-03-18 17:39:43 -070050
51 _RUNTEST_USAGE = (
52 "usage: runtest.py [options] short-test-name[s]\n\n"
53 "The runtest script works in two ways. You can query it "
54 "for a list of tests, or you can launch one or more tests.")
55
Brett Chabot72731f32009-03-31 11:14:05 -070056 def __init__(self):
57 # disable logging of timestamp
58 logger.SetTimestampLogging(False)
59
The Android Open Source Project6ffae012009-03-18 17:39:43 -070060 def _ProcessOptions(self):
61 """Processes command-line options."""
62 # TODO error messages on once-only or mutually-exclusive options.
63 user_test_default = os.path.join(os.environ.get("HOME"), ".android",
Brett Chabot2d85c0e2009-03-31 15:19:13 -070064 "test_defs.xml")
The Android Open Source Project6ffae012009-03-18 17:39:43 -070065
66 parser = optparse.OptionParser(usage=self._RUNTEST_USAGE)
67
68 parser.add_option("-l", "--list-tests", dest="only_list_tests",
69 default=False, action="store_true",
70 help="To view the list of tests")
71 parser.add_option("-b", "--skip-build", dest="skip_build", default=False,
72 action="store_true", help="Skip build - just launch")
73 parser.add_option("-n", "--skip_execute", dest="preview", default=False,
74 action="store_true",
75 help="Do not execute, just preview commands")
76 parser.add_option("-r", "--raw-mode", dest="raw_mode", default=False,
77 action="store_true",
78 help="Raw mode (for output to other tools)")
79 parser.add_option("-a", "--suite-assign", dest="suite_assign_mode",
80 default=False, action="store_true",
81 help="Suite assignment (for details & usage see "
82 "InstrumentationTestRunner)")
83 parser.add_option("-v", "--verbose", dest="verbose", default=False,
84 action="store_true",
85 help="Increase verbosity of %s" % sys.argv[0])
86 parser.add_option("-w", "--wait-for-debugger", dest="wait_for_debugger",
87 default=False, action="store_true",
88 help="Wait for debugger before launching tests")
89 parser.add_option("-c", "--test-class", dest="test_class",
90 help="Restrict test to a specific class")
91 parser.add_option("-m", "--test-method", dest="test_method",
92 help="Restrict test to a specific method")
93 parser.add_option("-u", "--user-tests-file", dest="user_tests_file",
94 metavar="FILE", default=user_test_default,
95 help="Alternate source of user test definitions")
96 parser.add_option("-o", "--coverage", dest="coverage",
97 default=False, action="store_true",
98 help="Generate code coverage metrics for test(s)")
99 parser.add_option("-t", "--all-tests", dest="all_tests",
100 default=False, action="store_true",
101 help="Run all defined tests")
102 parser.add_option("--continuous", dest="continuous_tests",
103 default=False, action="store_true",
104 help="Run all tests defined as part of the continuous "
105 "test set")
106
107 group = optparse.OptionGroup(
108 parser, "Targets", "Use these options to direct tests to a specific "
109 "Android target")
110 group.add_option("-e", "--emulator", dest="emulator", default=False,
111 action="store_true", help="use emulator")
112 group.add_option("-d", "--device", dest="device", default=False,
113 action="store_true", help="use device")
114 group.add_option("-s", "--serial", dest="serial",
115 help="use specific serial")
116 parser.add_option_group(group)
117
118 self._options, self._test_args = parser.parse_args()
119
120 if (not self._options.only_list_tests and not self._options.all_tests
121 and not self._options.continuous_tests and len(self._test_args) < 1):
122 parser.print_help()
123 logger.SilentLog("at least one test name must be specified")
124 raise errors.AbortError
125
126 self._adb = adb_interface.AdbInterface()
127 if self._options.emulator:
128 self._adb.SetEmulatorTarget()
129 elif self._options.device:
130 self._adb.SetDeviceTarget()
131 elif self._options.serial is not None:
132 self._adb.SetTargetSerial(self._options.serial)
133
134 if self._options.verbose:
135 logger.SetVerbose(True)
136
137 self._root_path = android_build.GetTop()
138
139 self._known_tests = self._ReadTests()
140
141 self._coverage_gen = coverage.CoverageGenerator(
142 android_root_path=self._root_path, adb_interface=self._adb)
143
144 def _ReadTests(self):
145 """Parses the set of test definition data.
146
147 Returns:
148 A TestDefinitions object that contains the set of parsed tests.
149 Raises:
150 AbortError: If a fatal error occurred when parsing the tests.
151 """
152 core_test_path = os.path.join(self._root_path, self._CORE_TEST_PATH)
153 try:
154 known_tests = test_defs.TestDefinitions()
155 known_tests.Parse(core_test_path)
Brett Chabot2d85c0e2009-03-31 15:19:13 -0700156 # read all <android root>/vendor/*/tests/testinfo/test_defs.xml paths
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700157 vendor_tests_pattern = os.path.join(self._root_path,
158 self._VENDOR_TEST_PATH)
159 test_file_paths = glob.glob(vendor_tests_pattern)
160 for test_file_path in test_file_paths:
161 known_tests.Parse(test_file_path)
162 if os.path.isfile(self._options.user_tests_file):
163 known_tests.Parse(self._options.user_tests_file)
164 return known_tests
165 except errors.ParseError:
166 raise errors.AbortError
167
168 def _DumpTests(self):
169 """Prints out set of defined tests."""
170 print "The following tests are currently defined:"
171 for test in self._known_tests:
172 print test.GetName()
173
174 def _DoBuild(self):
175 logger.SilentLog("Building tests...")
176 target_set = Set()
177 for test_suite in self._GetTestsToRun():
178 self._AddBuildTarget(test_suite.GetBuildPath(), target_set)
179
180 if target_set:
181 if self._options.coverage:
182 self._coverage_gen.EnableCoverageBuild()
183 self._AddBuildTarget(self._coverage_gen.GetEmmaBuildPath(), target_set)
184 target_build_string = " ".join(list(target_set))
Brett Chabot72731f32009-03-31 11:14:05 -0700185 logger.Log("mmm %s" % target_build_string)
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700186 cmd = 'ONE_SHOT_MAKEFILE="%s" make -C "%s" files' % (target_build_string,
187 self._root_path)
Brett Chabot72731f32009-03-31 11:14:05 -0700188 if self._options.preview:
189 # in preview mode, just display to the user what command would have been
190 # run
191 logger.Log("adb sync")
192 else:
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700193 run_command.RunCommand(cmd, return_output=False)
194 logger.Log("Syncing to device...")
195 self._adb.Sync()
196
197 def _AddBuildTarget(self, build_dir, target_set):
198 if build_dir is not None:
199 build_file_path = os.path.join(build_dir, "Android.mk")
200 if os.path.isfile(os.path.join(self._root_path, build_file_path)):
201 target_set.add(build_file_path)
202
203 def _GetTestsToRun(self):
204 """Get a list of TestSuite objects to run, based on command line args."""
205 if self._options.all_tests:
206 return self._known_tests.GetTests()
207 if self._options.continuous_tests:
208 return self._known_tests.GetContinuousTests()
209 tests = []
210 for name in self._test_args:
211 test = self._known_tests.GetTest(name)
212 if test is None:
213 logger.Log("Error: Could not find test %s" % name)
214 self._DumpTests()
215 raise errors.AbortError
216 tests.append(test)
217 return tests
218
219 def _RunTest(self, test_suite):
220 """Run the provided test suite.
221
222 Builds up an adb instrument command using provided input arguments.
223
224 Args:
225 test_suite: TestSuite to run
226 """
227
228 test_class = test_suite.GetClassName()
229 if self._options.test_class is not None:
230 test_class = self._options.test_class
231 if self._options.test_method is not None:
232 test_class = "%s#%s" % (test_class, self._options.test_method)
233
234 instrumentation_args = {}
235 if test_class is not None:
236 instrumentation_args["class"] = test_class
237 if self._options.wait_for_debugger:
238 instrumentation_args["debug"] = "true"
239 if self._options.suite_assign_mode:
240 instrumentation_args["suiteAssignment"] = "true"
241 if self._options.coverage:
242 instrumentation_args["coverage"] = "true"
243 if self._options.preview:
244 adb_cmd = self._adb.PreviewInstrumentationCommand(
245 package_name=test_suite.GetPackageName(),
246 runner_name=test_suite.GetRunnerName(),
247 raw_mode=self._options.raw_mode,
248 instrumentation_args=instrumentation_args)
249 logger.Log(adb_cmd)
250 else:
251 self._adb.StartInstrumentationNoResults(
252 package_name=test_suite.GetPackageName(),
253 runner_name=test_suite.GetRunnerName(),
254 raw_mode=self._options.raw_mode,
255 instrumentation_args=instrumentation_args)
256 if self._options.coverage and test_suite.GetTargetName() is not None:
257 coverage_file = self._coverage_gen.ExtractReport(test_suite)
258 if coverage_file is not None:
259 logger.Log("Coverage report generated at %s" % coverage_file)
260
261 def RunTests(self):
262 """Main entry method - executes the tests according to command line args."""
263 try:
264 run_command.SetAbortOnError()
265 self._ProcessOptions()
266 if self._options.only_list_tests:
267 self._DumpTests()
268 return
269
Brett Chabot72731f32009-03-31 11:14:05 -0700270 if not self._adb.IsDevicePresent():
271 logger.Log("Error: specified device cannot be found")
272 return
273
The Android Open Source Project6ffae012009-03-18 17:39:43 -0700274 if not self._options.skip_build:
275 self._DoBuild()
276
277 for test_suite in self._GetTestsToRun():
278 self._RunTest(test_suite)
279 except KeyboardInterrupt:
280 logger.Log("Exiting...")
281 except errors.AbortError:
282 logger.SilentLog("Exiting due to AbortError...")
283 except errors.WaitForResponseTimedOutError:
284 logger.Log("Timed out waiting for response")
285
286
287def RunTests():
288 runner = TestRunner()
289 runner.RunTests()
290
291if __name__ == "__main__":
292 RunTests()