4 # Copyright 2009, The Android Open Source Project
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
10 # http://www.apache.org/licenses/LICENSE-2.0
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.
18 """TestSuite for running native Android tests."""
25 from abstract_test import AbstractTestSuite
31 class NativeTestSuite(AbstractTestSuite):
32 """A test suite for running native aka C/C++ tests on device."""
34 TAG_NAME = "test-native"
36 def _GetTagName(self):
39 def Parse(self, suite_element):
40 super(NativeTestSuite, self).Parse(suite_element)
43 def Run(self, options, adb):
44 """Run the provided *native* test suite.
46 The test_suite must contain a build path where the native test
47 files are. Subdirectories are automatically scanned as well.
49 Each test's name must have a .cc or .cpp extension and match one
50 of the following patterns:
54 A successful test must return 0. Any other value will be considered
58 options: command line options
61 # find all test files, convert unicode names to ascii, take the basename
62 # and drop the .cc/.cpp extension.
64 build_path = self.GetBuildPath()
65 os.path.walk(build_path, self._CollectTestSources, source_list)
66 logger.SilentLog("Tests source %s" % source_list)
68 # Host tests are under out/host/<os>-<arch>/bin.
69 host_list = self._FilterOutMissing(android_build.GetHostBin(), source_list)
70 logger.SilentLog("Host tests %s" % host_list)
72 # Target tests are under $ANDROID_PRODUCT_OUT/system/bin.
73 target_list = self._FilterOutMissing(android_build.GetTargetSystemBin(),
75 logger.SilentLog("Target tests %s" % target_list)
78 logger.Log("\nRunning on host")
80 if run_command.RunHostCommand(f) != 0:
81 logger.Log("%s... failed" % f)
83 if run_command.HasValgrind():
84 if run_command.RunHostCommand(f, valgrind=True) == 0:
85 logger.Log("%s... ok\t\t[valgrind: ok]" % f)
87 logger.Log("%s... ok\t\t[valgrind: failed]" % f)
89 logger.Log("%s... ok\t\t[valgrind: missing]" % f)
92 logger.Log("\nRunning on target")
94 full_path = os.path.join(os.sep, "system", "bin", f)
96 # Single quotes are needed to prevent the shell splitting it.
97 output = adb.SendShellCommand("'%s 2>&1;echo -n exit code:$?'" %
100 success = output.endswith("exit code:0")
101 logger.Log("%s... %s" % (f, success and "ok" or "failed"))
102 # Print the captured output when the test failed.
103 if not success or options.verbose:
104 pos = output.rfind("exit code")
105 output = output[0:pos]
109 adb.SendShellCommand("rm %s" % full_path)
111 def _CollectTestSources(self, test_list, dirname, files):
112 """For each directory, find tests source file and add them to the list.
114 Test files must match one of the following pattern:
117 - *_unittest.[cc|cpp]
119 This method is a callback for os.path.walk.
122 test_list: Where new tests should be inserted.
123 dirname: Current directory.
124 files: List of files in the current directory.
127 (name, ext) = os.path.splitext(f)
128 if ext == ".cc" or ext == ".cpp" or ext == ".c":
129 if re.search("_test$|_test_$|_unittest$|_unittest_$|^test_", name):
130 logger.SilentLog("Found %s" % f)
131 test_list.append(str(os.path.join(dirname, f)))
133 def _FilterOutMissing(self, path, sources):
134 """Filter out from the sources list missing tests.
136 Sometimes some test source are not built for the target, i.e there
137 is no binary corresponding to the source file. We need to filter
141 path: Where the binaries should be.
142 sources: List of tests source path.
144 A list of test binaries built from the sources.
148 binary = os.path.basename(f)
149 binary = os.path.splitext(binary)[0]
150 full_path = os.path.join(path, binary)
151 if os.path.exists(full_path):
152 binaries.append(binary)
155 def _RunHostCommand(self, binary, valgrind=False):
156 """Run a command on the host (opt using valgrind).
158 Runs the host binary and returns the exit code.
159 If successfull, the output (stdout and stderr) are discarded,
160 but printed in case of error.
161 The command can be run under valgrind in which case all the
162 output are always discarded.
165 binary: basename of the file to be run. It is expected to be under
166 out/host/<os>-<arch>/bin.
167 valgrind: If True the command will be run under valgrind.
170 The command exit code (int)
172 full_path = os.path.join(android_build.GetHostBin(), binary)
173 return run_command.RunHostCommand(full_path, valgrind=valgrind)