/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Matthäus G. Chajdas
  • Date: 2010-10-12 01:18:01 UTC
  • mto: (5484.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 5485.
  • Revision ID: dev@anteru.net-20101012011801-thahmhfxdzz0j6d4
Remove spaces.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
 
30
30
import atexit
31
31
import codecs
32
 
from copy import copy
 
32
import copy
33
33
from cStringIO import StringIO
34
34
import difflib
35
35
import doctest
36
36
import errno
 
37
import itertools
37
38
import logging
38
 
import math
39
39
import os
40
 
from pprint import pformat
 
40
import platform
 
41
import pprint
41
42
import random
42
43
import re
43
44
import shlex
44
45
import stat
45
 
from subprocess import Popen, PIPE, STDOUT
 
46
import subprocess
46
47
import sys
47
48
import tempfile
48
49
import threading
70
71
    lock as _mod_lock,
71
72
    memorytree,
72
73
    osutils,
73
 
    progress,
74
74
    ui,
75
75
    urlutils,
76
76
    registry,
 
77
    transport as _mod_transport,
77
78
    workingtree,
78
79
    )
79
80
import bzrlib.branch
103
104
    )
104
105
import bzrlib.trace
105
106
from bzrlib.transport import (
106
 
    get_transport,
107
107
    memory,
108
108
    pathfilter,
109
109
    )
110
 
import bzrlib.transport
111
110
from bzrlib.trace import mutter, note
112
111
from bzrlib.tests import (
113
112
    test_server,
114
113
    TestUtil,
115
114
    treeshape,
116
115
    )
117
 
from bzrlib.tests.http_server import HttpServer
118
 
from bzrlib.tests.TestUtil import (
119
 
                          TestSuite,
120
 
                          TestLoader,
121
 
                          )
122
116
from bzrlib.ui import NullProgressView
123
117
from bzrlib.ui.text import TextUIFactory
124
118
import bzrlib.version_info_formats.format_custom
140
134
SUBUNIT_SEEK_SET = 0
141
135
SUBUNIT_SEEK_CUR = 1
142
136
 
 
137
# These are intentionally brought into this namespace. That way plugins, etc
 
138
# can just "from bzrlib.tests import TestCase, TestLoader, etc"
 
139
TestSuite = TestUtil.TestSuite
 
140
TestLoader = TestUtil.TestLoader
143
141
 
144
 
class ExtendedTestResult(unittest._TextTestResult):
 
142
class ExtendedTestResult(testtools.TextTestResult):
145
143
    """Accepts, reports and accumulates the results of running tests.
146
144
 
147
145
    Compared to the unittest version this class adds support for
168
166
        :param bench_history: Optionally, a writable file object to accumulate
169
167
            benchmark results.
170
168
        """
171
 
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
 
169
        testtools.TextTestResult.__init__(self, stream)
172
170
        if bench_history is not None:
173
171
            from bzrlib.version import _get_bzr_source_tree
174
172
            src_tree = _get_bzr_source_tree()
195
193
        self.count = 0
196
194
        self._overall_start_time = time.time()
197
195
        self._strict = strict
 
196
        self._first_thread_leaker_id = None
 
197
        self._tests_leaking_threads_count = 0
 
198
        self._traceback_from_test = None
198
199
 
199
200
    def stopTestRun(self):
200
201
        run = self.testsRun
201
202
        actionTaken = "Ran"
202
203
        stopTime = time.time()
203
204
        timeTaken = stopTime - self.startTime
204
 
        self.printErrors()
205
 
        self.stream.writeln(self.separator2)
206
 
        self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
 
205
        # GZ 2010-07-19: Seems testtools has no printErrors method, and though
 
206
        #                the parent class method is similar have to duplicate
 
207
        self._show_list('ERROR', self.errors)
 
208
        self._show_list('FAIL', self.failures)
 
209
        self.stream.write(self.sep2)
 
210
        self.stream.write("%s %d test%s in %.3fs\n\n" % (actionTaken,
207
211
                            run, run != 1 and "s" or "", timeTaken))
208
 
        self.stream.writeln()
209
212
        if not self.wasSuccessful():
210
213
            self.stream.write("FAILED (")
211
214
            failed, errored = map(len, (self.failures, self.errors))
218
221
                if failed or errored: self.stream.write(", ")
219
222
                self.stream.write("known_failure_count=%d" %
220
223
                    self.known_failure_count)
221
 
            self.stream.writeln(")")
 
224
            self.stream.write(")\n")
222
225
        else:
223
226
            if self.known_failure_count:
224
 
                self.stream.writeln("OK (known_failures=%d)" %
 
227
                self.stream.write("OK (known_failures=%d)\n" %
225
228
                    self.known_failure_count)
226
229
            else:
227
 
                self.stream.writeln("OK")
 
230
                self.stream.write("OK\n")
228
231
        if self.skip_count > 0:
229
232
            skipped = self.skip_count
230
 
            self.stream.writeln('%d test%s skipped' %
 
233
            self.stream.write('%d test%s skipped\n' %
231
234
                                (skipped, skipped != 1 and "s" or ""))
232
235
        if self.unsupported:
233
236
            for feature, count in sorted(self.unsupported.items()):
234
 
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
 
237
                self.stream.write("Missing feature '%s' skipped %d tests.\n" %
235
238
                    (feature, count))
236
239
        if self._strict:
237
240
            ok = self.wasStrictlySuccessful()
238
241
        else:
239
242
            ok = self.wasSuccessful()
240
 
        if TestCase._first_thread_leaker_id:
 
243
        if self._first_thread_leaker_id:
241
244
            self.stream.write(
242
245
                '%s is leaking threads among %d leaking tests.\n' % (
243
 
                TestCase._first_thread_leaker_id,
244
 
                TestCase._leaking_threads_tests))
 
246
                self._first_thread_leaker_id,
 
247
                self._tests_leaking_threads_count))
245
248
            # We don't report the main thread as an active one.
246
249
            self.stream.write(
247
250
                '%d non-main threads were left active in the end.\n'
248
 
                % (TestCase._active_threads - 1))
 
251
                % (len(self._active_threads) - 1))
249
252
 
250
253
    def getDescription(self, test):
251
254
        return test.id()
258
261
 
259
262
    def _elapsedTestTimeString(self):
260
263
        """Return a time string for the overall time the current test has taken."""
261
 
        return self._formatTime(time.time() - self._start_time)
 
264
        return self._formatTime(self._delta_to_float(
 
265
            self._now() - self._start_datetime))
262
266
 
263
267
    def _testTimeString(self, testCase):
264
268
        benchmark_time = self._extractBenchmarkTime(testCase)
275
279
 
276
280
    def _shortened_test_description(self, test):
277
281
        what = test.id()
278
 
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
 
282
        what = re.sub(r'^bzrlib\.tests\.', '', what)
279
283
        return what
280
284
 
 
285
    # GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
 
286
    #                multiple times in a row, because the handler is added for
 
287
    #                each test but the container list is shared between cases.
 
288
    #                See lp:498869 lp:625574 and lp:637725 for background.
 
289
    def _record_traceback_from_test(self, exc_info):
 
290
        """Store the traceback from passed exc_info tuple till"""
 
291
        self._traceback_from_test = exc_info[2]
 
292
 
281
293
    def startTest(self, test):
282
 
        unittest.TestResult.startTest(self, test)
 
294
        super(ExtendedTestResult, self).startTest(test)
283
295
        if self.count == 0:
284
296
            self.startTests()
 
297
        self.count += 1
285
298
        self.report_test_start(test)
286
299
        test.number = self.count
287
300
        self._recordTestStartTime()
 
301
        # Make testtools cases give us the real traceback on failure
 
302
        addOnException = getattr(test, "addOnException", None)
 
303
        if addOnException is not None:
 
304
            addOnException(self._record_traceback_from_test)
 
305
        # Only check for thread leaks if the test case supports cleanups
 
306
        addCleanup = getattr(test, "addCleanup", None)
 
307
        if addCleanup is not None:
 
308
            addCleanup(self._check_leaked_threads, test)
288
309
 
289
310
    def startTests(self):
290
 
        import platform
291
 
        if getattr(sys, 'frozen', None) is None:
292
 
            bzr_path = osutils.realpath(sys.argv[0])
293
 
        else:
294
 
            bzr_path = sys.executable
295
 
        self.stream.write(
296
 
            'bzr selftest: %s\n' % (bzr_path,))
297
 
        self.stream.write(
298
 
            '   %s\n' % (
299
 
                    bzrlib.__path__[0],))
300
 
        self.stream.write(
301
 
            '   bzr-%s python-%s %s\n' % (
302
 
                    bzrlib.version_string,
303
 
                    bzrlib._format_version_tuple(sys.version_info),
304
 
                    platform.platform(aliased=1),
305
 
                    ))
306
 
        self.stream.write('\n')
 
311
        self.report_tests_starting()
 
312
        self._active_threads = threading.enumerate()
 
313
 
 
314
    def stopTest(self, test):
 
315
        self._traceback_from_test = None
 
316
 
 
317
    def _check_leaked_threads(self, test):
 
318
        """See if any threads have leaked since last call
 
319
 
 
320
        A sample of live threads is stored in the _active_threads attribute,
 
321
        when this method runs it compares the current live threads and any not
 
322
        in the previous sample are treated as having leaked.
 
323
        """
 
324
        now_active_threads = set(threading.enumerate())
 
325
        threads_leaked = now_active_threads.difference(self._active_threads)
 
326
        if threads_leaked:
 
327
            self._report_thread_leak(test, threads_leaked, now_active_threads)
 
328
            self._tests_leaking_threads_count += 1
 
329
            if self._first_thread_leaker_id is None:
 
330
                self._first_thread_leaker_id = test.id()
 
331
            self._active_threads = now_active_threads
307
332
 
308
333
    def _recordTestStartTime(self):
309
334
        """Record that a test has started."""
310
 
        self._start_time = time.time()
311
 
 
312
 
    def _cleanupLogFile(self, test):
313
 
        # We can only do this if we have one of our TestCases, not if
314
 
        # we have a doctest.
315
 
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
316
 
        if setKeepLogfile is not None:
317
 
            setKeepLogfile()
 
335
        self._start_datetime = self._now()
318
336
 
319
337
    def addError(self, test, err):
320
338
        """Tell result that test finished with an error.
322
340
        Called from the TestCase run() method when the test
323
341
        fails with an unexpected error.
324
342
        """
325
 
        self._post_mortem()
326
 
        unittest.TestResult.addError(self, test, err)
 
343
        self._post_mortem(self._traceback_from_test)
 
344
        super(ExtendedTestResult, self).addError(test, err)
327
345
        self.error_count += 1
328
346
        self.report_error(test, err)
329
347
        if self.stop_early:
330
348
            self.stop()
331
 
        self._cleanupLogFile(test)
332
349
 
333
350
    def addFailure(self, test, err):
334
351
        """Tell result that test failed.
336
353
        Called from the TestCase run() method when the test
337
354
        fails because e.g. an assert() method failed.
338
355
        """
339
 
        self._post_mortem()
340
 
        unittest.TestResult.addFailure(self, test, err)
 
356
        self._post_mortem(self._traceback_from_test)
 
357
        super(ExtendedTestResult, self).addFailure(test, err)
341
358
        self.failure_count += 1
342
359
        self.report_failure(test, err)
343
360
        if self.stop_early:
344
361
            self.stop()
345
 
        self._cleanupLogFile(test)
346
362
 
347
363
    def addSuccess(self, test, details=None):
348
364
        """Tell result that test completed successfully.
356
372
                    self._formatTime(benchmark_time),
357
373
                    test.id()))
358
374
        self.report_success(test)
359
 
        self._cleanupLogFile(test)
360
 
        unittest.TestResult.addSuccess(self, test)
 
375
        super(ExtendedTestResult, self).addSuccess(test)
361
376
        test._log_contents = ''
362
377
 
363
378
    def addExpectedFailure(self, test, err):
386
401
        self.not_applicable_count += 1
387
402
        self.report_not_applicable(test, reason)
388
403
 
389
 
    def _post_mortem(self):
 
404
    def _post_mortem(self, tb=None):
390
405
        """Start a PDB post mortem session."""
391
406
        if os.environ.get('BZR_TEST_PDB', None):
392
 
            import pdb;pdb.post_mortem()
 
407
            import pdb
 
408
            pdb.post_mortem(tb)
393
409
 
394
410
    def progress(self, offset, whence):
395
411
        """The test is adjusting the count of tests to run."""
400
416
        else:
401
417
            raise errors.BzrError("Unknown whence %r" % whence)
402
418
 
403
 
    def report_cleaning_up(self):
404
 
        pass
 
419
    def report_tests_starting(self):
 
420
        """Display information before the test run begins"""
 
421
        if getattr(sys, 'frozen', None) is None:
 
422
            bzr_path = osutils.realpath(sys.argv[0])
 
423
        else:
 
424
            bzr_path = sys.executable
 
425
        self.stream.write(
 
426
            'bzr selftest: %s\n' % (bzr_path,))
 
427
        self.stream.write(
 
428
            '   %s\n' % (
 
429
                    bzrlib.__path__[0],))
 
430
        self.stream.write(
 
431
            '   bzr-%s python-%s %s\n' % (
 
432
                    bzrlib.version_string,
 
433
                    bzrlib._format_version_tuple(sys.version_info),
 
434
                    platform.platform(aliased=1),
 
435
                    ))
 
436
        self.stream.write('\n')
 
437
 
 
438
    def report_test_start(self, test):
 
439
        """Display information on the test just about to be run"""
 
440
 
 
441
    def _report_thread_leak(self, test, leaked_threads, active_threads):
 
442
        """Display information on a test that leaked one or more threads"""
 
443
        # GZ 2010-09-09: A leak summary reported separately from the general
 
444
        #                thread debugging would be nice. Tests under subunit
 
445
        #                need something not using stream, perhaps adding a
 
446
        #                testtools details object would be fitting.
 
447
        if 'threads' in selftest_debug_flags:
 
448
            self.stream.write('%s is leaking, active is now %d\n' %
 
449
                (test.id(), len(active_threads)))
405
450
 
406
451
    def startTestRun(self):
407
452
        self.startTime = time.time()
444
489
        self.pb.finished()
445
490
        super(TextTestResult, self).stopTestRun()
446
491
 
447
 
    def startTestRun(self):
448
 
        super(TextTestResult, self).startTestRun()
 
492
    def report_tests_starting(self):
 
493
        super(TextTestResult, self).report_tests_starting()
449
494
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
450
495
 
451
 
    def printErrors(self):
452
 
        # clear the pb to make room for the error listing
453
 
        self.pb.clear()
454
 
        super(TextTestResult, self).printErrors()
455
 
 
456
496
    def _progress_prefix_text(self):
457
497
        # the longer this text, the less space we have to show the test
458
498
        # name...
480
520
        return a
481
521
 
482
522
    def report_test_start(self, test):
483
 
        self.count += 1
484
523
        self.pb.update(
485
524
                self._progress_prefix_text()
486
525
                + ' '
513
552
    def report_unsupported(self, test, feature):
514
553
        """test cannot be run because feature is missing."""
515
554
 
516
 
    def report_cleaning_up(self):
517
 
        self.pb.update('Cleaning up')
518
 
 
519
555
 
520
556
class VerboseTestResult(ExtendedTestResult):
521
557
    """Produce long output, with one line per test run plus times"""
528
564
            result = a_string
529
565
        return result.ljust(final_width)
530
566
 
531
 
    def startTestRun(self):
532
 
        super(VerboseTestResult, self).startTestRun()
 
567
    def report_tests_starting(self):
533
568
        self.stream.write('running %d tests...\n' % self.num_tests)
 
569
        super(VerboseTestResult, self).report_tests_starting()
534
570
 
535
571
    def report_test_start(self, test):
536
 
        self.count += 1
537
572
        name = self._shortened_test_description(test)
538
573
        width = osutils.terminal_width()
539
574
        if width is not None:
551
586
        return '%s%s' % (indent, err[1])
552
587
 
553
588
    def report_error(self, test, err):
554
 
        self.stream.writeln('ERROR %s\n%s'
 
589
        self.stream.write('ERROR %s\n%s\n'
555
590
                % (self._testTimeString(test),
556
591
                   self._error_summary(err)))
557
592
 
558
593
    def report_failure(self, test, err):
559
 
        self.stream.writeln(' FAIL %s\n%s'
 
594
        self.stream.write(' FAIL %s\n%s\n'
560
595
                % (self._testTimeString(test),
561
596
                   self._error_summary(err)))
562
597
 
563
598
    def report_known_failure(self, test, err):
564
 
        self.stream.writeln('XFAIL %s\n%s'
 
599
        self.stream.write('XFAIL %s\n%s\n'
565
600
                % (self._testTimeString(test),
566
601
                   self._error_summary(err)))
567
602
 
568
603
    def report_success(self, test):
569
 
        self.stream.writeln('   OK %s' % self._testTimeString(test))
 
604
        self.stream.write('   OK %s\n' % self._testTimeString(test))
570
605
        for bench_called, stats in getattr(test, '_benchcalls', []):
571
 
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
606
            self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
572
607
            stats.pprint(file=self.stream)
573
608
        # flush the stream so that we get smooth output. This verbose mode is
574
609
        # used to show the output in PQM.
575
610
        self.stream.flush()
576
611
 
577
612
    def report_skip(self, test, reason):
578
 
        self.stream.writeln(' SKIP %s\n%s'
 
613
        self.stream.write(' SKIP %s\n%s\n'
579
614
                % (self._testTimeString(test), reason))
580
615
 
581
616
    def report_not_applicable(self, test, reason):
582
 
        self.stream.writeln('  N/A %s\n    %s'
 
617
        self.stream.write('  N/A %s\n    %s\n'
583
618
                % (self._testTimeString(test), reason))
584
619
 
585
620
    def report_unsupported(self, test, feature):
586
621
        """test cannot be run because feature is missing."""
587
 
        self.stream.writeln("NODEP %s\n    The feature '%s' is not available."
 
622
        self.stream.write("NODEP %s\n    The feature '%s' is not available.\n"
588
623
                %(self._testTimeString(test), feature))
589
624
 
590
625
 
619
654
            encode = codec.encode
620
655
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
621
656
        stream.encoding = new_encoding
622
 
        self.stream = unittest._WritelnDecorator(stream)
 
657
        self.stream = stream
623
658
        self.descriptions = descriptions
624
659
        self.verbosity = verbosity
625
660
        self._bench_history = bench_history
749
784
    # XXX: Should probably unify more with CannedInputUIFactory or a
750
785
    # particular configuration of TextUIFactory, or otherwise have a clearer
751
786
    # idea of how they're supposed to be different.
752
 
    # See https://bugs.edge.launchpad.net/bzr/+bug/408213
 
787
    # See https://bugs.launchpad.net/bzr/+bug/408213
753
788
 
754
789
    def __init__(self, stdout=None, stderr=None, stdin=None):
755
790
        if stdin is not None:
789
824
    routine, and to build and check bzr trees.
790
825
 
791
826
    In addition to the usual method of overriding tearDown(), this class also
792
 
    allows subclasses to register functions into the _cleanups list, which is
 
827
    allows subclasses to register cleanup functions via addCleanup, which are
793
828
    run in order as the object is torn down.  It's less likely this will be
794
829
    accidentally overlooked.
795
830
    """
796
831
 
797
 
    _active_threads = None
798
 
    _leaking_threads_tests = 0
799
 
    _first_thread_leaker_id = None
800
 
    _log_file_name = None
 
832
    _log_file = None
801
833
    # record lsprof data when performing benchmark calls.
802
834
    _gather_lsprof_in_benchmarks = False
803
835
 
804
836
    def __init__(self, methodName='testMethod'):
805
837
        super(TestCase, self).__init__(methodName)
806
 
        self._cleanups = []
807
838
        self._directory_isolation = True
808
839
        self.exception_handlers.insert(0,
809
840
            (UnavailableFeature, self._do_unsupported_or_skip))
827
858
        self._track_transports()
828
859
        self._track_locks()
829
860
        self._clear_debug_flags()
830
 
        TestCase._active_threads = threading.activeCount()
831
 
        self.addCleanup(self._check_leaked_threads)
 
861
        # Isolate global verbosity level, to make sure it's reproducible
 
862
        # between tests.  We should get rid of this altogether: bug 656694. --
 
863
        # mbp 20101008
 
864
        self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
832
865
 
833
866
    def debug(self):
834
867
        # debug a frame up.
835
868
        import pdb
836
869
        pdb.Pdb().set_trace(sys._getframe().f_back)
837
870
 
838
 
    def _check_leaked_threads(self):
839
 
        active = threading.activeCount()
840
 
        leaked_threads = active - TestCase._active_threads
841
 
        TestCase._active_threads = active
842
 
        # If some tests make the number of threads *decrease*, we'll consider
843
 
        # that they are just observing old threads dieing, not agressively kill
844
 
        # random threads. So we don't report these tests as leaking. The risk
845
 
        # is that we have false positives that way (the test see 2 threads
846
 
        # going away but leak one) but it seems less likely than the actual
847
 
        # false positives (the test see threads going away and does not leak).
848
 
        if leaked_threads > 0:
849
 
            TestCase._leaking_threads_tests += 1
850
 
            if TestCase._first_thread_leaker_id is None:
851
 
                TestCase._first_thread_leaker_id = self.id()
 
871
    def discardDetail(self, name):
 
872
        """Extend the addDetail, getDetails api so we can remove a detail.
 
873
 
 
874
        eg. bzr always adds the 'log' detail at startup, but we don't want to
 
875
        include it for skipped, xfail, etc tests.
 
876
 
 
877
        It is safe to call this for a detail that doesn't exist, in case this
 
878
        gets called multiple times.
 
879
        """
 
880
        # We cheat. details is stored in __details which means we shouldn't
 
881
        # touch it. but getDetails() returns the dict directly, so we can
 
882
        # mutate it.
 
883
        details = self.getDetails()
 
884
        if name in details:
 
885
            del details[name]
852
886
 
853
887
    def _clear_debug_flags(self):
854
888
        """Prevent externally set debug flags affecting tests.
943
977
 
944
978
    def permit_dir(self, name):
945
979
        """Permit a directory to be used by this test. See permit_url."""
946
 
        name_transport = get_transport(name)
 
980
        name_transport = _mod_transport.get_transport(name)
947
981
        self.permit_url(name)
948
982
        self.permit_url(name_transport.base)
949
983
 
972
1006
            try:
973
1007
                workingtree.WorkingTree.open(path)
974
1008
            except (errors.NotBranchError, errors.NoWorkingTree):
975
 
                return
 
1009
                raise TestSkipped('Needs a working tree of bzr sources')
976
1010
        finally:
977
1011
            self.enable_directory_isolation()
978
1012
 
1028
1062
        self.addCleanup(transport_server.stop_server)
1029
1063
        # Obtain a real transport because if the server supplies a password, it
1030
1064
        # will be hidden from the base on the client side.
1031
 
        t = get_transport(transport_server.get_url())
 
1065
        t = _mod_transport.get_transport(transport_server.get_url())
1032
1066
        # Some transport servers effectively chroot the backing transport;
1033
1067
        # others like SFTPServer don't - users of the transport can walk up the
1034
1068
        # transport to read the entire backing transport. This wouldn't matter
1095
1129
            message += '\n'
1096
1130
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1097
1131
            % (message,
1098
 
               pformat(a), pformat(b)))
 
1132
               pprint.pformat(a), pprint.pformat(b)))
1099
1133
 
1100
1134
    assertEquals = assertEqual
1101
1135
 
1455
1489
 
1456
1490
        The file is removed as the test is torn down.
1457
1491
        """
1458
 
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
1459
 
        self._log_file = os.fdopen(fileno, 'w+')
 
1492
        self._log_file = StringIO()
1460
1493
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
1461
 
        self._log_file_name = name
1462
1494
        self.addCleanup(self._finishLogFile)
1463
1495
 
1464
1496
    def _finishLogFile(self):
1486
1518
        """
1487
1519
        debug.debug_flags.discard('strict_locks')
1488
1520
 
1489
 
    def addCleanup(self, callable, *args, **kwargs):
1490
 
        """Arrange to run a callable when this case is torn down.
1491
 
 
1492
 
        Callables are run in the reverse of the order they are registered,
1493
 
        ie last-in first-out.
1494
 
        """
1495
 
        self._cleanups.append((callable, args, kwargs))
1496
 
 
1497
1521
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1498
1522
        """Overrides an object attribute restoring it after the test.
1499
1523
 
1524
1548
            'EDITOR': None,
1525
1549
            'BZR_EMAIL': None,
1526
1550
            'BZREMAIL': None, # may still be present in the environment
1527
 
            'EMAIL': None,
 
1551
            'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
1528
1552
            'BZR_PROGRESS_BAR': None,
1529
1553
            'BZR_LOG': None,
1530
1554
            'BZR_PLUGIN_PATH': None,
1583
1607
        """This test has failed for some known reason."""
1584
1608
        raise KnownFailure(reason)
1585
1609
 
 
1610
    def _suppress_log(self):
 
1611
        """Remove the log info from details."""
 
1612
        self.discardDetail('log')
 
1613
 
1586
1614
    def _do_skip(self, result, reason):
 
1615
        self._suppress_log()
1587
1616
        addSkip = getattr(result, 'addSkip', None)
1588
1617
        if not callable(addSkip):
1589
1618
            result.addSuccess(result)
1592
1621
 
1593
1622
    @staticmethod
1594
1623
    def _do_known_failure(self, result, e):
 
1624
        self._suppress_log()
1595
1625
        err = sys.exc_info()
1596
1626
        addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1597
1627
        if addExpectedFailure is not None:
1605
1635
            reason = 'No reason given'
1606
1636
        else:
1607
1637
            reason = e.args[0]
 
1638
        self._suppress_log ()
1608
1639
        addNotApplicable = getattr(result, 'addNotApplicable', None)
1609
1640
        if addNotApplicable is not None:
1610
1641
            result.addNotApplicable(self, reason)
1612
1643
            self._do_skip(result, reason)
1613
1644
 
1614
1645
    @staticmethod
 
1646
    def _report_skip(self, result, err):
 
1647
        """Override the default _report_skip.
 
1648
 
 
1649
        We want to strip the 'log' detail. If we waint until _do_skip, it has
 
1650
        already been formatted into the 'reason' string, and we can't pull it
 
1651
        out again.
 
1652
        """
 
1653
        self._suppress_log()
 
1654
        super(TestCase, self)._report_skip(self, result, err)
 
1655
 
 
1656
    @staticmethod
 
1657
    def _report_expected_failure(self, result, err):
 
1658
        """Strip the log.
 
1659
 
 
1660
        See _report_skip for motivation.
 
1661
        """
 
1662
        self._suppress_log()
 
1663
        super(TestCase, self)._report_expected_failure(self, result, err)
 
1664
 
 
1665
    @staticmethod
1615
1666
    def _do_unsupported_or_skip(self, result, e):
1616
1667
        reason = e.args[0]
 
1668
        self._suppress_log()
1617
1669
        addNotSupported = getattr(result, 'addNotSupported', None)
1618
1670
        if addNotSupported is not None:
1619
1671
            result.addNotSupported(self, reason)
1666
1718
                unicodestr = self._log_contents.decode('utf8', 'replace')
1667
1719
                self._log_contents = unicodestr.encode('utf8')
1668
1720
            return self._log_contents
1669
 
        import bzrlib.trace
1670
 
        if bzrlib.trace._trace_file:
1671
 
            # flush the log file, to get all content
1672
 
            bzrlib.trace._trace_file.flush()
1673
 
        if self._log_file_name is not None:
1674
 
            logfile = open(self._log_file_name)
1675
 
            try:
1676
 
                log_contents = logfile.read()
1677
 
            finally:
1678
 
                logfile.close()
 
1721
        if self._log_file is not None:
 
1722
            log_contents = self._log_file.getvalue()
1679
1723
            try:
1680
1724
                log_contents.decode('utf8')
1681
1725
            except UnicodeDecodeError:
1682
1726
                unicodestr = log_contents.decode('utf8', 'replace')
1683
1727
                log_contents = unicodestr.encode('utf8')
1684
1728
            if not keep_log_file:
1685
 
                close_attempts = 0
1686
 
                max_close_attempts = 100
1687
 
                first_close_error = None
1688
 
                while close_attempts < max_close_attempts:
1689
 
                    close_attempts += 1
1690
 
                    try:
1691
 
                        self._log_file.close()
1692
 
                    except IOError, ioe:
1693
 
                        if ioe.errno is None:
1694
 
                            # No errno implies 'close() called during
1695
 
                            # concurrent operation on the same file object', so
1696
 
                            # retry.  Probably a thread is trying to write to
1697
 
                            # the log file.
1698
 
                            if first_close_error is None:
1699
 
                                first_close_error = ioe
1700
 
                            continue
1701
 
                        raise
1702
 
                    else:
1703
 
                        break
1704
 
                if close_attempts > 1:
1705
 
                    sys.stderr.write(
1706
 
                        'Unable to close log file on first attempt, '
1707
 
                        'will retry: %s\n' % (first_close_error,))
1708
 
                    if close_attempts == max_close_attempts:
1709
 
                        sys.stderr.write(
1710
 
                            'Unable to close log file after %d attempts.\n'
1711
 
                            % (max_close_attempts,))
1712
1729
                self._log_file = None
1713
1730
                # Permit multiple calls to get_log until we clean it up in
1714
1731
                # finishLogFile
1715
1732
                self._log_contents = log_contents
1716
 
                try:
1717
 
                    os.remove(self._log_file_name)
1718
 
                except OSError, e:
1719
 
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
1720
 
                        sys.stderr.write(('Unable to delete log file '
1721
 
                                             ' %r\n' % self._log_file_name))
1722
 
                    else:
1723
 
                        raise
1724
 
                self._log_file_name = None
1725
1733
            return log_contents
1726
1734
        else:
1727
 
            return "No log file content and no log file name."
 
1735
            return "No log file content."
1728
1736
 
1729
1737
    def get_log(self):
1730
1738
        """Get a unicode string containing the log from bzrlib.trace.
1945
1953
            variables. A value of None will unset the env variable.
1946
1954
            The values must be strings. The change will only occur in the
1947
1955
            child, so you don't need to fix the environment after running.
1948
 
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
1949
 
            is not available.
 
1956
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
 
1957
            doesn't support signalling subprocesses.
1950
1958
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
1951
1959
 
1952
1960
        :returns: Popen object for the started process.
1953
1961
        """
1954
1962
        if skip_if_plan_to_signal:
1955
 
            if not getattr(os, 'kill', None):
1956
 
                raise TestSkipped("os.kill not available.")
 
1963
            if os.name != "posix":
 
1964
                raise TestSkipped("Sending signals not supported")
1957
1965
 
1958
1966
        if env_changes is None:
1959
1967
            env_changes = {}
1986
1994
            if not allow_plugins:
1987
1995
                command.append('--no-plugins')
1988
1996
            command.extend(process_args)
1989
 
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
 
1997
            process = self._popen(command, stdin=subprocess.PIPE,
 
1998
                                  stdout=subprocess.PIPE,
 
1999
                                  stderr=subprocess.PIPE)
1990
2000
        finally:
1991
2001
            restore_environment()
1992
2002
            if cwd is not None:
2000
2010
        Allows tests to override this method to intercept the calls made to
2001
2011
        Popen for introspection.
2002
2012
        """
2003
 
        return Popen(*args, **kwargs)
 
2013
        return subprocess.Popen(*args, **kwargs)
2004
2014
 
2005
2015
    def get_source_path(self):
2006
2016
        """Return the path of the directory containing bzrlib."""
2008
2018
 
2009
2019
    def get_bzr_path(self):
2010
2020
        """Return the path of the 'bzr' executable for this test suite."""
2011
 
        bzr_path = self.get_source_path()+'/bzr'
 
2021
        bzr_path = os.path.join(self.get_source_path(), "bzr")
2012
2022
        if not os.path.isfile(bzr_path):
2013
2023
            # We are probably installed. Assume sys.argv is the right file
2014
2024
            bzr_path = sys.argv[0]
2186
2196
 
2187
2197
        :param relpath: a path relative to the base url.
2188
2198
        """
2189
 
        t = get_transport(self.get_url(relpath))
 
2199
        t = _mod_transport.get_transport(self.get_url(relpath))
2190
2200
        self.assertFalse(t.is_readonly())
2191
2201
        return t
2192
2202
 
2198
2208
 
2199
2209
        :param relpath: a path relative to the base url.
2200
2210
        """
2201
 
        t = get_transport(self.get_readonly_url(relpath))
 
2211
        t = _mod_transport.get_transport(self.get_readonly_url(relpath))
2202
2212
        self.assertTrue(t.is_readonly())
2203
2213
        return t
2204
2214
 
2334
2344
        propagating. This method ensures than a test did not leaked.
2335
2345
        """
2336
2346
        root = TestCaseWithMemoryTransport.TEST_ROOT
2337
 
        self.permit_url(get_transport(root).base)
 
2347
        self.permit_url(_mod_transport.get_transport(root).base)
2338
2348
        wt = workingtree.WorkingTree.open(root)
2339
2349
        last_rev = wt.last_revision()
2340
2350
        if last_rev != 'null:':
2385
2395
            # might be a relative or absolute path
2386
2396
            maybe_a_url = self.get_url(relpath)
2387
2397
            segments = maybe_a_url.rsplit('/', 1)
2388
 
            t = get_transport(maybe_a_url)
 
2398
            t = _mod_transport.get_transport(maybe_a_url)
2389
2399
            if len(segments) > 1 and segments[-1] not in ('', '.'):
2390
2400
                t.ensure_base()
2391
2401
            if format is None:
2408
2418
        made_control = self.make_bzrdir(relpath, format=format)
2409
2419
        return made_control.create_repository(shared=shared)
2410
2420
 
2411
 
    def make_smart_server(self, path):
 
2421
    def make_smart_server(self, path, backing_server=None):
 
2422
        if backing_server is None:
 
2423
            backing_server = self.get_server()
2412
2424
        smart_server = test_server.SmartTCPServer_for_testing()
2413
 
        self.start_server(smart_server, self.get_server())
2414
 
        remote_transport = get_transport(smart_server.get_url()).clone(path)
 
2425
        self.start_server(smart_server, backing_server)
 
2426
        remote_transport = _mod_transport.get_transport(smart_server.get_url()
 
2427
                                                   ).clone(path)
2415
2428
        return remote_transport
2416
2429
 
2417
2430
    def make_branch_and_memory_tree(self, relpath, format=None):
2432
2445
 
2433
2446
    def setUp(self):
2434
2447
        super(TestCaseWithMemoryTransport, self).setUp()
 
2448
        # Ensure that ConnectedTransport doesn't leak sockets
 
2449
        def get_transport_with_cleanup(*args, **kwargs):
 
2450
            t = orig_get_transport(*args, **kwargs)
 
2451
            if isinstance(t, _mod_transport.ConnectedTransport):
 
2452
                self.addCleanup(t.disconnect)
 
2453
            return t
 
2454
 
 
2455
        orig_get_transport = self.overrideAttr(_mod_transport, 'get_transport',
 
2456
                                               get_transport_with_cleanup)
2435
2457
        self._make_test_root()
2436
2458
        self.addCleanup(os.chdir, os.getcwdu())
2437
2459
        self.makeAndChdirToTestDir()
2482
2504
 
2483
2505
    def check_file_contents(self, filename, expect):
2484
2506
        self.log("check contents of file %s" % filename)
2485
 
        contents = file(filename, 'r').read()
 
2507
        f = file(filename)
 
2508
        try:
 
2509
            contents = f.read()
 
2510
        finally:
 
2511
            f.close()
2486
2512
        if contents != expect:
2487
2513
            self.log("expected: %r" % expect)
2488
2514
            self.log("actually: %r" % contents)
2562
2588
                "a list or a tuple. Got %r instead" % (shape,))
2563
2589
        # It's OK to just create them using forward slashes on windows.
2564
2590
        if transport is None or transport.is_readonly():
2565
 
            transport = get_transport(".")
 
2591
            transport = _mod_transport.get_transport(".")
2566
2592
        for name in shape:
2567
2593
            self.assertIsInstance(name, basestring)
2568
2594
            if name[-1] == '/':
2725
2751
    """
2726
2752
 
2727
2753
    def setUp(self):
 
2754
        from bzrlib.tests import http_server
2728
2755
        super(ChrootedTestCase, self).setUp()
2729
2756
        if not self.vfs_transport_factory == memory.MemoryServer:
2730
 
            self.transport_readonly_server = HttpServer
 
2757
            self.transport_readonly_server = http_server.HttpServer
2731
2758
 
2732
2759
 
2733
2760
def condition_id_re(pattern):
2736
2763
    :param pattern: A regular expression string.
2737
2764
    :return: A callable that returns True if the re matches.
2738
2765
    """
2739
 
    filter_re = osutils.re_compile_checked(pattern, 0,
2740
 
        'test filter')
 
2766
    filter_re = re.compile(pattern, 0)
2741
2767
    def condition(test):
2742
2768
        test_id = test.id()
2743
2769
        return filter_re.search(test_id)
2995
3021
 
2996
3022
 
2997
3023
def fork_decorator(suite):
 
3024
    if getattr(os, "fork", None) is None:
 
3025
        raise errors.BzrCommandError("platform does not support fork,"
 
3026
            " try --parallel=subprocess instead.")
2998
3027
    concurrency = osutils.local_concurrency()
2999
3028
    if concurrency == 1:
3000
3029
        return suite
3055
3084
    return suite
3056
3085
 
3057
3086
 
3058
 
class TestDecorator(TestSuite):
 
3087
class TestDecorator(TestUtil.TestSuite):
3059
3088
    """A decorator for TestCase/TestSuite objects.
3060
3089
    
3061
3090
    Usually, subclasses should override __iter__(used when flattening test
3064
3093
    """
3065
3094
 
3066
3095
    def __init__(self, suite):
3067
 
        TestSuite.__init__(self)
 
3096
        TestUtil.TestSuite.__init__(self)
3068
3097
        self.addTest(suite)
3069
3098
 
3070
3099
    def countTestCases(self):
3189
3218
 
3190
3219
def partition_tests(suite, count):
3191
3220
    """Partition suite into count lists of tests."""
3192
 
    result = []
3193
 
    tests = list(iter_suite_tests(suite))
3194
 
    tests_per_process = int(math.ceil(float(len(tests)) / count))
3195
 
    for block in range(count):
3196
 
        low_test = block * tests_per_process
3197
 
        high_test = low_test + tests_per_process
3198
 
        process_tests = tests[low_test:high_test]
3199
 
        result.append(process_tests)
3200
 
    return result
 
3221
    # This just assigns tests in a round-robin fashion.  On one hand this
 
3222
    # splits up blocks of related tests that might run faster if they shared
 
3223
    # resources, but on the other it avoids assigning blocks of slow tests to
 
3224
    # just one partition.  So the slowest partition shouldn't be much slower
 
3225
    # than the fastest.
 
3226
    partitions = [list() for i in range(count)]
 
3227
    tests = iter_suite_tests(suite)
 
3228
    for partition, test in itertools.izip(itertools.cycle(partitions), tests):
 
3229
        partition.append(test)
 
3230
    return partitions
3201
3231
 
3202
3232
 
3203
3233
def workaround_zealous_crypto_random():
3237
3267
 
3238
3268
    test_blocks = partition_tests(suite, concurrency)
3239
3269
    for process_tests in test_blocks:
3240
 
        process_suite = TestSuite()
 
3270
        process_suite = TestUtil.TestSuite()
3241
3271
        process_suite.addTests(process_tests)
3242
3272
        c2pread, c2pwrite = os.pipe()
3243
3273
        pid = os.fork()
3309
3339
                '--subunit']
3310
3340
            if '--no-plugins' in sys.argv:
3311
3341
                argv.append('--no-plugins')
3312
 
            # stderr=STDOUT would be ideal, but until we prevent noise on
3313
 
            # stderr it can interrupt the subunit protocol.
3314
 
            process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
3315
 
                bufsize=1)
 
3342
            # stderr=subprocess.STDOUT would be ideal, but until we prevent
 
3343
            # noise on stderr it can interrupt the subunit protocol.
 
3344
            process = subprocess.Popen(argv, stdin=subprocess.PIPE,
 
3345
                                      stdout=subprocess.PIPE,
 
3346
                                      stderr=subprocess.PIPE,
 
3347
                                      bufsize=1)
3316
3348
            test = TestInSubprocess(process, test_list_file_name)
3317
3349
            result.append(test)
3318
3350
        except:
3367
3399
 
3368
3400
    def startTest(self, test):
3369
3401
        self.profiler = bzrlib.lsprof.BzrProfiler()
 
3402
        # Prevent deadlocks in tests that use lsprof: those tests will
 
3403
        # unavoidably fail.
 
3404
        bzrlib.lsprof.BzrProfiler.profiler_block = 0
3370
3405
        self.profiler.start()
3371
3406
        ForwardingResult.startTest(self, test)
3372
3407
 
3393
3428
#                           rather than failing tests. And no longer raise
3394
3429
#                           LockContention when fctnl locks are not being used
3395
3430
#                           with proper exclusion rules.
 
3431
#   -Ethreads               Will display thread ident at creation/join time to
 
3432
#                           help track thread leaks
3396
3433
selftest_debug_flags = set()
3397
3434
 
3398
3435
 
3631
3668
        'bzrlib.doc',
3632
3669
        'bzrlib.tests.blackbox',
3633
3670
        'bzrlib.tests.commands',
 
3671
        'bzrlib.tests.doc_generate',
3634
3672
        'bzrlib.tests.per_branch',
3635
3673
        'bzrlib.tests.per_bzrdir',
3636
 
        'bzrlib.tests.per_bzrdir_colo',
 
3674
        'bzrlib.tests.per_controldir',
 
3675
        'bzrlib.tests.per_controldir_colo',
3637
3676
        'bzrlib.tests.per_foreign_vcs',
3638
3677
        'bzrlib.tests.per_interrepository',
3639
3678
        'bzrlib.tests.per_intertree',
3652
3691
        'bzrlib.tests.per_workingtree',
3653
3692
        'bzrlib.tests.test__annotator',
3654
3693
        'bzrlib.tests.test__bencode',
 
3694
        'bzrlib.tests.test__btree_serializer',
3655
3695
        'bzrlib.tests.test__chk_map',
3656
3696
        'bzrlib.tests.test__dirstate_helpers',
3657
3697
        'bzrlib.tests.test__groupcompress',
3700
3740
        'bzrlib.tests.test_export',
3701
3741
        'bzrlib.tests.test_extract',
3702
3742
        'bzrlib.tests.test_fetch',
 
3743
        'bzrlib.tests.test_fixtures',
3703
3744
        'bzrlib.tests.test_fifo_cache',
3704
3745
        'bzrlib.tests.test_filters',
3705
3746
        'bzrlib.tests.test_ftp_transport',
3726
3767
        'bzrlib.tests.test_knit',
3727
3768
        'bzrlib.tests.test_lazy_import',
3728
3769
        'bzrlib.tests.test_lazy_regex',
 
3770
        'bzrlib.tests.test_library_state',
3729
3771
        'bzrlib.tests.test_lock',
3730
3772
        'bzrlib.tests.test_lockable_files',
3731
3773
        'bzrlib.tests.test_lockdir',
3733
3775
        'bzrlib.tests.test_lru_cache',
3734
3776
        'bzrlib.tests.test_lsprof',
3735
3777
        'bzrlib.tests.test_mail_client',
 
3778
        'bzrlib.tests.test_matchers',
3736
3779
        'bzrlib.tests.test_memorytree',
3737
3780
        'bzrlib.tests.test_merge',
3738
3781
        'bzrlib.tests.test_merge3',
3787
3830
        'bzrlib.tests.test_switch',
3788
3831
        'bzrlib.tests.test_symbol_versioning',
3789
3832
        'bzrlib.tests.test_tag',
 
3833
        'bzrlib.tests.test_test_server',
3790
3834
        'bzrlib.tests.test_testament',
3791
3835
        'bzrlib.tests.test_textfile',
3792
3836
        'bzrlib.tests.test_textmerge',
3798
3842
        'bzrlib.tests.test_transport_log',
3799
3843
        'bzrlib.tests.test_tree',
3800
3844
        'bzrlib.tests.test_treebuilder',
 
3845
        'bzrlib.tests.test_treeshape',
3801
3846
        'bzrlib.tests.test_tsort',
3802
3847
        'bzrlib.tests.test_tuned_gzip',
3803
3848
        'bzrlib.tests.test_ui',
3807
3852
        'bzrlib.tests.test_urlutils',
3808
3853
        'bzrlib.tests.test_version',
3809
3854
        'bzrlib.tests.test_version_info',
 
3855
        'bzrlib.tests.test_versionedfile',
3810
3856
        'bzrlib.tests.test_weave',
3811
3857
        'bzrlib.tests.test_whitebox',
3812
3858
        'bzrlib.tests.test_win32utils',
3834
3880
        'bzrlib.option',
3835
3881
        'bzrlib.symbol_versioning',
3836
3882
        'bzrlib.tests',
 
3883
        'bzrlib.tests.fixtures',
3837
3884
        'bzrlib.timestamp',
3838
3885
        'bzrlib.version_info_formats.format_custom',
3839
3886
        ]
3980
4027
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
3981
4028
    ...     [('one', dict(param=1)),
3982
4029
    ...      ('two', dict(param=2))],
3983
 
    ...     TestSuite())
 
4030
    ...     TestUtil.TestSuite())
3984
4031
    >>> tests = list(iter_suite_tests(r))
3985
4032
    >>> len(tests)
3986
4033
    2
4033
4080
    :param new_id: The id to assign to it.
4034
4081
    :return: The new test.
4035
4082
    """
4036
 
    new_test = copy(test)
 
4083
    new_test = copy.copy(test)
4037
4084
    new_test.id = lambda: new_id
 
4085
    # XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
 
4086
    # causes cloned tests to share the 'details' dict.  This makes it hard to
 
4087
    # read the test output for parameterized tests, because tracebacks will be
 
4088
    # associated with irrelevant tests.
 
4089
    try:
 
4090
        details = new_test._TestCase__details
 
4091
    except AttributeError:
 
4092
        # must be a different version of testtools than expected.  Do nothing.
 
4093
        pass
 
4094
    else:
 
4095
        # Reset the '__details' dict.
 
4096
        new_test._TestCase__details = {}
4038
4097
    return new_test
4039
4098
 
4040
4099
 
4100
4159
        if test_id != None:
4101
4160
            ui.ui_factory.clear_term()
4102
4161
            sys.stderr.write('\nWhile running: %s\n' % (test_id,))
 
4162
        # Ugly, but the last thing we want here is fail, so bear with it.
 
4163
        printable_e = str(e).decode(osutils.get_user_encoding(), 'replace'
 
4164
                                    ).encode('ascii', 'replace')
4103
4165
        sys.stderr.write('Unable to remove testing dir %s\n%s'
4104
 
                         % (os.path.basename(dirname), e))
 
4166
                         % (os.path.basename(dirname), printable_e))
4105
4167
 
4106
4168
 
4107
4169
class Feature(object):
4337
4399
UnicodeFilename = _UnicodeFilename()
4338
4400
 
4339
4401
 
 
4402
class _ByteStringNamedFilesystem(Feature):
 
4403
    """Is the filesystem based on bytes?"""
 
4404
 
 
4405
    def _probe(self):
 
4406
        if os.name == "posix":
 
4407
            return True
 
4408
        return False
 
4409
 
 
4410
ByteStringNamedFilesystem = _ByteStringNamedFilesystem()
 
4411
 
 
4412
 
4340
4413
class _UTF8Filesystem(Feature):
4341
4414
    """Is the filesystem UTF-8?"""
4342
4415
 
4452
4525
try:
4453
4526
    from subunit import TestProtocolClient
4454
4527
    from subunit.test_results import AutoTimingTestResultDecorator
 
4528
    class SubUnitBzrProtocolClient(TestProtocolClient):
 
4529
 
 
4530
        def addSuccess(self, test, details=None):
 
4531
            # The subunit client always includes the details in the subunit
 
4532
            # stream, but we don't want to include it in ours.
 
4533
            if details is not None and 'log' in details:
 
4534
                del details['log']
 
4535
            return super(SubUnitBzrProtocolClient, self).addSuccess(
 
4536
                test, details)
 
4537
 
4455
4538
    class SubUnitBzrRunner(TextTestRunner):
4456
4539
        def run(self, test):
4457
4540
            result = AutoTimingTestResultDecorator(
4458
 
                TestProtocolClient(self.stream))
 
4541
                SubUnitBzrProtocolClient(self.stream))
4459
4542
            test.run(result)
4460
4543
            return result
4461
4544
except ImportError: