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,
77
84
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.merge import merge_inner
95
from bzrlib.smart import client, request, server
97
from bzrlib import symbol_versioning
98
from bzrlib.symbol_versioning import (
92
from bzrlib.smart import client, request
106
93
from bzrlib.transport import (
110
from bzrlib.trace import mutter, note
111
97
from bzrlib.tests import (
139
123
TestSuite = TestUtil.TestSuite
140
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)
142
213
class ExtendedTestResult(testtools.TextTestResult):
143
214
"""Accepts, reports and accumulates the results of running tests.
280
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]
283
364
def startTest(self, test):
284
365
super(ExtendedTestResult, self).startTest(test)
285
366
if self.count == 0:
288
369
self.report_test_start(test)
289
370
test.number = self.count
290
371
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)
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)
296
380
def startTests(self):
297
381
self.report_tests_starting()
298
382
self._active_threads = threading.enumerate()
384
def stopTest(self, test):
385
self._traceback_from_test = None
300
387
def _check_leaked_threads(self, test):
301
388
"""See if any threads have leaked since last call
384
471
self.not_applicable_count += 1
385
472
self.report_not_applicable(test, reason)
387
def _post_mortem(self):
474
def _post_mortem(self, tb=None):
388
475
"""Start a PDB post mortem session."""
389
476
if os.environ.get('BZR_TEST_PDB', None):
390
import pdb;pdb.post_mortem()
392
480
def progress(self, offset, whence):
393
481
"""The test is adjusting the count of tests to run."""
790
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)
793
903
class TestCase(testtools.TestCase):
794
904
"""Base class for bzr unit tests.
878
992
def _clear_hooks(self):
879
993
# prevent hooks affecting tests
994
known_hooks = hooks.known_hooks
880
995
self._preserved_hooks = {}
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)
996
for key, (parent, name) in known_hooks.iter_parent_objects():
997
current_hooks = getattr(parent, name)
884
998
self._preserved_hooks[parent] = (name, current_hooks)
885
999
self.addCleanup(self._restoreHooks)
886
for key, factory in hooks.known_hooks.items():
887
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
1000
for key, (parent, name) in known_hooks.iter_parent_objects():
1001
factory = known_hooks.get(key)
888
1002
setattr(parent, name, factory())
889
1003
# this hook should always be installed
890
1004
request._install_hook()
1477
1590
Close the file and delete it, unless setKeepLogfile was called.
1479
if bzrlib.trace._trace_file:
1592
if trace._trace_file:
1480
1593
# flush the log file, to get all content
1481
bzrlib.trace._trace_file.flush()
1482
bzrlib.trace.pop_log_file(self._log_memento)
1594
trace._trace_file.flush()
1595
trace.pop_log_file(self._log_memento)
1483
1596
# Cache the log result and delete the file on disk
1484
1597
self._get_log(False)
1515
1628
setattr(obj, attr_name, new)
1631
def overrideEnv(self, name, new):
1632
"""Set an environment variable, and reset it after the test.
1634
:param name: The environment variable name.
1636
:param new: The value to set the variable to. If None, the
1637
variable is deleted from the environment.
1639
:returns: The actual variable value.
1641
value = osutils.set_or_unset_env(name, new)
1642
self.addCleanup(osutils.set_or_unset_env, name, value)
1518
1645
def _cleanEnvironment(self):
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)
1646
for name, value in isolated_environ.iteritems():
1647
self.overrideEnv(name, value)
1580
1649
def _restoreHooks(self):
1581
1650
for klass, (name, hooks) in self._preserved_hooks.items():
2024
2094
if retcode is not None and retcode != process.returncode:
2025
2095
if process_args is None:
2026
2096
process_args = "(unknown args)"
2027
mutter('Output of bzr %s:\n%s', process_args, out)
2028
mutter('Error for bzr %s:\n%s', process_args, err)
2097
trace.mutter('Output of bzr %s:\n%s', process_args, out)
2098
trace.mutter('Error for bzr %s:\n%s', process_args, err)
2029
2099
self.fail('Command bzr %s failed with retcode %s != %s'
2030
2100
% (process_args, retcode, process.returncode))
2031
2101
return [out, err]
2418
2488
test_home_dir = self.test_home_dir
2419
2489
if isinstance(test_home_dir, unicode):
2420
2490
test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
2421
os.environ['HOME'] = test_home_dir
2422
os.environ['BZR_HOME'] = test_home_dir
2491
self.overrideEnv('HOME', test_home_dir)
2492
self.overrideEnv('BZR_HOME', test_home_dir)
2424
2494
def setUp(self):
2425
2495
super(TestCaseWithMemoryTransport, self).setUp()
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):
3404
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3367
3405
"""Generate profiling data for all activity between start and success.
3369
3407
The profile data is appended to the test's _benchcalls attribute and can
3391
3429
test._benchcalls = []
3392
3430
calls = test._benchcalls
3393
3431
calls.append(((test.id(), "", ""), stats))
3394
ForwardingResult.addSuccess(self, test)
3432
testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
3396
3434
def stopTest(self, test):
3397
ForwardingResult.stopTest(self, test)
3435
testtools.ExtendedToOriginalDecorator.stopTest(self, test)
3398
3436
self.profiler = None
3773
3812
'bzrlib.tests.test_permissions',
3774
3813
'bzrlib.tests.test_plugins',
3775
3814
'bzrlib.tests.test_progress',
3815
'bzrlib.tests.test_pyutils',
3776
3816
'bzrlib.tests.test_read_bundle',
3777
3817
'bzrlib.tests.test_reconcile',
3778
3818
'bzrlib.tests.test_reconfigure',
3919
3962
# note that this really does mean "report only" -- doctest
3920
3963
# still runs the rest of the examples
3921
doc_suite = doctest.DocTestSuite(mod,
3922
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
3964
doc_suite = IsolatedDocTestSuite(
3965
mod, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
3923
3966
except ValueError, e:
3924
3967
print '**failed to get doctest for: %s\n%s' % (mod, e)
3961
4004
# Some tests mentioned in the list are not in the test suite. The
3962
4005
# list may be out of date, report to the tester.
3963
4006
for id in not_found:
3964
bzrlib.trace.warning('"%s" not found in the test suite', id)
4007
trace.warning('"%s" not found in the test suite', id)
3965
4008
for id in duplicates:
3966
bzrlib.trace.warning('"%s" is used as an id by several tests', id)
4009
trace.warning('"%s" is used as an id by several tests', id)
3971
def multiply_scenarios(scenarios_left, scenarios_right):
4014
def multiply_scenarios(*scenarios):
4015
"""Multiply two or more iterables of scenarios.
4017
It is safe to pass scenario generators or iterators.
4019
:returns: A list of compound scenarios: the cross-product of all
4020
scenarios, with the names concatenated and the parameters
4023
return reduce(_multiply_two_scenarios, map(list, scenarios))
4026
def _multiply_two_scenarios(scenarios_left, scenarios_right):
3972
4027
"""Multiply two sets of scenarios.
3974
4029
:returns: the cartesian product of the two sets of scenarios, that is
4257
4312
symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4258
4313
# Import the new feature and use it as a replacement for the
4259
4314
# deprecated one.
4260
mod = __import__(self._replacement_module, {}, {},
4261
[self._replacement_name])
4262
self._feature = getattr(mod, self._replacement_name)
4315
self._feature = pyutils.get_named_object(
4316
self._replacement_module, self._replacement_name)
4264
4318
def _probe(self):
4296
4350
return self.module_name
4299
# This is kept here for compatibility, it is recommended to use
4300
# 'bzrlib.tests.feature.paramiko' instead
4301
ParamikoFeature = _CompatabilityThunkFeature(
4302
deprecated_in((2,1,0)),
4303
'bzrlib.tests.features', 'ParamikoFeature', 'paramiko')
4306
4353
def probe_unicode_in_user_encoding():
4307
4354
"""Try to encode several unicode strings to use in unicode-aware tests.
4308
4355
Return first successfull match.