OSDN Git Service

merge from donut
[android-x86/development.git] / testrunner / test_defs / native_test.py
1 #!/usr/bin/python2.4
2 #
3 #
4 # Copyright 2009, The Android Open Source Project
5 #
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
9 #
10 #     http://www.apache.org/licenses/LICENSE-2.0
11 #
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.
17
18 """TestSuite for running native Android tests."""
19
20 # python imports
21 import re
22 import os
23
24 # local imports
25 from abstract_test import AbstractTestSuite
26 import android_build
27 import logger
28 import run_command
29
30
31 class NativeTestSuite(AbstractTestSuite):
32   """A test suite for running native aka C/C++ tests on device."""
33
34   TAG_NAME = "test-native"
35
36   def _GetTagName(self):
37     return self._TAG_NAME
38
39   def Parse(self, suite_element):
40     super(NativeTestSuite, self).Parse(suite_element)
41
42
43   def Run(self, options, adb):
44     """Run the provided *native* test suite.
45
46     The test_suite must contain a build path where the native test
47     files are. Subdirectories are automatically scanned as well.
48
49     Each test's name must have a .cc or .cpp extension and match one
50     of the following patterns:
51       - test_*
52       - *_test.[cc|cpp]
53       - *_unittest.[cc|cpp]
54     A successful test must return 0. Any other value will be considered
55     as an error.
56
57     Args:
58       options: command line options
59       adb: adb interface
60     """
61     # find all test files, convert unicode names to ascii, take the basename
62     # and drop the .cc/.cpp  extension.
63     source_list = []
64     build_path = self.GetBuildPath()
65     os.path.walk(build_path, self._CollectTestSources, source_list)
66     logger.SilentLog("Tests source %s" % source_list)
67
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)
71
72     # Target tests are under $ANDROID_PRODUCT_OUT/system/bin.
73     target_list = self._FilterOutMissing(android_build.GetTargetSystemBin(),
74                                          source_list)
75     logger.SilentLog("Target tests %s" % target_list)
76
77     # Run on the host
78     logger.Log("\nRunning on host")
79     for f in host_list:
80       if run_command.RunHostCommand(f) != 0:
81         logger.Log("%s... failed" % f)
82       else:
83         if run_command.HasValgrind():
84           if run_command.RunHostCommand(f, valgrind=True) == 0:
85             logger.Log("%s... ok\t\t[valgrind: ok]" % f)
86           else:
87             logger.Log("%s... ok\t\t[valgrind: failed]" % f)
88         else:
89           logger.Log("%s... ok\t\t[valgrind: missing]" % f)
90
91     # Run on the device
92     logger.Log("\nRunning on target")
93     for f in target_list:
94       full_path = os.path.join(os.sep, "system", "bin", f)
95
96       # Single quotes are needed to prevent the shell splitting it.
97       output = adb.SendShellCommand("'%s 2>&1;echo -n exit code:$?'" %
98                                     full_path,
99                                     int(options.timeout))
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]
106         logger.Log(output)
107
108       # Cleanup
109       adb.SendShellCommand("rm %s" % full_path)
110
111   def _CollectTestSources(self, test_list, dirname, files):
112     """For each directory, find tests source file and add them to the list.
113
114     Test files must match one of the following pattern:
115       - test_*.[cc|cpp]
116       - *_test.[cc|cpp]
117       - *_unittest.[cc|cpp]
118
119     This method is a callback for os.path.walk.
120
121     Args:
122       test_list: Where new tests should be inserted.
123       dirname: Current directory.
124       files: List of files in the current directory.
125     """
126     for f in files:
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)))
132
133   def _FilterOutMissing(self, path, sources):
134     """Filter out from the sources list missing tests.
135
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
138     these out.
139
140     Args:
141       path: Where the binaries should be.
142       sources: List of tests source path.
143     Returns:
144       A list of test binaries built from the sources.
145     """
146     binaries = []
147     for f in 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)
153     return binaries
154
155   def _RunHostCommand(self, binary, valgrind=False):
156     """Run a command on the host (opt using valgrind).
157
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.
163
164     Args:
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.
168
169     Returns:
170       The command exit code (int)
171     """
172     full_path = os.path.join(android_build.GetHostBin(), binary)
173     return run_command.RunHostCommand(full_path, valgrind=valgrind)