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,
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
class ExtendedTestResult(testtools.TextTestResult):
145
214
"""Accepts, reports and accumulates the results of running tests.
147
216
Compared to the unittest version this class adds support for
196
265
self._overall_start_time = time.time()
197
266
self._strict = strict
267
self._first_thread_leaker_id = None
268
self._tests_leaking_threads_count = 0
269
self._traceback_from_test = None
199
271
def stopTestRun(self):
200
272
run = self.testsRun
201
273
actionTaken = "Ran"
202
274
stopTime = time.time()
203
275
timeTaken = stopTime - self.startTime
205
self.stream.writeln(self.separator2)
206
self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
276
# GZ 2010-07-19: Seems testtools has no printErrors method, and though
277
# the parent class method is similar have to duplicate
278
self._show_list('ERROR', self.errors)
279
self._show_list('FAIL', self.failures)
280
self.stream.write(self.sep2)
281
self.stream.write("%s %d test%s in %.3fs\n\n" % (actionTaken,
207
282
run, run != 1 and "s" or "", timeTaken))
208
self.stream.writeln()
209
283
if not self.wasSuccessful():
210
284
self.stream.write("FAILED (")
211
285
failed, errored = map(len, (self.failures, self.errors))
218
292
if failed or errored: self.stream.write(", ")
219
293
self.stream.write("known_failure_count=%d" %
220
294
self.known_failure_count)
221
self.stream.writeln(")")
295
self.stream.write(")\n")
223
297
if self.known_failure_count:
224
self.stream.writeln("OK (known_failures=%d)" %
298
self.stream.write("OK (known_failures=%d)\n" %
225
299
self.known_failure_count)
227
self.stream.writeln("OK")
301
self.stream.write("OK\n")
228
302
if self.skip_count > 0:
229
303
skipped = self.skip_count
230
self.stream.writeln('%d test%s skipped' %
304
self.stream.write('%d test%s skipped\n' %
231
305
(skipped, skipped != 1 and "s" or ""))
232
306
if self.unsupported:
233
307
for feature, count in sorted(self.unsupported.items()):
234
self.stream.writeln("Missing feature '%s' skipped %d tests." %
308
self.stream.write("Missing feature '%s' skipped %d tests.\n" %
235
309
(feature, count))
237
311
ok = self.wasStrictlySuccessful()
239
313
ok = self.wasSuccessful()
240
if TestCase._first_thread_leaker_id:
314
if self._first_thread_leaker_id:
241
315
self.stream.write(
242
316
'%s is leaking threads among %d leaking tests.\n' % (
243
TestCase._first_thread_leaker_id,
244
TestCase._leaking_threads_tests))
317
self._first_thread_leaker_id,
318
self._tests_leaking_threads_count))
245
319
# We don't report the main thread as an active one.
246
320
self.stream.write(
247
321
'%d non-main threads were left active in the end.\n'
248
% (TestCase._active_threads - 1))
322
% (len(self._active_threads) - 1))
250
324
def getDescription(self, test):
276
351
def _shortened_test_description(self, test):
278
what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
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]
281
364
def startTest(self, test):
282
unittest.TestResult.startTest(self, test)
365
super(ExtendedTestResult, self).startTest(test)
283
366
if self.count == 0:
284
367
self.startTests()
285
369
self.report_test_start(test)
286
370
test.number = self.count
287
371
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)
289
380
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')
381
self.report_tests_starting()
382
self._active_threads = threading.enumerate()
384
def stopTest(self, test):
385
self._traceback_from_test = None
387
def _check_leaked_threads(self, test):
388
"""See if any threads have leaked since last call
390
A sample of live threads is stored in the _active_threads attribute,
391
when this method runs it compares the current live threads and any not
392
in the previous sample are treated as having leaked.
394
now_active_threads = set(threading.enumerate())
395
threads_leaked = now_active_threads.difference(self._active_threads)
397
self._report_thread_leak(test, threads_leaked, now_active_threads)
398
self._tests_leaking_threads_count += 1
399
if self._first_thread_leaker_id is None:
400
self._first_thread_leaker_id = test.id()
401
self._active_threads = now_active_threads
308
403
def _recordTestStartTime(self):
309
404
"""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:
405
self._start_datetime = self._now()
319
407
def addError(self, test, err):
320
408
"""Tell result that test finished with an error.
322
410
Called from the TestCase run() method when the test
323
411
fails with an unexpected error.
326
unittest.TestResult.addError(self, test, err)
413
self._post_mortem(self._traceback_from_test)
414
super(ExtendedTestResult, self).addError(test, err)
327
415
self.error_count += 1
328
416
self.report_error(test, err)
329
417
if self.stop_early:
331
self._cleanupLogFile(test)
333
420
def addFailure(self, test, err):
334
421
"""Tell result that test failed.
336
423
Called from the TestCase run() method when the test
337
424
fails because e.g. an assert() method failed.
340
unittest.TestResult.addFailure(self, test, err)
426
self._post_mortem(self._traceback_from_test)
427
super(ExtendedTestResult, self).addFailure(test, err)
341
428
self.failure_count += 1
342
429
self.report_failure(test, err)
343
430
if self.stop_early:
345
self._cleanupLogFile(test)
347
433
def addSuccess(self, test, details=None):
348
434
"""Tell result that test completed successfully.
401
487
raise errors.BzrError("Unknown whence %r" % whence)
403
def report_cleaning_up(self):
489
def report_tests_starting(self):
490
"""Display information before the test run begins"""
491
if getattr(sys, 'frozen', None) is None:
492
bzr_path = osutils.realpath(sys.argv[0])
494
bzr_path = sys.executable
496
'bzr selftest: %s\n' % (bzr_path,))
499
bzrlib.__path__[0],))
501
' bzr-%s python-%s %s\n' % (
502
bzrlib.version_string,
503
bzrlib._format_version_tuple(sys.version_info),
504
platform.platform(aliased=1),
506
self.stream.write('\n')
508
def report_test_start(self, test):
509
"""Display information on the test just about to be run"""
511
def _report_thread_leak(self, test, leaked_threads, active_threads):
512
"""Display information on a test that leaked one or more threads"""
513
# GZ 2010-09-09: A leak summary reported separately from the general
514
# thread debugging would be nice. Tests under subunit
515
# need something not using stream, perhaps adding a
516
# testtools details object would be fitting.
517
if 'threads' in selftest_debug_flags:
518
self.stream.write('%s is leaking, active is now %d\n' %
519
(test.id(), len(active_threads)))
406
521
def startTestRun(self):
407
522
self.startTime = time.time()
444
559
self.pb.finished()
445
560
super(TextTestResult, self).stopTestRun()
447
def startTestRun(self):
448
super(TextTestResult, self).startTestRun()
562
def report_tests_starting(self):
563
super(TextTestResult, self).report_tests_starting()
449
564
self.pb.update('[test 0/%d] Starting' % (self.num_tests))
451
def printErrors(self):
452
# clear the pb to make room for the error listing
454
super(TextTestResult, self).printErrors()
456
566
def _progress_prefix_text(self):
457
567
# the longer this text, the less space we have to show the test
551
656
return '%s%s' % (indent, err[1])
553
658
def report_error(self, test, err):
554
self.stream.writeln('ERROR %s\n%s'
659
self.stream.write('ERROR %s\n%s\n'
555
660
% (self._testTimeString(test),
556
661
self._error_summary(err)))
558
663
def report_failure(self, test, err):
559
self.stream.writeln(' FAIL %s\n%s'
664
self.stream.write(' FAIL %s\n%s\n'
560
665
% (self._testTimeString(test),
561
666
self._error_summary(err)))
563
668
def report_known_failure(self, test, err):
564
self.stream.writeln('XFAIL %s\n%s'
669
self.stream.write('XFAIL %s\n%s\n'
565
670
% (self._testTimeString(test),
566
671
self._error_summary(err)))
568
673
def report_success(self, test):
569
self.stream.writeln(' OK %s' % self._testTimeString(test))
674
self.stream.write(' OK %s\n' % self._testTimeString(test))
570
675
for bench_called, stats in getattr(test, '_benchcalls', []):
571
self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
676
self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
572
677
stats.pprint(file=self.stream)
573
678
# flush the stream so that we get smooth output. This verbose mode is
574
679
# used to show the output in PQM.
575
680
self.stream.flush()
577
682
def report_skip(self, test, reason):
578
self.stream.writeln(' SKIP %s\n%s'
683
self.stream.write(' SKIP %s\n%s\n'
579
684
% (self._testTimeString(test), reason))
581
686
def report_not_applicable(self, test, reason):
582
self.stream.writeln(' N/A %s\n %s'
687
self.stream.write(' N/A %s\n %s\n'
583
688
% (self._testTimeString(test), reason))
585
690
def report_unsupported(self, test, feature):
586
691
"""test cannot be run because feature is missing."""
587
self.stream.writeln("NODEP %s\n The feature '%s' is not available."
692
self.stream.write("NODEP %s\n The feature '%s' is not available.\n"
588
693
%(self._testTimeString(test), feature))
617
722
encode = codec[0]
619
724
encode = codec.encode
620
stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
725
# GZ 2010-09-08: Really we don't want to be writing arbitrary bytes,
726
# so should swap to the plain codecs.StreamWriter
727
stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream,
621
729
stream.encoding = new_encoding
622
self.stream = unittest._WritelnDecorator(stream)
623
731
self.descriptions = descriptions
624
732
self.verbosity = verbosity
625
733
self._bench_history = bench_history
773
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)
776
903
class TestCase(testtools.TestCase):
777
904
"""Base class for bzr unit tests.
789
916
routine, and to build and check bzr trees.
791
918
In addition to the usual method of overriding tearDown(), this class also
792
allows subclasses to register functions into the _cleanups list, which is
919
allows subclasses to register cleanup functions via addCleanup, which are
793
920
run in order as the object is torn down. It's less likely this will be
794
921
accidentally overlooked.
797
_active_threads = None
798
_leaking_threads_tests = 0
799
_first_thread_leaker_id = None
800
_log_file_name = None
801
925
# record lsprof data when performing benchmark calls.
802
926
_gather_lsprof_in_benchmarks = False
804
928
def __init__(self, methodName='testMethod'):
805
929
super(TestCase, self).__init__(methodName)
807
930
self._directory_isolation = True
808
931
self.exception_handlers.insert(0,
809
932
(UnavailableFeature, self._do_unsupported_or_skip))
827
950
self._track_transports()
828
951
self._track_locks()
829
952
self._clear_debug_flags()
830
TestCase._active_threads = threading.activeCount()
831
self.addCleanup(self._check_leaked_threads)
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)
834
959
# debug a frame up.
836
961
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()
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()
853
979
def _clear_debug_flags(self):
854
980
"""Prevent externally set debug flags affecting tests.
866
992
def _clear_hooks(self):
867
993
# prevent hooks affecting tests
994
known_hooks = hooks.known_hooks
868
995
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)
996
for key, (parent, name) in known_hooks.iter_parent_objects():
997
current_hooks = getattr(parent, name)
872
998
self._preserved_hooks[parent] = (name, current_hooks)
873
999
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)
1000
for key, (parent, name) in known_hooks.iter_parent_objects():
1001
factory = known_hooks.get(key)
876
1002
setattr(parent, name, factory())
877
1003
# this hook should always be installed
878
1004
request._install_hook()
1211
1336
if haystack.find(needle) == -1:
1212
1337
self.fail("string %r not found in '''%s'''" % (needle, haystack))
1339
def assertNotContainsString(self, haystack, needle):
1340
if haystack.find(needle) != -1:
1341
self.fail("string %r found in '''%s'''" % (needle, haystack))
1214
1343
def assertSubset(self, sublist, superlist):
1215
1344
"""Assert that every entry in sublist is present in superlist."""
1216
1345
missing = set(sublist) - set(superlist)
1487
1614
debug.debug_flags.discard('strict_locks')
1489
def addCleanup(self, callable, *args, **kwargs):
1490
"""Arrange to run a callable when this case is torn down.
1492
Callables are run in the reverse of the order they are registered,
1493
ie last-in first-out.
1495
self._cleanups.append((callable, args, kwargs))
1497
1616
def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1498
1617
"""Overrides an object attribute restoring it after the test.
1513
1632
setattr(obj, attr_name, new)
1635
def overrideEnv(self, name, new):
1636
"""Set an environment variable, and reset it after the test.
1638
:param name: The environment variable name.
1640
:param new: The value to set the variable to. If None, the
1641
variable is deleted from the environment.
1643
:returns: The actual variable value.
1645
value = osutils.set_or_unset_env(name, new)
1646
self.addCleanup(osutils.set_or_unset_env, name, value)
1516
1649
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)
1650
for name, value in isolated_environ.iteritems():
1651
self.overrideEnv(name, value)
1578
1653
def _restoreHooks(self):
1579
1654
for klass, (name, hooks) in self._preserved_hooks.items():
1612
1694
self._do_skip(result, reason)
1697
def _report_skip(self, result, err):
1698
"""Override the default _report_skip.
1700
We want to strip the 'log' detail. If we waint until _do_skip, it has
1701
already been formatted into the 'reason' string, and we can't pull it
1704
self._suppress_log()
1705
super(TestCase, self)._report_skip(self, result, err)
1708
def _report_expected_failure(self, result, err):
1711
See _report_skip for motivation.
1713
self._suppress_log()
1714
super(TestCase, self)._report_expected_failure(self, result, err)
1615
1717
def _do_unsupported_or_skip(self, result, e):
1616
1718
reason = e.args[0]
1719
self._suppress_log()
1617
1720
addNotSupported = getattr(result, 'addNotSupported', None)
1618
1721
if addNotSupported is not None:
1619
1722
result.addNotSupported(self, reason)
1666
1769
unicodestr = self._log_contents.decode('utf8', 'replace')
1667
1770
self._log_contents = unicodestr.encode('utf8')
1668
1771
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()
1772
if self._log_file is not None:
1773
log_contents = self._log_file.getvalue()
1680
1775
log_contents.decode('utf8')
1681
1776
except UnicodeDecodeError:
1682
1777
unicodestr = log_contents.decode('utf8', 'replace')
1683
1778
log_contents = unicodestr.encode('utf8')
1684
1779
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
1780
self._log_file = None
1713
1781
# Permit multiple calls to get_log until we clean it up in
1714
1782
# finishLogFile
1715
1783
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
1725
1784
return log_contents
1727
return "No log file content and no log file name."
1786
return "No log file content."
1729
1788
def get_log(self):
1730
1789
"""Get a unicode string containing the log from bzrlib.trace.
1945
2005
variables. A value of None will unset the env variable.
1946
2006
The values must be strings. The change will only occur in the
1947
2007
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
2008
:param skip_if_plan_to_signal: raise TestSkipped when true and system
2009
doesn't support signalling subprocesses.
1950
2010
:param allow_plugins: If False (default) pass --no-plugins to bzr.
1952
2012
:returns: Popen object for the started process.
1954
2014
if skip_if_plan_to_signal:
1955
if not getattr(os, 'kill', None):
1956
raise TestSkipped("os.kill not available.")
2015
if os.name != "posix":
2016
raise TestSkipped("Sending signals not supported")
1958
2018
if env_changes is None:
1959
2019
env_changes = {}
2036
2098
if retcode is not None and retcode != process.returncode:
2037
2099
if process_args is None:
2038
2100
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)
2101
trace.mutter('Output of bzr %s:\n%s', process_args, out)
2102
trace.mutter('Error for bzr %s:\n%s', process_args, err)
2041
2103
self.fail('Command bzr %s failed with retcode %s != %s'
2042
2104
% (process_args, retcode, process.returncode))
2043
2105
return [out, err]
2408
2470
made_control = self.make_bzrdir(relpath, format=format)
2409
2471
return made_control.create_repository(shared=shared)
2411
def make_smart_server(self, path):
2473
def make_smart_server(self, path, backing_server=None):
2474
if backing_server is None:
2475
backing_server = self.get_server()
2412
2476
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)
2477
self.start_server(smart_server, backing_server)
2478
remote_transport = _mod_transport.get_transport(smart_server.get_url()
2415
2480
return remote_transport
2417
2482
def make_branch_and_memory_tree(self, relpath, format=None):
2427
2492
test_home_dir = self.test_home_dir
2428
2493
if isinstance(test_home_dir, unicode):
2429
2494
test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
2430
os.environ['HOME'] = test_home_dir
2431
os.environ['BZR_HOME'] = test_home_dir
2495
self.overrideEnv('HOME', test_home_dir)
2496
self.overrideEnv('BZR_HOME', test_home_dir)
2433
2498
def setUp(self):
2434
2499
super(TestCaseWithMemoryTransport, self).setUp()
2500
# Ensure that ConnectedTransport doesn't leak sockets
2501
def get_transport_with_cleanup(*args, **kwargs):
2502
t = orig_get_transport(*args, **kwargs)
2503
if isinstance(t, _mod_transport.ConnectedTransport):
2504
self.addCleanup(t.disconnect)
2507
orig_get_transport = self.overrideAttr(_mod_transport, '_get_transport',
2508
get_transport_with_cleanup)
2435
2509
self._make_test_root()
2436
2510
self.addCleanup(os.chdir, os.getcwdu())
2437
2511
self.makeAndChdirToTestDir()
3191
3271
def partition_tests(suite, count):
3192
3272
"""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)
3273
# This just assigns tests in a round-robin fashion. On one hand this
3274
# splits up blocks of related tests that might run faster if they shared
3275
# resources, but on the other it avoids assigning blocks of slow tests to
3276
# just one partition. So the slowest partition shouldn't be much slower
3278
partitions = [list() for i in range(count)]
3279
tests = iter_suite_tests(suite)
3280
for partition, test in itertools.izip(itertools.cycle(partitions), tests):
3281
partition.append(test)
3204
3285
def workaround_zealous_crypto_random():
3311
3392
if '--no-plugins' in sys.argv:
3312
3393
argv.append('--no-plugins')
3313
# stderr=STDOUT would be ideal, but until we prevent noise on
3314
# stderr it can interrupt the subunit protocol.
3315
process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
3394
# stderr=subprocess.STDOUT would be ideal, but until we prevent
3395
# noise on stderr it can interrupt the subunit protocol.
3396
process = subprocess.Popen(argv, stdin=subprocess.PIPE,
3397
stdout=subprocess.PIPE,
3398
stderr=subprocess.PIPE,
3317
3400
test = TestInSubprocess(process, test_list_file_name)
3318
3401
result.append(test)
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):
3408
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3358
3409
"""Generate profiling data for all activity between start and success.
3360
3411
The profile data is appended to the test's _benchcalls attribute and can
3633
3690
'bzrlib.tests.blackbox',
3634
3691
'bzrlib.tests.commands',
3692
'bzrlib.tests.doc_generate',
3635
3693
'bzrlib.tests.per_branch',
3636
3694
'bzrlib.tests.per_bzrdir',
3637
'bzrlib.tests.per_bzrdir_colo',
3695
'bzrlib.tests.per_controldir',
3696
'bzrlib.tests.per_controldir_colo',
3638
3697
'bzrlib.tests.per_foreign_vcs',
3639
3698
'bzrlib.tests.per_interrepository',
3640
3699
'bzrlib.tests.per_intertree',
3938
4008
# Some tests mentioned in the list are not in the test suite. The
3939
4009
# list may be out of date, report to the tester.
3940
4010
for id in not_found:
3941
bzrlib.trace.warning('"%s" not found in the test suite', id)
4011
trace.warning('"%s" not found in the test suite', id)
3942
4012
for id in duplicates:
3943
bzrlib.trace.warning('"%s" is used as an id by several tests', id)
4013
trace.warning('"%s" is used as an id by several tests', id)
3948
def multiply_scenarios(scenarios_left, scenarios_right):
4018
def multiply_scenarios(*scenarios):
4019
"""Multiply two or more iterables of scenarios.
4021
It is safe to pass scenario generators or iterators.
4023
:returns: A list of compound scenarios: the cross-product of all
4024
scenarios, with the names concatenated and the parameters
4027
return reduce(_multiply_two_scenarios, map(list, scenarios))
4030
def _multiply_two_scenarios(scenarios_left, scenarios_right):
3949
4031
"""Multiply two sets of scenarios.
3951
4033
:returns: the cartesian product of the two sets of scenarios, that is
4035
4117
:param new_id: The id to assign to it.
4036
4118
:return: The new test.
4038
new_test = copy(test)
4120
new_test = copy.copy(test)
4039
4121
new_test.id = lambda: new_id
4122
# XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
4123
# causes cloned tests to share the 'details' dict. This makes it hard to
4124
# read the test output for parameterized tests, because tracebacks will be
4125
# associated with irrelevant tests.
4127
details = new_test._TestCase__details
4128
except AttributeError:
4129
# must be a different version of testtools than expected. Do nothing.
4132
# Reset the '__details' dict.
4133
new_test._TestCase__details = {}
4040
4134
return new_test
4102
4196
if test_id != None:
4103
4197
ui.ui_factory.clear_term()
4104
4198
sys.stderr.write('\nWhile running: %s\n' % (test_id,))
4199
# Ugly, but the last thing we want here is fail, so bear with it.
4200
printable_e = str(e).decode(osutils.get_user_encoding(), 'replace'
4201
).encode('ascii', 'replace')
4105
4202
sys.stderr.write('Unable to remove testing dir %s\n%s'
4106
% (os.path.basename(dirname), e))
4203
% (os.path.basename(dirname), printable_e))
4109
4206
class Feature(object):
4446
4546
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
4549
# Only define SubUnitBzrRunner if subunit is available.
4455
4551
from subunit import TestProtocolClient
4456
4552
from subunit.test_results import AutoTimingTestResultDecorator
4553
class SubUnitBzrProtocolClient(TestProtocolClient):
4555
def addSuccess(self, test, details=None):
4556
# The subunit client always includes the details in the subunit
4557
# stream, but we don't want to include it in ours.
4558
if details is not None and 'log' in details:
4560
return super(SubUnitBzrProtocolClient, self).addSuccess(
4457
4563
class SubUnitBzrRunner(TextTestRunner):
4458
4564
def run(self, test):
4459
4565
result = AutoTimingTestResultDecorator(
4460
TestProtocolClient(self.stream))
4566
SubUnitBzrProtocolClient(self.stream))
4461
4567
test.run(result)
4463
4569
except ImportError: