1#!/usr/bin/env python3 2# 3# Copyright 2017 - The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import os 18import subprocess 19import sys 20import tempfile 21import unittest 22 23 24class TestResult(object): 25 """ 26 Attributes: 27 failures_future: The list of failed test cases during this test. 28 output_file: The file containing the stderr/stdout for this test. 29 test_suite: The unittest.TestSuite used. Useful for debugging. 30 test_filename: The *_test.py file that ran in this test. 31 """ 32 def __init__(self, test_result, output_file, test_suite, test_filename): 33 self.test_result = test_result 34 self.output_file = output_file 35 self.test_suite = test_suite 36 self.test_filename = test_filename 37 38 39def run_all_unit_tests(): 40 suite = unittest.TestSuite() 41 test_files = [] 42 loader = unittest.TestLoader() 43 for root, _, files in os.walk(os.path.dirname(__file__)): 44 for filename in files: 45 if filename.endswith('_test.py'): 46 test_files.append(os.path.join(root, filename)) 47 try: 48 suite.addTest(loader.discover(root, filename)) 49 except ImportError as e: 50 if 'Start directory is not importable' not in e.args[0]: 51 raise 52 message = '. Did you forget to add an __init__.py file?' 53 raise ImportError(e.args[0] + message) 54 55 output_dir = tempfile.mkdtemp() 56 57 results = [] 58 59 for index, test in enumerate(suite._tests): 60 output_file = os.path.join(output_dir, 'test_%s.output' % index) 61 62 test_result = subprocess.Popen([sys.executable, test_files[index]], 63 stdout=open(output_file, 'w+'), 64 stderr=subprocess.STDOUT) 65 results.append( 66 TestResult(test_result, output_file, test, test_files[index])) 67 68 all_failures = [] 69 for index, result in enumerate(results): 70 try: 71 failures = result.test_result.wait(timeout=60) 72 if failures: 73 print('Failure logs for %s:' % result.test_filename, 74 file=sys.stderr) 75 with open(result.output_file, 'r') as out_file: 76 print(out_file.read(), file=sys.stderr) 77 all_failures.append(result.test_filename + ' (failed)') 78 except subprocess.TimeoutExpired: 79 all_failures.append(result.test_filename + ' (timed out)') 80 print('The following test timed out: %r' % result.test_filename, 81 file=sys.stderr) 82 with open(result.output_file, 'r') as out_file: 83 print(out_file.read(), file=sys.stderr) 84 85 # Prints a summary over all unit tests failed. 86 if all_failures: 87 print('The following tests failed:', file=sys.stderr) 88 for failure in all_failures: 89 print(' ', failure, file=sys.stderr) 90 91 exit(bool(all_failures)) 92 93 94if __name__ == '__main__': 95 run_all_unit_tests() 96