1# 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() 175