diff options
Diffstat (limited to 'testrunner/test_defs/test_walker.py')
-rwxr-xr-x | testrunner/test_defs/test_walker.py | 243 |
1 files changed, 94 insertions, 149 deletions
diff --git a/testrunner/test_defs/test_walker.py b/testrunner/test_defs/test_walker.py index e34dafc24..de93c808e 100755 --- a/testrunner/test_defs/test_walker.py +++ b/testrunner/test_defs/test_walker.py @@ -19,27 +19,31 @@ # python imports import os -import re # local imports import android_build -import android_manifest import android_mk +import gtest import instrumentation_test import logger class TestWalker(object): - """Finds instrumentation tests from filesystem.""" + """Finds Android tests from filesystem.""" def FindTests(self, path): - """Gets list of Android instrumentation tests found at given path. + """Gets list of Android tests found at given path. - Tests are created from the <instrumentation> tags found in - AndroidManifest.xml files relative to the given path. + Tests are created from info found in Android.mk and AndroidManifest.xml + files relative to the given path. + + Currently supported tests are: + - Android application tests run via instrumentation + - native C/C++ tests using GTest framework. (note Android.mk must follow + expected GTest template) FindTests will first scan sub-folders of path for tests. If none are found, - it will scan the file system upwards until a AndroidManifest.xml is found + it will scan the file system upwards until a valid test Android.mk is found or the Android build root is reached. Some sample values for path: @@ -55,6 +59,8 @@ class TestWalker(object): the instrumentation in ApiDemos/tests, with the java package filter set to com.example.android.apis. + TODO: add GTest examples + Args: path: file system path to search @@ -110,204 +116,143 @@ class TestWalker(object): # return string with common build_path removed return path[build_path_len:] - def _FindSubTests(self, path, tests, build_path=None): + def _FindSubTests(self, path, tests, upstream_build_path=None): """Recursively finds all tests within given path. Args: path: absolute file system path to check tests: current list of found tests - build_path: the parent directory where Android.mk that builds sub-folders - was found + upstream_build_path: the parent directory where Android.mk that builds + sub-folders was found Returns: updated list of tests """ if not os.path.isdir(path): return tests - filenames = os.listdir(path) - if filenames.count(android_manifest.AndroidManifest.FILENAME): - # found a manifest! now parse it to find the test definition(s) - manifest = android_manifest.AndroidManifest(app_path=path) - if not build_path: + android_mk_parser = android_mk.CreateAndroidMK(path) + if android_mk_parser: + if not upstream_build_path: # haven't found a parent makefile which builds this dir. Use current # dir as build path - tests.extend(self._CreateSuitesFromManifest( - manifest, self._MakePathRelativeToBuild(path))) + tests.extend(self._CreateSuites( + android_mk_parser, path, self._MakePathRelativeToBuild(path))) else: - tests.extend(self._CreateSuitesFromManifest(manifest, build_path)) - # Try to build as much of original path as possible, so - # keep track of upper-most parent directory where Android.mk was found that - # has rule to build sub-directory makefiles - # this is also necessary in case of overlapping tests - # ie if a test exists at 'foo' directory and 'foo/sub', attempting to - # build both 'foo' and 'foo/sub' will fail. - if filenames.count(android_mk.AndroidMK.FILENAME): - android_mk_parser = android_mk.AndroidMK(app_path=path) + tests.extend(self._CreateSuites(android_mk_parser, path, + upstream_build_path)) + # Try to build as much of original path as possible, so + # keep track of upper-most parent directory where Android.mk was found + # that has rule to build sub-directory makefiles. + # this is also necessary in case of overlapping tests + # ie if a test exists at 'foo' directory and 'foo/sub', attempting to + # build both 'foo' and 'foo/sub' will fail. + if android_mk_parser.HasInclude('call all-makefiles-under,$(LOCAL_PATH)'): - # found rule to build sub-directories. The parent path can be used, + # found rule to build sub-directories. The parent path can be used, # or if not set, use current path - if not build_path: - build_path = self._MakePathRelativeToBuild(path) + if not upstream_build_path: + upstream_build_path = self._MakePathRelativeToBuild(path) else: - build_path = None - for filename in filenames: - self._FindSubTests(os.path.join(path, filename), tests, build_path) + upstream_build_path = None + for filename in os.listdir(path): + self._FindSubTests(os.path.join(path, filename), tests, + upstream_build_path) return tests def _FindUpstreamTests(self, path): """Find tests defined upward from given path. Args: - path: the location to start searching. If it points to a java class file - or java package dir, the appropriate test suite filters will be set + path: the location to start searching. Returns: list of test_suite.AbstractTestSuite found, may be empty """ - class_name_arg = None - package_name = None - # if path is java file, populate class name - if self._IsJavaFile(path): - class_name_arg = self._GetClassNameFromFile(path) - logger.SilentLog('Using java test class %s' % class_name_arg) - elif self._IsJavaPackage(path): - package_name = self._GetPackageNameFromDir(path) - logger.SilentLog('Using java package %s' % package_name) - manifest = self._FindUpstreamManifest(path) - if manifest: - logger.SilentLog('Found AndroidManifest at %s' % manifest.GetAppPath()) - build_path = self._MakePathRelativeToBuild(manifest.GetAppPath()) - return self._CreateSuitesFromManifest(manifest, - build_path, - class_name=class_name_arg, - java_package_name=package_name) - - def _IsJavaFile(self, path): - """Returns true if given file system path is a java file.""" - return os.path.isfile(path) and self._IsJavaFileName(path) - - def _IsJavaFileName(self, filename): - """Returns true if given file name is a java file name.""" - return os.path.splitext(filename)[1] == '.java' - - def _IsJavaPackage(self, path): - """Returns true if given file path is a java package. - - Currently assumes if any java file exists in this directory, than it - represents a java package. - - Args: - path: file system path of directory to check + factory = self._FindUpstreamTestFactory(path) + if factory: + return factory.CreateTests(sub_tests_path=path) + else: + return [] - Returns: - True if path is a java package - """ - if not os.path.isdir(path): - return False - for file_name in os.listdir(path): - if self._IsJavaFileName(file_name): - return True - return False + def _GetTestFactory(self, android_mk_parser, path, upstream_build_path=None): + """Get the test factory for given makefile. - def _GetClassNameFromFile(self, java_file_path): - """Gets the fully qualified java class name from path. + If given path is a valid tests build path, will return the TestFactory + for creating tests. Args: - java_file_path: file system path of java file + android_mk_parser: the android mk to evaluate + path: the filesystem path of the makefile + upstream_build_path: optional filesystem path for the directory + to build when running tests. If unspecified, will use path Returns: - fully qualified java class name or None. + the TestFactory or None if path is not a valid tests build path """ - package_name = self._GetPackageNameFromFile(java_file_path) - if package_name: - filename = os.path.basename(java_file_path) - class_name = os.path.splitext(filename)[0] - return '%s.%s' % (package_name, class_name) - return None + if android_mk_parser.HasGTest(): + return gtest.GTestFactory(path, upstream_build_path=upstream_build_path) + elif android_mk_parser.HasJavaLibrary('android.test.runner'): + return instrumentation_test.InstrumentationTestFactory(path, + upstream_build_path=upstream_build_path) + else: + # somewhat unusual, but will continue searching + logger.SilentLog('Found makefile at %s, but did not detect any tests.' + % path) - def _GetPackageNameFromDir(self, path): - """Gets the java package name associated with given directory path. - - Caveat: currently just parses defined java package name from first java - file found in directory. - - Args: - path: file system path of directory + return None - Returns: - the java package name or None - """ - for filename in os.listdir(path): - if self._IsJavaFileName(filename): - return self._GetPackageNameFromFile(os.path.join(path, filename)) + def _GetTestFactoryForPath(self, path): + """Get the test factory for given path. - def _GetPackageNameFromFile(self, java_file_path): - """Gets the java package name associated with given java file path. + If given path is a valid tests build path, will return the TestFactory + for creating tests. Args: - java_file_path: file system path of java file + path: the filesystem path to evaluate Returns: - the java package name or None + the TestFactory or None if path is not a valid tests build path """ - logger.SilentLog('Looking for java package name in %s' % java_file_path) - re_package = re.compile(r'package\s+(.*);') - file_handle = open(java_file_path, 'r') - for line in file_handle: - match = re_package.match(line) - if match: - return match.group(1) - return None + android_mk_parser = android_mk.CreateAndroidMK(path) + if android_mk_parser: + return self._GetTestFactory(android_mk_parser, path) + else: + return None - def _FindUpstreamManifest(self, path): - """Recursively searches filesystem upwards for a AndroidManifest file. + def _FindUpstreamTestFactory(self, path): + """Recursively searches filesystem upwards for a test factory. Args: path: file system path to search Returns: - the AndroidManifest found or None + the TestFactory found or None """ - if (os.path.isdir(path) and - os.listdir(path).count(android_manifest.AndroidManifest.FILENAME)): - return android_manifest.AndroidManifest(app_path=path) + factory = self._GetTestFactoryForPath(path) + if factory: + return factory dirpath = os.path.dirname(path) if self._IsPathInBuildTree(path): - return self._FindUpstreamManifest(dirpath) - logger.Log('AndroidManifest.xml not found') + return self._FindUpstreamTestFactory(dirpath) + logger.Log('A tests Android.mk was not found') return None - def _CreateSuitesFromManifest(self, manifest, build_path, class_name=None, - java_package_name=None): - """Creates TestSuites from a AndroidManifest. + def _CreateSuites(self, android_mk_parser, path, upstream_build_path): + """Creates TestSuites from a AndroidMK. Args: - manifest: the AndroidManifest - build_path: the build path to use for test - class_name: optionally, the class filter for the suite - java_package_name: optionally, the java package filter for the suite + android_mk_parser: the AndroidMK + path: absolute file system path of the makefile to evaluate + upstream_build_path: the build path to use for test. This can be + different than the 'path', in cases where an upstream makefile + is being used. Returns: the list of tests created """ - tests = [] - for instr_name in manifest.GetInstrumentationNames(): - pkg_name = manifest.GetPackageName() - if instr_name.find(".") < 0: - instr_name = "." + instr_name - logger.SilentLog('Found instrumentation %s/%s' % (pkg_name, instr_name)) - suite = instrumentation_test.InstrumentationTestSuite() - suite.SetPackageName(pkg_name) - suite.SetBuildPath(build_path) - suite.SetRunnerName(instr_name) - suite.SetName(pkg_name) - suite.SetClassName(class_name) - suite.SetJavaPackageFilter(java_package_name) - # this is a bit of a hack, assume if 'com.android.cts' is in - # package name, this is a cts test - # this logic can be removed altogether when cts tests no longer require - # custom build steps - if suite.GetPackageName().startswith('com.android.cts'): - suite.SetSuite('cts') - tests.append(suite) - return tests + factory = self._GetTestFactory(android_mk_parser, path, + upstream_build_path=upstream_build_path) + if factory: + return factory.CreateTests(path) + else: + return [] |