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,
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)
213
142
class ExtendedTestResult(testtools.TextTestResult):
214
143
"""Accepts, reports and accumulates the results of running tests.
353
280
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]
364
283
def startTest(self, test):
365
284
super(ExtendedTestResult, self).startTest(test)
366
285
if self.count == 0:
369
288
self.report_test_start(test)
370
289
test.number = self.count
371
290
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)
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)
380
296
def startTests(self):
381
297
self.report_tests_starting()
382
298
self._active_threads = threading.enumerate()
384
def stopTest(self, test):
385
self._traceback_from_test = None
387
300
def _check_leaked_threads(self, test):
388
301
"""See if any threads have leaked since last call
471
384
self.not_applicable_count += 1
472
385
self.report_not_applicable(test, reason)
474
def _post_mortem(self, tb=None):
387
def _post_mortem(self):
475
388
"""Start a PDB post mortem session."""
476
389
if os.environ.get('BZR_TEST_PDB', None):
390
import pdb;pdb.post_mortem()
480
392
def progress(self, offset, whence):
481
393
"""The test is adjusting the count of tests to run."""
881
790
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)
903
793
class TestCase(testtools.TestCase):
904
794
"""Base class for bzr unit tests.
950
840
self._track_transports()
951
841
self._track_locks()
952
842
self._clear_debug_flags()
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)
959
845
# debug a frame up.
961
847
pdb.Pdb().set_trace(sys._getframe().f_back)
963
def discardDetail(self, name):
964
"""Extend the addDetail, getDetails api so we can remove a detail.
966
eg. bzr always adds the 'log' detail at startup, but we don't want to
967
include it for skipped, xfail, etc tests.
969
It is safe to call this for a detail that doesn't exist, in case this
970
gets called multiple times.
972
# We cheat. details is stored in __details which means we shouldn't
973
# touch it. but getDetails() returns the dict directly, so we can
975
details = self.getDetails()
979
849
def _clear_debug_flags(self):
980
850
"""Prevent externally set debug flags affecting tests.
992
862
def _clear_hooks(self):
993
863
# prevent hooks affecting tests
994
known_hooks = hooks.known_hooks
995
864
self._preserved_hooks = {}
996
for key, (parent, name) in known_hooks.iter_parent_objects():
997
current_hooks = getattr(parent, name)
865
for key, factory in hooks.known_hooks.items():
866
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
867
current_hooks = hooks.known_hooks_key_to_object(key)
998
868
self._preserved_hooks[parent] = (name, current_hooks)
999
869
self.addCleanup(self._restoreHooks)
1000
for key, (parent, name) in known_hooks.iter_parent_objects():
1001
factory = known_hooks.get(key)
870
for key, factory in hooks.known_hooks.items():
871
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
1002
872
setattr(parent, name, factory())
1003
873
# this hook should always be installed
1004
874
request._install_hook()
1590
1461
Close the file and delete it, unless setKeepLogfile was called.
1592
if trace._trace_file:
1463
if bzrlib.trace._trace_file:
1593
1464
# flush the log file, to get all content
1594
trace._trace_file.flush()
1595
trace.pop_log_file(self._log_memento)
1465
bzrlib.trace._trace_file.flush()
1466
bzrlib.trace.pop_log_file(self._log_memento)
1596
1467
# Cache the log result and delete the file on disk
1597
1468
self._get_log(False)
1628
1499
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)
1645
1502
def _cleanEnvironment(self):
1646
for name, value in isolated_environ.iteritems():
1647
self.overrideEnv(name, value)
1504
'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
1505
'HOME': os.getcwd(),
1506
# bzr now uses the Win32 API and doesn't rely on APPDATA, but the
1507
# tests do check our impls match APPDATA
1508
'BZR_EDITOR': None, # test_msgeditor manipulates this variable
1512
'BZREMAIL': None, # may still be present in the environment
1513
'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
1514
'BZR_PROGRESS_BAR': None,
1516
'BZR_PLUGIN_PATH': None,
1517
'BZR_DISABLE_PLUGINS': None,
1518
'BZR_PLUGINS_AT': None,
1519
'BZR_CONCURRENCY': None,
1520
# Make sure that any text ui tests are consistent regardless of
1521
# the environment the test case is run in; you may want tests that
1522
# test other combinations. 'dumb' is a reasonable guess for tests
1523
# going to a pipe or a StringIO.
1527
'BZR_COLUMNS': '80',
1529
'SSH_AUTH_SOCK': None,
1533
'https_proxy': None,
1534
'HTTPS_PROXY': None,
1539
# Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
1540
# least. If you do (care), please update this comment
1544
'BZR_REMOTE_PATH': None,
1545
# Generally speaking, we don't want apport reporting on crashes in
1546
# the test envirnoment unless we're specifically testing apport,
1547
# so that it doesn't leak into the real system environment. We
1548
# use an env var so it propagates to subprocesses.
1549
'APPORT_DISABLE': '1',
1552
self.addCleanup(self._restoreEnvironment)
1553
for name, value in new_env.iteritems():
1554
self._captureVar(name, value)
1556
def _captureVar(self, name, newvalue):
1557
"""Set an environment variable, and reset it when finished."""
1558
self._old_env[name] = osutils.set_or_unset_env(name, newvalue)
1560
def _restoreEnvironment(self):
1561
for name, value in self._old_env.iteritems():
1562
osutils.set_or_unset_env(name, value)
1649
1564
def _restoreHooks(self):
1650
1565
for klass, (name, hooks) in self._preserved_hooks.items():
1654
1569
"""This test has failed for some known reason."""
1655
1570
raise KnownFailure(reason)
1657
def _suppress_log(self):
1658
"""Remove the log info from details."""
1659
self.discardDetail('log')
1661
1572
def _do_skip(self, result, reason):
1662
self._suppress_log()
1663
1573
addSkip = getattr(result, 'addSkip', None)
1664
1574
if not callable(addSkip):
1665
1575
result.addSuccess(result)
1690
1598
self._do_skip(result, reason)
1693
def _report_skip(self, result, err):
1694
"""Override the default _report_skip.
1696
We want to strip the 'log' detail. If we waint until _do_skip, it has
1697
already been formatted into the 'reason' string, and we can't pull it
1700
self._suppress_log()
1701
super(TestCase, self)._report_skip(self, result, err)
1704
def _report_expected_failure(self, result, err):
1707
See _report_skip for motivation.
1709
self._suppress_log()
1710
super(TestCase, self)._report_expected_failure(self, result, err)
1713
1601
def _do_unsupported_or_skip(self, result, e):
1714
1602
reason = e.args[0]
1715
self._suppress_log()
1716
1603
addNotSupported = getattr(result, 'addNotSupported', None)
1717
1604
if addNotSupported is not None:
1718
1605
result.addNotSupported(self, reason)
2094
1980
if retcode is not None and retcode != process.returncode:
2095
1981
if process_args is None:
2096
1982
process_args = "(unknown args)"
2097
trace.mutter('Output of bzr %s:\n%s', process_args, out)
2098
trace.mutter('Error for bzr %s:\n%s', process_args, err)
1983
mutter('Output of bzr %s:\n%s', process_args, out)
1984
mutter('Error for bzr %s:\n%s', process_args, err)
2099
1985
self.fail('Command bzr %s failed with retcode %s != %s'
2100
1986
% (process_args, retcode, process.returncode))
2101
1987
return [out, err]
2488
2374
test_home_dir = self.test_home_dir
2489
2375
if isinstance(test_home_dir, unicode):
2490
2376
test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
2491
self.overrideEnv('HOME', test_home_dir)
2492
self.overrideEnv('BZR_HOME', test_home_dir)
2377
os.environ['HOME'] = test_home_dir
2378
os.environ['BZR_HOME'] = test_home_dir
2494
2380
def setUp(self):
2495
2381
super(TestCaseWithMemoryTransport, self).setUp()
3404
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3290
class ForwardingResult(unittest.TestResult):
3292
def __init__(self, target):
3293
unittest.TestResult.__init__(self)
3294
self.result = target
3296
def startTest(self, test):
3297
self.result.startTest(test)
3299
def stopTest(self, test):
3300
self.result.stopTest(test)
3302
def startTestRun(self):
3303
self.result.startTestRun()
3305
def stopTestRun(self):
3306
self.result.stopTestRun()
3308
def addSkip(self, test, reason):
3309
self.result.addSkip(test, reason)
3311
def addSuccess(self, test):
3312
self.result.addSuccess(test)
3314
def addError(self, test, err):
3315
self.result.addError(test, err)
3317
def addFailure(self, test, err):
3318
self.result.addFailure(test, err)
3319
ForwardingResult = testtools.ExtendedToOriginalDecorator
3322
class ProfileResult(ForwardingResult):
3405
3323
"""Generate profiling data for all activity between start and success.
3407
3325
The profile data is appended to the test's _benchcalls attribute and can
3429
3347
test._benchcalls = []
3430
3348
calls = test._benchcalls
3431
3349
calls.append(((test.id(), "", ""), stats))
3432
testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
3350
ForwardingResult.addSuccess(self, test)
3434
3352
def stopTest(self, test):
3435
testtools.ExtendedToOriginalDecorator.stopTest(self, test)
3353
ForwardingResult.stopTest(self, test)
3436
3354
self.profiler = None
3812
3729
'bzrlib.tests.test_permissions',
3813
3730
'bzrlib.tests.test_plugins',
3814
3731
'bzrlib.tests.test_progress',
3815
'bzrlib.tests.test_pyutils',
3816
3732
'bzrlib.tests.test_read_bundle',
3817
3733
'bzrlib.tests.test_reconcile',
3818
3734
'bzrlib.tests.test_reconfigure',
3962
3875
# note that this really does mean "report only" -- doctest
3963
3876
# still runs the rest of the examples
3964
doc_suite = IsolatedDocTestSuite(
3965
mod, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
3877
doc_suite = doctest.DocTestSuite(mod,
3878
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
3966
3879
except ValueError, e:
3967
3880
print '**failed to get doctest for: %s\n%s' % (mod, e)
4004
3917
# Some tests mentioned in the list are not in the test suite. The
4005
3918
# list may be out of date, report to the tester.
4006
3919
for id in not_found:
4007
trace.warning('"%s" not found in the test suite', id)
3920
bzrlib.trace.warning('"%s" not found in the test suite', id)
4008
3921
for id in duplicates:
4009
trace.warning('"%s" is used as an id by several tests', id)
3922
bzrlib.trace.warning('"%s" is used as an id by several tests', id)
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):
3927
def multiply_scenarios(scenarios_left, scenarios_right):
4027
3928
"""Multiply two sets of scenarios.
4029
3930
:returns: the cartesian product of the two sets of scenarios, that is
4312
4213
symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4313
4214
# Import the new feature and use it as a replacement for the
4314
4215
# deprecated one.
4315
self._feature = pyutils.get_named_object(
4316
self._replacement_module, self._replacement_name)
4216
mod = __import__(self._replacement_module, {}, {},
4217
[self._replacement_name])
4218
self._feature = getattr(mod, self._replacement_name)
4318
4220
def _probe(self):
4350
4252
return self.module_name
4255
# This is kept here for compatibility, it is recommended to use
4256
# 'bzrlib.tests.feature.paramiko' instead
4257
ParamikoFeature = _CompatabilityThunkFeature(
4258
deprecated_in((2,1,0)),
4259
'bzrlib.tests.features', 'ParamikoFeature', 'paramiko')
4353
4262
def probe_unicode_in_user_encoding():
4354
4263
"""Try to encode several unicode strings to use in unicode-aware tests.
4355
4264
Return first successfull match.
4542
4451
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
4454
# Kept for compatibility, use bzrlib.tests.features.subunit instead
4455
SubUnitFeature = _CompatabilityThunkFeature(
4456
deprecated_in((2,1,0)),
4457
'bzrlib.tests.features', 'SubUnitFeature', 'subunit')
4545
4458
# Only define SubUnitBzrRunner if subunit is available.
4547
4460
from subunit import TestProtocolClient
4548
4461
from subunit.test_results import AutoTimingTestResultDecorator
4549
class SubUnitBzrProtocolClient(TestProtocolClient):
4551
def addSuccess(self, test, details=None):
4552
# The subunit client always includes the details in the subunit
4553
# stream, but we don't want to include it in ours.
4554
if details is not None and 'log' in details:
4556
return super(SubUnitBzrProtocolClient, self).addSuccess(
4559
4462
class SubUnitBzrRunner(TextTestRunner):
4560
4463
def run(self, test):
4561
4464
result = AutoTimingTestResultDecorator(
4562
SubUnitBzrProtocolClient(self.stream))
4465
TestProtocolClient(self.stream))
4563
4466
test.run(result)
4565
4468
except ImportError: