35
40
from logging import debug, warning, error
44
class EarlyStoppingTestResultAdapter(object):
45
"""An adapter for TestResult to stop at the first first failure or error"""
47
def __init__(self, result):
50
def addError(self, test, err):
51
self._result.addError(test, err)
54
def addFailure(self, test, err):
55
self._result.addFailure(test, err)
58
def __getattr__(self, name):
59
return getattr(self._result, name)
61
def __setattr__(self, name, value):
63
object.__setattr__(self, name, value)
64
return setattr(self._result, name, value)
67
class _MyResult(unittest._TextTestResult):
71
No special behaviour for now.
74
def _elapsedTime(self):
75
return "(Took %.3fs)" % (time.time() - self._start_time)
77
def startTest(self, test):
78
unittest.TestResult.startTest(self, test)
79
# TODO: Maybe show test.shortDescription somewhere?
80
what = test.shortDescription() or test.id()
82
self.stream.write('%-70.70s' % what)
84
self._start_time = time.time()
86
def addError(self, test, err):
87
unittest.TestResult.addError(self, test, err)
89
self.stream.writeln("ERROR %s" % self._elapsedTime())
91
self.stream.write('E')
94
def addFailure(self, test, err):
95
unittest.TestResult.addFailure(self, test, err)
97
self.stream.writeln("FAIL %s" % self._elapsedTime())
99
self.stream.write('F')
102
def addSuccess(self, test):
104
self.stream.writeln('OK %s' % self._elapsedTime())
106
self.stream.write('~')
108
unittest.TestResult.addSuccess(self, test)
110
def printErrorList(self, flavour, errors):
111
for test, err in errors:
112
self.stream.writeln(self.separator1)
113
self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
114
if hasattr(test, '_get_log'):
115
self.stream.writeln()
116
self.stream.writeln('log from this test:')
117
print >>self.stream, test._get_log()
118
self.stream.writeln(self.separator2)
119
self.stream.writeln("%s" % err)
122
class TextTestRunner(unittest.TextTestRunner):
124
def _makeResult(self):
125
result = _MyResult(self.stream, self.descriptions, self.verbosity)
126
return EarlyStoppingTestResultAdapter(result)
129
def iter_suite_tests(suite):
130
"""Return all tests in a suite, recursing through nested suites"""
131
for item in suite._tests:
132
if isinstance(item, unittest.TestCase):
134
elif isinstance(item, unittest.TestSuite):
135
for r in iter_suite_tests(item):
138
raise Exception('unknown object %r inside test suite %r'
142
class TestSkipped(Exception):
143
"""Indicates that a test was intentionally skipped, rather than failing."""
37
147
class CommandFailed(Exception):
90
197
"""Return as a string the log for this test"""
91
198
return open(self._log_file_name).read()
201
def capture(self, cmd):
202
"""Shortcut that splits cmd into words, runs, and returns stdout"""
203
return self.run_bzr_captured(cmd.split())[0]
205
def run_bzr_captured(self, argv, retcode=0):
206
"""Invoke bzr and return (result, stdout, stderr).
208
Useful for code that wants to check the contents of the
209
output, the way error messages are presented, etc.
211
This should be the main method for tests that want to exercise the
212
overall behavior of the bzr application (rather than a unit test
213
or a functional test of the library.)
215
Much of the old code runs bzr by forking a new copy of Python, but
216
that is slower, harder to debug, and generally not necessary.
218
This runs bzr through the interface that catches and reports
219
errors, and with logging set to something approximating the
220
default, so that error reporting can be checked.
222
argv -- arguments to invoke bzr
223
retcode -- expected return code, or None for don't-care.
227
self.log('run bzr: %s', ' '.join(argv))
228
handler = logging.StreamHandler(stderr)
229
handler.setFormatter(bzrlib.trace.QuietFormatter())
230
handler.setLevel(logging.INFO)
231
logger = logging.getLogger('')
232
logger.addHandler(handler)
234
result = self.apply_redirected(None, stdout, stderr,
235
bzrlib.commands.run_bzr_catch_errors,
238
logger.removeHandler(handler)
239
out = stdout.getvalue()
240
err = stderr.getvalue()
242
self.log('output:\n%s', out)
244
self.log('errors:\n%s', err)
245
if retcode is not None:
246
self.assertEquals(result, retcode)
93
249
def run_bzr(self, *args, **kwargs):
94
250
"""Invoke bzr, as if it were run from the command line.
97
253
overall behavior of the bzr application (rather than a unit test
98
254
or a functional test of the library.)
100
Much of the old code runs bzr by forking a new copy of Python, but
101
that is slower, harder to debug, and generally not necessary.
256
This sends the stdout/stderr results into the test's log,
257
where it may be useful for debugging. See also run_captured.
103
retcode = kwargs.get('retcode', 0)
104
result = self.apply_redirected(None, None, None,
105
bzrlib.commands.run_bzr, args)
106
self.assertEquals(result, retcode)
259
retcode = kwargs.pop('retcode', 0)
260
return self.run_bzr_captured(args, retcode)
109
262
def check_inventory_shape(self, inv, shape):
111
Compare an inventory to a list of expected names.
263
"""Compare an inventory to a list of expected names.
113
265
Fail if they are not precisely equal.
181
338
if contents != expect:
182
339
self.log("expected: %r" % expect)
183
340
self.log("actually: %r" % contents)
184
self.fail("contents of %s not as expected")
341
self.fail("contents of %s not as expected" % filename)
186
343
def _make_test_root(self):
191
344
if TestCaseInTempDir.TEST_ROOT is not None:
193
TestCaseInTempDir.TEST_ROOT = os.path.abspath(
194
tempfile.mkdtemp(suffix='.tmp',
195
prefix=self._TEST_NAME + '-',
348
root = 'test%04d.tmp' % i
352
if e.errno == errno.EEXIST:
357
# successfully created
358
TestCaseInTempDir.TEST_ROOT = os.path.abspath(root)
198
360
# make a fake bzr directory there to prevent any tests propagating
199
361
# up onto the source directory's real branch
200
362
os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
203
365
super(TestCaseInTempDir, self).setUp()
205
366
self._make_test_root()
206
367
self._currentdir = os.getcwdu()
207
short_id = self.id().replace('bzrlib.selftest.', '')
368
short_id = self.id().replace('bzrlib.selftest.', '') \
369
.replace('__main__.', '')
208
370
self.test_dir = os.path.join(self.TEST_ROOT, short_id)
209
371
os.mkdir(self.test_dir)
210
372
os.chdir(self.test_dir)
212
374
def tearDown(self):
214
375
os.chdir(self._currentdir)
215
376
super(TestCaseInTempDir, self).tearDown()
217
def _formcmd(self, cmd):
218
if isinstance(cmd, basestring):
221
cmd[0] = self.BZRPATH
222
if self.OVERRIDE_PYTHON:
223
cmd.insert(0, self.OVERRIDE_PYTHON)
224
self.log('$ %r' % cmd)
227
def runcmd(self, cmd, retcode=0):
228
"""Run one command and check the return code.
230
Returns a tuple of (stdout,stderr) strings.
232
If a single string is based, it is split into words.
233
For commands that are not simple space-separated words, please
234
pass a list instead."""
235
cmd = self._formcmd(cmd)
236
self.log('$ ' + ' '.join(cmd))
237
actual_retcode = subprocess.call(cmd, stdout=self._log_file,
238
stderr=self._log_file)
239
if retcode != actual_retcode:
240
raise CommandFailed("test failed: %r returned %d, expected %d"
241
% (cmd, actual_retcode, retcode))
243
def backtick(self, cmd, retcode=0):
244
"""Run a command and return its output"""
245
cmd = self._formcmd(cmd)
246
child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=self._log_file)
247
outd, errd = child.communicate()
249
actual_retcode = child.wait()
251
outd = outd.replace('\r', '')
253
if retcode != actual_retcode:
254
raise CommandFailed("test failed: %r returned %d, expected %d"
255
% (cmd, actual_retcode, retcode))
261
378
def build_tree(self, shape):
262
379
"""Build a test tree according to a pattern.
410
def filter_suite_by_re(suite, pattern):
411
result = TestUtil.TestSuite()
412
filter_re = re.compile(pattern)
413
for test in iter_suite_tests(suite):
414
if filter_re.search(test.id()):
419
def run_suite(suite, name='test', verbose=False, pattern=".*"):
420
TestCaseInTempDir._TEST_NAME = name
425
runner = TextTestRunner(stream=sys.stdout,
429
suite = filter_suite_by_re(suite, pattern)
430
result = runner.run(suite)
431
# This is still a little bogus,
432
# but only a little. Folk not using our testrunner will
433
# have to delete their temp directories themselves.
434
if result.wasSuccessful():
435
if TestCaseInTempDir.TEST_ROOT is not None:
436
shutil.rmtree(TestCaseInTempDir.TEST_ROOT)
438
print "Failed tests working directories are in '%s'\n" % TestCaseInTempDir.TEST_ROOT
439
return result.wasSuccessful()
291
442
def selftest(verbose=False, pattern=".*"):
292
443
"""Run the whole test suite under the enhanced runner"""
293
444
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
296
447
def test_suite():
297
448
"""Build and return TestSuite for the whole program."""
298
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
299
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
300
import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
449
import bzrlib.store, bzrlib.inventory, bzrlib.branch
450
import bzrlib.osutils, bzrlib.merge3, bzrlib.plugin
301
451
from doctest import DocTestSuite
307
453
global MODULES_TO_TEST, MODULES_TO_DOCTEST
309
455
testmod_names = \
310
456
['bzrlib.selftest.MetaTestLog',
457
'bzrlib.selftest.testidentitymap',
311
458
'bzrlib.selftest.testinv',
459
'bzrlib.selftest.test_ancestry',
460
'bzrlib.selftest.test_commit',
461
'bzrlib.selftest.test_commit_merge',
462
'bzrlib.selftest.testconfig',
312
463
'bzrlib.selftest.versioning',
313
464
'bzrlib.selftest.testmerge3',
465
'bzrlib.selftest.testmerge',
314
466
'bzrlib.selftest.testhashcache',
315
467
'bzrlib.selftest.teststatus',
316
468
'bzrlib.selftest.testlog',
317
469
'bzrlib.selftest.testrevisionnamespaces',
318
470
'bzrlib.selftest.testbranch',
319
471
'bzrlib.selftest.testrevision',
472
'bzrlib.selftest.test_revision_info',
320
473
'bzrlib.selftest.test_merge_core',
321
474
'bzrlib.selftest.test_smart_add',
475
'bzrlib.selftest.test_bad_files',
322
476
'bzrlib.selftest.testdiff',
323
477
'bzrlib.selftest.test_parent',
324
478
'bzrlib.selftest.test_xml',
479
'bzrlib.selftest.test_weave',
325
480
'bzrlib.selftest.testfetch',
326
481
'bzrlib.selftest.whitebox',
327
482
'bzrlib.selftest.teststore',
328
483
'bzrlib.selftest.blackbox',
484
'bzrlib.selftest.testsampler',
485
'bzrlib.selftest.testtransactions',
486
'bzrlib.selftest.testtransport',
487
'bzrlib.selftest.testgraph',
488
'bzrlib.selftest.testworkingtree',
489
'bzrlib.selftest.test_upgrade',
490
'bzrlib.selftest.test_conflicts',
331
493
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,