239
238
ok = self.wasStrictlySuccessful()
241
240
ok = self.wasSuccessful()
242
if self._first_thread_leaker_id:
241
if TestCase._first_thread_leaker_id:
243
242
self.stream.write(
244
243
'%s is leaking threads among %d leaking tests.\n' % (
245
self._first_thread_leaker_id,
246
self._tests_leaking_threads_count))
244
TestCase._first_thread_leaker_id,
245
TestCase._leaking_threads_tests))
247
246
# We don't report the main thread as an active one.
248
247
self.stream.write(
249
248
'%d non-main threads were left active in the end.\n'
250
% (len(self._active_threads) - 1))
249
% (TestCase._active_threads - 1))
252
251
def getDescription(self, test):
284
283
super(ExtendedTestResult, self).startTest(test)
285
284
if self.count == 0:
286
285
self.startTests()
288
286
self.report_test_start(test)
289
287
test.number = self.count
290
288
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)
296
290
def startTests(self):
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
292
if getattr(sys, 'frozen', None) is None:
293
bzr_path = osutils.realpath(sys.argv[0])
295
bzr_path = sys.executable
297
'bzr selftest: %s\n' % (bzr_path,))
300
bzrlib.__path__[0],))
302
' bzr-%s python-%s %s\n' % (
303
bzrlib.version_string,
304
bzrlib._format_version_tuple(sys.version_info),
305
platform.platform(aliased=1),
307
self.stream.write('\n')
316
309
def _recordTestStartTime(self):
317
310
"""Record that a test has started."""
318
311
self._start_time = time.time()
313
def _cleanupLogFile(self, test):
314
# We can only do this if we have one of our TestCases, not if
316
setKeepLogfile = getattr(test, 'setKeepLogfile', None)
317
if setKeepLogfile is not None:
320
320
def addError(self, test, err):
321
321
"""Tell result that test finished with an error.
399
402
raise errors.BzrError("Unknown whence %r" % whence)
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)))
404
def report_cleaning_up(self):
433
407
def startTestRun(self):
434
408
self.startTime = time.time()
471
445
self.pb.finished()
472
446
super(TextTestResult, self).stopTestRun()
474
def report_tests_starting(self):
475
super(TextTestResult, self).report_tests_starting()
448
def startTestRun(self):
449
super(TextTestResult, self).startTestRun()
476
450
self.pb.update('[test 0/%d] Starting' % (self.num_tests))
452
def printErrors(self):
453
# clear the pb to make room for the error listing
455
super(TextTestResult, self).printErrors()
478
457
def _progress_prefix_text(self):
479
458
# the longer this text, the less space we have to show the test
534
514
def report_unsupported(self, test, feature):
535
515
"""test cannot be run because feature is missing."""
517
def report_cleaning_up(self):
518
self.pb.update('Cleaning up')
538
521
class VerboseTestResult(ExtendedTestResult):
539
522
"""Produce long output, with one line per test run plus times"""
546
529
result = a_string
547
530
return result.ljust(final_width)
549
def report_tests_starting(self):
532
def startTestRun(self):
533
super(VerboseTestResult, self).startTestRun()
550
534
self.stream.write('running %d tests...\n' % self.num_tests)
551
super(VerboseTestResult, self).report_tests_starting()
553
536
def report_test_start(self, test):
554
538
name = self._shortened_test_description(test)
555
539
width = osutils.terminal_width()
556
540
if width is not None:
806
790
routine, and to build and check bzr trees.
808
792
In addition to the usual method of overriding tearDown(), this class also
809
allows subclasses to register cleanup functions via addCleanup, which are
793
allows subclasses to register functions into the _cleanups list, which is
810
794
run in order as the object is torn down. It's less likely this will be
811
795
accidentally overlooked.
798
_active_threads = None
799
_leaking_threads_tests = 0
800
_first_thread_leaker_id = None
815
802
# record lsprof data when performing benchmark calls.
816
803
_gather_lsprof_in_benchmarks = False
818
805
def __init__(self, methodName='testMethod'):
819
806
super(TestCase, self).__init__(methodName)
820
808
self._directory_isolation = True
821
809
self.exception_handlers.insert(0,
822
810
(UnavailableFeature, self._do_unsupported_or_skip))
840
828
self._track_transports()
841
829
self._track_locks()
842
830
self._clear_debug_flags()
831
TestCase._active_threads = threading.activeCount()
832
self.addCleanup(self._check_leaked_threads)
845
835
# debug a frame up.
847
837
pdb.Pdb().set_trace(sys._getframe().f_back)
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()
839
def _check_leaked_threads(self):
840
active = threading.activeCount()
841
leaked_threads = active - TestCase._active_threads
842
TestCase._active_threads = active
843
# If some tests make the number of threads *decrease*, we'll consider
844
# that they are just observing old threads dieing, not agressively kill
845
# random threads. So we don't report these tests as leaking. The risk
846
# is that we have false positives that way (the test see 2 threads
847
# going away but leak one) but it seems less likely than the actual
848
# false positives (the test see threads going away and does not leak).
849
if leaked_threads > 0:
850
if 'threads' in selftest_debug_flags:
851
print '%s is leaking, active is now %d' % (self.id(), active)
852
TestCase._leaking_threads_tests += 1
853
if TestCase._first_thread_leaker_id is None:
854
TestCase._first_thread_leaker_id = self.id()
865
856
def _clear_debug_flags(self):
866
857
"""Prevent externally set debug flags affecting tests.
1497
1488
debug.debug_flags.discard('strict_locks')
1490
def addCleanup(self, callable, *args, **kwargs):
1491
"""Arrange to run a callable when this case is torn down.
1493
Callables are run in the reverse of the order they are registered,
1494
ie last-in first-out.
1496
self._cleanups.append((callable, args, kwargs))
1499
1498
def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1500
1499
"""Overrides an object attribute restoring it after the test.
1585
1584
"""This test has failed for some known reason."""
1586
1585
raise KnownFailure(reason)
1588
def _suppress_log(self):
1589
"""Remove the log info from details."""
1590
self.discardDetail('log')
1592
1587
def _do_skip(self, result, reason):
1593
self._suppress_log()
1594
1588
addSkip = getattr(result, 'addSkip', None)
1595
1589
if not callable(addSkip):
1596
1590
result.addSuccess(result)
1621
1613
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)
1644
1616
def _do_unsupported_or_skip(self, result, e):
1645
1617
reason = e.args[0]
1646
self._suppress_log()
1647
1618
addNotSupported = getattr(result, 'addNotSupported', None)
1648
1619
if addNotSupported is not None:
1649
1620
result.addNotSupported(self, reason)
3001
2972
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.")
3005
2973
concurrency = osutils.local_concurrency()
3006
2974
if concurrency == 1:
4061
4029
new_test = copy.copy(test)
4062
4030
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 = {}
4075
4031
return new_test
4504
4460
from subunit import TestProtocolClient
4505
4461
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(
4516
4462
class SubUnitBzrRunner(TextTestRunner):
4517
4463
def run(self, test):
4518
4464
result = AutoTimingTestResultDecorator(
4519
SubUnitBzrProtocolClient(self.stream))
4465
TestProtocolClient(self.stream))
4520
4466
test.run(result)
4522
4468
except ImportError: