55
56
# nb: check this before importing anything else from within it
56
57
_testtools_version = getattr(testtools, '__version__', ())
57
if _testtools_version < (0, 9, 2):
58
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"
59
60
% (testtools.__file__, _testtools_version))
60
61
from testtools import content
62
64
from bzrlib import (
68
commands as _mod_commands,
77
plugin as _mod_plugin,
84
transport as _mod_transport,
80
import bzrlib.commands
81
import bzrlib.timestamp
83
import bzrlib.inventory
84
import bzrlib.iterablefile
87
88
import bzrlib.lsprof
88
89
except ImportError:
89
90
# lsprof not available
91
from bzrlib.merge import merge_inner
94
from bzrlib.smart import client, request, server
96
from bzrlib import symbol_versioning
97
from bzrlib.symbol_versioning import (
92
from bzrlib.smart import client, request
105
93
from bzrlib.transport import (
110
import bzrlib.transport
111
from bzrlib.trace import mutter, note
112
97
from bzrlib.tests import (
116
from bzrlib.tests.http_server import HttpServer
117
from bzrlib.tests.TestUtil import (
121
from bzrlib.tests.treeshape import build_tree_contents
122
102
from bzrlib.ui import NullProgressView
123
103
from bzrlib.ui.text import TextUIFactory
124
import bzrlib.version_info_formats.format_custom
125
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
127
105
# Mark this python module as being part of the implementation
128
106
# of unittest: this gives us better tracebacks where the last
140
118
SUBUNIT_SEEK_SET = 0
141
119
SUBUNIT_SEEK_CUR = 1
144
class ExtendedTestResult(unittest._TextTestResult):
121
# These are intentionally brought into this namespace. That way plugins, etc
122
# can just "from bzrlib.tests import TestCase, TestLoader, etc"
123
TestSuite = TestUtil.TestSuite
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,
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
class ExtendedTestResult(testtools.TextTestResult):
145
217
"""Accepts, reports and accumulates the results of running tests.
147
219
Compared to the unittest version this class adds support for
196
268
self._overall_start_time = time.time()
197
269
self._strict = strict
270
self._first_thread_leaker_id = None
271
self._tests_leaking_threads_count = 0
272
self._traceback_from_test = None
199
274
def stopTestRun(self):
200
275
run = self.testsRun
201
276
actionTaken = "Ran"
202
277
stopTime = time.time()
203
278
timeTaken = stopTime - self.startTime
205
self.stream.writeln(self.separator2)
206
self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
279
# GZ 2010-07-19: Seems testtools has no printErrors method, and though
280
# the parent class method is similar have to duplicate
281
self._show_list('ERROR', self.errors)
282
self._show_list('FAIL', self.failures)
283
self.stream.write(self.sep2)
284
self.stream.write("%s %d test%s in %.3fs\n\n" % (actionTaken,
207
285
run, run != 1 and "s" or "", timeTaken))
208
self.stream.writeln()
209
286
if not self.wasSuccessful():
210
287
self.stream.write("FAILED (")
211
288
failed, errored = map(len, (self.failures, self.errors))
218
295
if failed or errored: self.stream.write(", ")
219
296
self.stream.write("known_failure_count=%d" %
220
297
self.known_failure_count)
221
self.stream.writeln(")")
298
self.stream.write(")\n")
223
300
if self.known_failure_count:
224
self.stream.writeln("OK (known_failures=%d)" %
301
self.stream.write("OK (known_failures=%d)\n" %
225
302
self.known_failure_count)
227
self.stream.writeln("OK")
304
self.stream.write("OK\n")
228
305
if self.skip_count > 0:
229
306
skipped = self.skip_count
230
self.stream.writeln('%d test%s skipped' %
307
self.stream.write('%d test%s skipped\n' %
231
308
(skipped, skipped != 1 and "s" or ""))
232
309
if self.unsupported:
233
310
for feature, count in sorted(self.unsupported.items()):
234
self.stream.writeln("Missing feature '%s' skipped %d tests." %
311
self.stream.write("Missing feature '%s' skipped %d tests.\n" %
235
312
(feature, count))
237
314
ok = self.wasStrictlySuccessful()
239
316
ok = self.wasSuccessful()
240
if TestCase._first_thread_leaker_id:
317
if self._first_thread_leaker_id:
241
318
self.stream.write(
242
319
'%s is leaking threads among %d leaking tests.\n' % (
243
TestCase._first_thread_leaker_id,
244
TestCase._leaking_threads_tests))
320
self._first_thread_leaker_id,
321
self._tests_leaking_threads_count))
245
322
# We don't report the main thread as an active one.
246
323
self.stream.write(
247
324
'%d non-main threads were left active in the end.\n'
248
% (TestCase._active_threads - 1))
325
% (len(self._active_threads) - 1))
250
327
def getDescription(self, test):
276
354
def _shortened_test_description(self, test):
278
what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
356
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]
281
367
def startTest(self, test):
282
unittest.TestResult.startTest(self, test)
368
super(ExtendedTestResult, self).startTest(test)
283
369
if self.count == 0:
284
370
self.startTests()
285
372
self.report_test_start(test)
286
373
test.number = self.count
287
374
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
289
394
def startTests(self):
291
if getattr(sys, 'frozen', None) is None:
292
bzr_path = osutils.realpath(sys.argv[0])
294
bzr_path = sys.executable
296
'bzr selftest: %s\n' % (bzr_path,))
299
bzrlib.__path__[0],))
301
' bzr-%s python-%s %s\n' % (
302
bzrlib.version_string,
303
bzrlib._format_version_tuple(sys.version_info),
304
platform.platform(aliased=1),
306
self.stream.write('\n')
395
self.report_tests_starting()
396
self._active_threads = threading.enumerate()
398
def _check_leaked_threads(self, test):
399
"""See if any threads have leaked since last call
401
A sample of live threads is stored in the _active_threads attribute,
402
when this method runs it compares the current live threads and any not
403
in the previous sample are treated as having leaked.
405
now_active_threads = set(threading.enumerate())
406
threads_leaked = now_active_threads.difference(self._active_threads)
408
self._report_thread_leak(test, threads_leaked, now_active_threads)
409
self._tests_leaking_threads_count += 1
410
if self._first_thread_leaker_id is None:
411
self._first_thread_leaker_id = test.id()
412
self._active_threads = now_active_threads
308
414
def _recordTestStartTime(self):
309
415
"""Record that a test has started."""
310
self._start_time = time.time()
312
def _cleanupLogFile(self, test):
313
# We can only do this if we have one of our TestCases, not if
315
setKeepLogfile = getattr(test, 'setKeepLogfile', None)
316
if setKeepLogfile is not None:
416
self._start_datetime = self._now()
319
418
def addError(self, test, err):
320
419
"""Tell result that test finished with an error.
356
453
self._formatTime(benchmark_time),
358
455
self.report_success(test)
359
self._cleanupLogFile(test)
360
unittest.TestResult.addSuccess(self, test)
456
super(ExtendedTestResult, self).addSuccess(test)
361
457
test._log_contents = ''
363
459
def addExpectedFailure(self, test, err):
364
460
self.known_failure_count += 1
365
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()))
367
476
def addNotSupported(self, test, feature):
368
477
"""The test will not be run because of a missing feature.
401
511
raise errors.BzrError("Unknown whence %r" % whence)
403
def report_cleaning_up(self):
513
def report_tests_starting(self):
514
"""Display information before the test run begins"""
515
if getattr(sys, 'frozen', None) is None:
516
bzr_path = osutils.realpath(sys.argv[0])
518
bzr_path = sys.executable
520
'bzr selftest: %s\n' % (bzr_path,))
523
bzrlib.__path__[0],))
525
' bzr-%s python-%s %s\n' % (
526
bzrlib.version_string,
527
bzrlib._format_version_tuple(sys.version_info),
528
platform.platform(aliased=1),
530
self.stream.write('\n')
532
def report_test_start(self, test):
533
"""Display information on the test just about to be run"""
535
def _report_thread_leak(self, test, leaked_threads, active_threads):
536
"""Display information on a test that leaked one or more threads"""
537
# GZ 2010-09-09: A leak summary reported separately from the general
538
# thread debugging would be nice. Tests under subunit
539
# need something not using stream, perhaps adding a
540
# testtools details object would be fitting.
541
if 'threads' in selftest_debug_flags:
542
self.stream.write('%s is leaking, active is now %d\n' %
543
(test.id(), len(active_threads)))
406
545
def startTestRun(self):
407
546
self.startTime = time.time()
551
687
return '%s%s' % (indent, err[1])
553
689
def report_error(self, test, err):
554
self.stream.writeln('ERROR %s\n%s'
690
self.stream.write('ERROR %s\n%s\n'
555
691
% (self._testTimeString(test),
556
692
self._error_summary(err)))
558
694
def report_failure(self, test, err):
559
self.stream.writeln(' FAIL %s\n%s'
695
self.stream.write(' FAIL %s\n%s\n'
560
696
% (self._testTimeString(test),
561
697
self._error_summary(err)))
563
699
def report_known_failure(self, test, err):
564
self.stream.writeln('XFAIL %s\n%s'
700
self.stream.write('XFAIL %s\n%s\n'
565
701
% (self._testTimeString(test),
566
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",
568
710
def report_success(self, test):
569
self.stream.writeln(' OK %s' % self._testTimeString(test))
711
self.stream.write(' OK %s\n' % self._testTimeString(test))
570
712
for bench_called, stats in getattr(test, '_benchcalls', []):
571
self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
713
self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
572
714
stats.pprint(file=self.stream)
573
715
# flush the stream so that we get smooth output. This verbose mode is
574
716
# used to show the output in PQM.
575
717
self.stream.flush()
577
719
def report_skip(self, test, reason):
578
self.stream.writeln(' SKIP %s\n%s'
720
self.stream.write(' SKIP %s\n%s\n'
579
721
% (self._testTimeString(test), reason))
581
723
def report_not_applicable(self, test, reason):
582
self.stream.writeln(' N/A %s\n %s'
724
self.stream.write(' N/A %s\n %s\n'
583
725
% (self._testTimeString(test), reason))
585
727
def report_unsupported(self, test, feature):
586
728
"""test cannot be run because feature is missing."""
587
self.stream.writeln("NODEP %s\n The feature '%s' is not available."
729
self.stream.write("NODEP %s\n The feature '%s' is not available.\n"
588
730
%(self._testTimeString(test), feature))
789
953
routine, and to build and check bzr trees.
791
955
In addition to the usual method of overriding tearDown(), this class also
792
allows subclasses to register functions into the _cleanups list, which is
956
allows subclasses to register cleanup functions via addCleanup, which are
793
957
run in order as the object is torn down. It's less likely this will be
794
958
accidentally overlooked.
797
_active_threads = None
798
_leaking_threads_tests = 0
799
_first_thread_leaker_id = None
800
_log_file_name = None
801
962
# record lsprof data when performing benchmark calls.
802
963
_gather_lsprof_in_benchmarks = False
804
965
def __init__(self, methodName='testMethod'):
805
966
super(TestCase, self).__init__(methodName)
807
967
self._directory_isolation = True
808
968
self.exception_handlers.insert(0,
809
969
(UnavailableFeature, self._do_unsupported_or_skip))
827
983
self._track_transports()
828
984
self._track_locks()
829
985
self._clear_debug_flags()
830
TestCase._active_threads = threading.activeCount()
831
self.addCleanup(self._check_leaked_threads)
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()
833
1002
def debug(self):
834
1003
# debug a frame up.
836
1005
pdb.Pdb().set_trace(sys._getframe().f_back)
838
def _check_leaked_threads(self):
839
active = threading.activeCount()
840
leaked_threads = active - TestCase._active_threads
841
TestCase._active_threads = active
842
# If some tests make the number of threads *decrease*, we'll consider
843
# that they are just observing old threads dieing, not agressively kill
844
# random threads. So we don't report these tests as leaking. The risk
845
# is that we have false positives that way (the test see 2 threads
846
# going away but leak one) but it seems less likely than the actual
847
# false positives (the test see threads going away and does not leak).
848
if leaked_threads > 0:
849
TestCase._leaking_threads_tests += 1
850
if TestCase._first_thread_leaker_id is None:
851
TestCase._first_thread_leaker_id = self.id()
1007
def discardDetail(self, name):
1008
"""Extend the addDetail, getDetails api so we can remove a detail.
1010
eg. bzr always adds the 'log' detail at startup, but we don't want to
1011
include it for skipped, xfail, etc tests.
1013
It is safe to call this for a detail that doesn't exist, in case this
1014
gets called multiple times.
1016
# We cheat. details is stored in __details which means we shouldn't
1017
# touch it. but getDetails() returns the dict directly, so we can
1019
details = self.getDetails()
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,))
853
1067
def _clear_debug_flags(self):
854
1068
"""Prevent externally set debug flags affecting tests.
866
1080
def _clear_hooks(self):
867
1081
# prevent hooks affecting tests
1082
known_hooks = hooks.known_hooks
868
1083
self._preserved_hooks = {}
869
for key, factory in hooks.known_hooks.items():
870
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
871
current_hooks = hooks.known_hooks_key_to_object(key)
1084
for key, (parent, name) in known_hooks.iter_parent_objects():
1085
current_hooks = getattr(parent, name)
872
1086
self._preserved_hooks[parent] = (name, current_hooks)
1087
self._preserved_lazy_hooks = hooks._lazy_hooks
1088
hooks._lazy_hooks = {}
873
1089
self.addCleanup(self._restoreHooks)
874
for key, factory in hooks.known_hooks.items():
875
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
1090
for key, (parent, name) in known_hooks.iter_parent_objects():
1091
factory = known_hooks.get(key)
876
1092
setattr(parent, name, factory())
877
1093
# this hook should always be installed
878
1094
request._install_hook()
907
1123
# break some locks on purpose and should be taken into account by
908
1124
# considering that breaking a lock is just a dirty way of releasing it.
909
1125
if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
910
message = ('Different number of acquired and '
911
'released or broken locks. (%s, %s + %s)' %
912
(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))
913
1133
if not self._lock_check_thorough:
914
1134
# Rather than fail, just warn
915
1135
print "Broken test %s: %s" % (self, message)
1135
1355
'st_mtime did not match')
1136
1356
self.assertEqual(expected.st_ctime, actual.st_ctime,
1137
1357
'st_ctime did not match')
1138
if sys.platform != 'win32':
1358
if sys.platform == 'win32':
1139
1359
# On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1140
1360
# is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
1141
# odd. Regardless we shouldn't actually try to assert anything
1142
# 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)
1143
1367
self.assertEqual(expected.st_dev, actual.st_dev,
1144
1368
'st_dev did not match')
1145
1369
self.assertEqual(expected.st_ino, actual.st_ino,
1154
1378
length, len(obj_with_len), obj_with_len))
1156
1380
def assertLogsError(self, exception_class, func, *args, **kwargs):
1157
"""Assert that func(*args, **kwargs) quietly logs a specific exception.
1381
"""Assert that `func(*args, **kwargs)` quietly logs a specific error.
1159
from bzrlib import trace
1161
1384
orig_log_exception_quietly = trace.log_exception_quietly
1164
1387
orig_log_exception_quietly()
1165
captured.append(sys.exc_info())
1388
captured.append(sys.exc_info()[1])
1166
1389
trace.log_exception_quietly = capture
1167
1390
func(*args, **kwargs)
1169
1392
trace.log_exception_quietly = orig_log_exception_quietly
1170
1393
self.assertLength(1, captured)
1171
err = captured[0][1]
1172
1395
self.assertIsInstance(err, exception_class)
1322
1549
self.assertEqual(expected_docstring, obj.__doc__)
1551
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1324
1552
def failUnlessExists(self, path):
1553
return self.assertPathExists(path)
1555
def assertPathExists(self, path):
1325
1556
"""Fail unless path or paths, which may be abs or relative, exist."""
1326
1557
if not isinstance(path, basestring):
1328
self.failUnlessExists(p)
1559
self.assertPathExists(p)
1330
self.failUnless(osutils.lexists(path),path+" does not exist")
1561
self.assertTrue(osutils.lexists(path),
1562
path + " does not exist")
1564
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1332
1565
def failIfExists(self, path):
1566
return self.assertPathDoesNotExist(path)
1568
def assertPathDoesNotExist(self, path):
1333
1569
"""Fail if path or paths, which may be abs or relative, exist."""
1334
1570
if not isinstance(path, basestring):
1336
self.failIfExists(p)
1572
self.assertPathDoesNotExist(p)
1338
self.failIf(osutils.lexists(path),path+" exists")
1574
self.assertFalse(osutils.lexists(path),
1340
1577
def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
1341
1578
"""A helper for callDeprecated and applyDeprecated.
1456
1694
The file is removed as the test is torn down.
1458
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
1459
self._log_file = os.fdopen(fileno, 'w+')
1460
self._log_memento = bzrlib.trace.push_log_file(self._log_file)
1461
self._log_file_name = name
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)
1462
1705
self.addCleanup(self._finishLogFile)
1464
1707
def _finishLogFile(self):
1465
1708
"""Finished with the log file.
1467
Close the file and delete it, unless setKeepLogfile was called.
1710
Close the file and delete it.
1469
if bzrlib.trace._trace_file:
1712
if trace._trace_file:
1470
1713
# flush the log file, to get all content
1471
bzrlib.trace._trace_file.flush()
1472
bzrlib.trace.pop_log_file(self._log_memento)
1473
# Cache the log result and delete the file on disk
1474
self._get_log(False)
1714
trace._trace_file.flush()
1715
trace.pop_log_file(self._log_memento)
1476
1717
def thisFailsStrictLockCheck(self):
1477
1718
"""It is known that this test would fail with -Dstrict_locks.
1513
1746
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)
1516
1763
def _cleanEnvironment(self):
1518
'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
1519
'HOME': os.getcwd(),
1520
# bzr now uses the Win32 API and doesn't rely on APPDATA, but the
1521
# tests do check our impls match APPDATA
1522
'BZR_EDITOR': None, # test_msgeditor manipulates this variable
1526
'BZREMAIL': None, # may still be present in the environment
1528
'BZR_PROGRESS_BAR': None,
1530
'BZR_PLUGIN_PATH': None,
1531
'BZR_DISABLE_PLUGINS': None,
1532
'BZR_PLUGINS_AT': None,
1533
'BZR_CONCURRENCY': None,
1534
# Make sure that any text ui tests are consistent regardless of
1535
# the environment the test case is run in; you may want tests that
1536
# test other combinations. 'dumb' is a reasonable guess for tests
1537
# going to a pipe or a StringIO.
1541
'BZR_COLUMNS': '80',
1543
'SSH_AUTH_SOCK': None,
1547
'https_proxy': None,
1548
'HTTPS_PROXY': None,
1553
# Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
1554
# least. If you do (care), please update this comment
1558
'BZR_REMOTE_PATH': None,
1559
# Generally speaking, we don't want apport reporting on crashes in
1560
# the test envirnoment unless we're specifically testing apport,
1561
# so that it doesn't leak into the real system environment. We
1562
# use an env var so it propagates to subprocesses.
1563
'APPORT_DISABLE': '1',
1566
self.addCleanup(self._restoreEnvironment)
1567
for name, value in new_env.iteritems():
1568
self._captureVar(name, value)
1570
def _captureVar(self, name, newvalue):
1571
"""Set an environment variable, and reset it when finished."""
1572
self._old_env[name] = osutils.set_or_unset_env(name, newvalue)
1574
def _restoreEnvironment(self):
1575
for name, value in self._old_env.iteritems():
1576
osutils.set_or_unset_env(name, value)
1764
for name, value in isolated_environ.iteritems():
1765
self.overrideEnv(name, value)
1578
1767
def _restoreHooks(self):
1579
1768
for klass, (name, hooks) in self._preserved_hooks.items():
1580
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()
1582
1774
def knownFailure(self, reason):
1583
1775
"""This test has failed for some known reason."""
1584
1776
raise KnownFailure(reason)
1778
def _suppress_log(self):
1779
"""Remove the log info from details."""
1780
self.discardDetail('log')
1586
1782
def _do_skip(self, result, reason):
1783
self._suppress_log()
1587
1784
addSkip = getattr(result, 'addSkip', None)
1588
1785
if not callable(addSkip):
1589
1786
result.addSuccess(result)
1612
1811
self._do_skip(result, reason)
1814
def _report_skip(self, result, err):
1815
"""Override the default _report_skip.
1817
We want to strip the 'log' detail. If we waint until _do_skip, it has
1818
already been formatted into the 'reason' string, and we can't pull it
1821
self._suppress_log()
1822
super(TestCase, self)._report_skip(self, result, err)
1825
def _report_expected_failure(self, result, err):
1828
See _report_skip for motivation.
1830
self._suppress_log()
1831
super(TestCase, self)._report_expected_failure(self, result, err)
1615
1834
def _do_unsupported_or_skip(self, result, e):
1616
1835
reason = e.args[0]
1836
self._suppress_log()
1617
1837
addNotSupported = getattr(result, 'addNotSupported', None)
1618
1838
if addNotSupported is not None:
1619
1839
result.addNotSupported(self, reason)
1645
1865
self._benchtime += time.time() - start
1647
1867
def log(self, *args):
1650
def _get_log(self, keep_log_file=False):
1651
"""Internal helper to get the log from bzrlib.trace for this test.
1653
Please use self.getDetails, or self.get_log to access this in test case
1656
:param keep_log_file: When True, if the log is still a file on disk
1657
leave it as a file on disk. When False, if the log is still a file
1658
on disk, the log file is deleted and the log preserved as
1660
:return: A string containing the log.
1662
if self._log_contents is not None:
1664
self._log_contents.decode('utf8')
1665
except UnicodeDecodeError:
1666
unicodestr = self._log_contents.decode('utf8', 'replace')
1667
self._log_contents = unicodestr.encode('utf8')
1668
return self._log_contents
1670
if bzrlib.trace._trace_file:
1671
# flush the log file, to get all content
1672
bzrlib.trace._trace_file.flush()
1673
if self._log_file_name is not None:
1674
logfile = open(self._log_file_name)
1676
log_contents = logfile.read()
1680
log_contents.decode('utf8')
1681
except UnicodeDecodeError:
1682
unicodestr = log_contents.decode('utf8', 'replace')
1683
log_contents = unicodestr.encode('utf8')
1684
if not keep_log_file:
1686
max_close_attempts = 100
1687
first_close_error = None
1688
while close_attempts < max_close_attempts:
1691
self._log_file.close()
1692
except IOError, ioe:
1693
if ioe.errno is None:
1694
# No errno implies 'close() called during
1695
# concurrent operation on the same file object', so
1696
# retry. Probably a thread is trying to write to
1698
if first_close_error is None:
1699
first_close_error = ioe
1704
if close_attempts > 1:
1706
'Unable to close log file on first attempt, '
1707
'will retry: %s\n' % (first_close_error,))
1708
if close_attempts == max_close_attempts:
1710
'Unable to close log file after %d attempts.\n'
1711
% (max_close_attempts,))
1712
self._log_file = None
1713
# Permit multiple calls to get_log until we clean it up in
1715
self._log_contents = log_contents
1717
os.remove(self._log_file_name)
1719
if sys.platform == 'win32' and e.errno == errno.EACCES:
1720
sys.stderr.write(('Unable to delete log file '
1721
' %r\n' % self._log_file_name))
1724
self._log_file_name = None
1727
return "No log file content and no log file name."
1729
1870
def get_log(self):
1730
1871
"""Get a unicode string containing the log from bzrlib.trace.
1945
2087
variables. A value of None will unset the env variable.
1946
2088
The values must be strings. The change will only occur in the
1947
2089
child, so you don't need to fix the environment after running.
1948
:param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
2090
:param skip_if_plan_to_signal: raise TestSkipped when true and system
2091
doesn't support signalling subprocesses.
1950
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``.
1952
2097
:returns: Popen object for the started process.
1954
2099
if skip_if_plan_to_signal:
1955
if not getattr(os, 'kill', None):
1956
raise TestSkipped("os.kill not available.")
2100
if os.name != "posix":
2101
raise TestSkipped("Sending signals not supported")
1958
2103
if env_changes is None:
1959
2104
env_changes = {}
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,),
1997
2174
def _popen(self, *args, **kwargs):
1998
2175
"""Place a call to Popen.
2000
2177
Allows tests to override this method to intercept the calls made to
2001
2178
Popen for introspection.
2003
return Popen(*args, **kwargs)
2180
return subprocess.Popen(*args, **kwargs)
2005
2182
def get_source_path(self):
2006
2183
"""Return the path of the directory containing bzrlib."""
2036
2213
if retcode is not None and retcode != process.returncode:
2037
2214
if process_args is None:
2038
2215
process_args = "(unknown args)"
2039
mutter('Output of bzr %s:\n%s', process_args, out)
2040
mutter('Error for bzr %s:\n%s', process_args, err)
2216
trace.mutter('Output of bzr %s:\n%s', process_args, out)
2217
trace.mutter('Error for bzr %s:\n%s', process_args, err)
2041
2218
self.fail('Command bzr %s failed with retcode %s != %s'
2042
2219
% (process_args, retcode, process.returncode))
2043
2220
return [out, err]
2045
def check_inventory_shape(self, inv, shape):
2046
"""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.
2048
2225
Fail if they are not precisely equal.
2051
2228
shape = list(shape) # copy
2052
for path, ie in inv.entries():
2229
for path, ie in tree.iter_entries_by_dir():
2053
2230
name = path.replace('\\', '/')
2054
2231
if ie.kind == 'directory':
2055
2232
name = name + '/'
2234
pass # ignore root entry
2057
2236
shape.remove(name)
2059
2238
extras.append(name)
2149
2328
class TestCaseWithMemoryTransport(TestCase):
2150
2329
"""Common test class for tests that do not need disk resources.
2152
Tests that need disk resources should derive from TestCaseWithTransport.
2331
Tests that need disk resources should derive from TestCaseInTempDir
2332
orTestCaseWithTransport.
2154
2334
TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2156
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
2157
2337
a directory which does not exist. This serves to help ensure test isolation
2158
is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
2159
must exist. However, TestCaseWithMemoryTransport does not offer local
2160
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
2161
2341
override, so tests that accidentally write to the common directory should
2164
:cvar TEST_ROOT: Directory containing all temporary directories, plus
2165
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.
2168
2348
TEST_ROOT = None
2408
2588
made_control = self.make_bzrdir(relpath, format=format)
2409
2589
return made_control.create_repository(shared=shared)
2411
def make_smart_server(self, path):
2591
def make_smart_server(self, path, backing_server=None):
2592
if backing_server is None:
2593
backing_server = self.get_server()
2412
2594
smart_server = test_server.SmartTCPServer_for_testing()
2413
self.start_server(smart_server, self.get_server())
2414
remote_transport = get_transport(smart_server.get_url()).clone(path)
2595
self.start_server(smart_server, backing_server)
2596
remote_transport = _mod_transport.get_transport(smart_server.get_url()
2415
2598
return remote_transport
2417
2600
def make_branch_and_memory_tree(self, relpath, format=None):
2427
2610
test_home_dir = self.test_home_dir
2428
2611
if isinstance(test_home_dir, unicode):
2429
2612
test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
2430
os.environ['HOME'] = test_home_dir
2431
os.environ['BZR_HOME'] = test_home_dir
2613
self.overrideEnv('HOME', test_home_dir)
2614
self.overrideEnv('BZR_HOME', test_home_dir)
2433
2616
def setUp(self):
2434
2617
super(TestCaseWithMemoryTransport, self).setUp()
2618
# Ensure that ConnectedTransport doesn't leak sockets
2619
def get_transport_with_cleanup(*args, **kwargs):
2620
t = orig_get_transport(*args, **kwargs)
2621
if isinstance(t, _mod_transport.ConnectedTransport):
2622
self.addCleanup(t.disconnect)
2625
orig_get_transport = self.overrideAttr(_mod_transport, 'get_transport',
2626
get_transport_with_cleanup)
2435
2627
self._make_test_root()
2436
2628
self.addCleanup(os.chdir, os.getcwdu())
2437
2629
self.makeAndChdirToTestDir()
3191
3395
def partition_tests(suite, count):
3192
3396
"""Partition suite into count lists of tests."""
3194
tests = list(iter_suite_tests(suite))
3195
tests_per_process = int(math.ceil(float(len(tests)) / count))
3196
for block in range(count):
3197
low_test = block * tests_per_process
3198
high_test = low_test + tests_per_process
3199
process_tests = tests[low_test:high_test]
3200
result.append(process_tests)
3397
# This just assigns tests in a round-robin fashion. On one hand this
3398
# splits up blocks of related tests that might run faster if they shared
3399
# resources, but on the other it avoids assigning blocks of slow tests to
3400
# just one partition. So the slowest partition shouldn't be much slower
3402
partitions = [list() for i in range(count)]
3403
tests = iter_suite_tests(suite)
3404
for partition, test in itertools.izip(itertools.cycle(partitions), tests):
3405
partition.append(test)
3204
3409
def workaround_zealous_crypto_random():
3325
class ForwardingResult(unittest.TestResult):
3327
def __init__(self, target):
3328
unittest.TestResult.__init__(self)
3329
self.result = target
3331
def startTest(self, test):
3332
self.result.startTest(test)
3334
def stopTest(self, test):
3335
self.result.stopTest(test)
3337
def startTestRun(self):
3338
self.result.startTestRun()
3340
def stopTestRun(self):
3341
self.result.stopTestRun()
3343
def addSkip(self, test, reason):
3344
self.result.addSkip(test, reason)
3346
def addSuccess(self, test):
3347
self.result.addSuccess(test)
3349
def addError(self, test, err):
3350
self.result.addError(test, err)
3352
def addFailure(self, test, err):
3353
self.result.addFailure(test, err)
3354
ForwardingResult = testtools.ExtendedToOriginalDecorator
3357
class ProfileResult(ForwardingResult):
3532
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3358
3533
"""Generate profiling data for all activity between start and success.
3360
3535
The profile data is appended to the test's _benchcalls attribute and can
3648
3833
'bzrlib.tests.per_repository',
3649
3834
'bzrlib.tests.per_repository_chk',
3650
3835
'bzrlib.tests.per_repository_reference',
3836
'bzrlib.tests.per_repository_vf',
3651
3837
'bzrlib.tests.per_uifactory',
3652
3838
'bzrlib.tests.per_versionedfile',
3653
3839
'bzrlib.tests.per_workingtree',
3654
3840
'bzrlib.tests.test__annotator',
3655
3841
'bzrlib.tests.test__bencode',
3842
'bzrlib.tests.test__btree_serializer',
3656
3843
'bzrlib.tests.test__chk_map',
3657
3844
'bzrlib.tests.test__dirstate_helpers',
3658
3845
'bzrlib.tests.test__groupcompress',
3686
3873
'bzrlib.tests.test_commit_merge',
3687
3874
'bzrlib.tests.test_config',
3688
3875
'bzrlib.tests.test_conflicts',
3876
'bzrlib.tests.test_controldir',
3689
3877
'bzrlib.tests.test_counted_lock',
3690
3878
'bzrlib.tests.test_crash',
3691
3879
'bzrlib.tests.test_decorators',
3692
3880
'bzrlib.tests.test_delta',
3693
3881
'bzrlib.tests.test_debug',
3694
'bzrlib.tests.test_deprecated_graph',
3695
3882
'bzrlib.tests.test_diff',
3696
3883
'bzrlib.tests.test_directory_service',
3697
3884
'bzrlib.tests.test_dirstate',
3938
4139
# Some tests mentioned in the list are not in the test suite. The
3939
4140
# list may be out of date, report to the tester.
3940
4141
for id in not_found:
3941
bzrlib.trace.warning('"%s" not found in the test suite', id)
4142
trace.warning('"%s" not found in the test suite', id)
3942
4143
for id in duplicates:
3943
bzrlib.trace.warning('"%s" is used as an id by several tests', id)
4144
trace.warning('"%s" is used as an id by several tests', id)
3948
def multiply_scenarios(scenarios_left, scenarios_right):
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):
3949
4162
"""Multiply two sets of scenarios.
3951
4164
:returns: the cartesian product of the two sets of scenarios, that is
4446
4677
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
4449
# Kept for compatibility, use bzrlib.tests.features.subunit instead
4450
SubUnitFeature = _CompatabilityThunkFeature(
4451
deprecated_in((2,1,0)),
4452
'bzrlib.tests.features', 'SubUnitFeature', 'subunit')
4453
4680
# Only define SubUnitBzrRunner if subunit is available.
4455
4682
from subunit import TestProtocolClient
4456
4683
from subunit.test_results import AutoTimingTestResultDecorator
4684
class SubUnitBzrProtocolClient(TestProtocolClient):
4686
def addSuccess(self, test, details=None):
4687
# The subunit client always includes the details in the subunit
4688
# stream, but we don't want to include it in ours.
4689
if details is not None and 'log' in details:
4691
return super(SubUnitBzrProtocolClient, self).addSuccess(
4457
4694
class SubUnitBzrRunner(TextTestRunner):
4458
4695
def run(self, test):
4459
4696
result = AutoTimingTestResultDecorator(
4460
TestProtocolClient(self.stream))
4697
SubUnitBzrProtocolClient(self.stream))
4461
4698
test.run(result)
4463
4700
except ImportError: