blob: 29891251833658373022be246c43137d4332b5c0 [file] [log] [blame]
Brett Chabot59b47782009-10-21 17:23:01 -07001#!/usr/bin/python2.4
2#
3#
4# Copyright 2009, 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"""Utility to find instrumentation test definitions from file system."""
19
20# python imports
21import os
Brett Chabot59b47782009-10-21 17:23:01 -070022
23# local imports
24import android_build
Brett Chabot59b47782009-10-21 17:23:01 -070025import android_mk
Brett Chabotbb5918e2011-06-17 17:07:12 -070026import gtest
Brett Chabot59b47782009-10-21 17:23:01 -070027import instrumentation_test
28import logger
29
30
31class TestWalker(object):
Brett Chabotbb5918e2011-06-17 17:07:12 -070032 """Finds Android tests from filesystem."""
Brett Chabot59b47782009-10-21 17:23:01 -070033
34 def FindTests(self, path):
Brett Chabotbb5918e2011-06-17 17:07:12 -070035 """Gets list of Android tests found at given path.
Brett Chabot59b47782009-10-21 17:23:01 -070036
Brett Chabotbb5918e2011-06-17 17:07:12 -070037 Tests are created from info found in Android.mk and AndroidManifest.xml
38 files relative to the given path.
39
40 Currently supported tests are:
41 - Android application tests run via instrumentation
42 - native C/C++ tests using GTest framework. (note Android.mk must follow
43 expected GTest template)
Brett Chabot59b47782009-10-21 17:23:01 -070044
45 FindTests will first scan sub-folders of path for tests. If none are found,
Brett Chabotbb5918e2011-06-17 17:07:12 -070046 it will scan the file system upwards until a valid test Android.mk is found
Brett Chabot59b47782009-10-21 17:23:01 -070047 or the Android build root is reached.
48
49 Some sample values for path:
50 - a parent directory containing many tests:
51 ie development/samples will return tests for instrumentation's in ApiDemos,
52 ApiDemos/tests, Notepad/tests etc
53 - a java test class file
54 ie ApiDemos/tests/src/../ApiDemosTest.java will return a test for
55 the instrumentation in ApiDemos/tests, with the class name filter set to
56 ApiDemosTest
57 - a java package directory
58 ie ApiDemos/tests/src/com/example/android/apis will return a test for
59 the instrumentation in ApiDemos/tests, with the java package filter set
60 to com.example.android.apis.
61
Brett Chabotbb5918e2011-06-17 17:07:12 -070062 TODO: add GTest examples
63
Brett Chabot59b47782009-10-21 17:23:01 -070064 Args:
65 path: file system path to search
66
67 Returns:
68 list of test suites that support operations defined by
69 test_suite.AbstractTestSuite
70 """
71 if not os.path.exists(path):
72 logger.Log('%s does not exist' % path)
73 return []
Brian Carlstrom90218ac2010-04-09 16:29:17 -070074 realpath = os.path.realpath(path)
Brett Chabot59b47782009-10-21 17:23:01 -070075 # ensure path is in ANDROID_BUILD_ROOT
Brian Carlstrom90218ac2010-04-09 16:29:17 -070076 self._build_top = os.path.realpath(android_build.GetTop())
77 if not self._IsPathInBuildTree(realpath):
Brett Chabot59b47782009-10-21 17:23:01 -070078 logger.Log('%s is not a sub-directory of build root %s' %
79 (path, self._build_top))
80 return []
81
82 # first, assume path is a parent directory, which specifies to run all
83 # tests within this directory
Brian Carlstrom90218ac2010-04-09 16:29:17 -070084 tests = self._FindSubTests(realpath, [])
Brett Chabot59b47782009-10-21 17:23:01 -070085 if not tests:
86 logger.SilentLog('No tests found within %s, searching upwards' % path)
Brian Carlstrom90218ac2010-04-09 16:29:17 -070087 tests = self._FindUpstreamTests(realpath)
Brett Chabot59b47782009-10-21 17:23:01 -070088 return tests
89
90 def _IsPathInBuildTree(self, path):
91 """Return true if given path is within current Android build tree.
92
93 Args:
94 path: absolute file system path
95
96 Returns:
97 True if path is within Android build tree
98 """
99 return os.path.commonprefix([self._build_top, path]) == self._build_top
100
101 def _MakePathRelativeToBuild(self, path):
102 """Convert given path to one relative to build tree root.
103
104 Args:
105 path: absolute file system path to convert.
106
107 Returns:
108 The converted path relative to build tree root.
109
110 Raises:
111 ValueError: if path is not within build tree
112 """
113 if not self._IsPathInBuildTree(path):
114 raise ValueError
115 build_path_len = len(self._build_top) + 1
116 # return string with common build_path removed
117 return path[build_path_len:]
118
Brett Chabotbb5918e2011-06-17 17:07:12 -0700119 def _FindSubTests(self, path, tests, upstream_build_path=None):
Brett Chabot59b47782009-10-21 17:23:01 -0700120 """Recursively finds all tests within given path.
121
122 Args:
123 path: absolute file system path to check
124 tests: current list of found tests
Brett Chabotbb5918e2011-06-17 17:07:12 -0700125 upstream_build_path: the parent directory where Android.mk that builds
126 sub-folders was found
Brett Chabot59b47782009-10-21 17:23:01 -0700127
128 Returns:
129 updated list of tests
130 """
131 if not os.path.isdir(path):
132 return tests
Brett Chabotbb5918e2011-06-17 17:07:12 -0700133 android_mk_parser = android_mk.CreateAndroidMK(path)
134 if android_mk_parser:
135 if not upstream_build_path:
Brett Chabot12c6d3f2010-07-29 15:27:30 -0700136 # haven't found a parent makefile which builds this dir. Use current
137 # dir as build path
Brett Chabotbb5918e2011-06-17 17:07:12 -0700138 tests.extend(self._CreateSuites(
139 android_mk_parser, path, self._MakePathRelativeToBuild(path)))
Brett Chabot12c6d3f2010-07-29 15:27:30 -0700140 else:
Brett Chabotbb5918e2011-06-17 17:07:12 -0700141 tests.extend(self._CreateSuites(android_mk_parser, path,
142 upstream_build_path))
143 # Try to build as much of original path as possible, so
144 # keep track of upper-most parent directory where Android.mk was found
145 # that has rule to build sub-directory makefiles.
146 # this is also necessary in case of overlapping tests
147 # ie if a test exists at 'foo' directory and 'foo/sub', attempting to
148 # build both 'foo' and 'foo/sub' will fail.
149
Brett Chabot12c6d3f2010-07-29 15:27:30 -0700150 if android_mk_parser.HasInclude('call all-makefiles-under,$(LOCAL_PATH)'):
Brett Chabotbb5918e2011-06-17 17:07:12 -0700151 # found rule to build sub-directories. The parent path can be used,
Brett Chabot12c6d3f2010-07-29 15:27:30 -0700152 # or if not set, use current path
Brett Chabotbb5918e2011-06-17 17:07:12 -0700153 if not upstream_build_path:
154 upstream_build_path = self._MakePathRelativeToBuild(path)
Brett Chabot12c6d3f2010-07-29 15:27:30 -0700155 else:
Brett Chabotbb5918e2011-06-17 17:07:12 -0700156 upstream_build_path = None
157 for filename in os.listdir(path):
158 self._FindSubTests(os.path.join(path, filename), tests,
159 upstream_build_path)
Brett Chabot59b47782009-10-21 17:23:01 -0700160 return tests
161
162 def _FindUpstreamTests(self, path):
163 """Find tests defined upward from given path.
164
165 Args:
Brett Chabotbb5918e2011-06-17 17:07:12 -0700166 path: the location to start searching.
Brett Chabot59b47782009-10-21 17:23:01 -0700167
168 Returns:
169 list of test_suite.AbstractTestSuite found, may be empty
170 """
Brett Chabotbb5918e2011-06-17 17:07:12 -0700171 factory = self._FindUpstreamTestFactory(path)
172 if factory:
173 return factory.CreateTests(sub_tests_path=path)
174 else:
175 return []
Brett Chabot59b47782009-10-21 17:23:01 -0700176
Brett Chabotbb5918e2011-06-17 17:07:12 -0700177 def _GetTestFactory(self, android_mk_parser, path, upstream_build_path=None):
178 """Get the test factory for given makefile.
Brett Chabot59b47782009-10-21 17:23:01 -0700179
Brett Chabotbb5918e2011-06-17 17:07:12 -0700180 If given path is a valid tests build path, will return the TestFactory
181 for creating tests.
Brett Chabot59b47782009-10-21 17:23:01 -0700182
183 Args:
Brett Chabotbb5918e2011-06-17 17:07:12 -0700184 android_mk_parser: the android mk to evaluate
185 path: the filesystem path of the makefile
186 upstream_build_path: optional filesystem path for the directory
187 to build when running tests. If unspecified, will use path
Brett Chabot59b47782009-10-21 17:23:01 -0700188
189 Returns:
Brett Chabotbb5918e2011-06-17 17:07:12 -0700190 the TestFactory or None if path is not a valid tests build path
Brett Chabot59b47782009-10-21 17:23:01 -0700191 """
Brett Chabotbb5918e2011-06-17 17:07:12 -0700192 if android_mk_parser.HasGTest():
193 return gtest.GTestFactory(path, upstream_build_path=upstream_build_path)
Brett Chabotecfcc7d2011-07-17 14:04:37 -0700194 elif instrumentation_test.HasInstrumentationTest(path):
Brett Chabotbb5918e2011-06-17 17:07:12 -0700195 return instrumentation_test.InstrumentationTestFactory(path,
196 upstream_build_path=upstream_build_path)
197 else:
198 # somewhat unusual, but will continue searching
199 logger.SilentLog('Found makefile at %s, but did not detect any tests.'
200 % path)
Brett Chabot59b47782009-10-21 17:23:01 -0700201
Brett Chabot59b47782009-10-21 17:23:01 -0700202 return None
203
Brett Chabotbb5918e2011-06-17 17:07:12 -0700204 def _GetTestFactoryForPath(self, path):
205 """Get the test factory for given path.
Brett Chabot59b47782009-10-21 17:23:01 -0700206
Brett Chabotbb5918e2011-06-17 17:07:12 -0700207 If given path is a valid tests build path, will return the TestFactory
208 for creating tests.
Brett Chabot59b47782009-10-21 17:23:01 -0700209
210 Args:
Brett Chabotbb5918e2011-06-17 17:07:12 -0700211 path: the filesystem path to evaluate
Brett Chabot59b47782009-10-21 17:23:01 -0700212
213 Returns:
Brett Chabotbb5918e2011-06-17 17:07:12 -0700214 the TestFactory or None if path is not a valid tests build path
Brett Chabot59b47782009-10-21 17:23:01 -0700215 """
Brett Chabotbb5918e2011-06-17 17:07:12 -0700216 android_mk_parser = android_mk.CreateAndroidMK(path)
217 if android_mk_parser:
218 return self._GetTestFactory(android_mk_parser, path)
219 else:
220 return None
Brett Chabot59b47782009-10-21 17:23:01 -0700221
Brett Chabotbb5918e2011-06-17 17:07:12 -0700222 def _FindUpstreamTestFactory(self, path):
223 """Recursively searches filesystem upwards for a test factory.
Brett Chabot59b47782009-10-21 17:23:01 -0700224
225 Args:
226 path: file system path to search
227
228 Returns:
Brett Chabotbb5918e2011-06-17 17:07:12 -0700229 the TestFactory found or None
Brett Chabot59b47782009-10-21 17:23:01 -0700230 """
Brett Chabotbb5918e2011-06-17 17:07:12 -0700231 factory = self._GetTestFactoryForPath(path)
232 if factory:
233 return factory
Brett Chabot59b47782009-10-21 17:23:01 -0700234 dirpath = os.path.dirname(path)
235 if self._IsPathInBuildTree(path):
Brett Chabotbb5918e2011-06-17 17:07:12 -0700236 return self._FindUpstreamTestFactory(dirpath)
237 logger.Log('A tests Android.mk was not found')
Brett Chabot59b47782009-10-21 17:23:01 -0700238 return None
239
Brett Chabotbb5918e2011-06-17 17:07:12 -0700240 def _CreateSuites(self, android_mk_parser, path, upstream_build_path):
241 """Creates TestSuites from a AndroidMK.
Brett Chabot59b47782009-10-21 17:23:01 -0700242
243 Args:
Brett Chabotbb5918e2011-06-17 17:07:12 -0700244 android_mk_parser: the AndroidMK
245 path: absolute file system path of the makefile to evaluate
246 upstream_build_path: the build path to use for test. This can be
247 different than the 'path', in cases where an upstream makefile
248 is being used.
Brett Chabot59b47782009-10-21 17:23:01 -0700249
250 Returns:
251 the list of tests created
252 """
Brett Chabotbb5918e2011-06-17 17:07:12 -0700253 factory = self._GetTestFactory(android_mk_parser, path,
254 upstream_build_path=upstream_build_path)
255 if factory:
256 return factory.CreateTests(path)
257 else:
258 return []