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:
@@ -3,22 +3,24 @@
|
|||||||
#
|
#
|
||||||
# Copyright 2008, The Android Open Source Project
|
# Copyright 2008, The Android Open Source Project
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
# You may obtain a copy of the License at
|
# You may obtain a copy of the License at
|
||||||
#
|
#
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
#
|
#
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
"""Contains utility functions for interacting with the Android build system."""
|
"""Contains utility functions for interacting with the Android build system."""
|
||||||
|
|
||||||
# Python imports
|
# Python imports
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
import errors
|
import errors
|
||||||
@@ -38,8 +40,96 @@ def GetTop():
|
|||||||
AbortError: if Android build root could not be found.
|
AbortError: if Android build root could not be found.
|
||||||
"""
|
"""
|
||||||
# TODO: does this need to be reimplemented to be like gettop() in envsetup.sh
|
# 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:
|
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
|
raise errors.AbortError
|
||||||
return root_path
|
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
|
import time
|
||||||
|
|
||||||
# local imports
|
# local imports
|
||||||
|
import android_build
|
||||||
import errors
|
import errors
|
||||||
import logger
|
import logger
|
||||||
|
|
||||||
@@ -128,13 +129,13 @@ def RunHostCommand(binary, valgrind=False):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
binary: basename of the file to be run. It is expected to be under
|
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.
|
valgrind: If True the command will be run under valgrind.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The command exit code (int)
|
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:
|
if not valgrind:
|
||||||
subproc = subprocess.Popen(full_path, stdout=subprocess.PIPE,
|
subproc = subprocess.Popen(full_path, stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.STDOUT)
|
stderr=subprocess.STDOUT)
|
||||||
|
|||||||
@@ -276,11 +276,61 @@ class TestRunner(object):
|
|||||||
if coverage_file is not None:
|
if coverage_file is not None:
|
||||||
logger.Log("Coverage report generated at %s" % coverage_file)
|
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):
|
def _RunNativeTest(self, test_suite):
|
||||||
"""Run the provided *native* test suite.
|
"""Run the provided *native* test suite.
|
||||||
|
|
||||||
The test_suite must contain a build path where the native test files are.
|
The test_suite must contain a build path where the native test
|
||||||
Each test's name must start with 'test_' and have a .cc or .cpp extension.
|
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
|
A successful test must return 0. Any other value will be considered
|
||||||
as an error.
|
as an error.
|
||||||
|
|
||||||
@@ -289,18 +339,23 @@ class TestRunner(object):
|
|||||||
"""
|
"""
|
||||||
# find all test files, convert unicode names to ascii, take the basename
|
# find all test files, convert unicode names to ascii, take the basename
|
||||||
# and drop the .cc/.cpp extension.
|
# and drop the .cc/.cpp extension.
|
||||||
file_pattern = os.path.join(test_suite.GetBuildPath(), "test_*")
|
source_list = []
|
||||||
logger.SilentLog("Scanning %s" % test_suite.GetBuildPath())
|
build_path = test_suite.GetBuildPath()
|
||||||
file_list = []
|
os.path.walk(build_path, self._CollectTestSources, source_list)
|
||||||
for f in map(str, glob.glob(file_pattern)):
|
logger.SilentLog("Tests source %s" % source_list)
|
||||||
f = os.path.basename(f)
|
|
||||||
f = re.split(".[cp]+$", f)[0]
|
# Host tests are under out/host/<os>-<arch>/bin.
|
||||||
logger.SilentLog("Found %s" % f)
|
host_list = self._FilterOutMissing(android_build.GetHostBin(), source_list)
|
||||||
file_list.append(f)
|
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
|
# Run on the host
|
||||||
logger.Log("\nRunning on host")
|
logger.Log("\nRunning on host")
|
||||||
for f in file_list:
|
for f in host_list:
|
||||||
if run_command.RunHostCommand(f) != 0:
|
if run_command.RunHostCommand(f) != 0:
|
||||||
logger.Log("%s... failed" % f)
|
logger.Log("%s... failed" % f)
|
||||||
else:
|
else:
|
||||||
@@ -311,8 +366,8 @@ class TestRunner(object):
|
|||||||
|
|
||||||
# Run on the device
|
# Run on the device
|
||||||
logger.Log("\nRunning on target")
|
logger.Log("\nRunning on target")
|
||||||
for f in file_list:
|
for f in target_list:
|
||||||
full_path = "/system/bin/%s" % f
|
full_path = os.path.join(os.sep, "system", "bin", f)
|
||||||
|
|
||||||
# Single quotes are needed to prevent the shell splitting it.
|
# Single quotes are needed to prevent the shell splitting it.
|
||||||
status = self._adb.SendShellCommand("'%s >/dev/null 2>&1;echo -n $?'" %
|
status = self._adb.SendShellCommand("'%s >/dev/null 2>&1;echo -n $?'" %
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -14,9 +14,9 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
This file contains standard test definitions for the Android platform
|
This file contains standard test definitions for the Android platform
|
||||||
|
|
||||||
Java tests are defined by <test> tags and native ones (C/C++) are defined by
|
Java tests are defined by <test> tags and native ones (C/C++) are defined by
|
||||||
<test-native> tags.
|
<test-native> tags.
|
||||||
|
|
||||||
@@ -32,8 +32,8 @@ JAVA/application tests:
|
|||||||
package's Android.mk file. If omitted, build/sync step for this test will
|
package's Android.mk file. If omitted, build/sync step for this test will
|
||||||
be skipped.
|
be skipped.
|
||||||
package: Android application package that contains the tests
|
package: Android application package that contains the tests
|
||||||
class: Optional. Fully qualified Java test class to run.
|
class: Optional. Fully qualified Java test class to run.
|
||||||
runner: Fully qualified InstrumentationTestRunner to execute. If omitted,
|
runner: Fully qualified InstrumentationTestRunner to execute. If omitted,
|
||||||
will default to android.test.InstrumentationTestRunner.
|
will default to android.test.InstrumentationTestRunner.
|
||||||
coverage_target: Build name of Android package this test targets - these
|
coverage_target: Build name of Android package this test targets - these
|
||||||
targets are defined in the coverage_targets.xml file. Used as basis for
|
targets are defined in the coverage_targets.xml file. Used as basis for
|
||||||
@@ -43,10 +43,10 @@ JAVA/application tests:
|
|||||||
to be reliable, and should be included in a continuous test system. false if
|
to be reliable, and should be included in a continuous test system. false if
|
||||||
they are under development.
|
they are under development.
|
||||||
|
|
||||||
description: Optional string. Default is empty. Short description (typically
|
description: Optional string. Default is empty. Short description (typically
|
||||||
less than 60 characters) about this test.
|
less than 60 characters) about this test.
|
||||||
|
|
||||||
These attributes map to the following commands:
|
These attributes map to the following commands:
|
||||||
(if class is defined)
|
(if class is defined)
|
||||||
adb shell am instrument -w <package>/<runner>
|
adb shell am instrument -w <package>/<runner>
|
||||||
(else)
|
(else)
|
||||||
@@ -61,8 +61,11 @@ Native tests:
|
|||||||
Where:
|
Where:
|
||||||
name: Self-descriptive name used to uniquely identify the test
|
name: Self-descriptive name used to uniquely identify the test
|
||||||
build_path: File system path, relative to Android build root, to this
|
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
|
package's Android.mk file. By convention the name of a test should match:
|
||||||
'test_'.
|
- test_*.[cc|cpp]
|
||||||
|
- *_test.[cc|cpp]
|
||||||
|
- *_unittest.[cc|cpp]
|
||||||
|
|
||||||
continuous: Optional boolean. Default is false. Set to true if tests are known
|
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.
|
to be reliable, and should be included in a continuous test system.
|
||||||
false if they are under development.
|
false if they are under development.
|
||||||
@@ -115,7 +118,7 @@ Native tests:
|
|||||||
package="android.core"
|
package="android.core"
|
||||||
class="android.core.JavaTests"
|
class="android.core.JavaTests"
|
||||||
coverage_target="framework" />
|
coverage_target="framework" />
|
||||||
|
|
||||||
<test name="apidemos"
|
<test name="apidemos"
|
||||||
build_path="development/samples/ApiDemos"
|
build_path="development/samples/ApiDemos"
|
||||||
package="com.example.android.apis.tests"
|
package="com.example.android.apis.tests"
|
||||||
@@ -215,13 +218,13 @@ Native tests:
|
|||||||
runner=".MediaFrameworkTestRunner"
|
runner=".MediaFrameworkTestRunner"
|
||||||
coverage_target="framework"
|
coverage_target="framework"
|
||||||
continuous="true" />
|
continuous="true" />
|
||||||
|
|
||||||
<test name="mediaunit"
|
<test name="mediaunit"
|
||||||
build_path="frameworks/base/media/tests/MediaFrameworkTest"
|
build_path="frameworks/base/media/tests/MediaFrameworkTest"
|
||||||
package="com.android.mediaframeworktest"
|
package="com.android.mediaframeworktest"
|
||||||
runner=".MediaFrameworkUnitTestRunner"
|
runner=".MediaFrameworkUnitTestRunner"
|
||||||
coverage_target="framework" />
|
coverage_target="framework" />
|
||||||
|
|
||||||
<test name="musicplayer"
|
<test name="musicplayer"
|
||||||
build_path="packages/apps/Music"
|
build_path="packages/apps/Music"
|
||||||
package="com.android.music.tests"
|
package="com.android.music.tests"
|
||||||
@@ -263,5 +266,11 @@ Native tests:
|
|||||||
description="Bionic libstdc++."
|
description="Bionic libstdc++."
|
||||||
extra_make_args="BIONIC_TESTS=1" />
|
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>
|
</test-definitions>
|
||||||
|
|||||||
Reference in New Issue
Block a user