56
56
# nb: check this before importing anything else from within it
57
57
_testtools_version = getattr(testtools, '__version__', ())
58
if _testtools_version < (0, 9, 2):
59
raise ImportError("need at least testtools 0.9.2: %s is %r"
58
if _testtools_version < (0, 9, 5):
59
raise ImportError("need at least testtools 0.9.5: %s is %r"
60
60
% (testtools.__file__, _testtools_version))
61
61
from testtools import content
63
64
from bzrlib import (
68
commands as _mod_commands,
77
plugin as _mod_plugin,
78
84
transport as _mod_transport,
82
import bzrlib.commands
83
import bzrlib.timestamp
85
import bzrlib.inventory
86
import bzrlib.iterablefile
89
88
import bzrlib.lsprof
90
89
except ImportError:
91
90
# lsprof not available
93
from bzrlib.merge import merge_inner
96
from bzrlib.smart import client, request, server
98
from bzrlib import symbol_versioning
99
from bzrlib.symbol_versioning import (
100
DEPRECATED_PARAMETER,
92
from bzrlib.smart import client, request
107
93
from bzrlib.transport import (
111
from bzrlib.trace import mutter, note
112
97
from bzrlib.tests import (
135
118
SUBUNIT_SEEK_SET = 0
136
119
SUBUNIT_SEEK_CUR = 1
121
# These are intentionally brought into this namespace. That way plugins, etc
122
# can just "from bzrlib.tests import TestCase, TestLoader, etc"
123
TestSuite = TestUtil.TestSuite
124
TestLoader = TestUtil.TestLoader
126
# Tests should run in a clean and clearly defined environment. The goal is to
127
# keep them isolated from the running environment as mush as possible. The test
128
# framework ensures the variables defined below are set (or deleted if the
129
# value is None) before a test is run and reset to their original value after
130
# the test is run. Generally if some code depends on an environment variable,
131
# the tests should start without this variable in the environment. There are a
132
# few exceptions but you shouldn't violate this rule lightly.
136
# bzr now uses the Win32 API and doesn't rely on APPDATA, but the
137
# tests do check our impls match APPDATA
138
'BZR_EDITOR': None, # test_msgeditor manipulates this variable
142
'BZREMAIL': None, # may still be present in the environment
143
'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
144
'BZR_PROGRESS_BAR': None,
146
'BZR_PLUGIN_PATH': None,
147
'BZR_DISABLE_PLUGINS': None,
148
'BZR_PLUGINS_AT': None,
149
'BZR_CONCURRENCY': None,
150
# Make sure that any text ui tests are consistent regardless of
151
# the environment the test case is run in; you may want tests that
152
# test other combinations. 'dumb' is a reasonable guess for tests
153
# going to a pipe or a StringIO.
159
'SSH_AUTH_SOCK': None,
169
# Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
170
# least. If you do (care), please update this comment
174
'BZR_REMOTE_PATH': None,
175
# Generally speaking, we don't want apport reporting on crashes in
176
# the test envirnoment unless we're specifically testing apport,
177
# so that it doesn't leak into the real system environment. We
178
# use an env var so it propagates to subprocesses.
179
'APPORT_DISABLE': '1',
183
def override_os_environ(test, env=None):
184
"""Modify os.environ keeping a copy.
186
:param test: A test instance
188
:param env: A dict containing variable definitions to be installed
191
env = isolated_environ
192
test._original_os_environ = dict([(var, value)
193
for var, value in os.environ.iteritems()])
194
for var, value in env.iteritems():
195
osutils.set_or_unset_env(var, value)
196
if var not in test._original_os_environ:
197
# The var is new, add it with a value of None, so
198
# restore_os_environ will delete it
199
test._original_os_environ[var] = None
202
def restore_os_environ(test):
203
"""Restore os.environ to its original state.
205
:param test: A test instance previously passed to override_os_environ.
207
for var, value in test._original_os_environ.iteritems():
208
# Restore the original value (or delete it if the value has been set to
209
# None in override_os_environ).
210
osutils.set_or_unset_env(var, value)
139
213
class ExtendedTestResult(testtools.TextTestResult):
140
214
"""Accepts, reports and accumulates the results of running tests.
234
311
ok = self.wasStrictlySuccessful()
236
313
ok = self.wasSuccessful()
237
if TestCase._first_thread_leaker_id:
314
if self._first_thread_leaker_id:
238
315
self.stream.write(
239
316
'%s is leaking threads among %d leaking tests.\n' % (
240
TestCase._first_thread_leaker_id,
241
TestCase._leaking_threads_tests))
317
self._first_thread_leaker_id,
318
self._tests_leaking_threads_count))
242
319
# We don't report the main thread as an active one.
243
320
self.stream.write(
244
321
'%d non-main threads were left active in the end.\n'
245
% (TestCase._active_threads - 1))
322
% (len(self._active_threads) - 1))
247
324
def getDescription(self, test):
275
353
what = re.sub(r'^bzrlib\.tests\.', '', what)
356
# GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
357
# multiple times in a row, because the handler is added for
358
# each test but the container list is shared between cases.
359
# See lp:498869 lp:625574 and lp:637725 for background.
360
def _record_traceback_from_test(self, exc_info):
361
"""Store the traceback from passed exc_info tuple till"""
362
self._traceback_from_test = exc_info[2]
278
364
def startTest(self, test):
279
365
super(ExtendedTestResult, self).startTest(test)
280
366
if self.count == 0:
281
367
self.startTests()
282
369
self.report_test_start(test)
283
370
test.number = self.count
284
371
self._recordTestStartTime()
372
# Make testtools cases give us the real traceback on failure
373
addOnException = getattr(test, "addOnException", None)
374
if addOnException is not None:
375
addOnException(self._record_traceback_from_test)
376
# Only check for thread leaks on bzrlib derived test cases
377
if isinstance(test, TestCase):
378
test.addCleanup(self._check_leaked_threads, test)
286
380
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')
381
self.report_tests_starting()
382
self._active_threads = threading.enumerate()
384
def stopTest(self, test):
385
self._traceback_from_test = None
387
def _check_leaked_threads(self, test):
388
"""See if any threads have leaked since last call
390
A sample of live threads is stored in the _active_threads attribute,
391
when this method runs it compares the current live threads and any not
392
in the previous sample are treated as having leaked.
394
now_active_threads = set(threading.enumerate())
395
threads_leaked = now_active_threads.difference(self._active_threads)
397
self._report_thread_leak(test, threads_leaked, now_active_threads)
398
self._tests_leaking_threads_count += 1
399
if self._first_thread_leaker_id is None:
400
self._first_thread_leaker_id = test.id()
401
self._active_threads = now_active_threads
305
403
def _recordTestStartTime(self):
306
404
"""Record that a test has started."""
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:
405
self._start_datetime = self._now()
316
407
def addError(self, test, err):
317
408
"""Tell result that test finished with an error.
398
487
raise errors.BzrError("Unknown whence %r" % whence)
400
def report_cleaning_up(self):
489
def report_tests_starting(self):
490
"""Display information before the test run begins"""
491
if getattr(sys, 'frozen', None) is None:
492
bzr_path = osutils.realpath(sys.argv[0])
494
bzr_path = sys.executable
496
'bzr selftest: %s\n' % (bzr_path,))
499
bzrlib.__path__[0],))
501
' bzr-%s python-%s %s\n' % (
502
bzrlib.version_string,
503
bzrlib._format_version_tuple(sys.version_info),
504
platform.platform(aliased=1),
506
self.stream.write('\n')
508
def report_test_start(self, test):
509
"""Display information on the test just about to be run"""
511
def _report_thread_leak(self, test, leaked_threads, active_threads):
512
"""Display information on a test that leaked one or more threads"""
513
# GZ 2010-09-09: A leak summary reported separately from the general
514
# thread debugging would be nice. Tests under subunit
515
# need something not using stream, perhaps adding a
516
# testtools details object would be fitting.
517
if 'threads' in selftest_debug_flags:
518
self.stream.write('%s is leaking, active is now %d\n' %
519
(test.id(), len(active_threads)))
403
521
def startTestRun(self):
404
522
self.startTime = time.time()
441
559
self.pb.finished()
442
560
super(TextTestResult, self).stopTestRun()
444
def startTestRun(self):
445
super(TextTestResult, self).startTestRun()
562
def report_tests_starting(self):
563
super(TextTestResult, self).report_tests_starting()
446
564
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
566
def _progress_prefix_text(self):
454
567
# the longer this text, the less space we have to show the test
770
881
return NullProgressView()
884
def isolated_doctest_setUp(test):
885
override_os_environ(test)
888
def isolated_doctest_tearDown(test):
889
restore_os_environ(test)
892
def IsolatedDocTestSuite(*args, **kwargs):
893
"""Overrides doctest.DocTestSuite to handle isolation.
895
The method is really a factory and users are expected to use it as such.
898
kwargs['setUp'] = isolated_doctest_setUp
899
kwargs['tearDown'] = isolated_doctest_tearDown
900
return doctest.DocTestSuite(*args, **kwargs)
773
903
class TestCase(testtools.TestCase):
774
904
"""Base class for bzr unit tests.
786
916
routine, and to build and check bzr trees.
788
918
In addition to the usual method of overriding tearDown(), this class also
789
allows subclasses to register functions into the _cleanups list, which is
919
allows subclasses to register cleanup functions via addCleanup, which are
790
920
run in order as the object is torn down. It's less likely this will be
791
921
accidentally overlooked.
794
_active_threads = None
795
_leaking_threads_tests = 0
796
_first_thread_leaker_id = None
797
_log_file_name = None
798
925
# record lsprof data when performing benchmark calls.
799
926
_gather_lsprof_in_benchmarks = False
801
928
def __init__(self, methodName='testMethod'):
802
929
super(TestCase, self).__init__(methodName)
804
930
self._directory_isolation = True
805
931
self.exception_handlers.insert(0,
806
932
(UnavailableFeature, self._do_unsupported_or_skip))
824
950
self._track_transports()
825
951
self._track_locks()
826
952
self._clear_debug_flags()
827
TestCase._active_threads = threading.activeCount()
828
self.addCleanup(self._check_leaked_threads)
953
# Isolate global verbosity level, to make sure it's reproducible
954
# between tests. We should get rid of this altogether: bug 656694. --
956
self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
957
# Isolate config option expansion until its default value for bzrlib is
958
# settled on or a the FIXME associated with _get_expand_default_value
959
# is addressed -- vila 20110219
960
self.overrideAttr(config, '_expand_default_value', None)
831
963
# debug a frame up.
833
965
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()
967
def discardDetail(self, name):
968
"""Extend the addDetail, getDetails api so we can remove a detail.
970
eg. bzr always adds the 'log' detail at startup, but we don't want to
971
include it for skipped, xfail, etc tests.
973
It is safe to call this for a detail that doesn't exist, in case this
974
gets called multiple times.
976
# We cheat. details is stored in __details which means we shouldn't
977
# touch it. but getDetails() returns the dict directly, so we can
979
details = self.getDetails()
852
983
def _clear_debug_flags(self):
853
984
"""Prevent externally set debug flags affecting tests.
865
996
def _clear_hooks(self):
866
997
# prevent hooks affecting tests
998
known_hooks = hooks.known_hooks
867
999
self._preserved_hooks = {}
868
for key, factory in hooks.known_hooks.items():
869
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
870
current_hooks = hooks.known_hooks_key_to_object(key)
1000
for key, (parent, name) in known_hooks.iter_parent_objects():
1001
current_hooks = getattr(parent, name)
871
1002
self._preserved_hooks[parent] = (name, current_hooks)
1003
self._preserved_lazy_hooks = hooks._lazy_hooks
1004
hooks._lazy_hooks = {}
872
1005
self.addCleanup(self._restoreHooks)
873
for key, factory in hooks.known_hooks.items():
874
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
1006
for key, (parent, name) in known_hooks.iter_parent_objects():
1007
factory = known_hooks.get(key)
875
1008
setattr(parent, name, factory())
876
1009
# this hook should always be installed
877
1010
request._install_hook()
1134
1267
'st_mtime did not match')
1135
1268
self.assertEqual(expected.st_ctime, actual.st_ctime,
1136
1269
'st_ctime did not match')
1137
if sys.platform != 'win32':
1270
if sys.platform == 'win32':
1138
1271
# On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1139
1272
# is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
1140
# odd. Regardless we shouldn't actually try to assert anything
1141
# about their values
1273
# odd. We just force it to always be 0 to avoid any problems.
1274
self.assertEqual(0, expected.st_dev)
1275
self.assertEqual(0, actual.st_dev)
1276
self.assertEqual(0, expected.st_ino)
1277
self.assertEqual(0, actual.st_ino)
1142
1279
self.assertEqual(expected.st_dev, actual.st_dev,
1143
1280
'st_dev did not match')
1144
1281
self.assertEqual(expected.st_ino, actual.st_ino,
1210
1346
if haystack.find(needle) == -1:
1211
1347
self.fail("string %r not found in '''%s'''" % (needle, haystack))
1349
def assertNotContainsString(self, haystack, needle):
1350
if haystack.find(needle) != -1:
1351
self.fail("string %r found in '''%s'''" % (needle, haystack))
1213
1353
def assertSubset(self, sublist, superlist):
1214
1354
"""Assert that every entry in sublist is present in superlist."""
1215
1355
missing = set(sublist) - set(superlist)
1321
1461
self.assertEqual(expected_docstring, obj.__doc__)
1463
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1323
1464
def failUnlessExists(self, path):
1465
return self.assertPathExists(path)
1467
def assertPathExists(self, path):
1324
1468
"""Fail unless path or paths, which may be abs or relative, exist."""
1325
1469
if not isinstance(path, basestring):
1327
self.failUnlessExists(p)
1471
self.assertPathExists(p)
1329
self.failUnless(osutils.lexists(path),path+" does not exist")
1473
self.assertTrue(osutils.lexists(path),
1474
path + " does not exist")
1476
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1331
1477
def failIfExists(self, path):
1478
return self.assertPathDoesNotExist(path)
1480
def assertPathDoesNotExist(self, path):
1332
1481
"""Fail if path or paths, which may be abs or relative, exist."""
1333
1482
if not isinstance(path, basestring):
1335
self.failIfExists(p)
1484
self.assertPathDoesNotExist(p)
1337
self.failIf(osutils.lexists(path),path+" exists")
1486
self.assertFalse(osutils.lexists(path),
1339
1489
def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
1340
1490
"""A helper for callDeprecated and applyDeprecated.
1455
1605
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+')
1459
self._log_memento = bzrlib.trace.push_log_file(self._log_file)
1460
self._log_file_name = name
1607
self._log_file = StringIO()
1608
self._log_memento = trace.push_log_file(self._log_file)
1461
1609
self.addCleanup(self._finishLogFile)
1463
1611
def _finishLogFile(self):
1486
1634
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
1636
def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1497
1637
"""Overrides an object attribute restoring it after the test.
1512
1652
setattr(obj, attr_name, new)
1655
def overrideEnv(self, name, new):
1656
"""Set an environment variable, and reset it after the test.
1658
:param name: The environment variable name.
1660
:param new: The value to set the variable to. If None, the
1661
variable is deleted from the environment.
1663
:returns: The actual variable value.
1665
value = osutils.set_or_unset_env(name, new)
1666
self.addCleanup(osutils.set_or_unset_env, name, value)
1515
1669
def _cleanEnvironment(self):
1517
'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
1518
'HOME': os.getcwd(),
1519
# bzr now uses the Win32 API and doesn't rely on APPDATA, but the
1520
# tests do check our impls match APPDATA
1521
'BZR_EDITOR': None, # test_msgeditor manipulates this variable
1525
'BZREMAIL': None, # may still be present in the environment
1526
'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
1527
'BZR_PROGRESS_BAR': None,
1529
'BZR_PLUGIN_PATH': None,
1530
'BZR_DISABLE_PLUGINS': None,
1531
'BZR_PLUGINS_AT': None,
1532
'BZR_CONCURRENCY': None,
1533
# Make sure that any text ui tests are consistent regardless of
1534
# the environment the test case is run in; you may want tests that
1535
# test other combinations. 'dumb' is a reasonable guess for tests
1536
# going to a pipe or a StringIO.
1540
'BZR_COLUMNS': '80',
1542
'SSH_AUTH_SOCK': None,
1546
'https_proxy': None,
1547
'HTTPS_PROXY': None,
1552
# Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
1553
# least. If you do (care), please update this comment
1557
'BZR_REMOTE_PATH': None,
1558
# Generally speaking, we don't want apport reporting on crashes in
1559
# the test envirnoment unless we're specifically testing apport,
1560
# so that it doesn't leak into the real system environment. We
1561
# use an env var so it propagates to subprocesses.
1562
'APPORT_DISABLE': '1',
1565
self.addCleanup(self._restoreEnvironment)
1566
for name, value in new_env.iteritems():
1567
self._captureVar(name, value)
1569
def _captureVar(self, name, newvalue):
1570
"""Set an environment variable, and reset it when finished."""
1571
self._old_env[name] = osutils.set_or_unset_env(name, newvalue)
1573
def _restoreEnvironment(self):
1574
for name, value in self._old_env.iteritems():
1575
osutils.set_or_unset_env(name, value)
1670
for name, value in isolated_environ.iteritems():
1671
self.overrideEnv(name, value)
1577
1673
def _restoreHooks(self):
1578
1674
for klass, (name, hooks) in self._preserved_hooks.items():
1579
1675
setattr(klass, name, hooks)
1676
hooks._lazy_hooks = self._preserved_lazy_hooks
1581
1678
def knownFailure(self, reason):
1582
1679
"""This test has failed for some known reason."""
1583
1680
raise KnownFailure(reason)
1682
def _suppress_log(self):
1683
"""Remove the log info from details."""
1684
self.discardDetail('log')
1585
1686
def _do_skip(self, result, reason):
1687
self._suppress_log()
1586
1688
addSkip = getattr(result, 'addSkip', None)
1587
1689
if not callable(addSkip):
1588
1690
result.addSuccess(result)
1611
1715
self._do_skip(result, reason)
1718
def _report_skip(self, result, err):
1719
"""Override the default _report_skip.
1721
We want to strip the 'log' detail. If we waint until _do_skip, it has
1722
already been formatted into the 'reason' string, and we can't pull it
1725
self._suppress_log()
1726
super(TestCase, self)._report_skip(self, result, err)
1729
def _report_expected_failure(self, result, err):
1732
See _report_skip for motivation.
1734
self._suppress_log()
1735
super(TestCase, self)._report_expected_failure(self, result, err)
1614
1738
def _do_unsupported_or_skip(self, result, e):
1615
1739
reason = e.args[0]
1740
self._suppress_log()
1616
1741
addNotSupported = getattr(result, 'addNotSupported', None)
1617
1742
if addNotSupported is not None:
1618
1743
result.addNotSupported(self, reason)
1665
1790
unicodestr = self._log_contents.decode('utf8', 'replace')
1666
1791
self._log_contents = unicodestr.encode('utf8')
1667
1792
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()
1793
if self._log_file is not None:
1794
log_contents = self._log_file.getvalue()
1679
1796
log_contents.decode('utf8')
1680
1797
except UnicodeDecodeError:
1681
1798
unicodestr = log_contents.decode('utf8', 'replace')
1682
1799
log_contents = unicodestr.encode('utf8')
1683
1800
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
1801
self._log_file = None
1712
1802
# Permit multiple calls to get_log until we clean it up in
1713
1803
# finishLogFile
1714
1804
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
1805
return log_contents
1726
return "No log file content and no log file name."
1807
return "No log file content."
1728
1809
def get_log(self):
1729
1810
"""Get a unicode string containing the log from bzrlib.trace.
1944
2026
variables. A value of None will unset the env variable.
1945
2027
The values must be strings. The change will only occur in the
1946
2028
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
2029
:param skip_if_plan_to_signal: raise TestSkipped when true and system
2030
doesn't support signalling subprocesses.
1949
2031
:param allow_plugins: If False (default) pass --no-plugins to bzr.
1951
2033
:returns: Popen object for the started process.
1953
2035
if skip_if_plan_to_signal:
1954
if not getattr(os, 'kill', None):
1955
raise TestSkipped("os.kill not available.")
2036
if os.name != "posix":
2037
raise TestSkipped("Sending signals not supported")
1957
2039
if env_changes is None:
1958
2040
env_changes = {}
2037
2119
if retcode is not None and retcode != process.returncode:
2038
2120
if process_args is None:
2039
2121
process_args = "(unknown args)"
2040
mutter('Output of bzr %s:\n%s', process_args, out)
2041
mutter('Error for bzr %s:\n%s', process_args, err)
2122
trace.mutter('Output of bzr %s:\n%s', process_args, out)
2123
trace.mutter('Error for bzr %s:\n%s', process_args, err)
2042
2124
self.fail('Command bzr %s failed with retcode %s != %s'
2043
2125
% (process_args, retcode, process.returncode))
2044
2126
return [out, err]
2046
def check_inventory_shape(self, inv, shape):
2047
"""Compare an inventory to a list of expected names.
2128
def check_tree_shape(self, tree, shape):
2129
"""Compare a tree to a list of expected names.
2049
2131
Fail if they are not precisely equal.
2052
2134
shape = list(shape) # copy
2053
for path, ie in inv.entries():
2135
for path, ie in tree.iter_entries_by_dir():
2054
2136
name = path.replace('\\', '/')
2055
2137
if ie.kind == 'directory':
2056
2138
name = name + '/'
2140
pass # ignore root entry
2058
2142
shape.remove(name)
2060
2144
extras.append(name)
3344
class ForwardingResult(unittest.TestResult):
3346
def __init__(self, target):
3347
unittest.TestResult.__init__(self)
3348
self.result = target
3350
def startTest(self, test):
3351
self.result.startTest(test)
3353
def stopTest(self, test):
3354
self.result.stopTest(test)
3356
def startTestRun(self):
3357
self.result.startTestRun()
3359
def stopTestRun(self):
3360
self.result.stopTestRun()
3362
def addSkip(self, test, reason):
3363
self.result.addSkip(test, reason)
3365
def addSuccess(self, test):
3366
self.result.addSuccess(test)
3368
def addError(self, test, err):
3369
self.result.addError(test, err)
3371
def addFailure(self, test, err):
3372
self.result.addFailure(test, err)
3373
ForwardingResult = testtools.ExtendedToOriginalDecorator
3376
class ProfileResult(ForwardingResult):
3431
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3377
3432
"""Generate profiling data for all activity between start and success.
3379
3434
The profile data is appended to the test's _benchcalls attribute and can
3712
3770
'bzrlib.tests.test_commit_merge',
3713
3771
'bzrlib.tests.test_config',
3714
3772
'bzrlib.tests.test_conflicts',
3773
'bzrlib.tests.test_controldir',
3715
3774
'bzrlib.tests.test_counted_lock',
3716
3775
'bzrlib.tests.test_crash',
3717
3776
'bzrlib.tests.test_decorators',
3718
3777
'bzrlib.tests.test_delta',
3719
3778
'bzrlib.tests.test_debug',
3720
'bzrlib.tests.test_deprecated_graph',
3721
3779
'bzrlib.tests.test_diff',
3722
3780
'bzrlib.tests.test_directory_service',
3723
3781
'bzrlib.tests.test_dirstate',
3970
4033
# Some tests mentioned in the list are not in the test suite. The
3971
4034
# list may be out of date, report to the tester.
3972
4035
for id in not_found:
3973
bzrlib.trace.warning('"%s" not found in the test suite', id)
4036
trace.warning('"%s" not found in the test suite', id)
3974
4037
for id in duplicates:
3975
bzrlib.trace.warning('"%s" is used as an id by several tests', id)
4038
trace.warning('"%s" is used as an id by several tests', id)
3980
def multiply_scenarios(scenarios_left, scenarios_right):
4043
def multiply_scenarios(*scenarios):
4044
"""Multiply two or more iterables of scenarios.
4046
It is safe to pass scenario generators or iterators.
4048
:returns: A list of compound scenarios: the cross-product of all
4049
scenarios, with the names concatenated and the parameters
4052
return reduce(_multiply_two_scenarios, map(list, scenarios))
4055
def _multiply_two_scenarios(scenarios_left, scenarios_right):
3981
4056
"""Multiply two sets of scenarios.
3983
4058
:returns: the cartesian product of the two sets of scenarios, that is
4070
4145
new_test = copy.copy(test)
4071
4146
new_test.id = lambda: new_id
4147
# XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
4148
# causes cloned tests to share the 'details' dict. This makes it hard to
4149
# read the test output for parameterized tests, because tracebacks will be
4150
# associated with irrelevant tests.
4152
details = new_test._TestCase__details
4153
except AttributeError:
4154
# must be a different version of testtools than expected. Do nothing.
4157
# Reset the '__details' dict.
4158
new_test._TestCase__details = {}
4072
4159
return new_test
4492
4571
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
4495
# Kept for compatibility, use bzrlib.tests.features.subunit instead
4496
SubUnitFeature = _CompatabilityThunkFeature(
4497
deprecated_in((2,1,0)),
4498
'bzrlib.tests.features', 'SubUnitFeature', 'subunit')
4499
4574
# Only define SubUnitBzrRunner if subunit is available.
4501
4576
from subunit import TestProtocolClient
4502
4577
from subunit.test_results import AutoTimingTestResultDecorator
4578
class SubUnitBzrProtocolClient(TestProtocolClient):
4580
def addSuccess(self, test, details=None):
4581
# The subunit client always includes the details in the subunit
4582
# stream, but we don't want to include it in ours.
4583
if details is not None and 'log' in details:
4585
return super(SubUnitBzrProtocolClient, self).addSuccess(
4503
4588
class SubUnitBzrRunner(TextTestRunner):
4504
4589
def run(self, test):
4505
4590
result = AutoTimingTestResultDecorator(
4506
TestProtocolClient(self.stream))
4591
SubUnitBzrProtocolClient(self.stream))
4507
4592
test.run(result)
4509
4594
except ImportError: