Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 1 | #!/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 |
| 21 | import os |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 22 | |
| 23 | # local imports |
| 24 | import android_build |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 25 | import android_mk |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 26 | import gtest |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 27 | import instrumentation_test |
| 28 | import logger |
| 29 | |
| 30 | |
| 31 | class TestWalker(object): |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 32 | """Finds Android tests from filesystem.""" |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 33 | |
| 34 | def FindTests(self, path): |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 35 | """Gets list of Android tests found at given path. |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 36 | |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 37 | 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 Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 44 | |
| 45 | FindTests will first scan sub-folders of path for tests. If none are found, |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 46 | it will scan the file system upwards until a valid test Android.mk is found |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 47 | 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 Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 62 | TODO: add GTest examples |
| 63 | |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 64 | 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 Carlstrom | 90218ac | 2010-04-09 16:29:17 -0700 | [diff] [blame] | 74 | realpath = os.path.realpath(path) |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 75 | # ensure path is in ANDROID_BUILD_ROOT |
Brian Carlstrom | 90218ac | 2010-04-09 16:29:17 -0700 | [diff] [blame] | 76 | self._build_top = os.path.realpath(android_build.GetTop()) |
| 77 | if not self._IsPathInBuildTree(realpath): |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 78 | 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 Carlstrom | 90218ac | 2010-04-09 16:29:17 -0700 | [diff] [blame] | 84 | tests = self._FindSubTests(realpath, []) |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 85 | if not tests: |
| 86 | logger.SilentLog('No tests found within %s, searching upwards' % path) |
Brian Carlstrom | 90218ac | 2010-04-09 16:29:17 -0700 | [diff] [blame] | 87 | tests = self._FindUpstreamTests(realpath) |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 88 | 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 Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 119 | def _FindSubTests(self, path, tests, upstream_build_path=None): |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 120 | """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 Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 125 | upstream_build_path: the parent directory where Android.mk that builds |
| 126 | sub-folders was found |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 127 | |
| 128 | Returns: |
| 129 | updated list of tests |
| 130 | """ |
| 131 | if not os.path.isdir(path): |
| 132 | return tests |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 133 | android_mk_parser = android_mk.CreateAndroidMK(path) |
| 134 | if android_mk_parser: |
| 135 | if not upstream_build_path: |
Brett Chabot | 12c6d3f | 2010-07-29 15:27:30 -0700 | [diff] [blame] | 136 | # haven't found a parent makefile which builds this dir. Use current |
| 137 | # dir as build path |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 138 | tests.extend(self._CreateSuites( |
| 139 | android_mk_parser, path, self._MakePathRelativeToBuild(path))) |
Brett Chabot | 12c6d3f | 2010-07-29 15:27:30 -0700 | [diff] [blame] | 140 | else: |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 141 | 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 Chabot | 12c6d3f | 2010-07-29 15:27:30 -0700 | [diff] [blame] | 150 | if android_mk_parser.HasInclude('call all-makefiles-under,$(LOCAL_PATH)'): |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 151 | # found rule to build sub-directories. The parent path can be used, |
Brett Chabot | 12c6d3f | 2010-07-29 15:27:30 -0700 | [diff] [blame] | 152 | # or if not set, use current path |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 153 | if not upstream_build_path: |
| 154 | upstream_build_path = self._MakePathRelativeToBuild(path) |
Brett Chabot | 12c6d3f | 2010-07-29 15:27:30 -0700 | [diff] [blame] | 155 | else: |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 156 | 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 Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 160 | return tests |
| 161 | |
| 162 | def _FindUpstreamTests(self, path): |
| 163 | """Find tests defined upward from given path. |
| 164 | |
| 165 | Args: |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 166 | path: the location to start searching. |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 167 | |
| 168 | Returns: |
| 169 | list of test_suite.AbstractTestSuite found, may be empty |
| 170 | """ |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 171 | factory = self._FindUpstreamTestFactory(path) |
| 172 | if factory: |
| 173 | return factory.CreateTests(sub_tests_path=path) |
| 174 | else: |
| 175 | return [] |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 176 | |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 177 | def _GetTestFactory(self, android_mk_parser, path, upstream_build_path=None): |
| 178 | """Get the test factory for given makefile. |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 179 | |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 180 | If given path is a valid tests build path, will return the TestFactory |
| 181 | for creating tests. |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 182 | |
| 183 | Args: |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 184 | 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 Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 188 | |
| 189 | Returns: |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 190 | the TestFactory or None if path is not a valid tests build path |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 191 | """ |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 192 | if android_mk_parser.HasGTest(): |
| 193 | return gtest.GTestFactory(path, upstream_build_path=upstream_build_path) |
Brett Chabot | ecfcc7d | 2011-07-17 14:04:37 -0700 | [diff] [blame^] | 194 | elif instrumentation_test.HasInstrumentationTest(path): |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 195 | 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 Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 201 | |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 202 | return None |
| 203 | |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 204 | def _GetTestFactoryForPath(self, path): |
| 205 | """Get the test factory for given path. |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 206 | |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 207 | If given path is a valid tests build path, will return the TestFactory |
| 208 | for creating tests. |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 209 | |
| 210 | Args: |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 211 | path: the filesystem path to evaluate |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 212 | |
| 213 | Returns: |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 214 | the TestFactory or None if path is not a valid tests build path |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 215 | """ |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 216 | 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 Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 221 | |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 222 | def _FindUpstreamTestFactory(self, path): |
| 223 | """Recursively searches filesystem upwards for a test factory. |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 224 | |
| 225 | Args: |
| 226 | path: file system path to search |
| 227 | |
| 228 | Returns: |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 229 | the TestFactory found or None |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 230 | """ |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 231 | factory = self._GetTestFactoryForPath(path) |
| 232 | if factory: |
| 233 | return factory |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 234 | dirpath = os.path.dirname(path) |
| 235 | if self._IsPathInBuildTree(path): |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 236 | return self._FindUpstreamTestFactory(dirpath) |
| 237 | logger.Log('A tests Android.mk was not found') |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 238 | return None |
| 239 | |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 240 | def _CreateSuites(self, android_mk_parser, path, upstream_build_path): |
| 241 | """Creates TestSuites from a AndroidMK. |
Brett Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 242 | |
| 243 | Args: |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 244 | 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 Chabot | 59b4778 | 2009-10-21 17:23:01 -0700 | [diff] [blame] | 249 | |
| 250 | Returns: |
| 251 | the list of tests created |
| 252 | """ |
Brett Chabot | bb5918e | 2011-06-17 17:07:12 -0700 | [diff] [blame] | 253 | 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 [] |