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,
988
991
# settled on or a the FIXME associated with _get_expand_default_value
989
992
# is addressed -- vila 20110219
990
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()
992
1002
def debug(self):
993
1003
# debug a frame up.
1010
1020
if name in details:
1011
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,))
1013
1067
def _clear_debug_flags(self):
1014
1068
"""Prevent externally set debug flags affecting tests.
1069
1123
# break some locks on purpose and should be taken into account by
1070
1124
# considering that breaking a lock is just a dirty way of releasing it.
1071
1125
if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
1072
message = ('Different number of acquired and '
1073
'released or broken locks. (%s, %s + %s)' %
1074
(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))
1075
1133
if not self._lock_check_thorough:
1076
1134
# Rather than fail, just warn
1077
1135
print "Broken test %s: %s" % (self, message)
1637
1696
pseudo_log_file = StringIO()
1638
1697
def _get_log_contents_for_weird_testtools_api():
1639
1698
return [pseudo_log_file.getvalue().decode(
1640
"utf-8", "replace").encode("utf-8")]
1699
"utf-8", "replace").encode("utf-8")]
1641
1700
self.addDetail("log", content.Content(content.ContentType("text",
1642
1701
"plain", {"charset": "utf8"}),
1643
1702
_get_log_contents_for_weird_testtools_api))
1648
1707
def _finishLogFile(self):
1649
1708
"""Finished with the log file.
1651
Close the file and delete it, unless setKeepLogfile was called.
1710
Close the file and delete it.
1653
1712
if trace._trace_file:
1654
1713
# flush the log file, to get all content
2065
2124
# so we will avoid using it on all platforms, just to
2066
2125
# make sure the code path is used, and we don't break on win32
2067
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())
2068
2130
command = [sys.executable]
2069
2131
# frozen executables don't need the path to bzr
2070
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,),
2085
2174
def _popen(self, *args, **kwargs):
2086
2175
"""Place a call to Popen.
2239
2328
class TestCaseWithMemoryTransport(TestCase):
2240
2329
"""Common test class for tests that do not need disk resources.
2242
Tests that need disk resources should derive from TestCaseWithTransport.
2331
Tests that need disk resources should derive from TestCaseInTempDir
2332
orTestCaseWithTransport.
2244
2334
TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2246
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
2247
2337
a directory which does not exist. This serves to help ensure test isolation
2248
is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
2249
must exist. However, TestCaseWithMemoryTransport does not offer local
2250
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
2251
2341
override, so tests that accidentally write to the common directory should
2254
:cvar TEST_ROOT: Directory containing all temporary directories, plus
2255
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.
2258
2348
TEST_ROOT = None
2583
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)
2585
2681
def check_file_contents(self, filename, expect):
2586
2682
self.log("check contents of file %s" % filename)
2587
2683
f = file(filename)