~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

(gz) Backslash escape selftest output when printing to non-unicode consoles
 (Martin [gz])

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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
53
55
import testtools
54
56
# nb: check this before importing anything else from within it
55
57
_testtools_version = getattr(testtools, '__version__', ())
56
 
if _testtools_version < (0, 9, 2):
57
 
    raise ImportError("need at least testtools 0.9.2: %s is %r"
 
58
if _testtools_version < (0, 9, 5):
 
59
    raise ImportError("need at least testtools 0.9.5: %s is %r"
58
60
        % (testtools.__file__, _testtools_version))
59
61
from testtools import content
60
62
 
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 (
101
103
    deprecated_passed,
102
104
    )
103
105
import bzrlib.trace
104
 
from bzrlib.transport import get_transport, pathfilter
105
 
import bzrlib.transport
106
 
from bzrlib.transport.local import LocalURLServer
107
 
from bzrlib.transport.memory import MemoryServer
108
 
from bzrlib.transport.readonly import ReadonlyServer
 
106
from bzrlib.transport import (
 
107
    memory,
 
108
    pathfilter,
 
109
    )
109
110
from bzrlib.trace import mutter, note
110
 
from bzrlib.tests import TestUtil
111
 
from bzrlib.tests.http_server import HttpServer
112
 
from bzrlib.tests.TestUtil import (
113
 
                          TestSuite,
114
 
                          TestLoader,
115
 
                          )
116
 
from bzrlib.tests.treeshape import build_tree_contents
 
111
from bzrlib.tests import (
 
112
    test_server,
 
113
    TestUtil,
 
114
    treeshape,
 
115
    )
117
116
from bzrlib.ui import NullProgressView
118
117
from bzrlib.ui.text import TextUIFactory
119
118
import bzrlib.version_info_formats.format_custom
120
 
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
121
119
 
122
120
# Mark this python module as being part of the implementation
123
121
# of unittest: this gives us better tracebacks where the last
124
122
# shown frame is the test code, not our assertXYZ.
125
123
__unittest = 1
126
124
 
127
 
default_transport = LocalURLServer
 
125
default_transport = test_server.LocalURLServer
128
126
 
129
127
 
130
128
_unitialized_attr = object()
135
133
SUBUNIT_SEEK_SET = 0
136
134
SUBUNIT_SEEK_CUR = 1
137
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
138
140
 
139
 
class ExtendedTestResult(unittest._TextTestResult):
 
141
class ExtendedTestResult(testtools.TextTestResult):
140
142
    """Accepts, reports and accumulates the results of running tests.
141
143
 
142
144
    Compared to the unittest version this class adds support for
163
165
        :param bench_history: Optionally, a writable file object to accumulate
164
166
            benchmark results.
165
167
        """
166
 
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
 
168
        testtools.TextTestResult.__init__(self, stream)
167
169
        if bench_history is not None:
168
170
            from bzrlib.version import _get_bzr_source_tree
169
171
            src_tree = _get_bzr_source_tree()
190
192
        self.count = 0
191
193
        self._overall_start_time = time.time()
192
194
        self._strict = strict
 
195
        self._first_thread_leaker_id = None
 
196
        self._tests_leaking_threads_count = 0
 
197
        self._traceback_from_test = None
193
198
 
194
199
    def stopTestRun(self):
195
200
        run = self.testsRun
196
201
        actionTaken = "Ran"
197
202
        stopTime = time.time()
198
203
        timeTaken = stopTime - self.startTime
199
 
        self.printErrors()
200
 
        self.stream.writeln(self.separator2)
201
 
        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,
202
210
                            run, run != 1 and "s" or "", timeTaken))
203
 
        self.stream.writeln()
204
211
        if not self.wasSuccessful():
205
212
            self.stream.write("FAILED (")
206
213
            failed, errored = map(len, (self.failures, self.errors))
213
220
                if failed or errored: self.stream.write(", ")
214
221
                self.stream.write("known_failure_count=%d" %
215
222
                    self.known_failure_count)
216
 
            self.stream.writeln(")")
 
223
            self.stream.write(")\n")
217
224
        else:
218
225
            if self.known_failure_count:
219
 
                self.stream.writeln("OK (known_failures=%d)" %
 
226
                self.stream.write("OK (known_failures=%d)\n" %
220
227
                    self.known_failure_count)
221
228
            else:
222
 
                self.stream.writeln("OK")
 
229
                self.stream.write("OK\n")
223
230
        if self.skip_count > 0:
224
231
            skipped = self.skip_count
225
 
            self.stream.writeln('%d test%s skipped' %
 
232
            self.stream.write('%d test%s skipped\n' %
226
233
                                (skipped, skipped != 1 and "s" or ""))
227
234
        if self.unsupported:
228
235
            for feature, count in sorted(self.unsupported.items()):
229
 
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
 
236
                self.stream.write("Missing feature '%s' skipped %d tests.\n" %
230
237
                    (feature, count))
231
238
        if self._strict:
232
239
            ok = self.wasStrictlySuccessful()
233
240
        else:
234
241
            ok = self.wasSuccessful()
235
 
        if TestCase._first_thread_leaker_id:
 
242
        if self._first_thread_leaker_id:
236
243
            self.stream.write(
237
244
                '%s is leaking threads among %d leaking tests.\n' % (
238
 
                TestCase._first_thread_leaker_id,
239
 
                TestCase._leaking_threads_tests))
 
245
                self._first_thread_leaker_id,
 
246
                self._tests_leaking_threads_count))
240
247
            # We don't report the main thread as an active one.
241
248
            self.stream.write(
242
249
                '%d non-main threads were left active in the end.\n'
243
 
                % (TestCase._active_threads - 1))
 
250
                % (len(self._active_threads) - 1))
244
251
 
245
252
    def getDescription(self, test):
246
253
        return test.id()
253
260
 
254
261
    def _elapsedTestTimeString(self):
255
262
        """Return a time string for the overall time the current test has taken."""
256
 
        return self._formatTime(time.time() - self._start_time)
 
263
        return self._formatTime(self._delta_to_float(
 
264
            self._now() - self._start_datetime))
257
265
 
258
266
    def _testTimeString(self, testCase):
259
267
        benchmark_time = self._extractBenchmarkTime(testCase)
270
278
 
271
279
    def _shortened_test_description(self, test):
272
280
        what = test.id()
273
 
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
 
281
        what = re.sub(r'^bzrlib\.tests\.', '', what)
274
282
        return what
275
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
 
276
292
    def startTest(self, test):
277
 
        unittest.TestResult.startTest(self, test)
 
293
        super(ExtendedTestResult, self).startTest(test)
278
294
        if self.count == 0:
279
295
            self.startTests()
 
296
        self.count += 1
280
297
        self.report_test_start(test)
281
298
        test.number = self.count
282
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)
283
308
 
284
309
    def startTests(self):
285
 
        import platform
286
 
        if getattr(sys, 'frozen', None) is None:
287
 
            bzr_path = osutils.realpath(sys.argv[0])
288
 
        else:
289
 
            bzr_path = sys.executable
290
 
        self.stream.write(
291
 
            'bzr selftest: %s\n' % (bzr_path,))
292
 
        self.stream.write(
293
 
            '   %s\n' % (
294
 
                    bzrlib.__path__[0],))
295
 
        self.stream.write(
296
 
            '   bzr-%s python-%s %s\n' % (
297
 
                    bzrlib.version_string,
298
 
                    bzrlib._format_version_tuple(sys.version_info),
299
 
                    platform.platform(aliased=1),
300
 
                    ))
301
 
        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
302
331
 
303
332
    def _recordTestStartTime(self):
304
333
        """Record that a test has started."""
305
 
        self._start_time = time.time()
306
 
 
307
 
    def _cleanupLogFile(self, test):
308
 
        # We can only do this if we have one of our TestCases, not if
309
 
        # we have a doctest.
310
 
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
311
 
        if setKeepLogfile is not None:
312
 
            setKeepLogfile()
 
334
        self._start_datetime = self._now()
313
335
 
314
336
    def addError(self, test, err):
315
337
        """Tell result that test finished with an error.
317
339
        Called from the TestCase run() method when the test
318
340
        fails with an unexpected error.
319
341
        """
320
 
        self._post_mortem()
321
 
        unittest.TestResult.addError(self, test, err)
 
342
        self._post_mortem(self._traceback_from_test)
 
343
        super(ExtendedTestResult, self).addError(test, err)
322
344
        self.error_count += 1
323
345
        self.report_error(test, err)
324
346
        if self.stop_early:
325
347
            self.stop()
326
 
        self._cleanupLogFile(test)
327
348
 
328
349
    def addFailure(self, test, err):
329
350
        """Tell result that test failed.
331
352
        Called from the TestCase run() method when the test
332
353
        fails because e.g. an assert() method failed.
333
354
        """
334
 
        self._post_mortem()
335
 
        unittest.TestResult.addFailure(self, test, err)
 
355
        self._post_mortem(self._traceback_from_test)
 
356
        super(ExtendedTestResult, self).addFailure(test, err)
336
357
        self.failure_count += 1
337
358
        self.report_failure(test, err)
338
359
        if self.stop_early:
339
360
            self.stop()
340
 
        self._cleanupLogFile(test)
341
361
 
342
362
    def addSuccess(self, test, details=None):
343
363
        """Tell result that test completed successfully.
351
371
                    self._formatTime(benchmark_time),
352
372
                    test.id()))
353
373
        self.report_success(test)
354
 
        self._cleanupLogFile(test)
355
 
        unittest.TestResult.addSuccess(self, test)
 
374
        super(ExtendedTestResult, self).addSuccess(test)
356
375
        test._log_contents = ''
357
376
 
358
377
    def addExpectedFailure(self, test, err):
381
400
        self.not_applicable_count += 1
382
401
        self.report_not_applicable(test, reason)
383
402
 
384
 
    def _post_mortem(self):
 
403
    def _post_mortem(self, tb=None):
385
404
        """Start a PDB post mortem session."""
386
405
        if os.environ.get('BZR_TEST_PDB', None):
387
 
            import pdb;pdb.post_mortem()
 
406
            import pdb
 
407
            pdb.post_mortem(tb)
388
408
 
389
409
    def progress(self, offset, whence):
390
410
        """The test is adjusting the count of tests to run."""
395
415
        else:
396
416
            raise errors.BzrError("Unknown whence %r" % whence)
397
417
 
398
 
    def report_cleaning_up(self):
399
 
        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)))
400
449
 
401
450
    def startTestRun(self):
402
451
        self.startTime = time.time()
439
488
        self.pb.finished()
440
489
        super(TextTestResult, self).stopTestRun()
441
490
 
442
 
    def startTestRun(self):
443
 
        super(TextTestResult, self).startTestRun()
 
491
    def report_tests_starting(self):
 
492
        super(TextTestResult, self).report_tests_starting()
444
493
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
445
494
 
446
 
    def printErrors(self):
447
 
        # clear the pb to make room for the error listing
448
 
        self.pb.clear()
449
 
        super(TextTestResult, self).printErrors()
450
 
 
451
495
    def _progress_prefix_text(self):
452
496
        # the longer this text, the less space we have to show the test
453
497
        # name...
475
519
        return a
476
520
 
477
521
    def report_test_start(self, test):
478
 
        self.count += 1
479
522
        self.pb.update(
480
523
                self._progress_prefix_text()
481
524
                + ' '
485
528
        return self._shortened_test_description(test)
486
529
 
487
530
    def report_error(self, test, err):
488
 
        ui.ui_factory.note('ERROR: %s\n    %s\n' % (
 
531
        self.stream.write('ERROR: %s\n    %s\n' % (
489
532
            self._test_description(test),
490
533
            err[1],
491
534
            ))
492
535
 
493
536
    def report_failure(self, test, err):
494
 
        ui.ui_factory.note('FAIL: %s\n    %s\n' % (
 
537
        self.stream.write('FAIL: %s\n    %s\n' % (
495
538
            self._test_description(test),
496
539
            err[1],
497
540
            ))
508
551
    def report_unsupported(self, test, feature):
509
552
        """test cannot be run because feature is missing."""
510
553
 
511
 
    def report_cleaning_up(self):
512
 
        self.pb.update('Cleaning up')
513
 
 
514
554
 
515
555
class VerboseTestResult(ExtendedTestResult):
516
556
    """Produce long output, with one line per test run plus times"""
523
563
            result = a_string
524
564
        return result.ljust(final_width)
525
565
 
526
 
    def startTestRun(self):
527
 
        super(VerboseTestResult, self).startTestRun()
 
566
    def report_tests_starting(self):
528
567
        self.stream.write('running %d tests...\n' % self.num_tests)
 
568
        super(VerboseTestResult, self).report_tests_starting()
529
569
 
530
570
    def report_test_start(self, test):
531
 
        self.count += 1
532
571
        name = self._shortened_test_description(test)
533
572
        width = osutils.terminal_width()
534
573
        if width is not None:
546
585
        return '%s%s' % (indent, err[1])
547
586
 
548
587
    def report_error(self, test, err):
549
 
        self.stream.writeln('ERROR %s\n%s'
 
588
        self.stream.write('ERROR %s\n%s\n'
550
589
                % (self._testTimeString(test),
551
590
                   self._error_summary(err)))
552
591
 
553
592
    def report_failure(self, test, err):
554
 
        self.stream.writeln(' FAIL %s\n%s'
 
593
        self.stream.write(' FAIL %s\n%s\n'
555
594
                % (self._testTimeString(test),
556
595
                   self._error_summary(err)))
557
596
 
558
597
    def report_known_failure(self, test, err):
559
 
        self.stream.writeln('XFAIL %s\n%s'
 
598
        self.stream.write('XFAIL %s\n%s\n'
560
599
                % (self._testTimeString(test),
561
600
                   self._error_summary(err)))
562
601
 
563
602
    def report_success(self, test):
564
 
        self.stream.writeln('   OK %s' % self._testTimeString(test))
 
603
        self.stream.write('   OK %s\n' % self._testTimeString(test))
565
604
        for bench_called, stats in getattr(test, '_benchcalls', []):
566
 
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
605
            self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
567
606
            stats.pprint(file=self.stream)
568
607
        # flush the stream so that we get smooth output. This verbose mode is
569
608
        # used to show the output in PQM.
570
609
        self.stream.flush()
571
610
 
572
611
    def report_skip(self, test, reason):
573
 
        self.stream.writeln(' SKIP %s\n%s'
 
612
        self.stream.write(' SKIP %s\n%s\n'
574
613
                % (self._testTimeString(test), reason))
575
614
 
576
615
    def report_not_applicable(self, test, reason):
577
 
        self.stream.writeln('  N/A %s\n    %s'
 
616
        self.stream.write('  N/A %s\n    %s\n'
578
617
                % (self._testTimeString(test), reason))
579
618
 
580
619
    def report_unsupported(self, test, feature):
581
620
        """test cannot be run because feature is missing."""
582
 
        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"
583
622
                %(self._testTimeString(test), feature))
584
623
 
585
624
 
612
651
            encode = codec[0]
613
652
        else:
614
653
            encode = codec.encode
615
 
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
 
654
        # GZ 2010-09-08: Really we don't want to be writing arbitrary bytes,
 
655
        #                so should swap to the plain codecs.StreamWriter
 
656
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream,
 
657
            "backslashreplace")
616
658
        stream.encoding = new_encoding
617
 
        self.stream = unittest._WritelnDecorator(stream)
 
659
        self.stream = stream
618
660
        self.descriptions = descriptions
619
661
        self.verbosity = verbosity
620
662
        self._bench_history = bench_history
702
744
    """
703
745
 
704
746
 
705
 
class CommandFailed(Exception):
706
 
    pass
707
 
 
708
 
 
709
747
class StringIOWrapper(object):
710
748
    """A wrapper around cStringIO which just adds an encoding attribute.
711
749
 
748
786
    # XXX: Should probably unify more with CannedInputUIFactory or a
749
787
    # particular configuration of TextUIFactory, or otherwise have a clearer
750
788
    # idea of how they're supposed to be different.
751
 
    # See https://bugs.edge.launchpad.net/bzr/+bug/408213
 
789
    # See https://bugs.launchpad.net/bzr/+bug/408213
752
790
 
753
791
    def __init__(self, stdout=None, stderr=None, stdin=None):
754
792
        if stdin is not None:
788
826
    routine, and to build and check bzr trees.
789
827
 
790
828
    In addition to the usual method of overriding tearDown(), this class also
791
 
    allows subclasses to register functions into the _cleanups list, which is
 
829
    allows subclasses to register cleanup functions via addCleanup, which are
792
830
    run in order as the object is torn down.  It's less likely this will be
793
831
    accidentally overlooked.
794
832
    """
795
833
 
796
 
    _active_threads = None
797
 
    _leaking_threads_tests = 0
798
 
    _first_thread_leaker_id = None
799
 
    _log_file_name = None
 
834
    _log_file = None
800
835
    # record lsprof data when performing benchmark calls.
801
836
    _gather_lsprof_in_benchmarks = False
802
837
 
803
838
    def __init__(self, methodName='testMethod'):
804
839
        super(TestCase, self).__init__(methodName)
805
 
        self._cleanups = []
806
840
        self._directory_isolation = True
807
841
        self.exception_handlers.insert(0,
808
842
            (UnavailableFeature, self._do_unsupported_or_skip))
826
860
        self._track_transports()
827
861
        self._track_locks()
828
862
        self._clear_debug_flags()
829
 
        TestCase._active_threads = threading.activeCount()
830
 
        self.addCleanup(self._check_leaked_threads)
 
863
        # Isolate global verbosity level, to make sure it's reproducible
 
864
        # between tests.  We should get rid of this altogether: bug 656694. --
 
865
        # mbp 20101008
 
866
        self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
831
867
 
832
868
    def debug(self):
833
869
        # debug a frame up.
834
870
        import pdb
835
871
        pdb.Pdb().set_trace(sys._getframe().f_back)
836
872
 
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()
 
873
    def discardDetail(self, name):
 
874
        """Extend the addDetail, getDetails api so we can remove a detail.
 
875
 
 
876
        eg. bzr always adds the 'log' detail at startup, but we don't want to
 
877
        include it for skipped, xfail, etc tests.
 
878
 
 
879
        It is safe to call this for a detail that doesn't exist, in case this
 
880
        gets called multiple times.
 
881
        """
 
882
        # We cheat. details is stored in __details which means we shouldn't
 
883
        # touch it. but getDetails() returns the dict directly, so we can
 
884
        # mutate it.
 
885
        details = self.getDetails()
 
886
        if name in details:
 
887
            del details[name]
851
888
 
852
889
    def _clear_debug_flags(self):
853
890
        """Prevent externally set debug flags affecting tests.
864
901
 
865
902
    def _clear_hooks(self):
866
903
        # prevent hooks affecting tests
 
904
        known_hooks = hooks.known_hooks
867
905
        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)
 
906
        for key, (parent, name) in known_hooks.iter_parent_objects():
 
907
            current_hooks = getattr(parent, name)
871
908
            self._preserved_hooks[parent] = (name, current_hooks)
872
909
        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)
 
910
        for key, (parent, name) in known_hooks.iter_parent_objects():
 
911
            factory = known_hooks.get(key)
875
912
            setattr(parent, name, factory())
876
913
        # this hook should always be installed
877
914
        request._install_hook()
942
979
 
943
980
    def permit_dir(self, name):
944
981
        """Permit a directory to be used by this test. See permit_url."""
945
 
        name_transport = get_transport(name)
 
982
        name_transport = _mod_transport.get_transport(name)
946
983
        self.permit_url(name)
947
984
        self.permit_url(name_transport.base)
948
985
 
971
1008
            try:
972
1009
                workingtree.WorkingTree.open(path)
973
1010
            except (errors.NotBranchError, errors.NoWorkingTree):
974
 
                return
 
1011
                raise TestSkipped('Needs a working tree of bzr sources')
975
1012
        finally:
976
1013
            self.enable_directory_isolation()
977
1014
 
1027
1064
        self.addCleanup(transport_server.stop_server)
1028
1065
        # Obtain a real transport because if the server supplies a password, it
1029
1066
        # will be hidden from the base on the client side.
1030
 
        t = get_transport(transport_server.get_url())
 
1067
        t = _mod_transport.get_transport(transport_server.get_url())
1031
1068
        # Some transport servers effectively chroot the backing transport;
1032
1069
        # others like SFTPServer don't - users of the transport can walk up the
1033
1070
        # transport to read the entire backing transport. This wouldn't matter
1044
1081
        if t.base.endswith('/work/'):
1045
1082
            # we have safety net/test root/work
1046
1083
            t = t.clone('../..')
1047
 
        elif isinstance(transport_server, server.SmartTCPServer_for_testing):
 
1084
        elif isinstance(transport_server,
 
1085
                        test_server.SmartTCPServer_for_testing):
1048
1086
            # The smart server adds a path similar to work, which is traversed
1049
1087
            # up from by the client. But the server is chrooted - the actual
1050
1088
            # backing transport is not escaped from, and VFS requests to the
1093
1131
            message += '\n'
1094
1132
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1095
1133
            % (message,
1096
 
               pformat(a), pformat(b)))
 
1134
               pprint.pformat(a), pprint.pformat(b)))
1097
1135
 
1098
1136
    assertEquals = assertEqual
1099
1137
 
1205
1243
            raise AssertionError('pattern "%s" found in "%s"'
1206
1244
                    % (needle_re, haystack))
1207
1245
 
 
1246
    def assertContainsString(self, haystack, needle):
 
1247
        if haystack.find(needle) == -1:
 
1248
            self.fail("string %r not found in '''%s'''" % (needle, haystack))
 
1249
 
1208
1250
    def assertSubset(self, sublist, superlist):
1209
1251
        """Assert that every entry in sublist is present in superlist."""
1210
1252
        missing = set(sublist) - set(superlist)
1307
1349
            f.close()
1308
1350
        self.assertEqualDiff(content, s)
1309
1351
 
 
1352
    def assertDocstring(self, expected_docstring, obj):
 
1353
        """Fail if obj does not have expected_docstring"""
 
1354
        if __doc__ is None:
 
1355
            # With -OO the docstring should be None instead
 
1356
            self.assertIs(obj.__doc__, None)
 
1357
        else:
 
1358
            self.assertEqual(expected_docstring, obj.__doc__)
 
1359
 
1310
1360
    def failUnlessExists(self, path):
1311
1361
        """Fail unless path or paths, which may be abs or relative, exist."""
1312
1362
        if not isinstance(path, basestring):
1441
1491
 
1442
1492
        The file is removed as the test is torn down.
1443
1493
        """
1444
 
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
1445
 
        self._log_file = os.fdopen(fileno, 'w+')
 
1494
        self._log_file = StringIO()
1446
1495
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
1447
 
        self._log_file_name = name
1448
1496
        self.addCleanup(self._finishLogFile)
1449
1497
 
1450
1498
    def _finishLogFile(self):
1472
1520
        """
1473
1521
        debug.debug_flags.discard('strict_locks')
1474
1522
 
1475
 
    def addCleanup(self, callable, *args, **kwargs):
1476
 
        """Arrange to run a callable when this case is torn down.
1477
 
 
1478
 
        Callables are run in the reverse of the order they are registered,
1479
 
        ie last-in first-out.
1480
 
        """
1481
 
        self._cleanups.append((callable, args, kwargs))
1482
 
 
1483
1523
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1484
1524
        """Overrides an object attribute restoring it after the test.
1485
1525
 
1510
1550
            'EDITOR': None,
1511
1551
            'BZR_EMAIL': None,
1512
1552
            'BZREMAIL': None, # may still be present in the environment
1513
 
            'EMAIL': None,
 
1553
            'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
1514
1554
            'BZR_PROGRESS_BAR': None,
1515
1555
            'BZR_LOG': None,
1516
1556
            'BZR_PLUGIN_PATH': None,
 
1557
            'BZR_DISABLE_PLUGINS': None,
 
1558
            'BZR_PLUGINS_AT': None,
1517
1559
            'BZR_CONCURRENCY': None,
1518
1560
            # Make sure that any text ui tests are consistent regardless of
1519
1561
            # the environment the test case is run in; you may want tests that
1540
1582
            'ftp_proxy': None,
1541
1583
            'FTP_PROXY': None,
1542
1584
            'BZR_REMOTE_PATH': None,
 
1585
            # Generally speaking, we don't want apport reporting on crashes in
 
1586
            # the test envirnoment unless we're specifically testing apport,
 
1587
            # so that it doesn't leak into the real system environment.  We
 
1588
            # use an env var so it propagates to subprocesses.
 
1589
            'APPORT_DISABLE': '1',
1543
1590
        }
1544
 
        self.__old_env = {}
 
1591
        self._old_env = {}
1545
1592
        self.addCleanup(self._restoreEnvironment)
1546
1593
        for name, value in new_env.iteritems():
1547
1594
            self._captureVar(name, value)
1548
1595
 
1549
1596
    def _captureVar(self, name, newvalue):
1550
1597
        """Set an environment variable, and reset it when finished."""
1551
 
        self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
 
1598
        self._old_env[name] = osutils.set_or_unset_env(name, newvalue)
1552
1599
 
1553
1600
    def _restoreEnvironment(self):
1554
 
        for name, value in self.__old_env.iteritems():
 
1601
        for name, value in self._old_env.iteritems():
1555
1602
            osutils.set_or_unset_env(name, value)
1556
1603
 
1557
1604
    def _restoreHooks(self):
1562
1609
        """This test has failed for some known reason."""
1563
1610
        raise KnownFailure(reason)
1564
1611
 
 
1612
    def _suppress_log(self):
 
1613
        """Remove the log info from details."""
 
1614
        self.discardDetail('log')
 
1615
 
1565
1616
    def _do_skip(self, result, reason):
 
1617
        self._suppress_log()
1566
1618
        addSkip = getattr(result, 'addSkip', None)
1567
1619
        if not callable(addSkip):
1568
1620
            result.addSuccess(result)
1571
1623
 
1572
1624
    @staticmethod
1573
1625
    def _do_known_failure(self, result, e):
 
1626
        self._suppress_log()
1574
1627
        err = sys.exc_info()
1575
1628
        addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1576
1629
        if addExpectedFailure is not None:
1584
1637
            reason = 'No reason given'
1585
1638
        else:
1586
1639
            reason = e.args[0]
 
1640
        self._suppress_log ()
1587
1641
        addNotApplicable = getattr(result, 'addNotApplicable', None)
1588
1642
        if addNotApplicable is not None:
1589
1643
            result.addNotApplicable(self, reason)
1591
1645
            self._do_skip(result, reason)
1592
1646
 
1593
1647
    @staticmethod
 
1648
    def _report_skip(self, result, err):
 
1649
        """Override the default _report_skip.
 
1650
 
 
1651
        We want to strip the 'log' detail. If we waint until _do_skip, it has
 
1652
        already been formatted into the 'reason' string, and we can't pull it
 
1653
        out again.
 
1654
        """
 
1655
        self._suppress_log()
 
1656
        super(TestCase, self)._report_skip(self, result, err)
 
1657
 
 
1658
    @staticmethod
 
1659
    def _report_expected_failure(self, result, err):
 
1660
        """Strip the log.
 
1661
 
 
1662
        See _report_skip for motivation.
 
1663
        """
 
1664
        self._suppress_log()
 
1665
        super(TestCase, self)._report_expected_failure(self, result, err)
 
1666
 
 
1667
    @staticmethod
1594
1668
    def _do_unsupported_or_skip(self, result, e):
1595
1669
        reason = e.args[0]
 
1670
        self._suppress_log()
1596
1671
        addNotSupported = getattr(result, 'addNotSupported', None)
1597
1672
        if addNotSupported is not None:
1598
1673
            result.addNotSupported(self, reason)
1645
1720
                unicodestr = self._log_contents.decode('utf8', 'replace')
1646
1721
                self._log_contents = unicodestr.encode('utf8')
1647
1722
            return self._log_contents
1648
 
        import bzrlib.trace
1649
 
        if bzrlib.trace._trace_file:
1650
 
            # flush the log file, to get all content
1651
 
            bzrlib.trace._trace_file.flush()
1652
 
        if self._log_file_name is not None:
1653
 
            logfile = open(self._log_file_name)
1654
 
            try:
1655
 
                log_contents = logfile.read()
1656
 
            finally:
1657
 
                logfile.close()
 
1723
        if self._log_file is not None:
 
1724
            log_contents = self._log_file.getvalue()
1658
1725
            try:
1659
1726
                log_contents.decode('utf8')
1660
1727
            except UnicodeDecodeError:
1661
1728
                unicodestr = log_contents.decode('utf8', 'replace')
1662
1729
                log_contents = unicodestr.encode('utf8')
1663
1730
            if not keep_log_file:
1664
 
                self._log_file.close()
1665
1731
                self._log_file = None
1666
1732
                # Permit multiple calls to get_log until we clean it up in
1667
1733
                # finishLogFile
1668
1734
                self._log_contents = log_contents
1669
 
                try:
1670
 
                    os.remove(self._log_file_name)
1671
 
                except OSError, e:
1672
 
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
1673
 
                        sys.stderr.write(('Unable to delete log file '
1674
 
                                             ' %r\n' % self._log_file_name))
1675
 
                    else:
1676
 
                        raise
1677
 
                self._log_file_name = None
1678
1735
            return log_contents
1679
1736
        else:
1680
 
            return "No log file content and no log file name."
 
1737
            return "No log file content."
1681
1738
 
1682
1739
    def get_log(self):
1683
1740
        """Get a unicode string containing the log from bzrlib.trace.
1898
1955
            variables. A value of None will unset the env variable.
1899
1956
            The values must be strings. The change will only occur in the
1900
1957
            child, so you don't need to fix the environment after running.
1901
 
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
1902
 
            is not available.
 
1958
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
 
1959
            doesn't support signalling subprocesses.
1903
1960
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
1904
1961
 
1905
1962
        :returns: Popen object for the started process.
1906
1963
        """
1907
1964
        if skip_if_plan_to_signal:
1908
 
            if not getattr(os, 'kill', None):
1909
 
                raise TestSkipped("os.kill not available.")
 
1965
            if os.name != "posix":
 
1966
                raise TestSkipped("Sending signals not supported")
1910
1967
 
1911
1968
        if env_changes is None:
1912
1969
            env_changes = {}
1939
1996
            if not allow_plugins:
1940
1997
                command.append('--no-plugins')
1941
1998
            command.extend(process_args)
1942
 
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
 
1999
            process = self._popen(command, stdin=subprocess.PIPE,
 
2000
                                  stdout=subprocess.PIPE,
 
2001
                                  stderr=subprocess.PIPE)
1943
2002
        finally:
1944
2003
            restore_environment()
1945
2004
            if cwd is not None:
1953
2012
        Allows tests to override this method to intercept the calls made to
1954
2013
        Popen for introspection.
1955
2014
        """
1956
 
        return Popen(*args, **kwargs)
 
2015
        return subprocess.Popen(*args, **kwargs)
1957
2016
 
1958
2017
    def get_source_path(self):
1959
2018
        """Return the path of the directory containing bzrlib."""
1961
2020
 
1962
2021
    def get_bzr_path(self):
1963
2022
        """Return the path of the 'bzr' executable for this test suite."""
1964
 
        bzr_path = self.get_source_path()+'/bzr'
 
2023
        bzr_path = os.path.join(self.get_source_path(), "bzr")
1965
2024
        if not os.path.isfile(bzr_path):
1966
2025
            # We are probably installed. Assume sys.argv is the right file
1967
2026
            bzr_path = sys.argv[0]
2139
2198
 
2140
2199
        :param relpath: a path relative to the base url.
2141
2200
        """
2142
 
        t = get_transport(self.get_url(relpath))
 
2201
        t = _mod_transport.get_transport(self.get_url(relpath))
2143
2202
        self.assertFalse(t.is_readonly())
2144
2203
        return t
2145
2204
 
2151
2210
 
2152
2211
        :param relpath: a path relative to the base url.
2153
2212
        """
2154
 
        t = get_transport(self.get_readonly_url(relpath))
 
2213
        t = _mod_transport.get_transport(self.get_readonly_url(relpath))
2155
2214
        self.assertTrue(t.is_readonly())
2156
2215
        return t
2157
2216
 
2170
2229
        if self.__readonly_server is None:
2171
2230
            if self.transport_readonly_server is None:
2172
2231
                # readonly decorator requested
2173
 
                self.__readonly_server = ReadonlyServer()
 
2232
                self.__readonly_server = test_server.ReadonlyServer()
2174
2233
            else:
2175
2234
                # explicit readonly transport.
2176
2235
                self.__readonly_server = self.create_transport_readonly_server()
2199
2258
        is no means to override it.
2200
2259
        """
2201
2260
        if self.__vfs_server is None:
2202
 
            self.__vfs_server = MemoryServer()
 
2261
            self.__vfs_server = memory.MemoryServer()
2203
2262
            self.start_server(self.__vfs_server)
2204
2263
        return self.__vfs_server
2205
2264
 
2287
2346
        propagating. This method ensures than a test did not leaked.
2288
2347
        """
2289
2348
        root = TestCaseWithMemoryTransport.TEST_ROOT
2290
 
        self.permit_url(get_transport(root).base)
 
2349
        self.permit_url(_mod_transport.get_transport(root).base)
2291
2350
        wt = workingtree.WorkingTree.open(root)
2292
2351
        last_rev = wt.last_revision()
2293
2352
        if last_rev != 'null:':
2338
2397
            # might be a relative or absolute path
2339
2398
            maybe_a_url = self.get_url(relpath)
2340
2399
            segments = maybe_a_url.rsplit('/', 1)
2341
 
            t = get_transport(maybe_a_url)
 
2400
            t = _mod_transport.get_transport(maybe_a_url)
2342
2401
            if len(segments) > 1 and segments[-1] not in ('', '.'):
2343
2402
                t.ensure_base()
2344
2403
            if format is None:
2361
2420
        made_control = self.make_bzrdir(relpath, format=format)
2362
2421
        return made_control.create_repository(shared=shared)
2363
2422
 
2364
 
    def make_smart_server(self, path):
2365
 
        smart_server = server.SmartTCPServer_for_testing()
2366
 
        self.start_server(smart_server, self.get_server())
2367
 
        remote_transport = get_transport(smart_server.get_url()).clone(path)
 
2423
    def make_smart_server(self, path, backing_server=None):
 
2424
        if backing_server is None:
 
2425
            backing_server = self.get_server()
 
2426
        smart_server = test_server.SmartTCPServer_for_testing()
 
2427
        self.start_server(smart_server, backing_server)
 
2428
        remote_transport = _mod_transport.get_transport(smart_server.get_url()
 
2429
                                                   ).clone(path)
2368
2430
        return remote_transport
2369
2431
 
2370
2432
    def make_branch_and_memory_tree(self, relpath, format=None):
2385
2447
 
2386
2448
    def setUp(self):
2387
2449
        super(TestCaseWithMemoryTransport, self).setUp()
 
2450
        # Ensure that ConnectedTransport doesn't leak sockets
 
2451
        def get_transport_with_cleanup(*args, **kwargs):
 
2452
            t = orig_get_transport(*args, **kwargs)
 
2453
            if isinstance(t, _mod_transport.ConnectedTransport):
 
2454
                self.addCleanup(t.disconnect)
 
2455
            return t
 
2456
 
 
2457
        orig_get_transport = self.overrideAttr(_mod_transport, '_get_transport',
 
2458
                                               get_transport_with_cleanup)
2388
2459
        self._make_test_root()
2389
2460
        self.addCleanup(os.chdir, os.getcwdu())
2390
2461
        self.makeAndChdirToTestDir()
2395
2466
 
2396
2467
    def setup_smart_server_with_call_log(self):
2397
2468
        """Sets up a smart server as the transport server with a call log."""
2398
 
        self.transport_server = server.SmartTCPServer_for_testing
 
2469
        self.transport_server = test_server.SmartTCPServer_for_testing
2399
2470
        self.hpss_calls = []
2400
2471
        import traceback
2401
2472
        # Skip the current stack down to the caller of
2435
2506
 
2436
2507
    def check_file_contents(self, filename, expect):
2437
2508
        self.log("check contents of file %s" % filename)
2438
 
        contents = file(filename, 'r').read()
 
2509
        f = file(filename)
 
2510
        try:
 
2511
            contents = f.read()
 
2512
        finally:
 
2513
            f.close()
2439
2514
        if contents != expect:
2440
2515
            self.log("expected: %r" % expect)
2441
2516
            self.log("actually: %r" % contents)
2515
2590
                "a list or a tuple. Got %r instead" % (shape,))
2516
2591
        # It's OK to just create them using forward slashes on windows.
2517
2592
        if transport is None or transport.is_readonly():
2518
 
            transport = get_transport(".")
 
2593
            transport = _mod_transport.get_transport(".")
2519
2594
        for name in shape:
2520
2595
            self.assertIsInstance(name, basestring)
2521
2596
            if name[-1] == '/':
2531
2606
                content = "contents of %s%s" % (name.encode('utf-8'), end)
2532
2607
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
2533
2608
 
2534
 
    def build_tree_contents(self, shape):
2535
 
        build_tree_contents(shape)
 
2609
    build_tree_contents = staticmethod(treeshape.build_tree_contents)
2536
2610
 
2537
2611
    def assertInWorkingTree(self, path, root_path='.', tree=None):
2538
2612
        """Assert whether path or paths are in the WorkingTree"""
2614
2688
            # We can only make working trees locally at the moment.  If the
2615
2689
            # transport can't support them, then we keep the non-disk-backed
2616
2690
            # branch and create a local checkout.
2617
 
            if self.vfs_transport_factory is LocalURLServer:
 
2691
            if self.vfs_transport_factory is test_server.LocalURLServer:
2618
2692
                # the branch is colocated on disk, we cannot create a checkout.
2619
2693
                # hopefully callers will expect this.
2620
2694
                local_controldir= bzrdir.BzrDir.open(self.get_vfs_only_url(relpath))
2679
2753
    """
2680
2754
 
2681
2755
    def setUp(self):
 
2756
        from bzrlib.tests import http_server
2682
2757
        super(ChrootedTestCase, self).setUp()
2683
 
        if not self.vfs_transport_factory == MemoryServer:
2684
 
            self.transport_readonly_server = HttpServer
 
2758
        if not self.vfs_transport_factory == memory.MemoryServer:
 
2759
            self.transport_readonly_server = http_server.HttpServer
2685
2760
 
2686
2761
 
2687
2762
def condition_id_re(pattern):
2690
2765
    :param pattern: A regular expression string.
2691
2766
    :return: A callable that returns True if the re matches.
2692
2767
    """
2693
 
    filter_re = osutils.re_compile_checked(pattern, 0,
2694
 
        'test filter')
 
2768
    filter_re = re.compile(pattern, 0)
2695
2769
    def condition(test):
2696
2770
        test_id = test.id()
2697
2771
        return filter_re.search(test_id)
2949
3023
 
2950
3024
 
2951
3025
def fork_decorator(suite):
 
3026
    if getattr(os, "fork", None) is None:
 
3027
        raise errors.BzrCommandError("platform does not support fork,"
 
3028
            " try --parallel=subprocess instead.")
2952
3029
    concurrency = osutils.local_concurrency()
2953
3030
    if concurrency == 1:
2954
3031
        return suite
3009
3086
    return suite
3010
3087
 
3011
3088
 
3012
 
class TestDecorator(TestSuite):
 
3089
class TestDecorator(TestUtil.TestSuite):
3013
3090
    """A decorator for TestCase/TestSuite objects.
3014
3091
    
3015
3092
    Usually, subclasses should override __iter__(used when flattening test
3018
3095
    """
3019
3096
 
3020
3097
    def __init__(self, suite):
3021
 
        TestSuite.__init__(self)
 
3098
        TestUtil.TestSuite.__init__(self)
3022
3099
        self.addTest(suite)
3023
3100
 
3024
3101
    def countTestCases(self):
3143
3220
 
3144
3221
def partition_tests(suite, count):
3145
3222
    """Partition suite into count lists of tests."""
3146
 
    result = []
3147
 
    tests = list(iter_suite_tests(suite))
3148
 
    tests_per_process = int(math.ceil(float(len(tests)) / count))
3149
 
    for block in range(count):
3150
 
        low_test = block * tests_per_process
3151
 
        high_test = low_test + tests_per_process
3152
 
        process_tests = tests[low_test:high_test]
3153
 
        result.append(process_tests)
3154
 
    return result
 
3223
    # This just assigns tests in a round-robin fashion.  On one hand this
 
3224
    # splits up blocks of related tests that might run faster if they shared
 
3225
    # resources, but on the other it avoids assigning blocks of slow tests to
 
3226
    # just one partition.  So the slowest partition shouldn't be much slower
 
3227
    # than the fastest.
 
3228
    partitions = [list() for i in range(count)]
 
3229
    tests = iter_suite_tests(suite)
 
3230
    for partition, test in itertools.izip(itertools.cycle(partitions), tests):
 
3231
        partition.append(test)
 
3232
    return partitions
 
3233
 
 
3234
 
 
3235
def workaround_zealous_crypto_random():
 
3236
    """Crypto.Random want to help us being secure, but we don't care here.
 
3237
 
 
3238
    This workaround some test failure related to the sftp server. Once paramiko
 
3239
    stop using the controversial API in Crypto.Random, we may get rid of it.
 
3240
    """
 
3241
    try:
 
3242
        from Crypto.Random import atfork
 
3243
        atfork()
 
3244
    except ImportError:
 
3245
        pass
3155
3246
 
3156
3247
 
3157
3248
def fork_for_tests(suite):
3174
3265
            try:
3175
3266
                ProtocolTestCase.run(self, result)
3176
3267
            finally:
3177
 
                os.waitpid(self.pid, os.WNOHANG)
 
3268
                os.waitpid(self.pid, 0)
3178
3269
 
3179
3270
    test_blocks = partition_tests(suite, concurrency)
3180
3271
    for process_tests in test_blocks:
3181
 
        process_suite = TestSuite()
 
3272
        process_suite = TestUtil.TestSuite()
3182
3273
        process_suite.addTests(process_tests)
3183
3274
        c2pread, c2pwrite = os.pipe()
3184
3275
        pid = os.fork()
3185
3276
        if pid == 0:
 
3277
            workaround_zealous_crypto_random()
3186
3278
            try:
3187
3279
                os.close(c2pread)
3188
3280
                # Leave stderr and stdout open so we can see test noise
3249
3341
                '--subunit']
3250
3342
            if '--no-plugins' in sys.argv:
3251
3343
                argv.append('--no-plugins')
3252
 
            # stderr=STDOUT would be ideal, but until we prevent noise on
3253
 
            # stderr it can interrupt the subunit protocol.
3254
 
            process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
3255
 
                bufsize=1)
 
3344
            # stderr=subprocess.STDOUT would be ideal, but until we prevent
 
3345
            # noise on stderr it can interrupt the subunit protocol.
 
3346
            process = subprocess.Popen(argv, stdin=subprocess.PIPE,
 
3347
                                      stdout=subprocess.PIPE,
 
3348
                                      stderr=subprocess.PIPE,
 
3349
                                      bufsize=1)
3256
3350
            test = TestInSubprocess(process, test_list_file_name)
3257
3351
            result.append(test)
3258
3352
        except:
3261
3355
    return result
3262
3356
 
3263
3357
 
3264
 
class ForwardingResult(unittest.TestResult):
3265
 
 
3266
 
    def __init__(self, target):
3267
 
        unittest.TestResult.__init__(self)
3268
 
        self.result = target
3269
 
 
3270
 
    def startTest(self, test):
3271
 
        self.result.startTest(test)
3272
 
 
3273
 
    def stopTest(self, test):
3274
 
        self.result.stopTest(test)
3275
 
 
3276
 
    def startTestRun(self):
3277
 
        self.result.startTestRun()
3278
 
 
3279
 
    def stopTestRun(self):
3280
 
        self.result.stopTestRun()
3281
 
 
3282
 
    def addSkip(self, test, reason):
3283
 
        self.result.addSkip(test, reason)
3284
 
 
3285
 
    def addSuccess(self, test):
3286
 
        self.result.addSuccess(test)
3287
 
 
3288
 
    def addError(self, test, err):
3289
 
        self.result.addError(test, err)
3290
 
 
3291
 
    def addFailure(self, test, err):
3292
 
        self.result.addFailure(test, err)
3293
 
ForwardingResult = testtools.ExtendedToOriginalDecorator
3294
 
 
3295
 
 
3296
 
class ProfileResult(ForwardingResult):
 
3358
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3297
3359
    """Generate profiling data for all activity between start and success.
3298
3360
    
3299
3361
    The profile data is appended to the test's _benchcalls attribute and can
3307
3369
 
3308
3370
    def startTest(self, test):
3309
3371
        self.profiler = bzrlib.lsprof.BzrProfiler()
 
3372
        # Prevent deadlocks in tests that use lsprof: those tests will
 
3373
        # unavoidably fail.
 
3374
        bzrlib.lsprof.BzrProfiler.profiler_block = 0
3310
3375
        self.profiler.start()
3311
 
        ForwardingResult.startTest(self, test)
 
3376
        testtools.ExtendedToOriginalDecorator.startTest(self, test)
3312
3377
 
3313
3378
    def addSuccess(self, test):
3314
3379
        stats = self.profiler.stop()
3318
3383
            test._benchcalls = []
3319
3384
            calls = test._benchcalls
3320
3385
        calls.append(((test.id(), "", ""), stats))
3321
 
        ForwardingResult.addSuccess(self, test)
 
3386
        testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
3322
3387
 
3323
3388
    def stopTest(self, test):
3324
 
        ForwardingResult.stopTest(self, test)
 
3389
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
3325
3390
        self.profiler = None
3326
3391
 
3327
3392
 
3333
3398
#                           rather than failing tests. And no longer raise
3334
3399
#                           LockContention when fctnl locks are not being used
3335
3400
#                           with proper exclusion rules.
 
3401
#   -Ethreads               Will display thread ident at creation/join time to
 
3402
#                           help track thread leaks
3336
3403
selftest_debug_flags = set()
3337
3404
 
3338
3405
 
3557
3624
# appear prefixed ('bzrlib.' is "replaced" by 'bzrlib.').
3558
3625
test_prefix_alias_registry.register('bzrlib', 'bzrlib')
3559
3626
 
3560
 
# Obvious higest levels prefixes, feel free to add your own via a plugin
 
3627
# Obvious highest levels prefixes, feel free to add your own via a plugin
3561
3628
test_prefix_alias_registry.register('bd', 'bzrlib.doc')
3562
3629
test_prefix_alias_registry.register('bu', 'bzrlib.utils')
3563
3630
test_prefix_alias_registry.register('bt', 'bzrlib.tests')
3571
3638
        'bzrlib.doc',
3572
3639
        'bzrlib.tests.blackbox',
3573
3640
        'bzrlib.tests.commands',
 
3641
        'bzrlib.tests.doc_generate',
3574
3642
        'bzrlib.tests.per_branch',
3575
3643
        'bzrlib.tests.per_bzrdir',
 
3644
        'bzrlib.tests.per_controldir',
 
3645
        'bzrlib.tests.per_controldir_colo',
3576
3646
        'bzrlib.tests.per_foreign_vcs',
3577
3647
        'bzrlib.tests.per_interrepository',
3578
3648
        'bzrlib.tests.per_intertree',
3591
3661
        'bzrlib.tests.per_workingtree',
3592
3662
        'bzrlib.tests.test__annotator',
3593
3663
        'bzrlib.tests.test__bencode',
 
3664
        'bzrlib.tests.test__btree_serializer',
3594
3665
        'bzrlib.tests.test__chk_map',
3595
3666
        'bzrlib.tests.test__dirstate_helpers',
3596
3667
        'bzrlib.tests.test__groupcompress',
3618
3689
        'bzrlib.tests.test_chunk_writer',
3619
3690
        'bzrlib.tests.test_clean_tree',
3620
3691
        'bzrlib.tests.test_cleanup',
 
3692
        'bzrlib.tests.test_cmdline',
3621
3693
        'bzrlib.tests.test_commands',
3622
3694
        'bzrlib.tests.test_commit',
3623
3695
        'bzrlib.tests.test_commit_merge',
3638
3710
        'bzrlib.tests.test_export',
3639
3711
        'bzrlib.tests.test_extract',
3640
3712
        'bzrlib.tests.test_fetch',
 
3713
        'bzrlib.tests.test_fixtures',
3641
3714
        'bzrlib.tests.test_fifo_cache',
3642
3715
        'bzrlib.tests.test_filters',
3643
3716
        'bzrlib.tests.test_ftp_transport',
3657
3730
        'bzrlib.tests.test_identitymap',
3658
3731
        'bzrlib.tests.test_ignores',
3659
3732
        'bzrlib.tests.test_index',
 
3733
        'bzrlib.tests.test_import_tariff',
3660
3734
        'bzrlib.tests.test_info',
3661
3735
        'bzrlib.tests.test_inv',
3662
3736
        'bzrlib.tests.test_inventory_delta',
3663
3737
        'bzrlib.tests.test_knit',
3664
3738
        'bzrlib.tests.test_lazy_import',
3665
3739
        'bzrlib.tests.test_lazy_regex',
 
3740
        'bzrlib.tests.test_library_state',
3666
3741
        'bzrlib.tests.test_lock',
3667
3742
        'bzrlib.tests.test_lockable_files',
3668
3743
        'bzrlib.tests.test_lockdir',
3670
3745
        'bzrlib.tests.test_lru_cache',
3671
3746
        'bzrlib.tests.test_lsprof',
3672
3747
        'bzrlib.tests.test_mail_client',
 
3748
        'bzrlib.tests.test_matchers',
3673
3749
        'bzrlib.tests.test_memorytree',
3674
3750
        'bzrlib.tests.test_merge',
3675
3751
        'bzrlib.tests.test_merge3',
3689
3765
        'bzrlib.tests.test_permissions',
3690
3766
        'bzrlib.tests.test_plugins',
3691
3767
        'bzrlib.tests.test_progress',
 
3768
        'bzrlib.tests.test_pyutils',
3692
3769
        'bzrlib.tests.test_read_bundle',
3693
3770
        'bzrlib.tests.test_reconcile',
3694
3771
        'bzrlib.tests.test_reconfigure',
3703
3780
        'bzrlib.tests.test_rio',
3704
3781
        'bzrlib.tests.test_rules',
3705
3782
        'bzrlib.tests.test_sampler',
 
3783
        'bzrlib.tests.test_scenarios',
3706
3784
        'bzrlib.tests.test_script',
3707
3785
        'bzrlib.tests.test_selftest',
3708
3786
        'bzrlib.tests.test_serializer',
3724
3802
        'bzrlib.tests.test_switch',
3725
3803
        'bzrlib.tests.test_symbol_versioning',
3726
3804
        'bzrlib.tests.test_tag',
 
3805
        'bzrlib.tests.test_test_server',
3727
3806
        'bzrlib.tests.test_testament',
3728
3807
        'bzrlib.tests.test_textfile',
3729
3808
        'bzrlib.tests.test_textmerge',
3735
3814
        'bzrlib.tests.test_transport_log',
3736
3815
        'bzrlib.tests.test_tree',
3737
3816
        'bzrlib.tests.test_treebuilder',
 
3817
        'bzrlib.tests.test_treeshape',
3738
3818
        'bzrlib.tests.test_tsort',
3739
3819
        'bzrlib.tests.test_tuned_gzip',
3740
3820
        'bzrlib.tests.test_ui',
3744
3824
        'bzrlib.tests.test_urlutils',
3745
3825
        'bzrlib.tests.test_version',
3746
3826
        'bzrlib.tests.test_version_info',
 
3827
        'bzrlib.tests.test_versionedfile',
3747
3828
        'bzrlib.tests.test_weave',
3748
3829
        'bzrlib.tests.test_whitebox',
3749
3830
        'bzrlib.tests.test_win32utils',
3755
3836
 
3756
3837
 
3757
3838
def _test_suite_modules_to_doctest():
3758
 
    """Return the list of modules to doctest."""   
 
3839
    """Return the list of modules to doctest."""
 
3840
    if __doc__ is None:
 
3841
        # GZ 2009-03-31: No docstrings with -OO so there's nothing to doctest
 
3842
        return []
3759
3843
    return [
3760
3844
        'bzrlib',
3761
3845
        'bzrlib.branchbuilder',
3766
3850
        'bzrlib.lockdir',
3767
3851
        'bzrlib.merge3',
3768
3852
        'bzrlib.option',
 
3853
        'bzrlib.pyutils',
3769
3854
        'bzrlib.symbol_versioning',
3770
3855
        'bzrlib.tests',
 
3856
        'bzrlib.tests.fixtures',
3771
3857
        'bzrlib.timestamp',
 
3858
        'bzrlib.transport.http',
3772
3859
        'bzrlib.version_info_formats.format_custom',
3773
3860
        ]
3774
3861
 
3877
3964
    return suite
3878
3965
 
3879
3966
 
3880
 
def multiply_scenarios(scenarios_left, scenarios_right):
 
3967
def multiply_scenarios(*scenarios):
 
3968
    """Multiply two or more iterables of scenarios.
 
3969
 
 
3970
    It is safe to pass scenario generators or iterators.
 
3971
 
 
3972
    :returns: A list of compound scenarios: the cross-product of all 
 
3973
        scenarios, with the names concatenated and the parameters
 
3974
        merged together.
 
3975
    """
 
3976
    return reduce(_multiply_two_scenarios, map(list, scenarios))
 
3977
 
 
3978
 
 
3979
def _multiply_two_scenarios(scenarios_left, scenarios_right):
3881
3980
    """Multiply two sets of scenarios.
3882
3981
 
3883
3982
    :returns: the cartesian product of the two sets of scenarios, that is
3914
4013
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
3915
4014
    ...     [('one', dict(param=1)),
3916
4015
    ...      ('two', dict(param=2))],
3917
 
    ...     TestSuite())
 
4016
    ...     TestUtil.TestSuite())
3918
4017
    >>> tests = list(iter_suite_tests(r))
3919
4018
    >>> len(tests)
3920
4019
    2
3967
4066
    :param new_id: The id to assign to it.
3968
4067
    :return: The new test.
3969
4068
    """
3970
 
    new_test = copy(test)
 
4069
    new_test = copy.copy(test)
3971
4070
    new_test.id = lambda: new_id
 
4071
    # XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
 
4072
    # causes cloned tests to share the 'details' dict.  This makes it hard to
 
4073
    # read the test output for parameterized tests, because tracebacks will be
 
4074
    # associated with irrelevant tests.
 
4075
    try:
 
4076
        details = new_test._TestCase__details
 
4077
    except AttributeError:
 
4078
        # must be a different version of testtools than expected.  Do nothing.
 
4079
        pass
 
4080
    else:
 
4081
        # Reset the '__details' dict.
 
4082
        new_test._TestCase__details = {}
3972
4083
    return new_test
3973
4084
 
3974
4085
 
3995
4106
        the module is available.
3996
4107
    """
3997
4108
 
3998
 
    py_module = __import__(py_module_name, {}, {}, ['NO_SUCH_ATTRIB'])
 
4109
    py_module = pyutils.get_named_object(py_module_name)
3999
4110
    scenarios = [
4000
4111
        ('python', {'module': py_module}),
4001
4112
    ]
4034
4145
        if test_id != None:
4035
4146
            ui.ui_factory.clear_term()
4036
4147
            sys.stderr.write('\nWhile running: %s\n' % (test_id,))
 
4148
        # Ugly, but the last thing we want here is fail, so bear with it.
 
4149
        printable_e = str(e).decode(osutils.get_user_encoding(), 'replace'
 
4150
                                    ).encode('ascii', 'replace')
4037
4151
        sys.stderr.write('Unable to remove testing dir %s\n%s'
4038
 
                         % (os.path.basename(dirname), e))
 
4152
                         % (os.path.basename(dirname), printable_e))
4039
4153
 
4040
4154
 
4041
4155
class Feature(object):
4130
4244
    should really use a different feature.
4131
4245
    """
4132
4246
 
4133
 
    def __init__(self, module, name, this_name, dep_version):
 
4247
    def __init__(self, dep_version, module, name,
 
4248
                 replacement_name, replacement_module=None):
4134
4249
        super(_CompatabilityThunkFeature, self).__init__()
4135
4250
        self._module = module
 
4251
        if replacement_module is None:
 
4252
            replacement_module = module
 
4253
        self._replacement_module = replacement_module
4136
4254
        self._name = name
4137
 
        self._this_name = this_name
 
4255
        self._replacement_name = replacement_name
4138
4256
        self._dep_version = dep_version
4139
4257
        self._feature = None
4140
4258
 
4141
4259
    def _ensure(self):
4142
4260
        if self._feature is None:
4143
 
            msg = (self._dep_version % self._this_name) + (
4144
 
                   ' Use %s.%s instead.' % (self._module, self._name))
4145
 
            symbol_versioning.warn(msg, DeprecationWarning)
4146
 
            mod = __import__(self._module, {}, {}, [self._name])
4147
 
            self._feature = getattr(mod, self._name)
 
4261
            depr_msg = self._dep_version % ('%s.%s'
 
4262
                                            % (self._module, self._name))
 
4263
            use_msg = ' Use %s.%s instead.' % (self._replacement_module,
 
4264
                                               self._replacement_name)
 
4265
            symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
 
4266
            # Import the new feature and use it as a replacement for the
 
4267
            # deprecated one.
 
4268
            self._feature = pyutils.get_named_object(
 
4269
                self._replacement_module, self._replacement_name)
4148
4270
 
4149
4271
    def _probe(self):
4150
4272
        self._ensure()
4176
4298
        if self.available(): # Make sure the probe has been done
4177
4299
            return self._module
4178
4300
        return None
4179
 
    
 
4301
 
4180
4302
    def feature_name(self):
4181
4303
        return self.module_name
4182
4304
 
4183
4305
 
4184
4306
# This is kept here for compatibility, it is recommended to use
4185
4307
# 'bzrlib.tests.feature.paramiko' instead
4186
 
ParamikoFeature = _CompatabilityThunkFeature('bzrlib.tests.features',
4187
 
    'paramiko', 'bzrlib.tests.ParamikoFeature', deprecated_in((2,1,0)))
 
4308
ParamikoFeature = _CompatabilityThunkFeature(
 
4309
    deprecated_in((2,1,0)),
 
4310
    'bzrlib.tests.features', 'ParamikoFeature', 'paramiko')
4188
4311
 
4189
4312
 
4190
4313
def probe_unicode_in_user_encoding():
4261
4384
UnicodeFilename = _UnicodeFilename()
4262
4385
 
4263
4386
 
 
4387
class _ByteStringNamedFilesystem(Feature):
 
4388
    """Is the filesystem based on bytes?"""
 
4389
 
 
4390
    def _probe(self):
 
4391
        if os.name == "posix":
 
4392
            return True
 
4393
        return False
 
4394
 
 
4395
ByteStringNamedFilesystem = _ByteStringNamedFilesystem()
 
4396
 
 
4397
 
4264
4398
class _UTF8Filesystem(Feature):
4265
4399
    """Is the filesystem UTF-8?"""
4266
4400
 
4351
4485
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
4352
4486
 
4353
4487
 
 
4488
class _CaseSensitiveFilesystemFeature(Feature):
 
4489
 
 
4490
    def _probe(self):
 
4491
        if CaseInsCasePresFilenameFeature.available():
 
4492
            return False
 
4493
        elif CaseInsensitiveFilesystemFeature.available():
 
4494
            return False
 
4495
        else:
 
4496
            return True
 
4497
 
 
4498
    def feature_name(self):
 
4499
        return 'case-sensitive filesystem'
 
4500
 
 
4501
# new coding style is for feature instances to be lowercase
 
4502
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
 
4503
 
 
4504
 
4354
4505
# Kept for compatibility, use bzrlib.tests.features.subunit instead
4355
 
SubUnitFeature = _CompatabilityThunkFeature('bzrlib.tests.features', 'subunit',
4356
 
    'bzrlib.tests.SubUnitFeature', deprecated_in((2,1,0)))
 
4506
SubUnitFeature = _CompatabilityThunkFeature(
 
4507
    deprecated_in((2,1,0)),
 
4508
    'bzrlib.tests.features', 'SubUnitFeature', 'subunit')
4357
4509
# Only define SubUnitBzrRunner if subunit is available.
4358
4510
try:
4359
4511
    from subunit import TestProtocolClient
4360
4512
    from subunit.test_results import AutoTimingTestResultDecorator
 
4513
    class SubUnitBzrProtocolClient(TestProtocolClient):
 
4514
 
 
4515
        def addSuccess(self, test, details=None):
 
4516
            # The subunit client always includes the details in the subunit
 
4517
            # stream, but we don't want to include it in ours.
 
4518
            if details is not None and 'log' in details:
 
4519
                del details['log']
 
4520
            return super(SubUnitBzrProtocolClient, self).addSuccess(
 
4521
                test, details)
 
4522
 
4361
4523
    class SubUnitBzrRunner(TextTestRunner):
4362
4524
        def run(self, test):
4363
4525
            result = AutoTimingTestResultDecorator(
4364
 
                TestProtocolClient(self.stream))
 
4526
                SubUnitBzrProtocolClient(self.stream))
4365
4527
            test.run(result)
4366
4528
            return result
4367
4529
except ImportError:
4368
4530
    pass
 
4531
 
 
4532
class _PosixPermissionsFeature(Feature):
 
4533
 
 
4534
    def _probe(self):
 
4535
        def has_perms():
 
4536
            # create temporary file and check if specified perms are maintained.
 
4537
            import tempfile
 
4538
 
 
4539
            write_perms = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
 
4540
            f = tempfile.mkstemp(prefix='bzr_perms_chk_')
 
4541
            fd, name = f
 
4542
            os.close(fd)
 
4543
            os.chmod(name, write_perms)
 
4544
 
 
4545
            read_perms = os.stat(name).st_mode & 0777
 
4546
            os.unlink(name)
 
4547
            return (write_perms == read_perms)
 
4548
 
 
4549
        return (os.name == 'posix') and has_perms()
 
4550
 
 
4551
    def feature_name(self):
 
4552
        return 'POSIX permissions support'
 
4553
 
 
4554
posix_permissions_feature = _PosixPermissionsFeature()