Broaden the search for native test files.
Previously we were looking for test files with this pattern: test_* I added *_test.[cc|cpp] and *_unittest.[cc|cpp] The search also scan all the subdirectories of the build_path from the test definition. I added a filtering stage where missing tests are ignored. For instance we may have a source file that has not been built for the target, in which case it is ignored when we run the target tests. In android_build.py I added 4 helper functions to get access to the build environment: - GetHostBin - GetProductOut - GetTargetSystemBin - GetHostOsArch Replace all the hardcoded linux-x86 strings with the value returned by GetHostOsArch.
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
|
||||
# Python imports
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
# local imports
|
||||
import errors
|
||||
@@ -38,8 +40,96 @@ def GetTop():
|
||||
AbortError: if Android build root could not be found.
|
||||
"""
|
||||
# TODO: does this need to be reimplemented to be like gettop() in envsetup.sh
|
||||
root_path = os.getenv('ANDROID_BUILD_TOP')
|
||||
root_path = os.getenv("ANDROID_BUILD_TOP")
|
||||
if root_path is None:
|
||||
logger.Log('Error: ANDROID_BUILD_TOP not defined. Please run envsetup.sh')
|
||||
logger.Log("Error: ANDROID_BUILD_TOP not defined. Please run envsetup.sh")
|
||||
raise errors.AbortError
|
||||
return root_path
|
||||
|
||||
|
||||
def GetHostOsArch():
|
||||
"""Identify the host os and arch.
|
||||
|
||||
Returns:
|
||||
The triple (HOST_OS, HOST_ARCH, HOST_OS-HOST_ARCH).
|
||||
|
||||
Raises:
|
||||
AbortError: If the os and/or arch could not be found.
|
||||
"""
|
||||
command = ("CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core "
|
||||
"make --no-print-directory -C \"%s\" -f build/core/config.mk "
|
||||
"dumpvar-report_config") % GetTop()
|
||||
|
||||
# Use the shell b/c we set some env variables before the make command.
|
||||
config = subprocess.Popen(command, stdout=subprocess.PIPE,
|
||||
shell=True).communicate()[0]
|
||||
host_os = re.search("HOST_OS=(\w+)", config).group(1)
|
||||
host_arch = re.search("HOST_ARCH=(\w+)", config).group(1)
|
||||
if not (host_os and host_arch):
|
||||
logger.Log("Error: Could not get host's OS and/or ARCH")
|
||||
raise errors.AbortError
|
||||
return (host_os, host_arch, "%s-%s" % (host_os, host_arch))
|
||||
|
||||
|
||||
def GetHostBin():
|
||||
"""Compute the full pathname to the host binary directory.
|
||||
|
||||
Typically $ANDROID_BUILD_TOP/out/host/linux-x86/bin.
|
||||
|
||||
Assumes build environment has been properly configured by envsetup &
|
||||
lunch/choosecombo.
|
||||
|
||||
Returns:
|
||||
The absolute file path of the Android host binary directory.
|
||||
|
||||
Raises:
|
||||
AbortError: if Android host binary directory could not be found.
|
||||
"""
|
||||
(_, _, os_arch) = GetHostOsArch()
|
||||
path = os.path.join(GetTop(), "out", "host", os_arch, "bin")
|
||||
if not os.path.exists(path):
|
||||
logger.Log("Error: Host bin path could not be found %s" % path)
|
||||
raise errors.AbortError
|
||||
return path
|
||||
|
||||
|
||||
def GetProductOut():
|
||||
"""Returns the full pathname to the target/product directory.
|
||||
|
||||
Typically the value of the env variable $ANDROID_PRODUCT_OUT.
|
||||
|
||||
Assumes build environment has been properly configured by envsetup &
|
||||
lunch/choosecombo.
|
||||
|
||||
Returns:
|
||||
The absolute file path of the Android product directory.
|
||||
|
||||
Raises:
|
||||
AbortError: if Android product directory could not be found.
|
||||
"""
|
||||
path = os.getenv("ANDROID_PRODUCT_OUT")
|
||||
if path is None:
|
||||
logger.Log("Error: ANDROID_PRODUCT_OUT not defined. Please run envsetup.sh")
|
||||
raise errors.AbortError
|
||||
return path
|
||||
|
||||
|
||||
def GetTargetSystemBin():
|
||||
"""Returns the full pathname to the target/product system/bin directory.
|
||||
|
||||
Typically the value of the env variable $ANDROID_PRODUCT_OUT/system/bin
|
||||
|
||||
Assumes build environment has been properly configured by envsetup &
|
||||
lunch/choosecombo.
|
||||
|
||||
Returns:
|
||||
The absolute file path of the Android target system bin directory.
|
||||
|
||||
Raises:
|
||||
AbortError: if Android target system bin directory could not be found.
|
||||
"""
|
||||
path = os.path.join(GetProductOut(), "system", "bin")
|
||||
if not os.path.exists(path):
|
||||
logger.Log("Error: Target system bin path could not be found")
|
||||
raise errors.AbortError
|
||||
return path
|
||||
|
||||
@@ -23,6 +23,7 @@ import threading
|
||||
import time
|
||||
|
||||
# local imports
|
||||
import android_build
|
||||
import errors
|
||||
import logger
|
||||
|
||||
@@ -128,13 +129,13 @@ def RunHostCommand(binary, valgrind=False):
|
||||
|
||||
Args:
|
||||
binary: basename of the file to be run. It is expected to be under
|
||||
out/host/linux-x86/bin.
|
||||
out/host/<os>-<arch>/bin.
|
||||
valgrind: If True the command will be run under valgrind.
|
||||
|
||||
Returns:
|
||||
The command exit code (int)
|
||||
"""
|
||||
full_path = os.path.join("out", "host", "linux-x86", "bin", binary)
|
||||
full_path = os.path.join(android_build.GetHostBin(), binary)
|
||||
if not valgrind:
|
||||
subproc = subprocess.Popen(full_path, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
|
||||
@@ -276,11 +276,61 @@ class TestRunner(object):
|
||||
if coverage_file is not None:
|
||||
logger.Log("Coverage report generated at %s" % coverage_file)
|
||||
|
||||
def _CollectTestSources(self, test_list, dirname, files):
|
||||
"""For each directory, find tests source file and add them to the list.
|
||||
|
||||
Test files must match one of the following pattern:
|
||||
- test_*.[cc|cpp]
|
||||
- *_test.[cc|cpp]
|
||||
- *_unittest.[cc|cpp]
|
||||
|
||||
This method is a callback for os.path.walk.
|
||||
|
||||
Args:
|
||||
test_list: Where new tests should be inserted.
|
||||
dirname: Current directory.
|
||||
files: List of files in the current directory.
|
||||
"""
|
||||
for f in files:
|
||||
(name, ext) = os.path.splitext(f)
|
||||
if ext == ".cc" or ext == ".cpp":
|
||||
if re.search("_test$|_test_$|_unittest$|_unittest_$|^test_", name):
|
||||
logger.SilentLog("Found %s" % f)
|
||||
test_list.append(str(os.path.join(dirname, f)))
|
||||
|
||||
def _FilterOutMissing(self, path, sources):
|
||||
"""Filter out from the sources list missing tests.
|
||||
|
||||
Sometimes some test source are not built for the target, i.e there
|
||||
is no binary corresponding to the source file. We need to filter
|
||||
these out.
|
||||
|
||||
Args:
|
||||
path: Where the binaries should be.
|
||||
sources: List of tests source path.
|
||||
Returns:
|
||||
A list of test binaries built from the sources.
|
||||
"""
|
||||
binaries = []
|
||||
for f in sources:
|
||||
binary = os.path.basename(f)
|
||||
binary = os.path.splitext(binary)[0]
|
||||
full_path = os.path.join(path, binary)
|
||||
if os.path.exists(full_path):
|
||||
binaries.append(binary)
|
||||
return binaries
|
||||
|
||||
def _RunNativeTest(self, test_suite):
|
||||
"""Run the provided *native* test suite.
|
||||
|
||||
The test_suite must contain a build path where the native test files are.
|
||||
Each test's name must start with 'test_' and have a .cc or .cpp extension.
|
||||
The test_suite must contain a build path where the native test
|
||||
files are. Subdirectories are automatically scanned as well.
|
||||
|
||||
Each test's name must have a .cc or .cpp extension and match one
|
||||
of the following patterns:
|
||||
- test_*
|
||||
- *_test.[cc|cpp]
|
||||
- *_unittest.[cc|cpp]
|
||||
A successful test must return 0. Any other value will be considered
|
||||
as an error.
|
||||
|
||||
@@ -289,18 +339,23 @@ class TestRunner(object):
|
||||
"""
|
||||
# find all test files, convert unicode names to ascii, take the basename
|
||||
# and drop the .cc/.cpp extension.
|
||||
file_pattern = os.path.join(test_suite.GetBuildPath(), "test_*")
|
||||
logger.SilentLog("Scanning %s" % test_suite.GetBuildPath())
|
||||
file_list = []
|
||||
for f in map(str, glob.glob(file_pattern)):
|
||||
f = os.path.basename(f)
|
||||
f = re.split(".[cp]+$", f)[0]
|
||||
logger.SilentLog("Found %s" % f)
|
||||
file_list.append(f)
|
||||
source_list = []
|
||||
build_path = test_suite.GetBuildPath()
|
||||
os.path.walk(build_path, self._CollectTestSources, source_list)
|
||||
logger.SilentLog("Tests source %s" % source_list)
|
||||
|
||||
# Host tests are under out/host/<os>-<arch>/bin.
|
||||
host_list = self._FilterOutMissing(android_build.GetHostBin(), source_list)
|
||||
logger.SilentLog("Host tests %s" % host_list)
|
||||
|
||||
# Target tests are under $ANDROID_PRODUCT_OUT/system/bin.
|
||||
target_list = self._FilterOutMissing(android_build.GetTargetSystemBin(),
|
||||
source_list)
|
||||
logger.SilentLog("Target tests %s" % target_list)
|
||||
|
||||
# Run on the host
|
||||
logger.Log("\nRunning on host")
|
||||
for f in file_list:
|
||||
for f in host_list:
|
||||
if run_command.RunHostCommand(f) != 0:
|
||||
logger.Log("%s... failed" % f)
|
||||
else:
|
||||
@@ -311,8 +366,8 @@ class TestRunner(object):
|
||||
|
||||
# Run on the device
|
||||
logger.Log("\nRunning on target")
|
||||
for f in file_list:
|
||||
full_path = "/system/bin/%s" % f
|
||||
for f in target_list:
|
||||
full_path = os.path.join(os.sep, "system", "bin", f)
|
||||
|
||||
# Single quotes are needed to prevent the shell splitting it.
|
||||
status = self._adb.SendShellCommand("'%s >/dev/null 2>&1;echo -n $?'" %
|
||||
|
||||
@@ -61,8 +61,11 @@ Native tests:
|
||||
Where:
|
||||
name: Self-descriptive name used to uniquely identify the test
|
||||
build_path: File system path, relative to Android build root, to this
|
||||
package's Android.mk file. By convention the name of a test starts with
|
||||
'test_'.
|
||||
package's Android.mk file. By convention the name of a test should match:
|
||||
- test_*.[cc|cpp]
|
||||
- *_test.[cc|cpp]
|
||||
- *_unittest.[cc|cpp]
|
||||
|
||||
continuous: Optional boolean. Default is false. Set to true if tests are known
|
||||
to be reliable, and should be included in a continuous test system.
|
||||
false if they are under development.
|
||||
@@ -263,5 +266,11 @@ Native tests:
|
||||
description="Bionic libstdc++."
|
||||
extra_make_args="BIONIC_TESTS=1" />
|
||||
|
||||
<!-- pending patch 820
|
||||
<test-native name="gtest"
|
||||
build_path="external/gtest"
|
||||
description="Google test."
|
||||
extra_make_args="GTEST_TESTS=1" />
|
||||
-->
|
||||
|
||||
</test-definitions>
|
||||
|
||||
Reference in New Issue
Block a user