# Copyright (C) 2014 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. import getopt import multiprocessing import os import re import subprocess import sys class ProgressBarWrapper(object): def __init__(self, maxval): try: import progressbar self.pb = progressbar.ProgressBar(maxval=maxval) except ImportError: self.pb = None def start(self): if self.pb: self.pb.start() def update(self, value): if self.pb: self.pb.update(value) def finish(self): if self.pb: self.pb.finish() class HostTest(object): def __init__(self, path): self.src_path = re.sub(r'\.pass\.cpp', '', path) self.name = '{0}'.format(self.src_path) self.path = '{0}/bin/libc++tests/{1}'.format( os.getenv('ANDROID_HOST_OUT'), self.name) def run(self): return subprocess.call(['timeout', '30', self.path], stdout=subprocess.PIPE, stderr=subprocess.PIPE) class DeviceTest(object): def __init__(self, path): self.src_path = re.sub(r'\.pass\.cpp', '', path) self.name = '{0}'.format(self.src_path) self.path = '/system/bin/libc++tests/{0}'.format(self.name) def run(self): return adb_shell(self.path) def adb_shell(command): proc = subprocess.Popen(['timeout', '30', 'adb', 'shell', '{0}; echo $? 2>&1'.format(command)], stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() proc.wait() if proc.returncode: return proc.returncode out = [x for x in out.split('\r\n') if x] return int(out[-1]) def get_all_tests(subdir): tests = {'host': [], 'device': []} for path, _dirs, files in os.walk(subdir): path = os.path.normpath(path) if path == '.': path = '' for test in [t for t in files if t.endswith('.pass.cpp')]: tests['host'].append(HostTest(os.path.join(path, test))) tests['device'].append(DeviceTest(os.path.join(path, test))) return tests def get_tests_in_subdirs(subdirs): tests = {'host': [], 'device': []} for subdir in subdirs: subdir_tests = get_all_tests(subdir=subdir) tests['host'].extend(subdir_tests['host']) tests['device'].extend(subdir_tests['device']) return tests def run_tests(tests, num_threads): pb = ProgressBarWrapper(maxval=len(tests)) pool = multiprocessing.Pool(num_threads) pb.start() results = pool.imap(pool_task, tests) num_run = {'host': 0, 'device': 0} failures = {'host': [], 'device': []} for name, status, target in results: num_run[target] += 1 if status: failures[target].append(name) pb.update(sum(num_run.values())) pb.finish() return {'num_run': num_run, 'failures': failures} def report_results(results): num_run = results['num_run'] failures = results['failures'] failed_both = sorted(filter( lambda x: x in failures['host'], failures['device'])) for target, failed in failures.iteritems(): failed = [x for x in failed if x not in failed_both] print '{0} tests run: {1}'.format(target, num_run[target]) print '{0} tests failed: {1}'.format(target, len(failed)) for failure in sorted(failed): print '\t{0}'.format(failure) print if len(failed_both): print '{0} tests failed in both environments'.format(len(failed_both)) for failure in failed_both: print '\t{0}'.format(failure) def pool_task(test): target = 'host' if isinstance(test, HostTest) else 'device' #print '{0} run {1}'.format(target, test.name) return (test.name, test.run(), target) def main(): try: opts, args = getopt.getopt( sys.argv[1:], 'n:t:', ['threads=', 'target=']) except getopt.GetoptError as err: sys.exit(str(err)) subdirs = ['.'] target = 'both' num_threads = multiprocessing.cpu_count() * 2 for opt, arg in opts: if opt in ('-n', '--threads'): num_threads = int(arg) elif opt in ('-t', '--target'): target = arg else: sys.exit('Unknown option {0}'.format(opt)) if len(args): subdirs = args tests = get_tests_in_subdirs(subdirs) if target == 'both': tests = tests['host'] + tests['device'] else: tests = tests[target] results = run_tests(tests, num_threads) report_results(results) if __name__ == '__main__': main()