~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-11-05 08:35:39 UTC
  • mfrom: (5521.1.2 670851-directory-and-files)
  • Revision ID: pqm@pqm.ubuntu.com-20101105083539-urkk2to9qakthagn
(vila) Respect --directory when path parameters are also used for shelve and
 restore (Vincent Ladeuil)

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
 
17
"""Testing framework extensions"""
17
18
 
18
19
# TODO: Perhaps there should be an API to find out if bzr running under the
19
20
# test suite -- some plugins might want to avoid making intrusive changes if
28
29
 
29
30
import atexit
30
31
import codecs
31
 
from copy import copy
 
32
import copy
32
33
from cStringIO import StringIO
33
34
import difflib
34
35
import doctest
35
36
import errno
 
37
import itertools
36
38
import logging
37
 
import math
38
39
import os
39
 
from pprint import pformat
 
40
import platform
 
41
import pprint
40
42
import random
41
43
import re
42
44
import shlex
43
45
import stat
44
 
from subprocess import Popen, PIPE, STDOUT
 
46
import subprocess
45
47
import sys
46
48
import tempfile
47
49
import threading
69
71
    lock as _mod_lock,
70
72
    memorytree,
71
73
    osutils,
72
 
    progress,
 
74
    pyutils,
73
75
    ui,
74
76
    urlutils,
75
77
    registry,
 
78
    transport as _mod_transport,
76
79
    workingtree,
77
80
    )
78
81
import bzrlib.branch
87
90
except ImportError:
88
91
    # lsprof not available
89
92
    pass
90
 
from bzrlib.merge import merge_inner
91
93
import bzrlib.merge3
92
94
import bzrlib.plugin
93
 
from bzrlib.smart import client, request, server
 
95
from bzrlib.smart import client, request
94
96
import bzrlib.store
95
97
from bzrlib import symbol_versioning
96
98
from bzrlib.symbol_versioning import (
102
104
    )
103
105
import bzrlib.trace
104
106
from bzrlib.transport import (
105
 
    get_transport,
106
107
    memory,
107
108
    pathfilter,
108
109
    )
109
 
import bzrlib.transport
110
110
from bzrlib.trace import mutter, note
111
111
from bzrlib.tests import (
112
112
    test_server,
113
113
    TestUtil,
 
114
    treeshape,
114
115
    )
115
 
from bzrlib.tests.http_server import HttpServer
116
 
from bzrlib.tests.TestUtil import (
117
 
                          TestSuite,
118
 
                          TestLoader,
119
 
                          )
120
 
from bzrlib.tests.treeshape import build_tree_contents
121
116
from bzrlib.ui import NullProgressView
122
117
from bzrlib.ui.text import TextUIFactory
123
118
import bzrlib.version_info_formats.format_custom
124
 
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
125
119
 
126
120
# Mark this python module as being part of the implementation
127
121
# of unittest: this gives us better tracebacks where the last
139
133
SUBUNIT_SEEK_SET = 0
140
134
SUBUNIT_SEEK_CUR = 1
141
135
 
 
136
# These are intentionally brought into this namespace. That way plugins, etc
 
137
# can just "from bzrlib.tests import TestCase, TestLoader, etc"
 
138
TestSuite = TestUtil.TestSuite
 
139
TestLoader = TestUtil.TestLoader
142
140
 
143
 
class ExtendedTestResult(unittest._TextTestResult):
 
141
class ExtendedTestResult(testtools.TextTestResult):
144
142
    """Accepts, reports and accumulates the results of running tests.
145
143
 
146
144
    Compared to the unittest version this class adds support for
167
165
        :param bench_history: Optionally, a writable file object to accumulate
168
166
            benchmark results.
169
167
        """
170
 
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
 
168
        testtools.TextTestResult.__init__(self, stream)
171
169
        if bench_history is not None:
172
170
            from bzrlib.version import _get_bzr_source_tree
173
171
            src_tree = _get_bzr_source_tree()
194
192
        self.count = 0
195
193
        self._overall_start_time = time.time()
196
194
        self._strict = strict
 
195
        self._first_thread_leaker_id = None
 
196
        self._tests_leaking_threads_count = 0
 
197
        self._traceback_from_test = None
197
198
 
198
199
    def stopTestRun(self):
199
200
        run = self.testsRun
200
201
        actionTaken = "Ran"
201
202
        stopTime = time.time()
202
203
        timeTaken = stopTime - self.startTime
203
 
        self.printErrors()
204
 
        self.stream.writeln(self.separator2)
205
 
        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,
206
210
                            run, run != 1 and "s" or "", timeTaken))
207
 
        self.stream.writeln()
208
211
        if not self.wasSuccessful():
209
212
            self.stream.write("FAILED (")
210
213
            failed, errored = map(len, (self.failures, self.errors))
217
220
                if failed or errored: self.stream.write(", ")
218
221
                self.stream.write("known_failure_count=%d" %
219
222
                    self.known_failure_count)
220
 
            self.stream.writeln(")")
 
223
            self.stream.write(")\n")
221
224
        else:
222
225
            if self.known_failure_count:
223
 
                self.stream.writeln("OK (known_failures=%d)" %
 
226
                self.stream.write("OK (known_failures=%d)\n" %
224
227
                    self.known_failure_count)
225
228
            else:
226
 
                self.stream.writeln("OK")
 
229
                self.stream.write("OK\n")
227
230
        if self.skip_count > 0:
228
231
            skipped = self.skip_count
229
 
            self.stream.writeln('%d test%s skipped' %
 
232
            self.stream.write('%d test%s skipped\n' %
230
233
                                (skipped, skipped != 1 and "s" or ""))
231
234
        if self.unsupported:
232
235
            for feature, count in sorted(self.unsupported.items()):
233
 
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
 
236
                self.stream.write("Missing feature '%s' skipped %d tests.\n" %
234
237
                    (feature, count))
235
238
        if self._strict:
236
239
            ok = self.wasStrictlySuccessful()
237
240
        else:
238
241
            ok = self.wasSuccessful()
239
 
        if TestCase._first_thread_leaker_id:
 
242
        if self._first_thread_leaker_id:
240
243
            self.stream.write(
241
244
                '%s is leaking threads among %d leaking tests.\n' % (
242
 
                TestCase._first_thread_leaker_id,
243
 
                TestCase._leaking_threads_tests))
 
245
                self._first_thread_leaker_id,
 
246
                self._tests_leaking_threads_count))
244
247
            # We don't report the main thread as an active one.
245
248
            self.stream.write(
246
249
                '%d non-main threads were left active in the end.\n'
247
 
                % (TestCase._active_threads - 1))
 
250
                % (len(self._active_threads) - 1))
248
251
 
249
252
    def getDescription(self, test):
250
253
        return test.id()
257
260
 
258
261
    def _elapsedTestTimeString(self):
259
262
        """Return a time string for the overall time the current test has taken."""
260
 
        return self._formatTime(time.time() - self._start_time)
 
263
        return self._formatTime(self._delta_to_float(
 
264
            self._now() - self._start_datetime))
261
265
 
262
266
    def _testTimeString(self, testCase):
263
267
        benchmark_time = self._extractBenchmarkTime(testCase)
274
278
 
275
279
    def _shortened_test_description(self, test):
276
280
        what = test.id()
277
 
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
 
281
        what = re.sub(r'^bzrlib\.tests\.', '', what)
278
282
        return what
279
283
 
 
284
    # GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
 
285
    #                multiple times in a row, because the handler is added for
 
286
    #                each test but the container list is shared between cases.
 
287
    #                See lp:498869 lp:625574 and lp:637725 for background.
 
288
    def _record_traceback_from_test(self, exc_info):
 
289
        """Store the traceback from passed exc_info tuple till"""
 
290
        self._traceback_from_test = exc_info[2]
 
291
 
280
292
    def startTest(self, test):
281
 
        unittest.TestResult.startTest(self, test)
 
293
        super(ExtendedTestResult, self).startTest(test)
282
294
        if self.count == 0:
283
295
            self.startTests()
 
296
        self.count += 1
284
297
        self.report_test_start(test)
285
298
        test.number = self.count
286
299
        self._recordTestStartTime()
 
300
        # Make testtools cases give us the real traceback on failure
 
301
        addOnException = getattr(test, "addOnException", None)
 
302
        if addOnException is not None:
 
303
            addOnException(self._record_traceback_from_test)
 
304
        # Only check for thread leaks if the test case supports cleanups
 
305
        addCleanup = getattr(test, "addCleanup", None)
 
306
        if addCleanup is not None:
 
307
            addCleanup(self._check_leaked_threads, test)
287
308
 
288
309
    def startTests(self):
289
 
        import platform
290
 
        if getattr(sys, 'frozen', None) is None:
291
 
            bzr_path = osutils.realpath(sys.argv[0])
292
 
        else:
293
 
            bzr_path = sys.executable
294
 
        self.stream.write(
295
 
            'bzr selftest: %s\n' % (bzr_path,))
296
 
        self.stream.write(
297
 
            '   %s\n' % (
298
 
                    bzrlib.__path__[0],))
299
 
        self.stream.write(
300
 
            '   bzr-%s python-%s %s\n' % (
301
 
                    bzrlib.version_string,
302
 
                    bzrlib._format_version_tuple(sys.version_info),
303
 
                    platform.platform(aliased=1),
304
 
                    ))
305
 
        self.stream.write('\n')
 
310
        self.report_tests_starting()
 
311
        self._active_threads = threading.enumerate()
 
312
 
 
313
    def stopTest(self, test):
 
314
        self._traceback_from_test = None
 
315
 
 
316
    def _check_leaked_threads(self, test):
 
317
        """See if any threads have leaked since last call
 
318
 
 
319
        A sample of live threads is stored in the _active_threads attribute,
 
320
        when this method runs it compares the current live threads and any not
 
321
        in the previous sample are treated as having leaked.
 
322
        """
 
323
        now_active_threads = set(threading.enumerate())
 
324
        threads_leaked = now_active_threads.difference(self._active_threads)
 
325
        if threads_leaked:
 
326
            self._report_thread_leak(test, threads_leaked, now_active_threads)
 
327
            self._tests_leaking_threads_count += 1
 
328
            if self._first_thread_leaker_id is None:
 
329
                self._first_thread_leaker_id = test.id()
 
330
            self._active_threads = now_active_threads
306
331
 
307
332
    def _recordTestStartTime(self):
308
333
        """Record that a test has started."""
309
 
        self._start_time = time.time()
310
 
 
311
 
    def _cleanupLogFile(self, test):
312
 
        # We can only do this if we have one of our TestCases, not if
313
 
        # we have a doctest.
314
 
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
315
 
        if setKeepLogfile is not None:
316
 
            setKeepLogfile()
 
334
        self._start_datetime = self._now()
317
335
 
318
336
    def addError(self, test, err):
319
337
        """Tell result that test finished with an error.
321
339
        Called from the TestCase run() method when the test
322
340
        fails with an unexpected error.
323
341
        """
324
 
        self._post_mortem()
325
 
        unittest.TestResult.addError(self, test, err)
 
342
        self._post_mortem(self._traceback_from_test)
 
343
        super(ExtendedTestResult, self).addError(test, err)
326
344
        self.error_count += 1
327
345
        self.report_error(test, err)
328
346
        if self.stop_early:
329
347
            self.stop()
330
 
        self._cleanupLogFile(test)
331
348
 
332
349
    def addFailure(self, test, err):
333
350
        """Tell result that test failed.
335
352
        Called from the TestCase run() method when the test
336
353
        fails because e.g. an assert() method failed.
337
354
        """
338
 
        self._post_mortem()
339
 
        unittest.TestResult.addFailure(self, test, err)
 
355
        self._post_mortem(self._traceback_from_test)
 
356
        super(ExtendedTestResult, self).addFailure(test, err)
340
357
        self.failure_count += 1
341
358
        self.report_failure(test, err)
342
359
        if self.stop_early:
343
360
            self.stop()
344
 
        self._cleanupLogFile(test)
345
361
 
346
362
    def addSuccess(self, test, details=None):
347
363
        """Tell result that test completed successfully.
355
371
                    self._formatTime(benchmark_time),
356
372
                    test.id()))
357
373
        self.report_success(test)
358
 
        self._cleanupLogFile(test)
359
 
        unittest.TestResult.addSuccess(self, test)
 
374
        super(ExtendedTestResult, self).addSuccess(test)
360
375
        test._log_contents = ''
361
376
 
362
377
    def addExpectedFailure(self, test, err):
385
400
        self.not_applicable_count += 1
386
401
        self.report_not_applicable(test, reason)
387
402
 
388
 
    def _post_mortem(self):
 
403
    def _post_mortem(self, tb=None):
389
404
        """Start a PDB post mortem session."""
390
405
        if os.environ.get('BZR_TEST_PDB', None):
391
 
            import pdb;pdb.post_mortem()
 
406
            import pdb
 
407
            pdb.post_mortem(tb)
392
408
 
393
409
    def progress(self, offset, whence):
394
410
        """The test is adjusting the count of tests to run."""
399
415
        else:
400
416
            raise errors.BzrError("Unknown whence %r" % whence)
401
417
 
402
 
    def report_cleaning_up(self):
403
 
        pass
 
418
    def report_tests_starting(self):
 
419
        """Display information before the test run begins"""
 
420
        if getattr(sys, 'frozen', None) is None:
 
421
            bzr_path = osutils.realpath(sys.argv[0])
 
422
        else:
 
423
            bzr_path = sys.executable
 
424
        self.stream.write(
 
425
            'bzr selftest: %s\n' % (bzr_path,))
 
426
        self.stream.write(
 
427
            '   %s\n' % (
 
428
                    bzrlib.__path__[0],))
 
429
        self.stream.write(
 
430
            '   bzr-%s python-%s %s\n' % (
 
431
                    bzrlib.version_string,
 
432
                    bzrlib._format_version_tuple(sys.version_info),
 
433
                    platform.platform(aliased=1),
 
434
                    ))
 
435
        self.stream.write('\n')
 
436
 
 
437
    def report_test_start(self, test):
 
438
        """Display information on the test just about to be run"""
 
439
 
 
440
    def _report_thread_leak(self, test, leaked_threads, active_threads):
 
441
        """Display information on a test that leaked one or more threads"""
 
442
        # GZ 2010-09-09: A leak summary reported separately from the general
 
443
        #                thread debugging would be nice. Tests under subunit
 
444
        #                need something not using stream, perhaps adding a
 
445
        #                testtools details object would be fitting.
 
446
        if 'threads' in selftest_debug_flags:
 
447
            self.stream.write('%s is leaking, active is now %d\n' %
 
448
                (test.id(), len(active_threads)))
404
449
 
405
450
    def startTestRun(self):
406
451
        self.startTime = time.time()
443
488
        self.pb.finished()
444
489
        super(TextTestResult, self).stopTestRun()
445
490
 
446
 
    def startTestRun(self):
447
 
        super(TextTestResult, self).startTestRun()
 
491
    def report_tests_starting(self):
 
492
        super(TextTestResult, self).report_tests_starting()
448
493
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
449
494
 
450
 
    def printErrors(self):
451
 
        # clear the pb to make room for the error listing
452
 
        self.pb.clear()
453
 
        super(TextTestResult, self).printErrors()
454
 
 
455
495
    def _progress_prefix_text(self):
456
496
        # the longer this text, the less space we have to show the test
457
497
        # name...
479
519
        return a
480
520
 
481
521
    def report_test_start(self, test):
482
 
        self.count += 1
483
522
        self.pb.update(
484
523
                self._progress_prefix_text()
485
524
                + ' '
489
528
        return self._shortened_test_description(test)
490
529
 
491
530
    def report_error(self, test, err):
492
 
        self.ui.note('ERROR: %s\n    %s\n' % (
 
531
        self.stream.write('ERROR: %s\n    %s\n' % (
493
532
            self._test_description(test),
494
533
            err[1],
495
534
            ))
496
535
 
497
536
    def report_failure(self, test, err):
498
 
        self.ui.note('FAIL: %s\n    %s\n' % (
 
537
        self.stream.write('FAIL: %s\n    %s\n' % (
499
538
            self._test_description(test),
500
539
            err[1],
501
540
            ))
512
551
    def report_unsupported(self, test, feature):
513
552
        """test cannot be run because feature is missing."""
514
553
 
515
 
    def report_cleaning_up(self):
516
 
        self.pb.update('Cleaning up')
517
 
 
518
554
 
519
555
class VerboseTestResult(ExtendedTestResult):
520
556
    """Produce long output, with one line per test run plus times"""
527
563
            result = a_string
528
564
        return result.ljust(final_width)
529
565
 
530
 
    def startTestRun(self):
531
 
        super(VerboseTestResult, self).startTestRun()
 
566
    def report_tests_starting(self):
532
567
        self.stream.write('running %d tests...\n' % self.num_tests)
 
568
        super(VerboseTestResult, self).report_tests_starting()
533
569
 
534
570
    def report_test_start(self, test):
535
 
        self.count += 1
536
571
        name = self._shortened_test_description(test)
537
572
        width = osutils.terminal_width()
538
573
        if width is not None:
550
585
        return '%s%s' % (indent, err[1])
551
586
 
552
587
    def report_error(self, test, err):
553
 
        self.stream.writeln('ERROR %s\n%s'
 
588
        self.stream.write('ERROR %s\n%s\n'
554
589
                % (self._testTimeString(test),
555
590
                   self._error_summary(err)))
556
591
 
557
592
    def report_failure(self, test, err):
558
 
        self.stream.writeln(' FAIL %s\n%s'
 
593
        self.stream.write(' FAIL %s\n%s\n'
559
594
                % (self._testTimeString(test),
560
595
                   self._error_summary(err)))
561
596
 
562
597
    def report_known_failure(self, test, err):
563
 
        self.stream.writeln('XFAIL %s\n%s'
 
598
        self.stream.write('XFAIL %s\n%s\n'
564
599
                % (self._testTimeString(test),
565
600
                   self._error_summary(err)))
566
601
 
567
602
    def report_success(self, test):
568
 
        self.stream.writeln('   OK %s' % self._testTimeString(test))
 
603
        self.stream.write('   OK %s\n' % self._testTimeString(test))
569
604
        for bench_called, stats in getattr(test, '_benchcalls', []):
570
 
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
605
            self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
571
606
            stats.pprint(file=self.stream)
572
607
        # flush the stream so that we get smooth output. This verbose mode is
573
608
        # used to show the output in PQM.
574
609
        self.stream.flush()
575
610
 
576
611
    def report_skip(self, test, reason):
577
 
        self.stream.writeln(' SKIP %s\n%s'
 
612
        self.stream.write(' SKIP %s\n%s\n'
578
613
                % (self._testTimeString(test), reason))
579
614
 
580
615
    def report_not_applicable(self, test, reason):
581
 
        self.stream.writeln('  N/A %s\n    %s'
 
616
        self.stream.write('  N/A %s\n    %s\n'
582
617
                % (self._testTimeString(test), reason))
583
618
 
584
619
    def report_unsupported(self, test, feature):
585
620
        """test cannot be run because feature is missing."""
586
 
        self.stream.writeln("NODEP %s\n    The feature '%s' is not available."
 
621
        self.stream.write("NODEP %s\n    The feature '%s' is not available.\n"
587
622
                %(self._testTimeString(test), feature))
588
623
 
589
624
 
618
653
            encode = codec.encode
619
654
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
620
655
        stream.encoding = new_encoding
621
 
        self.stream = unittest._WritelnDecorator(stream)
 
656
        self.stream = stream
622
657
        self.descriptions = descriptions
623
658
        self.verbosity = verbosity
624
659
        self._bench_history = bench_history
748
783
    # XXX: Should probably unify more with CannedInputUIFactory or a
749
784
    # particular configuration of TextUIFactory, or otherwise have a clearer
750
785
    # idea of how they're supposed to be different.
751
 
    # See https://bugs.edge.launchpad.net/bzr/+bug/408213
 
786
    # See https://bugs.launchpad.net/bzr/+bug/408213
752
787
 
753
788
    def __init__(self, stdout=None, stderr=None, stdin=None):
754
789
        if stdin is not None:
788
823
    routine, and to build and check bzr trees.
789
824
 
790
825
    In addition to the usual method of overriding tearDown(), this class also
791
 
    allows subclasses to register functions into the _cleanups list, which is
 
826
    allows subclasses to register cleanup functions via addCleanup, which are
792
827
    run in order as the object is torn down.  It's less likely this will be
793
828
    accidentally overlooked.
794
829
    """
795
830
 
796
 
    _active_threads = None
797
 
    _leaking_threads_tests = 0
798
 
    _first_thread_leaker_id = None
799
 
    _log_file_name = None
 
831
    _log_file = None
800
832
    # record lsprof data when performing benchmark calls.
801
833
    _gather_lsprof_in_benchmarks = False
802
834
 
803
835
    def __init__(self, methodName='testMethod'):
804
836
        super(TestCase, self).__init__(methodName)
805
 
        self._cleanups = []
806
837
        self._directory_isolation = True
807
838
        self.exception_handlers.insert(0,
808
839
            (UnavailableFeature, self._do_unsupported_or_skip))
826
857
        self._track_transports()
827
858
        self._track_locks()
828
859
        self._clear_debug_flags()
829
 
        TestCase._active_threads = threading.activeCount()
830
 
        self.addCleanup(self._check_leaked_threads)
 
860
        # Isolate global verbosity level, to make sure it's reproducible
 
861
        # between tests.  We should get rid of this altogether: bug 656694. --
 
862
        # mbp 20101008
 
863
        self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
831
864
 
832
865
    def debug(self):
833
866
        # debug a frame up.
834
867
        import pdb
835
868
        pdb.Pdb().set_trace(sys._getframe().f_back)
836
869
 
837
 
    def _check_leaked_threads(self):
838
 
        active = threading.activeCount()
839
 
        leaked_threads = active - TestCase._active_threads
840
 
        TestCase._active_threads = active
841
 
        # If some tests make the number of threads *decrease*, we'll consider
842
 
        # that they are just observing old threads dieing, not agressively kill
843
 
        # random threads. So we don't report these tests as leaking. The risk
844
 
        # is that we have false positives that way (the test see 2 threads
845
 
        # going away but leak one) but it seems less likely than the actual
846
 
        # false positives (the test see threads going away and does not leak).
847
 
        if leaked_threads > 0:
848
 
            TestCase._leaking_threads_tests += 1
849
 
            if TestCase._first_thread_leaker_id is None:
850
 
                TestCase._first_thread_leaker_id = self.id()
 
870
    def discardDetail(self, name):
 
871
        """Extend the addDetail, getDetails api so we can remove a detail.
 
872
 
 
873
        eg. bzr always adds the 'log' detail at startup, but we don't want to
 
874
        include it for skipped, xfail, etc tests.
 
875
 
 
876
        It is safe to call this for a detail that doesn't exist, in case this
 
877
        gets called multiple times.
 
878
        """
 
879
        # We cheat. details is stored in __details which means we shouldn't
 
880
        # touch it. but getDetails() returns the dict directly, so we can
 
881
        # mutate it.
 
882
        details = self.getDetails()
 
883
        if name in details:
 
884
            del details[name]
851
885
 
852
886
    def _clear_debug_flags(self):
853
887
        """Prevent externally set debug flags affecting tests.
864
898
 
865
899
    def _clear_hooks(self):
866
900
        # prevent hooks affecting tests
 
901
        known_hooks = hooks.known_hooks
867
902
        self._preserved_hooks = {}
868
 
        for key, factory in hooks.known_hooks.items():
869
 
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
870
 
            current_hooks = hooks.known_hooks_key_to_object(key)
 
903
        for key, (parent, name) in known_hooks.iter_parent_objects():
 
904
            current_hooks = getattr(parent, name)
871
905
            self._preserved_hooks[parent] = (name, current_hooks)
872
906
        self.addCleanup(self._restoreHooks)
873
 
        for key, factory in hooks.known_hooks.items():
874
 
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
907
        for key, (parent, name) in known_hooks.iter_parent_objects():
 
908
            factory = known_hooks.get(key)
875
909
            setattr(parent, name, factory())
876
910
        # this hook should always be installed
877
911
        request._install_hook()
942
976
 
943
977
    def permit_dir(self, name):
944
978
        """Permit a directory to be used by this test. See permit_url."""
945
 
        name_transport = get_transport(name)
 
979
        name_transport = _mod_transport.get_transport(name)
946
980
        self.permit_url(name)
947
981
        self.permit_url(name_transport.base)
948
982
 
971
1005
            try:
972
1006
                workingtree.WorkingTree.open(path)
973
1007
            except (errors.NotBranchError, errors.NoWorkingTree):
974
 
                return
 
1008
                raise TestSkipped('Needs a working tree of bzr sources')
975
1009
        finally:
976
1010
            self.enable_directory_isolation()
977
1011
 
1027
1061
        self.addCleanup(transport_server.stop_server)
1028
1062
        # Obtain a real transport because if the server supplies a password, it
1029
1063
        # will be hidden from the base on the client side.
1030
 
        t = get_transport(transport_server.get_url())
 
1064
        t = _mod_transport.get_transport(transport_server.get_url())
1031
1065
        # Some transport servers effectively chroot the backing transport;
1032
1066
        # others like SFTPServer don't - users of the transport can walk up the
1033
1067
        # transport to read the entire backing transport. This wouldn't matter
1094
1128
            message += '\n'
1095
1129
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1096
1130
            % (message,
1097
 
               pformat(a), pformat(b)))
 
1131
               pprint.pformat(a), pprint.pformat(b)))
1098
1132
 
1099
1133
    assertEquals = assertEqual
1100
1134
 
1312
1346
            f.close()
1313
1347
        self.assertEqualDiff(content, s)
1314
1348
 
 
1349
    def assertDocstring(self, expected_docstring, obj):
 
1350
        """Fail if obj does not have expected_docstring"""
 
1351
        if __doc__ is None:
 
1352
            # With -OO the docstring should be None instead
 
1353
            self.assertIs(obj.__doc__, None)
 
1354
        else:
 
1355
            self.assertEqual(expected_docstring, obj.__doc__)
 
1356
 
1315
1357
    def failUnlessExists(self, path):
1316
1358
        """Fail unless path or paths, which may be abs or relative, exist."""
1317
1359
        if not isinstance(path, basestring):
1446
1488
 
1447
1489
        The file is removed as the test is torn down.
1448
1490
        """
1449
 
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
1450
 
        self._log_file = os.fdopen(fileno, 'w+')
 
1491
        self._log_file = StringIO()
1451
1492
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
1452
 
        self._log_file_name = name
1453
1493
        self.addCleanup(self._finishLogFile)
1454
1494
 
1455
1495
    def _finishLogFile(self):
1477
1517
        """
1478
1518
        debug.debug_flags.discard('strict_locks')
1479
1519
 
1480
 
    def addCleanup(self, callable, *args, **kwargs):
1481
 
        """Arrange to run a callable when this case is torn down.
1482
 
 
1483
 
        Callables are run in the reverse of the order they are registered,
1484
 
        ie last-in first-out.
1485
 
        """
1486
 
        self._cleanups.append((callable, args, kwargs))
1487
 
 
1488
1520
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1489
1521
        """Overrides an object attribute restoring it after the test.
1490
1522
 
1515
1547
            'EDITOR': None,
1516
1548
            'BZR_EMAIL': None,
1517
1549
            'BZREMAIL': None, # may still be present in the environment
1518
 
            'EMAIL': None,
 
1550
            'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
1519
1551
            'BZR_PROGRESS_BAR': None,
1520
1552
            'BZR_LOG': None,
1521
1553
            'BZR_PLUGIN_PATH': None,
1574
1606
        """This test has failed for some known reason."""
1575
1607
        raise KnownFailure(reason)
1576
1608
 
 
1609
    def _suppress_log(self):
 
1610
        """Remove the log info from details."""
 
1611
        self.discardDetail('log')
 
1612
 
1577
1613
    def _do_skip(self, result, reason):
 
1614
        self._suppress_log()
1578
1615
        addSkip = getattr(result, 'addSkip', None)
1579
1616
        if not callable(addSkip):
1580
1617
            result.addSuccess(result)
1583
1620
 
1584
1621
    @staticmethod
1585
1622
    def _do_known_failure(self, result, e):
 
1623
        self._suppress_log()
1586
1624
        err = sys.exc_info()
1587
1625
        addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1588
1626
        if addExpectedFailure is not None:
1596
1634
            reason = 'No reason given'
1597
1635
        else:
1598
1636
            reason = e.args[0]
 
1637
        self._suppress_log ()
1599
1638
        addNotApplicable = getattr(result, 'addNotApplicable', None)
1600
1639
        if addNotApplicable is not None:
1601
1640
            result.addNotApplicable(self, reason)
1603
1642
            self._do_skip(result, reason)
1604
1643
 
1605
1644
    @staticmethod
 
1645
    def _report_skip(self, result, err):
 
1646
        """Override the default _report_skip.
 
1647
 
 
1648
        We want to strip the 'log' detail. If we waint until _do_skip, it has
 
1649
        already been formatted into the 'reason' string, and we can't pull it
 
1650
        out again.
 
1651
        """
 
1652
        self._suppress_log()
 
1653
        super(TestCase, self)._report_skip(self, result, err)
 
1654
 
 
1655
    @staticmethod
 
1656
    def _report_expected_failure(self, result, err):
 
1657
        """Strip the log.
 
1658
 
 
1659
        See _report_skip for motivation.
 
1660
        """
 
1661
        self._suppress_log()
 
1662
        super(TestCase, self)._report_expected_failure(self, result, err)
 
1663
 
 
1664
    @staticmethod
1606
1665
    def _do_unsupported_or_skip(self, result, e):
1607
1666
        reason = e.args[0]
 
1667
        self._suppress_log()
1608
1668
        addNotSupported = getattr(result, 'addNotSupported', None)
1609
1669
        if addNotSupported is not None:
1610
1670
            result.addNotSupported(self, reason)
1657
1717
                unicodestr = self._log_contents.decode('utf8', 'replace')
1658
1718
                self._log_contents = unicodestr.encode('utf8')
1659
1719
            return self._log_contents
1660
 
        import bzrlib.trace
1661
 
        if bzrlib.trace._trace_file:
1662
 
            # flush the log file, to get all content
1663
 
            bzrlib.trace._trace_file.flush()
1664
 
        if self._log_file_name is not None:
1665
 
            logfile = open(self._log_file_name)
1666
 
            try:
1667
 
                log_contents = logfile.read()
1668
 
            finally:
1669
 
                logfile.close()
 
1720
        if self._log_file is not None:
 
1721
            log_contents = self._log_file.getvalue()
1670
1722
            try:
1671
1723
                log_contents.decode('utf8')
1672
1724
            except UnicodeDecodeError:
1673
1725
                unicodestr = log_contents.decode('utf8', 'replace')
1674
1726
                log_contents = unicodestr.encode('utf8')
1675
1727
            if not keep_log_file:
1676
 
                close_attempts = 0
1677
 
                max_close_attempts = 100
1678
 
                first_close_error = None
1679
 
                while close_attempts < max_close_attempts:
1680
 
                    close_attempts += 1
1681
 
                    try:
1682
 
                        self._log_file.close()
1683
 
                    except IOError, ioe:
1684
 
                        if ioe.errno is None:
1685
 
                            # No errno implies 'close() called during
1686
 
                            # concurrent operation on the same file object', so
1687
 
                            # retry.  Probably a thread is trying to write to
1688
 
                            # the log file.
1689
 
                            if first_close_error is None:
1690
 
                                first_close_error = ioe
1691
 
                            continue
1692
 
                        raise
1693
 
                    else:
1694
 
                        break
1695
 
                if close_attempts > 1:
1696
 
                    sys.stderr.write(
1697
 
                        'Unable to close log file on first attempt, '
1698
 
                        'will retry: %s\n' % (first_close_error,))
1699
 
                    if close_attempts == max_close_attempts:
1700
 
                        sys.stderr.write(
1701
 
                            'Unable to close log file after %d attempts.\n'
1702
 
                            % (max_close_attempts,))
1703
1728
                self._log_file = None
1704
1729
                # Permit multiple calls to get_log until we clean it up in
1705
1730
                # finishLogFile
1706
1731
                self._log_contents = log_contents
1707
 
                try:
1708
 
                    os.remove(self._log_file_name)
1709
 
                except OSError, e:
1710
 
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
1711
 
                        sys.stderr.write(('Unable to delete log file '
1712
 
                                             ' %r\n' % self._log_file_name))
1713
 
                    else:
1714
 
                        raise
1715
 
                self._log_file_name = None
1716
1732
            return log_contents
1717
1733
        else:
1718
 
            return "No log file content and no log file name."
 
1734
            return "No log file content."
1719
1735
 
1720
1736
    def get_log(self):
1721
1737
        """Get a unicode string containing the log from bzrlib.trace.
1936
1952
            variables. A value of None will unset the env variable.
1937
1953
            The values must be strings. The change will only occur in the
1938
1954
            child, so you don't need to fix the environment after running.
1939
 
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
1940
 
            is not available.
 
1955
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
 
1956
            doesn't support signalling subprocesses.
1941
1957
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
1942
1958
 
1943
1959
        :returns: Popen object for the started process.
1944
1960
        """
1945
1961
        if skip_if_plan_to_signal:
1946
 
            if not getattr(os, 'kill', None):
1947
 
                raise TestSkipped("os.kill not available.")
 
1962
            if os.name != "posix":
 
1963
                raise TestSkipped("Sending signals not supported")
1948
1964
 
1949
1965
        if env_changes is None:
1950
1966
            env_changes = {}
1977
1993
            if not allow_plugins:
1978
1994
                command.append('--no-plugins')
1979
1995
            command.extend(process_args)
1980
 
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
 
1996
            process = self._popen(command, stdin=subprocess.PIPE,
 
1997
                                  stdout=subprocess.PIPE,
 
1998
                                  stderr=subprocess.PIPE)
1981
1999
        finally:
1982
2000
            restore_environment()
1983
2001
            if cwd is not None:
1991
2009
        Allows tests to override this method to intercept the calls made to
1992
2010
        Popen for introspection.
1993
2011
        """
1994
 
        return Popen(*args, **kwargs)
 
2012
        return subprocess.Popen(*args, **kwargs)
1995
2013
 
1996
2014
    def get_source_path(self):
1997
2015
        """Return the path of the directory containing bzrlib."""
1999
2017
 
2000
2018
    def get_bzr_path(self):
2001
2019
        """Return the path of the 'bzr' executable for this test suite."""
2002
 
        bzr_path = self.get_source_path()+'/bzr'
 
2020
        bzr_path = os.path.join(self.get_source_path(), "bzr")
2003
2021
        if not os.path.isfile(bzr_path):
2004
2022
            # We are probably installed. Assume sys.argv is the right file
2005
2023
            bzr_path = sys.argv[0]
2177
2195
 
2178
2196
        :param relpath: a path relative to the base url.
2179
2197
        """
2180
 
        t = get_transport(self.get_url(relpath))
 
2198
        t = _mod_transport.get_transport(self.get_url(relpath))
2181
2199
        self.assertFalse(t.is_readonly())
2182
2200
        return t
2183
2201
 
2189
2207
 
2190
2208
        :param relpath: a path relative to the base url.
2191
2209
        """
2192
 
        t = get_transport(self.get_readonly_url(relpath))
 
2210
        t = _mod_transport.get_transport(self.get_readonly_url(relpath))
2193
2211
        self.assertTrue(t.is_readonly())
2194
2212
        return t
2195
2213
 
2325
2343
        propagating. This method ensures than a test did not leaked.
2326
2344
        """
2327
2345
        root = TestCaseWithMemoryTransport.TEST_ROOT
2328
 
        self.permit_url(get_transport(root).base)
 
2346
        self.permit_url(_mod_transport.get_transport(root).base)
2329
2347
        wt = workingtree.WorkingTree.open(root)
2330
2348
        last_rev = wt.last_revision()
2331
2349
        if last_rev != 'null:':
2376
2394
            # might be a relative or absolute path
2377
2395
            maybe_a_url = self.get_url(relpath)
2378
2396
            segments = maybe_a_url.rsplit('/', 1)
2379
 
            t = get_transport(maybe_a_url)
 
2397
            t = _mod_transport.get_transport(maybe_a_url)
2380
2398
            if len(segments) > 1 and segments[-1] not in ('', '.'):
2381
2399
                t.ensure_base()
2382
2400
            if format is None:
2399
2417
        made_control = self.make_bzrdir(relpath, format=format)
2400
2418
        return made_control.create_repository(shared=shared)
2401
2419
 
2402
 
    def make_smart_server(self, path):
 
2420
    def make_smart_server(self, path, backing_server=None):
 
2421
        if backing_server is None:
 
2422
            backing_server = self.get_server()
2403
2423
        smart_server = test_server.SmartTCPServer_for_testing()
2404
 
        self.start_server(smart_server, self.get_server())
2405
 
        remote_transport = get_transport(smart_server.get_url()).clone(path)
 
2424
        self.start_server(smart_server, backing_server)
 
2425
        remote_transport = _mod_transport.get_transport(smart_server.get_url()
 
2426
                                                   ).clone(path)
2406
2427
        return remote_transport
2407
2428
 
2408
2429
    def make_branch_and_memory_tree(self, relpath, format=None):
2423
2444
 
2424
2445
    def setUp(self):
2425
2446
        super(TestCaseWithMemoryTransport, self).setUp()
 
2447
        # Ensure that ConnectedTransport doesn't leak sockets
 
2448
        def get_transport_with_cleanup(*args, **kwargs):
 
2449
            t = orig_get_transport(*args, **kwargs)
 
2450
            if isinstance(t, _mod_transport.ConnectedTransport):
 
2451
                self.addCleanup(t.disconnect)
 
2452
            return t
 
2453
 
 
2454
        orig_get_transport = self.overrideAttr(_mod_transport, '_get_transport',
 
2455
                                               get_transport_with_cleanup)
2426
2456
        self._make_test_root()
2427
2457
        self.addCleanup(os.chdir, os.getcwdu())
2428
2458
        self.makeAndChdirToTestDir()
2473
2503
 
2474
2504
    def check_file_contents(self, filename, expect):
2475
2505
        self.log("check contents of file %s" % filename)
2476
 
        contents = file(filename, 'r').read()
 
2506
        f = file(filename)
 
2507
        try:
 
2508
            contents = f.read()
 
2509
        finally:
 
2510
            f.close()
2477
2511
        if contents != expect:
2478
2512
            self.log("expected: %r" % expect)
2479
2513
            self.log("actually: %r" % contents)
2553
2587
                "a list or a tuple. Got %r instead" % (shape,))
2554
2588
        # It's OK to just create them using forward slashes on windows.
2555
2589
        if transport is None or transport.is_readonly():
2556
 
            transport = get_transport(".")
 
2590
            transport = _mod_transport.get_transport(".")
2557
2591
        for name in shape:
2558
2592
            self.assertIsInstance(name, basestring)
2559
2593
            if name[-1] == '/':
2569
2603
                content = "contents of %s%s" % (name.encode('utf-8'), end)
2570
2604
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
2571
2605
 
2572
 
    def build_tree_contents(self, shape):
2573
 
        build_tree_contents(shape)
 
2606
    build_tree_contents = staticmethod(treeshape.build_tree_contents)
2574
2607
 
2575
2608
    def assertInWorkingTree(self, path, root_path='.', tree=None):
2576
2609
        """Assert whether path or paths are in the WorkingTree"""
2717
2750
    """
2718
2751
 
2719
2752
    def setUp(self):
 
2753
        from bzrlib.tests import http_server
2720
2754
        super(ChrootedTestCase, self).setUp()
2721
2755
        if not self.vfs_transport_factory == memory.MemoryServer:
2722
 
            self.transport_readonly_server = HttpServer
 
2756
            self.transport_readonly_server = http_server.HttpServer
2723
2757
 
2724
2758
 
2725
2759
def condition_id_re(pattern):
2728
2762
    :param pattern: A regular expression string.
2729
2763
    :return: A callable that returns True if the re matches.
2730
2764
    """
2731
 
    filter_re = osutils.re_compile_checked(pattern, 0,
2732
 
        'test filter')
 
2765
    filter_re = re.compile(pattern, 0)
2733
2766
    def condition(test):
2734
2767
        test_id = test.id()
2735
2768
        return filter_re.search(test_id)
2987
3020
 
2988
3021
 
2989
3022
def fork_decorator(suite):
 
3023
    if getattr(os, "fork", None) is None:
 
3024
        raise errors.BzrCommandError("platform does not support fork,"
 
3025
            " try --parallel=subprocess instead.")
2990
3026
    concurrency = osutils.local_concurrency()
2991
3027
    if concurrency == 1:
2992
3028
        return suite
3047
3083
    return suite
3048
3084
 
3049
3085
 
3050
 
class TestDecorator(TestSuite):
 
3086
class TestDecorator(TestUtil.TestSuite):
3051
3087
    """A decorator for TestCase/TestSuite objects.
3052
3088
    
3053
3089
    Usually, subclasses should override __iter__(used when flattening test
3056
3092
    """
3057
3093
 
3058
3094
    def __init__(self, suite):
3059
 
        TestSuite.__init__(self)
 
3095
        TestUtil.TestSuite.__init__(self)
3060
3096
        self.addTest(suite)
3061
3097
 
3062
3098
    def countTestCases(self):
3181
3217
 
3182
3218
def partition_tests(suite, count):
3183
3219
    """Partition suite into count lists of tests."""
3184
 
    result = []
3185
 
    tests = list(iter_suite_tests(suite))
3186
 
    tests_per_process = int(math.ceil(float(len(tests)) / count))
3187
 
    for block in range(count):
3188
 
        low_test = block * tests_per_process
3189
 
        high_test = low_test + tests_per_process
3190
 
        process_tests = tests[low_test:high_test]
3191
 
        result.append(process_tests)
3192
 
    return result
 
3220
    # This just assigns tests in a round-robin fashion.  On one hand this
 
3221
    # splits up blocks of related tests that might run faster if they shared
 
3222
    # resources, but on the other it avoids assigning blocks of slow tests to
 
3223
    # just one partition.  So the slowest partition shouldn't be much slower
 
3224
    # than the fastest.
 
3225
    partitions = [list() for i in range(count)]
 
3226
    tests = iter_suite_tests(suite)
 
3227
    for partition, test in itertools.izip(itertools.cycle(partitions), tests):
 
3228
        partition.append(test)
 
3229
    return partitions
 
3230
 
 
3231
 
 
3232
def workaround_zealous_crypto_random():
 
3233
    """Crypto.Random want to help us being secure, but we don't care here.
 
3234
 
 
3235
    This workaround some test failure related to the sftp server. Once paramiko
 
3236
    stop using the controversial API in Crypto.Random, we may get rid of it.
 
3237
    """
 
3238
    try:
 
3239
        from Crypto.Random import atfork
 
3240
        atfork()
 
3241
    except ImportError:
 
3242
        pass
3193
3243
 
3194
3244
 
3195
3245
def fork_for_tests(suite):
3212
3262
            try:
3213
3263
                ProtocolTestCase.run(self, result)
3214
3264
            finally:
3215
 
                os.waitpid(self.pid, os.WNOHANG)
 
3265
                os.waitpid(self.pid, 0)
3216
3266
 
3217
3267
    test_blocks = partition_tests(suite, concurrency)
3218
3268
    for process_tests in test_blocks:
3219
 
        process_suite = TestSuite()
 
3269
        process_suite = TestUtil.TestSuite()
3220
3270
        process_suite.addTests(process_tests)
3221
3271
        c2pread, c2pwrite = os.pipe()
3222
3272
        pid = os.fork()
3223
3273
        if pid == 0:
 
3274
            workaround_zealous_crypto_random()
3224
3275
            try:
3225
3276
                os.close(c2pread)
3226
3277
                # Leave stderr and stdout open so we can see test noise
3287
3338
                '--subunit']
3288
3339
            if '--no-plugins' in sys.argv:
3289
3340
                argv.append('--no-plugins')
3290
 
            # stderr=STDOUT would be ideal, but until we prevent noise on
3291
 
            # stderr it can interrupt the subunit protocol.
3292
 
            process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
3293
 
                bufsize=1)
 
3341
            # stderr=subprocess.STDOUT would be ideal, but until we prevent
 
3342
            # noise on stderr it can interrupt the subunit protocol.
 
3343
            process = subprocess.Popen(argv, stdin=subprocess.PIPE,
 
3344
                                      stdout=subprocess.PIPE,
 
3345
                                      stderr=subprocess.PIPE,
 
3346
                                      bufsize=1)
3294
3347
            test = TestInSubprocess(process, test_list_file_name)
3295
3348
            result.append(test)
3296
3349
        except:
3299
3352
    return result
3300
3353
 
3301
3354
 
3302
 
class ForwardingResult(unittest.TestResult):
3303
 
 
3304
 
    def __init__(self, target):
3305
 
        unittest.TestResult.__init__(self)
3306
 
        self.result = target
3307
 
 
3308
 
    def startTest(self, test):
3309
 
        self.result.startTest(test)
3310
 
 
3311
 
    def stopTest(self, test):
3312
 
        self.result.stopTest(test)
3313
 
 
3314
 
    def startTestRun(self):
3315
 
        self.result.startTestRun()
3316
 
 
3317
 
    def stopTestRun(self):
3318
 
        self.result.stopTestRun()
3319
 
 
3320
 
    def addSkip(self, test, reason):
3321
 
        self.result.addSkip(test, reason)
3322
 
 
3323
 
    def addSuccess(self, test):
3324
 
        self.result.addSuccess(test)
3325
 
 
3326
 
    def addError(self, test, err):
3327
 
        self.result.addError(test, err)
3328
 
 
3329
 
    def addFailure(self, test, err):
3330
 
        self.result.addFailure(test, err)
3331
 
ForwardingResult = testtools.ExtendedToOriginalDecorator
3332
 
 
3333
 
 
3334
 
class ProfileResult(ForwardingResult):
 
3355
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3335
3356
    """Generate profiling data for all activity between start and success.
3336
3357
    
3337
3358
    The profile data is appended to the test's _benchcalls attribute and can
3345
3366
 
3346
3367
    def startTest(self, test):
3347
3368
        self.profiler = bzrlib.lsprof.BzrProfiler()
 
3369
        # Prevent deadlocks in tests that use lsprof: those tests will
 
3370
        # unavoidably fail.
 
3371
        bzrlib.lsprof.BzrProfiler.profiler_block = 0
3348
3372
        self.profiler.start()
3349
 
        ForwardingResult.startTest(self, test)
 
3373
        testtools.ExtendedToOriginalDecorator.startTest(self, test)
3350
3374
 
3351
3375
    def addSuccess(self, test):
3352
3376
        stats = self.profiler.stop()
3356
3380
            test._benchcalls = []
3357
3381
            calls = test._benchcalls
3358
3382
        calls.append(((test.id(), "", ""), stats))
3359
 
        ForwardingResult.addSuccess(self, test)
 
3383
        testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
3360
3384
 
3361
3385
    def stopTest(self, test):
3362
 
        ForwardingResult.stopTest(self, test)
 
3386
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
3363
3387
        self.profiler = None
3364
3388
 
3365
3389
 
3371
3395
#                           rather than failing tests. And no longer raise
3372
3396
#                           LockContention when fctnl locks are not being used
3373
3397
#                           with proper exclusion rules.
 
3398
#   -Ethreads               Will display thread ident at creation/join time to
 
3399
#                           help track thread leaks
3374
3400
selftest_debug_flags = set()
3375
3401
 
3376
3402
 
3609
3635
        'bzrlib.doc',
3610
3636
        'bzrlib.tests.blackbox',
3611
3637
        'bzrlib.tests.commands',
 
3638
        'bzrlib.tests.doc_generate',
3612
3639
        'bzrlib.tests.per_branch',
3613
3640
        'bzrlib.tests.per_bzrdir',
 
3641
        'bzrlib.tests.per_controldir',
 
3642
        'bzrlib.tests.per_controldir_colo',
3614
3643
        'bzrlib.tests.per_foreign_vcs',
3615
3644
        'bzrlib.tests.per_interrepository',
3616
3645
        'bzrlib.tests.per_intertree',
3629
3658
        'bzrlib.tests.per_workingtree',
3630
3659
        'bzrlib.tests.test__annotator',
3631
3660
        'bzrlib.tests.test__bencode',
 
3661
        'bzrlib.tests.test__btree_serializer',
3632
3662
        'bzrlib.tests.test__chk_map',
3633
3663
        'bzrlib.tests.test__dirstate_helpers',
3634
3664
        'bzrlib.tests.test__groupcompress',
3677
3707
        'bzrlib.tests.test_export',
3678
3708
        'bzrlib.tests.test_extract',
3679
3709
        'bzrlib.tests.test_fetch',
 
3710
        'bzrlib.tests.test_fixtures',
3680
3711
        'bzrlib.tests.test_fifo_cache',
3681
3712
        'bzrlib.tests.test_filters',
3682
3713
        'bzrlib.tests.test_ftp_transport',
3703
3734
        'bzrlib.tests.test_knit',
3704
3735
        'bzrlib.tests.test_lazy_import',
3705
3736
        'bzrlib.tests.test_lazy_regex',
 
3737
        'bzrlib.tests.test_library_state',
3706
3738
        'bzrlib.tests.test_lock',
3707
3739
        'bzrlib.tests.test_lockable_files',
3708
3740
        'bzrlib.tests.test_lockdir',
3710
3742
        'bzrlib.tests.test_lru_cache',
3711
3743
        'bzrlib.tests.test_lsprof',
3712
3744
        'bzrlib.tests.test_mail_client',
 
3745
        'bzrlib.tests.test_matchers',
3713
3746
        'bzrlib.tests.test_memorytree',
3714
3747
        'bzrlib.tests.test_merge',
3715
3748
        'bzrlib.tests.test_merge3',
3729
3762
        'bzrlib.tests.test_permissions',
3730
3763
        'bzrlib.tests.test_plugins',
3731
3764
        'bzrlib.tests.test_progress',
 
3765
        'bzrlib.tests.test_pyutils',
3732
3766
        'bzrlib.tests.test_read_bundle',
3733
3767
        'bzrlib.tests.test_reconcile',
3734
3768
        'bzrlib.tests.test_reconfigure',
3743
3777
        'bzrlib.tests.test_rio',
3744
3778
        'bzrlib.tests.test_rules',
3745
3779
        'bzrlib.tests.test_sampler',
 
3780
        'bzrlib.tests.test_scenarios',
3746
3781
        'bzrlib.tests.test_script',
3747
3782
        'bzrlib.tests.test_selftest',
3748
3783
        'bzrlib.tests.test_serializer',
3764
3799
        'bzrlib.tests.test_switch',
3765
3800
        'bzrlib.tests.test_symbol_versioning',
3766
3801
        'bzrlib.tests.test_tag',
 
3802
        'bzrlib.tests.test_test_server',
3767
3803
        'bzrlib.tests.test_testament',
3768
3804
        'bzrlib.tests.test_textfile',
3769
3805
        'bzrlib.tests.test_textmerge',
3775
3811
        'bzrlib.tests.test_transport_log',
3776
3812
        'bzrlib.tests.test_tree',
3777
3813
        'bzrlib.tests.test_treebuilder',
 
3814
        'bzrlib.tests.test_treeshape',
3778
3815
        'bzrlib.tests.test_tsort',
3779
3816
        'bzrlib.tests.test_tuned_gzip',
3780
3817
        'bzrlib.tests.test_ui',
3784
3821
        'bzrlib.tests.test_urlutils',
3785
3822
        'bzrlib.tests.test_version',
3786
3823
        'bzrlib.tests.test_version_info',
 
3824
        'bzrlib.tests.test_versionedfile',
3787
3825
        'bzrlib.tests.test_weave',
3788
3826
        'bzrlib.tests.test_whitebox',
3789
3827
        'bzrlib.tests.test_win32utils',
3795
3833
 
3796
3834
 
3797
3835
def _test_suite_modules_to_doctest():
3798
 
    """Return the list of modules to doctest."""   
 
3836
    """Return the list of modules to doctest."""
 
3837
    if __doc__ is None:
 
3838
        # GZ 2009-03-31: No docstrings with -OO so there's nothing to doctest
 
3839
        return []
3799
3840
    return [
3800
3841
        'bzrlib',
3801
3842
        'bzrlib.branchbuilder',
3806
3847
        'bzrlib.lockdir',
3807
3848
        'bzrlib.merge3',
3808
3849
        'bzrlib.option',
 
3850
        'bzrlib.pyutils',
3809
3851
        'bzrlib.symbol_versioning',
3810
3852
        'bzrlib.tests',
 
3853
        'bzrlib.tests.fixtures',
3811
3854
        'bzrlib.timestamp',
 
3855
        'bzrlib.transport.http',
3812
3856
        'bzrlib.version_info_formats.format_custom',
3813
3857
        ]
3814
3858
 
3917
3961
    return suite
3918
3962
 
3919
3963
 
3920
 
def multiply_scenarios(scenarios_left, scenarios_right):
 
3964
def multiply_scenarios(*scenarios):
 
3965
    """Multiply two or more iterables of scenarios.
 
3966
 
 
3967
    It is safe to pass scenario generators or iterators.
 
3968
 
 
3969
    :returns: A list of compound scenarios: the cross-product of all 
 
3970
        scenarios, with the names concatenated and the parameters
 
3971
        merged together.
 
3972
    """
 
3973
    return reduce(_multiply_two_scenarios, map(list, scenarios))
 
3974
 
 
3975
 
 
3976
def _multiply_two_scenarios(scenarios_left, scenarios_right):
3921
3977
    """Multiply two sets of scenarios.
3922
3978
 
3923
3979
    :returns: the cartesian product of the two sets of scenarios, that is
3954
4010
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
3955
4011
    ...     [('one', dict(param=1)),
3956
4012
    ...      ('two', dict(param=2))],
3957
 
    ...     TestSuite())
 
4013
    ...     TestUtil.TestSuite())
3958
4014
    >>> tests = list(iter_suite_tests(r))
3959
4015
    >>> len(tests)
3960
4016
    2
4007
4063
    :param new_id: The id to assign to it.
4008
4064
    :return: The new test.
4009
4065
    """
4010
 
    new_test = copy(test)
 
4066
    new_test = copy.copy(test)
4011
4067
    new_test.id = lambda: new_id
 
4068
    # XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
 
4069
    # causes cloned tests to share the 'details' dict.  This makes it hard to
 
4070
    # read the test output for parameterized tests, because tracebacks will be
 
4071
    # associated with irrelevant tests.
 
4072
    try:
 
4073
        details = new_test._TestCase__details
 
4074
    except AttributeError:
 
4075
        # must be a different version of testtools than expected.  Do nothing.
 
4076
        pass
 
4077
    else:
 
4078
        # Reset the '__details' dict.
 
4079
        new_test._TestCase__details = {}
4012
4080
    return new_test
4013
4081
 
4014
4082
 
4035
4103
        the module is available.
4036
4104
    """
4037
4105
 
4038
 
    py_module = __import__(py_module_name, {}, {}, ['NO_SUCH_ATTRIB'])
 
4106
    py_module = pyutils.get_named_object(py_module_name)
4039
4107
    scenarios = [
4040
4108
        ('python', {'module': py_module}),
4041
4109
    ]
4074
4142
        if test_id != None:
4075
4143
            ui.ui_factory.clear_term()
4076
4144
            sys.stderr.write('\nWhile running: %s\n' % (test_id,))
 
4145
        # Ugly, but the last thing we want here is fail, so bear with it.
 
4146
        printable_e = str(e).decode(osutils.get_user_encoding(), 'replace'
 
4147
                                    ).encode('ascii', 'replace')
4077
4148
        sys.stderr.write('Unable to remove testing dir %s\n%s'
4078
 
                         % (os.path.basename(dirname), e))
 
4149
                         % (os.path.basename(dirname), printable_e))
4079
4150
 
4080
4151
 
4081
4152
class Feature(object):
4191
4262
            symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4192
4263
            # Import the new feature and use it as a replacement for the
4193
4264
            # deprecated one.
4194
 
            mod = __import__(self._replacement_module, {}, {},
4195
 
                             [self._replacement_name])
4196
 
            self._feature = getattr(mod, self._replacement_name)
 
4265
            self._feature = pyutils.get_named_object(
 
4266
                self._replacement_module, self._replacement_name)
4197
4267
 
4198
4268
    def _probe(self):
4199
4269
        self._ensure()
4311
4381
UnicodeFilename = _UnicodeFilename()
4312
4382
 
4313
4383
 
 
4384
class _ByteStringNamedFilesystem(Feature):
 
4385
    """Is the filesystem based on bytes?"""
 
4386
 
 
4387
    def _probe(self):
 
4388
        if os.name == "posix":
 
4389
            return True
 
4390
        return False
 
4391
 
 
4392
ByteStringNamedFilesystem = _ByteStringNamedFilesystem()
 
4393
 
 
4394
 
4314
4395
class _UTF8Filesystem(Feature):
4315
4396
    """Is the filesystem UTF-8?"""
4316
4397
 
4426
4507
try:
4427
4508
    from subunit import TestProtocolClient
4428
4509
    from subunit.test_results import AutoTimingTestResultDecorator
 
4510
    class SubUnitBzrProtocolClient(TestProtocolClient):
 
4511
 
 
4512
        def addSuccess(self, test, details=None):
 
4513
            # The subunit client always includes the details in the subunit
 
4514
            # stream, but we don't want to include it in ours.
 
4515
            if details is not None and 'log' in details:
 
4516
                del details['log']
 
4517
            return super(SubUnitBzrProtocolClient, self).addSuccess(
 
4518
                test, details)
 
4519
 
4429
4520
    class SubUnitBzrRunner(TextTestRunner):
4430
4521
        def run(self, test):
4431
4522
            result = AutoTimingTestResultDecorator(
4432
 
                TestProtocolClient(self.stream))
 
4523
                SubUnitBzrProtocolClient(self.stream))
4433
4524
            test.run(result)
4434
4525
            return result
4435
4526
except ImportError:
4436
4527
    pass
 
4528
 
 
4529
class _PosixPermissionsFeature(Feature):
 
4530
 
 
4531
    def _probe(self):
 
4532
        def has_perms():
 
4533
            # create temporary file and check if specified perms are maintained.
 
4534
            import tempfile
 
4535
 
 
4536
            write_perms = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
 
4537
            f = tempfile.mkstemp(prefix='bzr_perms_chk_')
 
4538
            fd, name = f
 
4539
            os.close(fd)
 
4540
            os.chmod(name, write_perms)
 
4541
 
 
4542
            read_perms = os.stat(name).st_mode & 0777
 
4543
            os.unlink(name)
 
4544
            return (write_perms == read_perms)
 
4545
 
 
4546
        return (os.name == 'posix') and has_perms()
 
4547
 
 
4548
    def feature_name(self):
 
4549
        return 'POSIX permissions support'
 
4550
 
 
4551
posix_permissions_feature = _PosixPermissionsFeature()