221
223
"""Record that a test has started."""
222
224
self._start_time = time.time()
226
def _cleanupLogFile(self, test):
227
# We can only do this if we have one of our TestCases, not if
229
setKeepLogfile = getattr(test, 'setKeepLogfile', None)
230
if setKeepLogfile is not None:
224
233
def addError(self, test, err):
234
self.extractBenchmarkTime(test)
235
self._cleanupLogFile(test)
225
236
if isinstance(err[1], TestSkipped):
226
return self.addSkipped(test, err)
237
return self.addSkipped(test, err)
238
elif isinstance(err[1], UnavailableFeature):
239
return self.addNotSupported(test, err[1].args[0])
227
240
unittest.TestResult.addError(self, test, err)
228
# We can only do this if we have one of our TestCases, not if
230
setKeepLogfile = getattr(test, 'setKeepLogfile', None)
231
if setKeepLogfile is not None:
233
self.extractBenchmarkTime(test)
241
self.error_count += 1
234
242
self.report_error(test, err)
235
243
if self.stop_early:
238
246
def addFailure(self, test, err):
247
self._cleanupLogFile(test)
248
self.extractBenchmarkTime(test)
249
if isinstance(err[1], KnownFailure):
250
return self.addKnownFailure(test, err)
239
251
unittest.TestResult.addFailure(self, test, err)
240
# We can only do this if we have one of our TestCases, not if
242
setKeepLogfile = getattr(test, 'setKeepLogfile', None)
243
if setKeepLogfile is not None:
245
self.extractBenchmarkTime(test)
252
self.failure_count += 1
246
253
self.report_failure(test, err)
247
254
if self.stop_early:
257
def addKnownFailure(self, test, err):
258
self.known_failure_count += 1
259
self.report_known_failure(test, err)
261
def addNotSupported(self, test, feature):
262
self.unsupported.setdefault(str(feature), 0)
263
self.unsupported[str(feature)] += 1
264
self.report_unsupported(test, feature)
250
266
def addSuccess(self, test):
251
267
self.extractBenchmarkTime(test)
252
268
if self._bench_history is not None:
258
274
unittest.TestResult.addSuccess(self, test)
260
276
def addSkipped(self, test, skip_excinfo):
261
self.extractBenchmarkTime(test)
262
277
self.report_skip(test, skip_excinfo)
263
278
# seems best to treat this as success from point-of-view of unittest
264
279
# -- it actually does nothing so it barely matters :)
301
316
class TextTestResult(ExtendedTestResult):
302
317
"""Displays progress and results of tests in text form"""
304
def __init__(self, *args, **kw):
305
ExtendedTestResult.__init__(self, *args, **kw)
306
self.pb = self.ui.nested_progress_bar()
319
def __init__(self, stream, descriptions, verbosity,
324
ExtendedTestResult.__init__(self, stream, descriptions, verbosity,
325
bench_history, num_tests)
327
self.pb = self.ui.nested_progress_bar()
328
self._supplied_pb = False
331
self._supplied_pb = True
307
332
self.pb.show_pct = False
308
333
self.pb.show_spinner = False
309
self.pb.show_eta = False,
334
self.pb.show_eta = False,
310
335
self.pb.show_count = False
311
336
self.pb.show_bar = False
322
347
a += ', %d errors' % self.error_count
323
348
if self.failure_count:
324
349
a += ', %d failed' % self.failure_count
350
if self.known_failure_count:
351
a += ', %d known failures' % self.known_failure_count
325
352
if self.skip_count:
326
353
a += ', %d skipped' % self.skip_count
355
a += ', %d missing features' % len(self.unsupported)
342
371
return self._shortened_test_description(test)
344
373
def report_error(self, test, err):
345
self.error_count += 1
346
374
self.pb.note('ERROR: %s\n %s\n',
347
375
self._test_description(test),
351
379
def report_failure(self, test, err):
352
self.failure_count += 1
353
380
self.pb.note('FAIL: %s\n %s\n',
354
381
self._test_description(test),
385
def report_known_failure(self, test, err):
386
self.pb.note('XFAIL: %s\n%s\n',
387
self._test_description(test), err[1])
358
389
def report_skip(self, test, skip_excinfo):
359
390
self.skip_count += 1
371
402
# progress bar...
372
403
self.pb.note('SKIP: %s', skip_excinfo[1])
405
def report_unsupported(self, test, feature):
406
"""test cannot be run because feature is missing."""
374
408
def report_cleaning_up(self):
375
409
self.pb.update('cleaning up...')
377
411
def finished(self):
412
if not self._supplied_pb:
381
416
class VerboseTestResult(ExtendedTestResult):
414
449
return '%s%s' % (indent, err[1])
416
451
def report_error(self, test, err):
417
self.error_count += 1
418
452
self.stream.writeln('ERROR %s\n%s'
419
453
% (self._testTimeString(),
420
454
self._error_summary(err)))
422
456
def report_failure(self, test, err):
423
self.failure_count += 1
424
457
self.stream.writeln(' FAIL %s\n%s'
425
458
% (self._testTimeString(),
426
459
self._error_summary(err)))
461
def report_known_failure(self, test, err):
462
self.stream.writeln('XFAIL %s\n%s'
463
% (self._testTimeString(),
464
self._error_summary(err)))
428
466
def report_success(self, test):
429
467
self.stream.writeln(' OK %s' % self._testTimeString())
430
468
for bench_called, stats in getattr(test, '_benchcalls', []):
431
469
self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
432
470
stats.pprint(file=self.stream)
471
# flush the stream so that we get smooth output. This verbose mode is
472
# used to show the output in PQM.
433
473
self.stream.flush()
435
475
def report_skip(self, test, skip_excinfo):
438
478
% (self._testTimeString(),
439
479
self._error_summary(skip_excinfo)))
481
def report_unsupported(self, test, feature):
482
"""test cannot be run because feature is missing."""
483
self.stream.writeln("NODEP %s\n The feature '%s' is not available."
484
%(self._testTimeString(), feature))
442
488
class TextTestRunner(object):
443
489
stop_on_failure = False
487
533
if failed: self.stream.write(", ")
488
534
self.stream.write("errors=%d" % errored)
535
if result.known_failure_count:
536
if failed or errored: self.stream.write(", ")
537
self.stream.write("known_failure_count=%d" %
538
result.known_failure_count)
489
539
self.stream.writeln(")")
491
self.stream.writeln("OK")
541
if result.known_failure_count:
542
self.stream.writeln("OK (known_failures=%d)" %
543
result.known_failure_count)
545
self.stream.writeln("OK")
492
546
if result.skip_count > 0:
493
547
skipped = result.skip_count
494
548
self.stream.writeln('%d test%s skipped' %
495
549
(skipped, skipped != 1 and "s" or ""))
550
if result.unsupported:
551
for feature, count in sorted(result.unsupported.items()):
552
self.stream.writeln("Missing feature '%s' skipped %d tests." %
496
554
result.report_cleaning_up()
497
555
# This is still a little bogus,
498
556
# but only a little. Folk not using our testrunner will
545
603
"""Indicates that a test was intentionally skipped, rather than failing."""
606
class KnownFailure(AssertionError):
607
"""Indicates that a test failed in a precisely expected manner.
609
Such failures dont block the whole test suite from passing because they are
610
indicators of partially completed code or of future work. We have an
611
explicit error for them so that we can ensure that they are always visible:
612
KnownFailures are always shown in the output of bzr selftest.
616
class UnavailableFeature(Exception):
617
"""A feature required for this test was not available.
619
The feature should be used to construct the exception.
548
623
class CommandFailed(Exception):
796
871
excName = str(excClass)
797
872
raise self.failureException, "%s not raised" % excName
874
def assertRaises(self, excClass, func, *args, **kwargs):
875
"""Assert that a callable raises a particular exception.
877
:param excClass: As for the except statement, this may be either an
878
exception class, or a tuple of classes.
880
Returns the exception so that you can examine it.
883
func(*args, **kwargs)
887
if getattr(excClass,'__name__', None) is not None:
888
excName = excClass.__name__
891
excName = str(excClass)
892
raise self.failureException, "%s not raised" % excName
799
894
def assertIs(self, left, right, message=None):
800
895
if not (left is right):
801
896
if message is not None:
828
923
self.fail("%r is an instance of %s rather than %s" % (
829
924
obj, obj.__class__, kls))
926
def expectFailure(self, reason, assertion, *args, **kwargs):
927
"""Invoke a test, expecting it to fail for the given reason.
929
This is for assertions that ought to succeed, but currently fail.
930
(The failure is *expected* but not *wanted*.) Please be very precise
931
about the failure you're expecting. If a new bug is introduced,
932
AssertionError should be raised, not KnownFailure.
934
Frequently, expectFailure should be followed by an opposite assertion.
937
Intended to be used with a callable that raises AssertionError as the
938
'assertion' parameter. args and kwargs are passed to the 'assertion'.
940
Raises KnownFailure if the test fails. Raises AssertionError if the
945
self.expectFailure('Math is broken', self.assertNotEqual, 54,
947
self.assertEqual(42, dynamic_val)
949
This means that a dynamic_val of 54 will cause the test to raise
950
a KnownFailure. Once math is fixed and the expectFailure is removed,
951
only a dynamic_val of 42 will allow the test to pass. Anything other
952
than 54 or 42 will cause an AssertionError.
955
assertion(*args, **kwargs)
956
except AssertionError:
957
raise KnownFailure(reason)
959
self.fail('Unexpected success. Should have failed: %s' % reason)
831
961
def _capture_warnings(self, a_callable, *args, **kwargs):
832
962
"""A helper for callDeprecated and applyDeprecated.
974
1104
for klass, hooks in self._preserved_hooks.items():
975
1105
setattr(klass, 'hooks', hooks)
1107
def knownFailure(self, reason):
1108
"""This test has failed for some known reason."""
1109
raise KnownFailure(reason)
1111
def run(self, result=None):
1112
if result is None: result = self.defaultTestResult()
1113
for feature in getattr(self, '_test_needs_features', []):
1114
if not feature.available():
1115
result.startTest(self)
1116
if getattr(result, 'addNotSupported', None):
1117
result.addNotSupported(self, feature)
1119
result.addSuccess(self)
1120
result.stopTest(self)
1122
return unittest.TestCase.run(self, result)
977
1124
def tearDown(self):
978
1125
self._runCleanups()
979
1126
unittest.TestCase.tearDown(self)
1049
1196
"""Shortcut that splits cmd into words, runs, and returns stdout"""
1050
1197
return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
1199
def requireFeature(self, feature):
1200
"""This test requires a specific feature is available.
1202
:raises UnavailableFeature: When feature is not available.
1204
if not feature.available():
1205
raise UnavailableFeature(feature)
1052
1207
def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None,
1053
1208
working_dir=None):
1054
1209
"""Invoke bzr and return (stdout, stderr).
1387
1542
this_tree=wt_to)
1388
1543
wt_to.add_parent_tree_id(branch_from.last_revision())
1545
def reduceLockdirTimeout(self):
1546
"""Reduce the default lock timeout for the duration of the test, so that
1547
if LockContention occurs during a test, it does so quickly.
1549
Tests that expect to provoke LockContention errors should call this.
1551
orig_timeout = bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS
1553
bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = orig_timeout
1554
self.addCleanup(resetTimeout)
1555
bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = 0
1391
1557
BzrTestBase = TestCase
1416
1582
# execution. Variables that the parameteriser sets need to be
1417
1583
# ones that are not set by setUp, or setUp will trash them.
1418
1584
super(TestCaseWithMemoryTransport, self).__init__(methodName)
1419
self.transport_server = default_transport
1585
self.vfs_transport_factory = default_transport
1586
self.transport_server = None
1420
1587
self.transport_readonly_server = None
1588
self.__vfs_server = None
1422
1590
def get_transport(self):
1423
1591
"""Return a writeable transport for the test scratch space"""
1451
1619
if self.transport_readonly_server is None:
1452
1620
# readonly decorator requested
1453
1621
# bring up the server
1455
1622
self.__readonly_server = ReadonlyServer()
1456
self.__readonly_server.setUp(self.__server)
1623
self.__readonly_server.setUp(self.get_vfs_only_server())
1458
1625
self.__readonly_server = self.create_transport_readonly_server()
1459
self.__readonly_server.setUp()
1626
self.__readonly_server.setUp(self.get_vfs_only_server())
1460
1627
self.addCleanup(self.__readonly_server.tearDown)
1461
1628
return self.__readonly_server
1484
1651
For TestCaseWithMemoryTransport this is always a MemoryServer, and there
1485
1652
is no means to override it.
1654
if self.__vfs_server is None:
1655
self.__vfs_server = MemoryServer()
1656
self.__vfs_server.setUp()
1657
self.addCleanup(self.__vfs_server.tearDown)
1658
return self.__vfs_server
1660
def get_server(self):
1661
"""Get the read/write server instance.
1663
This is useful for some tests with specific servers that need
1666
This is built from the self.transport_server factory. If that is None,
1667
then the self.get_vfs_server is returned.
1487
1669
if self.__server is None:
1488
self.__server = MemoryServer()
1489
self.__server.setUp()
1670
if self.transport_server is None or self.transport_server is self.vfs_transport_factory:
1671
return self.get_vfs_only_server()
1673
# bring up a decorated means of access to the vfs only server.
1674
self.__server = self.transport_server()
1676
self.__server.setUp(self.get_vfs_only_server())
1677
except TypeError, e:
1678
# This should never happen; the try:Except here is to assist
1679
# developers having to update code rather than seeing an
1680
# uninformative TypeError.
1681
raise Exception, "Old server API in use: %s, %s" % (self.__server, e)
1490
1682
self.addCleanup(self.__server.tearDown)
1491
1683
return self.__server
1493
def get_url(self, relpath=None):
1685
def _adjust_url(self, base, relpath):
1494
1686
"""Get a URL (or maybe a path) for the readwrite transport.
1496
1688
This will either be backed by '.' or to an equivalent non-file based
1512
1703
base += urlutils.escape(relpath)
1706
def get_url(self, relpath=None):
1707
"""Get a URL (or maybe a path) for the readwrite transport.
1709
This will either be backed by '.' or to an equivalent non-file based
1711
relpath provides for clients to get a path relative to the base url.
1712
These should only be downwards relative, not upwards.
1714
base = self.get_server().get_url()
1715
return self._adjust_url(base, relpath)
1717
def get_vfs_only_url(self, relpath=None):
1718
"""Get a URL (or maybe a path for the plain old vfs transport.
1720
This will never be a smart protocol.
1721
:param relpath: provides for clients to get a path relative to the base
1722
url. These should only be downwards relative, not upwards.
1724
base = self.get_vfs_only_server().get_url()
1725
return self._adjust_url(base, relpath)
1515
1727
def _make_test_root(self):
1516
1728
if TestCaseWithMemoryTransport.TEST_ROOT is not None:
1739
1952
readwrite one must both define get_url() as resolving to os.getcwd().
1742
def create_transport_server(self):
1743
"""Create a transport server from class defined at init.
1745
This is mostly a hook for daughter classes.
1747
return self.transport_server()
1749
def get_server(self):
1955
def get_vfs_only_server(self):
1750
1956
"""See TestCaseWithMemoryTransport.
1752
1958
This is useful for some tests with specific servers that need
1755
if self.__server is None:
1756
self.__server = self.create_transport_server()
1757
self.__server.setUp()
1758
self.addCleanup(self.__server.tearDown)
1759
return self.__server
1961
if self.__vfs_server is None:
1962
self.__vfs_server = self.vfs_transport_factory()
1963
self.__vfs_server.setUp()
1964
self.addCleanup(self.__vfs_server.tearDown)
1965
return self.__vfs_server
1761
1967
def make_branch_and_tree(self, relpath, format=None):
1762
1968
"""Create a branch on the transport and a tree locally.
1764
1970
If the transport is not a LocalTransport, the Tree can't be created on
1765
the transport. In that case the working tree is created in the local
1766
directory, and the returned tree's branch and repository will also be
1769
This will fail if the original default transport for this test
1770
case wasn't backed by the working directory, as the branch won't
1771
be on disk for us to open it.
1971
the transport. In that case if the vfs_transport_factory is
1972
LocalURLServer the working tree is created in the local
1973
directory backing the transport, and the returned tree's branch and
1974
repository will also be accessed locally. Otherwise a lightweight
1975
checkout is created and returned.
1773
1977
:param format: The BzrDirFormat.
1774
1978
:returns: the WorkingTree.
1782
1986
return b.bzrdir.create_workingtree()
1783
1987
except errors.NotLocalUrl:
1784
1988
# We can only make working trees locally at the moment. If the
1785
# transport can't support them, then reopen the branch on a local
1786
# transport, and create the working tree there.
1788
# Possibly we should instead keep
1789
# the non-disk-backed branch and create a local checkout?
1790
bd = bzrdir.BzrDir.open(relpath)
1791
return bd.create_workingtree()
1989
# transport can't support them, then we keep the non-disk-backed
1990
# branch and create a local checkout.
1991
if self.vfs_transport_factory is LocalURLServer:
1992
# the branch is colocated on disk, we cannot create a checkout.
1993
# hopefully callers will expect this.
1994
local_controldir= bzrdir.BzrDir.open(self.get_vfs_only_url(relpath))
1995
return local_controldir.create_workingtree()
1997
return b.create_checkout(relpath, lightweight=True)
1793
1999
def assertIsDirectory(self, relpath, transport):
1794
2000
"""Assert that relpath within transport is a directory.
2006
2212
'bzrlib.tests.test_ssh_transport',
2007
2213
'bzrlib.tests.test_status',
2008
2214
'bzrlib.tests.test_store',
2215
'bzrlib.tests.test_strace',
2009
2216
'bzrlib.tests.test_subsume',
2010
2217
'bzrlib.tests.test_symbol_versioning',
2011
2218
'bzrlib.tests.test_tag',
2098
2305
print 'delete directory:', i
2099
2306
shutil.rmtree(i)
2309
class Feature(object):
2310
"""An operating system Feature."""
2313
self._available = None
2315
def available(self):
2316
"""Is the feature available?
2318
:return: True if the feature is available.
2320
if self._available is None:
2321
self._available = self._probe()
2322
return self._available
2325
"""Implement this method in concrete features.
2327
:return: True if the feature is available.
2329
raise NotImplementedError
2332
if getattr(self, 'feature_name', None):
2333
return self.feature_name()
2334
return self.__class__.__name__