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