33
31
from cStringIO import StringIO
37
from pprint import pformat
42
from subprocess import Popen, PIPE
56
# nb: check this before importing anything else from within it
57
_testtools_version = getattr(testtools, '__version__', ())
58
if _testtools_version < (0, 9, 5):
59
raise ImportError("need at least testtools 0.9.5: %s is %r"
60
% (testtools.__file__, _testtools_version))
61
from testtools import content
64
51
from bzrlib import (
68
commands as _mod_commands,
77
plugin as _mod_plugin,
84
transport as _mod_transport,
66
import bzrlib.commands
67
import bzrlib.timestamp
69
import bzrlib.inventory
70
import bzrlib.iterablefile
88
73
import bzrlib.lsprof
89
74
except ImportError:
90
75
# lsprof not available
92
from bzrlib.smart import client, request
93
from bzrlib.transport import (
97
from bzrlib.tests import (
102
from bzrlib.ui import NullProgressView
103
from bzrlib.ui.text import TextUIFactory
77
from bzrlib.merge import merge_inner
80
from bzrlib.smart import client, request, server
82
from bzrlib import symbol_versioning
83
from bzrlib.symbol_versioning import (
90
from bzrlib.transport import get_transport
91
import bzrlib.transport
92
from bzrlib.transport.local import LocalURLServer
93
from bzrlib.transport.memory import MemoryServer
94
from bzrlib.transport.readonly import ReadonlyServer
95
from bzrlib.trace import mutter, note
96
from bzrlib.tests import TestUtil
97
from bzrlib.tests.http_server import HttpServer
98
from bzrlib.tests.TestUtil import (
102
from bzrlib.tests.treeshape import build_tree_contents
103
import bzrlib.version_info_formats.format_custom
104
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
105
106
# Mark this python module as being part of the implementation
106
107
# of unittest: this gives us better tracebacks where the last
107
108
# shown frame is the test code, not our assertXYZ.
110
default_transport = test_server.LocalURLServer
113
_unitialized_attr = object()
114
"""A sentinel needed to act as a default value in a method signature."""
117
# Subunit result codes, defined here to prevent a hard dependency on subunit.
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):
111
default_transport = LocalURLServer
114
class ExtendedTestResult(unittest._TextTestResult):
217
115
"""Accepts, reports and accumulates the results of running tests.
219
117
Compared to the unittest version this class adds support for
266
164
self.unsupported = {}
268
166
self._overall_start_time = time.time()
269
self._strict = strict
270
self._first_thread_leaker_id = None
271
self._tests_leaking_threads_count = 0
272
self._traceback_from_test = None
274
def stopTestRun(self):
277
stopTime = time.time()
278
timeTaken = stopTime - self.startTime
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,
285
run, run != 1 and "s" or "", timeTaken))
286
if not self.wasSuccessful():
287
self.stream.write("FAILED (")
288
failed, errored = map(len, (self.failures, self.errors))
290
self.stream.write("failures=%d" % failed)
292
if failed: self.stream.write(", ")
293
self.stream.write("errors=%d" % errored)
294
if self.known_failure_count:
295
if failed or errored: self.stream.write(", ")
296
self.stream.write("known_failure_count=%d" %
297
self.known_failure_count)
298
self.stream.write(")\n")
300
if self.known_failure_count:
301
self.stream.write("OK (known_failures=%d)\n" %
302
self.known_failure_count)
304
self.stream.write("OK\n")
305
if self.skip_count > 0:
306
skipped = self.skip_count
307
self.stream.write('%d test%s skipped\n' %
308
(skipped, skipped != 1 and "s" or ""))
310
for feature, count in sorted(self.unsupported.items()):
311
self.stream.write("Missing feature '%s' skipped %d tests.\n" %
314
ok = self.wasStrictlySuccessful()
316
ok = self.wasSuccessful()
317
if self._first_thread_leaker_id:
319
'%s is leaking threads among %d leaking tests.\n' % (
320
self._first_thread_leaker_id,
321
self._tests_leaking_threads_count))
322
# We don't report the main thread as an active one.
324
'%d non-main threads were left active in the end.\n'
325
% (len(self._active_threads) - 1))
327
def getDescription(self, test):
330
def _extractBenchmarkTime(self, testCase, details=None):
168
def _extractBenchmarkTime(self, testCase):
331
169
"""Add a benchmark time for the current test case."""
332
if details and 'benchtime' in details:
333
return float(''.join(details['benchtime'].iter_bytes()))
334
170
return getattr(testCase, "_benchtime", None)
336
172
def _elapsedTestTimeString(self):
337
173
"""Return a time string for the overall time the current test has taken."""
338
return self._formatTime(self._delta_to_float(
339
self._now() - self._start_datetime))
174
return self._formatTime(time.time() - self._start_time)
341
176
def _testTimeString(self, testCase):
342
177
benchmark_time = self._extractBenchmarkTime(testCase)
343
178
if benchmark_time is not None:
344
return self._formatTime(benchmark_time) + "*"
180
self._formatTime(benchmark_time),
181
self._elapsedTestTimeString())
346
return self._elapsedTestTimeString()
183
return " %s" % self._elapsedTestTimeString()
348
185
def _formatTime(self, seconds):
349
186
"""Format seconds as milliseconds with leading spaces."""
354
191
def _shortened_test_description(self, test):
356
what = re.sub(r'^bzrlib\.tests\.', '', what)
193
what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', 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]
367
196
def startTest(self, test):
368
super(ExtendedTestResult, self).startTest(test)
197
unittest.TestResult.startTest(self, test)
372
198
self.report_test_start(test)
373
199
test.number = self.count
374
200
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
394
def startTests(self):
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
414
202
def _recordTestStartTime(self):
415
203
"""Record that a test has started."""
416
self._start_datetime = self._now()
204
self._start_time = time.time()
206
def _cleanupLogFile(self, test):
207
# We can only do this if we have one of our TestCases, not if
209
setKeepLogfile = getattr(test, 'setKeepLogfile', None)
210
if setKeepLogfile is not None:
418
213
def addError(self, test, err):
419
214
"""Tell result that test finished with an error.
434
235
Called from the TestCase run() method when the test
435
236
fails because e.g. an assert() method failed.
437
self._post_mortem(self._traceback_from_test)
438
super(ExtendedTestResult, self).addFailure(test, err)
439
self.failure_count += 1
440
self.report_failure(test, err)
238
self._testConcluded(test)
239
if isinstance(err[1], KnownFailure):
240
return self._addKnownFailure(test, err)
242
unittest.TestResult.addFailure(self, test, err)
243
self.failure_count += 1
244
self.report_failure(test, err)
247
self._cleanupLogFile(test)
444
def addSuccess(self, test, details=None):
249
def addSuccess(self, test):
445
250
"""Tell result that test completed successfully.
447
252
Called from the TestCase run()
254
self._testConcluded(test)
449
255
if self._bench_history is not None:
450
benchmark_time = self._extractBenchmarkTime(test, details)
256
benchmark_time = self._extractBenchmarkTime(test)
451
257
if benchmark_time is not None:
452
258
self._bench_history.write("%s %s\n" % (
453
259
self._formatTime(benchmark_time),
455
261
self.report_success(test)
456
super(ExtendedTestResult, self).addSuccess(test)
262
self._cleanupLogFile(test)
263
unittest.TestResult.addSuccess(self, test)
457
264
test._log_contents = ''
459
def addExpectedFailure(self, test, err):
266
def _testConcluded(self, test):
267
"""Common code when a test has finished.
269
Called regardless of whether it succeded, failed, etc.
273
def _addKnownFailure(self, test, err):
460
274
self.known_failure_count += 1
461
275
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()))
476
277
def addNotSupported(self, test, feature):
477
278
"""The test will not be run because of a missing feature.
479
280
# this can be called in two different ways: it may be that the
480
# test started running, and then raised (through requireFeature)
281
# test started running, and then raised (through addError)
481
282
# UnavailableFeature. Alternatively this method can be called
482
# while probing for features before running the test code proper; in
483
# that case we will see startTest and stopTest, but the test will
484
# never actually run.
283
# while probing for features before running the tests; in that
284
# case we will see startTest and stopTest, but the test will never
485
286
self.unsupported.setdefault(str(feature), 0)
486
287
self.unsupported[str(feature)] += 1
487
288
self.report_unsupported(test, feature)
491
292
self.skip_count += 1
492
293
self.report_skip(test, reason)
494
def addNotApplicable(self, test, reason):
495
self.not_applicable_count += 1
496
self.report_not_applicable(test, reason)
498
def _post_mortem(self, tb=None):
499
"""Start a PDB post mortem session."""
500
if os.environ.get('BZR_TEST_PDB', None):
504
def progress(self, offset, whence):
505
"""The test is adjusting the count of tests to run."""
506
if whence == SUBUNIT_SEEK_SET:
507
self.num_tests = offset
508
elif whence == SUBUNIT_SEEK_CUR:
509
self.num_tests += offset
511
raise errors.BzrError("Unknown whence %r" % whence)
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)))
545
def startTestRun(self):
546
self.startTime = time.time()
295
def _addNotApplicable(self, test, skip_excinfo):
296
if isinstance(skip_excinfo[1], TestNotApplicable):
297
self.not_applicable_count += 1
298
self.report_not_applicable(test, skip_excinfo)
301
except KeyboardInterrupt:
304
self.addError(test, test.exc_info())
306
# seems best to treat this as success from point-of-view of unittest
307
# -- it actually does nothing so it barely matters :)
308
unittest.TestResult.addSuccess(self, test)
309
test._log_contents = ''
311
def printErrorList(self, flavour, errors):
312
for test, err in errors:
313
self.stream.writeln(self.separator1)
314
self.stream.write("%s: " % flavour)
315
self.stream.writeln(self.getDescription(test))
316
if getattr(test, '_get_log', None) is not None:
317
self.stream.write('\n')
319
('vvvv[log from %s]' % test.id()).ljust(78,'-'))
320
self.stream.write('\n')
321
self.stream.write(test._get_log())
322
self.stream.write('\n')
324
('^^^^[log from %s]' % test.id()).ljust(78,'-'))
325
self.stream.write('\n')
326
self.stream.writeln(self.separator2)
327
self.stream.writeln("%s" % err)
332
def report_cleaning_up(self):
548
335
def report_success(self, test):
687
465
return '%s%s' % (indent, err[1])
689
467
def report_error(self, test, err):
690
self.stream.write('ERROR %s\n%s\n'
468
self.stream.writeln('ERROR %s\n%s'
691
469
% (self._testTimeString(test),
692
470
self._error_summary(err)))
694
472
def report_failure(self, test, err):
695
self.stream.write(' FAIL %s\n%s\n'
473
self.stream.writeln(' FAIL %s\n%s'
696
474
% (self._testTimeString(test),
697
475
self._error_summary(err)))
699
477
def report_known_failure(self, test, err):
700
self.stream.write('XFAIL %s\n%s\n'
478
self.stream.writeln('XFAIL %s\n%s'
701
479
% (self._testTimeString(test),
702
480
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",
710
482
def report_success(self, test):
711
self.stream.write(' OK %s\n' % self._testTimeString(test))
483
self.stream.writeln(' OK %s' % self._testTimeString(test))
712
484
for bench_called, stats in getattr(test, '_benchcalls', []):
713
self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
485
self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
714
486
stats.pprint(file=self.stream)
715
487
# flush the stream so that we get smooth output. This verbose mode is
716
488
# used to show the output in PQM.
717
489
self.stream.flush()
719
491
def report_skip(self, test, reason):
720
self.stream.write(' SKIP %s\n%s\n'
492
self.stream.writeln(' SKIP %s\n%s'
721
493
% (self._testTimeString(test), reason))
723
def report_not_applicable(self, test, reason):
724
self.stream.write(' N/A %s\n %s\n'
725
% (self._testTimeString(test), reason))
495
def report_not_applicable(self, test, skip_excinfo):
496
self.stream.writeln(' N/A %s\n%s'
497
% (self._testTimeString(test),
498
self._error_summary(skip_excinfo)))
727
500
def report_unsupported(self, test, feature):
728
501
"""test cannot be run because feature is missing."""
729
self.stream.write("NODEP %s\n The feature '%s' is not available.\n"
502
self.stream.writeln("NODEP %s\n The feature '%s' is not available."
730
503
%(self._testTimeString(test), feature))
740
513
bench_history=None,
742
result_decorators=None,
744
"""Create a TextTestRunner.
746
:param result_decorators: An optional list of decorators to apply
747
to the result object being used by the runner. Decorators are
748
applied left to right - the first element in the list is the
751
# stream may know claim to know to write unicode strings, but in older
752
# pythons this goes sufficiently wrong that it is a bad idea. (
753
# specifically a built in file with encoding 'UTF-8' will still try
754
# to encode using ascii.
755
new_encoding = osutils.get_terminal_encoding()
756
codec = codecs.lookup(new_encoding)
757
if type(codec) is tuple:
761
encode = codec.encode
762
# GZ 2010-09-08: Really we don't want to be writing arbitrary bytes,
763
# so should swap to the plain codecs.StreamWriter
764
stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream,
766
stream.encoding = new_encoding
516
self.stream = unittest._WritelnDecorator(stream)
768
517
self.descriptions = descriptions
769
518
self.verbosity = verbosity
770
519
self._bench_history = bench_history
771
self._strict = strict
772
self._result_decorators = result_decorators or []
520
self.list_only = list_only
774
522
def run(self, test):
775
523
"Run the given test case or test suite."
524
startTime = time.time()
776
525
if self.verbosity == 1:
777
526
result_class = TextTestResult
778
527
elif self.verbosity >= 2:
779
528
result_class = VerboseTestResult
780
original_result = result_class(self.stream,
529
result = result_class(self.stream,
781
530
self.descriptions,
783
532
bench_history=self._bench_history,
533
num_tests=test.countTestCases(),
786
# Signal to result objects that look at stop early policy to stop,
787
original_result.stop_early = self.stop_on_failure
788
result = original_result
789
for decorator in self._result_decorators:
790
result = decorator(result)
791
result.stop_early = self.stop_on_failure
792
result.startTestRun()
535
result.stop_early = self.stop_on_failure
536
result.report_starting()
538
if self.verbosity >= 2:
539
self.stream.writeln("Listing tests only ...\n")
541
for t in iter_suite_tests(test):
542
self.stream.writeln("%s" % (t.id()))
544
actionTaken = "Listed"
797
# higher level code uses our extended protocol to determine
798
# what exit code to give.
799
return original_result
547
run = result.testsRun
549
stopTime = time.time()
550
timeTaken = stopTime - startTime
552
self.stream.writeln(result.separator2)
553
self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
554
run, run != 1 and "s" or "", timeTaken))
555
self.stream.writeln()
556
if not result.wasSuccessful():
557
self.stream.write("FAILED (")
558
failed, errored = map(len, (result.failures, result.errors))
560
self.stream.write("failures=%d" % failed)
562
if failed: self.stream.write(", ")
563
self.stream.write("errors=%d" % errored)
564
if result.known_failure_count:
565
if failed or errored: self.stream.write(", ")
566
self.stream.write("known_failure_count=%d" %
567
result.known_failure_count)
568
self.stream.writeln(")")
570
if result.known_failure_count:
571
self.stream.writeln("OK (known_failures=%d)" %
572
result.known_failure_count)
574
self.stream.writeln("OK")
575
if result.skip_count > 0:
576
skipped = result.skip_count
577
self.stream.writeln('%d test%s skipped' %
578
(skipped, skipped != 1 and "s" or ""))
579
if result.unsupported:
580
for feature, count in sorted(result.unsupported.items()):
581
self.stream.writeln("Missing feature '%s' skipped %d tests." %
802
587
def iter_suite_tests(suite):
953
744
routine, and to build and check bzr trees.
955
746
In addition to the usual method of overriding tearDown(), this class also
956
allows subclasses to register cleanup functions via addCleanup, which are
747
allows subclasses to register functions into the _cleanups list, which is
957
748
run in order as the object is torn down. It's less likely this will be
958
749
accidentally overlooked.
752
_active_threads = None
753
_leaking_threads_tests = 0
754
_first_thread_leaker_id = None
755
_log_file_name = None
757
_keep_log_file = False
962
758
# record lsprof data when performing benchmark calls.
963
759
_gather_lsprof_in_benchmarks = False
760
attrs_to_keep = ('id', '_testMethodName', '_testMethodDoc',
761
'_log_contents', '_log_file_name', '_benchtime',
762
'_TestCase__testMethodName')
965
764
def __init__(self, methodName='testMethod'):
966
765
super(TestCase, self).__init__(methodName)
967
self._directory_isolation = True
968
self.exception_handlers.insert(0,
969
(UnavailableFeature, self._do_unsupported_or_skip))
970
self.exception_handlers.insert(0,
971
(TestNotApplicable, self._do_not_applicable))
767
self._bzr_test_setUp_run = False
768
self._bzr_test_tearDown_run = False
974
super(TestCase, self).setUp()
975
for feature in getattr(self, '_test_needs_features', []):
976
self.requireFeature(feature)
771
unittest.TestCase.setUp(self)
772
self._bzr_test_setUp_run = True
977
773
self._cleanEnvironment()
978
774
self._silenceUI()
979
775
self._startLogFile()
980
776
self._benchcalls = []
981
777
self._benchtime = None
982
778
self._clear_hooks()
983
self._track_transports()
985
779
self._clear_debug_flags()
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()
780
TestCase._active_threads = threading.activeCount()
781
self.addCleanup(self._check_leaked_threads)
1002
783
def debug(self):
1003
784
# debug a frame up.
1005
786
pdb.Pdb().set_trace(sys._getframe().f_back)
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,))
789
absent_attr = object()
790
exc_info = getattr(self, '_exc_info', absent_attr)
791
if exc_info is absent_attr:
792
exc_info = getattr(self, '_TestCase__exc_info')
795
def _check_leaked_threads(self):
796
active = threading.activeCount()
797
leaked_threads = active - TestCase._active_threads
798
TestCase._active_threads = active
800
TestCase._leaking_threads_tests += 1
801
if TestCase._first_thread_leaker_id is None:
802
TestCase._first_thread_leaker_id = self.id()
803
# we're not specifically told when all tests are finished.
804
# This will do. We use a function to avoid keeping a reference
805
# to a TestCase object.
806
atexit.register(_report_leaked_threads)
1067
808
def _clear_debug_flags(self):
1068
809
"""Prevent externally set debug flags affecting tests.
1070
811
Tests that want to use debug flags can just set them in the
1071
812
debug_flags set during setup/teardown.
1073
# Start with a copy of the current debug flags we can safely modify.
1074
self.overrideAttr(debug, 'debug_flags', set(debug.debug_flags))
814
self._preserved_debug_flags = set(debug.debug_flags)
1075
815
if 'allow_debug' not in selftest_debug_flags:
1076
816
debug.debug_flags.clear()
1077
if 'disable_lock_checks' not in selftest_debug_flags:
1078
debug.debug_flags.add('strict_locks')
817
self.addCleanup(self._restore_debug_flags)
1080
819
def _clear_hooks(self):
1081
820
# prevent hooks affecting tests
1082
known_hooks = hooks.known_hooks
1083
821
self._preserved_hooks = {}
1084
for key, (parent, name) in known_hooks.iter_parent_objects():
1085
current_hooks = getattr(parent, name)
822
for key, factory in hooks.known_hooks.items():
823
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
824
current_hooks = hooks.known_hooks_key_to_object(key)
1086
825
self._preserved_hooks[parent] = (name, current_hooks)
1087
self._preserved_lazy_hooks = hooks._lazy_hooks
1088
hooks._lazy_hooks = {}
1089
826
self.addCleanup(self._restoreHooks)
1090
for key, (parent, name) in known_hooks.iter_parent_objects():
1091
factory = known_hooks.get(key)
827
for key, factory in hooks.known_hooks.items():
828
parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
1092
829
setattr(parent, name, factory())
1093
830
# this hook should always be installed
1094
831
request._install_hook()
1096
def disable_directory_isolation(self):
1097
"""Turn off directory isolation checks."""
1098
self._directory_isolation = False
1100
def enable_directory_isolation(self):
1101
"""Enable directory isolation checks."""
1102
self._directory_isolation = True
1104
833
def _silenceUI(self):
1105
834
"""Turn off UI for duration of test"""
1106
835
# by default the UI is off; tests can turn it on if they want it.
1107
self.overrideAttr(ui, 'ui_factory', ui.SilentUIFactory())
1109
def _check_locks(self):
1110
"""Check that all lock take/release actions have been paired."""
1111
# We always check for mismatched locks. If a mismatch is found, we
1112
# fail unless -Edisable_lock_checks is supplied to selftest, in which
1113
# case we just print a warning.
1115
acquired_locks = [lock for action, lock in self._lock_actions
1116
if action == 'acquired']
1117
released_locks = [lock for action, lock in self._lock_actions
1118
if action == 'released']
1119
broken_locks = [lock for action, lock in self._lock_actions
1120
if action == 'broken']
1121
# trivially, given the tests for lock acquistion and release, if we
1122
# have as many in each list, it should be ok. Some lock tests also
1123
# break some locks on purpose and should be taken into account by
1124
# considering that breaking a lock is just a dirty way of releasing it.
1125
if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
1127
'Different number of acquired and '
1128
'released or broken locks.\n'
1132
(acquired_locks, released_locks, broken_locks))
1133
if not self._lock_check_thorough:
1134
# Rather than fail, just warn
1135
print "Broken test %s: %s" % (self, message)
1139
def _track_locks(self):
1140
"""Track lock activity during tests."""
1141
self._lock_actions = []
1142
if 'disable_lock_checks' in selftest_debug_flags:
1143
self._lock_check_thorough = False
1145
self._lock_check_thorough = True
1147
self.addCleanup(self._check_locks)
1148
_mod_lock.Lock.hooks.install_named_hook('lock_acquired',
1149
self._lock_acquired, None)
1150
_mod_lock.Lock.hooks.install_named_hook('lock_released',
1151
self._lock_released, None)
1152
_mod_lock.Lock.hooks.install_named_hook('lock_broken',
1153
self._lock_broken, None)
1155
def _lock_acquired(self, result):
1156
self._lock_actions.append(('acquired', result))
1158
def _lock_released(self, result):
1159
self._lock_actions.append(('released', result))
1161
def _lock_broken(self, result):
1162
self._lock_actions.append(('broken', result))
1164
def permit_dir(self, name):
1165
"""Permit a directory to be used by this test. See permit_url."""
1166
name_transport = _mod_transport.get_transport(name)
1167
self.permit_url(name)
1168
self.permit_url(name_transport.base)
1170
def permit_url(self, url):
1171
"""Declare that url is an ok url to use in this test.
1173
Do this for memory transports, temporary test directory etc.
1175
Do not do this for the current working directory, /tmp, or any other
1176
preexisting non isolated url.
1178
if not url.endswith('/'):
1180
self._bzr_selftest_roots.append(url)
1182
def permit_source_tree_branch_repo(self):
1183
"""Permit the source tree bzr is running from to be opened.
1185
Some code such as bzrlib.version attempts to read from the bzr branch
1186
that bzr is executing from (if any). This method permits that directory
1187
to be used in the test suite.
1189
path = self.get_source_path()
1190
self.record_directory_isolation()
1193
workingtree.WorkingTree.open(path)
1194
except (errors.NotBranchError, errors.NoWorkingTree):
1195
raise TestSkipped('Needs a working tree of bzr sources')
1197
self.enable_directory_isolation()
1199
def _preopen_isolate_transport(self, transport):
1200
"""Check that all transport openings are done in the test work area."""
1201
while isinstance(transport, pathfilter.PathFilteringTransport):
1202
# Unwrap pathfiltered transports
1203
transport = transport.server.backing_transport.clone(
1204
transport._filter('.'))
1205
url = transport.base
1206
# ReadonlySmartTCPServer_for_testing decorates the backing transport
1207
# urls it is given by prepending readonly+. This is appropriate as the
1208
# client shouldn't know that the server is readonly (or not readonly).
1209
# We could register all servers twice, with readonly+ prepending, but
1210
# that makes for a long list; this is about the same but easier to
1212
if url.startswith('readonly+'):
1213
url = url[len('readonly+'):]
1214
self._preopen_isolate_url(url)
1216
def _preopen_isolate_url(self, url):
1217
if not self._directory_isolation:
1219
if self._directory_isolation == 'record':
1220
self._bzr_selftest_roots.append(url)
1222
# This prevents all transports, including e.g. sftp ones backed on disk
1223
# from working unless they are explicitly granted permission. We then
1224
# depend on the code that sets up test transports to check that they are
1225
# appropriately isolated and enable their use by calling
1226
# self.permit_transport()
1227
if not osutils.is_inside_any(self._bzr_selftest_roots, url):
1228
raise errors.BzrError("Attempt to escape test isolation: %r %r"
1229
% (url, self._bzr_selftest_roots))
1231
def record_directory_isolation(self):
1232
"""Gather accessed directories to permit later access.
1234
This is used for tests that access the branch bzr is running from.
1236
self._directory_isolation = "record"
1238
def start_server(self, transport_server, backing_server=None):
1239
"""Start transport_server for this test.
1241
This starts the server, registers a cleanup for it and permits the
1242
server's urls to be used.
1244
if backing_server is None:
1245
transport_server.start_server()
1247
transport_server.start_server(backing_server)
1248
self.addCleanup(transport_server.stop_server)
1249
# Obtain a real transport because if the server supplies a password, it
1250
# will be hidden from the base on the client side.
1251
t = _mod_transport.get_transport(transport_server.get_url())
1252
# Some transport servers effectively chroot the backing transport;
1253
# others like SFTPServer don't - users of the transport can walk up the
1254
# transport to read the entire backing transport. This wouldn't matter
1255
# except that the workdir tests are given - and that they expect the
1256
# server's url to point at - is one directory under the safety net. So
1257
# Branch operations into the transport will attempt to walk up one
1258
# directory. Chrooting all servers would avoid this but also mean that
1259
# we wouldn't be testing directly against non-root urls. Alternatively
1260
# getting the test framework to start the server with a backing server
1261
# at the actual safety net directory would work too, but this then
1262
# means that the self.get_url/self.get_transport methods would need
1263
# to transform all their results. On balance its cleaner to handle it
1264
# here, and permit a higher url when we have one of these transports.
1265
if t.base.endswith('/work/'):
1266
# we have safety net/test root/work
1267
t = t.clone('../..')
1268
elif isinstance(transport_server,
1269
test_server.SmartTCPServer_for_testing):
1270
# The smart server adds a path similar to work, which is traversed
1271
# up from by the client. But the server is chrooted - the actual
1272
# backing transport is not escaped from, and VFS requests to the
1273
# root will error (because they try to escape the chroot).
1275
while t2.base != t.base:
1278
self.permit_url(t.base)
1280
def _track_transports(self):
1281
"""Install checks for transport usage."""
1282
# TestCase has no safe place it can write to.
1283
self._bzr_selftest_roots = []
1284
# Currently the easiest way to be sure that nothing is going on is to
1285
# hook into bzr dir opening. This leaves a small window of error for
1286
# transport tests, but they are well known, and we can improve on this
1288
bzrdir.BzrDir.hooks.install_named_hook("pre_open",
1289
self._preopen_isolate_transport, "Check bzr directories are safe.")
836
saved = ui.ui_factory
838
ui.ui_factory = saved
839
ui.ui_factory = ui.SilentUIFactory()
840
self.addCleanup(_restore)
1291
842
def _ndiff_strings(self, a, b):
1292
843
"""Return ndiff between two strings containing lines.
1694
1214
The file is removed as the test is torn down.
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)
1216
fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
1217
self._log_file = os.fdopen(fileno, 'w+')
1218
self._log_memento = bzrlib.trace.push_log_file(self._log_file)
1219
self._log_file_name = name
1705
1220
self.addCleanup(self._finishLogFile)
1707
1222
def _finishLogFile(self):
1708
1223
"""Finished with the log file.
1710
Close the file and delete it.
1712
if trace._trace_file:
1713
# flush the log file, to get all content
1714
trace._trace_file.flush()
1715
trace.pop_log_file(self._log_memento)
1717
def thisFailsStrictLockCheck(self):
1718
"""It is known that this test would fail with -Dstrict_locks.
1720
By default, all tests are run with strict lock checking unless
1721
-Edisable_lock_checks is supplied. However there are some tests which
1722
we know fail strict locks at this point that have not been fixed.
1723
They should call this function to disable the strict checking.
1725
This should be used sparingly, it is much better to fix the locking
1726
issues rather than papering over the problem by calling this function.
1728
debug.debug_flags.discard('strict_locks')
1730
def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1731
"""Overrides an object attribute restoring it after the test.
1733
:param obj: The object that will be mutated.
1735
:param attr_name: The attribute name we want to preserve/override in
1738
:param new: The optional value we want to set the attribute to.
1740
:returns: The actual attr value.
1742
value = getattr(obj, attr_name)
1743
# The actual value is captured by the call below
1744
self.addCleanup(setattr, obj, attr_name, value)
1745
if new is not _unitialized_attr:
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)
1225
Close the file and delete it, unless setKeepLogfile was called.
1227
if self._log_file is None:
1229
bzrlib.trace.pop_log_file(self._log_memento)
1230
self._log_file.close()
1231
self._log_file = None
1232
if not self._keep_log_file:
1233
os.remove(self._log_file_name)
1234
self._log_file_name = None
1236
def setKeepLogfile(self):
1237
"""Make the logfile not be deleted when _finishLogFile is called."""
1238
self._keep_log_file = True
1240
def addCleanup(self, callable, *args, **kwargs):
1241
"""Arrange to run a callable when this case is torn down.
1243
Callables are run in the reverse of the order they are registered,
1244
ie last-in first-out.
1246
self._cleanups.append((callable, args, kwargs))
1763
1248
def _cleanEnvironment(self):
1764
for name, value in isolated_environ.iteritems():
1765
self.overrideEnv(name, value)
1250
'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
1251
'HOME': os.getcwd(),
1252
# bzr now uses the Win32 API and doesn't rely on APPDATA, but the
1253
# tests do check our impls match APPDATA
1254
'BZR_EDITOR': None, # test_msgeditor manipulates this variable
1258
'BZREMAIL': None, # may still be present in the environment
1260
'BZR_PROGRESS_BAR': None,
1262
'BZR_PLUGIN_PATH': None,
1264
'SSH_AUTH_SOCK': None,
1268
'https_proxy': None,
1269
'HTTPS_PROXY': None,
1274
# Nobody cares about these ones AFAIK. So far at
1275
# least. If you do (care), please update this comment
1279
'BZR_REMOTE_PATH': None,
1282
self.addCleanup(self._restoreEnvironment)
1283
for name, value in new_env.iteritems():
1284
self._captureVar(name, value)
1286
def _captureVar(self, name, newvalue):
1287
"""Set an environment variable, and reset it when finished."""
1288
self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
1290
def _restore_debug_flags(self):
1291
debug.debug_flags.clear()
1292
debug.debug_flags.update(self._preserved_debug_flags)
1294
def _restoreEnvironment(self):
1295
for name, value in self.__old_env.iteritems():
1296
osutils.set_or_unset_env(name, value)
1767
1298
def _restoreHooks(self):
1768
1299
for klass, (name, hooks) in self._preserved_hooks.items():
1769
1300
setattr(klass, name, hooks)
1770
self._preserved_hooks.clear()
1771
bzrlib.hooks._lazy_hooks = self._preserved_lazy_hooks
1772
self._preserved_lazy_hooks.clear()
1774
1302
def knownFailure(self, reason):
1775
1303
"""This test has failed for some known reason."""
1776
1304
raise KnownFailure(reason)
1778
def _suppress_log(self):
1779
"""Remove the log info from details."""
1780
self.discardDetail('log')
1782
1306
def _do_skip(self, result, reason):
1783
self._suppress_log()
1784
1307
addSkip = getattr(result, 'addSkip', None)
1785
1308
if not callable(addSkip):
1786
result.addSuccess(result)
1309
result.addError(self, self.exc_info())
1788
1311
addSkip(self, reason)
1791
def _do_known_failure(self, result, e):
1792
self._suppress_log()
1793
err = sys.exc_info()
1794
addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1795
if addExpectedFailure is not None:
1796
addExpectedFailure(self, err)
1798
result.addSuccess(self)
1801
def _do_not_applicable(self, result, e):
1803
reason = 'No reason given'
1806
self._suppress_log ()
1807
addNotApplicable = getattr(result, 'addNotApplicable', None)
1808
if addNotApplicable is not None:
1809
result.addNotApplicable(self, reason)
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)
1834
def _do_unsupported_or_skip(self, result, e):
1836
self._suppress_log()
1837
addNotSupported = getattr(result, 'addNotSupported', None)
1838
if addNotSupported is not None:
1839
result.addNotSupported(self, reason)
1841
self._do_skip(result, reason)
1313
def run(self, result=None):
1314
if result is None: result = self.defaultTestResult()
1315
for feature in getattr(self, '_test_needs_features', []):
1316
if not feature.available():
1317
result.startTest(self)
1318
if getattr(result, 'addNotSupported', None):
1319
result.addNotSupported(self, feature)
1321
result.addSuccess(self)
1322
result.stopTest(self)
1326
result.startTest(self)
1327
absent_attr = object()
1329
method_name = getattr(self, '_testMethodName', absent_attr)
1330
if method_name is absent_attr:
1332
method_name = getattr(self, '_TestCase__testMethodName')
1333
testMethod = getattr(self, method_name)
1337
if not self._bzr_test_setUp_run:
1339
"test setUp did not invoke "
1340
"bzrlib.tests.TestCase's setUp")
1341
except KeyboardInterrupt:
1343
except TestSkipped, e:
1344
self._do_skip(result, e.args[0])
1348
result.addError(self, self.exc_info())
1355
except self.failureException:
1356
result.addFailure(self, self.exc_info())
1357
except TestSkipped, e:
1359
reason = "No reason given."
1362
self._do_skip(result, reason)
1363
except KeyboardInterrupt:
1366
result.addError(self, self.exc_info())
1370
if not self._bzr_test_tearDown_run:
1372
"test tearDown did not invoke "
1373
"bzrlib.tests.TestCase's tearDown")
1374
except KeyboardInterrupt:
1377
result.addError(self, self.exc_info())
1379
if ok: result.addSuccess(self)
1381
result.stopTest(self)
1383
except TestNotApplicable:
1384
# Not moved from the result [yet].
1386
except KeyboardInterrupt:
1390
absent_attr = object()
1391
for attr_name in self.attrs_to_keep:
1392
attr = getattr(self, attr_name, absent_attr)
1393
if attr is not absent_attr:
1394
saved_attrs[attr_name] = attr
1395
self.__dict__ = saved_attrs
1398
self._bzr_test_tearDown_run = True
1400
self._log_contents = ''
1401
unittest.TestCase.tearDown(self)
1843
1403
def time(self, callable, *args, **kwargs):
1844
1404
"""Run callable and accrue the time it takes to the benchmark time.
3392
2836
return iter(self._tests)
3395
def partition_tests(suite, count):
3396
"""Partition suite into count lists of 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)
3409
def workaround_zealous_crypto_random():
3410
"""Crypto.Random want to help us being secure, but we don't care here.
3412
This workaround some test failure related to the sftp server. Once paramiko
3413
stop using the controversial API in Crypto.Random, we may get rid of it.
3416
from Crypto.Random import atfork
3422
def fork_for_tests(suite):
3423
"""Take suite and start up one runner per CPU by forking()
3425
:return: An iterable of TestCase-like objects which can each have
3426
run(result) called on them to feed tests to result.
3428
concurrency = osutils.local_concurrency()
3430
from subunit import TestProtocolClient, ProtocolTestCase
3431
from subunit.test_results import AutoTimingTestResultDecorator
3432
class TestInOtherProcess(ProtocolTestCase):
3433
# Should be in subunit, I think. RBC.
3434
def __init__(self, stream, pid):
3435
ProtocolTestCase.__init__(self, stream)
3438
def run(self, result):
3440
ProtocolTestCase.run(self, result)
3442
os.waitpid(self.pid, 0)
3444
test_blocks = partition_tests(suite, concurrency)
3445
for process_tests in test_blocks:
3446
process_suite = TestUtil.TestSuite()
3447
process_suite.addTests(process_tests)
3448
c2pread, c2pwrite = os.pipe()
3451
workaround_zealous_crypto_random()
3454
# Leave stderr and stdout open so we can see test noise
3455
# Close stdin so that the child goes away if it decides to
3456
# read from stdin (otherwise its a roulette to see what
3457
# child actually gets keystrokes for pdb etc).
3460
stream = os.fdopen(c2pwrite, 'wb', 1)
3461
subunit_result = AutoTimingTestResultDecorator(
3462
TestProtocolClient(stream))
3463
process_suite.run(subunit_result)
3468
stream = os.fdopen(c2pread, 'rb', 1)
3469
test = TestInOtherProcess(stream, pid)
3474
def reinvoke_for_tests(suite):
3475
"""Take suite and start up one runner per CPU using subprocess().
3477
:return: An iterable of TestCase-like objects which can each have
3478
run(result) called on them to feed tests to result.
3480
concurrency = osutils.local_concurrency()
3482
from subunit import ProtocolTestCase
3483
class TestInSubprocess(ProtocolTestCase):
3484
def __init__(self, process, name):
3485
ProtocolTestCase.__init__(self, process.stdout)
3486
self.process = process
3487
self.process.stdin.close()
3490
def run(self, result):
3492
ProtocolTestCase.run(self, result)
3495
os.unlink(self.name)
3496
# print "pid %d finished" % finished_process
3497
test_blocks = partition_tests(suite, concurrency)
3498
for process_tests in test_blocks:
3499
# ugly; currently reimplement rather than reuses TestCase methods.
3500
bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
3501
if not os.path.isfile(bzr_path):
3502
# We are probably installed. Assume sys.argv is the right file
3503
bzr_path = sys.argv[0]
3504
bzr_path = [bzr_path]
3505
if sys.platform == "win32":
3506
# if we're on windows, we can't execute the bzr script directly
3507
bzr_path = [sys.executable] + bzr_path
3508
fd, test_list_file_name = tempfile.mkstemp()
3509
test_list_file = os.fdopen(fd, 'wb', 1)
3510
for test in process_tests:
3511
test_list_file.write(test.id() + '\n')
3512
test_list_file.close()
3514
argv = bzr_path + ['selftest', '--load-list', test_list_file_name,
3516
if '--no-plugins' in sys.argv:
3517
argv.append('--no-plugins')
3518
# stderr=subprocess.STDOUT would be ideal, but until we prevent
3519
# noise on stderr it can interrupt the subunit protocol.
3520
process = subprocess.Popen(argv, stdin=subprocess.PIPE,
3521
stdout=subprocess.PIPE,
3522
stderr=subprocess.PIPE,
3524
test = TestInSubprocess(process, test_list_file_name)
3527
os.unlink(test_list_file_name)
3532
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3533
"""Generate profiling data for all activity between start and success.
3535
The profile data is appended to the test's _benchcalls attribute and can
3536
be accessed by the forwarded-to TestResult.
3538
While it might be cleaner do accumulate this in stopTest, addSuccess is
3539
where our existing output support for lsprof is, and this class aims to
3540
fit in with that: while it could be moved it's not necessary to accomplish
3541
test profiling, nor would it be dramatically cleaner.
3544
def startTest(self, test):
3545
self.profiler = bzrlib.lsprof.BzrProfiler()
3546
# Prevent deadlocks in tests that use lsprof: those tests will
3548
bzrlib.lsprof.BzrProfiler.profiler_block = 0
3549
self.profiler.start()
3550
testtools.ExtendedToOriginalDecorator.startTest(self, test)
3552
def addSuccess(self, test):
3553
stats = self.profiler.stop()
3555
calls = test._benchcalls
3556
except AttributeError:
3557
test._benchcalls = []
3558
calls = test._benchcalls
3559
calls.append(((test.id(), "", ""), stats))
3560
testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
3562
def stopTest(self, test):
3563
testtools.ExtendedToOriginalDecorator.stopTest(self, test)
3564
self.profiler = None
3567
2839
# Controlled by "bzr selftest -E=..." option
3568
# Currently supported:
3569
# -Eallow_debug Will no longer clear debug.debug_flags() so it
3570
# preserves any flags supplied at the command line.
3571
# -Edisable_lock_checks Turns errors in mismatched locks into simple prints
3572
# rather than failing tests. And no longer raise
3573
# LockContention when fctnl locks are not being used
3574
# with proper exclusion rules.
3575
# -Ethreads Will display thread ident at creation/join time to
3576
# help track thread leaks
3578
# -Econfig_stats Will collect statistics using addDetail
3579
2840
selftest_debug_flags = set()
3809
3052
test_prefix_alias_registry.register('bp', 'bzrlib.plugins')
3812
def _test_suite_testmod_names():
3813
"""Return the standard list of test module names to test."""
3816
'bzrlib.tests.blackbox',
3817
'bzrlib.tests.commands',
3818
'bzrlib.tests.doc_generate',
3819
'bzrlib.tests.per_branch',
3820
'bzrlib.tests.per_bzrdir',
3821
'bzrlib.tests.per_controldir',
3822
'bzrlib.tests.per_controldir_colo',
3823
'bzrlib.tests.per_foreign_vcs',
3824
'bzrlib.tests.per_interrepository',
3825
'bzrlib.tests.per_intertree',
3826
'bzrlib.tests.per_inventory',
3827
'bzrlib.tests.per_interbranch',
3828
'bzrlib.tests.per_lock',
3829
'bzrlib.tests.per_merger',
3830
'bzrlib.tests.per_transport',
3831
'bzrlib.tests.per_tree',
3832
'bzrlib.tests.per_pack_repository',
3833
'bzrlib.tests.per_repository',
3834
'bzrlib.tests.per_repository_chk',
3835
'bzrlib.tests.per_repository_reference',
3836
'bzrlib.tests.per_repository_vf',
3837
'bzrlib.tests.per_uifactory',
3838
'bzrlib.tests.per_versionedfile',
3839
'bzrlib.tests.per_workingtree',
3840
'bzrlib.tests.test__annotator',
3841
'bzrlib.tests.test__bencode',
3842
'bzrlib.tests.test__btree_serializer',
3843
'bzrlib.tests.test__chk_map',
3844
'bzrlib.tests.test__dirstate_helpers',
3845
'bzrlib.tests.test__groupcompress',
3846
'bzrlib.tests.test__known_graph',
3847
'bzrlib.tests.test__rio',
3848
'bzrlib.tests.test__simple_set',
3849
'bzrlib.tests.test__static_tuple',
3850
'bzrlib.tests.test__walkdirs_win32',
3851
'bzrlib.tests.test_ancestry',
3852
'bzrlib.tests.test_annotate',
3853
'bzrlib.tests.test_api',
3854
'bzrlib.tests.test_atomicfile',
3855
'bzrlib.tests.test_bad_files',
3856
'bzrlib.tests.test_bisect_multi',
3857
'bzrlib.tests.test_branch',
3858
'bzrlib.tests.test_branchbuilder',
3859
'bzrlib.tests.test_btree_index',
3860
'bzrlib.tests.test_bugtracker',
3861
'bzrlib.tests.test_bundle',
3862
'bzrlib.tests.test_bzrdir',
3863
'bzrlib.tests.test__chunks_to_lines',
3864
'bzrlib.tests.test_cache_utf8',
3865
'bzrlib.tests.test_chk_map',
3866
'bzrlib.tests.test_chk_serializer',
3867
'bzrlib.tests.test_chunk_writer',
3868
'bzrlib.tests.test_clean_tree',
3869
'bzrlib.tests.test_cleanup',
3870
'bzrlib.tests.test_cmdline',
3871
'bzrlib.tests.test_commands',
3872
'bzrlib.tests.test_commit',
3873
'bzrlib.tests.test_commit_merge',
3874
'bzrlib.tests.test_config',
3875
'bzrlib.tests.test_conflicts',
3876
'bzrlib.tests.test_controldir',
3877
'bzrlib.tests.test_counted_lock',
3878
'bzrlib.tests.test_crash',
3879
'bzrlib.tests.test_decorators',
3880
'bzrlib.tests.test_delta',
3881
'bzrlib.tests.test_debug',
3882
'bzrlib.tests.test_diff',
3883
'bzrlib.tests.test_directory_service',
3884
'bzrlib.tests.test_dirstate',
3885
'bzrlib.tests.test_email_message',
3886
'bzrlib.tests.test_eol_filters',
3887
'bzrlib.tests.test_errors',
3888
'bzrlib.tests.test_export',
3889
'bzrlib.tests.test_export_pot',
3890
'bzrlib.tests.test_extract',
3891
'bzrlib.tests.test_fetch',
3892
'bzrlib.tests.test_fixtures',
3893
'bzrlib.tests.test_fifo_cache',
3894
'bzrlib.tests.test_filters',
3895
'bzrlib.tests.test_ftp_transport',
3896
'bzrlib.tests.test_foreign',
3897
'bzrlib.tests.test_generate_docs',
3898
'bzrlib.tests.test_generate_ids',
3899
'bzrlib.tests.test_globbing',
3900
'bzrlib.tests.test_gpg',
3901
'bzrlib.tests.test_graph',
3902
'bzrlib.tests.test_groupcompress',
3903
'bzrlib.tests.test_hashcache',
3904
'bzrlib.tests.test_help',
3905
'bzrlib.tests.test_hooks',
3906
'bzrlib.tests.test_http',
3907
'bzrlib.tests.test_http_response',
3908
'bzrlib.tests.test_https_ca_bundle',
3909
'bzrlib.tests.test_i18n',
3910
'bzrlib.tests.test_identitymap',
3911
'bzrlib.tests.test_ignores',
3912
'bzrlib.tests.test_index',
3913
'bzrlib.tests.test_import_tariff',
3914
'bzrlib.tests.test_info',
3915
'bzrlib.tests.test_inv',
3916
'bzrlib.tests.test_inventory_delta',
3917
'bzrlib.tests.test_knit',
3918
'bzrlib.tests.test_lazy_import',
3919
'bzrlib.tests.test_lazy_regex',
3920
'bzrlib.tests.test_library_state',
3921
'bzrlib.tests.test_lock',
3922
'bzrlib.tests.test_lockable_files',
3923
'bzrlib.tests.test_lockdir',
3924
'bzrlib.tests.test_log',
3925
'bzrlib.tests.test_lru_cache',
3926
'bzrlib.tests.test_lsprof',
3927
'bzrlib.tests.test_mail_client',
3928
'bzrlib.tests.test_matchers',
3929
'bzrlib.tests.test_memorytree',
3930
'bzrlib.tests.test_merge',
3931
'bzrlib.tests.test_merge3',
3932
'bzrlib.tests.test_merge_core',
3933
'bzrlib.tests.test_merge_directive',
3934
'bzrlib.tests.test_mergetools',
3935
'bzrlib.tests.test_missing',
3936
'bzrlib.tests.test_msgeditor',
3937
'bzrlib.tests.test_multiparent',
3938
'bzrlib.tests.test_mutabletree',
3939
'bzrlib.tests.test_nonascii',
3940
'bzrlib.tests.test_options',
3941
'bzrlib.tests.test_osutils',
3942
'bzrlib.tests.test_osutils_encodings',
3943
'bzrlib.tests.test_pack',
3944
'bzrlib.tests.test_patch',
3945
'bzrlib.tests.test_patches',
3946
'bzrlib.tests.test_permissions',
3947
'bzrlib.tests.test_plugins',
3948
'bzrlib.tests.test_progress',
3949
'bzrlib.tests.test_pyutils',
3950
'bzrlib.tests.test_read_bundle',
3951
'bzrlib.tests.test_reconcile',
3952
'bzrlib.tests.test_reconfigure',
3953
'bzrlib.tests.test_registry',
3954
'bzrlib.tests.test_remote',
3955
'bzrlib.tests.test_rename_map',
3956
'bzrlib.tests.test_repository',
3957
'bzrlib.tests.test_revert',
3958
'bzrlib.tests.test_revision',
3959
'bzrlib.tests.test_revisionspec',
3960
'bzrlib.tests.test_revisiontree',
3961
'bzrlib.tests.test_rio',
3962
'bzrlib.tests.test_rules',
3963
'bzrlib.tests.test_sampler',
3964
'bzrlib.tests.test_scenarios',
3965
'bzrlib.tests.test_script',
3966
'bzrlib.tests.test_selftest',
3967
'bzrlib.tests.test_serializer',
3968
'bzrlib.tests.test_setup',
3969
'bzrlib.tests.test_sftp_transport',
3970
'bzrlib.tests.test_shelf',
3971
'bzrlib.tests.test_shelf_ui',
3972
'bzrlib.tests.test_smart',
3973
'bzrlib.tests.test_smart_add',
3974
'bzrlib.tests.test_smart_request',
3975
'bzrlib.tests.test_smart_transport',
3976
'bzrlib.tests.test_smtp_connection',
3977
'bzrlib.tests.test_source',
3978
'bzrlib.tests.test_ssh_transport',
3979
'bzrlib.tests.test_status',
3980
'bzrlib.tests.test_store',
3981
'bzrlib.tests.test_strace',
3982
'bzrlib.tests.test_subsume',
3983
'bzrlib.tests.test_switch',
3984
'bzrlib.tests.test_symbol_versioning',
3985
'bzrlib.tests.test_tag',
3986
'bzrlib.tests.test_test_server',
3987
'bzrlib.tests.test_testament',
3988
'bzrlib.tests.test_textfile',
3989
'bzrlib.tests.test_textmerge',
3990
'bzrlib.tests.test_cethread',
3991
'bzrlib.tests.test_timestamp',
3992
'bzrlib.tests.test_trace',
3993
'bzrlib.tests.test_transactions',
3994
'bzrlib.tests.test_transform',
3995
'bzrlib.tests.test_transport',
3996
'bzrlib.tests.test_transport_log',
3997
'bzrlib.tests.test_tree',
3998
'bzrlib.tests.test_treebuilder',
3999
'bzrlib.tests.test_treeshape',
4000
'bzrlib.tests.test_tsort',
4001
'bzrlib.tests.test_tuned_gzip',
4002
'bzrlib.tests.test_ui',
4003
'bzrlib.tests.test_uncommit',
4004
'bzrlib.tests.test_upgrade',
4005
'bzrlib.tests.test_upgrade_stacked',
4006
'bzrlib.tests.test_urlutils',
4007
'bzrlib.tests.test_utextwrap',
4008
'bzrlib.tests.test_version',
4009
'bzrlib.tests.test_version_info',
4010
'bzrlib.tests.test_versionedfile',
4011
'bzrlib.tests.test_weave',
4012
'bzrlib.tests.test_whitebox',
4013
'bzrlib.tests.test_win32utils',
4014
'bzrlib.tests.test_workingtree',
4015
'bzrlib.tests.test_workingtree_4',
4016
'bzrlib.tests.test_wsgi',
4017
'bzrlib.tests.test_xml',
4021
def _test_suite_modules_to_doctest():
4022
"""Return the list of modules to doctest."""
4024
# GZ 2009-03-31: No docstrings with -OO so there's nothing to doctest
4028
'bzrlib.branchbuilder',
4029
'bzrlib.decorators',
4031
'bzrlib.iterablefile',
4036
'bzrlib.symbol_versioning',
4038
'bzrlib.tests.fixtures',
4040
'bzrlib.transport.http',
4041
'bzrlib.version_info_formats.format_custom',
4045
3055
def test_suite(keep_only=None, starting_with=None):
4046
3056
"""Build and return TestSuite for the whole of bzrlib.
4053
3063
This function can be replaced if you need to change the default test
4054
3064
suite on a global basis, but it is not encouraged.
3068
'bzrlib.tests.blackbox',
3069
'bzrlib.tests.branch_implementations',
3070
'bzrlib.tests.bzrdir_implementations',
3071
'bzrlib.tests.commands',
3072
'bzrlib.tests.interrepository_implementations',
3073
'bzrlib.tests.intertree_implementations',
3074
'bzrlib.tests.inventory_implementations',
3075
'bzrlib.tests.per_interbranch',
3076
'bzrlib.tests.per_lock',
3077
'bzrlib.tests.per_repository',
3078
'bzrlib.tests.per_repository_reference',
3079
'bzrlib.tests.test__dirstate_helpers',
3080
'bzrlib.tests.test__walkdirs_win32',
3081
'bzrlib.tests.test_ancestry',
3082
'bzrlib.tests.test_annotate',
3083
'bzrlib.tests.test_api',
3084
'bzrlib.tests.test_atomicfile',
3085
'bzrlib.tests.test_bad_files',
3086
'bzrlib.tests.test_bisect_multi',
3087
'bzrlib.tests.test_branch',
3088
'bzrlib.tests.test_branchbuilder',
3089
'bzrlib.tests.test_btree_index',
3090
'bzrlib.tests.test_bugtracker',
3091
'bzrlib.tests.test_bundle',
3092
'bzrlib.tests.test_bzrdir',
3093
'bzrlib.tests.test_cache_utf8',
3094
'bzrlib.tests.test_clean_tree',
3095
'bzrlib.tests.test_chunk_writer',
3096
'bzrlib.tests.test__chunks_to_lines',
3097
'bzrlib.tests.test_commands',
3098
'bzrlib.tests.test_commit',
3099
'bzrlib.tests.test_commit_merge',
3100
'bzrlib.tests.test_config',
3101
'bzrlib.tests.test_conflicts',
3102
'bzrlib.tests.test_counted_lock',
3103
'bzrlib.tests.test_decorators',
3104
'bzrlib.tests.test_delta',
3105
'bzrlib.tests.test_debug',
3106
'bzrlib.tests.test_deprecated_graph',
3107
'bzrlib.tests.test_diff',
3108
'bzrlib.tests.test_directory_service',
3109
'bzrlib.tests.test_dirstate',
3110
'bzrlib.tests.test_email_message',
3111
'bzrlib.tests.test_errors',
3112
'bzrlib.tests.test_export',
3113
'bzrlib.tests.test_extract',
3114
'bzrlib.tests.test_fetch',
3115
'bzrlib.tests.test_fifo_cache',
3116
'bzrlib.tests.test_filters',
3117
'bzrlib.tests.test_ftp_transport',
3118
'bzrlib.tests.test_foreign',
3119
'bzrlib.tests.test_generate_docs',
3120
'bzrlib.tests.test_generate_ids',
3121
'bzrlib.tests.test_globbing',
3122
'bzrlib.tests.test_gpg',
3123
'bzrlib.tests.test_graph',
3124
'bzrlib.tests.test_hashcache',
3125
'bzrlib.tests.test_help',
3126
'bzrlib.tests.test_hooks',
3127
'bzrlib.tests.test_http',
3128
'bzrlib.tests.test_http_implementations',
3129
'bzrlib.tests.test_http_response',
3130
'bzrlib.tests.test_https_ca_bundle',
3131
'bzrlib.tests.test_identitymap',
3132
'bzrlib.tests.test_ignores',
3133
'bzrlib.tests.test_index',
3134
'bzrlib.tests.test_info',
3135
'bzrlib.tests.test_inv',
3136
'bzrlib.tests.test_knit',
3137
'bzrlib.tests.test_lazy_import',
3138
'bzrlib.tests.test_lazy_regex',
3139
'bzrlib.tests.test_lockable_files',
3140
'bzrlib.tests.test_lockdir',
3141
'bzrlib.tests.test_log',
3142
'bzrlib.tests.test_lru_cache',
3143
'bzrlib.tests.test_lsprof',
3144
'bzrlib.tests.test_mail_client',
3145
'bzrlib.tests.test_memorytree',
3146
'bzrlib.tests.test_merge',
3147
'bzrlib.tests.test_merge3',
3148
'bzrlib.tests.test_merge_core',
3149
'bzrlib.tests.test_merge_directive',
3150
'bzrlib.tests.test_missing',
3151
'bzrlib.tests.test_msgeditor',
3152
'bzrlib.tests.test_multiparent',
3153
'bzrlib.tests.test_mutabletree',
3154
'bzrlib.tests.test_nonascii',
3155
'bzrlib.tests.test_options',
3156
'bzrlib.tests.test_osutils',
3157
'bzrlib.tests.test_osutils_encodings',
3158
'bzrlib.tests.test_pack',
3159
'bzrlib.tests.test_pack_repository',
3160
'bzrlib.tests.test_patch',
3161
'bzrlib.tests.test_patches',
3162
'bzrlib.tests.test_permissions',
3163
'bzrlib.tests.test_plugins',
3164
'bzrlib.tests.test_progress',
3165
'bzrlib.tests.test_read_bundle',
3166
'bzrlib.tests.test_reconcile',
3167
'bzrlib.tests.test_reconfigure',
3168
'bzrlib.tests.test_registry',
3169
'bzrlib.tests.test_remote',
3170
'bzrlib.tests.test_rename_map',
3171
'bzrlib.tests.test_repository',
3172
'bzrlib.tests.test_revert',
3173
'bzrlib.tests.test_revision',
3174
'bzrlib.tests.test_revisionspec',
3175
'bzrlib.tests.test_revisiontree',
3176
'bzrlib.tests.test_rio',
3177
'bzrlib.tests.test_rules',
3178
'bzrlib.tests.test_sampler',
3179
'bzrlib.tests.test_selftest',
3180
'bzrlib.tests.test_setup',
3181
'bzrlib.tests.test_sftp_transport',
3182
'bzrlib.tests.test_shelf',
3183
'bzrlib.tests.test_shelf_ui',
3184
'bzrlib.tests.test_smart',
3185
'bzrlib.tests.test_smart_add',
3186
'bzrlib.tests.test_smart_request',
3187
'bzrlib.tests.test_smart_transport',
3188
'bzrlib.tests.test_smtp_connection',
3189
'bzrlib.tests.test_source',
3190
'bzrlib.tests.test_ssh_transport',
3191
'bzrlib.tests.test_status',
3192
'bzrlib.tests.test_store',
3193
'bzrlib.tests.test_strace',
3194
'bzrlib.tests.test_subsume',
3195
'bzrlib.tests.test_switch',
3196
'bzrlib.tests.test_symbol_versioning',
3197
'bzrlib.tests.test_tag',
3198
'bzrlib.tests.test_testament',
3199
'bzrlib.tests.test_textfile',
3200
'bzrlib.tests.test_textmerge',
3201
'bzrlib.tests.test_timestamp',
3202
'bzrlib.tests.test_trace',
3203
'bzrlib.tests.test_transactions',
3204
'bzrlib.tests.test_transform',
3205
'bzrlib.tests.test_transport',
3206
'bzrlib.tests.test_transport_implementations',
3207
'bzrlib.tests.test_transport_log',
3208
'bzrlib.tests.test_tree',
3209
'bzrlib.tests.test_treebuilder',
3210
'bzrlib.tests.test_tsort',
3211
'bzrlib.tests.test_tuned_gzip',
3212
'bzrlib.tests.test_ui',
3213
'bzrlib.tests.test_uncommit',
3214
'bzrlib.tests.test_upgrade',
3215
'bzrlib.tests.test_upgrade_stacked',
3216
'bzrlib.tests.test_urlutils',
3217
'bzrlib.tests.test_version',
3218
'bzrlib.tests.test_version_info',
3219
'bzrlib.tests.test_versionedfile',
3220
'bzrlib.tests.test_weave',
3221
'bzrlib.tests.test_whitebox',
3222
'bzrlib.tests.test_win32utils',
3223
'bzrlib.tests.test_workingtree',
3224
'bzrlib.tests.test_workingtree_4',
3225
'bzrlib.tests.test_wsgi',
3226
'bzrlib.tests.test_xml',
3227
'bzrlib.tests.tree_implementations',
3228
'bzrlib.tests.workingtree_implementations',
3229
'bzrlib.util.tests.test_bencode',
4057
3232
loader = TestUtil.TestLoader()
4059
if keep_only is not None:
4060
id_filter = TestIdList(keep_only)
4061
3234
if starting_with:
3235
starting_with = [test_prefix_alias_registry.resolve_alias(start)
3236
for start in starting_with]
4062
3237
# We take precedence over keep_only because *at loading time* using
4063
3238
# both options means we will load less tests for the same final result.
4064
3239
def interesting_module(name):
4248
3429
:param new_id: The id to assign to it.
4249
3430
:return: The new test.
4251
new_test = copy.copy(test)
3432
from copy import deepcopy
3433
new_test = deepcopy(test)
4252
3434
new_test.id = lambda: new_id
4253
# XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
4254
# causes cloned tests to share the 'details' dict. This makes it hard to
4255
# read the test output for parameterized tests, because tracebacks will be
4256
# associated with irrelevant tests.
4258
details = new_test._TestCase__details
4259
except AttributeError:
4260
# must be a different version of testtools than expected. Do nothing.
4263
# Reset the '__details' dict.
4264
new_test._TestCase__details = {}
4265
3435
return new_test
4268
def permute_tests_for_extension(standard_tests, loader, py_module_name,
4270
"""Helper for permutating tests against an extension module.
4272
This is meant to be used inside a modules 'load_tests()' function. It will
4273
create 2 scenarios, and cause all tests in the 'standard_tests' to be run
4274
against both implementations. Setting 'test.module' to the appropriate
4275
module. See bzrlib.tests.test__chk_map.load_tests as an example.
4277
:param standard_tests: A test suite to permute
4278
:param loader: A TestLoader
4279
:param py_module_name: The python path to a python module that can always
4280
be loaded, and will be considered the 'python' implementation. (eg
4281
'bzrlib._chk_map_py')
4282
:param ext_module_name: The python path to an extension module. If the
4283
module cannot be loaded, a single test will be added, which notes that
4284
the module is not available. If it can be loaded, all standard_tests
4285
will be run against that module.
4286
:return: (suite, feature) suite is a test-suite that has all the permuted
4287
tests. feature is the Feature object that can be used to determine if
4288
the module is available.
4291
py_module = pyutils.get_named_object(py_module_name)
4293
('python', {'module': py_module}),
4295
suite = loader.suiteClass()
4296
feature = ModuleAvailableFeature(ext_module_name)
4297
if feature.available():
4298
scenarios.append(('C', {'module': feature.module}))
4300
# the compiled module isn't available, so we add a failing test
4301
class FailWithoutFeature(TestCase):
4302
def test_fail(self):
4303
self.requireFeature(feature)
4304
suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
4305
result = multiply_tests(standard_tests, scenarios, suite)
4306
return result, feature
4309
def _rmtree_temp_dir(dirname, test_id=None):
3438
def _rmtree_temp_dir(dirname):
4310
3439
# If LANG=C we probably have created some bogus paths
4311
3440
# which rmtree(unicode) will fail to delete
4312
3441
# so make sure we are using rmtree(str) to delete everything