blob: 2d1bf851d0c0eb95bd81b050330c5a1709d31737 [file] [log] [blame]
Dan Albert6f56ab72014-05-06 14:12:12 -07001# Copyright (C) 2014 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14import getopt
15import multiprocessing
16import os
17import re
18import subprocess
19import sys
20
21
22class ProgressBarWrapper(object):
23 def __init__(self, maxval):
24 try:
25 import progressbar
26 self.pb = progressbar.ProgressBar(maxval=maxval)
27 except ImportError:
28 self.pb = None
29
30 def start(self):
31 if self.pb:
32 self.pb.start()
33
34 def update(self, value):
35 if self.pb:
36 self.pb.update(value)
37
38 def finish(self):
39 if self.pb:
40 self.pb.finish()
41
42
43class HostTest(object):
44 def __init__(self, path):
45 self.src_path = re.sub(r'\.pass\.cpp', '', path)
46 self.name = '{0}'.format(self.src_path)
47 self.path = '{0}/bin/libc++tests/{1}'.format(
48 os.getenv('ANDROID_HOST_OUT'), self.name)
49
50 def run(self):
51 return subprocess.call(['timeout', '30', self.path],
52 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
53
54
55class DeviceTest(object):
56 def __init__(self, path):
57 self.src_path = re.sub(r'\.pass\.cpp', '', path)
58 self.name = '{0}'.format(self.src_path)
59 self.path = '/system/bin/libc++tests/{0}'.format(self.name)
60
61 def run(self):
62 return adb_shell(self.path)
63
64
65def adb_shell(command):
66 proc = subprocess.Popen(['timeout', '30',
67 'adb', 'shell', '{0}; echo $? 2>&1'.format(command)],
68 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
69 out, err = proc.communicate()
70 proc.wait()
71 if proc.returncode:
72 return proc.returncode
73 out = [x for x in out.split('\r\n') if x]
74 return int(out[-1])
75
76
77def get_all_tests(subdir):
78 tests = {'host': [], 'device': []}
79 for path, _dirs, files in os.walk(subdir):
80 path = os.path.normpath(path)
81 if path == '.':
82 path = ''
83 for test in [t for t in files if t.endswith('.pass.cpp')]:
84 tests['host'].append(HostTest(os.path.join(path, test)))
85 tests['device'].append(DeviceTest(os.path.join(path, test)))
86 return tests
87
88
89def get_tests_in_subdirs(subdirs):
90 tests = {'host': [], 'device': []}
91 for subdir in subdirs:
92 subdir_tests = get_all_tests(subdir=subdir)
93 tests['host'].extend(subdir_tests['host'])
94 tests['device'].extend(subdir_tests['device'])
95 return tests
96
97
98def run_tests(tests, num_threads):
99 pb = ProgressBarWrapper(maxval=len(tests))
100 pool = multiprocessing.Pool(num_threads)
101
102 pb.start()
103 results = pool.imap(pool_task, tests)
104 num_run = {'host': 0, 'device': 0}
105 failures = {'host': [], 'device': []}
106 for name, status, target in results:
107 num_run[target] += 1
108 if status:
109 failures[target].append(name)
110 pb.update(sum(num_run.values()))
111 pb.finish()
112 return {'num_run': num_run, 'failures': failures}
113
114
115def report_results(results):
116 num_run = results['num_run']
117 failures = results['failures']
118 failed_both = sorted(filter(
119 lambda x: x in failures['host'],
120 failures['device']))
121
122 for target, failed in failures.iteritems():
123 failed = [x for x in failed if x not in failed_both]
124 print '{0} tests run: {1}'.format(target, num_run[target])
125 print '{0} tests failed: {1}'.format(target, len(failed))
126 for failure in sorted(failed):
127 print '\t{0}'.format(failure)
128 print
129
130 if len(failed_both):
131 print '{0} tests failed in both environments'.format(len(failed_both))
132 for failure in failed_both:
133 print '\t{0}'.format(failure)
134
135
136def pool_task(test):
137 target = 'host' if isinstance(test, HostTest) else 'device'
138 #print '{0} run {1}'.format(target, test.name)
139 return (test.name, test.run(), target)
140
141
142def main():
143 try:
144 opts, args = getopt.getopt(
145 sys.argv[1:], 'n:t:', ['threads=', 'target='])
146 except getopt.GetoptError as err:
147 sys.exit(str(err))
148
149 subdirs = ['.']
150 target = 'both'
151 num_threads = multiprocessing.cpu_count() * 2
152 for opt, arg in opts:
153 if opt in ('-n', '--threads'):
154 num_threads = int(arg)
155 elif opt in ('-t', '--target'):
156 target = arg
157 else:
158 sys.exit('Unknown option {0}'.format(opt))
159
160 if len(args):
161 subdirs = args
162
163 tests = get_tests_in_subdirs(subdirs)
164 if target == 'both':
165 tests = tests['host'] + tests['device']
166 else:
167 tests = tests[target]
168
169 results = run_tests(tests, num_threads)
170 report_results(results)
171
172
173if __name__ == '__main__':
174 main()