1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
#!/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
|