~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Zearin
  • Date: 2010-11-12 22:08:18 UTC
  • mto: (5570.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 5572.
  • Revision ID: zearin@users.sourceforge.net-20101112220818-mb62len4zyxr8qvd
Fixed capitalization of XML and HTTP.  Fixed by hand and only where appropriate (e.g., left http://some/url lowercase, but capitalized "When making an HTTP request…").

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
    pyutils,
74
75
    ui,
75
76
    urlutils,
76
77
    registry,
 
78
    transport as _mod_transport,
77
79
    workingtree,
78
80
    )
79
81
import bzrlib.branch
88
90
except ImportError:
89
91
    # lsprof not available
90
92
    pass
91
 
from bzrlib.merge import merge_inner
92
93
import bzrlib.merge3
93
94
import bzrlib.plugin
94
 
from bzrlib.smart import client, request, server
 
95
from bzrlib.smart import client, request
95
96
import bzrlib.store
96
97
from bzrlib import symbol_versioning
97
98
from bzrlib.symbol_versioning import (
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
125
 
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
126
119
 
127
120
# Mark this python module as being part of the implementation
128
121
# of unittest: this gives us better tracebacks where the last
140
133
SUBUNIT_SEEK_SET = 0
141
134
SUBUNIT_SEEK_CUR = 1
142
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
143
140
 
144
 
class ExtendedTestResult(unittest._TextTestResult):
 
141
class ExtendedTestResult(testtools.TextTestResult):
145
142
    """Accepts, reports and accumulates the results of running tests.
146
143
 
147
144
    Compared to the unittest version this class adds support for
168
165
        :param bench_history: Optionally, a writable file object to accumulate
169
166
            benchmark results.
170
167
        """
171
 
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
 
168
        testtools.TextTestResult.__init__(self, stream)
172
169
        if bench_history is not None:
173
170
            from bzrlib.version import _get_bzr_source_tree
174
171
            src_tree = _get_bzr_source_tree()
195
192
        self.count = 0
196
193
        self._overall_start_time = time.time()
197
194
        self._strict = strict
 
195
        self._first_thread_leaker_id = None
 
196
        self._tests_leaking_threads_count = 0
 
197
        self._traceback_from_test = None
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()
258
260
 
259
261
    def _elapsedTestTimeString(self):
260
262
        """Return a time string for the overall time the current test has taken."""
261
 
        return self._formatTime(time.time() - self._start_time)
 
263
        return self._formatTime(self._delta_to_float(
 
264
            self._now() - self._start_datetime))
262
265
 
263
266
    def _testTimeString(self, testCase):
264
267
        benchmark_time = self._extractBenchmarkTime(testCase)
275
278
 
276
279
    def _shortened_test_description(self, test):
277
280
        what = test.id()
278
 
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
 
281
        what = re.sub(r'^bzrlib\.tests\.', '', what)
279
282
        return what
280
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
 
281
292
    def startTest(self, test):
282
 
        unittest.TestResult.startTest(self, test)
 
293
        super(ExtendedTestResult, self).startTest(test)
283
294
        if self.count == 0:
284
295
            self.startTests()
 
296
        self.count += 1
285
297
        self.report_test_start(test)
286
298
        test.number = self.count
287
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)
288
308
 
289
309
    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')
 
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
307
331
 
308
332
    def _recordTestStartTime(self):
309
333
        """Record that a test has started."""
310
 
        self._start_time = time.time()
311
 
 
312
 
    def _cleanupLogFile(self, test):
313
 
        # We can only do this if we have one of our TestCases, not if
314
 
        # we have a doctest.
315
 
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
316
 
        if setKeepLogfile is not None:
317
 
            setKeepLogfile()
 
334
        self._start_datetime = self._now()
318
335
 
319
336
    def addError(self, test, err):
320
337
        """Tell result that test finished with an error.
322
339
        Called from the TestCase run() method when the test
323
340
        fails with an unexpected error.
324
341
        """
325
 
        self._post_mortem()
326
 
        unittest.TestResult.addError(self, test, err)
 
342
        self._post_mortem(self._traceback_from_test)
 
343
        super(ExtendedTestResult, self).addError(test, err)
327
344
        self.error_count += 1
328
345
        self.report_error(test, err)
329
346
        if self.stop_early:
330
347
            self.stop()
331
 
        self._cleanupLogFile(test)
332
348
 
333
349
    def addFailure(self, test, err):
334
350
        """Tell result that test failed.
336
352
        Called from the TestCase run() method when the test
337
353
        fails because e.g. an assert() method failed.
338
354
        """
339
 
        self._post_mortem()
340
 
        unittest.TestResult.addFailure(self, test, err)
 
355
        self._post_mortem(self._traceback_from_test)
 
356
        super(ExtendedTestResult, self).addFailure(test, err)
341
357
        self.failure_count += 1
342
358
        self.report_failure(test, err)
343
359
        if self.stop_early:
344
360
            self.stop()
345
 
        self._cleanupLogFile(test)
346
361
 
347
362
    def addSuccess(self, test, details=None):
348
363
        """Tell result that test completed successfully.
356
371
                    self._formatTime(benchmark_time),
357
372
                    test.id()))
358
373
        self.report_success(test)
359
 
        self._cleanupLogFile(test)
360
 
        unittest.TestResult.addSuccess(self, test)
 
374
        super(ExtendedTestResult, self).addSuccess(test)
361
375
        test._log_contents = ''
362
376
 
363
377
    def addExpectedFailure(self, test, err):
386
400
        self.not_applicable_count += 1
387
401
        self.report_not_applicable(test, reason)
388
402
 
389
 
    def _post_mortem(self):
 
403
    def _post_mortem(self, tb=None):
390
404
        """Start a PDB post mortem session."""
391
405
        if os.environ.get('BZR_TEST_PDB', None):
392
 
            import pdb;pdb.post_mortem()
 
406
            import pdb
 
407
            pdb.post_mortem(tb)
393
408
 
394
409
    def progress(self, offset, whence):
395
410
        """The test is adjusting the count of tests to run."""
400
415
        else:
401
416
            raise errors.BzrError("Unknown whence %r" % whence)
402
417
 
403
 
    def report_cleaning_up(self):
404
 
        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)))
405
449
 
406
450
    def startTestRun(self):
407
451
        self.startTime = time.time()
444
488
        self.pb.finished()
445
489
        super(TextTestResult, self).stopTestRun()
446
490
 
447
 
    def startTestRun(self):
448
 
        super(TextTestResult, self).startTestRun()
 
491
    def report_tests_starting(self):
 
492
        super(TextTestResult, self).report_tests_starting()
449
493
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
450
494
 
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
495
    def _progress_prefix_text(self):
457
496
        # the longer this text, the less space we have to show the test
458
497
        # name...
480
519
        return a
481
520
 
482
521
    def report_test_start(self, test):
483
 
        self.count += 1
484
522
        self.pb.update(
485
523
                self._progress_prefix_text()
486
524
                + ' '
513
551
    def report_unsupported(self, test, feature):
514
552
        """test cannot be run because feature is missing."""
515
553
 
516
 
    def report_cleaning_up(self):
517
 
        self.pb.update('Cleaning up')
518
 
 
519
554
 
520
555
class VerboseTestResult(ExtendedTestResult):
521
556
    """Produce long output, with one line per test run plus times"""
528
563
            result = a_string
529
564
        return result.ljust(final_width)
530
565
 
531
 
    def startTestRun(self):
532
 
        super(VerboseTestResult, self).startTestRun()
 
566
    def report_tests_starting(self):
533
567
        self.stream.write('running %d tests...\n' % self.num_tests)
 
568
        super(VerboseTestResult, self).report_tests_starting()
534
569
 
535
570
    def report_test_start(self, test):
536
 
        self.count += 1
537
571
        name = self._shortened_test_description(test)
538
572
        width = osutils.terminal_width()
539
573
        if width is not None:
551
585
        return '%s%s' % (indent, err[1])
552
586
 
553
587
    def report_error(self, test, err):
554
 
        self.stream.writeln('ERROR %s\n%s'
 
588
        self.stream.write('ERROR %s\n%s\n'
555
589
                % (self._testTimeString(test),
556
590
                   self._error_summary(err)))
557
591
 
558
592
    def report_failure(self, test, err):
559
 
        self.stream.writeln(' FAIL %s\n%s'
 
593
        self.stream.write(' FAIL %s\n%s\n'
560
594
                % (self._testTimeString(test),
561
595
                   self._error_summary(err)))
562
596
 
563
597
    def report_known_failure(self, test, err):
564
 
        self.stream.writeln('XFAIL %s\n%s'
 
598
        self.stream.write('XFAIL %s\n%s\n'
565
599
                % (self._testTimeString(test),
566
600
                   self._error_summary(err)))
567
601
 
568
602
    def report_success(self, test):
569
 
        self.stream.writeln('   OK %s' % self._testTimeString(test))
 
603
        self.stream.write('   OK %s\n' % self._testTimeString(test))
570
604
        for bench_called, stats in getattr(test, '_benchcalls', []):
571
 
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
605
            self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
572
606
            stats.pprint(file=self.stream)
573
607
        # flush the stream so that we get smooth output. This verbose mode is
574
608
        # used to show the output in PQM.
575
609
        self.stream.flush()
576
610
 
577
611
    def report_skip(self, test, reason):
578
 
        self.stream.writeln(' SKIP %s\n%s'
 
612
        self.stream.write(' SKIP %s\n%s\n'
579
613
                % (self._testTimeString(test), reason))
580
614
 
581
615
    def report_not_applicable(self, test, reason):
582
 
        self.stream.writeln('  N/A %s\n    %s'
 
616
        self.stream.write('  N/A %s\n    %s\n'
583
617
                % (self._testTimeString(test), reason))
584
618
 
585
619
    def report_unsupported(self, test, feature):
586
620
        """test cannot be run because feature is missing."""
587
 
        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"
588
622
                %(self._testTimeString(test), feature))
589
623
 
590
624
 
619
653
            encode = codec.encode
620
654
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
621
655
        stream.encoding = new_encoding
622
 
        self.stream = unittest._WritelnDecorator(stream)
 
656
        self.stream = stream
623
657
        self.descriptions = descriptions
624
658
        self.verbosity = verbosity
625
659
        self._bench_history = bench_history
749
783
    # XXX: Should probably unify more with CannedInputUIFactory or a
750
784
    # particular configuration of TextUIFactory, or otherwise have a clearer
751
785
    # idea of how they're supposed to be different.
752
 
    # See https://bugs.edge.launchpad.net/bzr/+bug/408213
 
786
    # See https://bugs.launchpad.net/bzr/+bug/408213
753
787
 
754
788
    def __init__(self, stdout=None, stderr=None, stdin=None):
755
789
        if stdin is not None:
789
823
    routine, and to build and check bzr trees.
790
824
 
791
825
    In addition to the usual method of overriding tearDown(), this class also
792
 
    allows subclasses to register functions into the _cleanups list, which is
 
826
    allows subclasses to register cleanup functions via addCleanup, which are
793
827
    run in order as the object is torn down.  It's less likely this will be
794
828
    accidentally overlooked.
795
829
    """
796
830
 
797
 
    _active_threads = None
798
 
    _leaking_threads_tests = 0
799
 
    _first_thread_leaker_id = None
800
 
    _log_file_name = None
 
831
    _log_file = None
801
832
    # record lsprof data when performing benchmark calls.
802
833
    _gather_lsprof_in_benchmarks = False
803
834
 
804
835
    def __init__(self, methodName='testMethod'):
805
836
        super(TestCase, self).__init__(methodName)
806
 
        self._cleanups = []
807
837
        self._directory_isolation = True
808
838
        self.exception_handlers.insert(0,
809
839
            (UnavailableFeature, self._do_unsupported_or_skip))
827
857
        self._track_transports()
828
858
        self._track_locks()
829
859
        self._clear_debug_flags()
830
 
        TestCase._active_threads = threading.activeCount()
831
 
        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)
832
864
 
833
865
    def debug(self):
834
866
        # debug a frame up.
835
867
        import pdb
836
868
        pdb.Pdb().set_trace(sys._getframe().f_back)
837
869
 
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()
 
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]
852
885
 
853
886
    def _clear_debug_flags(self):
854
887
        """Prevent externally set debug flags affecting tests.
865
898
 
866
899
    def _clear_hooks(self):
867
900
        # prevent hooks affecting tests
 
901
        known_hooks = hooks.known_hooks
868
902
        self._preserved_hooks = {}
869
 
        for key, factory in hooks.known_hooks.items():
870
 
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
871
 
            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)
872
905
            self._preserved_hooks[parent] = (name, current_hooks)
873
906
        self.addCleanup(self._restoreHooks)
874
 
        for key, factory in hooks.known_hooks.items():
875
 
            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)
876
909
            setattr(parent, name, factory())
877
910
        # this hook should always be installed
878
911
        request._install_hook()
943
976
 
944
977
    def permit_dir(self, name):
945
978
        """Permit a directory to be used by this test. See permit_url."""
946
 
        name_transport = get_transport(name)
 
979
        name_transport = _mod_transport.get_transport(name)
947
980
        self.permit_url(name)
948
981
        self.permit_url(name_transport.base)
949
982
 
972
1005
            try:
973
1006
                workingtree.WorkingTree.open(path)
974
1007
            except (errors.NotBranchError, errors.NoWorkingTree):
975
 
                return
 
1008
                raise TestSkipped('Needs a working tree of bzr sources')
976
1009
        finally:
977
1010
            self.enable_directory_isolation()
978
1011
 
1028
1061
        self.addCleanup(transport_server.stop_server)
1029
1062
        # Obtain a real transport because if the server supplies a password, it
1030
1063
        # will be hidden from the base on the client side.
1031
 
        t = get_transport(transport_server.get_url())
 
1064
        t = _mod_transport.get_transport(transport_server.get_url())
1032
1065
        # Some transport servers effectively chroot the backing transport;
1033
1066
        # others like SFTPServer don't - users of the transport can walk up the
1034
1067
        # transport to read the entire backing transport. This wouldn't matter
1095
1128
            message += '\n'
1096
1129
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1097
1130
            % (message,
1098
 
               pformat(a), pformat(b)))
 
1131
               pprint.pformat(a), pprint.pformat(b)))
1099
1132
 
1100
1133
    assertEquals = assertEqual
1101
1134
 
1455
1488
 
1456
1489
        The file is removed as the test is torn down.
1457
1490
        """
1458
 
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
1459
 
        self._log_file = os.fdopen(fileno, 'w+')
 
1491
        self._log_file = StringIO()
1460
1492
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
1461
 
        self._log_file_name = name
1462
1493
        self.addCleanup(self._finishLogFile)
1463
1494
 
1464
1495
    def _finishLogFile(self):
1486
1517
        """
1487
1518
        debug.debug_flags.discard('strict_locks')
1488
1519
 
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
1520
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1498
1521
        """Overrides an object attribute restoring it after the test.
1499
1522
 
1524
1547
            'EDITOR': None,
1525
1548
            'BZR_EMAIL': None,
1526
1549
            'BZREMAIL': None, # may still be present in the environment
1527
 
            'EMAIL': None,
 
1550
            'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
1528
1551
            'BZR_PROGRESS_BAR': None,
1529
1552
            'BZR_LOG': None,
1530
1553
            'BZR_PLUGIN_PATH': None,
1583
1606
        """This test has failed for some known reason."""
1584
1607
        raise KnownFailure(reason)
1585
1608
 
 
1609
    def _suppress_log(self):
 
1610
        """Remove the log info from details."""
 
1611
        self.discardDetail('log')
 
1612
 
1586
1613
    def _do_skip(self, result, reason):
 
1614
        self._suppress_log()
1587
1615
        addSkip = getattr(result, 'addSkip', None)
1588
1616
        if not callable(addSkip):
1589
1617
            result.addSuccess(result)
1592
1620
 
1593
1621
    @staticmethod
1594
1622
    def _do_known_failure(self, result, e):
 
1623
        self._suppress_log()
1595
1624
        err = sys.exc_info()
1596
1625
        addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1597
1626
        if addExpectedFailure is not None:
1605
1634
            reason = 'No reason given'
1606
1635
        else:
1607
1636
            reason = e.args[0]
 
1637
        self._suppress_log ()
1608
1638
        addNotApplicable = getattr(result, 'addNotApplicable', None)
1609
1639
        if addNotApplicable is not None:
1610
1640
            result.addNotApplicable(self, reason)
1612
1642
            self._do_skip(result, reason)
1613
1643
 
1614
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
1615
1665
    def _do_unsupported_or_skip(self, result, e):
1616
1666
        reason = e.args[0]
 
1667
        self._suppress_log()
1617
1668
        addNotSupported = getattr(result, 'addNotSupported', None)
1618
1669
        if addNotSupported is not None:
1619
1670
            result.addNotSupported(self, reason)
1666
1717
                unicodestr = self._log_contents.decode('utf8', 'replace')
1667
1718
                self._log_contents = unicodestr.encode('utf8')
1668
1719
            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()
 
1720
        if self._log_file is not None:
 
1721
            log_contents = self._log_file.getvalue()
1679
1722
            try:
1680
1723
                log_contents.decode('utf8')
1681
1724
            except UnicodeDecodeError:
1682
1725
                unicodestr = log_contents.decode('utf8', 'replace')
1683
1726
                log_contents = unicodestr.encode('utf8')
1684
1727
            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
1728
                self._log_file = None
1713
1729
                # Permit multiple calls to get_log until we clean it up in
1714
1730
                # finishLogFile
1715
1731
                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
1732
            return log_contents
1726
1733
        else:
1727
 
            return "No log file content and no log file name."
 
1734
            return "No log file content."
1728
1735
 
1729
1736
    def get_log(self):
1730
1737
        """Get a unicode string containing the log from bzrlib.trace.
1945
1952
            variables. A value of None will unset the env variable.
1946
1953
            The values must be strings. The change will only occur in the
1947
1954
            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.
 
1955
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
 
1956
            doesn't support signalling subprocesses.
1950
1957
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
1951
1958
 
1952
1959
        :returns: Popen object for the started process.
1953
1960
        """
1954
1961
        if skip_if_plan_to_signal:
1955
 
            if not getattr(os, 'kill', None):
1956
 
                raise TestSkipped("os.kill not available.")
 
1962
            if os.name != "posix":
 
1963
                raise TestSkipped("Sending signals not supported")
1957
1964
 
1958
1965
        if env_changes is None:
1959
1966
            env_changes = {}
1986
1993
            if not allow_plugins:
1987
1994
                command.append('--no-plugins')
1988
1995
            command.extend(process_args)
1989
 
            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)
1990
1999
        finally:
1991
2000
            restore_environment()
1992
2001
            if cwd is not None:
2000
2009
        Allows tests to override this method to intercept the calls made to
2001
2010
        Popen for introspection.
2002
2011
        """
2003
 
        return Popen(*args, **kwargs)
 
2012
        return subprocess.Popen(*args, **kwargs)
2004
2013
 
2005
2014
    def get_source_path(self):
2006
2015
        """Return the path of the directory containing bzrlib."""
2008
2017
 
2009
2018
    def get_bzr_path(self):
2010
2019
        """Return the path of the 'bzr' executable for this test suite."""
2011
 
        bzr_path = self.get_source_path()+'/bzr'
 
2020
        bzr_path = os.path.join(self.get_source_path(), "bzr")
2012
2021
        if not os.path.isfile(bzr_path):
2013
2022
            # We are probably installed. Assume sys.argv is the right file
2014
2023
            bzr_path = sys.argv[0]
2186
2195
 
2187
2196
        :param relpath: a path relative to the base url.
2188
2197
        """
2189
 
        t = get_transport(self.get_url(relpath))
 
2198
        t = _mod_transport.get_transport(self.get_url(relpath))
2190
2199
        self.assertFalse(t.is_readonly())
2191
2200
        return t
2192
2201
 
2198
2207
 
2199
2208
        :param relpath: a path relative to the base url.
2200
2209
        """
2201
 
        t = get_transport(self.get_readonly_url(relpath))
 
2210
        t = _mod_transport.get_transport(self.get_readonly_url(relpath))
2202
2211
        self.assertTrue(t.is_readonly())
2203
2212
        return t
2204
2213
 
2334
2343
        propagating. This method ensures than a test did not leaked.
2335
2344
        """
2336
2345
        root = TestCaseWithMemoryTransport.TEST_ROOT
2337
 
        self.permit_url(get_transport(root).base)
 
2346
        self.permit_url(_mod_transport.get_transport(root).base)
2338
2347
        wt = workingtree.WorkingTree.open(root)
2339
2348
        last_rev = wt.last_revision()
2340
2349
        if last_rev != 'null:':
2385
2394
            # might be a relative or absolute path
2386
2395
            maybe_a_url = self.get_url(relpath)
2387
2396
            segments = maybe_a_url.rsplit('/', 1)
2388
 
            t = get_transport(maybe_a_url)
 
2397
            t = _mod_transport.get_transport(maybe_a_url)
2389
2398
            if len(segments) > 1 and segments[-1] not in ('', '.'):
2390
2399
                t.ensure_base()
2391
2400
            if format is None:
2408
2417
        made_control = self.make_bzrdir(relpath, format=format)
2409
2418
        return made_control.create_repository(shared=shared)
2410
2419
 
2411
 
    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()
2412
2423
        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)
 
2424
        self.start_server(smart_server, backing_server)
 
2425
        remote_transport = _mod_transport.get_transport(smart_server.get_url()
 
2426
                                                   ).clone(path)
2415
2427
        return remote_transport
2416
2428
 
2417
2429
    def make_branch_and_memory_tree(self, relpath, format=None):
2432
2444
 
2433
2445
    def setUp(self):
2434
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)
2435
2456
        self._make_test_root()
2436
2457
        self.addCleanup(os.chdir, os.getcwdu())
2437
2458
        self.makeAndChdirToTestDir()
2482
2503
 
2483
2504
    def check_file_contents(self, filename, expect):
2484
2505
        self.log("check contents of file %s" % filename)
2485
 
        contents = file(filename, 'r').read()
 
2506
        f = file(filename)
 
2507
        try:
 
2508
            contents = f.read()
 
2509
        finally:
 
2510
            f.close()
2486
2511
        if contents != expect:
2487
2512
            self.log("expected: %r" % expect)
2488
2513
            self.log("actually: %r" % contents)
2562
2587
                "a list or a tuple. Got %r instead" % (shape,))
2563
2588
        # It's OK to just create them using forward slashes on windows.
2564
2589
        if transport is None or transport.is_readonly():
2565
 
            transport = get_transport(".")
 
2590
            transport = _mod_transport.get_transport(".")
2566
2591
        for name in shape:
2567
2592
            self.assertIsInstance(name, basestring)
2568
2593
            if name[-1] == '/':
2578
2603
                content = "contents of %s%s" % (name.encode('utf-8'), end)
2579
2604
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
2580
2605
 
2581
 
    def build_tree_contents(self, shape):
2582
 
        build_tree_contents(shape)
 
2606
    build_tree_contents = staticmethod(treeshape.build_tree_contents)
2583
2607
 
2584
2608
    def assertInWorkingTree(self, path, root_path='.', tree=None):
2585
2609
        """Assert whether path or paths are in the WorkingTree"""
2726
2750
    """
2727
2751
 
2728
2752
    def setUp(self):
 
2753
        from bzrlib.tests import http_server
2729
2754
        super(ChrootedTestCase, self).setUp()
2730
2755
        if not self.vfs_transport_factory == memory.MemoryServer:
2731
 
            self.transport_readonly_server = HttpServer
 
2756
            self.transport_readonly_server = http_server.HttpServer
2732
2757
 
2733
2758
 
2734
2759
def condition_id_re(pattern):
2737
2762
    :param pattern: A regular expression string.
2738
2763
    :return: A callable that returns True if the re matches.
2739
2764
    """
2740
 
    filter_re = osutils.re_compile_checked(pattern, 0,
2741
 
        'test filter')
 
2765
    filter_re = re.compile(pattern, 0)
2742
2766
    def condition(test):
2743
2767
        test_id = test.id()
2744
2768
        return filter_re.search(test_id)
2996
3020
 
2997
3021
 
2998
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.")
2999
3026
    concurrency = osutils.local_concurrency()
3000
3027
    if concurrency == 1:
3001
3028
        return suite
3056
3083
    return suite
3057
3084
 
3058
3085
 
3059
 
class TestDecorator(TestSuite):
 
3086
class TestDecorator(TestUtil.TestSuite):
3060
3087
    """A decorator for TestCase/TestSuite objects.
3061
3088
    
3062
3089
    Usually, subclasses should override __iter__(used when flattening test
3065
3092
    """
3066
3093
 
3067
3094
    def __init__(self, suite):
3068
 
        TestSuite.__init__(self)
 
3095
        TestUtil.TestSuite.__init__(self)
3069
3096
        self.addTest(suite)
3070
3097
 
3071
3098
    def countTestCases(self):
3190
3217
 
3191
3218
def partition_tests(suite, count):
3192
3219
    """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
 
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
3202
3230
 
3203
3231
 
3204
3232
def workaround_zealous_crypto_random():
3238
3266
 
3239
3267
    test_blocks = partition_tests(suite, concurrency)
3240
3268
    for process_tests in test_blocks:
3241
 
        process_suite = TestSuite()
 
3269
        process_suite = TestUtil.TestSuite()
3242
3270
        process_suite.addTests(process_tests)
3243
3271
        c2pread, c2pwrite = os.pipe()
3244
3272
        pid = os.fork()
3310
3338
                '--subunit']
3311
3339
            if '--no-plugins' in sys.argv:
3312
3340
                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)
 
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)
3317
3347
            test = TestInSubprocess(process, test_list_file_name)
3318
3348
            result.append(test)
3319
3349
        except:
3322
3352
    return result
3323
3353
 
3324
3354
 
3325
 
class ForwardingResult(unittest.TestResult):
3326
 
 
3327
 
    def __init__(self, target):
3328
 
        unittest.TestResult.__init__(self)
3329
 
        self.result = target
3330
 
 
3331
 
    def startTest(self, test):
3332
 
        self.result.startTest(test)
3333
 
 
3334
 
    def stopTest(self, test):
3335
 
        self.result.stopTest(test)
3336
 
 
3337
 
    def startTestRun(self):
3338
 
        self.result.startTestRun()
3339
 
 
3340
 
    def stopTestRun(self):
3341
 
        self.result.stopTestRun()
3342
 
 
3343
 
    def addSkip(self, test, reason):
3344
 
        self.result.addSkip(test, reason)
3345
 
 
3346
 
    def addSuccess(self, test):
3347
 
        self.result.addSuccess(test)
3348
 
 
3349
 
    def addError(self, test, err):
3350
 
        self.result.addError(test, err)
3351
 
 
3352
 
    def addFailure(self, test, err):
3353
 
        self.result.addFailure(test, err)
3354
 
ForwardingResult = testtools.ExtendedToOriginalDecorator
3355
 
 
3356
 
 
3357
 
class ProfileResult(ForwardingResult):
 
3355
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3358
3356
    """Generate profiling data for all activity between start and success.
3359
3357
    
3360
3358
    The profile data is appended to the test's _benchcalls attribute and can
3368
3366
 
3369
3367
    def startTest(self, test):
3370
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
3371
3372
        self.profiler.start()
3372
 
        ForwardingResult.startTest(self, test)
 
3373
        testtools.ExtendedToOriginalDecorator.startTest(self, test)
3373
3374
 
3374
3375
    def addSuccess(self, test):
3375
3376
        stats = self.profiler.stop()
3379
3380
            test._benchcalls = []
3380
3381
            calls = test._benchcalls
3381
3382
        calls.append(((test.id(), "", ""), stats))
3382
 
        ForwardingResult.addSuccess(self, test)
 
3383
        testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
3383
3384
 
3384
3385
    def stopTest(self, test):
3385
 
        ForwardingResult.stopTest(self, test)
 
3386
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
3386
3387
        self.profiler = None
3387
3388
 
3388
3389
 
3394
3395
#                           rather than failing tests. And no longer raise
3395
3396
#                           LockContention when fctnl locks are not being used
3396
3397
#                           with proper exclusion rules.
 
3398
#   -Ethreads               Will display thread ident at creation/join time to
 
3399
#                           help track thread leaks
3397
3400
selftest_debug_flags = set()
3398
3401
 
3399
3402
 
3632
3635
        'bzrlib.doc',
3633
3636
        'bzrlib.tests.blackbox',
3634
3637
        'bzrlib.tests.commands',
 
3638
        'bzrlib.tests.doc_generate',
3635
3639
        'bzrlib.tests.per_branch',
3636
3640
        'bzrlib.tests.per_bzrdir',
3637
 
        'bzrlib.tests.per_bzrdir_colo',
 
3641
        'bzrlib.tests.per_controldir',
 
3642
        'bzrlib.tests.per_controldir_colo',
3638
3643
        'bzrlib.tests.per_foreign_vcs',
3639
3644
        'bzrlib.tests.per_interrepository',
3640
3645
        'bzrlib.tests.per_intertree',
3653
3658
        'bzrlib.tests.per_workingtree',
3654
3659
        'bzrlib.tests.test__annotator',
3655
3660
        'bzrlib.tests.test__bencode',
 
3661
        'bzrlib.tests.test__btree_serializer',
3656
3662
        'bzrlib.tests.test__chk_map',
3657
3663
        'bzrlib.tests.test__dirstate_helpers',
3658
3664
        'bzrlib.tests.test__groupcompress',
3701
3707
        'bzrlib.tests.test_export',
3702
3708
        'bzrlib.tests.test_extract',
3703
3709
        'bzrlib.tests.test_fetch',
 
3710
        'bzrlib.tests.test_fixtures',
3704
3711
        'bzrlib.tests.test_fifo_cache',
3705
3712
        'bzrlib.tests.test_filters',
3706
3713
        'bzrlib.tests.test_ftp_transport',
3727
3734
        'bzrlib.tests.test_knit',
3728
3735
        'bzrlib.tests.test_lazy_import',
3729
3736
        'bzrlib.tests.test_lazy_regex',
 
3737
        'bzrlib.tests.test_library_state',
3730
3738
        'bzrlib.tests.test_lock',
3731
3739
        'bzrlib.tests.test_lockable_files',
3732
3740
        'bzrlib.tests.test_lockdir',
3734
3742
        'bzrlib.tests.test_lru_cache',
3735
3743
        'bzrlib.tests.test_lsprof',
3736
3744
        'bzrlib.tests.test_mail_client',
 
3745
        'bzrlib.tests.test_matchers',
3737
3746
        'bzrlib.tests.test_memorytree',
3738
3747
        'bzrlib.tests.test_merge',
3739
3748
        'bzrlib.tests.test_merge3',
3753
3762
        'bzrlib.tests.test_permissions',
3754
3763
        'bzrlib.tests.test_plugins',
3755
3764
        'bzrlib.tests.test_progress',
 
3765
        'bzrlib.tests.test_pyutils',
3756
3766
        'bzrlib.tests.test_read_bundle',
3757
3767
        'bzrlib.tests.test_reconcile',
3758
3768
        'bzrlib.tests.test_reconfigure',
3767
3777
        'bzrlib.tests.test_rio',
3768
3778
        'bzrlib.tests.test_rules',
3769
3779
        'bzrlib.tests.test_sampler',
 
3780
        'bzrlib.tests.test_scenarios',
3770
3781
        'bzrlib.tests.test_script',
3771
3782
        'bzrlib.tests.test_selftest',
3772
3783
        'bzrlib.tests.test_serializer',
3788
3799
        'bzrlib.tests.test_switch',
3789
3800
        'bzrlib.tests.test_symbol_versioning',
3790
3801
        'bzrlib.tests.test_tag',
 
3802
        'bzrlib.tests.test_test_server',
3791
3803
        'bzrlib.tests.test_testament',
3792
3804
        'bzrlib.tests.test_textfile',
3793
3805
        'bzrlib.tests.test_textmerge',
3799
3811
        'bzrlib.tests.test_transport_log',
3800
3812
        'bzrlib.tests.test_tree',
3801
3813
        'bzrlib.tests.test_treebuilder',
 
3814
        'bzrlib.tests.test_treeshape',
3802
3815
        'bzrlib.tests.test_tsort',
3803
3816
        'bzrlib.tests.test_tuned_gzip',
3804
3817
        'bzrlib.tests.test_ui',
3808
3821
        'bzrlib.tests.test_urlutils',
3809
3822
        'bzrlib.tests.test_version',
3810
3823
        'bzrlib.tests.test_version_info',
 
3824
        'bzrlib.tests.test_versionedfile',
3811
3825
        'bzrlib.tests.test_weave',
3812
3826
        'bzrlib.tests.test_whitebox',
3813
3827
        'bzrlib.tests.test_win32utils',
3833
3847
        'bzrlib.lockdir',
3834
3848
        'bzrlib.merge3',
3835
3849
        'bzrlib.option',
 
3850
        'bzrlib.pyutils',
3836
3851
        'bzrlib.symbol_versioning',
3837
3852
        'bzrlib.tests',
 
3853
        'bzrlib.tests.fixtures',
3838
3854
        'bzrlib.timestamp',
 
3855
        'bzrlib.transport.http',
3839
3856
        'bzrlib.version_info_formats.format_custom',
3840
3857
        ]
3841
3858
 
3944
3961
    return suite
3945
3962
 
3946
3963
 
3947
 
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):
3948
3977
    """Multiply two sets of scenarios.
3949
3978
 
3950
3979
    :returns: the cartesian product of the two sets of scenarios, that is
3981
4010
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
3982
4011
    ...     [('one', dict(param=1)),
3983
4012
    ...      ('two', dict(param=2))],
3984
 
    ...     TestSuite())
 
4013
    ...     TestUtil.TestSuite())
3985
4014
    >>> tests = list(iter_suite_tests(r))
3986
4015
    >>> len(tests)
3987
4016
    2
4034
4063
    :param new_id: The id to assign to it.
4035
4064
    :return: The new test.
4036
4065
    """
4037
 
    new_test = copy(test)
 
4066
    new_test = copy.copy(test)
4038
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 = {}
4039
4080
    return new_test
4040
4081
 
4041
4082
 
4062
4103
        the module is available.
4063
4104
    """
4064
4105
 
4065
 
    py_module = __import__(py_module_name, {}, {}, ['NO_SUCH_ATTRIB'])
 
4106
    py_module = pyutils.get_named_object(py_module_name)
4066
4107
    scenarios = [
4067
4108
        ('python', {'module': py_module}),
4068
4109
    ]
4101
4142
        if test_id != None:
4102
4143
            ui.ui_factory.clear_term()
4103
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')
4104
4148
        sys.stderr.write('Unable to remove testing dir %s\n%s'
4105
 
                         % (os.path.basename(dirname), e))
 
4149
                         % (os.path.basename(dirname), printable_e))
4106
4150
 
4107
4151
 
4108
4152
class Feature(object):
4218
4262
            symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4219
4263
            # Import the new feature and use it as a replacement for the
4220
4264
            # deprecated one.
4221
 
            mod = __import__(self._replacement_module, {}, {},
4222
 
                             [self._replacement_name])
4223
 
            self._feature = getattr(mod, self._replacement_name)
 
4265
            self._feature = pyutils.get_named_object(
 
4266
                self._replacement_module, self._replacement_name)
4224
4267
 
4225
4268
    def _probe(self):
4226
4269
        self._ensure()
4338
4381
UnicodeFilename = _UnicodeFilename()
4339
4382
 
4340
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
 
4341
4395
class _UTF8Filesystem(Feature):
4342
4396
    """Is the filesystem UTF-8?"""
4343
4397
 
4453
4507
try:
4454
4508
    from subunit import TestProtocolClient
4455
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
 
4456
4520
    class SubUnitBzrRunner(TextTestRunner):
4457
4521
        def run(self, test):
4458
4522
            result = AutoTimingTestResultDecorator(
4459
 
                TestProtocolClient(self.stream))
 
4523
                SubUnitBzrProtocolClient(self.stream))
4460
4524
            test.run(result)
4461
4525
            return result
4462
4526
except ImportError: