With this change, also refactored runtest as follows: Modified the test suite schema and python implementation to have an inheritance structure. Each test type has its own python module, which will also handle the logic of running the test.
154 lines
5.0 KiB
Python
154 lines
5.0 KiB
Python
#!/usr/bin/python2.4
|
|
#
|
|
#
|
|
# Copyright 2008, The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""TestSuite for running native Android tests."""
|
|
|
|
# python imports
|
|
import os
|
|
|
|
# local imports
|
|
from abstract_test import AbstractTestSuite
|
|
import android_build
|
|
import errors
|
|
import logger
|
|
import run_command
|
|
|
|
|
|
class NativeTestSuite(AbstractTestSuite):
|
|
"""A test suite for running native aka C/C++ tests on device."""
|
|
|
|
TAG_NAME = "test-native"
|
|
|
|
def _GetTagName(self):
|
|
return self._TAG_NAME
|
|
|
|
def Parse(self, suite_element):
|
|
super(NativeTestSuite, self).Parse(suite_element)
|
|
|
|
|
|
def Run(self, options, adb):
|
|
"""Run the provided *native* test suite.
|
|
|
|
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.
|
|
|
|
Args:
|
|
options: command line options
|
|
adb: adb interface
|
|
"""
|
|
# find all test files, convert unicode names to ascii, take the basename
|
|
# and drop the .cc/.cpp extension.
|
|
source_list = []
|
|
build_path = self.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 host_list:
|
|
if run_command.RunHostCommand(f) != 0:
|
|
logger.Log("%s... failed" % f)
|
|
else:
|
|
if run_command.HasValgrind():
|
|
if run_command.RunHostCommand(f, valgrind=True) == 0:
|
|
logger.Log("%s... ok\t\t[valgrind: ok]" % f)
|
|
else:
|
|
logger.Log("%s... ok\t\t[valgrind: failed]" % f)
|
|
else:
|
|
logger.Log("%s... ok\t\t[valgrind: missing]" % f)
|
|
|
|
# Run on the device
|
|
logger.Log("\nRunning on target")
|
|
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.
|
|
output = self._adb.SendShellCommand("'%s 2>&1;echo -n exit code:$?'" %
|
|
full_path,
|
|
int(self._options.timeout))
|
|
success = output.endswith("exit code:0")
|
|
logger.Log("%s... %s" % (f, success and "ok" or "failed"))
|
|
# Print the captured output when the test failed.
|
|
if not success or options.verbose:
|
|
pos = output.rfind("exit code")
|
|
output = output[0:pos]
|
|
logger.Log(output)
|
|
|
|
# Cleanup
|
|
adb.SendShellCommand("rm %s" % full_path)
|
|
|
|
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
|