/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: Canonical.com Patch Queue Manager
  • Date: 2010-09-29 22:03:03 UTC
  • mfrom: (5416.2.6 jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20100929220303-cr95h8iwtggco721
(mbp) Add 'break-lock --force'

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,
 
114
    treeshape,
115
115
    )
116
 
from bzrlib.tests.http_server import HttpServer
117
 
from bzrlib.tests.TestUtil import (
118
 
                          TestSuite,
119
 
                          TestLoader,
120
 
                          )
121
 
from bzrlib.tests.treeshape import build_tree_contents
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
198
 
199
199
    def stopTestRun(self):
200
200
        run = self.testsRun
201
201
        actionTaken = "Ran"
202
202
        stopTime = time.time()
203
203
        timeTaken = stopTime - self.startTime
204
 
        self.printErrors()
205
 
        self.stream.writeln(self.separator2)
206
 
        self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
 
204
        # GZ 2010-07-19: Seems testtools has no printErrors method, and though
 
205
        #                the parent class method is similar have to duplicate
 
206
        self._show_list('ERROR', self.errors)
 
207
        self._show_list('FAIL', self.failures)
 
208
        self.stream.write(self.sep2)
 
209
        self.stream.write("%s %d test%s in %.3fs\n\n" % (actionTaken,
207
210
                            run, run != 1 and "s" or "", timeTaken))
208
 
        self.stream.writeln()
209
211
        if not self.wasSuccessful():
210
212
            self.stream.write("FAILED (")
211
213
            failed, errored = map(len, (self.failures, self.errors))
218
220
                if failed or errored: self.stream.write(", ")
219
221
                self.stream.write("known_failure_count=%d" %
220
222
                    self.known_failure_count)
221
 
            self.stream.writeln(")")
 
223
            self.stream.write(")\n")
222
224
        else:
223
225
            if self.known_failure_count:
224
 
                self.stream.writeln("OK (known_failures=%d)" %
 
226
                self.stream.write("OK (known_failures=%d)\n" %
225
227
                    self.known_failure_count)
226
228
            else:
227
 
                self.stream.writeln("OK")
 
229
                self.stream.write("OK\n")
228
230
        if self.skip_count > 0:
229
231
            skipped = self.skip_count
230
 
            self.stream.writeln('%d test%s skipped' %
 
232
            self.stream.write('%d test%s skipped\n' %
231
233
                                (skipped, skipped != 1 and "s" or ""))
232
234
        if self.unsupported:
233
235
            for feature, count in sorted(self.unsupported.items()):
234
 
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
 
236
                self.stream.write("Missing feature '%s' skipped %d tests.\n" %
235
237
                    (feature, count))
236
238
        if self._strict:
237
239
            ok = self.wasStrictlySuccessful()
238
240
        else:
239
241
            ok = self.wasSuccessful()
240
 
        if TestCase._first_thread_leaker_id:
 
242
        if self._first_thread_leaker_id:
241
243
            self.stream.write(
242
244
                '%s is leaking threads among %d leaking tests.\n' % (
243
 
                TestCase._first_thread_leaker_id,
244
 
                TestCase._leaking_threads_tests))
 
245
                self._first_thread_leaker_id,
 
246
                self._tests_leaking_threads_count))
245
247
            # We don't report the main thread as an active one.
246
248
            self.stream.write(
247
249
                '%d non-main threads were left active in the end.\n'
248
 
                % (TestCase._active_threads - 1))
 
250
                % (len(self._active_threads) - 1))
249
251
 
250
252
    def getDescription(self, test):
251
253
        return test.id()
275
277
 
276
278
    def _shortened_test_description(self, test):
277
279
        what = test.id()
278
 
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
 
280
        what = re.sub(r'^bzrlib\.tests\.', '', what)
279
281
        return what
280
282
 
281
283
    def startTest(self, test):
282
 
        unittest.TestResult.startTest(self, test)
 
284
        super(ExtendedTestResult, self).startTest(test)
283
285
        if self.count == 0:
284
286
            self.startTests()
 
287
        self.count += 1
285
288
        self.report_test_start(test)
286
289
        test.number = self.count
287
290
        self._recordTestStartTime()
 
291
        # Only check for thread leaks if the test case supports cleanups
 
292
        addCleanup = getattr(test, "addCleanup", None)
 
293
        if addCleanup is not None:
 
294
            addCleanup(self._check_leaked_threads, test)
288
295
 
289
296
    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')
 
297
        self.report_tests_starting()
 
298
        self._active_threads = threading.enumerate()
 
299
 
 
300
    def _check_leaked_threads(self, test):
 
301
        """See if any threads have leaked since last call
 
302
 
 
303
        A sample of live threads is stored in the _active_threads attribute,
 
304
        when this method runs it compares the current live threads and any not
 
305
        in the previous sample are treated as having leaked.
 
306
        """
 
307
        now_active_threads = set(threading.enumerate())
 
308
        threads_leaked = now_active_threads.difference(self._active_threads)
 
309
        if threads_leaked:
 
310
            self._report_thread_leak(test, threads_leaked, now_active_threads)
 
311
            self._tests_leaking_threads_count += 1
 
312
            if self._first_thread_leaker_id is None:
 
313
                self._first_thread_leaker_id = test.id()
 
314
            self._active_threads = now_active_threads
307
315
 
308
316
    def _recordTestStartTime(self):
309
317
        """Record that a test has started."""
310
318
        self._start_time = time.time()
311
319
 
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()
318
 
 
319
320
    def addError(self, test, err):
320
321
        """Tell result that test finished with an error.
321
322
 
323
324
        fails with an unexpected error.
324
325
        """
325
326
        self._post_mortem()
326
 
        unittest.TestResult.addError(self, test, err)
 
327
        super(ExtendedTestResult, self).addError(test, err)
327
328
        self.error_count += 1
328
329
        self.report_error(test, err)
329
330
        if self.stop_early:
330
331
            self.stop()
331
 
        self._cleanupLogFile(test)
332
332
 
333
333
    def addFailure(self, test, err):
334
334
        """Tell result that test failed.
337
337
        fails because e.g. an assert() method failed.
338
338
        """
339
339
        self._post_mortem()
340
 
        unittest.TestResult.addFailure(self, test, err)
 
340
        super(ExtendedTestResult, self).addFailure(test, err)
341
341
        self.failure_count += 1
342
342
        self.report_failure(test, err)
343
343
        if self.stop_early:
344
344
            self.stop()
345
 
        self._cleanupLogFile(test)
346
345
 
347
346
    def addSuccess(self, test, details=None):
348
347
        """Tell result that test completed successfully.
356
355
                    self._formatTime(benchmark_time),
357
356
                    test.id()))
358
357
        self.report_success(test)
359
 
        self._cleanupLogFile(test)
360
 
        unittest.TestResult.addSuccess(self, test)
 
358
        super(ExtendedTestResult, self).addSuccess(test)
361
359
        test._log_contents = ''
362
360
 
363
361
    def addExpectedFailure(self, test, err):
400
398
        else:
401
399
            raise errors.BzrError("Unknown whence %r" % whence)
402
400
 
403
 
    def report_cleaning_up(self):
404
 
        pass
 
401
    def report_tests_starting(self):
 
402
        """Display information before the test run begins"""
 
403
        if getattr(sys, 'frozen', None) is None:
 
404
            bzr_path = osutils.realpath(sys.argv[0])
 
405
        else:
 
406
            bzr_path = sys.executable
 
407
        self.stream.write(
 
408
            'bzr selftest: %s\n' % (bzr_path,))
 
409
        self.stream.write(
 
410
            '   %s\n' % (
 
411
                    bzrlib.__path__[0],))
 
412
        self.stream.write(
 
413
            '   bzr-%s python-%s %s\n' % (
 
414
                    bzrlib.version_string,
 
415
                    bzrlib._format_version_tuple(sys.version_info),
 
416
                    platform.platform(aliased=1),
 
417
                    ))
 
418
        self.stream.write('\n')
 
419
 
 
420
    def report_test_start(self, test):
 
421
        """Display information on the test just about to be run"""
 
422
 
 
423
    def _report_thread_leak(self, test, leaked_threads, active_threads):
 
424
        """Display information on a test that leaked one or more threads"""
 
425
        # GZ 2010-09-09: A leak summary reported separately from the general
 
426
        #                thread debugging would be nice. Tests under subunit
 
427
        #                need something not using stream, perhaps adding a
 
428
        #                testtools details object would be fitting.
 
429
        if 'threads' in selftest_debug_flags:
 
430
            self.stream.write('%s is leaking, active is now %d\n' %
 
431
                (test.id(), len(active_threads)))
405
432
 
406
433
    def startTestRun(self):
407
434
        self.startTime = time.time()
444
471
        self.pb.finished()
445
472
        super(TextTestResult, self).stopTestRun()
446
473
 
447
 
    def startTestRun(self):
448
 
        super(TextTestResult, self).startTestRun()
 
474
    def report_tests_starting(self):
 
475
        super(TextTestResult, self).report_tests_starting()
449
476
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
450
477
 
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
478
    def _progress_prefix_text(self):
457
479
        # the longer this text, the less space we have to show the test
458
480
        # name...
480
502
        return a
481
503
 
482
504
    def report_test_start(self, test):
483
 
        self.count += 1
484
505
        self.pb.update(
485
506
                self._progress_prefix_text()
486
507
                + ' '
513
534
    def report_unsupported(self, test, feature):
514
535
        """test cannot be run because feature is missing."""
515
536
 
516
 
    def report_cleaning_up(self):
517
 
        self.pb.update('Cleaning up')
518
 
 
519
537
 
520
538
class VerboseTestResult(ExtendedTestResult):
521
539
    """Produce long output, with one line per test run plus times"""
528
546
            result = a_string
529
547
        return result.ljust(final_width)
530
548
 
531
 
    def startTestRun(self):
532
 
        super(VerboseTestResult, self).startTestRun()
 
549
    def report_tests_starting(self):
533
550
        self.stream.write('running %d tests...\n' % self.num_tests)
 
551
        super(VerboseTestResult, self).report_tests_starting()
534
552
 
535
553
    def report_test_start(self, test):
536
 
        self.count += 1
537
554
        name = self._shortened_test_description(test)
538
555
        width = osutils.terminal_width()
539
556
        if width is not None:
551
568
        return '%s%s' % (indent, err[1])
552
569
 
553
570
    def report_error(self, test, err):
554
 
        self.stream.writeln('ERROR %s\n%s'
 
571
        self.stream.write('ERROR %s\n%s\n'
555
572
                % (self._testTimeString(test),
556
573
                   self._error_summary(err)))
557
574
 
558
575
    def report_failure(self, test, err):
559
 
        self.stream.writeln(' FAIL %s\n%s'
 
576
        self.stream.write(' FAIL %s\n%s\n'
560
577
                % (self._testTimeString(test),
561
578
                   self._error_summary(err)))
562
579
 
563
580
    def report_known_failure(self, test, err):
564
 
        self.stream.writeln('XFAIL %s\n%s'
 
581
        self.stream.write('XFAIL %s\n%s\n'
565
582
                % (self._testTimeString(test),
566
583
                   self._error_summary(err)))
567
584
 
568
585
    def report_success(self, test):
569
 
        self.stream.writeln('   OK %s' % self._testTimeString(test))
 
586
        self.stream.write('   OK %s\n' % self._testTimeString(test))
570
587
        for bench_called, stats in getattr(test, '_benchcalls', []):
571
 
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
588
            self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
572
589
            stats.pprint(file=self.stream)
573
590
        # flush the stream so that we get smooth output. This verbose mode is
574
591
        # used to show the output in PQM.
575
592
        self.stream.flush()
576
593
 
577
594
    def report_skip(self, test, reason):
578
 
        self.stream.writeln(' SKIP %s\n%s'
 
595
        self.stream.write(' SKIP %s\n%s\n'
579
596
                % (self._testTimeString(test), reason))
580
597
 
581
598
    def report_not_applicable(self, test, reason):
582
 
        self.stream.writeln('  N/A %s\n    %s'
 
599
        self.stream.write('  N/A %s\n    %s\n'
583
600
                % (self._testTimeString(test), reason))
584
601
 
585
602
    def report_unsupported(self, test, feature):
586
603
        """test cannot be run because feature is missing."""
587
 
        self.stream.writeln("NODEP %s\n    The feature '%s' is not available."
 
604
        self.stream.write("NODEP %s\n    The feature '%s' is not available.\n"
588
605
                %(self._testTimeString(test), feature))
589
606
 
590
607
 
619
636
            encode = codec.encode
620
637
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
621
638
        stream.encoding = new_encoding
622
 
        self.stream = unittest._WritelnDecorator(stream)
 
639
        self.stream = stream
623
640
        self.descriptions = descriptions
624
641
        self.verbosity = verbosity
625
642
        self._bench_history = bench_history
749
766
    # XXX: Should probably unify more with CannedInputUIFactory or a
750
767
    # particular configuration of TextUIFactory, or otherwise have a clearer
751
768
    # idea of how they're supposed to be different.
752
 
    # See https://bugs.edge.launchpad.net/bzr/+bug/408213
 
769
    # See https://bugs.launchpad.net/bzr/+bug/408213
753
770
 
754
771
    def __init__(self, stdout=None, stderr=None, stdin=None):
755
772
        if stdin is not None:
789
806
    routine, and to build and check bzr trees.
790
807
 
791
808
    In addition to the usual method of overriding tearDown(), this class also
792
 
    allows subclasses to register functions into the _cleanups list, which is
 
809
    allows subclasses to register cleanup functions via addCleanup, which are
793
810
    run in order as the object is torn down.  It's less likely this will be
794
811
    accidentally overlooked.
795
812
    """
796
813
 
797
 
    _active_threads = None
798
 
    _leaking_threads_tests = 0
799
 
    _first_thread_leaker_id = None
800
 
    _log_file_name = None
 
814
    _log_file = None
801
815
    # record lsprof data when performing benchmark calls.
802
816
    _gather_lsprof_in_benchmarks = False
803
817
 
804
818
    def __init__(self, methodName='testMethod'):
805
819
        super(TestCase, self).__init__(methodName)
806
 
        self._cleanups = []
807
820
        self._directory_isolation = True
808
821
        self.exception_handlers.insert(0,
809
822
            (UnavailableFeature, self._do_unsupported_or_skip))
827
840
        self._track_transports()
828
841
        self._track_locks()
829
842
        self._clear_debug_flags()
830
 
        TestCase._active_threads = threading.activeCount()
831
 
        self.addCleanup(self._check_leaked_threads)
832
843
 
833
844
    def debug(self):
834
845
        # debug a frame up.
835
846
        import pdb
836
847
        pdb.Pdb().set_trace(sys._getframe().f_back)
837
848
 
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()
 
849
    def discardDetail(self, name):
 
850
        """Extend the addDetail, getDetails api so we can remove a detail.
 
851
 
 
852
        eg. bzr always adds the 'log' detail at startup, but we don't want to
 
853
        include it for skipped, xfail, etc tests.
 
854
 
 
855
        It is safe to call this for a detail that doesn't exist, in case this
 
856
        gets called multiple times.
 
857
        """
 
858
        # We cheat. details is stored in __details which means we shouldn't
 
859
        # touch it. but getDetails() returns the dict directly, so we can
 
860
        # mutate it.
 
861
        details = self.getDetails()
 
862
        if name in details:
 
863
            del details[name]
852
864
 
853
865
    def _clear_debug_flags(self):
854
866
        """Prevent externally set debug flags affecting tests.
943
955
 
944
956
    def permit_dir(self, name):
945
957
        """Permit a directory to be used by this test. See permit_url."""
946
 
        name_transport = get_transport(name)
 
958
        name_transport = _mod_transport.get_transport(name)
947
959
        self.permit_url(name)
948
960
        self.permit_url(name_transport.base)
949
961
 
972
984
            try:
973
985
                workingtree.WorkingTree.open(path)
974
986
            except (errors.NotBranchError, errors.NoWorkingTree):
975
 
                return
 
987
                raise TestSkipped('Needs a working tree of bzr sources')
976
988
        finally:
977
989
            self.enable_directory_isolation()
978
990
 
1028
1040
        self.addCleanup(transport_server.stop_server)
1029
1041
        # Obtain a real transport because if the server supplies a password, it
1030
1042
        # will be hidden from the base on the client side.
1031
 
        t = get_transport(transport_server.get_url())
 
1043
        t = _mod_transport.get_transport(transport_server.get_url())
1032
1044
        # Some transport servers effectively chroot the backing transport;
1033
1045
        # others like SFTPServer don't - users of the transport can walk up the
1034
1046
        # transport to read the entire backing transport. This wouldn't matter
1095
1107
            message += '\n'
1096
1108
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1097
1109
            % (message,
1098
 
               pformat(a), pformat(b)))
 
1110
               pprint.pformat(a), pprint.pformat(b)))
1099
1111
 
1100
1112
    assertEquals = assertEqual
1101
1113
 
1455
1467
 
1456
1468
        The file is removed as the test is torn down.
1457
1469
        """
1458
 
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
1459
 
        self._log_file = os.fdopen(fileno, 'w+')
 
1470
        self._log_file = StringIO()
1460
1471
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
1461
 
        self._log_file_name = name
1462
1472
        self.addCleanup(self._finishLogFile)
1463
1473
 
1464
1474
    def _finishLogFile(self):
1486
1496
        """
1487
1497
        debug.debug_flags.discard('strict_locks')
1488
1498
 
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
1499
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1498
1500
        """Overrides an object attribute restoring it after the test.
1499
1501
 
1524
1526
            'EDITOR': None,
1525
1527
            'BZR_EMAIL': None,
1526
1528
            'BZREMAIL': None, # may still be present in the environment
1527
 
            'EMAIL': None,
 
1529
            'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
1528
1530
            'BZR_PROGRESS_BAR': None,
1529
1531
            'BZR_LOG': None,
1530
1532
            'BZR_PLUGIN_PATH': None,
1583
1585
        """This test has failed for some known reason."""
1584
1586
        raise KnownFailure(reason)
1585
1587
 
 
1588
    def _suppress_log(self):
 
1589
        """Remove the log info from details."""
 
1590
        self.discardDetail('log')
 
1591
 
1586
1592
    def _do_skip(self, result, reason):
 
1593
        self._suppress_log()
1587
1594
        addSkip = getattr(result, 'addSkip', None)
1588
1595
        if not callable(addSkip):
1589
1596
            result.addSuccess(result)
1592
1599
 
1593
1600
    @staticmethod
1594
1601
    def _do_known_failure(self, result, e):
 
1602
        self._suppress_log()
1595
1603
        err = sys.exc_info()
1596
1604
        addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1597
1605
        if addExpectedFailure is not None:
1605
1613
            reason = 'No reason given'
1606
1614
        else:
1607
1615
            reason = e.args[0]
 
1616
        self._suppress_log ()
1608
1617
        addNotApplicable = getattr(result, 'addNotApplicable', None)
1609
1618
        if addNotApplicable is not None:
1610
1619
            result.addNotApplicable(self, reason)
1612
1621
            self._do_skip(result, reason)
1613
1622
 
1614
1623
    @staticmethod
 
1624
    def _report_skip(self, result, err):
 
1625
        """Override the default _report_skip.
 
1626
 
 
1627
        We want to strip the 'log' detail. If we waint until _do_skip, it has
 
1628
        already been formatted into the 'reason' string, and we can't pull it
 
1629
        out again.
 
1630
        """
 
1631
        self._suppress_log()
 
1632
        super(TestCase, self)._report_skip(self, result, err)
 
1633
 
 
1634
    @staticmethod
 
1635
    def _report_expected_failure(self, result, err):
 
1636
        """Strip the log.
 
1637
 
 
1638
        See _report_skip for motivation.
 
1639
        """
 
1640
        self._suppress_log()
 
1641
        super(TestCase, self)._report_expected_failure(self, result, err)
 
1642
 
 
1643
    @staticmethod
1615
1644
    def _do_unsupported_or_skip(self, result, e):
1616
1645
        reason = e.args[0]
 
1646
        self._suppress_log()
1617
1647
        addNotSupported = getattr(result, 'addNotSupported', None)
1618
1648
        if addNotSupported is not None:
1619
1649
            result.addNotSupported(self, reason)
1666
1696
                unicodestr = self._log_contents.decode('utf8', 'replace')
1667
1697
                self._log_contents = unicodestr.encode('utf8')
1668
1698
            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()
 
1699
        if self._log_file is not None:
 
1700
            log_contents = self._log_file.getvalue()
1679
1701
            try:
1680
1702
                log_contents.decode('utf8')
1681
1703
            except UnicodeDecodeError:
1682
1704
                unicodestr = log_contents.decode('utf8', 'replace')
1683
1705
                log_contents = unicodestr.encode('utf8')
1684
1706
            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
1707
                self._log_file = None
1713
1708
                # Permit multiple calls to get_log until we clean it up in
1714
1709
                # finishLogFile
1715
1710
                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
1711
            return log_contents
1726
1712
        else:
1727
 
            return "No log file content and no log file name."
 
1713
            return "No log file content."
1728
1714
 
1729
1715
    def get_log(self):
1730
1716
        """Get a unicode string containing the log from bzrlib.trace.
1945
1931
            variables. A value of None will unset the env variable.
1946
1932
            The values must be strings. The change will only occur in the
1947
1933
            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.
 
1934
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
 
1935
            doesn't support signalling subprocesses.
1950
1936
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
1951
1937
 
1952
1938
        :returns: Popen object for the started process.
1953
1939
        """
1954
1940
        if skip_if_plan_to_signal:
1955
 
            if not getattr(os, 'kill', None):
1956
 
                raise TestSkipped("os.kill not available.")
 
1941
            if os.name != "posix":
 
1942
                raise TestSkipped("Sending signals not supported")
1957
1943
 
1958
1944
        if env_changes is None:
1959
1945
            env_changes = {}
1986
1972
            if not allow_plugins:
1987
1973
                command.append('--no-plugins')
1988
1974
            command.extend(process_args)
1989
 
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
 
1975
            process = self._popen(command, stdin=subprocess.PIPE,
 
1976
                                  stdout=subprocess.PIPE,
 
1977
                                  stderr=subprocess.PIPE)
1990
1978
        finally:
1991
1979
            restore_environment()
1992
1980
            if cwd is not None:
2000
1988
        Allows tests to override this method to intercept the calls made to
2001
1989
        Popen for introspection.
2002
1990
        """
2003
 
        return Popen(*args, **kwargs)
 
1991
        return subprocess.Popen(*args, **kwargs)
2004
1992
 
2005
1993
    def get_source_path(self):
2006
1994
        """Return the path of the directory containing bzrlib."""
2008
1996
 
2009
1997
    def get_bzr_path(self):
2010
1998
        """Return the path of the 'bzr' executable for this test suite."""
2011
 
        bzr_path = self.get_source_path()+'/bzr'
 
1999
        bzr_path = os.path.join(self.get_source_path(), "bzr")
2012
2000
        if not os.path.isfile(bzr_path):
2013
2001
            # We are probably installed. Assume sys.argv is the right file
2014
2002
            bzr_path = sys.argv[0]
2186
2174
 
2187
2175
        :param relpath: a path relative to the base url.
2188
2176
        """
2189
 
        t = get_transport(self.get_url(relpath))
 
2177
        t = _mod_transport.get_transport(self.get_url(relpath))
2190
2178
        self.assertFalse(t.is_readonly())
2191
2179
        return t
2192
2180
 
2198
2186
 
2199
2187
        :param relpath: a path relative to the base url.
2200
2188
        """
2201
 
        t = get_transport(self.get_readonly_url(relpath))
 
2189
        t = _mod_transport.get_transport(self.get_readonly_url(relpath))
2202
2190
        self.assertTrue(t.is_readonly())
2203
2191
        return t
2204
2192
 
2334
2322
        propagating. This method ensures than a test did not leaked.
2335
2323
        """
2336
2324
        root = TestCaseWithMemoryTransport.TEST_ROOT
2337
 
        self.permit_url(get_transport(root).base)
 
2325
        self.permit_url(_mod_transport.get_transport(root).base)
2338
2326
        wt = workingtree.WorkingTree.open(root)
2339
2327
        last_rev = wt.last_revision()
2340
2328
        if last_rev != 'null:':
2385
2373
            # might be a relative or absolute path
2386
2374
            maybe_a_url = self.get_url(relpath)
2387
2375
            segments = maybe_a_url.rsplit('/', 1)
2388
 
            t = get_transport(maybe_a_url)
 
2376
            t = _mod_transport.get_transport(maybe_a_url)
2389
2377
            if len(segments) > 1 and segments[-1] not in ('', '.'):
2390
2378
                t.ensure_base()
2391
2379
            if format is None:
2408
2396
        made_control = self.make_bzrdir(relpath, format=format)
2409
2397
        return made_control.create_repository(shared=shared)
2410
2398
 
2411
 
    def make_smart_server(self, path):
 
2399
    def make_smart_server(self, path, backing_server=None):
 
2400
        if backing_server is None:
 
2401
            backing_server = self.get_server()
2412
2402
        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)
 
2403
        self.start_server(smart_server, backing_server)
 
2404
        remote_transport = _mod_transport.get_transport(smart_server.get_url()
 
2405
                                                   ).clone(path)
2415
2406
        return remote_transport
2416
2407
 
2417
2408
    def make_branch_and_memory_tree(self, relpath, format=None):
2432
2423
 
2433
2424
    def setUp(self):
2434
2425
        super(TestCaseWithMemoryTransport, self).setUp()
 
2426
        # Ensure that ConnectedTransport doesn't leak sockets
 
2427
        def get_transport_with_cleanup(*args, **kwargs):
 
2428
            t = orig_get_transport(*args, **kwargs)
 
2429
            if isinstance(t, _mod_transport.ConnectedTransport):
 
2430
                self.addCleanup(t.disconnect)
 
2431
            return t
 
2432
 
 
2433
        orig_get_transport = self.overrideAttr(_mod_transport, 'get_transport',
 
2434
                                               get_transport_with_cleanup)
2435
2435
        self._make_test_root()
2436
2436
        self.addCleanup(os.chdir, os.getcwdu())
2437
2437
        self.makeAndChdirToTestDir()
2482
2482
 
2483
2483
    def check_file_contents(self, filename, expect):
2484
2484
        self.log("check contents of file %s" % filename)
2485
 
        contents = file(filename, 'r').read()
 
2485
        f = file(filename)
 
2486
        try:
 
2487
            contents = f.read()
 
2488
        finally:
 
2489
            f.close()
2486
2490
        if contents != expect:
2487
2491
            self.log("expected: %r" % expect)
2488
2492
            self.log("actually: %r" % contents)
2562
2566
                "a list or a tuple. Got %r instead" % (shape,))
2563
2567
        # It's OK to just create them using forward slashes on windows.
2564
2568
        if transport is None or transport.is_readonly():
2565
 
            transport = get_transport(".")
 
2569
            transport = _mod_transport.get_transport(".")
2566
2570
        for name in shape:
2567
2571
            self.assertIsInstance(name, basestring)
2568
2572
            if name[-1] == '/':
2578
2582
                content = "contents of %s%s" % (name.encode('utf-8'), end)
2579
2583
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
2580
2584
 
2581
 
    def build_tree_contents(self, shape):
2582
 
        build_tree_contents(shape)
 
2585
    build_tree_contents = staticmethod(treeshape.build_tree_contents)
2583
2586
 
2584
2587
    def assertInWorkingTree(self, path, root_path='.', tree=None):
2585
2588
        """Assert whether path or paths are in the WorkingTree"""
2726
2729
    """
2727
2730
 
2728
2731
    def setUp(self):
 
2732
        from bzrlib.tests import http_server
2729
2733
        super(ChrootedTestCase, self).setUp()
2730
2734
        if not self.vfs_transport_factory == memory.MemoryServer:
2731
 
            self.transport_readonly_server = HttpServer
 
2735
            self.transport_readonly_server = http_server.HttpServer
2732
2736
 
2733
2737
 
2734
2738
def condition_id_re(pattern):
2737
2741
    :param pattern: A regular expression string.
2738
2742
    :return: A callable that returns True if the re matches.
2739
2743
    """
2740
 
    filter_re = osutils.re_compile_checked(pattern, 0,
2741
 
        'test filter')
 
2744
    filter_re = re.compile(pattern, 0)
2742
2745
    def condition(test):
2743
2746
        test_id = test.id()
2744
2747
        return filter_re.search(test_id)
2996
2999
 
2997
3000
 
2998
3001
def fork_decorator(suite):
 
3002
    if getattr(os, "fork", None) is None:
 
3003
        raise errors.BzrCommandError("platform does not support fork,"
 
3004
            " try --parallel=subprocess instead.")
2999
3005
    concurrency = osutils.local_concurrency()
3000
3006
    if concurrency == 1:
3001
3007
        return suite
3056
3062
    return suite
3057
3063
 
3058
3064
 
3059
 
class TestDecorator(TestSuite):
 
3065
class TestDecorator(TestUtil.TestSuite):
3060
3066
    """A decorator for TestCase/TestSuite objects.
3061
3067
    
3062
3068
    Usually, subclasses should override __iter__(used when flattening test
3065
3071
    """
3066
3072
 
3067
3073
    def __init__(self, suite):
3068
 
        TestSuite.__init__(self)
 
3074
        TestUtil.TestSuite.__init__(self)
3069
3075
        self.addTest(suite)
3070
3076
 
3071
3077
    def countTestCases(self):
3190
3196
 
3191
3197
def partition_tests(suite, count):
3192
3198
    """Partition suite into count lists of tests."""
3193
 
    result = []
3194
 
    tests = list(iter_suite_tests(suite))
3195
 
    tests_per_process = int(math.ceil(float(len(tests)) / count))
3196
 
    for block in range(count):
3197
 
        low_test = block * tests_per_process
3198
 
        high_test = low_test + tests_per_process
3199
 
        process_tests = tests[low_test:high_test]
3200
 
        result.append(process_tests)
3201
 
    return result
 
3199
    # This just assigns tests in a round-robin fashion.  On one hand this
 
3200
    # splits up blocks of related tests that might run faster if they shared
 
3201
    # resources, but on the other it avoids assigning blocks of slow tests to
 
3202
    # just one partition.  So the slowest partition shouldn't be much slower
 
3203
    # than the fastest.
 
3204
    partitions = [list() for i in range(count)]
 
3205
    tests = iter_suite_tests(suite)
 
3206
    for partition, test in itertools.izip(itertools.cycle(partitions), tests):
 
3207
        partition.append(test)
 
3208
    return partitions
3202
3209
 
3203
3210
 
3204
3211
def workaround_zealous_crypto_random():
3238
3245
 
3239
3246
    test_blocks = partition_tests(suite, concurrency)
3240
3247
    for process_tests in test_blocks:
3241
 
        process_suite = TestSuite()
 
3248
        process_suite = TestUtil.TestSuite()
3242
3249
        process_suite.addTests(process_tests)
3243
3250
        c2pread, c2pwrite = os.pipe()
3244
3251
        pid = os.fork()
3310
3317
                '--subunit']
3311
3318
            if '--no-plugins' in sys.argv:
3312
3319
                argv.append('--no-plugins')
3313
 
            # stderr=STDOUT would be ideal, but until we prevent noise on
3314
 
            # stderr it can interrupt the subunit protocol.
3315
 
            process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
3316
 
                bufsize=1)
 
3320
            # stderr=subprocess.STDOUT would be ideal, but until we prevent
 
3321
            # noise on stderr it can interrupt the subunit protocol.
 
3322
            process = subprocess.Popen(argv, stdin=subprocess.PIPE,
 
3323
                                      stdout=subprocess.PIPE,
 
3324
                                      stderr=subprocess.PIPE,
 
3325
                                      bufsize=1)
3317
3326
            test = TestInSubprocess(process, test_list_file_name)
3318
3327
            result.append(test)
3319
3328
        except:
3368
3377
 
3369
3378
    def startTest(self, test):
3370
3379
        self.profiler = bzrlib.lsprof.BzrProfiler()
 
3380
        # Prevent deadlocks in tests that use lsprof: those tests will
 
3381
        # unavoidably fail.
 
3382
        bzrlib.lsprof.BzrProfiler.profiler_block = 0
3371
3383
        self.profiler.start()
3372
3384
        ForwardingResult.startTest(self, test)
3373
3385
 
3394
3406
#                           rather than failing tests. And no longer raise
3395
3407
#                           LockContention when fctnl locks are not being used
3396
3408
#                           with proper exclusion rules.
 
3409
#   -Ethreads               Will display thread ident at creation/join time to
 
3410
#                           help track thread leaks
3397
3411
selftest_debug_flags = set()
3398
3412
 
3399
3413
 
3632
3646
        'bzrlib.doc',
3633
3647
        'bzrlib.tests.blackbox',
3634
3648
        'bzrlib.tests.commands',
 
3649
        'bzrlib.tests.doc_generate',
3635
3650
        'bzrlib.tests.per_branch',
3636
3651
        'bzrlib.tests.per_bzrdir',
3637
 
        'bzrlib.tests.per_bzrdir_colo',
 
3652
        'bzrlib.tests.per_controldir',
 
3653
        'bzrlib.tests.per_controldir_colo',
3638
3654
        'bzrlib.tests.per_foreign_vcs',
3639
3655
        'bzrlib.tests.per_interrepository',
3640
3656
        'bzrlib.tests.per_intertree',
3653
3669
        'bzrlib.tests.per_workingtree',
3654
3670
        'bzrlib.tests.test__annotator',
3655
3671
        'bzrlib.tests.test__bencode',
 
3672
        'bzrlib.tests.test__btree_serializer',
3656
3673
        'bzrlib.tests.test__chk_map',
3657
3674
        'bzrlib.tests.test__dirstate_helpers',
3658
3675
        'bzrlib.tests.test__groupcompress',
3701
3718
        'bzrlib.tests.test_export',
3702
3719
        'bzrlib.tests.test_extract',
3703
3720
        'bzrlib.tests.test_fetch',
 
3721
        'bzrlib.tests.test_fixtures',
3704
3722
        'bzrlib.tests.test_fifo_cache',
3705
3723
        'bzrlib.tests.test_filters',
3706
3724
        'bzrlib.tests.test_ftp_transport',
3727
3745
        'bzrlib.tests.test_knit',
3728
3746
        'bzrlib.tests.test_lazy_import',
3729
3747
        'bzrlib.tests.test_lazy_regex',
 
3748
        'bzrlib.tests.test_library_state',
3730
3749
        'bzrlib.tests.test_lock',
3731
3750
        'bzrlib.tests.test_lockable_files',
3732
3751
        'bzrlib.tests.test_lockdir',
3789
3808
        'bzrlib.tests.test_switch',
3790
3809
        'bzrlib.tests.test_symbol_versioning',
3791
3810
        'bzrlib.tests.test_tag',
 
3811
        'bzrlib.tests.test_test_server',
3792
3812
        'bzrlib.tests.test_testament',
3793
3813
        'bzrlib.tests.test_textfile',
3794
3814
        'bzrlib.tests.test_textmerge',
3800
3820
        'bzrlib.tests.test_transport_log',
3801
3821
        'bzrlib.tests.test_tree',
3802
3822
        'bzrlib.tests.test_treebuilder',
 
3823
        'bzrlib.tests.test_treeshape',
3803
3824
        'bzrlib.tests.test_tsort',
3804
3825
        'bzrlib.tests.test_tuned_gzip',
3805
3826
        'bzrlib.tests.test_ui',
3809
3830
        'bzrlib.tests.test_urlutils',
3810
3831
        'bzrlib.tests.test_version',
3811
3832
        'bzrlib.tests.test_version_info',
 
3833
        'bzrlib.tests.test_versionedfile',
3812
3834
        'bzrlib.tests.test_weave',
3813
3835
        'bzrlib.tests.test_whitebox',
3814
3836
        'bzrlib.tests.test_win32utils',
3836
3858
        'bzrlib.option',
3837
3859
        'bzrlib.symbol_versioning',
3838
3860
        'bzrlib.tests',
 
3861
        'bzrlib.tests.fixtures',
3839
3862
        'bzrlib.timestamp',
3840
3863
        'bzrlib.version_info_formats.format_custom',
3841
3864
        ]
3982
4005
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
3983
4006
    ...     [('one', dict(param=1)),
3984
4007
    ...      ('two', dict(param=2))],
3985
 
    ...     TestSuite())
 
4008
    ...     TestUtil.TestSuite())
3986
4009
    >>> tests = list(iter_suite_tests(r))
3987
4010
    >>> len(tests)
3988
4011
    2
4035
4058
    :param new_id: The id to assign to it.
4036
4059
    :return: The new test.
4037
4060
    """
4038
 
    new_test = copy(test)
 
4061
    new_test = copy.copy(test)
4039
4062
    new_test.id = lambda: new_id
 
4063
    # XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
 
4064
    # causes cloned tests to share the 'details' dict.  This makes it hard to
 
4065
    # read the test output for parameterized tests, because tracebacks will be
 
4066
    # associated with irrelevant tests.
 
4067
    try:
 
4068
        details = new_test._TestCase__details
 
4069
    except AttributeError:
 
4070
        # must be a different version of testtools than expected.  Do nothing.
 
4071
        pass
 
4072
    else:
 
4073
        # Reset the '__details' dict.
 
4074
        new_test._TestCase__details = {}
4040
4075
    return new_test
4041
4076
 
4042
4077
 
4102
4137
        if test_id != None:
4103
4138
            ui.ui_factory.clear_term()
4104
4139
            sys.stderr.write('\nWhile running: %s\n' % (test_id,))
 
4140
        # Ugly, but the last thing we want here is fail, so bear with it.
 
4141
        printable_e = str(e).decode(osutils.get_user_encoding(), 'replace'
 
4142
                                    ).encode('ascii', 'replace')
4105
4143
        sys.stderr.write('Unable to remove testing dir %s\n%s'
4106
 
                         % (os.path.basename(dirname), e))
 
4144
                         % (os.path.basename(dirname), printable_e))
4107
4145
 
4108
4146
 
4109
4147
class Feature(object):
4339
4377
UnicodeFilename = _UnicodeFilename()
4340
4378
 
4341
4379
 
 
4380
class _ByteStringNamedFilesystem(Feature):
 
4381
    """Is the filesystem based on bytes?"""
 
4382
 
 
4383
    def _probe(self):
 
4384
        if os.name == "posix":
 
4385
            return True
 
4386
        return False
 
4387
 
 
4388
ByteStringNamedFilesystem = _ByteStringNamedFilesystem()
 
4389
 
 
4390
 
4342
4391
class _UTF8Filesystem(Feature):
4343
4392
    """Is the filesystem UTF-8?"""
4344
4393
 
4454
4503
try:
4455
4504
    from subunit import TestProtocolClient
4456
4505
    from subunit.test_results import AutoTimingTestResultDecorator
 
4506
    class SubUnitBzrProtocolClient(TestProtocolClient):
 
4507
 
 
4508
        def addSuccess(self, test, details=None):
 
4509
            # The subunit client always includes the details in the subunit
 
4510
            # stream, but we don't want to include it in ours.
 
4511
            if details is not None and 'log' in details:
 
4512
                del details['log']
 
4513
            return super(SubUnitBzrProtocolClient, self).addSuccess(
 
4514
                test, details)
 
4515
 
4457
4516
    class SubUnitBzrRunner(TextTestRunner):
4458
4517
        def run(self, test):
4459
4518
            result = AutoTimingTestResultDecorator(
4460
 
                TestProtocolClient(self.stream))
 
4519
                SubUnitBzrProtocolClient(self.stream))
4461
4520
            test.run(result)
4462
4521
            return result
4463
4522
except ImportError: