blob: 1bbedee712b8f06f7f41a1cc08a2d801b466a151 [file] [log] [blame]
Brett Chabot764d3fa2009-06-25 17:57:31 -07001#!/usr/bin/python2.4
2#
3#
4# Copyright 2008, The Android Open Source Project
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17
18"""TestSuite definition for Android instrumentation tests."""
19
Brett Chabotbb5918e2011-06-17 17:07:12 -070020import os
21import re
22
Brett Chabot764d3fa2009-06-25 17:57:31 -070023# local imports
Brett Chabotbb5918e2011-06-17 17:07:12 -070024import android_manifest
Brett Chabot8ac51182012-09-19 07:35:35 -070025from coverage import coverage
Brett Chabot764d3fa2009-06-25 17:57:31 -070026import errors
27import logger
Brett Chabot924c0892009-10-21 14:23:54 -070028import test_suite
Brett Chabot764d3fa2009-06-25 17:57:31 -070029
30
Brett Chabot924c0892009-10-21 14:23:54 -070031class InstrumentationTestSuite(test_suite.AbstractTestSuite):
32 """Represents a java instrumentation test suite definition run on device."""
Brett Chabot764d3fa2009-06-25 17:57:31 -070033
Brett Chabot924c0892009-10-21 14:23:54 -070034 DEFAULT_RUNNER = "android.test.InstrumentationTestRunner"
Brett Chabot764d3fa2009-06-25 17:57:31 -070035
Brett Chabot924c0892009-10-21 14:23:54 -070036 def __init__(self):
37 test_suite.AbstractTestSuite.__init__(self)
38 self._package_name = None
39 self._runner_name = self.DEFAULT_RUNNER
40 self._class_name = None
41 self._target_name = None
Brett Chabot1cd61742009-10-21 17:00:58 -070042 self._java_package = None
Brett Chabot764d3fa2009-06-25 17:57:31 -070043
44 def GetPackageName(self):
Brett Chabot924c0892009-10-21 14:23:54 -070045 return self._package_name
46
47 def SetPackageName(self, package_name):
48 self._package_name = package_name
49 return self
Brett Chabot764d3fa2009-06-25 17:57:31 -070050
51 def GetRunnerName(self):
Brett Chabot924c0892009-10-21 14:23:54 -070052 return self._runner_name
53
54 def SetRunnerName(self, runner_name):
55 self._runner_name = runner_name
56 return self
Brett Chabot764d3fa2009-06-25 17:57:31 -070057
58 def GetClassName(self):
Brett Chabot924c0892009-10-21 14:23:54 -070059 return self._class_name
60
61 def SetClassName(self, class_name):
62 self._class_name = class_name
63 return self
Brett Chabot764d3fa2009-06-25 17:57:31 -070064
Brett Chabot1cd61742009-10-21 17:00:58 -070065 def GetJavaPackageFilter(self):
66 return self._java_package
67
68 def SetJavaPackageFilter(self, java_package_name):
69 """Configure the suite to only run tests in given java package."""
70 self._java_package = java_package_name
71 return self
72
Brett Chabot764d3fa2009-06-25 17:57:31 -070073 def GetTargetName(self):
74 """Retrieve module that this test is targeting.
75
76 Used for generating code coverage metrics.
Brett Chabot924c0892009-10-21 14:23:54 -070077 Returns:
78 the module target name
Brett Chabot764d3fa2009-06-25 17:57:31 -070079 """
Brett Chabot924c0892009-10-21 14:23:54 -070080 return self._target_name
81
82 def SetTargetName(self, target_name):
83 self._target_name = target_name
84 return self
Brett Chabot764d3fa2009-06-25 17:57:31 -070085
86 def GetBuildDependencies(self, options):
Brett Chabot8ac51182012-09-19 07:35:35 -070087 if options.coverage_target_path:
88 return [options.coverage_target_path]
Brett Chabot764d3fa2009-06-25 17:57:31 -070089 return []
90
Brett Chabot764d3fa2009-06-25 17:57:31 -070091 def Run(self, options, adb):
92 """Run the provided test suite.
93
94 Builds up an adb instrument command using provided input arguments.
95
96 Args:
97 options: command line options to provide to test run
98 adb: adb_interface to device under test
Brett Chabot924c0892009-10-21 14:23:54 -070099
100 Raises:
101 errors.AbortError: if fatal error occurs
Brett Chabot764d3fa2009-06-25 17:57:31 -0700102 """
103
104 test_class = self.GetClassName()
105 if options.test_class is not None:
106 test_class = options.test_class.lstrip()
107 if test_class.startswith("."):
Brett Chabot3ae5f8a2009-06-28 12:00:47 -0700108 test_class = self.GetPackageName() + test_class
Brett Chabot764d3fa2009-06-25 17:57:31 -0700109 if options.test_method is not None:
110 test_class = "%s#%s" % (test_class, options.test_method)
111
Brett Chabot1cd61742009-10-21 17:00:58 -0700112 test_package = self.GetJavaPackageFilter()
113 if options.test_package:
114 test_package = options.test_package
115
116 if test_class and test_package:
117 logger.Log('Error: both class and java package options are specified')
118
Brett Chabot764d3fa2009-06-25 17:57:31 -0700119 instrumentation_args = {}
120 if test_class is not None:
121 instrumentation_args["class"] = test_class
Brett Chabot1cd61742009-10-21 17:00:58 -0700122 if test_package:
123 instrumentation_args["package"] = test_package
Brett Chabot764d3fa2009-06-25 17:57:31 -0700124 if options.test_size:
125 instrumentation_args["size"] = options.test_size
126 if options.wait_for_debugger:
127 instrumentation_args["debug"] = "true"
128 if options.suite_assign_mode:
129 instrumentation_args["suiteAssignment"] = "true"
130 if options.coverage:
131 instrumentation_args["coverage"] = "true"
Brett Chabotc0611542010-02-20 20:09:58 -0800132 if options.test_annotation:
133 instrumentation_args["annotation"] = options.test_annotation
134 if options.test_not_annotation:
135 instrumentation_args["notAnnotation"] = options.test_not_annotation
Brett Chabot764d3fa2009-06-25 17:57:31 -0700136 if options.preview:
137 adb_cmd = adb.PreviewInstrumentationCommand(
138 package_name=self.GetPackageName(),
139 runner_name=self.GetRunnerName(),
140 raw_mode=options.raw_mode,
141 instrumentation_args=instrumentation_args)
142 logger.Log(adb_cmd)
143 elif options.coverage:
144 coverage_gen = coverage.CoverageGenerator(adb)
Brett Chabot8ac51182012-09-19 07:35:35 -0700145 if options.coverage_target_path:
146 coverage_target = coverage_gen.GetCoverageTargetForPath(options.coverage_target_path)
147 elif self.GetTargetName():
148 coverage_target = coverage_gen.GetCoverageTarget(self.GetTargetName())
Brett Chabot81c475e2012-09-11 12:57:31 -0700149 self._CheckInstrumentationInstalled(adb)
Brett Chabot764d3fa2009-06-25 17:57:31 -0700150 # need to parse test output to determine path to coverage file
151 logger.Log("Running in coverage mode, suppressing test output")
152 try:
153 (test_results, status_map) = adb.StartInstrumentationForPackage(
Brett Chabot924c0892009-10-21 14:23:54 -0700154 package_name=self.GetPackageName(),
155 runner_name=self.GetRunnerName(),
156 timeout_time=60*60,
157 instrumentation_args=instrumentation_args)
Brett Chabot764d3fa2009-06-25 17:57:31 -0700158 except errors.InstrumentationError, errors.DeviceUnresponsiveError:
159 return
160 self._PrintTestResults(test_results)
161 device_coverage_path = status_map.get("coverageFilePath", None)
162 if device_coverage_path is None:
163 logger.Log("Error: could not find coverage data on device")
164 return
165
Brett Chabot8424ffc2010-01-21 17:29:18 -0800166 coverage_file = coverage_gen.ExtractReport(
Brett Chabot8ac51182012-09-19 07:35:35 -0700167 self.GetName(), coverage_target, device_coverage_path,
168 test_qualifier=options.test_size)
Brett Chabot764d3fa2009-06-25 17:57:31 -0700169 if coverage_file is not None:
170 logger.Log("Coverage report generated at %s" % coverage_file)
Brett Chabot81c475e2012-09-11 12:57:31 -0700171
Brett Chabot764d3fa2009-06-25 17:57:31 -0700172 else:
Brett Chabot81c475e2012-09-11 12:57:31 -0700173 self._CheckInstrumentationInstalled(adb)
174 adb.StartInstrumentationNoResults(package_name=self.GetPackageName(),
175 runner_name=self.GetRunnerName(),
176 raw_mode=options.raw_mode,
177 instrumentation_args=
178 instrumentation_args)
179
180 def _CheckInstrumentationInstalled(self, adb):
Brett Chabot8ac51182012-09-19 07:35:35 -0700181 if not adb.IsInstrumentationInstalled(self.GetPackageName(),
Brett Chabot81c475e2012-09-11 12:57:31 -0700182 self.GetRunnerName()):
183 msg=("Could not find instrumentation %s/%s on device. Try forcing a "
Brett Chabot8ac51182012-09-19 07:35:35 -0700184 "rebuild by updating a source file, and re-executing runtest." %
Brett Chabot81c475e2012-09-11 12:57:31 -0700185 (self.GetPackageName(), self.GetRunnerName()))
186 raise errors.AbortError(msg=msg)
Brett Chabot764d3fa2009-06-25 17:57:31 -0700187
188 def _PrintTestResults(self, test_results):
189 """Prints a summary of test result data to stdout.
190
191 Args:
192 test_results: a list of am_instrument_parser.TestResult
193 """
194 total_count = 0
195 error_count = 0
196 fail_count = 0
197 for test_result in test_results:
Brett Chabot924c0892009-10-21 14:23:54 -0700198 if test_result.GetStatusCode() == -1: # error
Brett Chabot764d3fa2009-06-25 17:57:31 -0700199 logger.Log("Error in %s: %s" % (test_result.GetTestName(),
200 test_result.GetFailureReason()))
201 error_count+=1
Brett Chabot924c0892009-10-21 14:23:54 -0700202 elif test_result.GetStatusCode() == -2: # failure
Brett Chabot764d3fa2009-06-25 17:57:31 -0700203 logger.Log("Failure in %s: %s" % (test_result.GetTestName(),
204 test_result.GetFailureReason()))
205 fail_count+=1
206 total_count+=1
207 logger.Log("Tests run: %d, Failures: %d, Errors: %d" %
208 (total_count, fail_count, error_count))
Brett Chabotbb5918e2011-06-17 17:07:12 -0700209
Brett Chabotecfcc7d2011-07-17 14:04:37 -0700210def HasInstrumentationTest(path):
211 """Determine if given path defines an instrumentation test.
212
213 Args:
214 path: file system path to instrumentation test.
215 """
216 manifest_parser = android_manifest.CreateAndroidManifest(path)
217 if manifest_parser:
218 return manifest_parser.GetInstrumentationNames()
219 return False
220
Brett Chabotbb5918e2011-06-17 17:07:12 -0700221class InstrumentationTestFactory(test_suite.AbstractTestFactory):
222 """A factory for creating InstrumentationTestSuites"""
223
Brett Chabotb0fd2cf2011-08-01 16:11:43 -0700224 def __init__(self, test_root_path, build_path):
Brett Chabotbb5918e2011-06-17 17:07:12 -0700225 test_suite.AbstractTestFactory.__init__(self, test_root_path,
Brett Chabotb0fd2cf2011-08-01 16:11:43 -0700226 build_path)
Brett Chabotbb5918e2011-06-17 17:07:12 -0700227
228 def CreateTests(self, sub_tests_path=None):
229 """Create tests found in test_path.
230
231 Will create a single InstrumentationTestSuite based on info found in
232 AndroidManifest.xml found at build_path. Will set additional filters if
233 test_path refers to a java package or java class.
234 """
235 tests = []
236 class_name_arg = None
237 java_package_name = None
238 if sub_tests_path:
239 # if path is java file, populate class name
240 if self._IsJavaFile(sub_tests_path):
241 class_name_arg = self._GetClassNameFromFile(sub_tests_path)
242 logger.SilentLog('Using java test class %s' % class_name_arg)
243 elif self._IsJavaPackage(sub_tests_path):
244 java_package_name = self._GetPackageNameFromDir(sub_tests_path)
245 logger.SilentLog('Using java package %s' % java_package_name)
246 try:
247 manifest_parser = android_manifest.AndroidManifest(app_path=
248 self.GetTestsRootPath())
249 instrs = manifest_parser.GetInstrumentationNames()
250 if not instrs:
251 logger.Log('Could not find instrumentation declarations in %s at %s' %
252 (android_manifest.AndroidManifest.FILENAME,
253 self.GetBuildPath()))
254 return tests
Brett Chabotf0afa302012-10-24 15:55:23 -0700255 elif len(instrs) > 1:
Brett Chabot616e8f92012-10-25 11:08:14 -0700256 logger.Log("Found multiple instrumentation declarations in %s/%s. "
Brett Chabotf0afa302012-10-24 15:55:23 -0700257 "Only using first declared." %
258 (self.GetBuildPath(),
259 android_manifest.AndroidManifest.FILENAME))
260 instr_name = manifest_parser.GetInstrumentationNames()[0]
Brett Chabot616e8f92012-10-25 11:08:14 -0700261 # escape inner class names
262 instr_name = instr_name.replace('$', '\$')
Brett Chabotf0afa302012-10-24 15:55:23 -0700263 pkg_name = manifest_parser.GetPackageName()
264 if instr_name.find(".") < 0:
265 instr_name = "." + instr_name
266 logger.SilentLog('Found instrumentation %s/%s' % (pkg_name, instr_name))
267 suite = InstrumentationTestSuite()
268 suite.SetPackageName(pkg_name)
269 suite.SetBuildPath(self.GetBuildPath())
270 suite.SetRunnerName(instr_name)
271 suite.SetName(pkg_name)
272 suite.SetClassName(class_name_arg)
273 suite.SetJavaPackageFilter(java_package_name)
274 # this is a bit of a hack, assume if 'com.android.cts' is in
275 # package name, this is a cts test
276 # this logic can be removed altogether when cts tests no longer require
277 # custom build steps
278 if suite.GetPackageName().startswith('com.android.cts'):
279 suite.SetSuite('cts')
Brett Chabot616e8f92012-10-25 11:08:14 -0700280 tests.append(suite)
Brett Chabotbb5918e2011-06-17 17:07:12 -0700281 return tests
282
283 except:
284 logger.Log('Could not find or parse %s at %s' %
285 (android_manifest.AndroidManifest.FILENAME,
286 self.GetBuildPath()))
287 return tests
288
289 def _IsJavaFile(self, path):
290 """Returns true if given file system path is a java file."""
291 return os.path.isfile(path) and self._IsJavaFileName(path)
292
293 def _IsJavaFileName(self, filename):
294 """Returns true if given file name is a java file name."""
295 return os.path.splitext(filename)[1] == '.java'
296
297 def _IsJavaPackage(self, path):
298 """Returns true if given file path is a java package.
299
300 Currently assumes if any java file exists in this directory, than it
301 represents a java package.
302
303 Args:
304 path: file system path of directory to check
305
306 Returns:
307 True if path is a java package
308 """
309 if not os.path.isdir(path):
310 return False
311 for file_name in os.listdir(path):
312 if self._IsJavaFileName(file_name):
313 return True
314 return False
315
316 def _GetClassNameFromFile(self, java_file_path):
317 """Gets the fully qualified java class name from path.
318
319 Args:
320 java_file_path: file system path of java file
321
322 Returns:
323 fully qualified java class name or None.
324 """
325 package_name = self._GetPackageNameFromFile(java_file_path)
326 if package_name:
327 filename = os.path.basename(java_file_path)
328 class_name = os.path.splitext(filename)[0]
329 return '%s.%s' % (package_name, class_name)
330 return None
331
332 def _GetPackageNameFromDir(self, path):
333 """Gets the java package name associated with given directory path.
334
335 Caveat: currently just parses defined java package name from first java
336 file found in directory.
337
338 Args:
339 path: file system path of directory
340
341 Returns:
342 the java package name or None
343 """
344 for filename in os.listdir(path):
345 if self._IsJavaFileName(filename):
346 return self._GetPackageNameFromFile(os.path.join(path, filename))
347
348 def _GetPackageNameFromFile(self, java_file_path):
349 """Gets the java package name associated with given java file path.
350
351 Args:
352 java_file_path: file system path of java file
353
354 Returns:
355 the java package name or None
356 """
357 logger.SilentLog('Looking for java package name in %s' % java_file_path)
358 re_package = re.compile(r'package\s+(.*);')
359 file_handle = open(java_file_path, 'r')
360 for line in file_handle:
361 match = re_package.match(line)
362 if match:
363 return match.group(1)
364 return None