direct-io.hg
changeset 7235:cd228621e1fd
Added Zope's test.py, and a unit test to sxp. This test itself isn't very
exciting, but it's there to encourage the creation of more interesting ones. A
test target has been added to the main Makefile, and the one in tools/python.
Signed-off-by: Ewan Mellor <ewan@xensource.com>
exciting, but it's there to encourage the creation of more interesting ones. A
test target has been added to the main Makefile, and the one in tools/python.
Signed-off-by: Ewan Mellor <ewan@xensource.com>
author | emellor@ewan |
---|---|
date | Thu Oct 06 15:12:31 2005 +0100 (2005-10-06) |
parents | bd37123974b2 |
children | 4083eb31def0 f5320ac7ed31 |
files | Makefile tools/python/Makefile tools/python/README tools/python/ZPL-2.0 tools/python/setup.py tools/python/test.py tools/python/xen/xend/tests/__init__.py tools/python/xen/xend/tests/test_sxp.py |
line diff
1.1 --- a/Makefile Thu Oct 06 11:12:55 2005 +0100 1.2 +++ b/Makefile Thu Oct 06 15:12:31 2005 +0100 1.3 @@ -36,6 +36,12 @@ build: kernels 1.4 $(MAKE) -C tools build 1.5 $(MAKE) -C docs build 1.6 1.7 +# The test target is for unit tests that can run without an installation. Of 1.8 +# course, many tests require a machine running Xen itself, and these are 1.9 +# handled elsewhere. 1.10 +test: 1.11 + $(MAKE) -C tools/python test 1.12 + 1.13 # build and install everything into local dist directory 1.14 dist: DESTDIR=$(DISTDIR)/install 1.15 dist: dist-xen dist-kernels dist-tools dist-docs
2.1 --- a/tools/python/Makefile Thu Oct 06 11:12:55 2005 +0100 2.2 +++ b/tools/python/Makefile Thu Oct 06 15:12:31 2005 +0100 2.3 @@ -15,5 +15,8 @@ install: all 2.4 CFLAGS="$(CFLAGS)" python setup.py install --root="$(DESTDIR)" 2.5 endif 2.6 2.7 +test: 2.8 + export LD_LIBRARY_PATH=$$(readlink -f ../libxc):$$(readlink -f ../xenstore); python test.py -b -u 2.9 + 2.10 clean: 2.11 rm -rf build *.pyc *.pyo *.o *.a *~
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/tools/python/README Thu Oct 06 15:12:31 2005 +0100 3.3 @@ -0,0 +1,3 @@ 3.4 +The file test.py here is from the Zope project, and is Copyright (c) 2001, 3.5 +2002 Zope Corporation and Contributors. This file is released under the Zope 3.6 +Public License, version 2.0, a copy of which is in the file ZPL-2.0.
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/tools/python/ZPL-2.0 Thu Oct 06 15:12:31 2005 +0100 4.3 @@ -0,0 +1,59 @@ 4.4 +Zope Public License (ZPL) Version 2.0 4.5 +----------------------------------------------- 4.6 + 4.7 +This software is Copyright (c) Zope Corporation (tm) and 4.8 +Contributors. All rights reserved. 4.9 + 4.10 +This license has been certified as open source. It has also 4.11 +been designated as GPL compatible by the Free Software 4.12 +Foundation (FSF). 4.13 + 4.14 +Redistribution and use in source and binary forms, with or 4.15 +without modification, are permitted provided that the 4.16 +following conditions are met: 4.17 + 4.18 +1. Redistributions in source code must retain the above 4.19 + copyright notice, this list of conditions, and the following 4.20 + disclaimer. 4.21 + 4.22 +2. Redistributions in binary form must reproduce the above 4.23 + copyright notice, this list of conditions, and the following 4.24 + disclaimer in the documentation and/or other materials 4.25 + provided with the distribution. 4.26 + 4.27 +3. The name Zope Corporation (tm) must not be used to 4.28 + endorse or promote products derived from this software 4.29 + without prior written permission from Zope Corporation. 4.30 + 4.31 +4. The right to distribute this software or to use it for 4.32 + any purpose does not give you the right to use Servicemarks 4.33 + (sm) or Trademarks (tm) of Zope Corporation. Use of them is 4.34 + covered in a separate agreement (see 4.35 + http://www.zope.com/Marks). 4.36 + 4.37 +5. If any files are modified, you must cause the modified 4.38 + files to carry prominent notices stating that you changed 4.39 + the files and the date of any change. 4.40 + 4.41 +Disclaimer 4.42 + 4.43 + THIS SOFTWARE IS PROVIDED BY ZOPE CORPORATION ``AS IS'' 4.44 + AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 4.45 + NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 4.46 + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 4.47 + NO EVENT SHALL ZOPE CORPORATION OR ITS CONTRIBUTORS BE 4.48 + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 4.49 + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 4.50 + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 4.51 + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4.52 + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 4.53 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 4.54 + OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 4.55 + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 4.56 + DAMAGE. 4.57 + 4.58 + 4.59 +This software consists of contributions made by Zope 4.60 +Corporation and many individuals on behalf of Zope 4.61 +Corporation. Specific attributions are listed in the 4.62 +accompanying credits file. 4.63 \ No newline at end of file
5.1 --- a/tools/python/setup.py Thu Oct 06 11:12:55 2005 +0100 5.2 +++ b/tools/python/setup.py Thu Oct 06 15:12:31 2005 +0100 5.3 @@ -42,7 +42,9 @@ setup(name = 'xen', 5.4 'xen.xend.xenstore', 5.5 'xen.xm', 5.6 'xen.web', 5.7 - 'xen.sv' 5.8 + 'xen.sv', 5.9 + 5.10 + 'xen.xend.tests' 5.11 ], 5.12 ext_package = "xen.lowlevel", 5.13 ext_modules = [ xc, xs ]
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/tools/python/test.py Thu Oct 06 15:12:31 2005 +0100 6.3 @@ -0,0 +1,1094 @@ 6.4 +#! /usr/bin/env python2.3 6.5 +############################################################################## 6.6 +# 6.7 +# Copyright (c) 2001, 2002 Zope Corporation and Contributors. 6.8 +# All Rights Reserved. 6.9 +# 6.10 +# This software is subject to the provisions of the Zope Public License, 6.11 +# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution. 6.12 +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED 6.13 +# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 6.14 +# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS 6.15 +# FOR A PARTICULAR PURPOSE. 6.16 +# 6.17 +############################################################################## 6.18 +""" 6.19 +test.py [-abBcdDfFgGhklLmMPprstTuUv] [modfilter [testfilter]] 6.20 + 6.21 +Find and run tests written using the unittest module. 6.22 + 6.23 +The test runner searches for Python modules that contain test suites. 6.24 +It collects those suites, and runs the tests. There are many options 6.25 +for controlling how the tests are run. There are options for using 6.26 +the debugger, reporting code coverage, and checking for refcount problems. 6.27 + 6.28 +The test runner uses the following rules for finding tests to run. It 6.29 +searches for packages and modules that contain "tests" as a component 6.30 +of the name, e.g. "frob.tests.nitz" matches this rule because tests is 6.31 +a sub-package of frob. Within each "tests" package, it looks for 6.32 +modules that begin with the name "test." For each test module, it 6.33 +imports the module and calls the module's test_suite() function, which must 6.34 +return a unittest TestSuite object. 6.35 + 6.36 +Options can be specified as command line arguments (see below). However, 6.37 +options may also be specified in a file named 'test.config', a Python 6.38 +script which, if found, will be executed before the command line 6.39 +arguments are processed. 6.40 + 6.41 +The test.config script should specify options by setting zero or more of the 6.42 +global variables: LEVEL, BUILD, and other capitalized variable names found in 6.43 +the test runner script (see the list of global variables in process_args().). 6.44 + 6.45 + 6.46 +-a level 6.47 +--at-level level 6.48 +--all 6.49 + Run the tests at the given level. Any test at a level at or below 6.50 + this is run, any test at a level above this is not run. Level 0 6.51 + runs all tests. The default is to run tests at level 1. --all is 6.52 + a shortcut for -a 0. 6.53 + 6.54 +-b 6.55 +--build 6.56 + Run "python setup.py build" before running tests, where "python" 6.57 + is the version of python used to run test.py. Highly recommended. 6.58 + Tests will be run from the build directory. 6.59 + 6.60 +-B 6.61 +--build-inplace 6.62 + Run "python setup.py build_ext -i" before running tests. Tests will be 6.63 + run from the source directory. 6.64 + 6.65 +-c 6.66 +--pychecker 6.67 + use pychecker 6.68 + 6.69 +-d 6.70 +--debug 6.71 + Instead of the normal test harness, run a debug version which 6.72 + doesn't catch any exceptions. This is occasionally handy when the 6.73 + unittest code catching the exception doesn't work right. 6.74 + Unfortunately, the debug harness doesn't print the name of the 6.75 + test, so Use With Care. 6.76 + 6.77 +-D 6.78 +--debug-inplace 6.79 + Works like -d, except that it loads pdb when an exception occurs. 6.80 + 6.81 +--dir directory 6.82 +-s directory 6.83 + Option to limit where tests are searched for. This is important 6.84 + when you *really* want to limit the code that gets run. This can 6.85 + be specified more than once to run tests in two different parts of 6.86 + the source tree. 6.87 + For example, if refactoring interfaces, you don't want to see the way 6.88 + you have broken setups for tests in other packages. You *just* want to 6.89 + run the interface tests. 6.90 + 6.91 +-f 6.92 +--skip-unit 6.93 + Run functional tests but not unit tests. 6.94 + Note that functional tests will be skipped if the module 6.95 + zope.app.tests.functional cannot be imported. 6.96 + Functional tests also expect to find the file ftesting.zcml, 6.97 + which is used to configure the functional-test run. 6.98 + 6.99 +-F 6.100 + DEPRECATED. Run both unit and functional tests. 6.101 + This option is deprecated, because this is the new default mode. 6.102 + Note that functional tests will be skipped if the module 6.103 + zope.app.tests.functional cannot be imported. 6.104 + 6.105 +-g threshold 6.106 +--gc-threshold threshold 6.107 + Set the garbage collector generation0 threshold. This can be used 6.108 + to stress memory and gc correctness. Some crashes are only 6.109 + reproducible when the threshold is set to 1 (agressive garbage 6.110 + collection). Do "-g 0" to disable garbage collection altogether. 6.111 + 6.112 +-G gc_option 6.113 +--gc-option gc_option 6.114 + Set the garbage collection debugging flags. The argument must be one 6.115 + of the DEBUG_ flags defined bythe Python gc module. Multiple options 6.116 + can be specified by using "-G OPTION1 -G OPTION2." 6.117 + 6.118 +-k 6.119 +--keepbytecode 6.120 + Do not delete all stale bytecode before running tests 6.121 + 6.122 +-l test_root 6.123 +--libdir test_root 6.124 + Search for tests starting in the specified start directory 6.125 + (useful for testing components being developed outside the main 6.126 + "src" or "build" trees). 6.127 + 6.128 +-L 6.129 +--loop 6.130 + Keep running the selected tests in a loop. You may experience 6.131 + memory leakage. 6.132 + 6.133 +-m 6.134 +-M minimal GUI. See -U. 6.135 + 6.136 +-P 6.137 +--profile 6.138 + Run the tests under hotshot and display the top 50 stats, sorted by 6.139 + cumulative time and number of calls. 6.140 + 6.141 +-p 6.142 +--progress 6.143 + Show running progress. It can be combined with -v or -vv. 6.144 + 6.145 +-r 6.146 +--refcount 6.147 + Look for refcount problems. 6.148 + This requires that Python was built --with-pydebug. 6.149 + 6.150 +-t 6.151 +--top-fifty 6.152 + Time the individual tests and print a list of the top 50, sorted from 6.153 + longest to shortest. 6.154 + 6.155 +--times n 6.156 +--times outfile 6.157 + With an integer argument, time the tests and print a list of the top <n> 6.158 + tests, sorted from longest to shortest. 6.159 + With a non-integer argument, specifies a file to which timing information 6.160 + is to be printed. 6.161 + 6.162 +-T 6.163 +--trace 6.164 + Use the trace module from Python for code coverage. The current 6.165 + utility writes coverage files to a directory named `coverage' that 6.166 + is parallel to `build'. It also prints a summary to stdout. 6.167 + 6.168 +-u 6.169 +--skip-functional 6.170 + CHANGED. Run unit tests but not functional tests. 6.171 + Note that the meaning of -u is changed from its former meaning, 6.172 + which is now specified by -U or --gui. 6.173 + 6.174 +-U 6.175 +--gui 6.176 + Use the PyUnit GUI instead of output to the command line. The GUI 6.177 + imports tests on its own, taking care to reload all dependencies 6.178 + on each run. The debug (-d), verbose (-v), progress (-p), and 6.179 + Loop (-L) options will be ignored. The testfilter filter is also 6.180 + not applied. 6.181 + 6.182 +-m 6.183 +-M 6.184 +--minimal-gui 6.185 + Note: -m is DEPRECATED in favour of -M or --minimal-gui. 6.186 + -m starts the gui minimized. Double-clicking the progress bar 6.187 + will start the import and run all tests. 6.188 + 6.189 + 6.190 +-v 6.191 +--verbose 6.192 + Verbose output. With one -v, unittest prints a dot (".") for each 6.193 + test run. With -vv, unittest prints the name of each test (for 6.194 + some definition of "name" ...). With no -v, unittest is silent 6.195 + until the end of the run, except when errors occur. 6.196 + 6.197 + When -p is also specified, the meaning of -v is slightly 6.198 + different. With -p and no -v only the percent indicator is 6.199 + displayed. With -p and -v the test name of the current test is 6.200 + shown to the right of the percent indicator. With -p and -vv the 6.201 + test name is not truncated to fit into 80 columns and it is not 6.202 + cleared after the test finishes. 6.203 + 6.204 + 6.205 +modfilter 6.206 +testfilter 6.207 + Case-sensitive regexps to limit which tests are run, used in search 6.208 + (not match) mode. 6.209 + In an extension of Python regexp notation, a leading "!" is stripped 6.210 + and causes the sense of the remaining regexp to be negated (so "!bc" 6.211 + matches any string that does not match "bc", and vice versa). 6.212 + By default these act like ".", i.e. nothing is excluded. 6.213 + 6.214 + modfilter is applied to a test file's path, starting at "build" and 6.215 + including (OS-dependent) path separators. 6.216 + 6.217 + testfilter is applied to the (method) name of the unittest methods 6.218 + contained in the test files whose paths modfilter matched. 6.219 + 6.220 +Extreme (yet useful) examples: 6.221 + 6.222 + test.py -vvb . "^testWriteClient$" 6.223 + 6.224 + Builds the project silently, then runs unittest in verbose mode on all 6.225 + tests whose names are precisely "testWriteClient". Useful when 6.226 + debugging a specific test. 6.227 + 6.228 + test.py -vvb . "!^testWriteClient$" 6.229 + 6.230 + As before, but runs all tests whose names aren't precisely 6.231 + "testWriteClient". Useful to avoid a specific failing test you don't 6.232 + want to deal with just yet. 6.233 + 6.234 + test.py -M . "!^testWriteClient$" 6.235 + 6.236 + As before, but now opens up a minimized PyUnit GUI window (only showing 6.237 + the progress bar). Useful for refactoring runs where you continually want 6.238 + to make sure all tests still pass. 6.239 +""" 6.240 + 6.241 +import gc 6.242 +import hotshot, hotshot.stats 6.243 +import os 6.244 +import re 6.245 +import pdb 6.246 +import sys 6.247 +import threading # just to get at Thread objects created by tests 6.248 +import time 6.249 +import traceback 6.250 +import unittest 6.251 +import warnings 6.252 + 6.253 +def set_trace_doctest(stdin=sys.stdin, stdout=sys.stdout, trace=pdb.set_trace): 6.254 + sys.stdin = stdin 6.255 + sys.stdout = stdout 6.256 + trace() 6.257 + 6.258 +pdb.set_trace_doctest = set_trace_doctest 6.259 + 6.260 +from distutils.util import get_platform 6.261 + 6.262 +PLAT_SPEC = "%s-%s" % (get_platform(), sys.version[0:3]) 6.263 + 6.264 +class ImmediateTestResult(unittest._TextTestResult): 6.265 + 6.266 + __super_init = unittest._TextTestResult.__init__ 6.267 + __super_startTest = unittest._TextTestResult.startTest 6.268 + __super_printErrors = unittest._TextTestResult.printErrors 6.269 + 6.270 + def __init__(self, stream, descriptions, verbosity, debug=False, 6.271 + count=None, progress=False): 6.272 + self.__super_init(stream, descriptions, verbosity) 6.273 + self._debug = debug 6.274 + self._progress = progress 6.275 + self._progressWithNames = False 6.276 + self.count = count 6.277 + self._testtimes = {} 6.278 + if progress and verbosity == 1: 6.279 + self.dots = False 6.280 + self._progressWithNames = True 6.281 + self._lastWidth = 0 6.282 + self._maxWidth = 80 6.283 + try: 6.284 + import curses 6.285 + except ImportError: 6.286 + pass 6.287 + else: 6.288 + curses.setupterm() 6.289 + self._maxWidth = curses.tigetnum('cols') 6.290 + self._maxWidth -= len("xxxx/xxxx (xxx.x%): ") + 1 6.291 + 6.292 + def stopTest(self, test): 6.293 + self._testtimes[test] = time.time() - self._testtimes[test] 6.294 + if gc.garbage: 6.295 + print "The following test left garbage:" 6.296 + print test 6.297 + print gc.garbage 6.298 + # XXX Perhaps eat the garbage here, so that the garbage isn't 6.299 + # printed for every subsequent test. 6.300 + 6.301 + # Did the test leave any new threads behind? 6.302 + new_threads = [t for t in threading.enumerate() 6.303 + if (t.isAlive() 6.304 + and 6.305 + t not in self._threads)] 6.306 + if new_threads: 6.307 + print "The following test left new threads behind:" 6.308 + print test 6.309 + print "New thread(s):", new_threads 6.310 + 6.311 + def print_times(self, stream, count=None): 6.312 + results = self._testtimes.items() 6.313 + results.sort(lambda x, y: cmp(y[1], x[1])) 6.314 + if count: 6.315 + n = min(count, len(results)) 6.316 + if n: 6.317 + print >>stream, "Top %d longest tests:" % n 6.318 + else: 6.319 + n = len(results) 6.320 + if not n: 6.321 + return 6.322 + for i in range(n): 6.323 + print >>stream, "%6dms" % int(results[i][1] * 1000), results[i][0] 6.324 + 6.325 + def _print_traceback(self, msg, err, test, errlist): 6.326 + if self.showAll or self.dots or self._progress: 6.327 + self.stream.writeln("\n") 6.328 + self._lastWidth = 0 6.329 + 6.330 + tb = "".join(traceback.format_exception(*err)) 6.331 + self.stream.writeln(msg) 6.332 + self.stream.writeln(tb) 6.333 + errlist.append((test, tb)) 6.334 + 6.335 + def startTest(self, test): 6.336 + if self._progress: 6.337 + self.stream.write("\r%4d" % (self.testsRun + 1)) 6.338 + if self.count: 6.339 + self.stream.write("/%d (%5.1f%%)" % (self.count, 6.340 + (self.testsRun + 1) * 100.0 / self.count)) 6.341 + if self.showAll: 6.342 + self.stream.write(": ") 6.343 + elif self._progressWithNames: 6.344 + # XXX will break with multibyte strings 6.345 + name = self.getShortDescription(test) 6.346 + width = len(name) 6.347 + if width < self._lastWidth: 6.348 + name += " " * (self._lastWidth - width) 6.349 + self.stream.write(": %s" % name) 6.350 + self._lastWidth = width 6.351 + self.stream.flush() 6.352 + self._threads = threading.enumerate() 6.353 + self.__super_startTest(test) 6.354 + self._testtimes[test] = time.time() 6.355 + 6.356 + def getShortDescription(self, test): 6.357 + s = self.getDescription(test) 6.358 + if len(s) > self._maxWidth: 6.359 + pos = s.find(" (") 6.360 + if pos >= 0: 6.361 + w = self._maxWidth - (pos + 5) 6.362 + if w < 1: 6.363 + # first portion (test method name) is too long 6.364 + s = s[:self._maxWidth-3] + "..." 6.365 + else: 6.366 + pre = s[:pos+2] 6.367 + post = s[-w:] 6.368 + s = "%s...%s" % (pre, post) 6.369 + return s[:self._maxWidth] 6.370 + 6.371 + def addError(self, test, err): 6.372 + if self._progress: 6.373 + self.stream.write("\r") 6.374 + if self._debug: 6.375 + raise err[0], err[1], err[2] 6.376 + self._print_traceback("Error in test %s" % test, err, 6.377 + test, self.errors) 6.378 + 6.379 + def addFailure(self, test, err): 6.380 + if self._progress: 6.381 + self.stream.write("\r") 6.382 + if self._debug: 6.383 + raise err[0], err[1], err[2] 6.384 + self._print_traceback("Failure in test %s" % test, err, 6.385 + test, self.failures) 6.386 + 6.387 + def printErrors(self): 6.388 + if self._progress and not (self.dots or self.showAll): 6.389 + self.stream.writeln() 6.390 + self.__super_printErrors() 6.391 + 6.392 + def printErrorList(self, flavor, errors): 6.393 + for test, err in errors: 6.394 + self.stream.writeln(self.separator1) 6.395 + self.stream.writeln("%s: %s" % (flavor, self.getDescription(test))) 6.396 + self.stream.writeln(self.separator2) 6.397 + self.stream.writeln(err) 6.398 + 6.399 + 6.400 +class ImmediateTestRunner(unittest.TextTestRunner): 6.401 + 6.402 + __super_init = unittest.TextTestRunner.__init__ 6.403 + 6.404 + def __init__(self, **kwarg): 6.405 + debug = kwarg.get("debug") 6.406 + if debug is not None: 6.407 + del kwarg["debug"] 6.408 + progress = kwarg.get("progress") 6.409 + if progress is not None: 6.410 + del kwarg["progress"] 6.411 + profile = kwarg.get("profile") 6.412 + if profile is not None: 6.413 + del kwarg["profile"] 6.414 + self.__super_init(**kwarg) 6.415 + self._debug = debug 6.416 + self._progress = progress 6.417 + self._profile = profile 6.418 + # Create the test result here, so that we can add errors if 6.419 + # the test suite search process has problems. The count 6.420 + # attribute must be set in run(), because we won't know the 6.421 + # count until all test suites have been found. 6.422 + self.result = ImmediateTestResult( 6.423 + self.stream, self.descriptions, self.verbosity, debug=self._debug, 6.424 + progress=self._progress) 6.425 + 6.426 + def _makeResult(self): 6.427 + # Needed base class run method. 6.428 + return self.result 6.429 + 6.430 + def run(self, test): 6.431 + self.result.count = test.countTestCases() 6.432 + if self._debug: 6.433 + club_debug(test) 6.434 + if self._profile: 6.435 + prof = hotshot.Profile("tests_profile.prof") 6.436 + args = (self, test) 6.437 + r = prof.runcall(unittest.TextTestRunner.run, *args) 6.438 + prof.close() 6.439 + stats = hotshot.stats.load("tests_profile.prof") 6.440 + stats.sort_stats('cumulative', 'calls') 6.441 + stats.print_stats(50) 6.442 + return r 6.443 + return unittest.TextTestRunner.run(self, test) 6.444 + 6.445 +def club_debug(test): 6.446 + # Beat a debug flag into debug-aware test cases 6.447 + setDebugModeOn = getattr(test, 'setDebugModeOn', None) 6.448 + if setDebugModeOn is not None: 6.449 + setDebugModeOn() 6.450 + 6.451 + for subtest in getattr(test, '_tests', ()): 6.452 + club_debug(subtest) 6.453 + 6.454 +# setup list of directories to put on the path 6.455 +class PathInit: 6.456 + def __init__(self, build, build_inplace, libdir=None): 6.457 + self.inplace = None 6.458 + # Figure out if we should test in-place or test in-build. If the -b 6.459 + # or -B option was given, test in the place we were told to build in. 6.460 + # Otherwise, we'll look for a build directory and if we find one, 6.461 + # we'll test there, otherwise we'll test in-place. 6.462 + if build: 6.463 + self.inplace = build_inplace 6.464 + if self.inplace is None: 6.465 + # Need to figure it out 6.466 + if os.path.isdir(os.path.join("build", "lib.%s" % PLAT_SPEC)): 6.467 + self.inplace = False 6.468 + else: 6.469 + self.inplace = True 6.470 + # Calculate which directories we're going to add to sys.path, and cd 6.471 + # to the appropriate working directory 6.472 + self.org_cwd = os.getcwd() 6.473 + if self.inplace: 6.474 + self.libdir = "src" 6.475 + else: 6.476 + self.libdir = "lib.%s" % PLAT_SPEC 6.477 + os.chdir("build") 6.478 + # Hack sys.path 6.479 + self.cwd = os.getcwd() 6.480 + sys.path.insert(0, os.path.join(self.cwd, self.libdir)) 6.481 + # Hack again for external products. 6.482 + global functional 6.483 + kind = functional and "FUNCTIONAL" or "UNIT" 6.484 + if libdir: 6.485 + extra = os.path.join(self.org_cwd, libdir) 6.486 + print "Running %s tests from %s" % (kind, extra) 6.487 + self.libdir = extra 6.488 + sys.path.insert(0, extra) 6.489 + else: 6.490 + print "Running %s tests from %s" % (kind, self.cwd) 6.491 + # Make sure functional tests find ftesting.zcml 6.492 + if functional: 6.493 + config_file = 'ftesting.zcml' 6.494 + if not self.inplace: 6.495 + # We chdired into build, so ftesting.zcml is in the 6.496 + # parent directory 6.497 + config_file = os.path.join('..', 'ftesting.zcml') 6.498 + print "Parsing %s" % config_file 6.499 + from zope.app.tests.functional import FunctionalTestSetup 6.500 + FunctionalTestSetup(config_file) 6.501 + 6.502 +def match(rx, s): 6.503 + if not rx: 6.504 + return True 6.505 + if rx[0] == "!": 6.506 + return re.search(rx[1:], s) is None 6.507 + else: 6.508 + return re.search(rx, s) is not None 6.509 + 6.510 +class TestFileFinder: 6.511 + def __init__(self, prefix): 6.512 + self.files = [] 6.513 + self._plen = len(prefix) 6.514 + if not prefix.endswith(os.sep): 6.515 + self._plen += 1 6.516 + global functional 6.517 + if functional: 6.518 + self.dirname = "ftests" 6.519 + else: 6.520 + self.dirname = "tests" 6.521 + 6.522 + def visit(self, rx, dir, files): 6.523 + if os.path.split(dir)[1] != self.dirname: 6.524 + # Allow tests/ftests module rather than package. 6.525 + modfname = self.dirname + '.py' 6.526 + if modfname in files: 6.527 + path = os.path.join(dir, modfname) 6.528 + if match(rx, path): 6.529 + self.files.append(path) 6.530 + return 6.531 + return 6.532 + # ignore tests that aren't in packages 6.533 + if not "__init__.py" in files: 6.534 + if not files or files == ["CVS"]: 6.535 + return 6.536 + print "not a package", dir 6.537 + return 6.538 + 6.539 + # Put matching files in matches. If matches is non-empty, 6.540 + # then make sure that the package is importable. 6.541 + matches = [] 6.542 + for file in files: 6.543 + if file.startswith('test') and os.path.splitext(file)[-1] == '.py': 6.544 + path = os.path.join(dir, file) 6.545 + if match(rx, path): 6.546 + matches.append(path) 6.547 + 6.548 + # ignore tests when the package can't be imported, possibly due to 6.549 + # dependency failures. 6.550 + pkg = dir[self._plen:].replace(os.sep, '.') 6.551 + try: 6.552 + __import__(pkg) 6.553 + # We specifically do not want to catch ImportError since that's useful 6.554 + # information to know when running the tests. 6.555 + except RuntimeError, e: 6.556 + if VERBOSE: 6.557 + print "skipping %s because: %s" % (pkg, e) 6.558 + return 6.559 + else: 6.560 + self.files.extend(matches) 6.561 + 6.562 + def module_from_path(self, path): 6.563 + """Return the Python package name indicated by the filesystem path.""" 6.564 + assert path.endswith(".py") 6.565 + path = path[self._plen:-3] 6.566 + mod = path.replace(os.sep, ".") 6.567 + return mod 6.568 + 6.569 +def walk_with_symlinks(top, func, arg): 6.570 + """Like os.path.walk, but follows symlinks on POSIX systems. 6.571 + 6.572 + This could theoreticaly result in an infinite loop, if you create symlink 6.573 + cycles in your Zope sandbox, so don't do that. 6.574 + """ 6.575 + try: 6.576 + names = os.listdir(top) 6.577 + except os.error: 6.578 + return 6.579 + func(arg, top, names) 6.580 + exceptions = ('.', '..') 6.581 + for name in names: 6.582 + if name not in exceptions: 6.583 + name = os.path.join(top, name) 6.584 + if os.path.isdir(name): 6.585 + walk_with_symlinks(name, func, arg) 6.586 + 6.587 +def find_test_dir(dir): 6.588 + if os.path.exists(dir): 6.589 + return dir 6.590 + d = os.path.join(pathinit.libdir, dir) 6.591 + if os.path.exists(d): 6.592 + if os.path.isdir(d): 6.593 + return d 6.594 + raise ValueError("%s does not exist and %s is not a directory" 6.595 + % (dir, d)) 6.596 + raise ValueError("%s does not exist!" % dir) 6.597 + 6.598 +def find_tests(rx): 6.599 + global finder 6.600 + finder = TestFileFinder(pathinit.libdir) 6.601 + 6.602 + if TEST_DIRS: 6.603 + for d in TEST_DIRS: 6.604 + d = find_test_dir(d) 6.605 + walk_with_symlinks(d, finder.visit, rx) 6.606 + else: 6.607 + walk_with_symlinks(pathinit.libdir, finder.visit, rx) 6.608 + return finder.files 6.609 + 6.610 +def package_import(modname): 6.611 + mod = __import__(modname) 6.612 + for part in modname.split(".")[1:]: 6.613 + mod = getattr(mod, part) 6.614 + return mod 6.615 + 6.616 +class PseudoTestCase: 6.617 + """Minimal test case objects to create error reports. 6.618 + 6.619 + If test.py finds something that looks like it should be a test but 6.620 + can't load it or find its test suite, it will report an error 6.621 + using a PseudoTestCase. 6.622 + """ 6.623 + 6.624 + def __init__(self, name, descr=None): 6.625 + self.name = name 6.626 + self.descr = descr 6.627 + 6.628 + def shortDescription(self): 6.629 + return self.descr 6.630 + 6.631 + def __str__(self): 6.632 + return "Invalid Test (%s)" % self.name 6.633 + 6.634 +def get_suite(file, result): 6.635 + modname = finder.module_from_path(file) 6.636 + try: 6.637 + mod = package_import(modname) 6.638 + return mod.test_suite() 6.639 + except: 6.640 + result.addError(PseudoTestCase(modname), sys.exc_info()) 6.641 + return None 6.642 + 6.643 +def filter_testcases(s, rx): 6.644 + new = unittest.TestSuite() 6.645 + for test in s._tests: 6.646 + # See if the levels match 6.647 + dolevel = (LEVEL == 0) or LEVEL >= getattr(test, "level", 0) 6.648 + if not dolevel: 6.649 + continue 6.650 + if isinstance(test, unittest.TestCase): 6.651 + name = test.id() # Full test name: package.module.class.method 6.652 + name = name[1 + name.rfind("."):] # extract method name 6.653 + if not rx or match(rx, name): 6.654 + new.addTest(test) 6.655 + else: 6.656 + filtered = filter_testcases(test, rx) 6.657 + if filtered: 6.658 + new.addTest(filtered) 6.659 + return new 6.660 + 6.661 +def gui_runner(files, test_filter): 6.662 + if BUILD_INPLACE: 6.663 + utildir = os.path.join(os.getcwd(), "utilities") 6.664 + else: 6.665 + utildir = os.path.join(os.getcwd(), "..", "utilities") 6.666 + sys.path.append(utildir) 6.667 + import unittestgui 6.668 + suites = [] 6.669 + for file in files: 6.670 + suites.append(finder.module_from_path(file) + ".test_suite") 6.671 + 6.672 + suites = ", ".join(suites) 6.673 + minimal = (GUI == "minimal") 6.674 + unittestgui.main(suites, minimal) 6.675 + 6.676 +class TrackRefs: 6.677 + """Object to track reference counts across test runs.""" 6.678 + 6.679 + def __init__(self): 6.680 + self.type2count = {} 6.681 + self.type2all = {} 6.682 + 6.683 + def update(self): 6.684 + obs = sys.getobjects(0) 6.685 + type2count = {} 6.686 + type2all = {} 6.687 + for o in obs: 6.688 + all = sys.getrefcount(o) 6.689 + 6.690 + if type(o) is str and o == '<dummy key>': 6.691 + # avoid dictionary madness 6.692 + continue 6.693 + t = type(o) 6.694 + if t in type2count: 6.695 + type2count[t] += 1 6.696 + type2all[t] += all 6.697 + else: 6.698 + type2count[t] = 1 6.699 + type2all[t] = all 6.700 + 6.701 + ct = [(type2count[t] - self.type2count.get(t, 0), 6.702 + type2all[t] - self.type2all.get(t, 0), 6.703 + t) 6.704 + for t in type2count.iterkeys()] 6.705 + ct.sort() 6.706 + ct.reverse() 6.707 + printed = False 6.708 + for delta1, delta2, t in ct: 6.709 + if delta1 or delta2: 6.710 + if not printed: 6.711 + print "%-55s %8s %8s" % ('', 'insts', 'refs') 6.712 + printed = True 6.713 + print "%-55s %8d %8d" % (t, delta1, delta2) 6.714 + 6.715 + self.type2count = type2count 6.716 + self.type2all = type2all 6.717 + 6.718 +def runner(files, test_filter, debug): 6.719 + runner = ImmediateTestRunner(verbosity=VERBOSE, debug=DEBUG, 6.720 + progress=PROGRESS, profile=PROFILE, 6.721 + descriptions=False) 6.722 + suite = unittest.TestSuite() 6.723 + for file in files: 6.724 + s = get_suite(file, runner.result) 6.725 + # See if the levels match 6.726 + dolevel = (LEVEL == 0) or LEVEL >= getattr(s, "level", 0) 6.727 + if s is not None and dolevel: 6.728 + s = filter_testcases(s, test_filter) 6.729 + suite.addTest(s) 6.730 + try: 6.731 + r = runner.run(suite) 6.732 + if TIMESFN: 6.733 + r.print_times(open(TIMESFN, "w")) 6.734 + if VERBOSE: 6.735 + print "Wrote timing data to", TIMESFN 6.736 + if TIMETESTS: 6.737 + r.print_times(sys.stdout, TIMETESTS) 6.738 + except: 6.739 + if DEBUGGER: 6.740 + print "%s:" % (sys.exc_info()[0], ) 6.741 + print sys.exc_info()[1] 6.742 + pdb.post_mortem(sys.exc_info()[2]) 6.743 + else: 6.744 + raise 6.745 + 6.746 +def remove_stale_bytecode(arg, dirname, names): 6.747 + names = map(os.path.normcase, names) 6.748 + for name in names: 6.749 + if name.endswith(".pyc") or name.endswith(".pyo"): 6.750 + srcname = name[:-1] 6.751 + if srcname not in names: 6.752 + fullname = os.path.join(dirname, name) 6.753 + print "Removing stale bytecode file", fullname 6.754 + os.unlink(fullname) 6.755 + 6.756 +def main(module_filter, test_filter, libdir): 6.757 + if not KEEP_STALE_BYTECODE: 6.758 + os.path.walk(os.curdir, remove_stale_bytecode, None) 6.759 + 6.760 + configure_logging() 6.761 + 6.762 + # Initialize the path and cwd 6.763 + global pathinit 6.764 + pathinit = PathInit(BUILD, BUILD_INPLACE, libdir) 6.765 + 6.766 + files = find_tests(module_filter) 6.767 + files.sort() 6.768 + 6.769 + if GUI: 6.770 + gui_runner(files, test_filter) 6.771 + elif LOOP: 6.772 + if REFCOUNT: 6.773 + rc = sys.gettotalrefcount() 6.774 + track = TrackRefs() 6.775 + while True: 6.776 + runner(files, test_filter, DEBUG) 6.777 + gc.collect() 6.778 + if gc.garbage: 6.779 + print "GARBAGE:", len(gc.garbage), gc.garbage 6.780 + return 6.781 + if REFCOUNT: 6.782 + prev = rc 6.783 + rc = sys.gettotalrefcount() 6.784 + print "totalrefcount=%-8d change=%-6d" % (rc, rc - prev) 6.785 + track.update() 6.786 + else: 6.787 + runner(files, test_filter, DEBUG) 6.788 + 6.789 + os.chdir(pathinit.org_cwd) 6.790 + 6.791 + 6.792 +def configure_logging(): 6.793 + """Initialize the logging module.""" 6.794 + import logging.config 6.795 + 6.796 + # Get the log.ini file from the current directory instead of possibly 6.797 + # buried in the build directory. XXX This isn't perfect because if 6.798 + # log.ini specifies a log file, it'll be relative to the build directory. 6.799 + # Hmm... 6.800 + logini = os.path.abspath("log.ini") 6.801 + 6.802 + if os.path.exists(logini): 6.803 + logging.config.fileConfig(logini) 6.804 + else: 6.805 + logging.basicConfig() 6.806 + 6.807 + if os.environ.has_key("LOGGING"): 6.808 + level = int(os.environ["LOGGING"]) 6.809 + logging.getLogger().setLevel(level) 6.810 + 6.811 + 6.812 +def process_args(argv=None): 6.813 + import getopt 6.814 + global MODULE_FILTER 6.815 + global TEST_FILTER 6.816 + global VERBOSE 6.817 + global LOOP 6.818 + global GUI 6.819 + global TRACE 6.820 + global REFCOUNT 6.821 + global DEBUG 6.822 + global DEBUGGER 6.823 + global BUILD 6.824 + global LEVEL 6.825 + global LIBDIR 6.826 + global TIMESFN 6.827 + global TIMETESTS 6.828 + global PROGRESS 6.829 + global BUILD_INPLACE 6.830 + global KEEP_STALE_BYTECODE 6.831 + global TEST_DIRS 6.832 + global PROFILE 6.833 + global GC_THRESHOLD 6.834 + global GC_FLAGS 6.835 + global RUN_UNIT 6.836 + global RUN_FUNCTIONAL 6.837 + global PYCHECKER 6.838 + 6.839 + if argv is None: 6.840 + argv = sys.argv 6.841 + 6.842 + MODULE_FILTER = None 6.843 + TEST_FILTER = None 6.844 + VERBOSE = 0 6.845 + LOOP = False 6.846 + GUI = False 6.847 + TRACE = False 6.848 + REFCOUNT = False 6.849 + DEBUG = False # Don't collect test results; simply let tests crash 6.850 + DEBUGGER = False 6.851 + BUILD = False 6.852 + BUILD_INPLACE = False 6.853 + GC_THRESHOLD = None 6.854 + gcdebug = 0 6.855 + GC_FLAGS = [] 6.856 + LEVEL = 1 6.857 + LIBDIR = None 6.858 + PROGRESS = False 6.859 + TIMESFN = None 6.860 + TIMETESTS = 0 6.861 + KEEP_STALE_BYTECODE = 0 6.862 + RUN_UNIT = True 6.863 + RUN_FUNCTIONAL = True 6.864 + TEST_DIRS = [] 6.865 + PROFILE = False 6.866 + PYCHECKER = False 6.867 + config_filename = 'test.config' 6.868 + 6.869 + # import the config file 6.870 + if os.path.isfile(config_filename): 6.871 + print 'Configuration file found.' 6.872 + execfile(config_filename, globals()) 6.873 + 6.874 + 6.875 + try: 6.876 + opts, args = getopt.getopt(argv[1:], "a:bBcdDfFg:G:hkl:LmMPprs:tTuUv", 6.877 + ["all", "help", "libdir=", "times=", 6.878 + "keepbytecode", "dir=", "build", 6.879 + "build-inplace", 6.880 + "at-level=", 6.881 + "pychecker", "debug", "pdebug", 6.882 + "gc-threshold=", "gc-option=", 6.883 + "loop", "gui", "minimal-gui", 6.884 + "profile", "progress", "refcount", "trace", 6.885 + "top-fifty", "verbose", 6.886 + ]) 6.887 + # fixme: add the long names 6.888 + # fixme: add the extra documentation 6.889 + # fixme: test for functional first! 6.890 + except getopt.error, msg: 6.891 + print msg 6.892 + print "Try `python %s -h' for more information." % argv[0] 6.893 + sys.exit(2) 6.894 + 6.895 + for k, v in opts: 6.896 + if k in ("-a", "--at-level"): 6.897 + LEVEL = int(v) 6.898 + elif k == "--all": 6.899 + LEVEL = 0 6.900 + os.environ["COMPLAIN_IF_TESTS_MISSED"]='1' 6.901 + elif k in ("-b", "--build"): 6.902 + BUILD = True 6.903 + elif k in ("-B", "--build-inplace"): 6.904 + BUILD = BUILD_INPLACE = True 6.905 + elif k in("-c", "--pychecker"): 6.906 + PYCHECKER = True 6.907 + elif k in ("-d", "--debug"): 6.908 + DEBUG = True 6.909 + elif k in ("-D", "--pdebug"): 6.910 + DEBUG = True 6.911 + DEBUGGER = True 6.912 + elif k in ("-f", "--skip-unit"): 6.913 + RUN_UNIT = False 6.914 + elif k in ("-u", "--skip-functional"): 6.915 + RUN_FUNCTIONAL = False 6.916 + elif k == "-F": 6.917 + message = 'Unit plus functional is the default behaviour.' 6.918 + warnings.warn(message, DeprecationWarning) 6.919 + RUN_UNIT = True 6.920 + RUN_FUNCTIONAL = True 6.921 + elif k in ("-h", "--help"): 6.922 + print __doc__ 6.923 + sys.exit(0) 6.924 + elif k in ("-g", "--gc-threshold"): 6.925 + GC_THRESHOLD = int(v) 6.926 + elif k in ("-G", "--gc-option"): 6.927 + if not v.startswith("DEBUG_"): 6.928 + print "-G argument must be DEBUG_ flag, not", repr(v) 6.929 + sys.exit(1) 6.930 + GC_FLAGS.append(v) 6.931 + elif k in ('-k', '--keepbytecode'): 6.932 + KEEP_STALE_BYTECODE = 1 6.933 + elif k in ('-l', '--libdir'): 6.934 + LIBDIR = v 6.935 + elif k in ("-L", "--loop"): 6.936 + LOOP = 1 6.937 + elif k == "-m": 6.938 + GUI = "minimal" 6.939 + msg = "Use -M or --minimal-gui instead of -m." 6.940 + warnings.warn(msg, DeprecationWarning) 6.941 + elif k in ("-M", "--minimal-gui"): 6.942 + GUI = "minimal" 6.943 + elif k in ("-P", "--profile"): 6.944 + PROFILE = True 6.945 + elif k in ("-p", "--progress"): 6.946 + PROGRESS = True 6.947 + elif k in ("-r", "--refcount"): 6.948 + REFCOUNT = True 6.949 + elif k in ("-T", "--trace"): 6.950 + TRACE = True 6.951 + elif k in ("-t", "--top-fifty"): 6.952 + if not TIMETESTS: 6.953 + TIMETESTS = 50 6.954 + elif k in ("-u", "--gui"): 6.955 + GUI = 1 6.956 + elif k in ("-v", "--verbose"): 6.957 + VERBOSE += 1 6.958 + elif k == "--times": 6.959 + try: 6.960 + TIMETESTS = int(v) 6.961 + except ValueError: 6.962 + # must be a filename to write 6.963 + TIMESFN = v 6.964 + elif k in ('-s', '--dir'): 6.965 + TEST_DIRS.append(v) 6.966 + 6.967 + if PYCHECKER: 6.968 + # make sure you have a recent version of pychecker 6.969 + if not os.environ.get("PYCHECKER"): 6.970 + os.environ["PYCHECKER"] = "-q" 6.971 + import pychecker.checker 6.972 + 6.973 + if REFCOUNT and not hasattr(sys, "gettotalrefcount"): 6.974 + print "-r ignored, because it needs a debug build of Python" 6.975 + REFCOUNT = False 6.976 + 6.977 + if sys.version_info < ( 2,3,2 ): 6.978 + print """\ 6.979 + ERROR: Your python version is not supported by Zope3. 6.980 + Zope3 needs Python 2.3.2 or greater. You are running:""" + sys.version 6.981 + sys.exit(1) 6.982 + 6.983 + if GC_THRESHOLD is not None: 6.984 + if GC_THRESHOLD == 0: 6.985 + gc.disable() 6.986 + print "gc disabled" 6.987 + else: 6.988 + gc.set_threshold(GC_THRESHOLD) 6.989 + print "gc threshold:", gc.get_threshold() 6.990 + 6.991 + if GC_FLAGS: 6.992 + val = 0 6.993 + for flag in GC_FLAGS: 6.994 + v = getattr(gc, flag, None) 6.995 + if v is None: 6.996 + print "Unknown gc flag", repr(flag) 6.997 + print gc.set_debug.__doc__ 6.998 + sys.exit(1) 6.999 + val |= v 6.1000 + gcdebug |= v 6.1001 + 6.1002 + if gcdebug: 6.1003 + gc.set_debug(gcdebug) 6.1004 + 6.1005 + if BUILD: 6.1006 + # Python 2.3 is more sane in its non -q output 6.1007 + if sys.hexversion >= 0x02030000: 6.1008 + qflag = "" 6.1009 + else: 6.1010 + qflag = "-q" 6.1011 + cmd = sys.executable + " setup.py " + qflag + " build" 6.1012 + if BUILD_INPLACE: 6.1013 + cmd += "_ext -i" 6.1014 + if VERBOSE: 6.1015 + print cmd 6.1016 + sts = os.system(cmd) 6.1017 + if sts: 6.1018 + print "Build failed", hex(sts) 6.1019 + sys.exit(1) 6.1020 + 6.1021 + k = [] 6.1022 + if RUN_UNIT: 6.1023 + k.append(False) 6.1024 + if RUN_FUNCTIONAL: 6.1025 + k.append(True) 6.1026 + 6.1027 + global functional 6.1028 + for functional in k: 6.1029 + 6.1030 + if VERBOSE: 6.1031 + kind = functional and "FUNCTIONAL" or "UNIT" 6.1032 + if LEVEL == 0: 6.1033 + print "Running %s tests at all levels" % kind 6.1034 + else: 6.1035 + print "Running %s tests at level %d" % (kind, LEVEL) 6.1036 + 6.1037 +# This was to avoid functional tests outside of z3, but this doesn't really 6.1038 +# work right. 6.1039 +## if functional: 6.1040 +## try: 6.1041 +## from zope.app.tests.functional import FunctionalTestSetup 6.1042 +## except ImportError: 6.1043 +## raise 6.1044 +## print ('Skipping functional tests: could not import ' 6.1045 +## 'zope.app.tests.functional') 6.1046 +## continue 6.1047 + 6.1048 + # XXX We want to change *visible* warnings into errors. The next 6.1049 + # line changes all warnings into errors, including warnings we 6.1050 + # normally never see. In particular, test_datetime does some 6.1051 + # short-integer arithmetic that overflows to long ints, and, by 6.1052 + # default, Python doesn't display the overflow warning that can 6.1053 + # be enabled when this happens. The next line turns that into an 6.1054 + # error instead. Guido suggests that a better to get what we're 6.1055 + # after is to replace warnings.showwarning() with our own thing 6.1056 + # that raises an error. 6.1057 + ## warnings.filterwarnings("error") 6.1058 + warnings.filterwarnings("ignore", module="logging") 6.1059 + 6.1060 + if args: 6.1061 + if len(args) > 1: 6.1062 + TEST_FILTER = args[1] 6.1063 + MODULE_FILTER = args[0] 6.1064 + try: 6.1065 + if TRACE: 6.1066 + # if the trace module is used, then we don't exit with 6.1067 + # status if on a false return value from main. 6.1068 + coverdir = os.path.join(os.getcwd(), "coverage") 6.1069 + import trace 6.1070 + ignoremods = ["os", "posixpath", "stat"] 6.1071 + tracer = trace.Trace(ignoredirs=[sys.prefix, sys.exec_prefix], 6.1072 + ignoremods=ignoremods, 6.1073 + trace=False, count=True) 6.1074 + 6.1075 + tracer.runctx("main(MODULE_FILTER, TEST_FILTER, LIBDIR)", 6.1076 + globals=globals(), locals=vars()) 6.1077 + r = tracer.results() 6.1078 + path = "/tmp/trace.%s" % os.getpid() 6.1079 + import cPickle 6.1080 + f = open(path, "wb") 6.1081 + cPickle.dump(r, f) 6.1082 + f.close() 6.1083 + print path 6.1084 + r.write_results(show_missing=True, 6.1085 + summary=True, coverdir=coverdir) 6.1086 + else: 6.1087 + bad = main(MODULE_FILTER, TEST_FILTER, LIBDIR) 6.1088 + if bad: 6.1089 + sys.exit(1) 6.1090 + except ImportError, err: 6.1091 + print err 6.1092 + print sys.path 6.1093 + raise 6.1094 + 6.1095 + 6.1096 +if __name__ == "__main__": 6.1097 + process_args()
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/tools/python/xen/xend/tests/test_sxp.py Thu Oct 06 15:12:31 2005 +0100 8.3 @@ -0,0 +1,18 @@ 8.4 +import unittest 8.5 + 8.6 +import xen.xend.sxp 8.7 + 8.8 + 8.9 +class test_sxp(unittest.TestCase): 8.10 + 8.11 + def testAllFromString(self): 8.12 + def t(input, expected): 8.13 + self.assertEqual(xen.xend.sxp.all_from_string(input), expected) 8.14 + 8.15 + t('String', ['String']) 8.16 + t('(String Thing)', [['String', 'Thing']]) 8.17 + t('(String) (Thing)', [['String'], ['Thing']]) 8.18 + 8.19 + 8.20 +def test_suite(): 8.21 + return unittest.makeSuite(test_sxp)