35
38
from logging import debug, warning, error
42
class EarlyStoppingTestResultAdapter(object):
43
"""An adapter for TestResult to stop at the first first failure or error"""
45
def __init__(self, result):
48
def addError(self, test, err):
49
self._result.addError(test, err)
52
def addFailure(self, test, err):
53
self._result.addFailure(test, err)
56
def __getattr__(self, name):
57
return getattr(self._result, name)
59
def __setattr__(self, name, value):
61
object.__setattr__(self, name, value)
62
return setattr(self._result, name, value)
65
class _MyResult(unittest._TextTestResult):
69
No special behaviour for now.
72
def startTest(self, test):
73
unittest.TestResult.startTest(self, test)
74
# TODO: Maybe show test.shortDescription somewhere?
75
what = test.shortDescription() or test.id()
77
self.stream.write('%-70.70s' % what)
80
def addError(self, test, err):
81
super(_MyResult, self).addError(test, err)
84
def addFailure(self, test, err):
85
super(_MyResult, self).addFailure(test, err)
88
def addSuccess(self, test):
90
self.stream.writeln('OK')
92
self.stream.write('~')
94
unittest.TestResult.addSuccess(self, test)
96
def printErrorList(self, flavour, errors):
97
for test, err in errors:
98
self.stream.writeln(self.separator1)
99
self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
100
if hasattr(test, '_get_log'):
101
self.stream.writeln()
102
self.stream.writeln('log from this test:')
103
print >>self.stream, test._get_log()
104
self.stream.writeln(self.separator2)
105
self.stream.writeln("%s" % err)
108
class TextTestRunner(unittest.TextTestRunner):
110
def _makeResult(self):
111
result = _MyResult(self.stream, self.descriptions, self.verbosity)
112
return EarlyStoppingTestResultAdapter(result)
115
class filteringVisitor(TestUtil.TestVisitor):
116
"""I accruse all the testCases I visit that pass a regexp filter on id
120
def __init__(self, filter):
122
TestUtil.TestVisitor.__init__(self)
124
self.filter=re.compile(filter)
127
"""answer the suite we are building"""
128
if self._suite is None:
129
self._suite=TestUtil.TestSuite()
132
def visitCase(self, aCase):
133
if self.filter.match(aCase.id()):
134
self.suite().addTest(aCase)
136
class TestSkipped(Exception):
137
"""Indicates that a test was intentionally skipped, rather than failing."""
37
141
class CommandFailed(Exception):
90
191
"""Return as a string the log for this test"""
91
192
return open(self._log_file_name).read()
195
def capture(self, cmd):
196
"""Shortcut that splits cmd into words, runs, and returns stdout"""
197
return self.run_bzr_captured(cmd.split())[0]
199
def run_bzr_captured(self, argv, retcode=0):
200
"""Invoke bzr and return (result, stdout, stderr).
202
Useful for code that wants to check the contents of the
203
output, the way error messages are presented, etc.
205
This should be the main method for tests that want to exercise the
206
overall behavior of the bzr application (rather than a unit test
207
or a functional test of the library.)
209
Much of the old code runs bzr by forking a new copy of Python, but
210
that is slower, harder to debug, and generally not necessary.
212
This runs bzr through the interface that catches and reports
213
errors, and with logging set to something approximating the
214
default, so that error reporting can be checked.
216
argv -- arguments to invoke bzr
217
retcode -- expected return code, or None for don't-care.
221
self.log('run bzr: %s', ' '.join(argv))
222
handler = logging.StreamHandler(stderr)
223
handler.setFormatter(bzrlib.trace.QuietFormatter())
224
handler.setLevel(logging.INFO)
225
logger = logging.getLogger('')
226
logger.addHandler(handler)
228
result = self.apply_redirected(None, stdout, stderr,
229
bzrlib.commands.run_bzr_catch_errors,
232
logger.removeHandler(handler)
233
out = stdout.getvalue()
234
err = stderr.getvalue()
236
self.log('output:\n%s', out)
238
self.log('errors:\n%s', err)
239
if retcode is not None:
240
self.assertEquals(result, retcode)
93
243
def run_bzr(self, *args, **kwargs):
94
244
"""Invoke bzr, as if it were run from the command line.
97
247
overall behavior of the bzr application (rather than a unit test
98
248
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.
250
This sends the stdout/stderr results into the test's log,
251
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)
253
retcode = kwargs.pop('retcode', 0)
254
return self.run_bzr_captured(args, retcode)
109
256
def check_inventory_shape(self, inv, shape):
111
Compare an inventory to a list of expected names.
257
"""Compare an inventory to a list of expected names.
113
259
Fail if they are not precisely equal.
181
332
if contents != expect:
182
333
self.log("expected: %r" % expect)
183
334
self.log("actually: %r" % contents)
184
self.fail("contents of %s not as expected")
335
self.fail("contents of %s not as expected" % filename)
186
337
def _make_test_root(self):
191
338
if TestCaseInTempDir.TEST_ROOT is not None:
193
TestCaseInTempDir.TEST_ROOT = os.path.abspath(
194
tempfile.mkdtemp(suffix='.tmp',
195
prefix=self._TEST_NAME + '-',
342
root = 'test%04d.tmp' % i
346
if e.errno == errno.EEXIST:
351
# successfully created
352
TestCaseInTempDir.TEST_ROOT = os.path.abspath(root)
198
354
# make a fake bzr directory there to prevent any tests propagating
199
355
# up onto the source directory's real branch
200
356
os.mkdir(os.path.join(TestCaseInTempDir.TEST_ROOT, '.bzr'))
203
359
super(TestCaseInTempDir, self).setUp()
205
360
self._make_test_root()
206
361
self._currentdir = os.getcwdu()
207
self.test_dir = os.path.join(self.TEST_ROOT, self.id())
362
short_id = self.id().replace('bzrlib.selftest.', '') \
363
.replace('__main__.', '')
364
self.test_dir = os.path.join(self.TEST_ROOT, short_id)
208
365
os.mkdir(self.test_dir)
209
366
os.chdir(self.test_dir)
211
368
def tearDown(self):
213
369
os.chdir(self._currentdir)
214
370
super(TestCaseInTempDir, self).tearDown()
216
def _formcmd(self, cmd):
217
if isinstance(cmd, basestring):
220
cmd[0] = self.BZRPATH
221
if self.OVERRIDE_PYTHON:
222
cmd.insert(0, self.OVERRIDE_PYTHON)
223
self.log('$ %r' % cmd)
226
def runcmd(self, cmd, retcode=0):
227
"""Run one command and check the return code.
229
Returns a tuple of (stdout,stderr) strings.
231
If a single string is based, it is split into words.
232
For commands that are not simple space-separated words, please
233
pass a list instead."""
234
cmd = self._formcmd(cmd)
235
self.log('$ ' + ' '.join(cmd))
236
actual_retcode = subprocess.call(cmd, stdout=self._log_file,
237
stderr=self._log_file)
238
if retcode != actual_retcode:
239
raise CommandFailed("test failed: %r returned %d, expected %d"
240
% (cmd, actual_retcode, retcode))
242
def backtick(self, cmd, retcode=0):
243
"""Run a command and return its output"""
244
cmd = self._formcmd(cmd)
245
child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=self._log_file)
246
outd, errd = child.communicate()
248
actual_retcode = child.wait()
250
outd = outd.replace('\r', '')
252
if retcode != actual_retcode:
253
raise CommandFailed("test failed: %r returned %d, expected %d"
254
% (cmd, actual_retcode, retcode))
260
372
def build_tree(self, shape):
261
373
"""Build a test tree according to a pattern.
401
def run_suite(suite, name='test', verbose=False, pattern=".*"):
402
TestCaseInTempDir._TEST_NAME = name
407
runner = TextTestRunner(stream=sys.stdout,
410
visitor = filteringVisitor(pattern)
412
result = runner.run(visitor.suite())
413
# This is still a little bogus,
414
# but only a little. Folk not using our testrunner will
415
# have to delete their temp directories themselves.
416
if result.wasSuccessful():
417
if TestCaseInTempDir.TEST_ROOT is not None:
418
shutil.rmtree(TestCaseInTempDir.TEST_ROOT)
420
print "Failed tests working directories are in '%s'\n" % TestCaseInTempDir.TEST_ROOT
421
return result.wasSuccessful()
290
424
def selftest(verbose=False, pattern=".*"):
425
"""Run the whole test suite under the enhanced runner"""
291
426
return run_suite(test_suite(), 'testbzr', verbose=verbose, pattern=pattern)
294
429
def test_suite():
295
from bzrlib.selftest.TestUtil import TestLoader, TestSuite
296
import bzrlib, bzrlib.store, bzrlib.inventory, bzrlib.branch
297
import bzrlib.osutils, bzrlib.commands, bzrlib.merge3, bzrlib.plugin
430
"""Build and return TestSuite for the whole program."""
431
import bzrlib.store, bzrlib.inventory, bzrlib.branch
432
import bzrlib.osutils, bzrlib.merge3, bzrlib.plugin
298
433
from doctest import DocTestSuite
304
435
global MODULES_TO_TEST, MODULES_TO_DOCTEST
306
437
testmod_names = \
307
438
['bzrlib.selftest.MetaTestLog',
308
'bzrlib.selftest.test_parent',
309
439
'bzrlib.selftest.testinv',
310
'bzrlib.selftest.testfetch',
440
'bzrlib.selftest.test_ancestry',
441
'bzrlib.selftest.test_commit',
442
'bzrlib.selftest.test_commit_merge',
311
443
'bzrlib.selftest.versioning',
312
'bzrlib.selftest.whitebox',
313
444
'bzrlib.selftest.testmerge3',
445
'bzrlib.selftest.testmerge',
314
446
'bzrlib.selftest.testhashcache',
315
447
'bzrlib.selftest.teststatus',
316
448
'bzrlib.selftest.testlog',
317
'bzrlib.selftest.blackbox',
318
449
'bzrlib.selftest.testrevisionnamespaces',
319
450
'bzrlib.selftest.testbranch',
451
'bzrlib.selftest.testremotebranch',
320
452
'bzrlib.selftest.testrevision',
453
'bzrlib.selftest.test_revision_info',
321
454
'bzrlib.selftest.test_merge_core',
322
455
'bzrlib.selftest.test_smart_add',
456
'bzrlib.selftest.test_bad_files',
323
457
'bzrlib.selftest.testdiff',
458
'bzrlib.selftest.test_parent',
459
'bzrlib.selftest.test_xml',
460
'bzrlib.selftest.test_weave',
461
'bzrlib.selftest.testfetch',
462
'bzrlib.selftest.whitebox',
325
463
'bzrlib.selftest.teststore',
464
'bzrlib.selftest.blackbox',
465
'bzrlib.selftest.testgraph',
328
468
for m in (bzrlib.store, bzrlib.inventory, bzrlib.branch,