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, 5):
59
raise ImportError("need at least testtools 0.9.5: %s is %r"
58
if _testtools_version < (0, 9, 2):
59
raise ImportError("need at least testtools 0.9.2: %s is %r"
60
60
% (testtools.__file__, _testtools_version))
61
61
from testtools import content
64
63
from bzrlib import (
68
commands as _mod_commands,
77
plugin as _mod_plugin,
84
77
transport as _mod_transport,
81
import bzrlib.commands
82
import bzrlib.timestamp
84
import bzrlib.inventory
85
import bzrlib.iterablefile
88
88
import bzrlib.lsprof
89
89
except ImportError:
90
90
# lsprof not available
92
from bzrlib.smart import client, request
92
from bzrlib.merge import merge_inner
95
from bzrlib.smart import client, request, server
97
from bzrlib import symbol_versioning
98
from bzrlib.symbol_versioning import (
93
106
from bzrlib.transport import (
110
from bzrlib.trace import mutter, note
97
111
from bzrlib.tests import (
123
139
TestSuite = TestUtil.TestSuite
124
140
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,
145
# This should trap leaks to ~/.bzr.log. This occurs when tests use TestCase
146
# as a base class instead of TestCaseInTempDir. Tests inheriting from
147
# TestCase should not use disk resources, BZR_LOG is one.
148
'BZR_LOG': '/you-should-use-TestCaseInTempDir-if-you-need-a-log-file',
149
'BZR_PLUGIN_PATH': None,
150
'BZR_DISABLE_PLUGINS': None,
151
'BZR_PLUGINS_AT': None,
152
'BZR_CONCURRENCY': None,
153
# Make sure that any text ui tests are consistent regardless of
154
# the environment the test case is run in; you may want tests that
155
# test other combinations. 'dumb' is a reasonable guess for tests
156
# going to a pipe or a StringIO.
162
'SSH_AUTH_SOCK': None,
172
# Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
173
# least. If you do (care), please update this comment
177
'BZR_REMOTE_PATH': None,
178
# Generally speaking, we don't want apport reporting on crashes in
179
# the test envirnoment unless we're specifically testing apport,
180
# so that it doesn't leak into the real system environment. We
181
# use an env var so it propagates to subprocesses.
182
'APPORT_DISABLE': '1',
186
def override_os_environ(test, env=None):
187
"""Modify os.environ keeping a copy.
189
:param test: A test instance
191
:param env: A dict containing variable definitions to be installed
194
env = isolated_environ
195
test._original_os_environ = dict([(var, value)
196
for var, value in os.environ.iteritems()])
197
for var, value in env.iteritems():
198
osutils.set_or_unset_env(var, value)
199
if var not in test._original_os_environ:
200
# The var is new, add it with a value of None, so
201
# restore_os_environ will delete it
202
test._original_os_environ[var] = None
205
def restore_os_environ(test):
206
"""Restore os.environ to its original state.
208
:param test: A test instance previously passed to override_os_environ.
210
for var, value in test._original_os_environ.iteritems():
211
# Restore the original value (or delete it if the value has been set to
212
# None in override_os_environ).
213
osutils.set_or_unset_env(var, value)
216
142
class ExtendedTestResult(testtools.TextTestResult):
217
143
"""Accepts, reports and accumulates the results of running tests.
356
280
what = re.sub(r'^bzrlib\.tests\.', '', what)
359
# GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
360
# multiple times in a row, because the handler is added for
361
# each test but the container list is shared between cases.
362
# See lp:498869 lp:625574 and lp:637725 for background.
363
def _record_traceback_from_test(self, exc_info):
364
"""Store the traceback from passed exc_info tuple till"""
365
self._traceback_from_test = exc_info[2]
367
283
def startTest(self, test):
368
284
super(ExtendedTestResult, self).startTest(test)
369
285
if self.count == 0:
372
288
self.report_test_start(test)
373
289
test.number = self.count
374
290
self._recordTestStartTime()
375
# Make testtools cases give us the real traceback on failure
376
addOnException = getattr(test, "addOnException", None)
377
if addOnException is not None:
378
addOnException(self._record_traceback_from_test)
379
# Only check for thread leaks on bzrlib derived test cases
380
if isinstance(test, TestCase):
381
test.addCleanup(self._check_leaked_threads, test)
383
def stopTest(self, test):
384
super(ExtendedTestResult, self).stopTest(test)
385
# Manually break cycles, means touching various private things but hey
386
getDetails = getattr(test, "getDetails", None)
387
if getDetails is not None:
389
type_equality_funcs = getattr(test, "_type_equality_funcs", None)
390
if type_equality_funcs is not None:
391
type_equality_funcs.clear()
392
self._traceback_from_test = None
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)
394
296
def startTests(self):
395
297
self.report_tests_starting()
460
362
self.known_failure_count += 1
461
363
self.report_known_failure(test, err)
463
def addUnexpectedSuccess(self, test, details=None):
464
"""Tell result the test unexpectedly passed, counting as a failure
466
When the minimum version of testtools required becomes 0.9.8 this
467
can be updated to use the new handling there.
469
super(ExtendedTestResult, self).addFailure(test, details=details)
470
self.failure_count += 1
471
self.report_unexpected_success(test,
472
"".join(details["reason"].iter_text()))
476
365
def addNotSupported(self, test, feature):
477
366
"""The test will not be run because of a missing feature.
495
384
self.not_applicable_count += 1
496
385
self.report_not_applicable(test, reason)
498
def _post_mortem(self, tb=None):
387
def _post_mortem(self):
499
388
"""Start a PDB post mortem session."""
500
389
if os.environ.get('BZR_TEST_PDB', None):
390
import pdb;pdb.post_mortem()
504
392
def progress(self, offset, whence):
505
393
"""The test is adjusting the count of tests to run."""
701
582
% (self._testTimeString(test),
702
583
self._error_summary(err)))
704
def report_unexpected_success(self, test, reason):
705
self.stream.write(' FAIL %s\n%s: %s\n'
706
% (self._testTimeString(test),
707
"Unexpected success. Should have failed",
710
585
def report_success(self, test):
711
586
self.stream.write(' OK %s\n' % self._testTimeString(test))
712
587
for bench_called, stats in getattr(test, '_benchcalls', []):
918
790
return NullProgressView()
921
def isolated_doctest_setUp(test):
922
override_os_environ(test)
925
def isolated_doctest_tearDown(test):
926
restore_os_environ(test)
929
def IsolatedDocTestSuite(*args, **kwargs):
930
"""Overrides doctest.DocTestSuite to handle isolation.
932
The method is really a factory and users are expected to use it as such.
935
kwargs['setUp'] = isolated_doctest_setUp
936
kwargs['tearDown'] = isolated_doctest_tearDown
937
return doctest.DocTestSuite(*args, **kwargs)
940
793
class TestCase(testtools.TestCase):
941
794
"""Base class for bzr unit tests.
974
827
super(TestCase, self).setUp()
975
828
for feature in getattr(self, '_test_needs_features', []):
976
829
self.requireFeature(feature)
830
self._log_contents = None
831
self.addDetail("log", content.Content(content.ContentType("text",
832
"plain", {"charset": "utf8"}),
833
lambda:[self._get_log(keep_log_file=True)]))
977
834
self._cleanEnvironment()
978
835
self._silenceUI()
979
836
self._startLogFile()
983
840
self._track_transports()
984
841
self._track_locks()
985
842
self._clear_debug_flags()
986
# Isolate global verbosity level, to make sure it's reproducible
987
# between tests. We should get rid of this altogether: bug 656694. --
989
self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
990
# Isolate config option expansion until its default value for bzrlib is
991
# settled on or a the FIXME associated with _get_expand_default_value
992
# is addressed -- vila 20110219
993
self.overrideAttr(config, '_expand_default_value', None)
994
self._log_files = set()
995
# Each key in the ``_counters`` dict holds a value for a different
996
# counter. When the test ends, addDetail() should be used to output the
997
# counter values. This happens in install_counter_hook().
999
if 'config_stats' in selftest_debug_flags:
1000
self._install_config_stats_hooks()
1002
844
def debug(self):
1003
845
# debug a frame up.
1020
862
if name in details:
1021
863
del details[name]
1023
def install_counter_hook(self, hooks, name, counter_name=None):
1024
"""Install a counting hook.
1026
Any hook can be counted as long as it doesn't need to return a value.
1028
:param hooks: Where the hook should be installed.
1030
:param name: The hook name that will be counted.
1032
:param counter_name: The counter identifier in ``_counters``, defaults
1035
_counters = self._counters # Avoid closing over self
1036
if counter_name is None:
1038
if _counters.has_key(counter_name):
1039
raise AssertionError('%s is already used as a counter name'
1041
_counters[counter_name] = 0
1042
self.addDetail(counter_name, content.Content(content.UTF8_TEXT,
1043
lambda: ['%d' % (_counters[counter_name],)]))
1044
def increment_counter(*args, **kwargs):
1045
_counters[counter_name] += 1
1046
label = 'count %s calls' % (counter_name,)
1047
hooks.install_named_hook(name, increment_counter, label)
1048
self.addCleanup(hooks.uninstall_named_hook, name, label)
1050
def _install_config_stats_hooks(self):
1051
"""Install config hooks to count hook calls.
1054
for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1055
self.install_counter_hook(config.ConfigHooks, hook_name,
1056
'config.%s' % (hook_name,))
1058
# The OldConfigHooks are private and need special handling to protect
1059
# against recursive tests (tests that run other tests), so we just do
1060
# manually what registering them into _builtin_known_hooks will provide
1062
self.overrideAttr(config, 'OldConfigHooks', config._OldConfigHooks())
1063
for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1064
self.install_counter_hook(config.OldConfigHooks, hook_name,
1065
'old_config.%s' % (hook_name,))
1067
865
def _clear_debug_flags(self):
1068
866
"""Prevent externally set debug flags affecting tests.
1080
878
def _clear_hooks(self):
1081
879
# prevent hooks affecting tests
1082
known_hooks = hooks.known_hooks
1083
880
self._preserved_hooks = {}
1084
for key, (parent, name) in known_hooks.iter_parent_objects():
1085
current_hooks = getattr(parent, name)
881
for key, factory in hooks.known_hooks.items():
882
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
883
current_hooks = hooks.known_hooks_key_to_object(key)
1086
884
self._preserved_hooks[parent] = (name, current_hooks)
1087
self._preserved_lazy_hooks = hooks._lazy_hooks
1088
hooks._lazy_hooks = {}
1089
885
self.addCleanup(self._restoreHooks)
1090
for key, (parent, name) in known_hooks.iter_parent_objects():
1091
factory = known_hooks.get(key)
886
for key, factory in hooks.known_hooks.items():
887
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
1092
888
setattr(parent, name, factory())
1093
889
# this hook should always be installed
1094
890
request._install_hook()
1123
919
# break some locks on purpose and should be taken into account by
1124
920
# considering that breaking a lock is just a dirty way of releasing it.
1125
921
if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
1127
'Different number of acquired and '
1128
'released or broken locks.\n'
1132
(acquired_locks, released_locks, broken_locks))
922
message = ('Different number of acquired and '
923
'released or broken locks. (%s, %s + %s)' %
924
(acquired_locks, released_locks, broken_locks))
1133
925
if not self._lock_check_thorough:
1134
926
# Rather than fail, just warn
1135
927
print "Broken test %s: %s" % (self, message)
1355
1147
'st_mtime did not match')
1356
1148
self.assertEqual(expected.st_ctime, actual.st_ctime,
1357
1149
'st_ctime did not match')
1358
if sys.platform == 'win32':
1150
if sys.platform != 'win32':
1359
1151
# On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1360
1152
# is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
1361
# odd. We just force it to always be 0 to avoid any problems.
1362
self.assertEqual(0, expected.st_dev)
1363
self.assertEqual(0, actual.st_dev)
1364
self.assertEqual(0, expected.st_ino)
1365
self.assertEqual(0, actual.st_ino)
1153
# odd. Regardless we shouldn't actually try to assert anything
1154
# about their values
1367
1155
self.assertEqual(expected.st_dev, actual.st_dev,
1368
1156
'st_dev did not match')
1369
1157
self.assertEqual(expected.st_ino, actual.st_ino,
1378
1166
length, len(obj_with_len), obj_with_len))
1380
1168
def assertLogsError(self, exception_class, func, *args, **kwargs):
1381
"""Assert that `func(*args, **kwargs)` quietly logs a specific error.
1169
"""Assert that func(*args, **kwargs) quietly logs a specific exception.
1171
from bzrlib import trace
1384
1173
orig_log_exception_quietly = trace.log_exception_quietly
1387
1176
orig_log_exception_quietly()
1388
captured.append(sys.exc_info()[1])
1177
captured.append(sys.exc_info())
1389
1178
trace.log_exception_quietly = capture
1390
1179
func(*args, **kwargs)
1392
1181
trace.log_exception_quietly = orig_log_exception_quietly
1393
1182
self.assertLength(1, captured)
1183
err = captured[0][1]
1395
1184
self.assertIsInstance(err, exception_class)
1434
1223
if haystack.find(needle) == -1:
1435
1224
self.fail("string %r not found in '''%s'''" % (needle, haystack))
1437
def assertNotContainsString(self, haystack, needle):
1438
if haystack.find(needle) != -1:
1439
self.fail("string %r found in '''%s'''" % (needle, haystack))
1441
1226
def assertSubset(self, sublist, superlist):
1442
1227
"""Assert that every entry in sublist is present in superlist."""
1443
1228
missing = set(sublist) - set(superlist)
1549
1334
self.assertEqual(expected_docstring, obj.__doc__)
1551
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1552
1336
def failUnlessExists(self, path):
1553
return self.assertPathExists(path)
1555
def assertPathExists(self, path):
1556
1337
"""Fail unless path or paths, which may be abs or relative, exist."""
1557
1338
if not isinstance(path, basestring):
1559
self.assertPathExists(p)
1340
self.failUnlessExists(p)
1561
self.assertTrue(osutils.lexists(path),
1562
path + " does not exist")
1342
self.failUnless(osutils.lexists(path),path+" does not exist")
1564
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1565
1344
def failIfExists(self, path):
1566
return self.assertPathDoesNotExist(path)
1568
def assertPathDoesNotExist(self, path):
1569
1345
"""Fail if path or paths, which may be abs or relative, exist."""
1570
1346
if not isinstance(path, basestring):
1572
self.assertPathDoesNotExist(p)
1348
self.failIfExists(p)
1574
self.assertFalse(osutils.lexists(path),
1350
self.failIf(osutils.lexists(path),path+" exists")
1577
1352
def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
1578
1353
"""A helper for callDeprecated and applyDeprecated.
1694
1468
The file is removed as the test is torn down.
1696
pseudo_log_file = StringIO()
1697
def _get_log_contents_for_weird_testtools_api():
1698
return [pseudo_log_file.getvalue().decode(
1699
"utf-8", "replace").encode("utf-8")]
1700
self.addDetail("log", content.Content(content.ContentType("text",
1701
"plain", {"charset": "utf8"}),
1702
_get_log_contents_for_weird_testtools_api))
1703
self._log_file = pseudo_log_file
1704
self._log_memento = trace.push_log_file(self._log_file)
1470
self._log_file = StringIO()
1471
self._log_memento = bzrlib.trace.push_log_file(self._log_file)
1705
1472
self.addCleanup(self._finishLogFile)
1707
1474
def _finishLogFile(self):
1708
1475
"""Finished with the log file.
1710
Close the file and delete it.
1477
Close the file and delete it, unless setKeepLogfile was called.
1712
if trace._trace_file:
1479
if bzrlib.trace._trace_file:
1713
1480
# flush the log file, to get all content
1714
trace._trace_file.flush()
1715
trace.pop_log_file(self._log_memento)
1481
bzrlib.trace._trace_file.flush()
1482
bzrlib.trace.pop_log_file(self._log_memento)
1483
# Cache the log result and delete the file on disk
1484
self._get_log(False)
1717
1486
def thisFailsStrictLockCheck(self):
1718
1487
"""It is known that this test would fail with -Dstrict_locks.
1746
1515
setattr(obj, attr_name, new)
1749
def overrideEnv(self, name, new):
1750
"""Set an environment variable, and reset it after the test.
1752
:param name: The environment variable name.
1754
:param new: The value to set the variable to. If None, the
1755
variable is deleted from the environment.
1757
:returns: The actual variable value.
1759
value = osutils.set_or_unset_env(name, new)
1760
self.addCleanup(osutils.set_or_unset_env, name, value)
1763
1518
def _cleanEnvironment(self):
1764
for name, value in isolated_environ.iteritems():
1765
self.overrideEnv(name, value)
1520
'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
1521
'HOME': os.getcwd(),
1522
# bzr now uses the Win32 API and doesn't rely on APPDATA, but the
1523
# tests do check our impls match APPDATA
1524
'BZR_EDITOR': None, # test_msgeditor manipulates this variable
1528
'BZREMAIL': None, # may still be present in the environment
1529
'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
1530
'BZR_PROGRESS_BAR': None,
1532
'BZR_PLUGIN_PATH': None,
1533
'BZR_DISABLE_PLUGINS': None,
1534
'BZR_PLUGINS_AT': None,
1535
'BZR_CONCURRENCY': None,
1536
# Make sure that any text ui tests are consistent regardless of
1537
# the environment the test case is run in; you may want tests that
1538
# test other combinations. 'dumb' is a reasonable guess for tests
1539
# going to a pipe or a StringIO.
1543
'BZR_COLUMNS': '80',
1545
'SSH_AUTH_SOCK': None,
1549
'https_proxy': None,
1550
'HTTPS_PROXY': None,
1555
# Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
1556
# least. If you do (care), please update this comment
1560
'BZR_REMOTE_PATH': None,
1561
# Generally speaking, we don't want apport reporting on crashes in
1562
# the test envirnoment unless we're specifically testing apport,
1563
# so that it doesn't leak into the real system environment. We
1564
# use an env var so it propagates to subprocesses.
1565
'APPORT_DISABLE': '1',
1568
self.addCleanup(self._restoreEnvironment)
1569
for name, value in new_env.iteritems():
1570
self._captureVar(name, value)
1572
def _captureVar(self, name, newvalue):
1573
"""Set an environment variable, and reset it when finished."""
1574
self._old_env[name] = osutils.set_or_unset_env(name, newvalue)
1576
def _restoreEnvironment(self):
1577
for name, value in self._old_env.iteritems():
1578
osutils.set_or_unset_env(name, value)
1767
1580
def _restoreHooks(self):
1768
1581
for klass, (name, hooks) in self._preserved_hooks.items():
1769
1582
setattr(klass, name, hooks)
1770
self._preserved_hooks.clear()
1771
bzrlib.hooks._lazy_hooks = self._preserved_lazy_hooks
1772
self._preserved_lazy_hooks.clear()
1774
1584
def knownFailure(self, reason):
1775
1585
"""This test has failed for some known reason."""
1865
1675
self._benchtime += time.time() - start
1867
1677
def log(self, *args):
1680
def _get_log(self, keep_log_file=False):
1681
"""Internal helper to get the log from bzrlib.trace for this test.
1683
Please use self.getDetails, or self.get_log to access this in test case
1686
:param keep_log_file: When True, if the log is still a file on disk
1687
leave it as a file on disk. When False, if the log is still a file
1688
on disk, the log file is deleted and the log preserved as
1690
:return: A string containing the log.
1692
if self._log_contents is not None:
1694
self._log_contents.decode('utf8')
1695
except UnicodeDecodeError:
1696
unicodestr = self._log_contents.decode('utf8', 'replace')
1697
self._log_contents = unicodestr.encode('utf8')
1698
return self._log_contents
1699
if self._log_file is not None:
1700
log_contents = self._log_file.getvalue()
1702
log_contents.decode('utf8')
1703
except UnicodeDecodeError:
1704
unicodestr = log_contents.decode('utf8', 'replace')
1705
log_contents = unicodestr.encode('utf8')
1706
if not keep_log_file:
1707
self._log_file = None
1708
# Permit multiple calls to get_log until we clean it up in
1710
self._log_contents = log_contents
1713
return "No log file content."
1870
1715
def get_log(self):
1871
1716
"""Get a unicode string containing the log from bzrlib.trace.
2124
1965
# so we will avoid using it on all platforms, just to
2125
1966
# make sure the code path is used, and we don't break on win32
2126
1967
cleanup_environment()
2127
# Include the subprocess's log file in the test details, in case
2128
# the test fails due to an error in the subprocess.
2129
self._add_subprocess_log(trace._get_bzr_log_filename())
2130
1968
command = [sys.executable]
2131
1969
# frozen executables don't need the path to bzr
2132
1970
if getattr(sys, "frozen", None) is None:
2147
def _add_subprocess_log(self, log_file_path):
2148
if len(self._log_files) == 0:
2149
# Register an addCleanup func. We do this on the first call to
2150
# _add_subprocess_log rather than in TestCase.setUp so that this
2151
# addCleanup is registered after any cleanups for tempdirs that
2152
# subclasses might create, which will probably remove the log file
2154
self.addCleanup(self._subprocess_log_cleanup)
2155
# self._log_files is a set, so if a log file is reused we won't grab it
2157
self._log_files.add(log_file_path)
2159
def _subprocess_log_cleanup(self):
2160
for count, log_file_path in enumerate(self._log_files):
2161
# We use buffer_now=True to avoid holding the file open beyond
2162
# the life of this function, which might interfere with e.g.
2163
# cleaning tempdirs on Windows.
2164
# XXX: Testtools 0.9.5 doesn't have the content_from_file helper
2165
#detail_content = content.content_from_file(
2166
# log_file_path, buffer_now=True)
2167
with open(log_file_path, 'rb') as log_file:
2168
log_file_bytes = log_file.read()
2169
detail_content = content.Content(content.ContentType("text",
2170
"plain", {"charset": "utf8"}), lambda: [log_file_bytes])
2171
self.addDetail("start_bzr_subprocess-log-%d" % (count,),
2174
1985
def _popen(self, *args, **kwargs):
2175
1986
"""Place a call to Popen.
2213
2024
if retcode is not None and retcode != process.returncode:
2214
2025
if process_args is None:
2215
2026
process_args = "(unknown args)"
2216
trace.mutter('Output of bzr %s:\n%s', process_args, out)
2217
trace.mutter('Error for bzr %s:\n%s', process_args, err)
2027
mutter('Output of bzr %s:\n%s', process_args, out)
2028
mutter('Error for bzr %s:\n%s', process_args, err)
2218
2029
self.fail('Command bzr %s failed with retcode %s != %s'
2219
2030
% (process_args, retcode, process.returncode))
2220
2031
return [out, err]
2222
def check_tree_shape(self, tree, shape):
2223
"""Compare a tree to a list of expected names.
2033
def check_inventory_shape(self, inv, shape):
2034
"""Compare an inventory to a list of expected names.
2225
2036
Fail if they are not precisely equal.
2228
2039
shape = list(shape) # copy
2229
for path, ie in tree.iter_entries_by_dir():
2040
for path, ie in inv.entries():
2230
2041
name = path.replace('\\', '/')
2231
2042
if ie.kind == 'directory':
2232
2043
name = name + '/'
2234
pass # ignore root entry
2236
2045
shape.remove(name)
2238
2047
extras.append(name)
2328
2137
class TestCaseWithMemoryTransport(TestCase):
2329
2138
"""Common test class for tests that do not need disk resources.
2331
Tests that need disk resources should derive from TestCaseInTempDir
2332
orTestCaseWithTransport.
2140
Tests that need disk resources should derive from TestCaseWithTransport.
2334
2142
TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2336
For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
2144
For TestCaseWithMemoryTransport the test_home_dir is set to the name of
2337
2145
a directory which does not exist. This serves to help ensure test isolation
2338
is preserved. ``test_dir`` is set to the TEST_ROOT, as is cwd, because they
2339
must exist. However, TestCaseWithMemoryTransport does not offer local file
2340
defaults for the transport in tests, nor does it obey the command line
2146
is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
2147
must exist. However, TestCaseWithMemoryTransport does not offer local
2148
file defaults for the transport in tests, nor does it obey the command line
2341
2149
override, so tests that accidentally write to the common directory should
2344
:cvar TEST_ROOT: Directory containing all temporary directories, plus a
2345
``.bzr`` directory that stops us ascending higher into the filesystem.
2152
:cvar TEST_ROOT: Directory containing all temporary directories, plus
2153
a .bzr directory that stops us ascending higher into the filesystem.
2348
2156
TEST_ROOT = None
2610
2418
test_home_dir = self.test_home_dir
2611
2419
if isinstance(test_home_dir, unicode):
2612
2420
test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
2613
self.overrideEnv('HOME', test_home_dir)
2614
self.overrideEnv('BZR_HOME', test_home_dir)
2421
os.environ['HOME'] = test_home_dir
2422
os.environ['BZR_HOME'] = test_home_dir
2616
2424
def setUp(self):
2617
2425
super(TestCaseWithMemoryTransport, self).setUp()
3532
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3334
class ForwardingResult(unittest.TestResult):
3336
def __init__(self, target):
3337
unittest.TestResult.__init__(self)
3338
self.result = target
3340
def startTest(self, test):
3341
self.result.startTest(test)
3343
def stopTest(self, test):
3344
self.result.stopTest(test)
3346
def startTestRun(self):
3347
self.result.startTestRun()
3349
def stopTestRun(self):
3350
self.result.stopTestRun()
3352
def addSkip(self, test, reason):
3353
self.result.addSkip(test, reason)
3355
def addSuccess(self, test):
3356
self.result.addSuccess(test)
3358
def addError(self, test, err):
3359
self.result.addError(test, err)
3361
def addFailure(self, test, err):
3362
self.result.addFailure(test, err)
3363
ForwardingResult = testtools.ExtendedToOriginalDecorator
3366
class ProfileResult(ForwardingResult):
3533
3367
"""Generate profiling data for all activity between start and success.
3535
3369
The profile data is appended to the test's _benchcalls attribute and can
3557
3391
test._benchcalls = []
3558
3392
calls = test._benchcalls
3559
3393
calls.append(((test.id(), "", ""), stats))
3560
testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
3394
ForwardingResult.addSuccess(self, test)
3562
3396
def stopTest(self, test):
3563
testtools.ExtendedToOriginalDecorator.stopTest(self, test)
3397
ForwardingResult.stopTest(self, test)
3564
3398
self.profiler = None
3833
3664
'bzrlib.tests.per_repository',
3834
3665
'bzrlib.tests.per_repository_chk',
3835
3666
'bzrlib.tests.per_repository_reference',
3836
'bzrlib.tests.per_repository_vf',
3837
3667
'bzrlib.tests.per_uifactory',
3838
3668
'bzrlib.tests.per_versionedfile',
3839
3669
'bzrlib.tests.per_workingtree',
3873
3703
'bzrlib.tests.test_commit_merge',
3874
3704
'bzrlib.tests.test_config',
3875
3705
'bzrlib.tests.test_conflicts',
3876
'bzrlib.tests.test_controldir',
3877
3706
'bzrlib.tests.test_counted_lock',
3878
3707
'bzrlib.tests.test_crash',
3879
3708
'bzrlib.tests.test_decorators',
3880
3709
'bzrlib.tests.test_delta',
3881
3710
'bzrlib.tests.test_debug',
3711
'bzrlib.tests.test_deprecated_graph',
3882
3712
'bzrlib.tests.test_diff',
3883
3713
'bzrlib.tests.test_directory_service',
3884
3714
'bzrlib.tests.test_dirstate',
3886
3716
'bzrlib.tests.test_eol_filters',
3887
3717
'bzrlib.tests.test_errors',
3888
3718
'bzrlib.tests.test_export',
3889
'bzrlib.tests.test_export_pot',
3890
3719
'bzrlib.tests.test_extract',
3891
3720
'bzrlib.tests.test_fetch',
3892
3721
'bzrlib.tests.test_fixtures',
3906
3735
'bzrlib.tests.test_http',
3907
3736
'bzrlib.tests.test_http_response',
3908
3737
'bzrlib.tests.test_https_ca_bundle',
3909
'bzrlib.tests.test_i18n',
3910
3738
'bzrlib.tests.test_identitymap',
3911
3739
'bzrlib.tests.test_ignores',
3912
3740
'bzrlib.tests.test_index',
3931
3759
'bzrlib.tests.test_merge3',
3932
3760
'bzrlib.tests.test_merge_core',
3933
3761
'bzrlib.tests.test_merge_directive',
3934
'bzrlib.tests.test_mergetools',
3935
3762
'bzrlib.tests.test_missing',
3936
3763
'bzrlib.tests.test_msgeditor',
3937
3764
'bzrlib.tests.test_multiparent',
3946
3773
'bzrlib.tests.test_permissions',
3947
3774
'bzrlib.tests.test_plugins',
3948
3775
'bzrlib.tests.test_progress',
3949
'bzrlib.tests.test_pyutils',
3950
3776
'bzrlib.tests.test_read_bundle',
3951
3777
'bzrlib.tests.test_reconcile',
3952
3778
'bzrlib.tests.test_reconfigure',
3987
3812
'bzrlib.tests.test_testament',
3988
3813
'bzrlib.tests.test_textfile',
3989
3814
'bzrlib.tests.test_textmerge',
3990
'bzrlib.tests.test_cethread',
3991
3815
'bzrlib.tests.test_timestamp',
3992
3816
'bzrlib.tests.test_trace',
3993
3817
'bzrlib.tests.test_transactions',
4004
3828
'bzrlib.tests.test_upgrade',
4005
3829
'bzrlib.tests.test_upgrade_stacked',
4006
3830
'bzrlib.tests.test_urlutils',
4007
'bzrlib.tests.test_utextwrap',
4008
3831
'bzrlib.tests.test_version',
4009
3832
'bzrlib.tests.test_version_info',
4010
3833
'bzrlib.tests.test_versionedfile',
4139
3961
# Some tests mentioned in the list are not in the test suite. The
4140
3962
# list may be out of date, report to the tester.
4141
3963
for id in not_found:
4142
trace.warning('"%s" not found in the test suite', id)
3964
bzrlib.trace.warning('"%s" not found in the test suite', id)
4143
3965
for id in duplicates:
4144
trace.warning('"%s" is used as an id by several tests', id)
3966
bzrlib.trace.warning('"%s" is used as an id by several tests', id)
4149
def multiply_scenarios(*scenarios):
4150
"""Multiply two or more iterables of scenarios.
4152
It is safe to pass scenario generators or iterators.
4154
:returns: A list of compound scenarios: the cross-product of all
4155
scenarios, with the names concatenated and the parameters
4158
return reduce(_multiply_two_scenarios, map(list, scenarios))
4161
def _multiply_two_scenarios(scenarios_left, scenarios_right):
3971
def multiply_scenarios(scenarios_left, scenarios_right):
4162
3972
"""Multiply two sets of scenarios.
4164
3974
:returns: the cartesian product of the two sets of scenarios, that is
4447
4257
symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4448
4258
# Import the new feature and use it as a replacement for the
4449
4259
# deprecated one.
4450
self._feature = pyutils.get_named_object(
4451
self._replacement_module, self._replacement_name)
4260
mod = __import__(self._replacement_module, {}, {},
4261
[self._replacement_name])
4262
self._feature = getattr(mod, self._replacement_name)
4453
4264
def _probe(self):