54
56
# nb: check this before importing anything else from within it
55
57
_testtools_version = getattr(testtools, '__version__', ())
56
if _testtools_version < (0, 9, 2):
57
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"
58
60
% (testtools.__file__, _testtools_version))
59
61
from testtools import content
101
103
deprecated_passed,
103
105
import bzrlib.trace
104
from bzrlib.transport import get_transport, pathfilter
105
import bzrlib.transport
106
from bzrlib.transport.local import LocalURLServer
107
from bzrlib.transport.memory import MemoryServer
108
from bzrlib.transport.readonly import ReadonlyServer
106
from bzrlib.transport import (
109
110
from bzrlib.trace import mutter, note
110
from bzrlib.tests import TestUtil
111
from bzrlib.tests.http_server import HttpServer
112
from bzrlib.tests.TestUtil import (
116
from bzrlib.tests.treeshape import build_tree_contents
111
from bzrlib.tests import (
117
116
from bzrlib.ui import NullProgressView
118
117
from bzrlib.ui.text import TextUIFactory
119
118
import bzrlib.version_info_formats.format_custom
120
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
122
120
# Mark this python module as being part of the implementation
123
121
# of unittest: this gives us better tracebacks where the last
124
122
# shown frame is the test code, not our assertXYZ.
127
default_transport = LocalURLServer
125
default_transport = test_server.LocalURLServer
130
128
_unitialized_attr = object()
191
193
self._overall_start_time = time.time()
192
194
self._strict = strict
195
self._first_thread_leaker_id = None
196
self._tests_leaking_threads_count = 0
197
self._traceback_from_test = None
194
199
def stopTestRun(self):
195
200
run = self.testsRun
196
201
actionTaken = "Ran"
197
202
stopTime = time.time()
198
203
timeTaken = stopTime - self.startTime
200
self.stream.writeln(self.separator2)
201
self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
204
# GZ 2010-07-19: Seems testtools has no printErrors method, and though
205
# the parent class method is similar have to duplicate
206
self._show_list('ERROR', self.errors)
207
self._show_list('FAIL', self.failures)
208
self.stream.write(self.sep2)
209
self.stream.write("%s %d test%s in %.3fs\n\n" % (actionTaken,
202
210
run, run != 1 and "s" or "", timeTaken))
203
self.stream.writeln()
204
211
if not self.wasSuccessful():
205
212
self.stream.write("FAILED (")
206
213
failed, errored = map(len, (self.failures, self.errors))
213
220
if failed or errored: self.stream.write(", ")
214
221
self.stream.write("known_failure_count=%d" %
215
222
self.known_failure_count)
216
self.stream.writeln(")")
223
self.stream.write(")\n")
218
225
if self.known_failure_count:
219
self.stream.writeln("OK (known_failures=%d)" %
226
self.stream.write("OK (known_failures=%d)\n" %
220
227
self.known_failure_count)
222
self.stream.writeln("OK")
229
self.stream.write("OK\n")
223
230
if self.skip_count > 0:
224
231
skipped = self.skip_count
225
self.stream.writeln('%d test%s skipped' %
232
self.stream.write('%d test%s skipped\n' %
226
233
(skipped, skipped != 1 and "s" or ""))
227
234
if self.unsupported:
228
235
for feature, count in sorted(self.unsupported.items()):
229
self.stream.writeln("Missing feature '%s' skipped %d tests." %
236
self.stream.write("Missing feature '%s' skipped %d tests.\n" %
230
237
(feature, count))
232
239
ok = self.wasStrictlySuccessful()
234
241
ok = self.wasSuccessful()
235
if TestCase._first_thread_leaker_id:
242
if self._first_thread_leaker_id:
236
243
self.stream.write(
237
244
'%s is leaking threads among %d leaking tests.\n' % (
238
TestCase._first_thread_leaker_id,
239
TestCase._leaking_threads_tests))
245
self._first_thread_leaker_id,
246
self._tests_leaking_threads_count))
240
247
# We don't report the main thread as an active one.
241
248
self.stream.write(
242
249
'%d non-main threads were left active in the end.\n'
243
% (TestCase._active_threads - 1))
250
% (len(self._active_threads) - 1))
245
252
def getDescription(self, test):
271
279
def _shortened_test_description(self, test):
273
what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
281
what = re.sub(r'^bzrlib\.tests\.', '', what)
284
# GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
285
# multiple times in a row, because the handler is added for
286
# each test but the container list is shared between cases.
287
# See lp:498869 lp:625574 and lp:637725 for background.
288
def _record_traceback_from_test(self, exc_info):
289
"""Store the traceback from passed exc_info tuple till"""
290
self._traceback_from_test = exc_info[2]
276
292
def startTest(self, test):
277
unittest.TestResult.startTest(self, test)
293
super(ExtendedTestResult, self).startTest(test)
278
294
if self.count == 0:
279
295
self.startTests()
280
297
self.report_test_start(test)
281
298
test.number = self.count
282
299
self._recordTestStartTime()
300
# Make testtools cases give us the real traceback on failure
301
addOnException = getattr(test, "addOnException", None)
302
if addOnException is not None:
303
addOnException(self._record_traceback_from_test)
304
# Only check for thread leaks if the test case supports cleanups
305
addCleanup = getattr(test, "addCleanup", None)
306
if addCleanup is not None:
307
addCleanup(self._check_leaked_threads, test)
284
309
def startTests(self):
286
if getattr(sys, 'frozen', None) is None:
287
bzr_path = osutils.realpath(sys.argv[0])
289
bzr_path = sys.executable
291
'bzr selftest: %s\n' % (bzr_path,))
294
bzrlib.__path__[0],))
296
' bzr-%s python-%s %s\n' % (
297
bzrlib.version_string,
298
bzrlib._format_version_tuple(sys.version_info),
299
platform.platform(aliased=1),
301
self.stream.write('\n')
310
self.report_tests_starting()
311
self._active_threads = threading.enumerate()
313
def stopTest(self, test):
314
self._traceback_from_test = None
316
def _check_leaked_threads(self, test):
317
"""See if any threads have leaked since last call
319
A sample of live threads is stored in the _active_threads attribute,
320
when this method runs it compares the current live threads and any not
321
in the previous sample are treated as having leaked.
323
now_active_threads = set(threading.enumerate())
324
threads_leaked = now_active_threads.difference(self._active_threads)
326
self._report_thread_leak(test, threads_leaked, now_active_threads)
327
self._tests_leaking_threads_count += 1
328
if self._first_thread_leaker_id is None:
329
self._first_thread_leaker_id = test.id()
330
self._active_threads = now_active_threads
303
332
def _recordTestStartTime(self):
304
333
"""Record that a test has started."""
305
self._start_time = time.time()
307
def _cleanupLogFile(self, test):
308
# We can only do this if we have one of our TestCases, not if
310
setKeepLogfile = getattr(test, 'setKeepLogfile', None)
311
if setKeepLogfile is not None:
334
self._start_datetime = self._now()
314
336
def addError(self, test, err):
315
337
"""Tell result that test finished with an error.
317
339
Called from the TestCase run() method when the test
318
340
fails with an unexpected error.
321
unittest.TestResult.addError(self, test, err)
342
self._post_mortem(self._traceback_from_test)
343
super(ExtendedTestResult, self).addError(test, err)
322
344
self.error_count += 1
323
345
self.report_error(test, err)
324
346
if self.stop_early:
326
self._cleanupLogFile(test)
328
349
def addFailure(self, test, err):
329
350
"""Tell result that test failed.
331
352
Called from the TestCase run() method when the test
332
353
fails because e.g. an assert() method failed.
335
unittest.TestResult.addFailure(self, test, err)
355
self._post_mortem(self._traceback_from_test)
356
super(ExtendedTestResult, self).addFailure(test, err)
336
357
self.failure_count += 1
337
358
self.report_failure(test, err)
338
359
if self.stop_early:
340
self._cleanupLogFile(test)
342
362
def addSuccess(self, test, details=None):
343
363
"""Tell result that test completed successfully.
396
416
raise errors.BzrError("Unknown whence %r" % whence)
398
def report_cleaning_up(self):
418
def report_tests_starting(self):
419
"""Display information before the test run begins"""
420
if getattr(sys, 'frozen', None) is None:
421
bzr_path = osutils.realpath(sys.argv[0])
423
bzr_path = sys.executable
425
'bzr selftest: %s\n' % (bzr_path,))
428
bzrlib.__path__[0],))
430
' bzr-%s python-%s %s\n' % (
431
bzrlib.version_string,
432
bzrlib._format_version_tuple(sys.version_info),
433
platform.platform(aliased=1),
435
self.stream.write('\n')
437
def report_test_start(self, test):
438
"""Display information on the test just about to be run"""
440
def _report_thread_leak(self, test, leaked_threads, active_threads):
441
"""Display information on a test that leaked one or more threads"""
442
# GZ 2010-09-09: A leak summary reported separately from the general
443
# thread debugging would be nice. Tests under subunit
444
# need something not using stream, perhaps adding a
445
# testtools details object would be fitting.
446
if 'threads' in selftest_debug_flags:
447
self.stream.write('%s is leaking, active is now %d\n' %
448
(test.id(), len(active_threads)))
401
450
def startTestRun(self):
402
451
self.startTime = time.time()
439
488
self.pb.finished()
440
489
super(TextTestResult, self).stopTestRun()
442
def startTestRun(self):
443
super(TextTestResult, self).startTestRun()
491
def report_tests_starting(self):
492
super(TextTestResult, self).report_tests_starting()
444
493
self.pb.update('[test 0/%d] Starting' % (self.num_tests))
446
def printErrors(self):
447
# clear the pb to make room for the error listing
449
super(TextTestResult, self).printErrors()
451
495
def _progress_prefix_text(self):
452
496
# the longer this text, the less space we have to show the test
485
528
return self._shortened_test_description(test)
487
530
def report_error(self, test, err):
488
ui.ui_factory.note('ERROR: %s\n %s\n' % (
531
self.stream.write('ERROR: %s\n %s\n' % (
489
532
self._test_description(test),
493
536
def report_failure(self, test, err):
494
ui.ui_factory.note('FAIL: %s\n %s\n' % (
537
self.stream.write('FAIL: %s\n %s\n' % (
495
538
self._test_description(test),
546
585
return '%s%s' % (indent, err[1])
548
587
def report_error(self, test, err):
549
self.stream.writeln('ERROR %s\n%s'
588
self.stream.write('ERROR %s\n%s\n'
550
589
% (self._testTimeString(test),
551
590
self._error_summary(err)))
553
592
def report_failure(self, test, err):
554
self.stream.writeln(' FAIL %s\n%s'
593
self.stream.write(' FAIL %s\n%s\n'
555
594
% (self._testTimeString(test),
556
595
self._error_summary(err)))
558
597
def report_known_failure(self, test, err):
559
self.stream.writeln('XFAIL %s\n%s'
598
self.stream.write('XFAIL %s\n%s\n'
560
599
% (self._testTimeString(test),
561
600
self._error_summary(err)))
563
602
def report_success(self, test):
564
self.stream.writeln(' OK %s' % self._testTimeString(test))
603
self.stream.write(' OK %s\n' % self._testTimeString(test))
565
604
for bench_called, stats in getattr(test, '_benchcalls', []):
566
self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
605
self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
567
606
stats.pprint(file=self.stream)
568
607
# flush the stream so that we get smooth output. This verbose mode is
569
608
# used to show the output in PQM.
570
609
self.stream.flush()
572
611
def report_skip(self, test, reason):
573
self.stream.writeln(' SKIP %s\n%s'
612
self.stream.write(' SKIP %s\n%s\n'
574
613
% (self._testTimeString(test), reason))
576
615
def report_not_applicable(self, test, reason):
577
self.stream.writeln(' N/A %s\n %s'
616
self.stream.write(' N/A %s\n %s\n'
578
617
% (self._testTimeString(test), reason))
580
619
def report_unsupported(self, test, feature):
581
620
"""test cannot be run because feature is missing."""
582
self.stream.writeln("NODEP %s\n The feature '%s' is not available."
621
self.stream.write("NODEP %s\n The feature '%s' is not available.\n"
583
622
%(self._testTimeString(test), feature))
612
651
encode = codec[0]
614
653
encode = codec.encode
615
stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
654
# GZ 2010-09-08: Really we don't want to be writing arbitrary bytes,
655
# so should swap to the plain codecs.StreamWriter
656
stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream,
616
658
stream.encoding = new_encoding
617
self.stream = unittest._WritelnDecorator(stream)
618
660
self.descriptions = descriptions
619
661
self.verbosity = verbosity
620
662
self._bench_history = bench_history
788
826
routine, and to build and check bzr trees.
790
828
In addition to the usual method of overriding tearDown(), this class also
791
allows subclasses to register functions into the _cleanups list, which is
829
allows subclasses to register cleanup functions via addCleanup, which are
792
830
run in order as the object is torn down. It's less likely this will be
793
831
accidentally overlooked.
796
_active_threads = None
797
_leaking_threads_tests = 0
798
_first_thread_leaker_id = None
799
_log_file_name = None
800
835
# record lsprof data when performing benchmark calls.
801
836
_gather_lsprof_in_benchmarks = False
803
838
def __init__(self, methodName='testMethod'):
804
839
super(TestCase, self).__init__(methodName)
806
840
self._directory_isolation = True
807
841
self.exception_handlers.insert(0,
808
842
(UnavailableFeature, self._do_unsupported_or_skip))
826
860
self._track_transports()
827
861
self._track_locks()
828
862
self._clear_debug_flags()
829
TestCase._active_threads = threading.activeCount()
830
self.addCleanup(self._check_leaked_threads)
863
# Isolate global verbosity level, to make sure it's reproducible
864
# between tests. We should get rid of this altogether: bug 656694. --
866
self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
833
869
# debug a frame up.
835
871
pdb.Pdb().set_trace(sys._getframe().f_back)
837
def _check_leaked_threads(self):
838
active = threading.activeCount()
839
leaked_threads = active - TestCase._active_threads
840
TestCase._active_threads = active
841
# If some tests make the number of threads *decrease*, we'll consider
842
# that they are just observing old threads dieing, not agressively kill
843
# random threads. So we don't report these tests as leaking. The risk
844
# is that we have false positives that way (the test see 2 threads
845
# going away but leak one) but it seems less likely than the actual
846
# false positives (the test see threads going away and does not leak).
847
if leaked_threads > 0:
848
TestCase._leaking_threads_tests += 1
849
if TestCase._first_thread_leaker_id is None:
850
TestCase._first_thread_leaker_id = self.id()
873
def discardDetail(self, name):
874
"""Extend the addDetail, getDetails api so we can remove a detail.
876
eg. bzr always adds the 'log' detail at startup, but we don't want to
877
include it for skipped, xfail, etc tests.
879
It is safe to call this for a detail that doesn't exist, in case this
880
gets called multiple times.
882
# We cheat. details is stored in __details which means we shouldn't
883
# touch it. but getDetails() returns the dict directly, so we can
885
details = self.getDetails()
852
889
def _clear_debug_flags(self):
853
890
"""Prevent externally set debug flags affecting tests.
865
902
def _clear_hooks(self):
866
903
# prevent hooks affecting tests
904
known_hooks = hooks.known_hooks
867
905
self._preserved_hooks = {}
868
for key, factory in hooks.known_hooks.items():
869
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
870
current_hooks = hooks.known_hooks_key_to_object(key)
906
for key, (parent, name) in known_hooks.iter_parent_objects():
907
current_hooks = getattr(parent, name)
871
908
self._preserved_hooks[parent] = (name, current_hooks)
872
909
self.addCleanup(self._restoreHooks)
873
for key, factory in hooks.known_hooks.items():
874
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
910
for key, (parent, name) in known_hooks.iter_parent_objects():
911
factory = known_hooks.get(key)
875
912
setattr(parent, name, factory())
876
913
# this hook should always be installed
877
914
request._install_hook()
1308
1350
self.assertEqualDiff(content, s)
1352
def assertDocstring(self, expected_docstring, obj):
1353
"""Fail if obj does not have expected_docstring"""
1355
# With -OO the docstring should be None instead
1356
self.assertIs(obj.__doc__, None)
1358
self.assertEqual(expected_docstring, obj.__doc__)
1310
1360
def failUnlessExists(self, path):
1311
1361
"""Fail unless path or paths, which may be abs or relative, exist."""
1312
1362
if not isinstance(path, basestring):
1473
1521
debug.debug_flags.discard('strict_locks')
1475
def addCleanup(self, callable, *args, **kwargs):
1476
"""Arrange to run a callable when this case is torn down.
1478
Callables are run in the reverse of the order they are registered,
1479
ie last-in first-out.
1481
self._cleanups.append((callable, args, kwargs))
1483
1523
def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1484
1524
"""Overrides an object attribute restoring it after the test.
1540
1582
'ftp_proxy': None,
1541
1583
'FTP_PROXY': None,
1542
1584
'BZR_REMOTE_PATH': None,
1585
# Generally speaking, we don't want apport reporting on crashes in
1586
# the test envirnoment unless we're specifically testing apport,
1587
# so that it doesn't leak into the real system environment. We
1588
# use an env var so it propagates to subprocesses.
1589
'APPORT_DISABLE': '1',
1545
1592
self.addCleanup(self._restoreEnvironment)
1546
1593
for name, value in new_env.iteritems():
1547
1594
self._captureVar(name, value)
1549
1596
def _captureVar(self, name, newvalue):
1550
1597
"""Set an environment variable, and reset it when finished."""
1551
self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
1598
self._old_env[name] = osutils.set_or_unset_env(name, newvalue)
1553
1600
def _restoreEnvironment(self):
1554
for name, value in self.__old_env.iteritems():
1601
for name, value in self._old_env.iteritems():
1555
1602
osutils.set_or_unset_env(name, value)
1557
1604
def _restoreHooks(self):
1591
1645
self._do_skip(result, reason)
1648
def _report_skip(self, result, err):
1649
"""Override the default _report_skip.
1651
We want to strip the 'log' detail. If we waint until _do_skip, it has
1652
already been formatted into the 'reason' string, and we can't pull it
1655
self._suppress_log()
1656
super(TestCase, self)._report_skip(self, result, err)
1659
def _report_expected_failure(self, result, err):
1662
See _report_skip for motivation.
1664
self._suppress_log()
1665
super(TestCase, self)._report_expected_failure(self, result, err)
1594
1668
def _do_unsupported_or_skip(self, result, e):
1595
1669
reason = e.args[0]
1670
self._suppress_log()
1596
1671
addNotSupported = getattr(result, 'addNotSupported', None)
1597
1672
if addNotSupported is not None:
1598
1673
result.addNotSupported(self, reason)
1645
1720
unicodestr = self._log_contents.decode('utf8', 'replace')
1646
1721
self._log_contents = unicodestr.encode('utf8')
1647
1722
return self._log_contents
1649
if bzrlib.trace._trace_file:
1650
# flush the log file, to get all content
1651
bzrlib.trace._trace_file.flush()
1652
if self._log_file_name is not None:
1653
logfile = open(self._log_file_name)
1655
log_contents = logfile.read()
1723
if self._log_file is not None:
1724
log_contents = self._log_file.getvalue()
1659
1726
log_contents.decode('utf8')
1660
1727
except UnicodeDecodeError:
1661
1728
unicodestr = log_contents.decode('utf8', 'replace')
1662
1729
log_contents = unicodestr.encode('utf8')
1663
1730
if not keep_log_file:
1664
self._log_file.close()
1665
1731
self._log_file = None
1666
1732
# Permit multiple calls to get_log until we clean it up in
1667
1733
# finishLogFile
1668
1734
self._log_contents = log_contents
1670
os.remove(self._log_file_name)
1672
if sys.platform == 'win32' and e.errno == errno.EACCES:
1673
sys.stderr.write(('Unable to delete log file '
1674
' %r\n' % self._log_file_name))
1677
self._log_file_name = None
1678
1735
return log_contents
1680
return "No log file content and no log file name."
1737
return "No log file content."
1682
1739
def get_log(self):
1683
1740
"""Get a unicode string containing the log from bzrlib.trace.
1898
1955
variables. A value of None will unset the env variable.
1899
1956
The values must be strings. The change will only occur in the
1900
1957
child, so you don't need to fix the environment after running.
1901
:param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
1958
:param skip_if_plan_to_signal: raise TestSkipped when true and system
1959
doesn't support signalling subprocesses.
1903
1960
:param allow_plugins: If False (default) pass --no-plugins to bzr.
1905
1962
:returns: Popen object for the started process.
1907
1964
if skip_if_plan_to_signal:
1908
if not getattr(os, 'kill', None):
1909
raise TestSkipped("os.kill not available.")
1965
if os.name != "posix":
1966
raise TestSkipped("Sending signals not supported")
1911
1968
if env_changes is None:
1912
1969
env_changes = {}
2361
2420
made_control = self.make_bzrdir(relpath, format=format)
2362
2421
return made_control.create_repository(shared=shared)
2364
def make_smart_server(self, path):
2365
smart_server = server.SmartTCPServer_for_testing()
2366
self.start_server(smart_server, self.get_server())
2367
remote_transport = get_transport(smart_server.get_url()).clone(path)
2423
def make_smart_server(self, path, backing_server=None):
2424
if backing_server is None:
2425
backing_server = self.get_server()
2426
smart_server = test_server.SmartTCPServer_for_testing()
2427
self.start_server(smart_server, backing_server)
2428
remote_transport = _mod_transport.get_transport(smart_server.get_url()
2368
2430
return remote_transport
2370
2432
def make_branch_and_memory_tree(self, relpath, format=None):
2386
2448
def setUp(self):
2387
2449
super(TestCaseWithMemoryTransport, self).setUp()
2450
# Ensure that ConnectedTransport doesn't leak sockets
2451
def get_transport_with_cleanup(*args, **kwargs):
2452
t = orig_get_transport(*args, **kwargs)
2453
if isinstance(t, _mod_transport.ConnectedTransport):
2454
self.addCleanup(t.disconnect)
2457
orig_get_transport = self.overrideAttr(_mod_transport, '_get_transport',
2458
get_transport_with_cleanup)
2388
2459
self._make_test_root()
2389
2460
self.addCleanup(os.chdir, os.getcwdu())
2390
2461
self.makeAndChdirToTestDir()
3144
3221
def partition_tests(suite, count):
3145
3222
"""Partition suite into count lists of tests."""
3147
tests = list(iter_suite_tests(suite))
3148
tests_per_process = int(math.ceil(float(len(tests)) / count))
3149
for block in range(count):
3150
low_test = block * tests_per_process
3151
high_test = low_test + tests_per_process
3152
process_tests = tests[low_test:high_test]
3153
result.append(process_tests)
3223
# This just assigns tests in a round-robin fashion. On one hand this
3224
# splits up blocks of related tests that might run faster if they shared
3225
# resources, but on the other it avoids assigning blocks of slow tests to
3226
# just one partition. So the slowest partition shouldn't be much slower
3228
partitions = [list() for i in range(count)]
3229
tests = iter_suite_tests(suite)
3230
for partition, test in itertools.izip(itertools.cycle(partitions), tests):
3231
partition.append(test)
3235
def workaround_zealous_crypto_random():
3236
"""Crypto.Random want to help us being secure, but we don't care here.
3238
This workaround some test failure related to the sftp server. Once paramiko
3239
stop using the controversial API in Crypto.Random, we may get rid of it.
3242
from Crypto.Random import atfork
3157
3248
def fork_for_tests(suite):
3175
3266
ProtocolTestCase.run(self, result)
3177
os.waitpid(self.pid, os.WNOHANG)
3268
os.waitpid(self.pid, 0)
3179
3270
test_blocks = partition_tests(suite, concurrency)
3180
3271
for process_tests in test_blocks:
3181
process_suite = TestSuite()
3272
process_suite = TestUtil.TestSuite()
3182
3273
process_suite.addTests(process_tests)
3183
3274
c2pread, c2pwrite = os.pipe()
3184
3275
pid = os.fork()
3277
workaround_zealous_crypto_random()
3187
3279
os.close(c2pread)
3188
3280
# Leave stderr and stdout open so we can see test noise
3250
3342
if '--no-plugins' in sys.argv:
3251
3343
argv.append('--no-plugins')
3252
# stderr=STDOUT would be ideal, but until we prevent noise on
3253
# stderr it can interrupt the subunit protocol.
3254
process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
3344
# stderr=subprocess.STDOUT would be ideal, but until we prevent
3345
# noise on stderr it can interrupt the subunit protocol.
3346
process = subprocess.Popen(argv, stdin=subprocess.PIPE,
3347
stdout=subprocess.PIPE,
3348
stderr=subprocess.PIPE,
3256
3350
test = TestInSubprocess(process, test_list_file_name)
3257
3351
result.append(test)
3264
class ForwardingResult(unittest.TestResult):
3266
def __init__(self, target):
3267
unittest.TestResult.__init__(self)
3268
self.result = target
3270
def startTest(self, test):
3271
self.result.startTest(test)
3273
def stopTest(self, test):
3274
self.result.stopTest(test)
3276
def startTestRun(self):
3277
self.result.startTestRun()
3279
def stopTestRun(self):
3280
self.result.stopTestRun()
3282
def addSkip(self, test, reason):
3283
self.result.addSkip(test, reason)
3285
def addSuccess(self, test):
3286
self.result.addSuccess(test)
3288
def addError(self, test, err):
3289
self.result.addError(test, err)
3291
def addFailure(self, test, err):
3292
self.result.addFailure(test, err)
3293
ForwardingResult = testtools.ExtendedToOriginalDecorator
3296
class ProfileResult(ForwardingResult):
3358
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3297
3359
"""Generate profiling data for all activity between start and success.
3299
3361
The profile data is appended to the test's _benchcalls attribute and can
3572
3639
'bzrlib.tests.blackbox',
3573
3640
'bzrlib.tests.commands',
3641
'bzrlib.tests.doc_generate',
3574
3642
'bzrlib.tests.per_branch',
3575
3643
'bzrlib.tests.per_bzrdir',
3644
'bzrlib.tests.per_controldir',
3645
'bzrlib.tests.per_controldir_colo',
3576
3646
'bzrlib.tests.per_foreign_vcs',
3577
3647
'bzrlib.tests.per_interrepository',
3578
3648
'bzrlib.tests.per_intertree',
3657
3730
'bzrlib.tests.test_identitymap',
3658
3731
'bzrlib.tests.test_ignores',
3659
3732
'bzrlib.tests.test_index',
3733
'bzrlib.tests.test_import_tariff',
3660
3734
'bzrlib.tests.test_info',
3661
3735
'bzrlib.tests.test_inv',
3662
3736
'bzrlib.tests.test_inventory_delta',
3663
3737
'bzrlib.tests.test_knit',
3664
3738
'bzrlib.tests.test_lazy_import',
3665
3739
'bzrlib.tests.test_lazy_regex',
3740
'bzrlib.tests.test_library_state',
3666
3741
'bzrlib.tests.test_lock',
3667
3742
'bzrlib.tests.test_lockable_files',
3668
3743
'bzrlib.tests.test_lockdir',
3880
def multiply_scenarios(scenarios_left, scenarios_right):
3967
def multiply_scenarios(*scenarios):
3968
"""Multiply two or more iterables of scenarios.
3970
It is safe to pass scenario generators or iterators.
3972
:returns: A list of compound scenarios: the cross-product of all
3973
scenarios, with the names concatenated and the parameters
3976
return reduce(_multiply_two_scenarios, map(list, scenarios))
3979
def _multiply_two_scenarios(scenarios_left, scenarios_right):
3881
3980
"""Multiply two sets of scenarios.
3883
3982
:returns: the cartesian product of the two sets of scenarios, that is
3967
4066
:param new_id: The id to assign to it.
3968
4067
:return: The new test.
3970
new_test = copy(test)
4069
new_test = copy.copy(test)
3971
4070
new_test.id = lambda: new_id
4071
# XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
4072
# causes cloned tests to share the 'details' dict. This makes it hard to
4073
# read the test output for parameterized tests, because tracebacks will be
4074
# associated with irrelevant tests.
4076
details = new_test._TestCase__details
4077
except AttributeError:
4078
# must be a different version of testtools than expected. Do nothing.
4081
# Reset the '__details' dict.
4082
new_test._TestCase__details = {}
3972
4083
return new_test
4034
4145
if test_id != None:
4035
4146
ui.ui_factory.clear_term()
4036
4147
sys.stderr.write('\nWhile running: %s\n' % (test_id,))
4148
# Ugly, but the last thing we want here is fail, so bear with it.
4149
printable_e = str(e).decode(osutils.get_user_encoding(), 'replace'
4150
).encode('ascii', 'replace')
4037
4151
sys.stderr.write('Unable to remove testing dir %s\n%s'
4038
% (os.path.basename(dirname), e))
4152
% (os.path.basename(dirname), printable_e))
4041
4155
class Feature(object):
4130
4244
should really use a different feature.
4133
def __init__(self, module, name, this_name, dep_version):
4247
def __init__(self, dep_version, module, name,
4248
replacement_name, replacement_module=None):
4134
4249
super(_CompatabilityThunkFeature, self).__init__()
4135
4250
self._module = module
4251
if replacement_module is None:
4252
replacement_module = module
4253
self._replacement_module = replacement_module
4136
4254
self._name = name
4137
self._this_name = this_name
4255
self._replacement_name = replacement_name
4138
4256
self._dep_version = dep_version
4139
4257
self._feature = None
4141
4259
def _ensure(self):
4142
4260
if self._feature is None:
4143
msg = (self._dep_version % self._this_name) + (
4144
' Use %s.%s instead.' % (self._module, self._name))
4145
symbol_versioning.warn(msg, DeprecationWarning)
4146
mod = __import__(self._module, {}, {}, [self._name])
4147
self._feature = getattr(mod, self._name)
4261
depr_msg = self._dep_version % ('%s.%s'
4262
% (self._module, self._name))
4263
use_msg = ' Use %s.%s instead.' % (self._replacement_module,
4264
self._replacement_name)
4265
symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4266
# Import the new feature and use it as a replacement for the
4268
self._feature = pyutils.get_named_object(
4269
self._replacement_module, self._replacement_name)
4149
4271
def _probe(self):
4176
4298
if self.available(): # Make sure the probe has been done
4177
4299
return self._module
4180
4302
def feature_name(self):
4181
4303
return self.module_name
4184
4306
# This is kept here for compatibility, it is recommended to use
4185
4307
# 'bzrlib.tests.feature.paramiko' instead
4186
ParamikoFeature = _CompatabilityThunkFeature('bzrlib.tests.features',
4187
'paramiko', 'bzrlib.tests.ParamikoFeature', deprecated_in((2,1,0)))
4308
ParamikoFeature = _CompatabilityThunkFeature(
4309
deprecated_in((2,1,0)),
4310
'bzrlib.tests.features', 'ParamikoFeature', 'paramiko')
4190
4313
def probe_unicode_in_user_encoding():
4351
4485
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
4488
class _CaseSensitiveFilesystemFeature(Feature):
4491
if CaseInsCasePresFilenameFeature.available():
4493
elif CaseInsensitiveFilesystemFeature.available():
4498
def feature_name(self):
4499
return 'case-sensitive filesystem'
4501
# new coding style is for feature instances to be lowercase
4502
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
4354
4505
# Kept for compatibility, use bzrlib.tests.features.subunit instead
4355
SubUnitFeature = _CompatabilityThunkFeature('bzrlib.tests.features', 'subunit',
4356
'bzrlib.tests.SubUnitFeature', deprecated_in((2,1,0)))
4506
SubUnitFeature = _CompatabilityThunkFeature(
4507
deprecated_in((2,1,0)),
4508
'bzrlib.tests.features', 'SubUnitFeature', 'subunit')
4357
4509
# Only define SubUnitBzrRunner if subunit is available.
4359
4511
from subunit import TestProtocolClient
4360
4512
from subunit.test_results import AutoTimingTestResultDecorator
4513
class SubUnitBzrProtocolClient(TestProtocolClient):
4515
def addSuccess(self, test, details=None):
4516
# The subunit client always includes the details in the subunit
4517
# stream, but we don't want to include it in ours.
4518
if details is not None and 'log' in details:
4520
return super(SubUnitBzrProtocolClient, self).addSuccess(
4361
4523
class SubUnitBzrRunner(TextTestRunner):
4362
4524
def run(self, test):
4363
4525
result = AutoTimingTestResultDecorator(
4364
TestProtocolClient(self.stream))
4526
SubUnitBzrProtocolClient(self.stream))
4365
4527
test.run(result)
4367
4529
except ImportError:
4532
class _PosixPermissionsFeature(Feature):
4536
# create temporary file and check if specified perms are maintained.
4539
write_perms = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
4540
f = tempfile.mkstemp(prefix='bzr_perms_chk_')
4543
os.chmod(name, write_perms)
4545
read_perms = os.stat(name).st_mode & 0777
4547
return (write_perms == read_perms)
4549
return (os.name == 'posix') and has_perms()
4551
def feature_name(self):
4552
return 'POSIX permissions support'
4554
posix_permissions_feature = _PosixPermissionsFeature()