1import sys, os 2import optparse 3import unittest 4 5def getoptionparser(): 6 parser = optparse.OptionParser() 7 8 parser.add_option("-q", "--quiet", 9 action="store_const", const=0, dest="verbose", default=1, 10 help="do not print status messages to stdout") 11 parser.add_option("-v", "--verbose", 12 action="store_const", const=2, dest="verbose", default=1, 13 help="print status messages to stdout") 14 parser.add_option("-i", "--include", type="string", 15 action="append", dest="include", default=[], 16 help="include tests matching PATTERN", metavar="PATTERN") 17 parser.add_option("-e", "--exclude", type="string", 18 action="append", dest="exclude", default=[], 19 help="exclude tests matching PATTERN", metavar="PATTERN") 20 parser.add_option("-f", "--failfast", 21 action="store_true", dest="failfast", default=False, 22 help="Stop on first failure") 23 parser.add_option("--no-builddir", 24 action="store_false", dest="builddir", default=True, 25 help="disable testing from build directory") 26 parser.add_option("--path", type="string", 27 action="append", dest="path", default=[], 28 help="prepend PATH to sys.path", metavar="PATH") 29 parser.add_option("--refleaks", type="int", 30 action="store", dest="repeats", default=3, 31 help="run tests REPEAT times in a loop to catch leaks", 32 metavar="REPEAT") 33 parser.add_option("--arch", type="string", 34 action="store", dest="arch", default=None, 35 help="use PETSC_ARCH", 36 metavar="PETSC_ARCH") 37 parser.add_option("-s","--summary", 38 action="store_true", dest="summary", default=0, 39 help="print PETSc log summary") 40 return parser 41 42def getbuilddir(): 43 from distutils.util import get_platform 44 s = os.path.join("build", "lib.%s-%.3s" % (get_platform(), sys.version)) 45 if hasattr(sys, 'gettotalrefcount'): s += '-pydebug' 46 return s 47 48def setup_python(options): 49 rootdir = os.path.dirname(os.path.dirname(__file__)) 50 builddir = os.path.join(rootdir, getbuilddir()) 51 if options.builddir and os.path.exists(builddir): 52 sys.path.insert(0, builddir) 53 if options.path: 54 path = options.path[:] 55 path.reverse() 56 for p in path: 57 sys.path.insert(0, p) 58 59def setup_unittest(options): 60 from unittest import TestSuite 61 try: 62 from unittest.runner import _WritelnDecorator 63 except ImportError: 64 from unittest import _WritelnDecorator 65 # 66 writeln_orig = _WritelnDecorator.writeln 67 def writeln(self, message=''): 68 try: self.stream.flush() 69 except: pass 70 writeln_orig(self, message) 71 try: self.stream.flush() 72 except: pass 73 _WritelnDecorator.writeln = writeln 74 75def import_package(options, pkgname): 76 args = [ 77 sys.argv[0], 78 '-malloc', 79 '-malloc_debug', 80 '-malloc_dump', 81 ] 82 if options.summary: 83 args.append('-log_view') 84 package = __import__(pkgname) 85 package.init(args, arch=options.arch) 86 return package 87 88def getprocessorinfo(): 89 try: 90 name = os.uname()[1] 91 except: 92 import platform 93 name = platform.uname()[1] 94 from petsc4py.PETSc import COMM_WORLD 95 rank = COMM_WORLD.getRank() 96 return (rank, name) 97 98def getlibraryinfo(): 99 from petsc4py import PETSc 100 (major, minor, micro) = PETSc.Sys.getVersion() 101 r = PETSc.Sys.getVersionInfo()['release'] 102 if r: release = 'release' 103 else: release = 'development' 104 arch = PETSc.__arch__ 105 return ("PETSc %d.%d.%d %s (conf: '%s')" 106 % (major, minor, micro, release, arch) ) 107 108def getpythoninfo(): 109 x, y = sys.version_info[:2] 110 return ("Python %d.%d (%s)" % (x, y, sys.executable)) 111 112def getpackageinfo(pkg): 113 return ("%s %s (%s)" % (pkg.__name__, 114 pkg.__version__, 115 pkg.__path__[0])) 116 117def writeln(message='', endl='\n'): 118 from petsc4py.PETSc import Sys 119 Sys.syncPrint(message, endl=endl, flush=True) 120 121def print_banner(options, package): 122 r, n = getprocessorinfo() 123 fmt = "[%d@%s] %s" 124 if options.verbose: 125 writeln(fmt % (r, n, getpythoninfo())) 126 writeln(fmt % (r, n, getlibraryinfo())) 127 writeln(fmt % (r, n, getpackageinfo(package))) 128 129def load_tests(options, args): 130 from glob import glob 131 import re 132 testsuitedir = os.path.dirname(__file__) 133 sys.path.insert(0, testsuitedir) 134 pattern = 'test_*.py' 135 wildcard = os.path.join(testsuitedir, pattern) 136 testfiles = glob(wildcard) 137 testfiles.sort() 138 testsuite = unittest.TestSuite() 139 testloader = unittest.TestLoader() 140 include = exclude = None 141 if options.include: 142 include = re.compile('|'.join(options.include)).search 143 if options.exclude: 144 exclude = re.compile('|'.join(options.exclude)).search 145 for testfile in testfiles: 146 filename = os.path.basename(testfile) 147 testname = os.path.splitext(filename)[0] 148 if ((exclude and exclude(testname)) or 149 (include and not include(testname))): 150 continue 151 module = __import__(testname) 152 for arg in args: 153 try: 154 cases = testloader.loadTestsFromNames((arg,), module) 155 testsuite.addTests(cases) 156 except AttributeError: 157 pass 158 if not args: 159 cases = testloader.loadTestsFromModule(module) 160 testsuite.addTests(cases) 161 return testsuite 162 163def run_tests(options, testsuite, runner=None): 164 if runner is None: 165 runner = unittest.TextTestRunner(verbosity=options.verbose) 166 runner.failfast = options.failfast 167 result = runner.run(testsuite) 168 return result.wasSuccessful() 169 170def test_refleaks(options, args): 171 from sys import gettotalrefcount 172 from gc import collect 173 from copy import deepcopy 174 testsuite = load_tests(options, args) 175 class EmptyIO(object): 176 def write(self, *args): 177 pass 178 runner = unittest.TextTestRunner(stream=EmptyIO(), verbosity=0) 179 rank, name = getprocessorinfo() 180 r1 = r2 = 0 181 repeats = options.repeats 182 while repeats: 183 collect() 184 r1 = gettotalrefcount() 185 run_tests(options, deepcopy(testsuite), runner) 186 collect() 187 r2 = gettotalrefcount() 188 leaks = r2-r1 189 if leaks and repeats < options.repeats: 190 writeln('[%d@%s] refleaks: (%d - %d) --> %d' 191 % (rank, name, r2, r1, leaks)) 192 repeats -= 1 193 194def abort(code=1): 195 os.abort() 196 197def shutdown(success): 198 pass 199 200def main(args=None): 201 pkgname = 'petsc4py' 202 parser = getoptionparser() 203 (options, args) = parser.parse_args(args) 204 setup_python(options) 205 setup_unittest(options) 206 package = import_package(options, pkgname) 207 print_banner(options, package) 208 testsuite = load_tests(options, args) 209 success = run_tests(options, testsuite) 210 if not success and options.failfast: abort() 211 if success and hasattr(sys, 'gettotalrefcount'): 212 test_refleaks(options, args) 213 shutdown(success) 214 return not success 215 216if __name__ == '__main__': 217 import sys 218 sys.dont_write_bytecode = True 219 sys.exit(main()) 220