ia64/xen-unstable

view tools/python/test.py @ 11827:a7c6b1c5507c

[IA64] remove unused vmx/mm.c file

Signed-off-by: Tristan Gingold <tristan.gingold@bull.net>
author awilliam@xenbuild.aw
date Sun Oct 22 14:14:58 2006 -0600 (2006-10-22)
parents cd228621e1fd
children
line source
1 #! /usr/bin/env python2.3
2 ##############################################################################
3 #
4 # Copyright (c) 2001, 2002 Zope Corporation and Contributors.
5 # All Rights Reserved.
6 #
7 # This software is subject to the provisions of the Zope Public License,
8 # Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
9 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
10 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
11 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
12 # FOR A PARTICULAR PURPOSE.
13 #
14 ##############################################################################
15 """
16 test.py [-abBcdDfFgGhklLmMPprstTuUv] [modfilter [testfilter]]
18 Find and run tests written using the unittest module.
20 The test runner searches for Python modules that contain test suites.
21 It collects those suites, and runs the tests. There are many options
22 for controlling how the tests are run. There are options for using
23 the debugger, reporting code coverage, and checking for refcount problems.
25 The test runner uses the following rules for finding tests to run. It
26 searches for packages and modules that contain "tests" as a component
27 of the name, e.g. "frob.tests.nitz" matches this rule because tests is
28 a sub-package of frob. Within each "tests" package, it looks for
29 modules that begin with the name "test." For each test module, it
30 imports the module and calls the module's test_suite() function, which must
31 return a unittest TestSuite object.
33 Options can be specified as command line arguments (see below). However,
34 options may also be specified in a file named 'test.config', a Python
35 script which, if found, will be executed before the command line
36 arguments are processed.
38 The test.config script should specify options by setting zero or more of the
39 global variables: LEVEL, BUILD, and other capitalized variable names found in
40 the test runner script (see the list of global variables in process_args().).
43 -a level
44 --at-level level
45 --all
46 Run the tests at the given level. Any test at a level at or below
47 this is run, any test at a level above this is not run. Level 0
48 runs all tests. The default is to run tests at level 1. --all is
49 a shortcut for -a 0.
51 -b
52 --build
53 Run "python setup.py build" before running tests, where "python"
54 is the version of python used to run test.py. Highly recommended.
55 Tests will be run from the build directory.
57 -B
58 --build-inplace
59 Run "python setup.py build_ext -i" before running tests. Tests will be
60 run from the source directory.
62 -c
63 --pychecker
64 use pychecker
66 -d
67 --debug
68 Instead of the normal test harness, run a debug version which
69 doesn't catch any exceptions. This is occasionally handy when the
70 unittest code catching the exception doesn't work right.
71 Unfortunately, the debug harness doesn't print the name of the
72 test, so Use With Care.
74 -D
75 --debug-inplace
76 Works like -d, except that it loads pdb when an exception occurs.
78 --dir directory
79 -s directory
80 Option to limit where tests are searched for. This is important
81 when you *really* want to limit the code that gets run. This can
82 be specified more than once to run tests in two different parts of
83 the source tree.
84 For example, if refactoring interfaces, you don't want to see the way
85 you have broken setups for tests in other packages. You *just* want to
86 run the interface tests.
88 -f
89 --skip-unit
90 Run functional tests but not unit tests.
91 Note that functional tests will be skipped if the module
92 zope.app.tests.functional cannot be imported.
93 Functional tests also expect to find the file ftesting.zcml,
94 which is used to configure the functional-test run.
96 -F
97 DEPRECATED. Run both unit and functional tests.
98 This option is deprecated, because this is the new default mode.
99 Note that functional tests will be skipped if the module
100 zope.app.tests.functional cannot be imported.
102 -g threshold
103 --gc-threshold threshold
104 Set the garbage collector generation0 threshold. This can be used
105 to stress memory and gc correctness. Some crashes are only
106 reproducible when the threshold is set to 1 (agressive garbage
107 collection). Do "-g 0" to disable garbage collection altogether.
109 -G gc_option
110 --gc-option gc_option
111 Set the garbage collection debugging flags. The argument must be one
112 of the DEBUG_ flags defined bythe Python gc module. Multiple options
113 can be specified by using "-G OPTION1 -G OPTION2."
115 -k
116 --keepbytecode
117 Do not delete all stale bytecode before running tests
119 -l test_root
120 --libdir test_root
121 Search for tests starting in the specified start directory
122 (useful for testing components being developed outside the main
123 "src" or "build" trees).
125 -L
126 --loop
127 Keep running the selected tests in a loop. You may experience
128 memory leakage.
130 -m
131 -M minimal GUI. See -U.
133 -P
134 --profile
135 Run the tests under hotshot and display the top 50 stats, sorted by
136 cumulative time and number of calls.
138 -p
139 --progress
140 Show running progress. It can be combined with -v or -vv.
142 -r
143 --refcount
144 Look for refcount problems.
145 This requires that Python was built --with-pydebug.
147 -t
148 --top-fifty
149 Time the individual tests and print a list of the top 50, sorted from
150 longest to shortest.
152 --times n
153 --times outfile
154 With an integer argument, time the tests and print a list of the top <n>
155 tests, sorted from longest to shortest.
156 With a non-integer argument, specifies a file to which timing information
157 is to be printed.
159 -T
160 --trace
161 Use the trace module from Python for code coverage. The current
162 utility writes coverage files to a directory named `coverage' that
163 is parallel to `build'. It also prints a summary to stdout.
165 -u
166 --skip-functional
167 CHANGED. Run unit tests but not functional tests.
168 Note that the meaning of -u is changed from its former meaning,
169 which is now specified by -U or --gui.
171 -U
172 --gui
173 Use the PyUnit GUI instead of output to the command line. The GUI
174 imports tests on its own, taking care to reload all dependencies
175 on each run. The debug (-d), verbose (-v), progress (-p), and
176 Loop (-L) options will be ignored. The testfilter filter is also
177 not applied.
179 -m
180 -M
181 --minimal-gui
182 Note: -m is DEPRECATED in favour of -M or --minimal-gui.
183 -m starts the gui minimized. Double-clicking the progress bar
184 will start the import and run all tests.
187 -v
188 --verbose
189 Verbose output. With one -v, unittest prints a dot (".") for each
190 test run. With -vv, unittest prints the name of each test (for
191 some definition of "name" ...). With no -v, unittest is silent
192 until the end of the run, except when errors occur.
194 When -p is also specified, the meaning of -v is slightly
195 different. With -p and no -v only the percent indicator is
196 displayed. With -p and -v the test name of the current test is
197 shown to the right of the percent indicator. With -p and -vv the
198 test name is not truncated to fit into 80 columns and it is not
199 cleared after the test finishes.
202 modfilter
203 testfilter
204 Case-sensitive regexps to limit which tests are run, used in search
205 (not match) mode.
206 In an extension of Python regexp notation, a leading "!" is stripped
207 and causes the sense of the remaining regexp to be negated (so "!bc"
208 matches any string that does not match "bc", and vice versa).
209 By default these act like ".", i.e. nothing is excluded.
211 modfilter is applied to a test file's path, starting at "build" and
212 including (OS-dependent) path separators.
214 testfilter is applied to the (method) name of the unittest methods
215 contained in the test files whose paths modfilter matched.
217 Extreme (yet useful) examples:
219 test.py -vvb . "^testWriteClient$"
221 Builds the project silently, then runs unittest in verbose mode on all
222 tests whose names are precisely "testWriteClient". Useful when
223 debugging a specific test.
225 test.py -vvb . "!^testWriteClient$"
227 As before, but runs all tests whose names aren't precisely
228 "testWriteClient". Useful to avoid a specific failing test you don't
229 want to deal with just yet.
231 test.py -M . "!^testWriteClient$"
233 As before, but now opens up a minimized PyUnit GUI window (only showing
234 the progress bar). Useful for refactoring runs where you continually want
235 to make sure all tests still pass.
236 """
238 import gc
239 import hotshot, hotshot.stats
240 import os
241 import re
242 import pdb
243 import sys
244 import threading # just to get at Thread objects created by tests
245 import time
246 import traceback
247 import unittest
248 import warnings
250 def set_trace_doctest(stdin=sys.stdin, stdout=sys.stdout, trace=pdb.set_trace):
251 sys.stdin = stdin
252 sys.stdout = stdout
253 trace()
255 pdb.set_trace_doctest = set_trace_doctest
257 from distutils.util import get_platform
259 PLAT_SPEC = "%s-%s" % (get_platform(), sys.version[0:3])
261 class ImmediateTestResult(unittest._TextTestResult):
263 __super_init = unittest._TextTestResult.__init__
264 __super_startTest = unittest._TextTestResult.startTest
265 __super_printErrors = unittest._TextTestResult.printErrors
267 def __init__(self, stream, descriptions, verbosity, debug=False,
268 count=None, progress=False):
269 self.__super_init(stream, descriptions, verbosity)
270 self._debug = debug
271 self._progress = progress
272 self._progressWithNames = False
273 self.count = count
274 self._testtimes = {}
275 if progress and verbosity == 1:
276 self.dots = False
277 self._progressWithNames = True
278 self._lastWidth = 0
279 self._maxWidth = 80
280 try:
281 import curses
282 except ImportError:
283 pass
284 else:
285 curses.setupterm()
286 self._maxWidth = curses.tigetnum('cols')
287 self._maxWidth -= len("xxxx/xxxx (xxx.x%): ") + 1
289 def stopTest(self, test):
290 self._testtimes[test] = time.time() - self._testtimes[test]
291 if gc.garbage:
292 print "The following test left garbage:"
293 print test
294 print gc.garbage
295 # XXX Perhaps eat the garbage here, so that the garbage isn't
296 # printed for every subsequent test.
298 # Did the test leave any new threads behind?
299 new_threads = [t for t in threading.enumerate()
300 if (t.isAlive()
301 and
302 t not in self._threads)]
303 if new_threads:
304 print "The following test left new threads behind:"
305 print test
306 print "New thread(s):", new_threads
308 def print_times(self, stream, count=None):
309 results = self._testtimes.items()
310 results.sort(lambda x, y: cmp(y[1], x[1]))
311 if count:
312 n = min(count, len(results))
313 if n:
314 print >>stream, "Top %d longest tests:" % n
315 else:
316 n = len(results)
317 if not n:
318 return
319 for i in range(n):
320 print >>stream, "%6dms" % int(results[i][1] * 1000), results[i][0]
322 def _print_traceback(self, msg, err, test, errlist):
323 if self.showAll or self.dots or self._progress:
324 self.stream.writeln("\n")
325 self._lastWidth = 0
327 tb = "".join(traceback.format_exception(*err))
328 self.stream.writeln(msg)
329 self.stream.writeln(tb)
330 errlist.append((test, tb))
332 def startTest(self, test):
333 if self._progress:
334 self.stream.write("\r%4d" % (self.testsRun + 1))
335 if self.count:
336 self.stream.write("/%d (%5.1f%%)" % (self.count,
337 (self.testsRun + 1) * 100.0 / self.count))
338 if self.showAll:
339 self.stream.write(": ")
340 elif self._progressWithNames:
341 # XXX will break with multibyte strings
342 name = self.getShortDescription(test)
343 width = len(name)
344 if width < self._lastWidth:
345 name += " " * (self._lastWidth - width)
346 self.stream.write(": %s" % name)
347 self._lastWidth = width
348 self.stream.flush()
349 self._threads = threading.enumerate()
350 self.__super_startTest(test)
351 self._testtimes[test] = time.time()
353 def getShortDescription(self, test):
354 s = self.getDescription(test)
355 if len(s) > self._maxWidth:
356 pos = s.find(" (")
357 if pos >= 0:
358 w = self._maxWidth - (pos + 5)
359 if w < 1:
360 # first portion (test method name) is too long
361 s = s[:self._maxWidth-3] + "..."
362 else:
363 pre = s[:pos+2]
364 post = s[-w:]
365 s = "%s...%s" % (pre, post)
366 return s[:self._maxWidth]
368 def addError(self, test, err):
369 if self._progress:
370 self.stream.write("\r")
371 if self._debug:
372 raise err[0], err[1], err[2]
373 self._print_traceback("Error in test %s" % test, err,
374 test, self.errors)
376 def addFailure(self, test, err):
377 if self._progress:
378 self.stream.write("\r")
379 if self._debug:
380 raise err[0], err[1], err[2]
381 self._print_traceback("Failure in test %s" % test, err,
382 test, self.failures)
384 def printErrors(self):
385 if self._progress and not (self.dots or self.showAll):
386 self.stream.writeln()
387 self.__super_printErrors()
389 def printErrorList(self, flavor, errors):
390 for test, err in errors:
391 self.stream.writeln(self.separator1)
392 self.stream.writeln("%s: %s" % (flavor, self.getDescription(test)))
393 self.stream.writeln(self.separator2)
394 self.stream.writeln(err)
397 class ImmediateTestRunner(unittest.TextTestRunner):
399 __super_init = unittest.TextTestRunner.__init__
401 def __init__(self, **kwarg):
402 debug = kwarg.get("debug")
403 if debug is not None:
404 del kwarg["debug"]
405 progress = kwarg.get("progress")
406 if progress is not None:
407 del kwarg["progress"]
408 profile = kwarg.get("profile")
409 if profile is not None:
410 del kwarg["profile"]
411 self.__super_init(**kwarg)
412 self._debug = debug
413 self._progress = progress
414 self._profile = profile
415 # Create the test result here, so that we can add errors if
416 # the test suite search process has problems. The count
417 # attribute must be set in run(), because we won't know the
418 # count until all test suites have been found.
419 self.result = ImmediateTestResult(
420 self.stream, self.descriptions, self.verbosity, debug=self._debug,
421 progress=self._progress)
423 def _makeResult(self):
424 # Needed base class run method.
425 return self.result
427 def run(self, test):
428 self.result.count = test.countTestCases()
429 if self._debug:
430 club_debug(test)
431 if self._profile:
432 prof = hotshot.Profile("tests_profile.prof")
433 args = (self, test)
434 r = prof.runcall(unittest.TextTestRunner.run, *args)
435 prof.close()
436 stats = hotshot.stats.load("tests_profile.prof")
437 stats.sort_stats('cumulative', 'calls')
438 stats.print_stats(50)
439 return r
440 return unittest.TextTestRunner.run(self, test)
442 def club_debug(test):
443 # Beat a debug flag into debug-aware test cases
444 setDebugModeOn = getattr(test, 'setDebugModeOn', None)
445 if setDebugModeOn is not None:
446 setDebugModeOn()
448 for subtest in getattr(test, '_tests', ()):
449 club_debug(subtest)
451 # setup list of directories to put on the path
452 class PathInit:
453 def __init__(self, build, build_inplace, libdir=None):
454 self.inplace = None
455 # Figure out if we should test in-place or test in-build. If the -b
456 # or -B option was given, test in the place we were told to build in.
457 # Otherwise, we'll look for a build directory and if we find one,
458 # we'll test there, otherwise we'll test in-place.
459 if build:
460 self.inplace = build_inplace
461 if self.inplace is None:
462 # Need to figure it out
463 if os.path.isdir(os.path.join("build", "lib.%s" % PLAT_SPEC)):
464 self.inplace = False
465 else:
466 self.inplace = True
467 # Calculate which directories we're going to add to sys.path, and cd
468 # to the appropriate working directory
469 self.org_cwd = os.getcwd()
470 if self.inplace:
471 self.libdir = "src"
472 else:
473 self.libdir = "lib.%s" % PLAT_SPEC
474 os.chdir("build")
475 # Hack sys.path
476 self.cwd = os.getcwd()
477 sys.path.insert(0, os.path.join(self.cwd, self.libdir))
478 # Hack again for external products.
479 global functional
480 kind = functional and "FUNCTIONAL" or "UNIT"
481 if libdir:
482 extra = os.path.join(self.org_cwd, libdir)
483 print "Running %s tests from %s" % (kind, extra)
484 self.libdir = extra
485 sys.path.insert(0, extra)
486 else:
487 print "Running %s tests from %s" % (kind, self.cwd)
488 # Make sure functional tests find ftesting.zcml
489 if functional:
490 config_file = 'ftesting.zcml'
491 if not self.inplace:
492 # We chdired into build, so ftesting.zcml is in the
493 # parent directory
494 config_file = os.path.join('..', 'ftesting.zcml')
495 print "Parsing %s" % config_file
496 from zope.app.tests.functional import FunctionalTestSetup
497 FunctionalTestSetup(config_file)
499 def match(rx, s):
500 if not rx:
501 return True
502 if rx[0] == "!":
503 return re.search(rx[1:], s) is None
504 else:
505 return re.search(rx, s) is not None
507 class TestFileFinder:
508 def __init__(self, prefix):
509 self.files = []
510 self._plen = len(prefix)
511 if not prefix.endswith(os.sep):
512 self._plen += 1
513 global functional
514 if functional:
515 self.dirname = "ftests"
516 else:
517 self.dirname = "tests"
519 def visit(self, rx, dir, files):
520 if os.path.split(dir)[1] != self.dirname:
521 # Allow tests/ftests module rather than package.
522 modfname = self.dirname + '.py'
523 if modfname in files:
524 path = os.path.join(dir, modfname)
525 if match(rx, path):
526 self.files.append(path)
527 return
528 return
529 # ignore tests that aren't in packages
530 if not "__init__.py" in files:
531 if not files or files == ["CVS"]:
532 return
533 print "not a package", dir
534 return
536 # Put matching files in matches. If matches is non-empty,
537 # then make sure that the package is importable.
538 matches = []
539 for file in files:
540 if file.startswith('test') and os.path.splitext(file)[-1] == '.py':
541 path = os.path.join(dir, file)
542 if match(rx, path):
543 matches.append(path)
545 # ignore tests when the package can't be imported, possibly due to
546 # dependency failures.
547 pkg = dir[self._plen:].replace(os.sep, '.')
548 try:
549 __import__(pkg)
550 # We specifically do not want to catch ImportError since that's useful
551 # information to know when running the tests.
552 except RuntimeError, e:
553 if VERBOSE:
554 print "skipping %s because: %s" % (pkg, e)
555 return
556 else:
557 self.files.extend(matches)
559 def module_from_path(self, path):
560 """Return the Python package name indicated by the filesystem path."""
561 assert path.endswith(".py")
562 path = path[self._plen:-3]
563 mod = path.replace(os.sep, ".")
564 return mod
566 def walk_with_symlinks(top, func, arg):
567 """Like os.path.walk, but follows symlinks on POSIX systems.
569 This could theoreticaly result in an infinite loop, if you create symlink
570 cycles in your Zope sandbox, so don't do that.
571 """
572 try:
573 names = os.listdir(top)
574 except os.error:
575 return
576 func(arg, top, names)
577 exceptions = ('.', '..')
578 for name in names:
579 if name not in exceptions:
580 name = os.path.join(top, name)
581 if os.path.isdir(name):
582 walk_with_symlinks(name, func, arg)
584 def find_test_dir(dir):
585 if os.path.exists(dir):
586 return dir
587 d = os.path.join(pathinit.libdir, dir)
588 if os.path.exists(d):
589 if os.path.isdir(d):
590 return d
591 raise ValueError("%s does not exist and %s is not a directory"
592 % (dir, d))
593 raise ValueError("%s does not exist!" % dir)
595 def find_tests(rx):
596 global finder
597 finder = TestFileFinder(pathinit.libdir)
599 if TEST_DIRS:
600 for d in TEST_DIRS:
601 d = find_test_dir(d)
602 walk_with_symlinks(d, finder.visit, rx)
603 else:
604 walk_with_symlinks(pathinit.libdir, finder.visit, rx)
605 return finder.files
607 def package_import(modname):
608 mod = __import__(modname)
609 for part in modname.split(".")[1:]:
610 mod = getattr(mod, part)
611 return mod
613 class PseudoTestCase:
614 """Minimal test case objects to create error reports.
616 If test.py finds something that looks like it should be a test but
617 can't load it or find its test suite, it will report an error
618 using a PseudoTestCase.
619 """
621 def __init__(self, name, descr=None):
622 self.name = name
623 self.descr = descr
625 def shortDescription(self):
626 return self.descr
628 def __str__(self):
629 return "Invalid Test (%s)" % self.name
631 def get_suite(file, result):
632 modname = finder.module_from_path(file)
633 try:
634 mod = package_import(modname)
635 return mod.test_suite()
636 except:
637 result.addError(PseudoTestCase(modname), sys.exc_info())
638 return None
640 def filter_testcases(s, rx):
641 new = unittest.TestSuite()
642 for test in s._tests:
643 # See if the levels match
644 dolevel = (LEVEL == 0) or LEVEL >= getattr(test, "level", 0)
645 if not dolevel:
646 continue
647 if isinstance(test, unittest.TestCase):
648 name = test.id() # Full test name: package.module.class.method
649 name = name[1 + name.rfind("."):] # extract method name
650 if not rx or match(rx, name):
651 new.addTest(test)
652 else:
653 filtered = filter_testcases(test, rx)
654 if filtered:
655 new.addTest(filtered)
656 return new
658 def gui_runner(files, test_filter):
659 if BUILD_INPLACE:
660 utildir = os.path.join(os.getcwd(), "utilities")
661 else:
662 utildir = os.path.join(os.getcwd(), "..", "utilities")
663 sys.path.append(utildir)
664 import unittestgui
665 suites = []
666 for file in files:
667 suites.append(finder.module_from_path(file) + ".test_suite")
669 suites = ", ".join(suites)
670 minimal = (GUI == "minimal")
671 unittestgui.main(suites, minimal)
673 class TrackRefs:
674 """Object to track reference counts across test runs."""
676 def __init__(self):
677 self.type2count = {}
678 self.type2all = {}
680 def update(self):
681 obs = sys.getobjects(0)
682 type2count = {}
683 type2all = {}
684 for o in obs:
685 all = sys.getrefcount(o)
687 if type(o) is str and o == '<dummy key>':
688 # avoid dictionary madness
689 continue
690 t = type(o)
691 if t in type2count:
692 type2count[t] += 1
693 type2all[t] += all
694 else:
695 type2count[t] = 1
696 type2all[t] = all
698 ct = [(type2count[t] - self.type2count.get(t, 0),
699 type2all[t] - self.type2all.get(t, 0),
700 t)
701 for t in type2count.iterkeys()]
702 ct.sort()
703 ct.reverse()
704 printed = False
705 for delta1, delta2, t in ct:
706 if delta1 or delta2:
707 if not printed:
708 print "%-55s %8s %8s" % ('', 'insts', 'refs')
709 printed = True
710 print "%-55s %8d %8d" % (t, delta1, delta2)
712 self.type2count = type2count
713 self.type2all = type2all
715 def runner(files, test_filter, debug):
716 runner = ImmediateTestRunner(verbosity=VERBOSE, debug=DEBUG,
717 progress=PROGRESS, profile=PROFILE,
718 descriptions=False)
719 suite = unittest.TestSuite()
720 for file in files:
721 s = get_suite(file, runner.result)
722 # See if the levels match
723 dolevel = (LEVEL == 0) or LEVEL >= getattr(s, "level", 0)
724 if s is not None and dolevel:
725 s = filter_testcases(s, test_filter)
726 suite.addTest(s)
727 try:
728 r = runner.run(suite)
729 if TIMESFN:
730 r.print_times(open(TIMESFN, "w"))
731 if VERBOSE:
732 print "Wrote timing data to", TIMESFN
733 if TIMETESTS:
734 r.print_times(sys.stdout, TIMETESTS)
735 except:
736 if DEBUGGER:
737 print "%s:" % (sys.exc_info()[0], )
738 print sys.exc_info()[1]
739 pdb.post_mortem(sys.exc_info()[2])
740 else:
741 raise
743 def remove_stale_bytecode(arg, dirname, names):
744 names = map(os.path.normcase, names)
745 for name in names:
746 if name.endswith(".pyc") or name.endswith(".pyo"):
747 srcname = name[:-1]
748 if srcname not in names:
749 fullname = os.path.join(dirname, name)
750 print "Removing stale bytecode file", fullname
751 os.unlink(fullname)
753 def main(module_filter, test_filter, libdir):
754 if not KEEP_STALE_BYTECODE:
755 os.path.walk(os.curdir, remove_stale_bytecode, None)
757 configure_logging()
759 # Initialize the path and cwd
760 global pathinit
761 pathinit = PathInit(BUILD, BUILD_INPLACE, libdir)
763 files = find_tests(module_filter)
764 files.sort()
766 if GUI:
767 gui_runner(files, test_filter)
768 elif LOOP:
769 if REFCOUNT:
770 rc = sys.gettotalrefcount()
771 track = TrackRefs()
772 while True:
773 runner(files, test_filter, DEBUG)
774 gc.collect()
775 if gc.garbage:
776 print "GARBAGE:", len(gc.garbage), gc.garbage
777 return
778 if REFCOUNT:
779 prev = rc
780 rc = sys.gettotalrefcount()
781 print "totalrefcount=%-8d change=%-6d" % (rc, rc - prev)
782 track.update()
783 else:
784 runner(files, test_filter, DEBUG)
786 os.chdir(pathinit.org_cwd)
789 def configure_logging():
790 """Initialize the logging module."""
791 import logging.config
793 # Get the log.ini file from the current directory instead of possibly
794 # buried in the build directory. XXX This isn't perfect because if
795 # log.ini specifies a log file, it'll be relative to the build directory.
796 # Hmm...
797 logini = os.path.abspath("log.ini")
799 if os.path.exists(logini):
800 logging.config.fileConfig(logini)
801 else:
802 logging.basicConfig()
804 if os.environ.has_key("LOGGING"):
805 level = int(os.environ["LOGGING"])
806 logging.getLogger().setLevel(level)
809 def process_args(argv=None):
810 import getopt
811 global MODULE_FILTER
812 global TEST_FILTER
813 global VERBOSE
814 global LOOP
815 global GUI
816 global TRACE
817 global REFCOUNT
818 global DEBUG
819 global DEBUGGER
820 global BUILD
821 global LEVEL
822 global LIBDIR
823 global TIMESFN
824 global TIMETESTS
825 global PROGRESS
826 global BUILD_INPLACE
827 global KEEP_STALE_BYTECODE
828 global TEST_DIRS
829 global PROFILE
830 global GC_THRESHOLD
831 global GC_FLAGS
832 global RUN_UNIT
833 global RUN_FUNCTIONAL
834 global PYCHECKER
836 if argv is None:
837 argv = sys.argv
839 MODULE_FILTER = None
840 TEST_FILTER = None
841 VERBOSE = 0
842 LOOP = False
843 GUI = False
844 TRACE = False
845 REFCOUNT = False
846 DEBUG = False # Don't collect test results; simply let tests crash
847 DEBUGGER = False
848 BUILD = False
849 BUILD_INPLACE = False
850 GC_THRESHOLD = None
851 gcdebug = 0
852 GC_FLAGS = []
853 LEVEL = 1
854 LIBDIR = None
855 PROGRESS = False
856 TIMESFN = None
857 TIMETESTS = 0
858 KEEP_STALE_BYTECODE = 0
859 RUN_UNIT = True
860 RUN_FUNCTIONAL = True
861 TEST_DIRS = []
862 PROFILE = False
863 PYCHECKER = False
864 config_filename = 'test.config'
866 # import the config file
867 if os.path.isfile(config_filename):
868 print 'Configuration file found.'
869 execfile(config_filename, globals())
872 try:
873 opts, args = getopt.getopt(argv[1:], "a:bBcdDfFg:G:hkl:LmMPprs:tTuUv",
874 ["all", "help", "libdir=", "times=",
875 "keepbytecode", "dir=", "build",
876 "build-inplace",
877 "at-level=",
878 "pychecker", "debug", "pdebug",
879 "gc-threshold=", "gc-option=",
880 "loop", "gui", "minimal-gui",
881 "profile", "progress", "refcount", "trace",
882 "top-fifty", "verbose",
883 ])
884 # fixme: add the long names
885 # fixme: add the extra documentation
886 # fixme: test for functional first!
887 except getopt.error, msg:
888 print msg
889 print "Try `python %s -h' for more information." % argv[0]
890 sys.exit(2)
892 for k, v in opts:
893 if k in ("-a", "--at-level"):
894 LEVEL = int(v)
895 elif k == "--all":
896 LEVEL = 0
897 os.environ["COMPLAIN_IF_TESTS_MISSED"]='1'
898 elif k in ("-b", "--build"):
899 BUILD = True
900 elif k in ("-B", "--build-inplace"):
901 BUILD = BUILD_INPLACE = True
902 elif k in("-c", "--pychecker"):
903 PYCHECKER = True
904 elif k in ("-d", "--debug"):
905 DEBUG = True
906 elif k in ("-D", "--pdebug"):
907 DEBUG = True
908 DEBUGGER = True
909 elif k in ("-f", "--skip-unit"):
910 RUN_UNIT = False
911 elif k in ("-u", "--skip-functional"):
912 RUN_FUNCTIONAL = False
913 elif k == "-F":
914 message = 'Unit plus functional is the default behaviour.'
915 warnings.warn(message, DeprecationWarning)
916 RUN_UNIT = True
917 RUN_FUNCTIONAL = True
918 elif k in ("-h", "--help"):
919 print __doc__
920 sys.exit(0)
921 elif k in ("-g", "--gc-threshold"):
922 GC_THRESHOLD = int(v)
923 elif k in ("-G", "--gc-option"):
924 if not v.startswith("DEBUG_"):
925 print "-G argument must be DEBUG_ flag, not", repr(v)
926 sys.exit(1)
927 GC_FLAGS.append(v)
928 elif k in ('-k', '--keepbytecode'):
929 KEEP_STALE_BYTECODE = 1
930 elif k in ('-l', '--libdir'):
931 LIBDIR = v
932 elif k in ("-L", "--loop"):
933 LOOP = 1
934 elif k == "-m":
935 GUI = "minimal"
936 msg = "Use -M or --minimal-gui instead of -m."
937 warnings.warn(msg, DeprecationWarning)
938 elif k in ("-M", "--minimal-gui"):
939 GUI = "minimal"
940 elif k in ("-P", "--profile"):
941 PROFILE = True
942 elif k in ("-p", "--progress"):
943 PROGRESS = True
944 elif k in ("-r", "--refcount"):
945 REFCOUNT = True
946 elif k in ("-T", "--trace"):
947 TRACE = True
948 elif k in ("-t", "--top-fifty"):
949 if not TIMETESTS:
950 TIMETESTS = 50
951 elif k in ("-u", "--gui"):
952 GUI = 1
953 elif k in ("-v", "--verbose"):
954 VERBOSE += 1
955 elif k == "--times":
956 try:
957 TIMETESTS = int(v)
958 except ValueError:
959 # must be a filename to write
960 TIMESFN = v
961 elif k in ('-s', '--dir'):
962 TEST_DIRS.append(v)
964 if PYCHECKER:
965 # make sure you have a recent version of pychecker
966 if not os.environ.get("PYCHECKER"):
967 os.environ["PYCHECKER"] = "-q"
968 import pychecker.checker
970 if REFCOUNT and not hasattr(sys, "gettotalrefcount"):
971 print "-r ignored, because it needs a debug build of Python"
972 REFCOUNT = False
974 if sys.version_info < ( 2,3,2 ):
975 print """\
976 ERROR: Your python version is not supported by Zope3.
977 Zope3 needs Python 2.3.2 or greater. You are running:""" + sys.version
978 sys.exit(1)
980 if GC_THRESHOLD is not None:
981 if GC_THRESHOLD == 0:
982 gc.disable()
983 print "gc disabled"
984 else:
985 gc.set_threshold(GC_THRESHOLD)
986 print "gc threshold:", gc.get_threshold()
988 if GC_FLAGS:
989 val = 0
990 for flag in GC_FLAGS:
991 v = getattr(gc, flag, None)
992 if v is None:
993 print "Unknown gc flag", repr(flag)
994 print gc.set_debug.__doc__
995 sys.exit(1)
996 val |= v
997 gcdebug |= v
999 if gcdebug:
1000 gc.set_debug(gcdebug)
1002 if BUILD:
1003 # Python 2.3 is more sane in its non -q output
1004 if sys.hexversion >= 0x02030000:
1005 qflag = ""
1006 else:
1007 qflag = "-q"
1008 cmd = sys.executable + " setup.py " + qflag + " build"
1009 if BUILD_INPLACE:
1010 cmd += "_ext -i"
1011 if VERBOSE:
1012 print cmd
1013 sts = os.system(cmd)
1014 if sts:
1015 print "Build failed", hex(sts)
1016 sys.exit(1)
1018 k = []
1019 if RUN_UNIT:
1020 k.append(False)
1021 if RUN_FUNCTIONAL:
1022 k.append(True)
1024 global functional
1025 for functional in k:
1027 if VERBOSE:
1028 kind = functional and "FUNCTIONAL" or "UNIT"
1029 if LEVEL == 0:
1030 print "Running %s tests at all levels" % kind
1031 else:
1032 print "Running %s tests at level %d" % (kind, LEVEL)
1034 # This was to avoid functional tests outside of z3, but this doesn't really
1035 # work right.
1036 ## if functional:
1037 ## try:
1038 ## from zope.app.tests.functional import FunctionalTestSetup
1039 ## except ImportError:
1040 ## raise
1041 ## print ('Skipping functional tests: could not import '
1042 ## 'zope.app.tests.functional')
1043 ## continue
1045 # XXX We want to change *visible* warnings into errors. The next
1046 # line changes all warnings into errors, including warnings we
1047 # normally never see. In particular, test_datetime does some
1048 # short-integer arithmetic that overflows to long ints, and, by
1049 # default, Python doesn't display the overflow warning that can
1050 # be enabled when this happens. The next line turns that into an
1051 # error instead. Guido suggests that a better to get what we're
1052 # after is to replace warnings.showwarning() with our own thing
1053 # that raises an error.
1054 ## warnings.filterwarnings("error")
1055 warnings.filterwarnings("ignore", module="logging")
1057 if args:
1058 if len(args) > 1:
1059 TEST_FILTER = args[1]
1060 MODULE_FILTER = args[0]
1061 try:
1062 if TRACE:
1063 # if the trace module is used, then we don't exit with
1064 # status if on a false return value from main.
1065 coverdir = os.path.join(os.getcwd(), "coverage")
1066 import trace
1067 ignoremods = ["os", "posixpath", "stat"]
1068 tracer = trace.Trace(ignoredirs=[sys.prefix, sys.exec_prefix],
1069 ignoremods=ignoremods,
1070 trace=False, count=True)
1072 tracer.runctx("main(MODULE_FILTER, TEST_FILTER, LIBDIR)",
1073 globals=globals(), locals=vars())
1074 r = tracer.results()
1075 path = "/tmp/trace.%s" % os.getpid()
1076 import cPickle
1077 f = open(path, "wb")
1078 cPickle.dump(r, f)
1079 f.close()
1080 print path
1081 r.write_results(show_missing=True,
1082 summary=True, coverdir=coverdir)
1083 else:
1084 bad = main(MODULE_FILTER, TEST_FILTER, LIBDIR)
1085 if bad:
1086 sys.exit(1)
1087 except ImportError, err:
1088 print err
1089 print sys.path
1090 raise
1093 if __name__ == "__main__":
1094 process_args()