142
142
'BZREMAIL': None, # may still be present in the environment
143
143
'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
144
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',
146
149
'BZR_PLUGIN_PATH': None,
147
150
'BZR_DISABLE_PLUGINS': None,
148
151
'BZR_PLUGINS_AT': None,
377
380
if isinstance(test, TestCase):
378
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
380
394
def startTests(self):
381
395
self.report_tests_starting()
382
396
self._active_threads = threading.enumerate()
384
def stopTest(self, test):
385
self._traceback_from_test = None
387
398
def _check_leaked_threads(self, test):
388
399
"""See if any threads have leaked since last call
449
460
self.known_failure_count += 1
450
461
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()))
452
476
def addNotSupported(self, test, feature):
453
477
"""The test will not be run because of a missing feature.
613
637
def report_known_failure(self, test, err):
640
def report_unexpected_success(self, test, reason):
641
self.stream.write('FAIL: %s\n %s: %s\n' % (
642
self._test_description(test),
643
"Unexpected success. Should have failed",
616
647
def report_skip(self, test, reason):
670
701
% (self._testTimeString(test),
671
702
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",
673
710
def report_success(self, test):
674
711
self.stream.write(' OK %s\n' % self._testTimeString(test))
675
712
for bench_called, stats in getattr(test, '_benchcalls', []):
937
974
super(TestCase, self).setUp()
938
975
for feature in getattr(self, '_test_needs_features', []):
939
976
self.requireFeature(feature)
940
self._log_contents = None
941
self.addDetail("log", content.Content(content.ContentType("text",
942
"plain", {"charset": "utf8"}),
943
lambda:[self._get_log(keep_log_file=True)]))
944
977
self._cleanEnvironment()
945
978
self._silenceUI()
946
979
self._startLogFile()
954
987
# between tests. We should get rid of this altogether: bug 656694. --
956
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()
958
1002
def debug(self):
959
1003
# debug a frame up.
976
1020
if name in details:
977
1021
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,))
979
1067
def _clear_debug_flags(self):
980
1068
"""Prevent externally set debug flags affecting tests.
996
1084
for key, (parent, name) in known_hooks.iter_parent_objects():
997
1085
current_hooks = getattr(parent, name)
998
1086
self._preserved_hooks[parent] = (name, current_hooks)
1087
self._preserved_lazy_hooks = hooks._lazy_hooks
1088
hooks._lazy_hooks = {}
999
1089
self.addCleanup(self._restoreHooks)
1000
1090
for key, (parent, name) in known_hooks.iter_parent_objects():
1001
1091
factory = known_hooks.get(key)
1033
1123
# break some locks on purpose and should be taken into account by
1034
1124
# considering that breaking a lock is just a dirty way of releasing it.
1035
1125
if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
1036
message = ('Different number of acquired and '
1037
'released or broken locks. (%s, %s + %s)' %
1038
(acquired_locks, released_locks, broken_locks))
1127
'Different number of acquired and '
1128
'released or broken locks.\n'
1132
(acquired_locks, released_locks, broken_locks))
1039
1133
if not self._lock_check_thorough:
1040
1134
# Rather than fail, just warn
1041
1135
print "Broken test %s: %s" % (self, message)
1261
1355
'st_mtime did not match')
1262
1356
self.assertEqual(expected.st_ctime, actual.st_ctime,
1263
1357
'st_ctime did not match')
1264
if sys.platform != 'win32':
1358
if sys.platform == 'win32':
1265
1359
# On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1266
1360
# is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
1267
# odd. Regardless we shouldn't actually try to assert anything
1268
# about their values
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)
1269
1367
self.assertEqual(expected.st_dev, actual.st_dev,
1270
1368
'st_dev did not match')
1271
1369
self.assertEqual(expected.st_ino, actual.st_ino,
1280
1378
length, len(obj_with_len), obj_with_len))
1282
1380
def assertLogsError(self, exception_class, func, *args, **kwargs):
1283
"""Assert that func(*args, **kwargs) quietly logs a specific exception.
1381
"""Assert that `func(*args, **kwargs)` quietly logs a specific error.
1286
1384
orig_log_exception_quietly = trace.log_exception_quietly
1289
1387
orig_log_exception_quietly()
1290
captured.append(sys.exc_info())
1388
captured.append(sys.exc_info()[1])
1291
1389
trace.log_exception_quietly = capture
1292
1390
func(*args, **kwargs)
1294
1392
trace.log_exception_quietly = orig_log_exception_quietly
1295
1393
self.assertLength(1, captured)
1296
err = captured[0][1]
1297
1395
self.assertIsInstance(err, exception_class)
1462
1561
self.assertTrue(osutils.lexists(path),
1463
1562
path + " does not exist")
1564
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1465
1565
def failIfExists(self, path):
1466
1566
return self.assertPathDoesNotExist(path)
1593
1694
The file is removed as the test is torn down.
1595
self._log_file = StringIO()
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
1596
1704
self._log_memento = trace.push_log_file(self._log_file)
1597
1705
self.addCleanup(self._finishLogFile)
1599
1707
def _finishLogFile(self):
1600
1708
"""Finished with the log file.
1602
Close the file and delete it, unless setKeepLogfile was called.
1710
Close the file and delete it.
1604
1712
if trace._trace_file:
1605
1713
# flush the log file, to get all content
1606
1714
trace._trace_file.flush()
1607
1715
trace.pop_log_file(self._log_memento)
1608
# Cache the log result and delete the file on disk
1609
self._get_log(False)
1611
1717
def thisFailsStrictLockCheck(self):
1612
1718
"""It is known that this test would fail with -Dstrict_locks.
1661
1767
def _restoreHooks(self):
1662
1768
for klass, (name, hooks) in self._preserved_hooks.items():
1663
1769
setattr(klass, name, hooks)
1770
self._preserved_hooks.clear()
1771
bzrlib.hooks._lazy_hooks = self._preserved_lazy_hooks
1772
self._preserved_lazy_hooks.clear()
1665
1774
def knownFailure(self, reason):
1666
1775
"""This test has failed for some known reason."""
1758
1867
def log(self, *args):
1759
1868
trace.mutter(*args)
1761
def _get_log(self, keep_log_file=False):
1762
"""Internal helper to get the log from bzrlib.trace for this test.
1764
Please use self.getDetails, or self.get_log to access this in test case
1767
:param keep_log_file: When True, if the log is still a file on disk
1768
leave it as a file on disk. When False, if the log is still a file
1769
on disk, the log file is deleted and the log preserved as
1771
:return: A string containing the log.
1773
if self._log_contents is not None:
1775
self._log_contents.decode('utf8')
1776
except UnicodeDecodeError:
1777
unicodestr = self._log_contents.decode('utf8', 'replace')
1778
self._log_contents = unicodestr.encode('utf8')
1779
return self._log_contents
1780
if self._log_file is not None:
1781
log_contents = self._log_file.getvalue()
1783
log_contents.decode('utf8')
1784
except UnicodeDecodeError:
1785
unicodestr = log_contents.decode('utf8', 'replace')
1786
log_contents = unicodestr.encode('utf8')
1787
if not keep_log_file:
1788
self._log_file = None
1789
# Permit multiple calls to get_log until we clean it up in
1791
self._log_contents = log_contents
1794
return "No log file content."
1796
1870
def get_log(self):
1797
1871
"""Get a unicode string containing the log from bzrlib.trace.
1998
2072
def start_bzr_subprocess(self, process_args, env_changes=None,
1999
2073
skip_if_plan_to_signal=False,
2000
2074
working_dir=None,
2001
allow_plugins=False):
2075
allow_plugins=False, stderr=subprocess.PIPE):
2002
2076
"""Start bzr in a subprocess for testing.
2004
2078
This starts a new Python interpreter and runs bzr in there.
2016
2090
:param skip_if_plan_to_signal: raise TestSkipped when true and system
2017
2091
doesn't support signalling subprocesses.
2018
2092
:param allow_plugins: If False (default) pass --no-plugins to bzr.
2093
:param stderr: file to use for the subprocess's stderr. Valid values
2094
are those valid for the stderr argument of `subprocess.Popen`.
2095
Default value is ``subprocess.PIPE``.
2020
2097
:returns: Popen object for the started process.
2047
2124
# so we will avoid using it on all platforms, just to
2048
2125
# make sure the code path is used, and we don't break on win32
2049
2126
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())
2050
2130
command = [sys.executable]
2051
2131
# frozen executables don't need the path to bzr
2052
2132
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,),
2067
2174
def _popen(self, *args, **kwargs):
2068
2175
"""Place a call to Popen.
2112
2219
% (process_args, retcode, process.returncode))
2113
2220
return [out, err]
2115
def check_inventory_shape(self, inv, shape):
2116
"""Compare an inventory to a list of expected names.
2222
def check_tree_shape(self, tree, shape):
2223
"""Compare a tree to a list of expected names.
2118
2225
Fail if they are not precisely equal.
2121
2228
shape = list(shape) # copy
2122
for path, ie in inv.entries():
2229
for path, ie in tree.iter_entries_by_dir():
2123
2230
name = path.replace('\\', '/')
2124
2231
if ie.kind == 'directory':
2125
2232
name = name + '/'
2234
pass # ignore root entry
2127
2236
shape.remove(name)
2129
2238
extras.append(name)
2219
2328
class TestCaseWithMemoryTransport(TestCase):
2220
2329
"""Common test class for tests that do not need disk resources.
2222
Tests that need disk resources should derive from TestCaseWithTransport.
2331
Tests that need disk resources should derive from TestCaseInTempDir
2332
orTestCaseWithTransport.
2224
2334
TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2226
For TestCaseWithMemoryTransport the test_home_dir is set to the name of
2336
For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
2227
2337
a directory which does not exist. This serves to help ensure test isolation
2228
is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
2229
must exist. However, TestCaseWithMemoryTransport does not offer local
2230
file defaults for the transport in tests, nor does it obey the command line
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
2231
2341
override, so tests that accidentally write to the common directory should
2234
:cvar TEST_ROOT: Directory containing all temporary directories, plus
2235
a .bzr directory that stops us ascending higher into the filesystem.
2344
:cvar TEST_ROOT: Directory containing all temporary directories, plus a
2345
``.bzr`` directory that stops us ascending higher into the filesystem.
2238
2348
TEST_ROOT = None
2563
2673
OVERRIDE_PYTHON = 'python'
2676
super(TestCaseInTempDir, self).setUp()
2677
# Remove the protection set in isolated_environ, we have a proper
2678
# access to disk resources now.
2679
self.overrideEnv('BZR_LOG', None)
2565
2681
def check_file_contents(self, filename, expect):
2566
2682
self.log("check contents of file %s" % filename)
2567
2683
f = file(filename)
3715
3833
'bzrlib.tests.per_repository',
3716
3834
'bzrlib.tests.per_repository_chk',
3717
3835
'bzrlib.tests.per_repository_reference',
3836
'bzrlib.tests.per_repository_vf',
3718
3837
'bzrlib.tests.per_uifactory',
3719
3838
'bzrlib.tests.per_versionedfile',
3720
3839
'bzrlib.tests.per_workingtree',
3754
3873
'bzrlib.tests.test_commit_merge',
3755
3874
'bzrlib.tests.test_config',
3756
3875
'bzrlib.tests.test_conflicts',
3876
'bzrlib.tests.test_controldir',
3757
3877
'bzrlib.tests.test_counted_lock',
3758
3878
'bzrlib.tests.test_crash',
3759
3879
'bzrlib.tests.test_decorators',
3760
3880
'bzrlib.tests.test_delta',
3761
3881
'bzrlib.tests.test_debug',
3762
'bzrlib.tests.test_deprecated_graph',
3763
3882
'bzrlib.tests.test_diff',
3764
3883
'bzrlib.tests.test_directory_service',
3765
3884
'bzrlib.tests.test_dirstate',
3767
3886
'bzrlib.tests.test_eol_filters',
3768
3887
'bzrlib.tests.test_errors',
3769
3888
'bzrlib.tests.test_export',
3889
'bzrlib.tests.test_export_pot',
3770
3890
'bzrlib.tests.test_extract',
3771
3891
'bzrlib.tests.test_fetch',
3772
3892
'bzrlib.tests.test_fixtures',
3786
3906
'bzrlib.tests.test_http',
3787
3907
'bzrlib.tests.test_http_response',
3788
3908
'bzrlib.tests.test_https_ca_bundle',
3909
'bzrlib.tests.test_i18n',
3789
3910
'bzrlib.tests.test_identitymap',
3790
3911
'bzrlib.tests.test_ignores',
3791
3912
'bzrlib.tests.test_index',
3810
3931
'bzrlib.tests.test_merge3',
3811
3932
'bzrlib.tests.test_merge_core',
3812
3933
'bzrlib.tests.test_merge_directive',
3934
'bzrlib.tests.test_mergetools',
3813
3935
'bzrlib.tests.test_missing',
3814
3936
'bzrlib.tests.test_msgeditor',
3815
3937
'bzrlib.tests.test_multiparent',
3865
3987
'bzrlib.tests.test_testament',
3866
3988
'bzrlib.tests.test_textfile',
3867
3989
'bzrlib.tests.test_textmerge',
3990
'bzrlib.tests.test_cethread',
3868
3991
'bzrlib.tests.test_timestamp',
3869
3992
'bzrlib.tests.test_trace',
3870
3993
'bzrlib.tests.test_transactions',
3881
4004
'bzrlib.tests.test_upgrade',
3882
4005
'bzrlib.tests.test_upgrade_stacked',
3883
4006
'bzrlib.tests.test_urlutils',
4007
'bzrlib.tests.test_utextwrap',
3884
4008
'bzrlib.tests.test_version',
3885
4009
'bzrlib.tests.test_version_info',
3886
4010
'bzrlib.tests.test_versionedfile',