61
67
from bzrlib.merge import merge_inner
62
68
import bzrlib.merge3
63
69
import bzrlib.osutils
64
import bzrlib.osutils as osutils
65
70
import bzrlib.plugin
66
import bzrlib.progress as progress
67
71
from bzrlib.revision import common_ancestor
68
72
import bzrlib.store
69
73
from bzrlib import symbol_versioning
70
74
import bzrlib.trace
71
75
from bzrlib.transport import get_transport
72
76
import bzrlib.transport
73
from bzrlib.transport.local import LocalRelpathServer
77
from bzrlib.transport.local import LocalURLServer
74
78
from bzrlib.transport.memory import MemoryServer
75
79
from bzrlib.transport.readonly import ReadonlyServer
76
from bzrlib.trace import mutter
80
from bzrlib.trace import mutter, note
77
81
from bzrlib.tests import TestUtil
82
from bzrlib.tests.HttpServer import HttpServer
78
83
from bzrlib.tests.TestUtil import (
82
87
from bzrlib.tests.treeshape import build_tree_contents
83
import bzrlib.urlutils as urlutils
84
88
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
86
default_transport = LocalRelpathServer
90
default_transport = LocalURLServer
88
92
MODULES_TO_TEST = []
89
93
MODULES_TO_DOCTEST = [
91
94
bzrlib.bundle.serializer,
138
class _MyResult(unittest._TextTestResult):
139
"""Custom TestResult.
138
class ExtendedTestResult(unittest._TextTestResult):
139
"""Accepts, reports and accumulates the results of running tests.
141
Shows output in a different format, including displaying runtime for tests.
141
Compared to this unittest version this class adds support for profiling,
142
benchmarking, stopping as soon as a test fails, and skipping tests.
143
There are further-specialized subclasses for different types of display.
143
146
stop_early = False
145
def __init__(self, stream, descriptions, verbosity, pb=None,
148
def __init__(self, stream, descriptions, verbosity,
147
152
"""Construct new TestResult.
149
154
:param bench_history: Optionally, a writable file object to accumulate
150
155
benchmark results.
152
157
unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
154
158
if bench_history is not None:
155
159
from bzrlib.version import _get_bzr_source_tree
156
160
src_tree = _get_bzr_source_tree()
181
192
self._formatTime(self._benchmarkTime),
182
193
self._elapsedTestTimeString())
184
return " %s" % self._elapsedTestTimeString()
195
return " %s" % self._elapsedTestTimeString()
186
197
def _formatTime(self, seconds):
187
198
"""Format seconds as milliseconds with leading spaces."""
188
return "%5dms" % (1000 * seconds)
199
# some benchmarks can take thousands of seconds to run, so we need 8
201
return "%8dms" % (1000 * seconds)
190
def _ellipsise_unimportant_words(self, a_string, final_width,
192
"""Add ellipses (sp?) for overly long strings.
194
:param keep_start: If true preserve the start of a_string rather
198
if len(a_string) > final_width:
199
result = a_string[:final_width-3] + '...'
203
if len(a_string) > final_width:
204
result = '...' + a_string[3-final_width:]
207
return result.ljust(final_width)
203
def _shortened_test_description(self, test):
205
what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
209
208
def startTest(self, test):
210
209
unittest.TestResult.startTest(self, test)
211
# In a short description, the important words are in
212
# the beginning, but in an id, the important words are
214
SHOW_DESCRIPTIONS = False
216
if not self.showAll and self.dots and self.pb is not None:
219
final_width = osutils.terminal_width()
220
final_width = final_width - 15 - 8
222
if SHOW_DESCRIPTIONS:
223
what = test.shortDescription()
225
what = self._ellipsise_unimportant_words(what, final_width, keep_start=True)
228
if what.startswith('bzrlib.tests.'):
230
what = self._ellipsise_unimportant_words(what, final_width)
232
self.stream.write(what)
233
elif self.dots and self.pb is not None:
234
self.pb.update(what, self.testsRun - 1, None)
210
self.report_test_start(test)
236
211
self._recordTestStartTime()
238
213
def _recordTestStartTime(self):
290
247
self._bench_history.write("%s %s\n" % (
291
248
self._formatTime(self._benchmarkTime),
294
self.stream.writeln(' OK %s' % self._testTimeString())
295
for bench_called, stats in getattr(test, '_benchcalls', []):
296
self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
297
stats.pprint(file=self.stream)
298
elif self.dots and self.pb is None:
299
self.stream.write('~')
301
self.pb.update(self._ellipsise_unimportant_words('OK', 13), self.testsRun, None)
250
self.report_success(test)
303
251
unittest.TestResult.addSuccess(self, test)
305
253
def addSkipped(self, test, skip_excinfo):
306
254
self.extractBenchmarkTime(test)
308
print >>self.stream, ' SKIP %s' % self._testTimeString()
309
print >>self.stream, ' %s' % skip_excinfo[1]
310
elif self.dots and self.pb is None:
311
self.stream.write('S')
313
self.pb.update(self._ellipsise_unimportant_words('SKIP', 13), self.testsRun, None)
255
self.report_skip(test, skip_excinfo)
315
256
# seems best to treat this as success from point-of-view of unittest
316
257
# -- it actually does nothing so it barely matters :)
337
278
self.stream.writeln(self.separator2)
338
279
self.stream.writeln("%s" % err)
284
def report_cleaning_up(self):
287
def report_success(self, test):
291
class TextTestResult(ExtendedTestResult):
292
"""Displays progress and results of tests in text form"""
294
def __init__(self, *args, **kw):
295
ExtendedTestResult.__init__(self, *args, **kw)
296
self.pb = self.ui.nested_progress_bar()
297
self.pb.show_pct = False
298
self.pb.show_spinner = False
299
self.pb.show_eta = False,
300
self.pb.show_count = False
301
self.pb.show_bar = False
303
def report_starting(self):
304
self.pb.update('[test 0/%d] starting...' % (self.num_tests))
306
def _progress_prefix_text(self):
307
a = '[%d' % self.count
308
if self.num_tests is not None:
309
a +='/%d' % self.num_tests
310
a += ' in %ds' % (time.time() - self._overall_start_time)
312
a += ', %d errors' % self.error_count
313
if self.failure_count:
314
a += ', %d failed' % self.failure_count
316
a += ', %d skipped' % self.skip_count
320
def report_test_start(self, test):
323
self._progress_prefix_text()
325
+ self._shortened_test_description(test))
327
def report_error(self, test, err):
328
self.error_count += 1
329
self.pb.note('ERROR: %s\n %s\n',
330
self._shortened_test_description(test),
334
def report_failure(self, test, err):
335
self.failure_count += 1
336
self.pb.note('FAIL: %s\n %s\n',
337
self._shortened_test_description(test),
341
def report_skip(self, test, skip_excinfo):
344
# at the moment these are mostly not things we can fix
345
# and so they just produce stipple; use the verbose reporter
348
# show test and reason for skip
349
self.pb.note('SKIP: %s\n %s\n',
350
self._shortened_test_description(test),
353
# since the class name was left behind in the still-visible
355
self.pb.note('SKIP: %s', skip_excinfo[1])
357
def report_cleaning_up(self):
358
self.pb.update('cleaning up...')
364
class VerboseTestResult(ExtendedTestResult):
365
"""Produce long output, with one line per test run plus times"""
367
def _ellipsize_to_right(self, a_string, final_width):
368
"""Truncate and pad a string, keeping the right hand side"""
369
if len(a_string) > final_width:
370
result = '...' + a_string[3-final_width:]
373
return result.ljust(final_width)
375
def report_starting(self):
376
self.stream.write('running %d tests...\n' % self.num_tests)
378
def report_test_start(self, test):
380
name = self._shortened_test_description(test)
381
# width needs space for 6 char status, plus 1 for slash, plus 2 10-char
382
# numbers, plus a trailing blank
383
self.stream.write(self._ellipsize_to_right(name,
384
osutils.terminal_width()-30))
387
def report_error(self, test, err):
388
self.error_count += 1
389
self.stream.writeln('ERROR %s\n %s'
390
% (self._testTimeString(), err[1]))
392
def report_failure(self, test, err):
393
self.failure_count += 1
394
self.stream.writeln(' FAIL %s\n %s'
395
% (self._testTimeString(), err[1]))
397
def report_success(self, test):
398
self.stream.writeln(' OK %s' % self._testTimeString())
399
for bench_called, stats in getattr(test, '_benchcalls', []):
400
self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
401
stats.pprint(file=self.stream)
404
def report_skip(self, test, skip_excinfo):
405
print >>self.stream, ' SKIP %s' % self._testTimeString()
406
print >>self.stream, ' %s' % skip_excinfo[1]
341
409
class TextTestRunner(object):
342
410
stop_on_failure = False
348
416
keep_output=False,
350
417
bench_history=None):
351
418
self.stream = unittest._WritelnDecorator(stream)
352
419
self.descriptions = descriptions
353
420
self.verbosity = verbosity
354
421
self.keep_output = keep_output
356
422
self._bench_history = bench_history
358
def _makeResult(self):
359
result = _MyResult(self.stream,
363
bench_history=self._bench_history)
364
result.stop_early = self.stop_on_failure
367
424
def run(self, test):
368
425
"Run the given test case or test suite."
369
result = self._makeResult()
370
426
startTime = time.time()
371
if self.pb is not None:
372
self.pb.update('Running tests', 0, test.countTestCases())
427
if self.verbosity == 1:
428
result_class = TextTestResult
429
elif self.verbosity >= 2:
430
result_class = VerboseTestResult
431
result = result_class(self.stream,
434
bench_history=self._bench_history,
435
num_tests=test.countTestCases(),
437
result.stop_early = self.stop_on_failure
438
result.report_starting()
374
440
stopTime = time.time()
375
441
timeTaken = stopTime - startTime
507
565
unittest.TestCase.setUp(self)
508
566
self._cleanEnvironment()
509
567
bzrlib.trace.disable_default_logging()
510
569
self._startLogFile()
511
570
self._benchcalls = []
512
571
self._benchtime = None
572
# prevent hooks affecting tests
573
self._preserved_hooks = bzrlib.branch.Branch.hooks
574
self.addCleanup(self._restoreHooks)
575
# this list of hooks must be kept in sync with the defaults
577
bzrlib.branch.Branch.hooks = bzrlib.branch.BranchHooks()
579
def _silenceUI(self):
580
"""Turn off UI for duration of test"""
581
# by default the UI is off; tests can turn it on if they want it.
582
saved = bzrlib.ui.ui_factory
584
bzrlib.ui.ui_factory = saved
585
bzrlib.ui.ui_factory = bzrlib.ui.SilentUIFactory()
586
self.addCleanup(_restore)
514
588
def _ndiff_strings(self, a, b):
515
589
"""Return ndiff between two strings containing lines.
575
649
raise AssertionError("value(s) %r not present in container %r" %
576
650
(missing, superlist))
578
def assertIs(self, left, right):
652
def assertListRaises(self, excClass, func, *args, **kwargs):
653
"""Fail unless excClass is raised when the iterator from func is used.
655
Many functions can return generators this makes sure
656
to wrap them in a list() call to make sure the whole generator
657
is run, and that the proper exception is raised.
660
list(func(*args, **kwargs))
664
if getattr(excClass,'__name__', None) is not None:
665
excName = excClass.__name__
667
excName = str(excClass)
668
raise self.failureException, "%s not raised" % excName
670
def assertIs(self, left, right, message=None):
579
671
if not (left is right):
580
raise AssertionError("%r is not %r." % (left, right))
672
if message is not None:
673
raise AssertionError(message)
675
raise AssertionError("%r is not %r." % (left, right))
677
def assertIsNot(self, left, right, message=None):
679
if message is not None:
680
raise AssertionError(message)
682
raise AssertionError("%r is %r." % (left, right))
582
684
def assertTransportMode(self, transport, path, mode):
583
685
"""Fail if a path does not have mode mode.
931
1055
The values must be strings. The change will only occur in the
932
1056
child, so you don't need to fix the environment after running.
933
1057
:param universal_newlines: Convert CRLF => LF
1058
:param allow_plugins: By default the subprocess is run with
1059
--no-plugins to ensure test reproducibility. Also, it is possible
1060
for system-wide plugins to create unexpected output on stderr,
1061
which can cause unnecessary test failures.
935
1063
env_changes = kwargs.get('env_changes', {})
936
1064
working_dir = kwargs.get('working_dir', None)
1065
allow_plugins = kwargs.get('allow_plugins', False)
937
1066
process = self.start_bzr_subprocess(args, env_changes=env_changes,
938
working_dir=working_dir)
1067
working_dir=working_dir,
1068
allow_plugins=allow_plugins)
939
1069
# We distinguish between retcode=None and retcode not passed.
940
1070
supplied_retcode = kwargs.get('retcode', 0)
941
1071
return self.finish_bzr_subprocess(process, retcode=supplied_retcode,
1398
1542
elif line_endings == 'native':
1399
1543
end = os.linesep
1401
raise errors.BzrError('Invalid line ending request %r' % (line_endings,))
1545
raise errors.BzrError(
1546
'Invalid line ending request %r' % line_endings)
1402
1547
content = "contents of %s%s" % (name.encode('utf-8'), end)
1403
# Technically 'put()' is the right command. However, put
1404
# uses an AtomicFile, which requires an extra rename into place
1405
# As long as the files didn't exist in the past, append() will
1406
# do the same thing as put()
1407
# On jam's machine, make_kernel_like_tree is:
1408
# put: 4.5-7.5s (averaging 6s)
1410
# put_non_atomic: 2.9-4.5s
1411
1548
transport.put_bytes_non_atomic(urlutils.escape(name), content)
1413
1550
def build_tree_contents(self, shape):
1416
1553
def assertFileEqual(self, content, path):
1417
1554
"""Fail if path does not contain 'content'."""
1418
self.failUnless(osutils.lexists(path))
1555
self.failUnlessExists(path)
1419
1556
# TODO: jam 20060427 Shouldn't this be 'rb'?
1420
1557
self.assertEqualDiff(content, open(path, 'r').read())
1559
def failUnlessExists(self, path):
1560
"""Fail unless path, which may be abs or relative, exists."""
1561
self.failUnless(osutils.lexists(path),path+" does not exist")
1563
def failIfExists(self, path):
1564
"""Fail if path, which may be abs or relative, exists."""
1565
self.failIf(osutils.lexists(path),path+" exists")
1423
1568
class TestCaseWithTransport(TestCaseInTempDir):
1424
1569
"""A test case that provides get_url and get_readonly_url facilities.
1680
def sort_suite_by_re(suite, pattern):
1683
filter_re = re.compile(pattern)
1684
for test in iter_suite_tests(suite):
1685
if filter_re.search(test.id()):
1689
return TestUtil.TestSuite(first + second)
1529
1692
def run_suite(suite, name='test', verbose=False, pattern=".*",
1530
1693
stop_on_failure=False, keep_output=False,
1531
transport=None, lsprof_timed=None, bench_history=None):
1694
transport=None, lsprof_timed=None, bench_history=None,
1695
matching_tests_first=None):
1532
1696
TestCase._gather_lsprof_in_benchmarks = lsprof_timed
1538
pb = progress.ProgressBar()
1539
1701
runner = TextTestRunner(stream=sys.stdout,
1540
1702
descriptions=0,
1541
1703
verbosity=verbosity,
1542
1704
keep_output=keep_output,
1544
1705
bench_history=bench_history)
1545
1706
runner.stop_on_failure=stop_on_failure
1546
1707
if pattern != '.*':
1547
suite = filter_suite_by_re(suite, pattern)
1708
if matching_tests_first:
1709
suite = sort_suite_by_re(suite, pattern)
1711
suite = filter_suite_by_re(suite, pattern)
1548
1712
result = runner.run(suite)
1549
1713
return result.wasSuccessful()
1596
1763
'bzrlib.tests.test_bundle',
1597
1764
'bzrlib.tests.test_bzrdir',
1598
1765
'bzrlib.tests.test_cache_utf8',
1599
'bzrlib.tests.test_command',
1766
'bzrlib.tests.test_commands',
1600
1767
'bzrlib.tests.test_commit',
1601
1768
'bzrlib.tests.test_commit_merge',
1602
1769
'bzrlib.tests.test_config',
1603
1770
'bzrlib.tests.test_conflicts',
1604
1771
'bzrlib.tests.test_decorators',
1772
'bzrlib.tests.test_delta',
1605
1773
'bzrlib.tests.test_diff',
1606
1774
'bzrlib.tests.test_doc_generate',
1607
1775
'bzrlib.tests.test_errors',
1608
1776
'bzrlib.tests.test_escaped_store',
1609
1777
'bzrlib.tests.test_fetch',
1610
1778
'bzrlib.tests.test_ftp_transport',
1779
'bzrlib.tests.test_generate_docs',
1780
'bzrlib.tests.test_generate_ids',
1781
'bzrlib.tests.test_globbing',
1611
1782
'bzrlib.tests.test_gpg',
1612
1783
'bzrlib.tests.test_graph',
1613
1784
'bzrlib.tests.test_hashcache',
1630
1802
'bzrlib.tests.test_nonascii',
1631
1803
'bzrlib.tests.test_options',
1632
1804
'bzrlib.tests.test_osutils',
1805
'bzrlib.tests.test_osutils_encodings',
1633
1806
'bzrlib.tests.test_patch',
1634
1807
'bzrlib.tests.test_patches',
1635
1808
'bzrlib.tests.test_permissions',
1636
1809
'bzrlib.tests.test_plugins',
1637
1810
'bzrlib.tests.test_progress',
1638
1811
'bzrlib.tests.test_reconcile',
1812
'bzrlib.tests.test_registry',
1639
1813
'bzrlib.tests.test_repository',
1640
1814
'bzrlib.tests.test_revert',
1641
1815
'bzrlib.tests.test_revision',