238
239
ok = self.wasStrictlySuccessful()
240
241
ok = self.wasSuccessful()
241
if TestCase._first_thread_leaker_id:
242
if self._first_thread_leaker_id:
242
243
self.stream.write(
243
244
'%s is leaking threads among %d leaking tests.\n' % (
244
TestCase._first_thread_leaker_id,
245
TestCase._leaking_threads_tests))
245
self._first_thread_leaker_id,
246
self._tests_leaking_threads_count))
246
247
# We don't report the main thread as an active one.
247
248
self.stream.write(
248
249
'%d non-main threads were left active in the end.\n'
249
% (TestCase._active_threads - 1))
250
% (len(self._active_threads) - 1))
251
252
def getDescription(self, test):
283
284
super(ExtendedTestResult, self).startTest(test)
284
285
if self.count == 0:
285
286
self.startTests()
286
288
self.report_test_start(test)
287
289
test.number = self.count
288
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)
290
296
def startTests(self):
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')
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
309
316
def _recordTestStartTime(self):
310
317
"""Record that a test has started."""
311
318
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.
402
399
raise errors.BzrError("Unknown whence %r" % whence)
404
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)))
407
433
def startTestRun(self):
408
434
self.startTime = time.time()
445
471
self.pb.finished()
446
472
super(TextTestResult, self).stopTestRun()
448
def startTestRun(self):
449
super(TextTestResult, self).startTestRun()
474
def report_tests_starting(self):
475
super(TextTestResult, self).report_tests_starting()
450
476
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()
457
478
def _progress_prefix_text(self):
458
479
# the longer this text, the less space we have to show the test
514
534
def report_unsupported(self, test, feature):
515
535
"""test cannot be run because feature is missing."""
517
def report_cleaning_up(self):
518
self.pb.update('Cleaning up')
521
538
class VerboseTestResult(ExtendedTestResult):
522
539
"""Produce long output, with one line per test run plus times"""
529
546
result = a_string
530
547
return result.ljust(final_width)
532
def startTestRun(self):
533
super(VerboseTestResult, self).startTestRun()
549
def report_tests_starting(self):
534
550
self.stream.write('running %d tests...\n' % self.num_tests)
551
super(VerboseTestResult, self).report_tests_starting()
536
553
def report_test_start(self, test):
538
554
name = self._shortened_test_description(test)
539
555
width = osutils.terminal_width()
540
556
if width is not None:
790
806
routine, and to build and check bzr trees.
792
808
In addition to the usual method of overriding tearDown(), this class also
793
allows subclasses to register functions into the _cleanups list, which is
809
allows subclasses to register cleanup functions via addCleanup, which are
794
810
run in order as the object is torn down. It's less likely this will be
795
811
accidentally overlooked.
798
_active_threads = None
799
_leaking_threads_tests = 0
800
_first_thread_leaker_id = None
802
815
# record lsprof data when performing benchmark calls.
803
816
_gather_lsprof_in_benchmarks = False
805
818
def __init__(self, methodName='testMethod'):
806
819
super(TestCase, self).__init__(methodName)
808
820
self._directory_isolation = True
809
821
self.exception_handlers.insert(0,
810
822
(UnavailableFeature, self._do_unsupported_or_skip))
828
840
self._track_transports()
829
841
self._track_locks()
830
842
self._clear_debug_flags()
831
TestCase._active_threads = threading.activeCount()
832
self.addCleanup(self._check_leaked_threads)
835
845
# debug a frame up.
837
847
pdb.Pdb().set_trace(sys._getframe().f_back)
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()
856
849
def _clear_debug_flags(self):
857
850
"""Prevent externally set debug flags affecting tests.
1488
1481
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))
1498
1483
def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1499
1484
"""Overrides an object attribute restoring it after the test.
2972
2957
def fork_decorator(suite):
2958
if getattr(os, "fork", None) is None:
2959
raise errors.BzrCommandError("platform does not support fork,"
2960
" try --parallel=subprocess instead.")
2973
2961
concurrency = osutils.local_concurrency()
2974
2962
if concurrency == 1:
4029
4017
new_test = copy.copy(test)
4030
4018
new_test.id = lambda: new_id
4019
# XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
4020
# causes cloned tests to share the 'details' dict. This makes it hard to
4021
# read the test output for parameterized tests, because tracebacks will be
4022
# associated with irrelevant tests.
4024
details = new_test._TestCase__details
4025
except AttributeError:
4026
# must be a different version of testtools than expected. Do nothing.
4029
# Reset the '__details' dict.
4030
new_test._TestCase__details = {}
4031
4031
return new_test