134
135
SUBUNIT_SEEK_SET = 0
135
136
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
142
139
class ExtendedTestResult(testtools.TextTestResult):
143
140
"""Accepts, reports and accumulates the results of running tests.
239
234
ok = self.wasStrictlySuccessful()
241
236
ok = self.wasSuccessful()
242
if self._first_thread_leaker_id:
237
if TestCase._first_thread_leaker_id:
243
238
self.stream.write(
244
239
'%s is leaking threads among %d leaking tests.\n' % (
245
self._first_thread_leaker_id,
246
self._tests_leaking_threads_count))
240
TestCase._first_thread_leaker_id,
241
TestCase._leaking_threads_tests))
247
242
# We don't report the main thread as an active one.
248
243
self.stream.write(
249
244
'%d non-main threads were left active in the end.\n'
250
% (len(self._active_threads) - 1))
245
% (TestCase._active_threads - 1))
252
247
def getDescription(self, test):
284
279
super(ExtendedTestResult, self).startTest(test)
285
280
if self.count == 0:
286
281
self.startTests()
288
282
self.report_test_start(test)
289
283
test.number = self.count
290
284
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
286
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
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')
316
305
def _recordTestStartTime(self):
317
306
"""Record that a test has started."""
318
307
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:
320
316
def addError(self, test, err):
321
317
"""Tell result that test finished with an error.
399
398
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)))
400
def report_cleaning_up(self):
433
403
def startTestRun(self):
434
404
self.startTime = time.time()
471
441
self.pb.finished()
472
442
super(TextTestResult, self).stopTestRun()
474
def report_tests_starting(self):
475
super(TextTestResult, self).report_tests_starting()
444
def startTestRun(self):
445
super(TextTestResult, self).startTestRun()
476
446
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()
478
453
def _progress_prefix_text(self):
479
454
# the longer this text, the less space we have to show the test
534
510
def report_unsupported(self, test, feature):
535
511
"""test cannot be run because feature is missing."""
513
def report_cleaning_up(self):
514
self.pb.update('Cleaning up')
538
517
class VerboseTestResult(ExtendedTestResult):
539
518
"""Produce long output, with one line per test run plus times"""
546
525
result = a_string
547
526
return result.ljust(final_width)
549
def report_tests_starting(self):
528
def startTestRun(self):
529
super(VerboseTestResult, self).startTestRun()
550
530
self.stream.write('running %d tests...\n' % self.num_tests)
551
super(VerboseTestResult, self).report_tests_starting()
553
532
def report_test_start(self, test):
554
534
name = self._shortened_test_description(test)
555
535
width = osutils.terminal_width()
556
536
if width is not None:
806
786
routine, and to build and check bzr trees.
808
788
In addition to the usual method of overriding tearDown(), this class also
809
allows subclasses to register cleanup functions via addCleanup, which are
789
allows subclasses to register functions into the _cleanups list, which is
810
790
run in order as the object is torn down. It's less likely this will be
811
791
accidentally overlooked.
794
_active_threads = None
795
_leaking_threads_tests = 0
796
_first_thread_leaker_id = None
797
_log_file_name = None
815
798
# record lsprof data when performing benchmark calls.
816
799
_gather_lsprof_in_benchmarks = False
818
801
def __init__(self, methodName='testMethod'):
819
802
super(TestCase, self).__init__(methodName)
820
804
self._directory_isolation = True
821
805
self.exception_handlers.insert(0,
822
806
(UnavailableFeature, self._do_unsupported_or_skip))
840
824
self._track_transports()
841
825
self._track_locks()
842
826
self._clear_debug_flags()
827
TestCase._active_threads = threading.activeCount()
828
self.addCleanup(self._check_leaked_threads)
845
831
# debug a frame up.
847
833
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()
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()
865
852
def _clear_debug_flags(self):
866
853
"""Prevent externally set debug flags affecting tests.
1468
1455
The file is removed as the test is torn down.
1470
self._log_file = StringIO()
1457
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
1458
self._log_file = os.fdopen(fileno, 'w+')
1471
1459
self._log_memento = bzrlib.trace.push_log_file(self._log_file)
1460
self._log_file_name = name
1472
1461
self.addCleanup(self._finishLogFile)
1474
1463
def _finishLogFile(self):
1497
1486
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))
1499
1496
def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1500
1497
"""Overrides an object attribute restoring it after the test.
1585
1582
"""This test has failed for some known reason."""
1586
1583
raise KnownFailure(reason)
1588
def _suppress_log(self):
1589
"""Remove the log info from details."""
1590
self.discardDetail('log')
1592
1585
def _do_skip(self, result, reason):
1593
self._suppress_log()
1594
1586
addSkip = getattr(result, 'addSkip', None)
1595
1587
if not callable(addSkip):
1596
1588
result.addSuccess(result)
1621
1611
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
1614
def _do_unsupported_or_skip(self, result, e):
1645
1615
reason = e.args[0]
1646
self._suppress_log()
1647
1616
addNotSupported = getattr(result, 'addNotSupported', None)
1648
1617
if addNotSupported is not None:
1649
1618
result.addNotSupported(self, reason)
1696
1665
unicodestr = self._log_contents.decode('utf8', 'replace')
1697
1666
self._log_contents = unicodestr.encode('utf8')
1698
1667
return self._log_contents
1699
if self._log_file is not None:
1700
log_contents = self._log_file.getvalue()
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()
1702
1679
log_contents.decode('utf8')
1703
1680
except UnicodeDecodeError:
1704
1681
unicodestr = log_contents.decode('utf8', 'replace')
1705
1682
log_contents = unicodestr.encode('utf8')
1706
1683
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,))
1707
1711
self._log_file = None
1708
1712
# Permit multiple calls to get_log until we clean it up in
1709
1713
# finishLogFile
1710
1714
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
1711
1724
return log_contents
1713
return "No log file content."
1726
return "No log file content and no log file name."
1715
1728
def get_log(self):
1716
1729
"""Get a unicode string containing the log from bzrlib.trace.
1931
1944
variables. A value of None will unset the env variable.
1932
1945
The values must be strings. The change will only occur in the
1933
1946
child, so you don't need to fix the environment after running.
1934
:param skip_if_plan_to_signal: raise TestSkipped when true and system
1935
doesn't support signalling subprocesses.
1947
:param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
1936
1949
:param allow_plugins: If False (default) pass --no-plugins to bzr.
1938
1951
:returns: Popen object for the started process.
1940
1953
if skip_if_plan_to_signal:
1941
if os.name != "posix":
1942
raise TestSkipped("Sending signals not supported")
1954
if not getattr(os, 'kill', None):
1955
raise TestSkipped("os.kill not available.")
1944
1957
if env_changes is None:
1945
1958
env_changes = {}
3001
3014
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
3015
concurrency = osutils.local_concurrency()
3006
3016
if concurrency == 1:
3648
3658
'bzrlib.tests.commands',
3649
3659
'bzrlib.tests.doc_generate',
3650
3660
'bzrlib.tests.per_branch',
3651
'bzrlib.tests.per_bzrdir',
3652
3661
'bzrlib.tests.per_controldir',
3653
3662
'bzrlib.tests.per_controldir_colo',
3654
3663
'bzrlib.tests.per_foreign_vcs',
4061
4070
new_test = copy.copy(test)
4062
4071
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
4072
return new_test
4504
4501
from subunit import TestProtocolClient
4505
4502
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
4503
class SubUnitBzrRunner(TextTestRunner):
4517
4504
def run(self, test):
4518
4505
result = AutoTimingTestResultDecorator(
4519
SubUnitBzrProtocolClient(self.stream))
4506
TestProtocolClient(self.stream))
4520
4507
test.run(result)
4522
4509
except ImportError: