~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Robert Collins
  • Date: 2009-12-16 22:29:31 UTC
  • mto: This revision was merged to the branch mainline in revision 4920.
  • Revision ID: robertc@robertcollins.net-20091216222931-wbbn5ey4mwmpatwd
Review feedback.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 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
# TODO: Perhaps there should be an API to find out if bzr running under the
 
19
# test suite -- some plugins might want to avoid making intrusive changes if
 
20
# this is the case.  However, we want behaviour under to test to diverge as
 
21
# little as possible, so this should be used rarely if it's added at all.
 
22
# (Suggestion from j-a-meinel, 2005-11-24)
18
23
 
19
24
# NOTE: Some classes in here use camelCaseNaming() rather than
20
25
# underscore_naming().  That's for consistency with unittest; it's not the
23
28
 
24
29
import atexit
25
30
import codecs
26
 
import copy
 
31
from copy import copy
27
32
from cStringIO import StringIO
28
33
import difflib
29
34
import doctest
30
35
import errno
31
 
import itertools
32
36
import logging
 
37
import math
33
38
import os
34
 
import platform
35
 
import pprint
 
39
from pprint import pformat
36
40
import random
37
41
import re
38
42
import shlex
39
43
import stat
40
 
import subprocess
 
44
from subprocess import Popen, PIPE, STDOUT
41
45
import sys
42
46
import tempfile
43
47
import threading
47
51
import warnings
48
52
 
49
53
import testtools
50
 
# nb: check this before importing anything else from within it
51
 
_testtools_version = getattr(testtools, '__version__', ())
52
 
if _testtools_version < (0, 9, 5):
53
 
    raise ImportError("need at least testtools 0.9.5: %s is %r"
54
 
        % (testtools.__file__, _testtools_version))
55
54
from testtools import content
56
55
 
57
 
import bzrlib
58
56
from bzrlib import (
59
57
    branchbuilder,
60
58
    bzrdir,
61
59
    chk_map,
62
 
    commands as _mod_commands,
63
60
    config,
64
61
    debug,
65
62
    errors,
66
63
    hooks,
67
64
    lock as _mod_lock,
68
 
    lockdir,
69
65
    memorytree,
70
66
    osutils,
71
 
    plugin as _mod_plugin,
72
 
    pyutils,
 
67
    progress,
73
68
    ui,
74
69
    urlutils,
75
70
    registry,
76
 
    symbol_versioning,
77
 
    trace,
78
 
    transport as _mod_transport,
79
71
    workingtree,
80
72
    )
 
73
import bzrlib.branch
 
74
import bzrlib.commands
 
75
import bzrlib.timestamp
 
76
import bzrlib.export
 
77
import bzrlib.inventory
 
78
import bzrlib.iterablefile
 
79
import bzrlib.lockdir
81
80
try:
82
81
    import bzrlib.lsprof
83
82
except ImportError:
84
83
    # lsprof not available
85
84
    pass
86
 
from bzrlib.smart import client, request
87
 
from bzrlib.transport import (
88
 
    memory,
89
 
    pathfilter,
90
 
    )
 
85
from bzrlib.merge import merge_inner
 
86
import bzrlib.merge3
 
87
import bzrlib.plugin
 
88
from bzrlib.smart import client, request, server
 
89
import bzrlib.store
 
90
from bzrlib import symbol_versioning
91
91
from bzrlib.symbol_versioning import (
 
92
    DEPRECATED_PARAMETER,
92
93
    deprecated_function,
93
 
    deprecated_in,
94
 
    )
95
 
from bzrlib.tests import (
96
 
    test_server,
97
 
    TestUtil,
98
 
    treeshape,
99
 
    )
 
94
    deprecated_method,
 
95
    deprecated_passed,
 
96
    )
 
97
import bzrlib.trace
 
98
from bzrlib.transport import get_transport, pathfilter
 
99
import bzrlib.transport
 
100
from bzrlib.transport.local import LocalURLServer
 
101
from bzrlib.transport.memory import MemoryServer
 
102
from bzrlib.transport.readonly import ReadonlyServer
 
103
from bzrlib.trace import mutter, note
 
104
from bzrlib.tests import TestUtil
 
105
from bzrlib.tests.http_server import HttpServer
 
106
from bzrlib.tests.TestUtil import (
 
107
                          TestSuite,
 
108
                          TestLoader,
 
109
                          )
 
110
from bzrlib.tests.treeshape import build_tree_contents
100
111
from bzrlib.ui import NullProgressView
101
112
from bzrlib.ui.text import TextUIFactory
 
113
import bzrlib.version_info_formats.format_custom
 
114
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
102
115
 
103
116
# Mark this python module as being part of the implementation
104
117
# of unittest: this gives us better tracebacks where the last
105
118
# shown frame is the test code, not our assertXYZ.
106
119
__unittest = 1
107
120
 
108
 
default_transport = test_server.LocalURLServer
109
 
 
110
 
 
111
 
_unitialized_attr = object()
112
 
"""A sentinel needed to act as a default value in a method signature."""
113
 
 
 
121
default_transport = LocalURLServer
114
122
 
115
123
# Subunit result codes, defined here to prevent a hard dependency on subunit.
116
124
SUBUNIT_SEEK_SET = 0
117
125
SUBUNIT_SEEK_CUR = 1
118
126
 
119
 
# These are intentionally brought into this namespace. That way plugins, etc
120
 
# can just "from bzrlib.tests import TestCase, TestLoader, etc"
121
 
TestSuite = TestUtil.TestSuite
122
 
TestLoader = TestUtil.TestLoader
123
 
 
124
 
# Tests should run in a clean and clearly defined environment. The goal is to
125
 
# keep them isolated from the running environment as mush as possible. The test
126
 
# framework ensures the variables defined below are set (or deleted if the
127
 
# value is None) before a test is run and reset to their original value after
128
 
# the test is run. Generally if some code depends on an environment variable,
129
 
# the tests should start without this variable in the environment. There are a
130
 
# few exceptions but you shouldn't violate this rule lightly.
131
 
isolated_environ = {
132
 
    'BZR_HOME': None,
133
 
    'HOME': None,
134
 
    # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
135
 
    # tests do check our impls match APPDATA
136
 
    'BZR_EDITOR': None, # test_msgeditor manipulates this variable
137
 
    'VISUAL': None,
138
 
    'EDITOR': None,
139
 
    'BZR_EMAIL': None,
140
 
    'BZREMAIL': None, # may still be present in the environment
141
 
    'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
142
 
    'BZR_PROGRESS_BAR': None,
143
 
    # This should trap leaks to ~/.bzr.log. This occurs when tests use TestCase
144
 
    # as a base class instead of TestCaseInTempDir. Tests inheriting from
145
 
    # TestCase should not use disk resources, BZR_LOG is one.
146
 
    'BZR_LOG': '/you-should-use-TestCaseInTempDir-if-you-need-a-log-file',
147
 
    'BZR_PLUGIN_PATH': None,
148
 
    'BZR_DISABLE_PLUGINS': None,
149
 
    'BZR_PLUGINS_AT': None,
150
 
    'BZR_CONCURRENCY': None,
151
 
    # Make sure that any text ui tests are consistent regardless of
152
 
    # the environment the test case is run in; you may want tests that
153
 
    # test other combinations.  'dumb' is a reasonable guess for tests
154
 
    # going to a pipe or a StringIO.
155
 
    'TERM': 'dumb',
156
 
    'LINES': '25',
157
 
    'COLUMNS': '80',
158
 
    'BZR_COLUMNS': '80',
159
 
    # Disable SSH Agent
160
 
    'SSH_AUTH_SOCK': None,
161
 
    # Proxies
162
 
    'http_proxy': None,
163
 
    'HTTP_PROXY': None,
164
 
    'https_proxy': None,
165
 
    'HTTPS_PROXY': None,
166
 
    'no_proxy': None,
167
 
    'NO_PROXY': None,
168
 
    'all_proxy': None,
169
 
    'ALL_PROXY': None,
170
 
    # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
171
 
    # least. If you do (care), please update this comment
172
 
    # -- vila 20080401
173
 
    'ftp_proxy': None,
174
 
    'FTP_PROXY': None,
175
 
    'BZR_REMOTE_PATH': None,
176
 
    # Generally speaking, we don't want apport reporting on crashes in
177
 
    # the test envirnoment unless we're specifically testing apport,
178
 
    # so that it doesn't leak into the real system environment.  We
179
 
    # use an env var so it propagates to subprocesses.
180
 
    'APPORT_DISABLE': '1',
181
 
    }
182
 
 
183
 
 
184
 
def override_os_environ(test, env=None):
185
 
    """Modify os.environ keeping a copy.
186
 
    
187
 
    :param test: A test instance
188
 
 
189
 
    :param env: A dict containing variable definitions to be installed
190
 
    """
191
 
    if env is None:
192
 
        env = isolated_environ
193
 
    test._original_os_environ = dict([(var, value)
194
 
                                      for var, value in os.environ.iteritems()])
195
 
    for var, value in env.iteritems():
196
 
        osutils.set_or_unset_env(var, value)
197
 
        if var not in test._original_os_environ:
198
 
            # The var is new, add it with a value of None, so
199
 
            # restore_os_environ will delete it
200
 
            test._original_os_environ[var] = None
201
 
 
202
 
 
203
 
def restore_os_environ(test):
204
 
    """Restore os.environ to its original state.
205
 
 
206
 
    :param test: A test instance previously passed to override_os_environ.
207
 
    """
208
 
    for var, value in test._original_os_environ.iteritems():
209
 
        # Restore the original value (or delete it if the value has been set to
210
 
        # None in override_os_environ).
211
 
        osutils.set_or_unset_env(var, value)
212
 
 
213
 
 
214
 
class ExtendedTestResult(testtools.TextTestResult):
 
127
 
 
128
class ExtendedTestResult(unittest._TextTestResult):
215
129
    """Accepts, reports and accumulates the results of running tests.
216
130
 
217
131
    Compared to the unittest version this class adds support for
238
152
        :param bench_history: Optionally, a writable file object to accumulate
239
153
            benchmark results.
240
154
        """
241
 
        testtools.TextTestResult.__init__(self, stream)
 
155
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
242
156
        if bench_history is not None:
243
157
            from bzrlib.version import _get_bzr_source_tree
244
158
            src_tree = _get_bzr_source_tree()
265
179
        self.count = 0
266
180
        self._overall_start_time = time.time()
267
181
        self._strict = strict
268
 
        self._first_thread_leaker_id = None
269
 
        self._tests_leaking_threads_count = 0
270
 
        self._traceback_from_test = None
271
182
 
272
183
    def stopTestRun(self):
273
184
        run = self.testsRun
274
185
        actionTaken = "Ran"
275
186
        stopTime = time.time()
276
187
        timeTaken = stopTime - self.startTime
277
 
        # GZ 2010-07-19: Seems testtools has no printErrors method, and though
278
 
        #                the parent class method is similar have to duplicate
279
 
        self._show_list('ERROR', self.errors)
280
 
        self._show_list('FAIL', self.failures)
281
 
        self.stream.write(self.sep2)
282
 
        self.stream.write("%s %d test%s in %.3fs\n\n" % (actionTaken,
 
188
        self.printErrors()
 
189
        self.stream.writeln(self.separator2)
 
190
        self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
283
191
                            run, run != 1 and "s" or "", timeTaken))
 
192
        self.stream.writeln()
284
193
        if not self.wasSuccessful():
285
194
            self.stream.write("FAILED (")
286
195
            failed, errored = map(len, (self.failures, self.errors))
293
202
                if failed or errored: self.stream.write(", ")
294
203
                self.stream.write("known_failure_count=%d" %
295
204
                    self.known_failure_count)
296
 
            self.stream.write(")\n")
 
205
            self.stream.writeln(")")
297
206
        else:
298
207
            if self.known_failure_count:
299
 
                self.stream.write("OK (known_failures=%d)\n" %
 
208
                self.stream.writeln("OK (known_failures=%d)" %
300
209
                    self.known_failure_count)
301
210
            else:
302
 
                self.stream.write("OK\n")
 
211
                self.stream.writeln("OK")
303
212
        if self.skip_count > 0:
304
213
            skipped = self.skip_count
305
 
            self.stream.write('%d test%s skipped\n' %
 
214
            self.stream.writeln('%d test%s skipped' %
306
215
                                (skipped, skipped != 1 and "s" or ""))
307
216
        if self.unsupported:
308
217
            for feature, count in sorted(self.unsupported.items()):
309
 
                self.stream.write("Missing feature '%s' skipped %d tests.\n" %
 
218
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
310
219
                    (feature, count))
311
220
        if self._strict:
312
221
            ok = self.wasStrictlySuccessful()
313
222
        else:
314
223
            ok = self.wasSuccessful()
315
 
        if self._first_thread_leaker_id:
 
224
        if TestCase._first_thread_leaker_id:
316
225
            self.stream.write(
317
226
                '%s is leaking threads among %d leaking tests.\n' % (
318
 
                self._first_thread_leaker_id,
319
 
                self._tests_leaking_threads_count))
 
227
                TestCase._first_thread_leaker_id,
 
228
                TestCase._leaking_threads_tests))
320
229
            # We don't report the main thread as an active one.
321
230
            self.stream.write(
322
231
                '%d non-main threads were left active in the end.\n'
323
 
                % (len(self._active_threads) - 1))
324
 
 
325
 
    def getDescription(self, test):
326
 
        return test.id()
 
232
                % (TestCase._active_threads - 1))
327
233
 
328
234
    def _extractBenchmarkTime(self, testCase, details=None):
329
235
        """Add a benchmark time for the current test case."""
333
239
 
334
240
    def _elapsedTestTimeString(self):
335
241
        """Return a time string for the overall time the current test has taken."""
336
 
        return self._formatTime(self._delta_to_float(
337
 
            self._now() - self._start_datetime))
 
242
        return self._formatTime(time.time() - self._start_time)
338
243
 
339
244
    def _testTimeString(self, testCase):
340
245
        benchmark_time = self._extractBenchmarkTime(testCase)
351
256
 
352
257
    def _shortened_test_description(self, test):
353
258
        what = test.id()
354
 
        what = re.sub(r'^bzrlib\.tests\.', '', what)
 
259
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
355
260
        return what
356
261
 
357
 
    # GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
358
 
    #                multiple times in a row, because the handler is added for
359
 
    #                each test but the container list is shared between cases.
360
 
    #                See lp:498869 lp:625574 and lp:637725 for background.
361
 
    def _record_traceback_from_test(self, exc_info):
362
 
        """Store the traceback from passed exc_info tuple till"""
363
 
        self._traceback_from_test = exc_info[2]
364
 
 
365
262
    def startTest(self, test):
366
 
        super(ExtendedTestResult, self).startTest(test)
 
263
        unittest.TestResult.startTest(self, test)
367
264
        if self.count == 0:
368
265
            self.startTests()
369
 
        self.count += 1
370
266
        self.report_test_start(test)
371
267
        test.number = self.count
372
268
        self._recordTestStartTime()
373
 
        # Make testtools cases give us the real traceback on failure
374
 
        addOnException = getattr(test, "addOnException", None)
375
 
        if addOnException is not None:
376
 
            addOnException(self._record_traceback_from_test)
377
 
        # Only check for thread leaks on bzrlib derived test cases
378
 
        if isinstance(test, TestCase):
379
 
            test.addCleanup(self._check_leaked_threads, test)
380
 
 
381
 
    def stopTest(self, test):
382
 
        super(ExtendedTestResult, self).stopTest(test)
383
 
        # Manually break cycles, means touching various private things but hey
384
 
        getDetails = getattr(test, "getDetails", None)
385
 
        if getDetails is not None:
386
 
            getDetails().clear()
387
 
        # Clear _type_equality_funcs to try to stop TestCase instances
388
 
        # from wasting memory. 'clear' is not available in all Python
389
 
        # versions (bug 809048)
390
 
        type_equality_funcs = getattr(test, "_type_equality_funcs", None)
391
 
        if type_equality_funcs is not None:
392
 
            tef_clear = getattr(type_equality_funcs, "clear", None)
393
 
            if tef_clear is None:
394
 
                tef_instance_dict = getattr(type_equality_funcs, "__dict__", None)
395
 
                if tef_instance_dict is not None:
396
 
                    tef_clear = tef_instance_dict.clear
397
 
            if tef_clear is not None:
398
 
                tef_clear()
399
 
        self._traceback_from_test = None
400
269
 
401
270
    def startTests(self):
402
 
        self.report_tests_starting()
403
 
        self._active_threads = threading.enumerate()
404
 
 
405
 
    def _check_leaked_threads(self, test):
406
 
        """See if any threads have leaked since last call
407
 
 
408
 
        A sample of live threads is stored in the _active_threads attribute,
409
 
        when this method runs it compares the current live threads and any not
410
 
        in the previous sample are treated as having leaked.
411
 
        """
412
 
        now_active_threads = set(threading.enumerate())
413
 
        threads_leaked = now_active_threads.difference(self._active_threads)
414
 
        if threads_leaked:
415
 
            self._report_thread_leak(test, threads_leaked, now_active_threads)
416
 
            self._tests_leaking_threads_count += 1
417
 
            if self._first_thread_leaker_id is None:
418
 
                self._first_thread_leaker_id = test.id()
419
 
            self._active_threads = now_active_threads
 
271
        import platform
 
272
        if getattr(sys, 'frozen', None) is None:
 
273
            bzr_path = osutils.realpath(sys.argv[0])
 
274
        else:
 
275
            bzr_path = sys.executable
 
276
        self.stream.write(
 
277
            'bzr selftest: %s\n' % (bzr_path,))
 
278
        self.stream.write(
 
279
            '   %s\n' % (
 
280
                    bzrlib.__path__[0],))
 
281
        self.stream.write(
 
282
            '   bzr-%s python-%s %s\n' % (
 
283
                    bzrlib.version_string,
 
284
                    bzrlib._format_version_tuple(sys.version_info),
 
285
                    platform.platform(aliased=1),
 
286
                    ))
 
287
        self.stream.write('\n')
420
288
 
421
289
    def _recordTestStartTime(self):
422
290
        """Record that a test has started."""
423
 
        self._start_datetime = self._now()
 
291
        self._start_time = time.time()
 
292
 
 
293
    def _cleanupLogFile(self, test):
 
294
        # We can only do this if we have one of our TestCases, not if
 
295
        # we have a doctest.
 
296
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
297
        if setKeepLogfile is not None:
 
298
            setKeepLogfile()
424
299
 
425
300
    def addError(self, test, err):
426
301
        """Tell result that test finished with an error.
428
303
        Called from the TestCase run() method when the test
429
304
        fails with an unexpected error.
430
305
        """
431
 
        self._post_mortem(self._traceback_from_test)
432
 
        super(ExtendedTestResult, self).addError(test, err)
 
306
        self._post_mortem()
 
307
        unittest.TestResult.addError(self, test, err)
433
308
        self.error_count += 1
434
309
        self.report_error(test, err)
435
310
        if self.stop_early:
436
311
            self.stop()
 
312
        self._cleanupLogFile(test)
437
313
 
438
314
    def addFailure(self, test, err):
439
315
        """Tell result that test failed.
441
317
        Called from the TestCase run() method when the test
442
318
        fails because e.g. an assert() method failed.
443
319
        """
444
 
        self._post_mortem(self._traceback_from_test)
445
 
        super(ExtendedTestResult, self).addFailure(test, err)
 
320
        self._post_mortem()
 
321
        unittest.TestResult.addFailure(self, test, err)
446
322
        self.failure_count += 1
447
323
        self.report_failure(test, err)
448
324
        if self.stop_early:
449
325
            self.stop()
 
326
        self._cleanupLogFile(test)
450
327
 
451
328
    def addSuccess(self, test, details=None):
452
329
        """Tell result that test completed successfully.
460
337
                    self._formatTime(benchmark_time),
461
338
                    test.id()))
462
339
        self.report_success(test)
463
 
        super(ExtendedTestResult, self).addSuccess(test)
 
340
        self._cleanupLogFile(test)
 
341
        unittest.TestResult.addSuccess(self, test)
464
342
        test._log_contents = ''
465
343
 
466
344
    def addExpectedFailure(self, test, err):
467
345
        self.known_failure_count += 1
468
346
        self.report_known_failure(test, err)
469
347
 
470
 
    def addUnexpectedSuccess(self, test, details=None):
471
 
        """Tell result the test unexpectedly passed, counting as a failure
472
 
 
473
 
        When the minimum version of testtools required becomes 0.9.8 this
474
 
        can be updated to use the new handling there.
475
 
        """
476
 
        super(ExtendedTestResult, self).addFailure(test, details=details)
477
 
        self.failure_count += 1
478
 
        self.report_unexpected_success(test,
479
 
            "".join(details["reason"].iter_text()))
480
 
        if self.stop_early:
481
 
            self.stop()
482
 
 
483
348
    def addNotSupported(self, test, feature):
484
349
        """The test will not be run because of a missing feature.
485
350
        """
502
367
        self.not_applicable_count += 1
503
368
        self.report_not_applicable(test, reason)
504
369
 
505
 
    def _post_mortem(self, tb=None):
 
370
    def _post_mortem(self):
506
371
        """Start a PDB post mortem session."""
507
372
        if os.environ.get('BZR_TEST_PDB', None):
508
 
            import pdb
509
 
            pdb.post_mortem(tb)
 
373
            import pdb;pdb.post_mortem()
510
374
 
511
375
    def progress(self, offset, whence):
512
376
        """The test is adjusting the count of tests to run."""
517
381
        else:
518
382
            raise errors.BzrError("Unknown whence %r" % whence)
519
383
 
520
 
    def report_tests_starting(self):
521
 
        """Display information before the test run begins"""
522
 
        if getattr(sys, 'frozen', None) is None:
523
 
            bzr_path = osutils.realpath(sys.argv[0])
524
 
        else:
525
 
            bzr_path = sys.executable
526
 
        self.stream.write(
527
 
            'bzr selftest: %s\n' % (bzr_path,))
528
 
        self.stream.write(
529
 
            '   %s\n' % (
530
 
                    bzrlib.__path__[0],))
531
 
        self.stream.write(
532
 
            '   bzr-%s python-%s %s\n' % (
533
 
                    bzrlib.version_string,
534
 
                    bzrlib._format_version_tuple(sys.version_info),
535
 
                    platform.platform(aliased=1),
536
 
                    ))
537
 
        self.stream.write('\n')
538
 
 
539
 
    def report_test_start(self, test):
540
 
        """Display information on the test just about to be run"""
541
 
 
542
 
    def _report_thread_leak(self, test, leaked_threads, active_threads):
543
 
        """Display information on a test that leaked one or more threads"""
544
 
        # GZ 2010-09-09: A leak summary reported separately from the general
545
 
        #                thread debugging would be nice. Tests under subunit
546
 
        #                need something not using stream, perhaps adding a
547
 
        #                testtools details object would be fitting.
548
 
        if 'threads' in selftest_debug_flags:
549
 
            self.stream.write('%s is leaking, active is now %d\n' %
550
 
                (test.id(), len(active_threads)))
 
384
    def report_cleaning_up(self):
 
385
        pass
551
386
 
552
387
    def startTestRun(self):
553
388
        self.startTime = time.time()
590
425
        self.pb.finished()
591
426
        super(TextTestResult, self).stopTestRun()
592
427
 
593
 
    def report_tests_starting(self):
594
 
        super(TextTestResult, self).report_tests_starting()
 
428
    def startTestRun(self):
 
429
        super(TextTestResult, self).startTestRun()
595
430
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
596
431
 
 
432
    def printErrors(self):
 
433
        # clear the pb to make room for the error listing
 
434
        self.pb.clear()
 
435
        super(TextTestResult, self).printErrors()
 
436
 
597
437
    def _progress_prefix_text(self):
598
438
        # the longer this text, the less space we have to show the test
599
439
        # name...
612
452
            a += '%dm%ds' % (runtime / 60, runtime % 60)
613
453
        else:
614
454
            a += '%ds' % runtime
615
 
        total_fail_count = self.error_count + self.failure_count
616
 
        if total_fail_count:
617
 
            a += ', %d failed' % total_fail_count
 
455
        if self.error_count:
 
456
            a += ', %d err' % self.error_count
 
457
        if self.failure_count:
 
458
            a += ', %d fail' % self.failure_count
618
459
        # if self.unsupported:
619
460
        #     a += ', %d missing' % len(self.unsupported)
620
461
        a += ']'
621
462
        return a
622
463
 
623
464
    def report_test_start(self, test):
 
465
        self.count += 1
624
466
        self.pb.update(
625
467
                self._progress_prefix_text()
626
468
                + ' '
630
472
        return self._shortened_test_description(test)
631
473
 
632
474
    def report_error(self, test, err):
633
 
        self.stream.write('ERROR: %s\n    %s\n' % (
 
475
        ui.ui_factory.note('ERROR: %s\n    %s\n' % (
634
476
            self._test_description(test),
635
477
            err[1],
636
478
            ))
637
479
 
638
480
    def report_failure(self, test, err):
639
 
        self.stream.write('FAIL: %s\n    %s\n' % (
 
481
        ui.ui_factory.note('FAIL: %s\n    %s\n' % (
640
482
            self._test_description(test),
641
483
            err[1],
642
484
            ))
644
486
    def report_known_failure(self, test, err):
645
487
        pass
646
488
 
647
 
    def report_unexpected_success(self, test, reason):
648
 
        self.stream.write('FAIL: %s\n    %s: %s\n' % (
649
 
            self._test_description(test),
650
 
            "Unexpected success. Should have failed",
651
 
            reason,
652
 
            ))
653
 
 
654
489
    def report_skip(self, test, reason):
655
490
        pass
656
491
 
660
495
    def report_unsupported(self, test, feature):
661
496
        """test cannot be run because feature is missing."""
662
497
 
 
498
    def report_cleaning_up(self):
 
499
        self.pb.update('Cleaning up')
 
500
 
663
501
 
664
502
class VerboseTestResult(ExtendedTestResult):
665
503
    """Produce long output, with one line per test run plus times"""
672
510
            result = a_string
673
511
        return result.ljust(final_width)
674
512
 
675
 
    def report_tests_starting(self):
 
513
    def startTestRun(self):
 
514
        super(VerboseTestResult, self).startTestRun()
676
515
        self.stream.write('running %d tests...\n' % self.num_tests)
677
 
        super(VerboseTestResult, self).report_tests_starting()
678
516
 
679
517
    def report_test_start(self, test):
 
518
        self.count += 1
680
519
        name = self._shortened_test_description(test)
681
520
        width = osutils.terminal_width()
682
521
        if width is not None:
694
533
        return '%s%s' % (indent, err[1])
695
534
 
696
535
    def report_error(self, test, err):
697
 
        self.stream.write('ERROR %s\n%s\n'
 
536
        self.stream.writeln('ERROR %s\n%s'
698
537
                % (self._testTimeString(test),
699
538
                   self._error_summary(err)))
700
539
 
701
540
    def report_failure(self, test, err):
702
 
        self.stream.write(' FAIL %s\n%s\n'
 
541
        self.stream.writeln(' FAIL %s\n%s'
703
542
                % (self._testTimeString(test),
704
543
                   self._error_summary(err)))
705
544
 
706
545
    def report_known_failure(self, test, err):
707
 
        self.stream.write('XFAIL %s\n%s\n'
 
546
        self.stream.writeln('XFAIL %s\n%s'
708
547
                % (self._testTimeString(test),
709
548
                   self._error_summary(err)))
710
549
 
711
 
    def report_unexpected_success(self, test, reason):
712
 
        self.stream.write(' FAIL %s\n%s: %s\n'
713
 
                % (self._testTimeString(test),
714
 
                   "Unexpected success. Should have failed",
715
 
                   reason))
716
 
 
717
550
    def report_success(self, test):
718
 
        self.stream.write('   OK %s\n' % self._testTimeString(test))
 
551
        self.stream.writeln('   OK %s' % self._testTimeString(test))
719
552
        for bench_called, stats in getattr(test, '_benchcalls', []):
720
 
            self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
 
553
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
721
554
            stats.pprint(file=self.stream)
722
555
        # flush the stream so that we get smooth output. This verbose mode is
723
556
        # used to show the output in PQM.
724
557
        self.stream.flush()
725
558
 
726
559
    def report_skip(self, test, reason):
727
 
        self.stream.write(' SKIP %s\n%s\n'
 
560
        self.stream.writeln(' SKIP %s\n%s'
728
561
                % (self._testTimeString(test), reason))
729
562
 
730
563
    def report_not_applicable(self, test, reason):
731
 
        self.stream.write('  N/A %s\n    %s\n'
 
564
        self.stream.writeln('  N/A %s\n    %s'
732
565
                % (self._testTimeString(test), reason))
733
566
 
734
567
    def report_unsupported(self, test, feature):
735
568
        """test cannot be run because feature is missing."""
736
 
        self.stream.write("NODEP %s\n    The feature '%s' is not available.\n"
 
569
        self.stream.writeln("NODEP %s\n    The feature '%s' is not available."
737
570
                %(self._testTimeString(test), feature))
738
571
 
739
572
 
761
594
        # to encode using ascii.
762
595
        new_encoding = osutils.get_terminal_encoding()
763
596
        codec = codecs.lookup(new_encoding)
764
 
        if type(codec) is tuple:
765
 
            # Python 2.4
766
 
            encode = codec[0]
767
 
        else:
768
 
            encode = codec.encode
769
 
        # GZ 2010-09-08: Really we don't want to be writing arbitrary bytes,
770
 
        #                so should swap to the plain codecs.StreamWriter
771
 
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream,
772
 
            "backslashreplace")
 
597
        stream = osutils.UnicodeOrBytesToBytesWriter(codec, stream)
773
598
        stream.encoding = new_encoding
774
 
        self.stream = stream
 
599
        self.stream = unittest._WritelnDecorator(stream)
775
600
        self.descriptions = descriptions
776
601
        self.verbosity = verbosity
777
602
        self._bench_history = bench_history
846
671
traceback._some_str = _clever_some_str
847
672
 
848
673
 
849
 
# deprecated - use self.knownFailure(), or self.expectFailure.
 
674
# deprecated
850
675
KnownFailure = testtools.testcase._ExpectedFailure
851
676
 
852
677
 
859
684
    """
860
685
 
861
686
 
 
687
class CommandFailed(Exception):
 
688
    pass
 
689
 
 
690
 
862
691
class StringIOWrapper(object):
863
692
    """A wrapper around cStringIO which just adds an encoding attribute.
864
693
 
901
730
    # XXX: Should probably unify more with CannedInputUIFactory or a
902
731
    # particular configuration of TextUIFactory, or otherwise have a clearer
903
732
    # idea of how they're supposed to be different.
904
 
    # See https://bugs.launchpad.net/bzr/+bug/408213
 
733
    # See https://bugs.edge.launchpad.net/bzr/+bug/408213
905
734
 
906
735
    def __init__(self, stdout=None, stderr=None, stdin=None):
907
736
        if stdin is not None:
925
754
        return NullProgressView()
926
755
 
927
756
 
928
 
def isolated_doctest_setUp(test):
929
 
    override_os_environ(test)
930
 
 
931
 
 
932
 
def isolated_doctest_tearDown(test):
933
 
    restore_os_environ(test)
934
 
 
935
 
 
936
 
def IsolatedDocTestSuite(*args, **kwargs):
937
 
    """Overrides doctest.DocTestSuite to handle isolation.
938
 
 
939
 
    The method is really a factory and users are expected to use it as such.
940
 
    """
941
 
 
942
 
    kwargs['setUp'] = isolated_doctest_setUp
943
 
    kwargs['tearDown'] = isolated_doctest_tearDown
944
 
    return doctest.DocTestSuite(*args, **kwargs)
945
 
 
946
 
 
947
757
class TestCase(testtools.TestCase):
948
758
    """Base class for bzr unit tests.
949
759
 
960
770
    routine, and to build and check bzr trees.
961
771
 
962
772
    In addition to the usual method of overriding tearDown(), this class also
963
 
    allows subclasses to register cleanup functions via addCleanup, which are
 
773
    allows subclasses to register functions into the _cleanups list, which is
964
774
    run in order as the object is torn down.  It's less likely this will be
965
775
    accidentally overlooked.
966
776
    """
967
777
 
968
 
    _log_file = None
 
778
    _active_threads = None
 
779
    _leaking_threads_tests = 0
 
780
    _first_thread_leaker_id = None
 
781
    _log_file_name = None
969
782
    # record lsprof data when performing benchmark calls.
970
783
    _gather_lsprof_in_benchmarks = False
971
784
 
972
785
    def __init__(self, methodName='testMethod'):
973
786
        super(TestCase, self).__init__(methodName)
 
787
        self._cleanups = []
974
788
        self._directory_isolation = True
975
789
        self.exception_handlers.insert(0,
976
790
            (UnavailableFeature, self._do_unsupported_or_skip))
981
795
        super(TestCase, self).setUp()
982
796
        for feature in getattr(self, '_test_needs_features', []):
983
797
            self.requireFeature(feature)
 
798
        self._log_contents = None
 
799
        self.addDetail("log", content.Content(content.ContentType("text",
 
800
            "plain", {"charset": "utf8"}),
 
801
            lambda:[self._get_log(keep_log_file=True)]))
984
802
        self._cleanEnvironment()
985
803
        self._silenceUI()
986
804
        self._startLogFile()
990
808
        self._track_transports()
991
809
        self._track_locks()
992
810
        self._clear_debug_flags()
993
 
        # Isolate global verbosity level, to make sure it's reproducible
994
 
        # between tests.  We should get rid of this altogether: bug 656694. --
995
 
        # mbp 20101008
996
 
        self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
997
 
        # Isolate config option expansion until its default value for bzrlib is
998
 
        # settled on or a the FIXME associated with _get_expand_default_value
999
 
        # is addressed -- vila 20110219
1000
 
        self.overrideAttr(config, '_expand_default_value', None)
1001
 
        self._log_files = set()
1002
 
        # Each key in the ``_counters`` dict holds a value for a different
1003
 
        # counter. When the test ends, addDetail() should be used to output the
1004
 
        # counter values. This happens in install_counter_hook().
1005
 
        self._counters = {}
1006
 
        if 'config_stats' in selftest_debug_flags:
1007
 
            self._install_config_stats_hooks()
 
811
        TestCase._active_threads = threading.activeCount()
 
812
        self.addCleanup(self._check_leaked_threads)
1008
813
 
1009
814
    def debug(self):
1010
815
        # debug a frame up.
1011
816
        import pdb
1012
817
        pdb.Pdb().set_trace(sys._getframe().f_back)
1013
818
 
1014
 
    def discardDetail(self, name):
1015
 
        """Extend the addDetail, getDetails api so we can remove a detail.
1016
 
 
1017
 
        eg. bzr always adds the 'log' detail at startup, but we don't want to
1018
 
        include it for skipped, xfail, etc tests.
1019
 
 
1020
 
        It is safe to call this for a detail that doesn't exist, in case this
1021
 
        gets called multiple times.
1022
 
        """
1023
 
        # We cheat. details is stored in __details which means we shouldn't
1024
 
        # touch it. but getDetails() returns the dict directly, so we can
1025
 
        # mutate it.
1026
 
        details = self.getDetails()
1027
 
        if name in details:
1028
 
            del details[name]
1029
 
 
1030
 
    def install_counter_hook(self, hooks, name, counter_name=None):
1031
 
        """Install a counting hook.
1032
 
 
1033
 
        Any hook can be counted as long as it doesn't need to return a value.
1034
 
 
1035
 
        :param hooks: Where the hook should be installed.
1036
 
 
1037
 
        :param name: The hook name that will be counted.
1038
 
 
1039
 
        :param counter_name: The counter identifier in ``_counters``, defaults
1040
 
            to ``name``.
1041
 
        """
1042
 
        _counters = self._counters # Avoid closing over self
1043
 
        if counter_name is None:
1044
 
            counter_name = name
1045
 
        if _counters.has_key(counter_name):
1046
 
            raise AssertionError('%s is already used as a counter name'
1047
 
                                  % (counter_name,))
1048
 
        _counters[counter_name] = 0
1049
 
        self.addDetail(counter_name, content.Content(content.UTF8_TEXT,
1050
 
            lambda: ['%d' % (_counters[counter_name],)]))
1051
 
        def increment_counter(*args, **kwargs):
1052
 
            _counters[counter_name] += 1
1053
 
        label = 'count %s calls' % (counter_name,)
1054
 
        hooks.install_named_hook(name, increment_counter, label)
1055
 
        self.addCleanup(hooks.uninstall_named_hook, name, label)
1056
 
 
1057
 
    def _install_config_stats_hooks(self):
1058
 
        """Install config hooks to count hook calls.
1059
 
 
1060
 
        """
1061
 
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1062
 
            self.install_counter_hook(config.ConfigHooks, hook_name,
1063
 
                                       'config.%s' % (hook_name,))
1064
 
 
1065
 
        # The OldConfigHooks are private and need special handling to protect
1066
 
        # against recursive tests (tests that run other tests), so we just do
1067
 
        # manually what registering them into _builtin_known_hooks will provide
1068
 
        # us.
1069
 
        self.overrideAttr(config, 'OldConfigHooks', config._OldConfigHooks())
1070
 
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1071
 
            self.install_counter_hook(config.OldConfigHooks, hook_name,
1072
 
                                      'old_config.%s' % (hook_name,))
 
819
    def _check_leaked_threads(self):
 
820
        active = threading.activeCount()
 
821
        leaked_threads = active - TestCase._active_threads
 
822
        TestCase._active_threads = active
 
823
        # If some tests make the number of threads *decrease*, we'll consider
 
824
        # that they are just observing old threads dieing, not agressively kill
 
825
        # random threads. So we don't report these tests as leaking. The risk
 
826
        # is that we have false positives that way (the test see 2 threads
 
827
        # going away but leak one) but it seems less likely than the actual
 
828
        # false positives (the test see threads going away and does not leak).
 
829
        if leaked_threads > 0:
 
830
            TestCase._leaking_threads_tests += 1
 
831
            if TestCase._first_thread_leaker_id is None:
 
832
                TestCase._first_thread_leaker_id = self.id()
1073
833
 
1074
834
    def _clear_debug_flags(self):
1075
835
        """Prevent externally set debug flags affecting tests.
1077
837
        Tests that want to use debug flags can just set them in the
1078
838
        debug_flags set during setup/teardown.
1079
839
        """
1080
 
        # Start with a copy of the current debug flags we can safely modify.
1081
 
        self.overrideAttr(debug, 'debug_flags', set(debug.debug_flags))
 
840
        self._preserved_debug_flags = set(debug.debug_flags)
1082
841
        if 'allow_debug' not in selftest_debug_flags:
1083
842
            debug.debug_flags.clear()
1084
843
        if 'disable_lock_checks' not in selftest_debug_flags:
1085
844
            debug.debug_flags.add('strict_locks')
 
845
        self.addCleanup(self._restore_debug_flags)
1086
846
 
1087
847
    def _clear_hooks(self):
1088
848
        # prevent hooks affecting tests
1089
 
        known_hooks = hooks.known_hooks
1090
849
        self._preserved_hooks = {}
1091
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1092
 
            current_hooks = getattr(parent, name)
 
850
        for key, factory in hooks.known_hooks.items():
 
851
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
852
            current_hooks = hooks.known_hooks_key_to_object(key)
1093
853
            self._preserved_hooks[parent] = (name, current_hooks)
1094
 
        self._preserved_lazy_hooks = hooks._lazy_hooks
1095
 
        hooks._lazy_hooks = {}
1096
854
        self.addCleanup(self._restoreHooks)
1097
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1098
 
            factory = known_hooks.get(key)
 
855
        for key, factory in hooks.known_hooks.items():
 
856
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
1099
857
            setattr(parent, name, factory())
1100
858
        # this hook should always be installed
1101
859
        request._install_hook()
1111
869
    def _silenceUI(self):
1112
870
        """Turn off UI for duration of test"""
1113
871
        # by default the UI is off; tests can turn it on if they want it.
1114
 
        self.overrideAttr(ui, 'ui_factory', ui.SilentUIFactory())
 
872
        saved = ui.ui_factory
 
873
        def _restore():
 
874
            ui.ui_factory = saved
 
875
        ui.ui_factory = ui.SilentUIFactory()
 
876
        self.addCleanup(_restore)
1115
877
 
1116
878
    def _check_locks(self):
1117
879
        """Check that all lock take/release actions have been paired."""
1130
892
        # break some locks on purpose and should be taken into account by
1131
893
        # considering that breaking a lock is just a dirty way of releasing it.
1132
894
        if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
1133
 
            message = (
1134
 
                'Different number of acquired and '
1135
 
                'released or broken locks.\n'
1136
 
                'acquired=%s\n'
1137
 
                'released=%s\n'
1138
 
                'broken=%s\n' %
1139
 
                (acquired_locks, released_locks, broken_locks))
 
895
            message = ('Different number of acquired and '
 
896
                       'released or broken locks. (%s, %s + %s)' %
 
897
                       (acquired_locks, released_locks, broken_locks))
1140
898
            if not self._lock_check_thorough:
1141
899
                # Rather than fail, just warn
1142
900
                print "Broken test %s: %s" % (self, message)
1150
908
            self._lock_check_thorough = False
1151
909
        else:
1152
910
            self._lock_check_thorough = True
1153
 
 
 
911
            
1154
912
        self.addCleanup(self._check_locks)
1155
913
        _mod_lock.Lock.hooks.install_named_hook('lock_acquired',
1156
914
                                                self._lock_acquired, None)
1170
928
 
1171
929
    def permit_dir(self, name):
1172
930
        """Permit a directory to be used by this test. See permit_url."""
1173
 
        name_transport = _mod_transport.get_transport_from_path(name)
 
931
        name_transport = get_transport(name)
1174
932
        self.permit_url(name)
1175
933
        self.permit_url(name_transport.base)
1176
934
 
1199
957
            try:
1200
958
                workingtree.WorkingTree.open(path)
1201
959
            except (errors.NotBranchError, errors.NoWorkingTree):
1202
 
                raise TestSkipped('Needs a working tree of bzr sources')
 
960
                return
1203
961
        finally:
1204
962
            self.enable_directory_isolation()
1205
963
 
1249
1007
        server's urls to be used.
1250
1008
        """
1251
1009
        if backing_server is None:
1252
 
            transport_server.start_server()
 
1010
            transport_server.setUp()
1253
1011
        else:
1254
 
            transport_server.start_server(backing_server)
1255
 
        self.addCleanup(transport_server.stop_server)
 
1012
            transport_server.setUp(backing_server)
 
1013
        self.addCleanup(transport_server.tearDown)
1256
1014
        # Obtain a real transport because if the server supplies a password, it
1257
1015
        # will be hidden from the base on the client side.
1258
 
        t = _mod_transport.get_transport_from_url(transport_server.get_url())
 
1016
        t = get_transport(transport_server.get_url())
1259
1017
        # Some transport servers effectively chroot the backing transport;
1260
1018
        # others like SFTPServer don't - users of the transport can walk up the
1261
1019
        # transport to read the entire backing transport. This wouldn't matter
1272
1030
        if t.base.endswith('/work/'):
1273
1031
            # we have safety net/test root/work
1274
1032
            t = t.clone('../..')
1275
 
        elif isinstance(transport_server,
1276
 
                        test_server.SmartTCPServer_for_testing):
 
1033
        elif isinstance(transport_server, server.SmartTCPServer_for_testing):
1277
1034
            # The smart server adds a path similar to work, which is traversed
1278
1035
            # up from by the client. But the server is chrooted - the actual
1279
1036
            # backing transport is not escaped from, and VFS requests to the
1317
1074
        except UnicodeError, e:
1318
1075
            # If we can't compare without getting a UnicodeError, then
1319
1076
            # obviously they are different
1320
 
            trace.mutter('UnicodeError: %s', e)
 
1077
            mutter('UnicodeError: %s', e)
1321
1078
        if message:
1322
1079
            message += '\n'
1323
1080
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1324
1081
            % (message,
1325
 
               pprint.pformat(a), pprint.pformat(b)))
 
1082
               pformat(a), pformat(b)))
1326
1083
 
1327
1084
    assertEquals = assertEqual
1328
1085
 
1362
1119
                         'st_mtime did not match')
1363
1120
        self.assertEqual(expected.st_ctime, actual.st_ctime,
1364
1121
                         'st_ctime did not match')
1365
 
        if sys.platform == 'win32':
 
1122
        if sys.platform != 'win32':
1366
1123
            # On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1367
1124
            # is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
1368
 
            # odd. We just force it to always be 0 to avoid any problems.
1369
 
            self.assertEqual(0, expected.st_dev)
1370
 
            self.assertEqual(0, actual.st_dev)
1371
 
            self.assertEqual(0, expected.st_ino)
1372
 
            self.assertEqual(0, actual.st_ino)
1373
 
        else:
 
1125
            # odd. Regardless we shouldn't actually try to assert anything
 
1126
            # about their values
1374
1127
            self.assertEqual(expected.st_dev, actual.st_dev,
1375
1128
                             'st_dev did not match')
1376
1129
            self.assertEqual(expected.st_ino, actual.st_ino,
1385
1138
                length, len(obj_with_len), obj_with_len))
1386
1139
 
1387
1140
    def assertLogsError(self, exception_class, func, *args, **kwargs):
1388
 
        """Assert that `func(*args, **kwargs)` quietly logs a specific error.
 
1141
        """Assert that func(*args, **kwargs) quietly logs a specific exception.
1389
1142
        """
 
1143
        from bzrlib import trace
1390
1144
        captured = []
1391
1145
        orig_log_exception_quietly = trace.log_exception_quietly
1392
1146
        try:
1393
1147
            def capture():
1394
1148
                orig_log_exception_quietly()
1395
 
                captured.append(sys.exc_info()[1])
 
1149
                captured.append(sys.exc_info())
1396
1150
            trace.log_exception_quietly = capture
1397
1151
            func(*args, **kwargs)
1398
1152
        finally:
1399
1153
            trace.log_exception_quietly = orig_log_exception_quietly
1400
1154
        self.assertLength(1, captured)
1401
 
        err = captured[0]
 
1155
        err = captured[0][1]
1402
1156
        self.assertIsInstance(err, exception_class)
1403
1157
        return err
1404
1158
 
1437
1191
            raise AssertionError('pattern "%s" found in "%s"'
1438
1192
                    % (needle_re, haystack))
1439
1193
 
1440
 
    def assertContainsString(self, haystack, needle):
1441
 
        if haystack.find(needle) == -1:
1442
 
            self.fail("string %r not found in '''%s'''" % (needle, haystack))
1443
 
 
1444
 
    def assertNotContainsString(self, haystack, needle):
1445
 
        if haystack.find(needle) != -1:
1446
 
            self.fail("string %r found in '''%s'''" % (needle, haystack))
1447
 
 
1448
1194
    def assertSubset(self, sublist, superlist):
1449
1195
        """Assert that every entry in sublist is present in superlist."""
1450
1196
        missing = set(sublist) - set(superlist)
1539
1285
 
1540
1286
    def assertFileEqual(self, content, path):
1541
1287
        """Fail if path does not contain 'content'."""
1542
 
        self.assertPathExists(path)
 
1288
        self.failUnlessExists(path)
1543
1289
        f = file(path, 'rb')
1544
1290
        try:
1545
1291
            s = f.read()
1547
1293
            f.close()
1548
1294
        self.assertEqualDiff(content, s)
1549
1295
 
1550
 
    def assertDocstring(self, expected_docstring, obj):
1551
 
        """Fail if obj does not have expected_docstring"""
1552
 
        if __doc__ is None:
1553
 
            # With -OO the docstring should be None instead
1554
 
            self.assertIs(obj.__doc__, None)
1555
 
        else:
1556
 
            self.assertEqual(expected_docstring, obj.__doc__)
1557
 
 
1558
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1559
1296
    def failUnlessExists(self, path):
1560
 
        return self.assertPathExists(path)
1561
 
 
1562
 
    def assertPathExists(self, path):
1563
1297
        """Fail unless path or paths, which may be abs or relative, exist."""
1564
1298
        if not isinstance(path, basestring):
1565
1299
            for p in path:
1566
 
                self.assertPathExists(p)
 
1300
                self.failUnlessExists(p)
1567
1301
        else:
1568
 
            self.assertTrue(osutils.lexists(path),
1569
 
                path + " does not exist")
 
1302
            self.failUnless(osutils.lexists(path),path+" does not exist")
1570
1303
 
1571
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1572
1304
    def failIfExists(self, path):
1573
 
        return self.assertPathDoesNotExist(path)
1574
 
 
1575
 
    def assertPathDoesNotExist(self, path):
1576
1305
        """Fail if path or paths, which may be abs or relative, exist."""
1577
1306
        if not isinstance(path, basestring):
1578
1307
            for p in path:
1579
 
                self.assertPathDoesNotExist(p)
 
1308
                self.failIfExists(p)
1580
1309
        else:
1581
 
            self.assertFalse(osutils.lexists(path),
1582
 
                path + " exists")
 
1310
            self.failIf(osutils.lexists(path),path+" exists")
1583
1311
 
1584
1312
    def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
1585
1313
        """A helper for callDeprecated and applyDeprecated.
1611
1339
        not other callers that go direct to the warning module.
1612
1340
 
1613
1341
        To test that a deprecated method raises an error, do something like
1614
 
        this (remember that both assertRaises and applyDeprecated delays *args
1615
 
        and **kwargs passing)::
 
1342
        this::
1616
1343
 
1617
1344
            self.assertRaises(errors.ReservedId,
1618
1345
                self.applyDeprecated,
1700
1427
 
1701
1428
        The file is removed as the test is torn down.
1702
1429
        """
1703
 
        pseudo_log_file = StringIO()
1704
 
        def _get_log_contents_for_weird_testtools_api():
1705
 
            return [pseudo_log_file.getvalue().decode(
1706
 
                "utf-8", "replace").encode("utf-8")]
1707
 
        self.addDetail("log", content.Content(content.ContentType("text",
1708
 
            "plain", {"charset": "utf8"}),
1709
 
            _get_log_contents_for_weird_testtools_api))
1710
 
        self._log_file = pseudo_log_file
1711
 
        self._log_memento = trace.push_log_file(self._log_file)
 
1430
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
 
1431
        self._log_file = os.fdopen(fileno, 'w+')
 
1432
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
 
1433
        self._log_file_name = name
1712
1434
        self.addCleanup(self._finishLogFile)
1713
1435
 
1714
1436
    def _finishLogFile(self):
1715
1437
        """Finished with the log file.
1716
1438
 
1717
 
        Close the file and delete it.
 
1439
        Close the file and delete it, unless setKeepLogfile was called.
1718
1440
        """
1719
 
        if trace._trace_file:
 
1441
        if bzrlib.trace._trace_file:
1720
1442
            # flush the log file, to get all content
1721
 
            trace._trace_file.flush()
1722
 
        trace.pop_log_file(self._log_memento)
 
1443
            bzrlib.trace._trace_file.flush()
 
1444
        bzrlib.trace.pop_log_file(self._log_memento)
 
1445
        # Cache the log result and delete the file on disk
 
1446
        self._get_log(False)
1723
1447
 
1724
1448
    def thisFailsStrictLockCheck(self):
1725
1449
        """It is known that this test would fail with -Dstrict_locks.
1734
1458
        """
1735
1459
        debug.debug_flags.discard('strict_locks')
1736
1460
 
1737
 
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1738
 
        """Overrides an object attribute restoring it after the test.
1739
 
 
1740
 
        :note: This should be used with discretion; you should think about
1741
 
        whether it's better to make the code testable without monkey-patching.
1742
 
 
1743
 
        :param obj: The object that will be mutated.
1744
 
 
1745
 
        :param attr_name: The attribute name we want to preserve/override in
1746
 
            the object.
1747
 
 
1748
 
        :param new: The optional value we want to set the attribute to.
1749
 
 
1750
 
        :returns: The actual attr value.
1751
 
        """
1752
 
        value = getattr(obj, attr_name)
1753
 
        # The actual value is captured by the call below
1754
 
        self.addCleanup(setattr, obj, attr_name, value)
1755
 
        if new is not _unitialized_attr:
1756
 
            setattr(obj, attr_name, new)
1757
 
        return value
1758
 
 
1759
 
    def overrideEnv(self, name, new):
1760
 
        """Set an environment variable, and reset it after the test.
1761
 
 
1762
 
        :param name: The environment variable name.
1763
 
 
1764
 
        :param new: The value to set the variable to. If None, the 
1765
 
            variable is deleted from the environment.
1766
 
 
1767
 
        :returns: The actual variable value.
1768
 
        """
1769
 
        value = osutils.set_or_unset_env(name, new)
1770
 
        self.addCleanup(osutils.set_or_unset_env, name, value)
1771
 
        return value
1772
 
 
1773
 
    def recordCalls(self, obj, attr_name):
1774
 
        """Monkeypatch in a wrapper that will record calls.
1775
 
 
1776
 
        The monkeypatch is automatically removed when the test concludes.
1777
 
 
1778
 
        :param obj: The namespace holding the reference to be replaced;
1779
 
            typically a module, class, or object.
1780
 
        :param attr_name: A string for the name of the attribute to 
1781
 
            patch.
1782
 
        :returns: A list that will be extended with one item every time the
1783
 
            function is called, with a tuple of (args, kwargs).
1784
 
        """
1785
 
        calls = []
1786
 
 
1787
 
        def decorator(*args, **kwargs):
1788
 
            calls.append((args, kwargs))
1789
 
            return orig(*args, **kwargs)
1790
 
        orig = self.overrideAttr(obj, attr_name, decorator)
1791
 
        return calls
 
1461
    def addCleanup(self, callable, *args, **kwargs):
 
1462
        """Arrange to run a callable when this case is torn down.
 
1463
 
 
1464
        Callables are run in the reverse of the order they are registered,
 
1465
        ie last-in first-out.
 
1466
        """
 
1467
        self._cleanups.append((callable, args, kwargs))
1792
1468
 
1793
1469
    def _cleanEnvironment(self):
1794
 
        for name, value in isolated_environ.iteritems():
1795
 
            self.overrideEnv(name, value)
 
1470
        new_env = {
 
1471
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
 
1472
            'HOME': os.getcwd(),
 
1473
            # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
 
1474
            # tests do check our impls match APPDATA
 
1475
            'BZR_EDITOR': None, # test_msgeditor manipulates this variable
 
1476
            'VISUAL': None,
 
1477
            'EDITOR': None,
 
1478
            'BZR_EMAIL': None,
 
1479
            'BZREMAIL': None, # may still be present in the environment
 
1480
            'EMAIL': None,
 
1481
            'BZR_PROGRESS_BAR': None,
 
1482
            'BZR_LOG': None,
 
1483
            'BZR_PLUGIN_PATH': None,
 
1484
            'BZR_CONCURRENCY': None,
 
1485
            # Make sure that any text ui tests are consistent regardless of
 
1486
            # the environment the test case is run in; you may want tests that
 
1487
            # test other combinations.  'dumb' is a reasonable guess for tests
 
1488
            # going to a pipe or a StringIO.
 
1489
            'TERM': 'dumb',
 
1490
            'LINES': '25',
 
1491
            'COLUMNS': '80',
 
1492
            'BZR_COLUMNS': '80',
 
1493
            # SSH Agent
 
1494
            'SSH_AUTH_SOCK': None,
 
1495
            # Proxies
 
1496
            'http_proxy': None,
 
1497
            'HTTP_PROXY': None,
 
1498
            'https_proxy': None,
 
1499
            'HTTPS_PROXY': None,
 
1500
            'no_proxy': None,
 
1501
            'NO_PROXY': None,
 
1502
            'all_proxy': None,
 
1503
            'ALL_PROXY': None,
 
1504
            # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
 
1505
            # least. If you do (care), please update this comment
 
1506
            # -- vila 20080401
 
1507
            'ftp_proxy': None,
 
1508
            'FTP_PROXY': None,
 
1509
            'BZR_REMOTE_PATH': None,
 
1510
        }
 
1511
        self.__old_env = {}
 
1512
        self.addCleanup(self._restoreEnvironment)
 
1513
        for name, value in new_env.iteritems():
 
1514
            self._captureVar(name, value)
 
1515
 
 
1516
    def _captureVar(self, name, newvalue):
 
1517
        """Set an environment variable, and reset it when finished."""
 
1518
        self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
 
1519
 
 
1520
    def _restore_debug_flags(self):
 
1521
        debug.debug_flags.clear()
 
1522
        debug.debug_flags.update(self._preserved_debug_flags)
 
1523
 
 
1524
    def _restoreEnvironment(self):
 
1525
        for name, value in self.__old_env.iteritems():
 
1526
            osutils.set_or_unset_env(name, value)
1796
1527
 
1797
1528
    def _restoreHooks(self):
1798
1529
        for klass, (name, hooks) in self._preserved_hooks.items():
1799
1530
            setattr(klass, name, hooks)
1800
 
        self._preserved_hooks.clear()
1801
 
        bzrlib.hooks._lazy_hooks = self._preserved_lazy_hooks
1802
 
        self._preserved_lazy_hooks.clear()
1803
1531
 
1804
1532
    def knownFailure(self, reason):
1805
 
        """Declare that this test fails for a known reason
1806
 
 
1807
 
        Tests that are known to fail should generally be using expectedFailure
1808
 
        with an appropriate reverse assertion if a change could cause the test
1809
 
        to start passing. Conversely if the test has no immediate prospect of
1810
 
        succeeding then using skip is more suitable.
1811
 
 
1812
 
        When this method is called while an exception is being handled, that
1813
 
        traceback will be used, otherwise a new exception will be thrown to
1814
 
        provide one but won't be reported.
1815
 
        """
1816
 
        self._add_reason(reason)
1817
 
        try:
1818
 
            exc_info = sys.exc_info()
1819
 
            if exc_info != (None, None, None):
1820
 
                self._report_traceback(exc_info)
1821
 
            else:
1822
 
                try:
1823
 
                    raise self.failureException(reason)
1824
 
                except self.failureException:
1825
 
                    exc_info = sys.exc_info()
1826
 
            # GZ 02-08-2011: Maybe cleanup this err.exc_info attribute too?
1827
 
            raise testtools.testcase._ExpectedFailure(exc_info)
1828
 
        finally:
1829
 
            del exc_info
1830
 
 
1831
 
    def _suppress_log(self):
1832
 
        """Remove the log info from details."""
1833
 
        self.discardDetail('log')
 
1533
        """This test has failed for some known reason."""
 
1534
        raise KnownFailure(reason)
1834
1535
 
1835
1536
    def _do_skip(self, result, reason):
1836
 
        self._suppress_log()
1837
1537
        addSkip = getattr(result, 'addSkip', None)
1838
1538
        if not callable(addSkip):
1839
1539
            result.addSuccess(result)
1842
1542
 
1843
1543
    @staticmethod
1844
1544
    def _do_known_failure(self, result, e):
1845
 
        self._suppress_log()
1846
1545
        err = sys.exc_info()
1847
1546
        addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1848
1547
        if addExpectedFailure is not None:
1856
1555
            reason = 'No reason given'
1857
1556
        else:
1858
1557
            reason = e.args[0]
1859
 
        self._suppress_log ()
1860
1558
        addNotApplicable = getattr(result, 'addNotApplicable', None)
1861
1559
        if addNotApplicable is not None:
1862
1560
            result.addNotApplicable(self, reason)
1864
1562
            self._do_skip(result, reason)
1865
1563
 
1866
1564
    @staticmethod
1867
 
    def _report_skip(self, result, err):
1868
 
        """Override the default _report_skip.
1869
 
 
1870
 
        We want to strip the 'log' detail. If we waint until _do_skip, it has
1871
 
        already been formatted into the 'reason' string, and we can't pull it
1872
 
        out again.
1873
 
        """
1874
 
        self._suppress_log()
1875
 
        super(TestCase, self)._report_skip(self, result, err)
1876
 
 
1877
 
    @staticmethod
1878
 
    def _report_expected_failure(self, result, err):
1879
 
        """Strip the log.
1880
 
 
1881
 
        See _report_skip for motivation.
1882
 
        """
1883
 
        self._suppress_log()
1884
 
        super(TestCase, self)._report_expected_failure(self, result, err)
1885
 
 
1886
 
    @staticmethod
1887
1565
    def _do_unsupported_or_skip(self, result, e):
1888
1566
        reason = e.args[0]
1889
 
        self._suppress_log()
1890
1567
        addNotSupported = getattr(result, 'addNotSupported', None)
1891
1568
        if addNotSupported is not None:
1892
1569
            result.addNotSupported(self, reason)
1918
1595
            self._benchtime += time.time() - start
1919
1596
 
1920
1597
    def log(self, *args):
1921
 
        trace.mutter(*args)
 
1598
        mutter(*args)
 
1599
 
 
1600
    def _get_log(self, keep_log_file=False):
 
1601
        """Internal helper to get the log from bzrlib.trace for this test.
 
1602
 
 
1603
        Please use self.getDetails, or self.get_log to access this in test case
 
1604
        code.
 
1605
 
 
1606
        :param keep_log_file: When True, if the log is still a file on disk
 
1607
            leave it as a file on disk. When False, if the log is still a file
 
1608
            on disk, the log file is deleted and the log preserved as
 
1609
            self._log_contents.
 
1610
        :return: A string containing the log.
 
1611
        """
 
1612
        if self._log_contents is not None:
 
1613
            try:
 
1614
                self._log_contents.decode('utf8')
 
1615
            except UnicodeDecodeError:
 
1616
                unicodestr = self._log_contents.decode('utf8', 'replace')
 
1617
                self._log_contents = unicodestr.encode('utf8')
 
1618
            return self._log_contents
 
1619
        import bzrlib.trace
 
1620
        if bzrlib.trace._trace_file:
 
1621
            # flush the log file, to get all content
 
1622
            bzrlib.trace._trace_file.flush()
 
1623
        if self._log_file_name is not None:
 
1624
            logfile = open(self._log_file_name)
 
1625
            try:
 
1626
                log_contents = logfile.read()
 
1627
            finally:
 
1628
                logfile.close()
 
1629
            try:
 
1630
                log_contents.decode('utf8')
 
1631
            except UnicodeDecodeError:
 
1632
                unicodestr = log_contents.decode('utf8', 'replace')
 
1633
                log_contents = unicodestr.encode('utf8')
 
1634
            if not keep_log_file:
 
1635
                self._log_file.close()
 
1636
                self._log_file = None
 
1637
                # Permit multiple calls to get_log until we clean it up in
 
1638
                # finishLogFile
 
1639
                self._log_contents = log_contents
 
1640
                try:
 
1641
                    os.remove(self._log_file_name)
 
1642
                except OSError, e:
 
1643
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
 
1644
                        sys.stderr.write(('Unable to delete log file '
 
1645
                                             ' %r\n' % self._log_file_name))
 
1646
                    else:
 
1647
                        raise
 
1648
                self._log_file_name = None
 
1649
            return log_contents
 
1650
        else:
 
1651
            return "No log file content and no log file name."
1922
1652
 
1923
1653
    def get_log(self):
1924
1654
        """Get a unicode string containing the log from bzrlib.trace.
1974
1704
 
1975
1705
        try:
1976
1706
            try:
1977
 
                result = self.apply_redirected(
1978
 
                    ui.ui_factory.stdin,
 
1707
                result = self.apply_redirected(ui.ui_factory.stdin,
1979
1708
                    stdout, stderr,
1980
 
                    _mod_commands.run_bzr_catch_user_errors,
 
1709
                    bzrlib.commands.run_bzr_catch_user_errors,
1981
1710
                    args)
1982
1711
            except KeyboardInterrupt:
1983
1712
                # Reraise KeyboardInterrupt with contents of redirected stdout
2125
1854
    def start_bzr_subprocess(self, process_args, env_changes=None,
2126
1855
                             skip_if_plan_to_signal=False,
2127
1856
                             working_dir=None,
2128
 
                             allow_plugins=False, stderr=subprocess.PIPE):
 
1857
                             allow_plugins=False):
2129
1858
        """Start bzr in a subprocess for testing.
2130
1859
 
2131
1860
        This starts a new Python interpreter and runs bzr in there.
2140
1869
            variables. A value of None will unset the env variable.
2141
1870
            The values must be strings. The change will only occur in the
2142
1871
            child, so you don't need to fix the environment after running.
2143
 
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
2144
 
            doesn't support signalling subprocesses.
 
1872
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
 
1873
            is not available.
2145
1874
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
2146
 
        :param stderr: file to use for the subprocess's stderr.  Valid values
2147
 
            are those valid for the stderr argument of `subprocess.Popen`.
2148
 
            Default value is ``subprocess.PIPE``.
2149
1875
 
2150
1876
        :returns: Popen object for the started process.
2151
1877
        """
2152
1878
        if skip_if_plan_to_signal:
2153
 
            if os.name != "posix":
2154
 
                raise TestSkipped("Sending signals not supported")
 
1879
            if not getattr(os, 'kill', None):
 
1880
                raise TestSkipped("os.kill not available.")
2155
1881
 
2156
1882
        if env_changes is None:
2157
1883
            env_changes = {}
2177
1903
            # so we will avoid using it on all platforms, just to
2178
1904
            # make sure the code path is used, and we don't break on win32
2179
1905
            cleanup_environment()
2180
 
            # Include the subprocess's log file in the test details, in case
2181
 
            # the test fails due to an error in the subprocess.
2182
 
            self._add_subprocess_log(trace._get_bzr_log_filename())
2183
1906
            command = [sys.executable]
2184
1907
            # frozen executables don't need the path to bzr
2185
1908
            if getattr(sys, "frozen", None) is None:
2187
1910
            if not allow_plugins:
2188
1911
                command.append('--no-plugins')
2189
1912
            command.extend(process_args)
2190
 
            process = self._popen(command, stdin=subprocess.PIPE,
2191
 
                                  stdout=subprocess.PIPE,
2192
 
                                  stderr=stderr)
 
1913
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
2193
1914
        finally:
2194
1915
            restore_environment()
2195
1916
            if cwd is not None:
2197
1918
 
2198
1919
        return process
2199
1920
 
2200
 
    def _add_subprocess_log(self, log_file_path):
2201
 
        if len(self._log_files) == 0:
2202
 
            # Register an addCleanup func.  We do this on the first call to
2203
 
            # _add_subprocess_log rather than in TestCase.setUp so that this
2204
 
            # addCleanup is registered after any cleanups for tempdirs that
2205
 
            # subclasses might create, which will probably remove the log file
2206
 
            # we want to read.
2207
 
            self.addCleanup(self._subprocess_log_cleanup)
2208
 
        # self._log_files is a set, so if a log file is reused we won't grab it
2209
 
        # twice.
2210
 
        self._log_files.add(log_file_path)
2211
 
 
2212
 
    def _subprocess_log_cleanup(self):
2213
 
        for count, log_file_path in enumerate(self._log_files):
2214
 
            # We use buffer_now=True to avoid holding the file open beyond
2215
 
            # the life of this function, which might interfere with e.g.
2216
 
            # cleaning tempdirs on Windows.
2217
 
            # XXX: Testtools 0.9.5 doesn't have the content_from_file helper
2218
 
            #detail_content = content.content_from_file(
2219
 
            #    log_file_path, buffer_now=True)
2220
 
            with open(log_file_path, 'rb') as log_file:
2221
 
                log_file_bytes = log_file.read()
2222
 
            detail_content = content.Content(content.ContentType("text",
2223
 
                "plain", {"charset": "utf8"}), lambda: [log_file_bytes])
2224
 
            self.addDetail("start_bzr_subprocess-log-%d" % (count,),
2225
 
                detail_content)
2226
 
 
2227
1921
    def _popen(self, *args, **kwargs):
2228
1922
        """Place a call to Popen.
2229
1923
 
2230
1924
        Allows tests to override this method to intercept the calls made to
2231
1925
        Popen for introspection.
2232
1926
        """
2233
 
        return subprocess.Popen(*args, **kwargs)
 
1927
        return Popen(*args, **kwargs)
2234
1928
 
2235
1929
    def get_source_path(self):
2236
1930
        """Return the path of the directory containing bzrlib."""
2238
1932
 
2239
1933
    def get_bzr_path(self):
2240
1934
        """Return the path of the 'bzr' executable for this test suite."""
2241
 
        bzr_path = os.path.join(self.get_source_path(), "bzr")
 
1935
        bzr_path = self.get_source_path()+'/bzr'
2242
1936
        if not os.path.isfile(bzr_path):
2243
1937
            # We are probably installed. Assume sys.argv is the right file
2244
1938
            bzr_path = sys.argv[0]
2266
1960
        if retcode is not None and retcode != process.returncode:
2267
1961
            if process_args is None:
2268
1962
                process_args = "(unknown args)"
2269
 
            trace.mutter('Output of bzr %s:\n%s', process_args, out)
2270
 
            trace.mutter('Error for bzr %s:\n%s', process_args, err)
 
1963
            mutter('Output of bzr %s:\n%s', process_args, out)
 
1964
            mutter('Error for bzr %s:\n%s', process_args, err)
2271
1965
            self.fail('Command bzr %s failed with retcode %s != %s'
2272
1966
                      % (process_args, retcode, process.returncode))
2273
1967
        return [out, err]
2274
1968
 
2275
 
    def check_tree_shape(self, tree, shape):
2276
 
        """Compare a tree to a list of expected names.
 
1969
    def check_inventory_shape(self, inv, shape):
 
1970
        """Compare an inventory to a list of expected names.
2277
1971
 
2278
1972
        Fail if they are not precisely equal.
2279
1973
        """
2280
1974
        extras = []
2281
1975
        shape = list(shape)             # copy
2282
 
        for path, ie in tree.iter_entries_by_dir():
 
1976
        for path, ie in inv.entries():
2283
1977
            name = path.replace('\\', '/')
2284
1978
            if ie.kind == 'directory':
2285
1979
                name = name + '/'
2286
 
            if name == "/":
2287
 
                pass # ignore root entry
2288
 
            elif name in shape:
 
1980
            if name in shape:
2289
1981
                shape.remove(name)
2290
1982
            else:
2291
1983
                extras.append(name)
2332
2024
 
2333
2025
        Tests that expect to provoke LockContention errors should call this.
2334
2026
        """
2335
 
        self.overrideAttr(lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
 
2027
        orig_timeout = bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS
 
2028
        def resetTimeout():
 
2029
            bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = orig_timeout
 
2030
        self.addCleanup(resetTimeout)
 
2031
        bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = 0
2336
2032
 
2337
2033
    def make_utf8_encoded_stringio(self, encoding_type=None):
2338
2034
        """Return a StringIOWrapper instance, that will encode Unicode
2352
2048
        request_handlers = request.request_handlers
2353
2049
        orig_method = request_handlers.get(verb)
2354
2050
        request_handlers.remove(verb)
2355
 
        self.addCleanup(request_handlers.register, verb, orig_method)
 
2051
        def restoreVerb():
 
2052
            request_handlers.register(verb, orig_method)
 
2053
        self.addCleanup(restoreVerb)
2356
2054
 
2357
2055
 
2358
2056
class CapturedCall(object):
2381
2079
class TestCaseWithMemoryTransport(TestCase):
2382
2080
    """Common test class for tests that do not need disk resources.
2383
2081
 
2384
 
    Tests that need disk resources should derive from TestCaseInTempDir
2385
 
    orTestCaseWithTransport.
 
2082
    Tests that need disk resources should derive from TestCaseWithTransport.
2386
2083
 
2387
2084
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2388
2085
 
2389
 
    For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
 
2086
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
2390
2087
    a directory which does not exist. This serves to help ensure test isolation
2391
 
    is preserved. ``test_dir`` is set to the TEST_ROOT, as is cwd, because they
2392
 
    must exist. However, TestCaseWithMemoryTransport does not offer local file
2393
 
    defaults for the transport in tests, nor does it obey the command line
 
2088
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
 
2089
    must exist. However, TestCaseWithMemoryTransport does not offer local
 
2090
    file defaults for the transport in tests, nor does it obey the command line
2394
2091
    override, so tests that accidentally write to the common directory should
2395
2092
    be rare.
2396
2093
 
2397
 
    :cvar TEST_ROOT: Directory containing all temporary directories, plus a
2398
 
        ``.bzr`` directory that stops us ascending higher into the filesystem.
 
2094
    :cvar TEST_ROOT: Directory containing all temporary directories, plus
 
2095
    a .bzr directory that stops us ascending higher into the filesystem.
2399
2096
    """
2400
2097
 
2401
2098
    TEST_ROOT = None
2419
2116
 
2420
2117
        :param relpath: a path relative to the base url.
2421
2118
        """
2422
 
        t = _mod_transport.get_transport_from_url(self.get_url(relpath))
 
2119
        t = get_transport(self.get_url(relpath))
2423
2120
        self.assertFalse(t.is_readonly())
2424
2121
        return t
2425
2122
 
2431
2128
 
2432
2129
        :param relpath: a path relative to the base url.
2433
2130
        """
2434
 
        t = _mod_transport.get_transport(self.get_readonly_url(relpath))
 
2131
        t = get_transport(self.get_readonly_url(relpath))
2435
2132
        self.assertTrue(t.is_readonly())
2436
2133
        return t
2437
2134
 
2450
2147
        if self.__readonly_server is None:
2451
2148
            if self.transport_readonly_server is None:
2452
2149
                # readonly decorator requested
2453
 
                self.__readonly_server = test_server.ReadonlyServer()
 
2150
                self.__readonly_server = ReadonlyServer()
2454
2151
            else:
2455
2152
                # explicit readonly transport.
2456
2153
                self.__readonly_server = self.create_transport_readonly_server()
2479
2176
        is no means to override it.
2480
2177
        """
2481
2178
        if self.__vfs_server is None:
2482
 
            self.__vfs_server = memory.MemoryServer()
 
2179
            self.__vfs_server = MemoryServer()
2483
2180
            self.start_server(self.__vfs_server)
2484
2181
        return self.__vfs_server
2485
2182
 
2558
2255
        real branch.
2559
2256
        """
2560
2257
        root = TestCaseWithMemoryTransport.TEST_ROOT
2561
 
        wt = bzrdir.BzrDir.create_standalone_workingtree(root)
2562
 
        # Hack for speed: remember the raw bytes of the dirstate file so that
2563
 
        # we don't need to re-open the wt to check it hasn't changed.
2564
 
        TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE = (
2565
 
            wt.control_transport.get_bytes('dirstate'))
 
2258
        bzrdir.BzrDir.create_standalone_workingtree(root)
2566
2259
 
2567
2260
    def _check_safety_net(self):
2568
2261
        """Check that the safety .bzr directory have not been touched.
2571
2264
        propagating. This method ensures than a test did not leaked.
2572
2265
        """
2573
2266
        root = TestCaseWithMemoryTransport.TEST_ROOT
2574
 
        t = _mod_transport.get_transport(root)
2575
 
        self.permit_url(t.base)
2576
 
        if (t.get_bytes('.bzr/checkout/dirstate') != 
2577
 
                TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE):
 
2267
        self.permit_url(get_transport(root).base)
 
2268
        wt = workingtree.WorkingTree.open(root)
 
2269
        last_rev = wt.last_revision()
 
2270
        if last_rev != 'null:':
2578
2271
            # The current test have modified the /bzr directory, we need to
2579
2272
            # recreate a new one or all the followng tests will fail.
2580
2273
            # If you need to inspect its content uncomment the following line
2622
2315
            # might be a relative or absolute path
2623
2316
            maybe_a_url = self.get_url(relpath)
2624
2317
            segments = maybe_a_url.rsplit('/', 1)
2625
 
            t = _mod_transport.get_transport(maybe_a_url)
 
2318
            t = get_transport(maybe_a_url)
2626
2319
            if len(segments) > 1 and segments[-1] not in ('', '.'):
2627
2320
                t.ensure_base()
2628
2321
            if format is None:
2645
2338
        made_control = self.make_bzrdir(relpath, format=format)
2646
2339
        return made_control.create_repository(shared=shared)
2647
2340
 
2648
 
    def make_smart_server(self, path, backing_server=None):
2649
 
        if backing_server is None:
2650
 
            backing_server = self.get_server()
2651
 
        smart_server = test_server.SmartTCPServer_for_testing()
2652
 
        self.start_server(smart_server, backing_server)
2653
 
        remote_transport = _mod_transport.get_transport_from_url(smart_server.get_url()
2654
 
                                                   ).clone(path)
 
2341
    def make_smart_server(self, path):
 
2342
        smart_server = server.SmartTCPServer_for_testing()
 
2343
        self.start_server(smart_server, self.get_server())
 
2344
        remote_transport = get_transport(smart_server.get_url()).clone(path)
2655
2345
        return remote_transport
2656
2346
 
2657
2347
    def make_branch_and_memory_tree(self, relpath, format=None):
2667
2357
        test_home_dir = self.test_home_dir
2668
2358
        if isinstance(test_home_dir, unicode):
2669
2359
            test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
2670
 
        self.overrideEnv('HOME', test_home_dir)
2671
 
        self.overrideEnv('BZR_HOME', test_home_dir)
 
2360
        os.environ['HOME'] = test_home_dir
 
2361
        os.environ['BZR_HOME'] = test_home_dir
2672
2362
 
2673
2363
    def setUp(self):
2674
2364
        super(TestCaseWithMemoryTransport, self).setUp()
2675
 
        # Ensure that ConnectedTransport doesn't leak sockets
2676
 
        def get_transport_from_url_with_cleanup(*args, **kwargs):
2677
 
            t = orig_get_transport_from_url(*args, **kwargs)
2678
 
            if isinstance(t, _mod_transport.ConnectedTransport):
2679
 
                self.addCleanup(t.disconnect)
2680
 
            return t
2681
 
 
2682
 
        orig_get_transport_from_url = self.overrideAttr(
2683
 
            _mod_transport, 'get_transport_from_url',
2684
 
            get_transport_from_url_with_cleanup)
2685
2365
        self._make_test_root()
2686
 
        self.addCleanup(os.chdir, os.getcwdu())
 
2366
        _currentdir = os.getcwdu()
 
2367
        def _leaveDirectory():
 
2368
            os.chdir(_currentdir)
 
2369
        self.addCleanup(_leaveDirectory)
2687
2370
        self.makeAndChdirToTestDir()
2688
2371
        self.overrideEnvironmentForTesting()
2689
2372
        self.__readonly_server = None
2692
2375
 
2693
2376
    def setup_smart_server_with_call_log(self):
2694
2377
        """Sets up a smart server as the transport server with a call log."""
2695
 
        self.transport_server = test_server.SmartTCPServer_for_testing
 
2378
        self.transport_server = server.SmartTCPServer_for_testing
2696
2379
        self.hpss_calls = []
2697
2380
        import traceback
2698
2381
        # Skip the current stack down to the caller of
2730
2413
 
2731
2414
    OVERRIDE_PYTHON = 'python'
2732
2415
 
2733
 
    def setUp(self):
2734
 
        super(TestCaseInTempDir, self).setUp()
2735
 
        # Remove the protection set in isolated_environ, we have a proper
2736
 
        # access to disk resources now.
2737
 
        self.overrideEnv('BZR_LOG', None)
2738
 
 
2739
2416
    def check_file_contents(self, filename, expect):
2740
2417
        self.log("check contents of file %s" % filename)
2741
 
        f = file(filename)
2742
 
        try:
2743
 
            contents = f.read()
2744
 
        finally:
2745
 
            f.close()
 
2418
        contents = file(filename, 'r').read()
2746
2419
        if contents != expect:
2747
2420
            self.log("expected: %r" % expect)
2748
2421
            self.log("actually: %r" % contents)
2822
2495
                "a list or a tuple. Got %r instead" % (shape,))
2823
2496
        # It's OK to just create them using forward slashes on windows.
2824
2497
        if transport is None or transport.is_readonly():
2825
 
            transport = _mod_transport.get_transport(".")
 
2498
            transport = get_transport(".")
2826
2499
        for name in shape:
2827
2500
            self.assertIsInstance(name, basestring)
2828
2501
            if name[-1] == '/':
2838
2511
                content = "contents of %s%s" % (name.encode('utf-8'), end)
2839
2512
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
2840
2513
 
2841
 
    build_tree_contents = staticmethod(treeshape.build_tree_contents)
 
2514
    def build_tree_contents(self, shape):
 
2515
        build_tree_contents(shape)
2842
2516
 
2843
2517
    def assertInWorkingTree(self, path, root_path='.', tree=None):
2844
2518
        """Assert whether path or paths are in the WorkingTree"""
2920
2594
            # We can only make working trees locally at the moment.  If the
2921
2595
            # transport can't support them, then we keep the non-disk-backed
2922
2596
            # branch and create a local checkout.
2923
 
            if self.vfs_transport_factory is test_server.LocalURLServer:
 
2597
            if self.vfs_transport_factory is LocalURLServer:
2924
2598
                # the branch is colocated on disk, we cannot create a checkout.
2925
2599
                # hopefully callers will expect this.
2926
2600
                local_controldir= bzrdir.BzrDir.open(self.get_vfs_only_url(relpath))
2985
2659
    """
2986
2660
 
2987
2661
    def setUp(self):
2988
 
        from bzrlib.tests import http_server
2989
2662
        super(ChrootedTestCase, self).setUp()
2990
 
        if not self.vfs_transport_factory == memory.MemoryServer:
2991
 
            self.transport_readonly_server = http_server.HttpServer
 
2663
        if not self.vfs_transport_factory == MemoryServer:
 
2664
            self.transport_readonly_server = HttpServer
2992
2665
 
2993
2666
 
2994
2667
def condition_id_re(pattern):
2997
2670
    :param pattern: A regular expression string.
2998
2671
    :return: A callable that returns True if the re matches.
2999
2672
    """
3000
 
    filter_re = re.compile(pattern, 0)
 
2673
    filter_re = osutils.re_compile_checked(pattern, 0,
 
2674
        'test filter')
3001
2675
    def condition(test):
3002
2676
        test_id = test.id()
3003
2677
        return filter_re.search(test_id)
3255
2929
 
3256
2930
 
3257
2931
def fork_decorator(suite):
3258
 
    if getattr(os, "fork", None) is None:
3259
 
        raise errors.BzrCommandError("platform does not support fork,"
3260
 
            " try --parallel=subprocess instead.")
3261
2932
    concurrency = osutils.local_concurrency()
3262
2933
    if concurrency == 1:
3263
2934
        return suite
3318
2989
    return suite
3319
2990
 
3320
2991
 
3321
 
class TestDecorator(TestUtil.TestSuite):
 
2992
class TestDecorator(TestSuite):
3322
2993
    """A decorator for TestCase/TestSuite objects.
3323
2994
    
3324
2995
    Usually, subclasses should override __iter__(used when flattening test
3327
2998
    """
3328
2999
 
3329
3000
    def __init__(self, suite):
3330
 
        TestUtil.TestSuite.__init__(self)
 
3001
        TestSuite.__init__(self)
3331
3002
        self.addTest(suite)
3332
3003
 
3333
3004
    def countTestCases(self):
3452
3123
 
3453
3124
def partition_tests(suite, count):
3454
3125
    """Partition suite into count lists of tests."""
3455
 
    # This just assigns tests in a round-robin fashion.  On one hand this
3456
 
    # splits up blocks of related tests that might run faster if they shared
3457
 
    # resources, but on the other it avoids assigning blocks of slow tests to
3458
 
    # just one partition.  So the slowest partition shouldn't be much slower
3459
 
    # than the fastest.
3460
 
    partitions = [list() for i in range(count)]
3461
 
    tests = iter_suite_tests(suite)
3462
 
    for partition, test in itertools.izip(itertools.cycle(partitions), tests):
3463
 
        partition.append(test)
3464
 
    return partitions
3465
 
 
3466
 
 
3467
 
def workaround_zealous_crypto_random():
3468
 
    """Crypto.Random want to help us being secure, but we don't care here.
3469
 
 
3470
 
    This workaround some test failure related to the sftp server. Once paramiko
3471
 
    stop using the controversial API in Crypto.Random, we may get rid of it.
3472
 
    """
3473
 
    try:
3474
 
        from Crypto.Random import atfork
3475
 
        atfork()
3476
 
    except ImportError:
3477
 
        pass
 
3126
    result = []
 
3127
    tests = list(iter_suite_tests(suite))
 
3128
    tests_per_process = int(math.ceil(float(len(tests)) / count))
 
3129
    for block in range(count):
 
3130
        low_test = block * tests_per_process
 
3131
        high_test = low_test + tests_per_process
 
3132
        process_tests = tests[low_test:high_test]
 
3133
        result.append(process_tests)
 
3134
    return result
3478
3135
 
3479
3136
 
3480
3137
def fork_for_tests(suite):
3486
3143
    concurrency = osutils.local_concurrency()
3487
3144
    result = []
3488
3145
    from subunit import TestProtocolClient, ProtocolTestCase
3489
 
    from subunit.test_results import AutoTimingTestResultDecorator
3490
3146
    class TestInOtherProcess(ProtocolTestCase):
3491
3147
        # Should be in subunit, I think. RBC.
3492
3148
        def __init__(self, stream, pid):
3497
3153
            try:
3498
3154
                ProtocolTestCase.run(self, result)
3499
3155
            finally:
3500
 
                os.waitpid(self.pid, 0)
 
3156
                os.waitpid(self.pid, os.WNOHANG)
3501
3157
 
3502
3158
    test_blocks = partition_tests(suite, concurrency)
3503
3159
    for process_tests in test_blocks:
3504
 
        process_suite = TestUtil.TestSuite()
 
3160
        process_suite = TestSuite()
3505
3161
        process_suite.addTests(process_tests)
3506
3162
        c2pread, c2pwrite = os.pipe()
3507
3163
        pid = os.fork()
3508
3164
        if pid == 0:
3509
 
            workaround_zealous_crypto_random()
3510
3165
            try:
3511
3166
                os.close(c2pread)
3512
3167
                # Leave stderr and stdout open so we can see test noise
3573
3228
                '--subunit']
3574
3229
            if '--no-plugins' in sys.argv:
3575
3230
                argv.append('--no-plugins')
3576
 
            # stderr=subprocess.STDOUT would be ideal, but until we prevent
3577
 
            # noise on stderr it can interrupt the subunit protocol.
3578
 
            process = subprocess.Popen(argv, stdin=subprocess.PIPE,
3579
 
                                      stdout=subprocess.PIPE,
3580
 
                                      stderr=subprocess.PIPE,
3581
 
                                      bufsize=1)
 
3231
            # stderr=STDOUT would be ideal, but until we prevent noise on
 
3232
            # stderr it can interrupt the subunit protocol.
 
3233
            process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
 
3234
                bufsize=1)
3582
3235
            test = TestInSubprocess(process, test_list_file_name)
3583
3236
            result.append(test)
3584
3237
        except:
3587
3240
    return result
3588
3241
 
3589
3242
 
3590
 
class ProfileResult(testtools.ExtendedToOriginalDecorator):
 
3243
class ForwardingResult(unittest.TestResult):
 
3244
 
 
3245
    def __init__(self, target):
 
3246
        unittest.TestResult.__init__(self)
 
3247
        self.result = target
 
3248
 
 
3249
    def startTest(self, test):
 
3250
        self.result.startTest(test)
 
3251
 
 
3252
    def stopTest(self, test):
 
3253
        self.result.stopTest(test)
 
3254
 
 
3255
    def startTestRun(self):
 
3256
        self.result.startTestRun()
 
3257
 
 
3258
    def stopTestRun(self):
 
3259
        self.result.stopTestRun()
 
3260
 
 
3261
    def addSkip(self, test, reason):
 
3262
        self.result.addSkip(test, reason)
 
3263
 
 
3264
    def addSuccess(self, test):
 
3265
        self.result.addSuccess(test)
 
3266
 
 
3267
    def addError(self, test, err):
 
3268
        self.result.addError(test, err)
 
3269
 
 
3270
    def addFailure(self, test, err):
 
3271
        self.result.addFailure(test, err)
 
3272
ForwardingResult = testtools.ExtendedToOriginalDecorator
 
3273
 
 
3274
 
 
3275
from subunit.test_results import AutoTimingTestResultDecorator
 
3276
 
 
3277
 
 
3278
class ProfileResult(ForwardingResult):
3591
3279
    """Generate profiling data for all activity between start and success.
3592
3280
    
3593
3281
    The profile data is appended to the test's _benchcalls attribute and can
3601
3289
 
3602
3290
    def startTest(self, test):
3603
3291
        self.profiler = bzrlib.lsprof.BzrProfiler()
3604
 
        # Prevent deadlocks in tests that use lsprof: those tests will
3605
 
        # unavoidably fail.
3606
 
        bzrlib.lsprof.BzrProfiler.profiler_block = 0
3607
3292
        self.profiler.start()
3608
 
        testtools.ExtendedToOriginalDecorator.startTest(self, test)
 
3293
        ForwardingResult.startTest(self, test)
3609
3294
 
3610
3295
    def addSuccess(self, test):
3611
3296
        stats = self.profiler.stop()
3615
3300
            test._benchcalls = []
3616
3301
            calls = test._benchcalls
3617
3302
        calls.append(((test.id(), "", ""), stats))
3618
 
        testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
 
3303
        ForwardingResult.addSuccess(self, test)
3619
3304
 
3620
3305
    def stopTest(self, test):
3621
 
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
 
3306
        ForwardingResult.stopTest(self, test)
3622
3307
        self.profiler = None
3623
3308
 
3624
3309
 
3630
3315
#                           rather than failing tests. And no longer raise
3631
3316
#                           LockContention when fctnl locks are not being used
3632
3317
#                           with proper exclusion rules.
3633
 
#   -Ethreads               Will display thread ident at creation/join time to
3634
 
#                           help track thread leaks
3635
 
 
3636
 
#   -Econfig_stats          Will collect statistics using addDetail
3637
3318
selftest_debug_flags = set()
3638
3319
 
3639
3320
 
3833
3514
                key, obj, help=help, info=info, override_existing=False)
3834
3515
        except KeyError:
3835
3516
            actual = self.get(key)
3836
 
            trace.note(
3837
 
                'Test prefix alias %s is already used for %s, ignoring %s'
3838
 
                % (key, actual, obj))
 
3517
            note('Test prefix alias %s is already used for %s, ignoring %s'
 
3518
                 % (key, actual, obj))
3839
3519
 
3840
3520
    def resolve_alias(self, id_start):
3841
3521
        """Replace the alias by the prefix in the given string.
3859
3539
# appear prefixed ('bzrlib.' is "replaced" by 'bzrlib.').
3860
3540
test_prefix_alias_registry.register('bzrlib', 'bzrlib')
3861
3541
 
3862
 
# Obvious highest levels prefixes, feel free to add your own via a plugin
 
3542
# Obvious higest levels prefixes, feel free to add your own via a plugin
3863
3543
test_prefix_alias_registry.register('bd', 'bzrlib.doc')
3864
3544
test_prefix_alias_registry.register('bu', 'bzrlib.utils')
3865
3545
test_prefix_alias_registry.register('bt', 'bzrlib.tests')
3873
3553
        'bzrlib.doc',
3874
3554
        'bzrlib.tests.blackbox',
3875
3555
        'bzrlib.tests.commands',
3876
 
        'bzrlib.tests.doc_generate',
3877
3556
        'bzrlib.tests.per_branch',
3878
3557
        'bzrlib.tests.per_bzrdir',
3879
 
        'bzrlib.tests.per_controldir',
3880
 
        'bzrlib.tests.per_controldir_colo',
3881
3558
        'bzrlib.tests.per_foreign_vcs',
3882
3559
        'bzrlib.tests.per_interrepository',
3883
3560
        'bzrlib.tests.per_intertree',
3884
3561
        'bzrlib.tests.per_inventory',
3885
3562
        'bzrlib.tests.per_interbranch',
3886
3563
        'bzrlib.tests.per_lock',
3887
 
        'bzrlib.tests.per_merger',
3888
3564
        'bzrlib.tests.per_transport',
3889
3565
        'bzrlib.tests.per_tree',
3890
3566
        'bzrlib.tests.per_pack_repository',
3891
3567
        'bzrlib.tests.per_repository',
3892
3568
        'bzrlib.tests.per_repository_chk',
3893
3569
        'bzrlib.tests.per_repository_reference',
3894
 
        'bzrlib.tests.per_repository_vf',
3895
3570
        'bzrlib.tests.per_uifactory',
3896
3571
        'bzrlib.tests.per_versionedfile',
3897
3572
        'bzrlib.tests.per_workingtree',
3898
3573
        'bzrlib.tests.test__annotator',
3899
 
        'bzrlib.tests.test__bencode',
3900
 
        'bzrlib.tests.test__btree_serializer',
3901
3574
        'bzrlib.tests.test__chk_map',
3902
3575
        'bzrlib.tests.test__dirstate_helpers',
3903
3576
        'bzrlib.tests.test__groupcompress',
3911
3584
        'bzrlib.tests.test_api',
3912
3585
        'bzrlib.tests.test_atomicfile',
3913
3586
        'bzrlib.tests.test_bad_files',
 
3587
        'bzrlib.tests.test_bencode',
3914
3588
        'bzrlib.tests.test_bisect_multi',
3915
3589
        'bzrlib.tests.test_branch',
3916
3590
        'bzrlib.tests.test_branchbuilder',
3925
3599
        'bzrlib.tests.test_chunk_writer',
3926
3600
        'bzrlib.tests.test_clean_tree',
3927
3601
        'bzrlib.tests.test_cleanup',
3928
 
        'bzrlib.tests.test_cmdline',
3929
3602
        'bzrlib.tests.test_commands',
3930
3603
        'bzrlib.tests.test_commit',
3931
3604
        'bzrlib.tests.test_commit_merge',
3932
3605
        'bzrlib.tests.test_config',
3933
3606
        'bzrlib.tests.test_conflicts',
3934
 
        'bzrlib.tests.test_controldir',
3935
3607
        'bzrlib.tests.test_counted_lock',
3936
3608
        'bzrlib.tests.test_crash',
3937
3609
        'bzrlib.tests.test_decorators',
3938
3610
        'bzrlib.tests.test_delta',
3939
3611
        'bzrlib.tests.test_debug',
 
3612
        'bzrlib.tests.test_deprecated_graph',
3940
3613
        'bzrlib.tests.test_diff',
3941
3614
        'bzrlib.tests.test_directory_service',
3942
3615
        'bzrlib.tests.test_dirstate',
3944
3617
        'bzrlib.tests.test_eol_filters',
3945
3618
        'bzrlib.tests.test_errors',
3946
3619
        'bzrlib.tests.test_export',
3947
 
        'bzrlib.tests.test_export_pot',
3948
3620
        'bzrlib.tests.test_extract',
3949
 
        'bzrlib.tests.test_features',
3950
3621
        'bzrlib.tests.test_fetch',
3951
 
        'bzrlib.tests.test_fixtures',
3952
3622
        'bzrlib.tests.test_fifo_cache',
3953
3623
        'bzrlib.tests.test_filters',
3954
 
        'bzrlib.tests.test_filter_tree',
3955
3624
        'bzrlib.tests.test_ftp_transport',
3956
3625
        'bzrlib.tests.test_foreign',
3957
3626
        'bzrlib.tests.test_generate_docs',
3966
3635
        'bzrlib.tests.test_http',
3967
3636
        'bzrlib.tests.test_http_response',
3968
3637
        'bzrlib.tests.test_https_ca_bundle',
3969
 
        'bzrlib.tests.test_i18n',
3970
3638
        'bzrlib.tests.test_identitymap',
3971
3639
        'bzrlib.tests.test_ignores',
3972
3640
        'bzrlib.tests.test_index',
3973
 
        'bzrlib.tests.test_import_tariff',
3974
3641
        'bzrlib.tests.test_info',
3975
3642
        'bzrlib.tests.test_inv',
3976
3643
        'bzrlib.tests.test_inventory_delta',
3977
3644
        'bzrlib.tests.test_knit',
3978
3645
        'bzrlib.tests.test_lazy_import',
3979
3646
        'bzrlib.tests.test_lazy_regex',
3980
 
        'bzrlib.tests.test_library_state',
3981
3647
        'bzrlib.tests.test_lock',
3982
3648
        'bzrlib.tests.test_lockable_files',
3983
3649
        'bzrlib.tests.test_lockdir',
3985
3651
        'bzrlib.tests.test_lru_cache',
3986
3652
        'bzrlib.tests.test_lsprof',
3987
3653
        'bzrlib.tests.test_mail_client',
3988
 
        'bzrlib.tests.test_matchers',
3989
3654
        'bzrlib.tests.test_memorytree',
3990
3655
        'bzrlib.tests.test_merge',
3991
3656
        'bzrlib.tests.test_merge3',
3992
3657
        'bzrlib.tests.test_merge_core',
3993
3658
        'bzrlib.tests.test_merge_directive',
3994
 
        'bzrlib.tests.test_mergetools',
3995
3659
        'bzrlib.tests.test_missing',
3996
3660
        'bzrlib.tests.test_msgeditor',
3997
3661
        'bzrlib.tests.test_multiparent',
4006
3670
        'bzrlib.tests.test_permissions',
4007
3671
        'bzrlib.tests.test_plugins',
4008
3672
        'bzrlib.tests.test_progress',
4009
 
        'bzrlib.tests.test_pyutils',
4010
3673
        'bzrlib.tests.test_read_bundle',
4011
3674
        'bzrlib.tests.test_reconcile',
4012
3675
        'bzrlib.tests.test_reconfigure',
4021
3684
        'bzrlib.tests.test_rio',
4022
3685
        'bzrlib.tests.test_rules',
4023
3686
        'bzrlib.tests.test_sampler',
4024
 
        'bzrlib.tests.test_scenarios',
4025
3687
        'bzrlib.tests.test_script',
4026
3688
        'bzrlib.tests.test_selftest',
4027
3689
        'bzrlib.tests.test_serializer',
4043
3705
        'bzrlib.tests.test_switch',
4044
3706
        'bzrlib.tests.test_symbol_versioning',
4045
3707
        'bzrlib.tests.test_tag',
4046
 
        'bzrlib.tests.test_test_server',
4047
3708
        'bzrlib.tests.test_testament',
4048
3709
        'bzrlib.tests.test_textfile',
4049
3710
        'bzrlib.tests.test_textmerge',
4050
 
        'bzrlib.tests.test_cethread',
4051
3711
        'bzrlib.tests.test_timestamp',
4052
3712
        'bzrlib.tests.test_trace',
4053
3713
        'bzrlib.tests.test_transactions',
4056
3716
        'bzrlib.tests.test_transport_log',
4057
3717
        'bzrlib.tests.test_tree',
4058
3718
        'bzrlib.tests.test_treebuilder',
4059
 
        'bzrlib.tests.test_treeshape',
4060
3719
        'bzrlib.tests.test_tsort',
4061
3720
        'bzrlib.tests.test_tuned_gzip',
4062
3721
        'bzrlib.tests.test_ui',
4064
3723
        'bzrlib.tests.test_upgrade',
4065
3724
        'bzrlib.tests.test_upgrade_stacked',
4066
3725
        'bzrlib.tests.test_urlutils',
4067
 
        'bzrlib.tests.test_utextwrap',
4068
3726
        'bzrlib.tests.test_version',
4069
3727
        'bzrlib.tests.test_version_info',
4070
 
        'bzrlib.tests.test_versionedfile',
4071
3728
        'bzrlib.tests.test_weave',
4072
3729
        'bzrlib.tests.test_whitebox',
4073
3730
        'bzrlib.tests.test_win32utils',
4079
3736
 
4080
3737
 
4081
3738
def _test_suite_modules_to_doctest():
4082
 
    """Return the list of modules to doctest."""
4083
 
    if __doc__ is None:
4084
 
        # GZ 2009-03-31: No docstrings with -OO so there's nothing to doctest
4085
 
        return []
 
3739
    """Return the list of modules to doctest."""   
4086
3740
    return [
4087
3741
        'bzrlib',
4088
3742
        'bzrlib.branchbuilder',
4089
 
        'bzrlib.decorators',
 
3743
        'bzrlib.export',
4090
3744
        'bzrlib.inventory',
4091
3745
        'bzrlib.iterablefile',
4092
3746
        'bzrlib.lockdir',
4093
3747
        'bzrlib.merge3',
4094
3748
        'bzrlib.option',
4095
 
        'bzrlib.pyutils',
4096
3749
        'bzrlib.symbol_versioning',
4097
3750
        'bzrlib.tests',
4098
 
        'bzrlib.tests.fixtures',
4099
3751
        'bzrlib.timestamp',
4100
 
        'bzrlib.transport.http',
4101
3752
        'bzrlib.version_info_formats.format_custom',
4102
3753
        ]
4103
3754
 
4156
3807
        try:
4157
3808
            # note that this really does mean "report only" -- doctest
4158
3809
            # still runs the rest of the examples
4159
 
            doc_suite = IsolatedDocTestSuite(
4160
 
                mod, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
 
3810
            doc_suite = doctest.DocTestSuite(mod,
 
3811
                optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
4161
3812
        except ValueError, e:
4162
3813
            print '**failed to get doctest for: %s\n%s' % (mod, e)
4163
3814
            raise
4166
3817
        suite.addTest(doc_suite)
4167
3818
 
4168
3819
    default_encoding = sys.getdefaultencoding()
4169
 
    for name, plugin in _mod_plugin.plugins().items():
 
3820
    for name, plugin in bzrlib.plugin.plugins().items():
4170
3821
        if not interesting_module(plugin.module.__name__):
4171
3822
            continue
4172
3823
        plugin_suite = plugin.test_suite()
4178
3829
        if plugin_suite is not None:
4179
3830
            suite.addTest(plugin_suite)
4180
3831
        if default_encoding != sys.getdefaultencoding():
4181
 
            trace.warning(
 
3832
            bzrlib.trace.warning(
4182
3833
                'Plugin "%s" tried to reset default encoding to: %s', name,
4183
3834
                sys.getdefaultencoding())
4184
3835
            reload(sys)
4199
3850
            # Some tests mentioned in the list are not in the test suite. The
4200
3851
            # list may be out of date, report to the tester.
4201
3852
            for id in not_found:
4202
 
                trace.warning('"%s" not found in the test suite', id)
 
3853
                bzrlib.trace.warning('"%s" not found in the test suite', id)
4203
3854
        for id in duplicates:
4204
 
            trace.warning('"%s" is used as an id by several tests', id)
 
3855
            bzrlib.trace.warning('"%s" is used as an id by several tests', id)
4205
3856
 
4206
3857
    return suite
4207
3858
 
4208
3859
 
4209
 
def multiply_scenarios(*scenarios):
4210
 
    """Multiply two or more iterables of scenarios.
4211
 
 
4212
 
    It is safe to pass scenario generators or iterators.
4213
 
 
4214
 
    :returns: A list of compound scenarios: the cross-product of all 
4215
 
        scenarios, with the names concatenated and the parameters
4216
 
        merged together.
4217
 
    """
4218
 
    return reduce(_multiply_two_scenarios, map(list, scenarios))
4219
 
 
4220
 
 
4221
 
def _multiply_two_scenarios(scenarios_left, scenarios_right):
 
3860
def multiply_scenarios(scenarios_left, scenarios_right):
4222
3861
    """Multiply two sets of scenarios.
4223
3862
 
4224
3863
    :returns: the cartesian product of the two sets of scenarios, that is
4255
3894
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
4256
3895
    ...     [('one', dict(param=1)),
4257
3896
    ...      ('two', dict(param=2))],
4258
 
    ...     TestUtil.TestSuite())
 
3897
    ...     TestSuite())
4259
3898
    >>> tests = list(iter_suite_tests(r))
4260
3899
    >>> len(tests)
4261
3900
    2
4308
3947
    :param new_id: The id to assign to it.
4309
3948
    :return: The new test.
4310
3949
    """
4311
 
    new_test = copy.copy(test)
 
3950
    new_test = copy(test)
4312
3951
    new_test.id = lambda: new_id
4313
 
    # XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
4314
 
    # causes cloned tests to share the 'details' dict.  This makes it hard to
4315
 
    # read the test output for parameterized tests, because tracebacks will be
4316
 
    # associated with irrelevant tests.
4317
 
    try:
4318
 
        details = new_test._TestCase__details
4319
 
    except AttributeError:
4320
 
        # must be a different version of testtools than expected.  Do nothing.
4321
 
        pass
4322
 
    else:
4323
 
        # Reset the '__details' dict.
4324
 
        new_test._TestCase__details = {}
4325
3952
    return new_test
4326
3953
 
4327
3954
 
4328
 
def permute_tests_for_extension(standard_tests, loader, py_module_name,
4329
 
                                ext_module_name):
4330
 
    """Helper for permutating tests against an extension module.
4331
 
 
4332
 
    This is meant to be used inside a modules 'load_tests()' function. It will
4333
 
    create 2 scenarios, and cause all tests in the 'standard_tests' to be run
4334
 
    against both implementations. Setting 'test.module' to the appropriate
4335
 
    module. See bzrlib.tests.test__chk_map.load_tests as an example.
4336
 
 
4337
 
    :param standard_tests: A test suite to permute
4338
 
    :param loader: A TestLoader
4339
 
    :param py_module_name: The python path to a python module that can always
4340
 
        be loaded, and will be considered the 'python' implementation. (eg
4341
 
        'bzrlib._chk_map_py')
4342
 
    :param ext_module_name: The python path to an extension module. If the
4343
 
        module cannot be loaded, a single test will be added, which notes that
4344
 
        the module is not available. If it can be loaded, all standard_tests
4345
 
        will be run against that module.
4346
 
    :return: (suite, feature) suite is a test-suite that has all the permuted
4347
 
        tests. feature is the Feature object that can be used to determine if
4348
 
        the module is available.
4349
 
    """
4350
 
 
4351
 
    from bzrlib.tests.features import ModuleAvailableFeature
4352
 
    py_module = pyutils.get_named_object(py_module_name)
4353
 
    scenarios = [
4354
 
        ('python', {'module': py_module}),
4355
 
    ]
4356
 
    suite = loader.suiteClass()
4357
 
    feature = ModuleAvailableFeature(ext_module_name)
4358
 
    if feature.available():
4359
 
        scenarios.append(('C', {'module': feature.module}))
4360
 
    else:
4361
 
        # the compiled module isn't available, so we add a failing test
4362
 
        class FailWithoutFeature(TestCase):
4363
 
            def test_fail(self):
4364
 
                self.requireFeature(feature)
4365
 
        suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
4366
 
    result = multiply_tests(standard_tests, scenarios, suite)
4367
 
    return result, feature
4368
 
 
4369
 
 
4370
3955
def _rmtree_temp_dir(dirname, test_id=None):
4371
3956
    # If LANG=C we probably have created some bogus paths
4372
3957
    # which rmtree(unicode) will fail to delete
4388
3973
        if test_id != None:
4389
3974
            ui.ui_factory.clear_term()
4390
3975
            sys.stderr.write('\nWhile running: %s\n' % (test_id,))
4391
 
        # Ugly, but the last thing we want here is fail, so bear with it.
4392
 
        printable_e = str(e).decode(osutils.get_user_encoding(), 'replace'
4393
 
                                    ).encode('ascii', 'replace')
4394
3976
        sys.stderr.write('Unable to remove testing dir %s\n%s'
4395
 
                         % (os.path.basename(dirname), printable_e))
 
3977
                         % (os.path.basename(dirname), e))
 
3978
 
 
3979
 
 
3980
class Feature(object):
 
3981
    """An operating system Feature."""
 
3982
 
 
3983
    def __init__(self):
 
3984
        self._available = None
 
3985
 
 
3986
    def available(self):
 
3987
        """Is the feature available?
 
3988
 
 
3989
        :return: True if the feature is available.
 
3990
        """
 
3991
        if self._available is None:
 
3992
            self._available = self._probe()
 
3993
        return self._available
 
3994
 
 
3995
    def _probe(self):
 
3996
        """Implement this method in concrete features.
 
3997
 
 
3998
        :return: True if the feature is available.
 
3999
        """
 
4000
        raise NotImplementedError
 
4001
 
 
4002
    def __str__(self):
 
4003
        if getattr(self, 'feature_name', None):
 
4004
            return self.feature_name()
 
4005
        return self.__class__.__name__
 
4006
 
 
4007
 
 
4008
class _SymlinkFeature(Feature):
 
4009
 
 
4010
    def _probe(self):
 
4011
        return osutils.has_symlinks()
 
4012
 
 
4013
    def feature_name(self):
 
4014
        return 'symlinks'
 
4015
 
 
4016
SymlinkFeature = _SymlinkFeature()
 
4017
 
 
4018
 
 
4019
class _HardlinkFeature(Feature):
 
4020
 
 
4021
    def _probe(self):
 
4022
        return osutils.has_hardlinks()
 
4023
 
 
4024
    def feature_name(self):
 
4025
        return 'hardlinks'
 
4026
 
 
4027
HardlinkFeature = _HardlinkFeature()
 
4028
 
 
4029
 
 
4030
class _OsFifoFeature(Feature):
 
4031
 
 
4032
    def _probe(self):
 
4033
        return getattr(os, 'mkfifo', None)
 
4034
 
 
4035
    def feature_name(self):
 
4036
        return 'filesystem fifos'
 
4037
 
 
4038
OsFifoFeature = _OsFifoFeature()
 
4039
 
 
4040
 
 
4041
class _UnicodeFilenameFeature(Feature):
 
4042
    """Does the filesystem support Unicode filenames?"""
 
4043
 
 
4044
    def _probe(self):
 
4045
        try:
 
4046
            # Check for character combinations unlikely to be covered by any
 
4047
            # single non-unicode encoding. We use the characters
 
4048
            # - greek small letter alpha (U+03B1) and
 
4049
            # - braille pattern dots-123456 (U+283F).
 
4050
            os.stat(u'\u03b1\u283f')
 
4051
        except UnicodeEncodeError:
 
4052
            return False
 
4053
        except (IOError, OSError):
 
4054
            # The filesystem allows the Unicode filename but the file doesn't
 
4055
            # exist.
 
4056
            return True
 
4057
        else:
 
4058
            # The filesystem allows the Unicode filename and the file exists,
 
4059
            # for some reason.
 
4060
            return True
 
4061
 
 
4062
UnicodeFilenameFeature = _UnicodeFilenameFeature()
 
4063
 
 
4064
 
 
4065
class ModuleAvailableFeature(Feature):
 
4066
    """This is a feature than describes a module we want to be available.
 
4067
 
 
4068
    Declare the name of the module in __init__(), and then after probing, the
 
4069
    module will be available as 'self.module'.
 
4070
 
 
4071
    :ivar module: The module if it is available, else None.
 
4072
    """
 
4073
 
 
4074
    def __init__(self, module_name):
 
4075
        super(ModuleAvailableFeature, self).__init__()
 
4076
        self.module_name = module_name
 
4077
 
 
4078
    def _probe(self):
 
4079
        try:
 
4080
            self._module = __import__(self.module_name, {}, {}, [''])
 
4081
            return True
 
4082
        except ImportError:
 
4083
            return False
 
4084
 
 
4085
    @property
 
4086
    def module(self):
 
4087
        if self.available(): # Make sure the probe has been done
 
4088
            return self._module
 
4089
        return None
 
4090
    
 
4091
    def feature_name(self):
 
4092
        return self.module_name
 
4093
 
4396
4094
 
4397
4095
 
4398
4096
def probe_unicode_in_user_encoding():
4428
4126
    return None
4429
4127
 
4430
4128
 
 
4129
class _HTTPSServerFeature(Feature):
 
4130
    """Some tests want an https Server, check if one is available.
 
4131
 
 
4132
    Right now, the only way this is available is under python2.6 which provides
 
4133
    an ssl module.
 
4134
    """
 
4135
 
 
4136
    def _probe(self):
 
4137
        try:
 
4138
            import ssl
 
4139
            return True
 
4140
        except ImportError:
 
4141
            return False
 
4142
 
 
4143
    def feature_name(self):
 
4144
        return 'HTTPSServer'
 
4145
 
 
4146
 
 
4147
HTTPSServerFeature = _HTTPSServerFeature()
 
4148
 
 
4149
 
 
4150
class _ParamikoFeature(Feature):
 
4151
    """Is paramiko available?"""
 
4152
 
 
4153
    def _probe(self):
 
4154
        try:
 
4155
            from bzrlib.transport.sftp import SFTPAbsoluteServer
 
4156
            return True
 
4157
        except errors.ParamikoNotPresent:
 
4158
            return False
 
4159
 
 
4160
    def feature_name(self):
 
4161
        return "Paramiko"
 
4162
 
 
4163
 
 
4164
ParamikoFeature = _ParamikoFeature()
 
4165
 
 
4166
 
 
4167
class _UnicodeFilename(Feature):
 
4168
    """Does the filesystem support Unicode filenames?"""
 
4169
 
 
4170
    def _probe(self):
 
4171
        try:
 
4172
            os.stat(u'\u03b1')
 
4173
        except UnicodeEncodeError:
 
4174
            return False
 
4175
        except (IOError, OSError):
 
4176
            # The filesystem allows the Unicode filename but the file doesn't
 
4177
            # exist.
 
4178
            return True
 
4179
        else:
 
4180
            # The filesystem allows the Unicode filename and the file exists,
 
4181
            # for some reason.
 
4182
            return True
 
4183
 
 
4184
UnicodeFilename = _UnicodeFilename()
 
4185
 
 
4186
 
 
4187
class _UTF8Filesystem(Feature):
 
4188
    """Is the filesystem UTF-8?"""
 
4189
 
 
4190
    def _probe(self):
 
4191
        if osutils._fs_enc.upper() in ('UTF-8', 'UTF8'):
 
4192
            return True
 
4193
        return False
 
4194
 
 
4195
UTF8Filesystem = _UTF8Filesystem()
 
4196
 
 
4197
 
 
4198
class _BreakinFeature(Feature):
 
4199
    """Does this platform support the breakin feature?"""
 
4200
 
 
4201
    def _probe(self):
 
4202
        from bzrlib import breakin
 
4203
        if breakin.determine_signal() is None:
 
4204
            return False
 
4205
        if sys.platform == 'win32':
 
4206
            # Windows doesn't have os.kill, and we catch the SIGBREAK signal.
 
4207
            # We trigger SIGBREAK via a Console api so we need ctypes to
 
4208
            # access the function
 
4209
            try:
 
4210
                import ctypes
 
4211
            except OSError:
 
4212
                return False
 
4213
        return True
 
4214
 
 
4215
    def feature_name(self):
 
4216
        return "SIGQUIT or SIGBREAK w/ctypes on win32"
 
4217
 
 
4218
 
 
4219
BreakinFeature = _BreakinFeature()
 
4220
 
 
4221
 
 
4222
class _CaseInsCasePresFilenameFeature(Feature):
 
4223
    """Is the file-system case insensitive, but case-preserving?"""
 
4224
 
 
4225
    def _probe(self):
 
4226
        fileno, name = tempfile.mkstemp(prefix='MixedCase')
 
4227
        try:
 
4228
            # first check truly case-preserving for created files, then check
 
4229
            # case insensitive when opening existing files.
 
4230
            name = osutils.normpath(name)
 
4231
            base, rel = osutils.split(name)
 
4232
            found_rel = osutils.canonical_relpath(base, name)
 
4233
            return (found_rel == rel
 
4234
                    and os.path.isfile(name.upper())
 
4235
                    and os.path.isfile(name.lower()))
 
4236
        finally:
 
4237
            os.close(fileno)
 
4238
            os.remove(name)
 
4239
 
 
4240
    def feature_name(self):
 
4241
        return "case-insensitive case-preserving filesystem"
 
4242
 
 
4243
CaseInsCasePresFilenameFeature = _CaseInsCasePresFilenameFeature()
 
4244
 
 
4245
 
 
4246
class _CaseInsensitiveFilesystemFeature(Feature):
 
4247
    """Check if underlying filesystem is case-insensitive but *not* case
 
4248
    preserving.
 
4249
    """
 
4250
    # Note that on Windows, Cygwin, MacOS etc, the file-systems are far
 
4251
    # more likely to be case preserving, so this case is rare.
 
4252
 
 
4253
    def _probe(self):
 
4254
        if CaseInsCasePresFilenameFeature.available():
 
4255
            return False
 
4256
 
 
4257
        if TestCaseWithMemoryTransport.TEST_ROOT is None:
 
4258
            root = osutils.mkdtemp(prefix='testbzr-', suffix='.tmp')
 
4259
            TestCaseWithMemoryTransport.TEST_ROOT = root
 
4260
        else:
 
4261
            root = TestCaseWithMemoryTransport.TEST_ROOT
 
4262
        tdir = osutils.mkdtemp(prefix='case-sensitive-probe-', suffix='',
 
4263
            dir=root)
 
4264
        name_a = osutils.pathjoin(tdir, 'a')
 
4265
        name_A = osutils.pathjoin(tdir, 'A')
 
4266
        os.mkdir(name_a)
 
4267
        result = osutils.isdir(name_A)
 
4268
        _rmtree_temp_dir(tdir)
 
4269
        return result
 
4270
 
 
4271
    def feature_name(self):
 
4272
        return 'case-insensitive filesystem'
 
4273
 
 
4274
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
 
4275
 
 
4276
 
 
4277
class _SubUnitFeature(Feature):
 
4278
    """Check if subunit is available."""
 
4279
 
 
4280
    def _probe(self):
 
4281
        try:
 
4282
            import subunit
 
4283
            return True
 
4284
        except ImportError:
 
4285
            return False
 
4286
 
 
4287
    def feature_name(self):
 
4288
        return 'subunit'
 
4289
 
 
4290
SubUnitFeature = _SubUnitFeature()
4431
4291
# Only define SubUnitBzrRunner if subunit is available.
4432
4292
try:
4433
4293
    from subunit import TestProtocolClient
4434
 
    from subunit.test_results import AutoTimingTestResultDecorator
4435
 
    class SubUnitBzrProtocolClient(TestProtocolClient):
4436
 
 
4437
 
        def addSuccess(self, test, details=None):
4438
 
            # The subunit client always includes the details in the subunit
4439
 
            # stream, but we don't want to include it in ours.
4440
 
            if details is not None and 'log' in details:
4441
 
                del details['log']
4442
 
            return super(SubUnitBzrProtocolClient, self).addSuccess(
4443
 
                test, details)
4444
 
 
4445
4294
    class SubUnitBzrRunner(TextTestRunner):
4446
4295
        def run(self, test):
4447
4296
            result = AutoTimingTestResultDecorator(
4448
 
                SubUnitBzrProtocolClient(self.stream))
 
4297
                TestProtocolClient(self.stream))
4449
4298
            test.run(result)
4450
4299
            return result
4451
4300
except ImportError:
4452
4301
    pass
4453
 
 
4454
 
 
4455
 
@deprecated_function(deprecated_in((2, 5, 0)))
4456
 
def ModuleAvailableFeature(name):
4457
 
    from bzrlib.tests import features
4458
 
    return features.ModuleAvailableFeature(name)
4459