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):
279
281
what = re.sub(r'^bzrlib\.tests\.', '', what)
284
# GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
285
# multiple times in a row, because the handler is added for
286
# each test but the container list is shared between cases.
287
# See lp:498869 lp:625574 and lp:637725 for background.
288
def _record_traceback_from_test(self, exc_info):
289
"""Store the traceback from passed exc_info tuple till"""
290
self._traceback_from_test = exc_info[2]
282
292
def startTest(self, test):
283
293
super(ExtendedTestResult, self).startTest(test)
284
294
if self.count == 0:
285
295
self.startTests()
286
297
self.report_test_start(test)
287
298
test.number = self.count
288
299
self._recordTestStartTime()
300
# Make testtools cases give us the real traceback on failure
301
addOnException = getattr(test, "addOnException", None)
302
if addOnException is not None:
303
addOnException(self._record_traceback_from_test)
304
# Only check for thread leaks if the test case supports cleanups
305
addCleanup = getattr(test, "addCleanup", None)
306
if addCleanup is not None:
307
addCleanup(self._check_leaked_threads, test)
290
309
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')
310
self.report_tests_starting()
311
self._active_threads = threading.enumerate()
313
def stopTest(self, test):
314
self._traceback_from_test = None
316
def _check_leaked_threads(self, test):
317
"""See if any threads have leaked since last call
319
A sample of live threads is stored in the _active_threads attribute,
320
when this method runs it compares the current live threads and any not
321
in the previous sample are treated as having leaked.
323
now_active_threads = set(threading.enumerate())
324
threads_leaked = now_active_threads.difference(self._active_threads)
326
self._report_thread_leak(test, threads_leaked, now_active_threads)
327
self._tests_leaking_threads_count += 1
328
if self._first_thread_leaker_id is None:
329
self._first_thread_leaker_id = test.id()
330
self._active_threads = now_active_threads
309
332
def _recordTestStartTime(self):
310
333
"""Record that a test has started."""
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:
334
self._start_datetime = self._now()
320
336
def addError(self, test, err):
321
337
"""Tell result that test finished with an error.
323
339
Called from the TestCase run() method when the test
324
340
fails with an unexpected error.
342
self._post_mortem(self._traceback_from_test)
327
343
super(ExtendedTestResult, self).addError(test, err)
328
344
self.error_count += 1
329
345
self.report_error(test, err)
330
346
if self.stop_early:
332
self._cleanupLogFile(test)
334
349
def addFailure(self, test, err):
335
350
"""Tell result that test failed.
337
352
Called from the TestCase run() method when the test
338
353
fails because e.g. an assert() method failed.
355
self._post_mortem(self._traceback_from_test)
341
356
super(ExtendedTestResult, self).addFailure(test, err)
342
357
self.failure_count += 1
343
358
self.report_failure(test, err)
344
359
if self.stop_early:
346
self._cleanupLogFile(test)
348
362
def addSuccess(self, test, details=None):
349
363
"""Tell result that test completed successfully.
387
400
self.not_applicable_count += 1
388
401
self.report_not_applicable(test, reason)
390
def _post_mortem(self):
403
def _post_mortem(self, tb=None):
391
404
"""Start a PDB post mortem session."""
392
405
if os.environ.get('BZR_TEST_PDB', None):
393
import pdb;pdb.post_mortem()
395
409
def progress(self, offset, whence):
396
410
"""The test is adjusting the count of tests to run."""
402
416
raise errors.BzrError("Unknown whence %r" % whence)
404
def report_cleaning_up(self):
418
def report_tests_starting(self):
419
"""Display information before the test run begins"""
420
if getattr(sys, 'frozen', None) is None:
421
bzr_path = osutils.realpath(sys.argv[0])
423
bzr_path = sys.executable
425
'bzr selftest: %s\n' % (bzr_path,))
428
bzrlib.__path__[0],))
430
' bzr-%s python-%s %s\n' % (
431
bzrlib.version_string,
432
bzrlib._format_version_tuple(sys.version_info),
433
platform.platform(aliased=1),
435
self.stream.write('\n')
437
def report_test_start(self, test):
438
"""Display information on the test just about to be run"""
440
def _report_thread_leak(self, test, leaked_threads, active_threads):
441
"""Display information on a test that leaked one or more threads"""
442
# GZ 2010-09-09: A leak summary reported separately from the general
443
# thread debugging would be nice. Tests under subunit
444
# need something not using stream, perhaps adding a
445
# testtools details object would be fitting.
446
if 'threads' in selftest_debug_flags:
447
self.stream.write('%s is leaking, active is now %d\n' %
448
(test.id(), len(active_threads)))
407
450
def startTestRun(self):
408
451
self.startTime = time.time()
445
488
self.pb.finished()
446
489
super(TextTestResult, self).stopTestRun()
448
def startTestRun(self):
449
super(TextTestResult, self).startTestRun()
491
def report_tests_starting(self):
492
super(TextTestResult, self).report_tests_starting()
450
493
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
495
def _progress_prefix_text(self):
458
496
# the longer this text, the less space we have to show the test
790
823
routine, and to build and check bzr trees.
792
825
In addition to the usual method of overriding tearDown(), this class also
793
allows subclasses to register functions into the _cleanups list, which is
826
allows subclasses to register cleanup functions via addCleanup, which are
794
827
run in order as the object is torn down. It's less likely this will be
795
828
accidentally overlooked.
798
_active_threads = None
799
_leaking_threads_tests = 0
800
_first_thread_leaker_id = None
802
832
# record lsprof data when performing benchmark calls.
803
833
_gather_lsprof_in_benchmarks = False
805
835
def __init__(self, methodName='testMethod'):
806
836
super(TestCase, self).__init__(methodName)
808
837
self._directory_isolation = True
809
838
self.exception_handlers.insert(0,
810
839
(UnavailableFeature, self._do_unsupported_or_skip))
828
857
self._track_transports()
829
858
self._track_locks()
830
859
self._clear_debug_flags()
831
TestCase._active_threads = threading.activeCount()
832
self.addCleanup(self._check_leaked_threads)
860
# Isolate global verbosity level, to make sure it's reproducible
861
# between tests. We should get rid of this altogether: bug 656694. --
863
self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
835
866
# debug a frame up.
837
868
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()
870
def discardDetail(self, name):
871
"""Extend the addDetail, getDetails api so we can remove a detail.
873
eg. bzr always adds the 'log' detail at startup, but we don't want to
874
include it for skipped, xfail, etc tests.
876
It is safe to call this for a detail that doesn't exist, in case this
877
gets called multiple times.
879
# We cheat. details is stored in __details which means we shouldn't
880
# touch it. but getDetails() returns the dict directly, so we can
882
details = self.getDetails()
856
886
def _clear_debug_flags(self):
857
887
"""Prevent externally set debug flags affecting tests.
869
899
def _clear_hooks(self):
870
900
# prevent hooks affecting tests
901
known_hooks = hooks.known_hooks
871
902
self._preserved_hooks = {}
872
for key, factory in hooks.known_hooks.items():
873
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
874
current_hooks = hooks.known_hooks_key_to_object(key)
903
for key, (parent, name) in known_hooks.iter_parent_objects():
904
current_hooks = getattr(parent, name)
875
905
self._preserved_hooks[parent] = (name, current_hooks)
876
906
self.addCleanup(self._restoreHooks)
877
for key, factory in hooks.known_hooks.items():
878
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
907
for key, (parent, name) in known_hooks.iter_parent_objects():
908
factory = known_hooks.get(key)
879
909
setattr(parent, name, factory())
880
910
# this hook should always be installed
881
911
request._install_hook()
1488
1518
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
1520
def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1499
1521
"""Overrides an object attribute restoring it after the test.
1613
1642
self._do_skip(result, reason)
1645
def _report_skip(self, result, err):
1646
"""Override the default _report_skip.
1648
We want to strip the 'log' detail. If we waint until _do_skip, it has
1649
already been formatted into the 'reason' string, and we can't pull it
1652
self._suppress_log()
1653
super(TestCase, self)._report_skip(self, result, err)
1656
def _report_expected_failure(self, result, err):
1659
See _report_skip for motivation.
1661
self._suppress_log()
1662
super(TestCase, self)._report_expected_failure(self, result, err)
1616
1665
def _do_unsupported_or_skip(self, result, e):
1617
1666
reason = e.args[0]
1667
self._suppress_log()
1618
1668
addNotSupported = getattr(result, 'addNotSupported', None)
1619
1669
if addNotSupported is not None:
1620
1670
result.addNotSupported(self, reason)
3302
class ForwardingResult(unittest.TestResult):
3304
def __init__(self, target):
3305
unittest.TestResult.__init__(self)
3306
self.result = target
3308
def startTest(self, test):
3309
self.result.startTest(test)
3311
def stopTest(self, test):
3312
self.result.stopTest(test)
3314
def startTestRun(self):
3315
self.result.startTestRun()
3317
def stopTestRun(self):
3318
self.result.stopTestRun()
3320
def addSkip(self, test, reason):
3321
self.result.addSkip(test, reason)
3323
def addSuccess(self, test):
3324
self.result.addSuccess(test)
3326
def addError(self, test, err):
3327
self.result.addError(test, err)
3329
def addFailure(self, test, err):
3330
self.result.addFailure(test, err)
3331
ForwardingResult = testtools.ExtendedToOriginalDecorator
3334
class ProfileResult(ForwardingResult):
3355
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3335
3356
"""Generate profiling data for all activity between start and success.
3337
3358
The profile data is appended to the test's _benchcalls attribute and can
3939
def multiply_scenarios(scenarios_left, scenarios_right):
3964
def multiply_scenarios(*scenarios):
3965
"""Multiply two or more iterables of scenarios.
3967
It is safe to pass scenario generators or iterators.
3969
:returns: A list of compound scenarios: the cross-product of all
3970
scenarios, with the names concatenated and the parameters
3973
return reduce(_multiply_two_scenarios, map(list, scenarios))
3976
def _multiply_two_scenarios(scenarios_left, scenarios_right):
3940
3977
"""Multiply two sets of scenarios.
3942
3979
:returns: the cartesian product of the two sets of scenarios, that is
4029
4066
new_test = copy.copy(test)
4030
4067
new_test.id = lambda: new_id
4068
# XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
4069
# causes cloned tests to share the 'details' dict. This makes it hard to
4070
# read the test output for parameterized tests, because tracebacks will be
4071
# associated with irrelevant tests.
4073
details = new_test._TestCase__details
4074
except AttributeError:
4075
# must be a different version of testtools than expected. Do nothing.
4078
# Reset the '__details' dict.
4079
new_test._TestCase__details = {}
4031
4080
return new_test
4213
4262
symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4214
4263
# Import the new feature and use it as a replacement for the
4215
4264
# deprecated one.
4216
mod = __import__(self._replacement_module, {}, {},
4217
[self._replacement_name])
4218
self._feature = getattr(mod, self._replacement_name)
4265
self._feature = pyutils.get_named_object(
4266
self._replacement_module, self._replacement_name)
4220
4268
def _probe(self):
4460
4508
from subunit import TestProtocolClient
4461
4509
from subunit.test_results import AutoTimingTestResultDecorator
4510
class SubUnitBzrProtocolClient(TestProtocolClient):
4512
def addSuccess(self, test, details=None):
4513
# The subunit client always includes the details in the subunit
4514
# stream, but we don't want to include it in ours.
4515
if details is not None and 'log' in details:
4517
return super(SubUnitBzrProtocolClient, self).addSuccess(
4462
4520
class SubUnitBzrRunner(TextTestRunner):
4463
4521
def run(self, test):
4464
4522
result = AutoTimingTestResultDecorator(
4465
TestProtocolClient(self.stream))
4523
SubUnitBzrProtocolClient(self.stream))
4466
4524
test.run(result)
4468
4526
except ImportError: