135
134
SUBUNIT_SEEK_SET = 0
136
135
SUBUNIT_SEEK_CUR = 1
137
# These are intentionally brought into this namespace. That way plugins, etc
138
# can just "from bzrlib.tests import TestCase, TestLoader, etc"
139
TestSuite = TestUtil.TestSuite
140
TestLoader = TestUtil.TestLoader
139
142
class ExtendedTestResult(testtools.TextTestResult):
140
143
"""Accepts, reports and accumulates the results of running tests.
234
239
ok = self.wasStrictlySuccessful()
236
241
ok = self.wasSuccessful()
237
if TestCase._first_thread_leaker_id:
242
if self._first_thread_leaker_id:
238
243
self.stream.write(
239
244
'%s is leaking threads among %d leaking tests.\n' % (
240
TestCase._first_thread_leaker_id,
241
TestCase._leaking_threads_tests))
245
self._first_thread_leaker_id,
246
self._tests_leaking_threads_count))
242
247
# We don't report the main thread as an active one.
243
248
self.stream.write(
244
249
'%d non-main threads were left active in the end.\n'
245
% (TestCase._active_threads - 1))
250
% (len(self._active_threads) - 1))
247
252
def getDescription(self, test):
279
284
super(ExtendedTestResult, self).startTest(test)
280
285
if self.count == 0:
281
286
self.startTests()
282
288
self.report_test_start(test)
283
289
test.number = self.count
284
290
self._recordTestStartTime()
291
# Only check for thread leaks if the test case supports cleanups
292
addCleanup = getattr(test, "addCleanup", None)
293
if addCleanup is not None:
294
addCleanup(self._check_leaked_threads, test)
286
296
def startTests(self):
288
if getattr(sys, 'frozen', None) is None:
289
bzr_path = osutils.realpath(sys.argv[0])
291
bzr_path = sys.executable
293
'bzr selftest: %s\n' % (bzr_path,))
296
bzrlib.__path__[0],))
298
' bzr-%s python-%s %s\n' % (
299
bzrlib.version_string,
300
bzrlib._format_version_tuple(sys.version_info),
301
platform.platform(aliased=1),
303
self.stream.write('\n')
297
self.report_tests_starting()
298
self._active_threads = threading.enumerate()
300
def _check_leaked_threads(self, test):
301
"""See if any threads have leaked since last call
303
A sample of live threads is stored in the _active_threads attribute,
304
when this method runs it compares the current live threads and any not
305
in the previous sample are treated as having leaked.
307
now_active_threads = set(threading.enumerate())
308
threads_leaked = now_active_threads.difference(self._active_threads)
310
self._report_thread_leak(test, threads_leaked, now_active_threads)
311
self._tests_leaking_threads_count += 1
312
if self._first_thread_leaker_id is None:
313
self._first_thread_leaker_id = test.id()
314
self._active_threads = now_active_threads
305
316
def _recordTestStartTime(self):
306
317
"""Record that a test has started."""
307
318
self._start_time = time.time()
309
def _cleanupLogFile(self, test):
310
# We can only do this if we have one of our TestCases, not if
312
setKeepLogfile = getattr(test, 'setKeepLogfile', None)
313
if setKeepLogfile is not None:
316
320
def addError(self, test, err):
317
321
"""Tell result that test finished with an error.
398
399
raise errors.BzrError("Unknown whence %r" % whence)
400
def report_cleaning_up(self):
401
def report_tests_starting(self):
402
"""Display information before the test run begins"""
403
if getattr(sys, 'frozen', None) is None:
404
bzr_path = osutils.realpath(sys.argv[0])
406
bzr_path = sys.executable
408
'bzr selftest: %s\n' % (bzr_path,))
411
bzrlib.__path__[0],))
413
' bzr-%s python-%s %s\n' % (
414
bzrlib.version_string,
415
bzrlib._format_version_tuple(sys.version_info),
416
platform.platform(aliased=1),
418
self.stream.write('\n')
420
def report_test_start(self, test):
421
"""Display information on the test just about to be run"""
423
def _report_thread_leak(self, test, leaked_threads, active_threads):
424
"""Display information on a test that leaked one or more threads"""
425
# GZ 2010-09-09: A leak summary reported separately from the general
426
# thread debugging would be nice. Tests under subunit
427
# need something not using stream, perhaps adding a
428
# testtools details object would be fitting.
429
if 'threads' in selftest_debug_flags:
430
self.stream.write('%s is leaking, active is now %d\n' %
431
(test.id(), len(active_threads)))
403
433
def startTestRun(self):
404
434
self.startTime = time.time()
441
471
self.pb.finished()
442
472
super(TextTestResult, self).stopTestRun()
444
def startTestRun(self):
445
super(TextTestResult, self).startTestRun()
474
def report_tests_starting(self):
475
super(TextTestResult, self).report_tests_starting()
446
476
self.pb.update('[test 0/%d] Starting' % (self.num_tests))
448
def printErrors(self):
449
# clear the pb to make room for the error listing
451
super(TextTestResult, self).printErrors()
453
478
def _progress_prefix_text(self):
454
479
# the longer this text, the less space we have to show the test
510
534
def report_unsupported(self, test, feature):
511
535
"""test cannot be run because feature is missing."""
513
def report_cleaning_up(self):
514
self.pb.update('Cleaning up')
517
538
class VerboseTestResult(ExtendedTestResult):
518
539
"""Produce long output, with one line per test run plus times"""
525
546
result = a_string
526
547
return result.ljust(final_width)
528
def startTestRun(self):
529
super(VerboseTestResult, self).startTestRun()
549
def report_tests_starting(self):
530
550
self.stream.write('running %d tests...\n' % self.num_tests)
551
super(VerboseTestResult, self).report_tests_starting()
532
553
def report_test_start(self, test):
534
554
name = self._shortened_test_description(test)
535
555
width = osutils.terminal_width()
536
556
if width is not None:
786
806
routine, and to build and check bzr trees.
788
808
In addition to the usual method of overriding tearDown(), this class also
789
allows subclasses to register functions into the _cleanups list, which is
809
allows subclasses to register cleanup functions via addCleanup, which are
790
810
run in order as the object is torn down. It's less likely this will be
791
811
accidentally overlooked.
794
_active_threads = None
795
_leaking_threads_tests = 0
796
_first_thread_leaker_id = None
797
_log_file_name = None
798
815
# record lsprof data when performing benchmark calls.
799
816
_gather_lsprof_in_benchmarks = False
801
818
def __init__(self, methodName='testMethod'):
802
819
super(TestCase, self).__init__(methodName)
804
820
self._directory_isolation = True
805
821
self.exception_handlers.insert(0,
806
822
(UnavailableFeature, self._do_unsupported_or_skip))
824
840
self._track_transports()
825
841
self._track_locks()
826
842
self._clear_debug_flags()
827
TestCase._active_threads = threading.activeCount()
828
self.addCleanup(self._check_leaked_threads)
831
845
# debug a frame up.
833
847
pdb.Pdb().set_trace(sys._getframe().f_back)
835
def _check_leaked_threads(self):
836
active = threading.activeCount()
837
leaked_threads = active - TestCase._active_threads
838
TestCase._active_threads = active
839
# If some tests make the number of threads *decrease*, we'll consider
840
# that they are just observing old threads dieing, not agressively kill
841
# random threads. So we don't report these tests as leaking. The risk
842
# is that we have false positives that way (the test see 2 threads
843
# going away but leak one) but it seems less likely than the actual
844
# false positives (the test see threads going away and does not leak).
845
if leaked_threads > 0:
846
if 'threads' in selftest_debug_flags:
847
print '%s is leaking, active is now %d' % (self.id(), active)
848
TestCase._leaking_threads_tests += 1
849
if TestCase._first_thread_leaker_id is None:
850
TestCase._first_thread_leaker_id = self.id()
849
def discardDetail(self, name):
850
"""Extend the addDetail, getDetails api so we can remove a detail.
852
eg. bzr always adds the 'log' detail at startup, but we don't want to
853
include it for skipped, xfail, etc tests.
855
It is safe to call this for a detail that doesn't exist, in case this
856
gets called multiple times.
858
# We cheat. details is stored in __details which means we shouldn't
859
# touch it. but getDetails() returns the dict directly, so we can
861
details = self.getDetails()
852
865
def _clear_debug_flags(self):
853
866
"""Prevent externally set debug flags affecting tests.
1455
1468
The file is removed as the test is torn down.
1457
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
1458
self._log_file = os.fdopen(fileno, 'w+')
1470
self._log_file = StringIO()
1459
1471
self._log_memento = bzrlib.trace.push_log_file(self._log_file)
1460
self._log_file_name = name
1461
1472
self.addCleanup(self._finishLogFile)
1463
1474
def _finishLogFile(self):
1486
1497
debug.debug_flags.discard('strict_locks')
1488
def addCleanup(self, callable, *args, **kwargs):
1489
"""Arrange to run a callable when this case is torn down.
1491
Callables are run in the reverse of the order they are registered,
1492
ie last-in first-out.
1494
self._cleanups.append((callable, args, kwargs))
1496
1499
def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1497
1500
"""Overrides an object attribute restoring it after the test.
1582
1585
"""This test has failed for some known reason."""
1583
1586
raise KnownFailure(reason)
1588
def _suppress_log(self):
1589
"""Remove the log info from details."""
1590
self.discardDetail('log')
1585
1592
def _do_skip(self, result, reason):
1593
self._suppress_log()
1586
1594
addSkip = getattr(result, 'addSkip', None)
1587
1595
if not callable(addSkip):
1588
1596
result.addSuccess(result)
1611
1621
self._do_skip(result, reason)
1624
def _report_skip(self, result, err):
1625
"""Override the default _report_skip.
1627
We want to strip the 'log' detail. If we waint until _do_skip, it has
1628
already been formatted into the 'reason' string, and we can't pull it
1631
self._suppress_log()
1632
super(TestCase, self)._report_skip(self, result, err)
1635
def _report_expected_failure(self, result, err):
1638
See _report_skip for motivation.
1640
self._suppress_log()
1641
super(TestCase, self)._report_expected_failure(self, result, err)
1614
1644
def _do_unsupported_or_skip(self, result, e):
1615
1645
reason = e.args[0]
1646
self._suppress_log()
1616
1647
addNotSupported = getattr(result, 'addNotSupported', None)
1617
1648
if addNotSupported is not None:
1618
1649
result.addNotSupported(self, reason)
1665
1696
unicodestr = self._log_contents.decode('utf8', 'replace')
1666
1697
self._log_contents = unicodestr.encode('utf8')
1667
1698
return self._log_contents
1669
if bzrlib.trace._trace_file:
1670
# flush the log file, to get all content
1671
bzrlib.trace._trace_file.flush()
1672
if self._log_file_name is not None:
1673
logfile = open(self._log_file_name)
1675
log_contents = logfile.read()
1699
if self._log_file is not None:
1700
log_contents = self._log_file.getvalue()
1679
1702
log_contents.decode('utf8')
1680
1703
except UnicodeDecodeError:
1681
1704
unicodestr = log_contents.decode('utf8', 'replace')
1682
1705
log_contents = unicodestr.encode('utf8')
1683
1706
if not keep_log_file:
1685
max_close_attempts = 100
1686
first_close_error = None
1687
while close_attempts < max_close_attempts:
1690
self._log_file.close()
1691
except IOError, ioe:
1692
if ioe.errno is None:
1693
# No errno implies 'close() called during
1694
# concurrent operation on the same file object', so
1695
# retry. Probably a thread is trying to write to
1697
if first_close_error is None:
1698
first_close_error = ioe
1703
if close_attempts > 1:
1705
'Unable to close log file on first attempt, '
1706
'will retry: %s\n' % (first_close_error,))
1707
if close_attempts == max_close_attempts:
1709
'Unable to close log file after %d attempts.\n'
1710
% (max_close_attempts,))
1711
1707
self._log_file = None
1712
1708
# Permit multiple calls to get_log until we clean it up in
1713
1709
# finishLogFile
1714
1710
self._log_contents = log_contents
1716
os.remove(self._log_file_name)
1718
if sys.platform == 'win32' and e.errno == errno.EACCES:
1719
sys.stderr.write(('Unable to delete log file '
1720
' %r\n' % self._log_file_name))
1723
self._log_file_name = None
1724
1711
return log_contents
1726
return "No log file content and no log file name."
1713
return "No log file content."
1728
1715
def get_log(self):
1729
1716
"""Get a unicode string containing the log from bzrlib.trace.
1944
1931
variables. A value of None will unset the env variable.
1945
1932
The values must be strings. The change will only occur in the
1946
1933
child, so you don't need to fix the environment after running.
1947
:param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
1934
:param skip_if_plan_to_signal: raise TestSkipped when true and system
1935
doesn't support signalling subprocesses.
1949
1936
:param allow_plugins: If False (default) pass --no-plugins to bzr.
1951
1938
:returns: Popen object for the started process.
1953
1940
if skip_if_plan_to_signal:
1954
if not getattr(os, 'kill', None):
1955
raise TestSkipped("os.kill not available.")
1941
if os.name != "posix":
1942
raise TestSkipped("Sending signals not supported")
1957
1944
if env_changes is None:
1958
1945
env_changes = {}
3014
3001
def fork_decorator(suite):
3002
if getattr(os, "fork", None) is None:
3003
raise errors.BzrCommandError("platform does not support fork,"
3004
" try --parallel=subprocess instead.")
3015
3005
concurrency = osutils.local_concurrency()
3016
3006
if concurrency == 1:
3658
3648
'bzrlib.tests.commands',
3659
3649
'bzrlib.tests.doc_generate',
3660
3650
'bzrlib.tests.per_branch',
3651
'bzrlib.tests.per_bzrdir',
3661
3652
'bzrlib.tests.per_controldir',
3662
3653
'bzrlib.tests.per_controldir_colo',
3663
3654
'bzrlib.tests.per_foreign_vcs',
4070
4061
new_test = copy.copy(test)
4071
4062
new_test.id = lambda: new_id
4063
# XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
4064
# causes cloned tests to share the 'details' dict. This makes it hard to
4065
# read the test output for parameterized tests, because tracebacks will be
4066
# associated with irrelevant tests.
4068
details = new_test._TestCase__details
4069
except AttributeError:
4070
# must be a different version of testtools than expected. Do nothing.
4073
# Reset the '__details' dict.
4074
new_test._TestCase__details = {}
4072
4075
return new_test
4501
4504
from subunit import TestProtocolClient
4502
4505
from subunit.test_results import AutoTimingTestResultDecorator
4506
class SubUnitBzrProtocolClient(TestProtocolClient):
4508
def addSuccess(self, test, details=None):
4509
# The subunit client always includes the details in the subunit
4510
# stream, but we don't want to include it in ours.
4511
if details is not None and 'log' in details:
4513
return super(SubUnitBzrProtocolClient, self).addSuccess(
4503
4516
class SubUnitBzrRunner(TextTestRunner):
4504
4517
def run(self, test):
4505
4518
result = AutoTimingTestResultDecorator(
4506
TestProtocolClient(self.stream))
4519
SubUnitBzrProtocolClient(self.stream))
4507
4520
test.run(result)
4509
4522
except ImportError: