~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Martin Packman
  • Date: 2011-12-23 19:38:22 UTC
  • mto: This revision was merged to the branch mainline in revision 6405.
  • Revision ID: martin.packman@canonical.com-20111223193822-hesheea4o8aqwexv
Accept and document passing the medium rather than transport for smart connections

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005-2011 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
 
 
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)
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Testing framework extensions"""
23
18
 
24
19
# NOTE: Some classes in here use camelCaseNaming() rather than
25
20
# underscore_naming().  That's for consistency with unittest; it's not the
28
23
 
29
24
import atexit
30
25
import codecs
 
26
import copy
31
27
from cStringIO import StringIO
32
28
import difflib
33
29
import doctest
34
30
import errno
 
31
import itertools
35
32
import logging
36
33
import os
37
 
from pprint import pformat
 
34
import platform
 
35
import pprint
38
36
import random
39
37
import re
40
38
import shlex
 
39
import site
41
40
import stat
42
 
from subprocess import Popen, PIPE
 
41
import subprocess
43
42
import sys
44
43
import tempfile
 
44
import threading
 
45
import time
 
46
import traceback
45
47
import unittest
46
 
import time
47
48
import warnings
48
49
 
 
50
import testtools
 
51
# nb: check this before importing anything else from within it
 
52
_testtools_version = getattr(testtools, '__version__', ())
 
53
if _testtools_version < (0, 9, 5):
 
54
    raise ImportError("need at least testtools 0.9.5: %s is %r"
 
55
        % (testtools.__file__, _testtools_version))
 
56
from testtools import content
49
57
 
 
58
import bzrlib
50
59
from bzrlib import (
 
60
    branchbuilder,
51
61
    bzrdir,
 
62
    chk_map,
 
63
    commands as _mod_commands,
 
64
    config,
 
65
    i18n,
52
66
    debug,
53
67
    errors,
 
68
    hooks,
 
69
    lock as _mod_lock,
 
70
    lockdir,
54
71
    memorytree,
55
72
    osutils,
56
 
    progress,
 
73
    plugin as _mod_plugin,
 
74
    pyutils,
57
75
    ui,
58
76
    urlutils,
 
77
    registry,
 
78
    symbol_versioning,
 
79
    trace,
 
80
    transport as _mod_transport,
59
81
    workingtree,
60
82
    )
61
 
import bzrlib.branch
62
 
import bzrlib.commands
63
 
import bzrlib.timestamp
64
 
import bzrlib.export
65
 
import bzrlib.inventory
66
 
import bzrlib.iterablefile
67
 
import bzrlib.lockdir
68
83
try:
69
84
    import bzrlib.lsprof
70
85
except ImportError:
71
86
    # lsprof not available
72
87
    pass
73
 
from bzrlib.merge import merge_inner
74
 
import bzrlib.merge3
75
 
import bzrlib.osutils
76
 
import bzrlib.plugin
77
 
from bzrlib.revision import common_ancestor
78
 
import bzrlib.store
79
 
from bzrlib import symbol_versioning
 
88
from bzrlib.smart import client, request
 
89
from bzrlib.transport import (
 
90
    memory,
 
91
    pathfilter,
 
92
    )
80
93
from bzrlib.symbol_versioning import (
81
 
    deprecated_method,
82
 
    zero_eighteen,
83
 
    )
84
 
import bzrlib.trace
85
 
from bzrlib.transport import get_transport
86
 
import bzrlib.transport
87
 
from bzrlib.transport.local import LocalURLServer
88
 
from bzrlib.transport.memory import MemoryServer
89
 
from bzrlib.transport.readonly import ReadonlyServer
90
 
from bzrlib.trace import mutter, note
91
 
from bzrlib.tests import TestUtil
92
 
from bzrlib.tests.HttpServer import HttpServer
93
 
from bzrlib.tests.TestUtil import (
94
 
                          TestSuite,
95
 
                          TestLoader,
96
 
                          )
97
 
from bzrlib.tests.treeshape import build_tree_contents
98
 
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
 
94
    deprecated_function,
 
95
    deprecated_in,
 
96
    )
 
97
from bzrlib.tests import (
 
98
    fixtures,
 
99
    test_server,
 
100
    TestUtil,
 
101
    treeshape,
 
102
    )
 
103
from bzrlib.ui import NullProgressView
 
104
from bzrlib.ui.text import TextUIFactory
 
105
from bzrlib.tests.features import _CompatabilityThunkFeature
99
106
 
100
107
# Mark this python module as being part of the implementation
101
108
# of unittest: this gives us better tracebacks where the last
102
109
# shown frame is the test code, not our assertXYZ.
103
110
__unittest = 1
104
111
 
105
 
default_transport = LocalURLServer
106
 
 
107
 
MODULES_TO_TEST = []
108
 
MODULES_TO_DOCTEST = [
109
 
                      bzrlib.timestamp,
110
 
                      bzrlib.errors,
111
 
                      bzrlib.export,
112
 
                      bzrlib.inventory,
113
 
                      bzrlib.iterablefile,
114
 
                      bzrlib.lockdir,
115
 
                      bzrlib.merge3,
116
 
                      bzrlib.option,
117
 
                      bzrlib.store,
118
 
                      ]
119
 
 
120
 
 
121
 
def packages_to_test():
122
 
    """Return a list of packages to test.
123
 
 
124
 
    The packages are not globally imported so that import failures are
125
 
    triggered when running selftest, not when importing the command.
126
 
    """
127
 
    import bzrlib.doc
128
 
    import bzrlib.tests.blackbox
129
 
    import bzrlib.tests.branch_implementations
130
 
    import bzrlib.tests.bzrdir_implementations
131
 
    import bzrlib.tests.interrepository_implementations
132
 
    import bzrlib.tests.interversionedfile_implementations
133
 
    import bzrlib.tests.intertree_implementations
134
 
    import bzrlib.tests.per_lock
135
 
    import bzrlib.tests.repository_implementations
136
 
    import bzrlib.tests.revisionstore_implementations
137
 
    import bzrlib.tests.tree_implementations
138
 
    import bzrlib.tests.workingtree_implementations
139
 
    return [
140
 
            bzrlib.doc,
141
 
            bzrlib.tests.blackbox,
142
 
            bzrlib.tests.branch_implementations,
143
 
            bzrlib.tests.bzrdir_implementations,
144
 
            bzrlib.tests.interrepository_implementations,
145
 
            bzrlib.tests.interversionedfile_implementations,
146
 
            bzrlib.tests.intertree_implementations,
147
 
            bzrlib.tests.per_lock,
148
 
            bzrlib.tests.repository_implementations,
149
 
            bzrlib.tests.revisionstore_implementations,
150
 
            bzrlib.tests.tree_implementations,
151
 
            bzrlib.tests.workingtree_implementations,
152
 
            ]
153
 
 
154
 
 
155
 
class ExtendedTestResult(unittest._TextTestResult):
 
112
default_transport = test_server.LocalURLServer
 
113
 
 
114
 
 
115
_unitialized_attr = object()
 
116
"""A sentinel needed to act as a default value in a method signature."""
 
117
 
 
118
 
 
119
# Subunit result codes, defined here to prevent a hard dependency on subunit.
 
120
SUBUNIT_SEEK_SET = 0
 
121
SUBUNIT_SEEK_CUR = 1
 
122
 
 
123
# These are intentionally brought into this namespace. That way plugins, etc
 
124
# can just "from bzrlib.tests import TestCase, TestLoader, etc"
 
125
TestSuite = TestUtil.TestSuite
 
126
TestLoader = TestUtil.TestLoader
 
127
 
 
128
# Tests should run in a clean and clearly defined environment. The goal is to
 
129
# keep them isolated from the running environment as mush as possible. The test
 
130
# framework ensures the variables defined below are set (or deleted if the
 
131
# value is None) before a test is run and reset to their original value after
 
132
# the test is run. Generally if some code depends on an environment variable,
 
133
# the tests should start without this variable in the environment. There are a
 
134
# few exceptions but you shouldn't violate this rule lightly.
 
135
isolated_environ = {
 
136
    'BZR_HOME': None,
 
137
    'HOME': None,
 
138
    # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
 
139
    # tests do check our impls match APPDATA
 
140
    'BZR_EDITOR': None, # test_msgeditor manipulates this variable
 
141
    'VISUAL': None,
 
142
    'EDITOR': None,
 
143
    'BZR_EMAIL': None,
 
144
    'BZREMAIL': None, # may still be present in the environment
 
145
    'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
 
146
    'BZR_PROGRESS_BAR': None,
 
147
    # This should trap leaks to ~/.bzr.log. This occurs when tests use TestCase
 
148
    # as a base class instead of TestCaseInTempDir. Tests inheriting from
 
149
    # TestCase should not use disk resources, BZR_LOG is one.
 
150
    'BZR_LOG': '/you-should-use-TestCaseInTempDir-if-you-need-a-log-file',
 
151
    'BZR_PLUGIN_PATH': None,
 
152
    'BZR_DISABLE_PLUGINS': None,
 
153
    'BZR_PLUGINS_AT': None,
 
154
    'BZR_CONCURRENCY': None,
 
155
    # Make sure that any text ui tests are consistent regardless of
 
156
    # the environment the test case is run in; you may want tests that
 
157
    # test other combinations.  'dumb' is a reasonable guess for tests
 
158
    # going to a pipe or a StringIO.
 
159
    'TERM': 'dumb',
 
160
    'LINES': '25',
 
161
    'COLUMNS': '80',
 
162
    'BZR_COLUMNS': '80',
 
163
    # Disable SSH Agent
 
164
    'SSH_AUTH_SOCK': None,
 
165
    # Proxies
 
166
    'http_proxy': None,
 
167
    'HTTP_PROXY': None,
 
168
    'https_proxy': None,
 
169
    'HTTPS_PROXY': None,
 
170
    'no_proxy': None,
 
171
    'NO_PROXY': None,
 
172
    'all_proxy': None,
 
173
    'ALL_PROXY': None,
 
174
    # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
 
175
    # least. If you do (care), please update this comment
 
176
    # -- vila 20080401
 
177
    'ftp_proxy': None,
 
178
    'FTP_PROXY': None,
 
179
    'BZR_REMOTE_PATH': None,
 
180
    # Generally speaking, we don't want apport reporting on crashes in
 
181
    # the test envirnoment unless we're specifically testing apport,
 
182
    # so that it doesn't leak into the real system environment.  We
 
183
    # use an env var so it propagates to subprocesses.
 
184
    'APPORT_DISABLE': '1',
 
185
    }
 
186
 
 
187
 
 
188
def override_os_environ(test, env=None):
 
189
    """Modify os.environ keeping a copy.
 
190
    
 
191
    :param test: A test instance
 
192
 
 
193
    :param env: A dict containing variable definitions to be installed
 
194
    """
 
195
    if env is None:
 
196
        env = isolated_environ
 
197
    test._original_os_environ = dict([(var, value)
 
198
                                      for var, value in os.environ.iteritems()])
 
199
    for var, value in env.iteritems():
 
200
        osutils.set_or_unset_env(var, value)
 
201
        if var not in test._original_os_environ:
 
202
            # The var is new, add it with a value of None, so
 
203
            # restore_os_environ will delete it
 
204
            test._original_os_environ[var] = None
 
205
 
 
206
 
 
207
def restore_os_environ(test):
 
208
    """Restore os.environ to its original state.
 
209
 
 
210
    :param test: A test instance previously passed to override_os_environ.
 
211
    """
 
212
    for var, value in test._original_os_environ.iteritems():
 
213
        # Restore the original value (or delete it if the value has been set to
 
214
        # None in override_os_environ).
 
215
        osutils.set_or_unset_env(var, value)
 
216
 
 
217
 
 
218
def _clear__type_equality_funcs(test):
 
219
    """Cleanup bound methods stored on TestCase instances
 
220
 
 
221
    Clear the dict breaking a few (mostly) harmless cycles in the affected
 
222
    unittests released with Python 2.6 and initial Python 2.7 versions.
 
223
 
 
224
    For a few revisions between Python 2.7.1 and Python 2.7.2 that annoyingly
 
225
    shipped in Oneiric, an object with no clear method was used, hence the
 
226
    extra complications, see bug 809048 for details.
 
227
    """
 
228
    type_equality_funcs = getattr(test, "_type_equality_funcs", None)
 
229
    if type_equality_funcs is not None:
 
230
        tef_clear = getattr(type_equality_funcs, "clear", None)
 
231
        if tef_clear is None:
 
232
            tef_instance_dict = getattr(type_equality_funcs, "__dict__", None)
 
233
            if tef_instance_dict is not None:
 
234
                tef_clear = tef_instance_dict.clear
 
235
        if tef_clear is not None:
 
236
            tef_clear()
 
237
 
 
238
 
 
239
class ExtendedTestResult(testtools.TextTestResult):
156
240
    """Accepts, reports and accumulates the results of running tests.
157
241
 
158
 
    Compared to this unittest version this class adds support for profiling,
159
 
    benchmarking, stopping as soon as a test fails,  and skipping tests.
160
 
    There are further-specialized subclasses for different types of display.
 
242
    Compared to the unittest version this class adds support for
 
243
    profiling, benchmarking, stopping as soon as a test fails,  and
 
244
    skipping tests.  There are further-specialized subclasses for
 
245
    different types of display.
 
246
 
 
247
    When a test finishes, in whatever way, it calls one of the addSuccess,
 
248
    addFailure or addError classes.  These in turn may redirect to a more
 
249
    specific case for the special test results supported by our extended
 
250
    tests.
 
251
 
 
252
    Note that just one of these objects is fed the results from many tests.
161
253
    """
162
254
 
163
255
    stop_early = False
164
 
    
 
256
 
165
257
    def __init__(self, stream, descriptions, verbosity,
166
258
                 bench_history=None,
167
 
                 num_tests=None,
168
 
                 use_numbered_dirs=False,
 
259
                 strict=False,
169
260
                 ):
170
261
        """Construct new TestResult.
171
262
 
172
263
        :param bench_history: Optionally, a writable file object to accumulate
173
264
            benchmark results.
174
265
        """
175
 
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
 
266
        testtools.TextTestResult.__init__(self, stream)
176
267
        if bench_history is not None:
177
268
            from bzrlib.version import _get_bzr_source_tree
178
269
            src_tree = _get_bzr_source_tree()
189
280
            bench_history.write("--date %s %s\n" % (time.time(), revision_id))
190
281
        self._bench_history = bench_history
191
282
        self.ui = ui.ui_factory
192
 
        self.num_tests = num_tests
 
283
        self.num_tests = 0
193
284
        self.error_count = 0
194
285
        self.failure_count = 0
195
286
        self.known_failure_count = 0
196
287
        self.skip_count = 0
 
288
        self.not_applicable_count = 0
197
289
        self.unsupported = {}
198
290
        self.count = 0
199
 
        self.use_numbered_dirs = use_numbered_dirs
200
291
        self._overall_start_time = time.time()
201
 
    
202
 
    def extractBenchmarkTime(self, testCase):
 
292
        self._strict = strict
 
293
        self._first_thread_leaker_id = None
 
294
        self._tests_leaking_threads_count = 0
 
295
        self._traceback_from_test = None
 
296
 
 
297
    def stopTestRun(self):
 
298
        run = self.testsRun
 
299
        actionTaken = "Ran"
 
300
        stopTime = time.time()
 
301
        timeTaken = stopTime - self.startTime
 
302
        # GZ 2010-07-19: Seems testtools has no printErrors method, and though
 
303
        #                the parent class method is similar have to duplicate
 
304
        self._show_list('ERROR', self.errors)
 
305
        self._show_list('FAIL', self.failures)
 
306
        self.stream.write(self.sep2)
 
307
        self.stream.write("%s %d test%s in %.3fs\n\n" % (actionTaken,
 
308
                            run, run != 1 and "s" or "", timeTaken))
 
309
        if not self.wasSuccessful():
 
310
            self.stream.write("FAILED (")
 
311
            failed, errored = map(len, (self.failures, self.errors))
 
312
            if failed:
 
313
                self.stream.write("failures=%d" % failed)
 
314
            if errored:
 
315
                if failed: self.stream.write(", ")
 
316
                self.stream.write("errors=%d" % errored)
 
317
            if self.known_failure_count:
 
318
                if failed or errored: self.stream.write(", ")
 
319
                self.stream.write("known_failure_count=%d" %
 
320
                    self.known_failure_count)
 
321
            self.stream.write(")\n")
 
322
        else:
 
323
            if self.known_failure_count:
 
324
                self.stream.write("OK (known_failures=%d)\n" %
 
325
                    self.known_failure_count)
 
326
            else:
 
327
                self.stream.write("OK\n")
 
328
        if self.skip_count > 0:
 
329
            skipped = self.skip_count
 
330
            self.stream.write('%d test%s skipped\n' %
 
331
                                (skipped, skipped != 1 and "s" or ""))
 
332
        if self.unsupported:
 
333
            for feature, count in sorted(self.unsupported.items()):
 
334
                self.stream.write("Missing feature '%s' skipped %d tests.\n" %
 
335
                    (feature, count))
 
336
        if self._strict:
 
337
            ok = self.wasStrictlySuccessful()
 
338
        else:
 
339
            ok = self.wasSuccessful()
 
340
        if self._first_thread_leaker_id:
 
341
            self.stream.write(
 
342
                '%s is leaking threads among %d leaking tests.\n' % (
 
343
                self._first_thread_leaker_id,
 
344
                self._tests_leaking_threads_count))
 
345
            # We don't report the main thread as an active one.
 
346
            self.stream.write(
 
347
                '%d non-main threads were left active in the end.\n'
 
348
                % (len(self._active_threads) - 1))
 
349
 
 
350
    def getDescription(self, test):
 
351
        return test.id()
 
352
 
 
353
    def _extractBenchmarkTime(self, testCase, details=None):
203
354
        """Add a benchmark time for the current test case."""
204
 
        self._benchmarkTime = getattr(testCase, "_benchtime", None)
205
 
    
 
355
        if details and 'benchtime' in details:
 
356
            return float(''.join(details['benchtime'].iter_bytes()))
 
357
        return getattr(testCase, "_benchtime", None)
 
358
 
206
359
    def _elapsedTestTimeString(self):
207
360
        """Return a time string for the overall time the current test has taken."""
208
 
        return self._formatTime(time.time() - self._start_time)
 
361
        return self._formatTime(self._delta_to_float(
 
362
            self._now() - self._start_datetime))
209
363
 
210
 
    def _testTimeString(self):
211
 
        if self._benchmarkTime is not None:
212
 
            return "%s/%s" % (
213
 
                self._formatTime(self._benchmarkTime),
214
 
                self._elapsedTestTimeString())
 
364
    def _testTimeString(self, testCase):
 
365
        benchmark_time = self._extractBenchmarkTime(testCase)
 
366
        if benchmark_time is not None:
 
367
            return self._formatTime(benchmark_time) + "*"
215
368
        else:
216
 
            return "           %s" % self._elapsedTestTimeString()
 
369
            return self._elapsedTestTimeString()
217
370
 
218
371
    def _formatTime(self, seconds):
219
372
        """Format seconds as milliseconds with leading spaces."""
223
376
 
224
377
    def _shortened_test_description(self, test):
225
378
        what = test.id()
226
 
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
 
379
        what = re.sub(r'^bzrlib\.tests\.', '', what)
227
380
        return what
228
381
 
 
382
    # GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
 
383
    #                multiple times in a row, because the handler is added for
 
384
    #                each test but the container list is shared between cases.
 
385
    #                See lp:498869 lp:625574 and lp:637725 for background.
 
386
    def _record_traceback_from_test(self, exc_info):
 
387
        """Store the traceback from passed exc_info tuple till"""
 
388
        self._traceback_from_test = exc_info[2]
 
389
 
229
390
    def startTest(self, test):
230
 
        unittest.TestResult.startTest(self, test)
 
391
        super(ExtendedTestResult, self).startTest(test)
 
392
        if self.count == 0:
 
393
            self.startTests()
 
394
        self.count += 1
231
395
        self.report_test_start(test)
232
396
        test.number = self.count
233
397
        self._recordTestStartTime()
 
398
        # Make testtools cases give us the real traceback on failure
 
399
        addOnException = getattr(test, "addOnException", None)
 
400
        if addOnException is not None:
 
401
            addOnException(self._record_traceback_from_test)
 
402
        # Only check for thread leaks on bzrlib derived test cases
 
403
        if isinstance(test, TestCase):
 
404
            test.addCleanup(self._check_leaked_threads, test)
 
405
 
 
406
    def stopTest(self, test):
 
407
        super(ExtendedTestResult, self).stopTest(test)
 
408
        # Manually break cycles, means touching various private things but hey
 
409
        getDetails = getattr(test, "getDetails", None)
 
410
        if getDetails is not None:
 
411
            getDetails().clear()
 
412
        _clear__type_equality_funcs(test)
 
413
        self._traceback_from_test = None
 
414
 
 
415
    def startTests(self):
 
416
        self.report_tests_starting()
 
417
        self._active_threads = threading.enumerate()
 
418
 
 
419
    def _check_leaked_threads(self, test):
 
420
        """See if any threads have leaked since last call
 
421
 
 
422
        A sample of live threads is stored in the _active_threads attribute,
 
423
        when this method runs it compares the current live threads and any not
 
424
        in the previous sample are treated as having leaked.
 
425
        """
 
426
        now_active_threads = set(threading.enumerate())
 
427
        threads_leaked = now_active_threads.difference(self._active_threads)
 
428
        if threads_leaked:
 
429
            self._report_thread_leak(test, threads_leaked, now_active_threads)
 
430
            self._tests_leaking_threads_count += 1
 
431
            if self._first_thread_leaker_id is None:
 
432
                self._first_thread_leaker_id = test.id()
 
433
            self._active_threads = now_active_threads
234
434
 
235
435
    def _recordTestStartTime(self):
236
436
        """Record that a test has started."""
237
 
        self._start_time = time.time()
238
 
 
239
 
    def _cleanupLogFile(self, test):
240
 
        # We can only do this if we have one of our TestCases, not if
241
 
        # we have a doctest.
242
 
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
243
 
        if setKeepLogfile is not None:
244
 
            setKeepLogfile()
 
437
        self._start_datetime = self._now()
245
438
 
246
439
    def addError(self, test, err):
247
 
        self.extractBenchmarkTime(test)
248
 
        self._cleanupLogFile(test)
249
 
        if isinstance(err[1], TestSkipped):
250
 
            return self.addSkipped(test, err)
251
 
        elif isinstance(err[1], UnavailableFeature):
252
 
            return self.addNotSupported(test, err[1].args[0])
253
 
        unittest.TestResult.addError(self, test, err)
 
440
        """Tell result that test finished with an error.
 
441
 
 
442
        Called from the TestCase run() method when the test
 
443
        fails with an unexpected error.
 
444
        """
 
445
        self._post_mortem(self._traceback_from_test)
 
446
        super(ExtendedTestResult, self).addError(test, err)
254
447
        self.error_count += 1
255
448
        self.report_error(test, err)
256
449
        if self.stop_early:
257
450
            self.stop()
258
451
 
259
452
    def addFailure(self, test, err):
260
 
        self._cleanupLogFile(test)
261
 
        self.extractBenchmarkTime(test)
262
 
        if isinstance(err[1], KnownFailure):
263
 
            return self.addKnownFailure(test, err)
264
 
        unittest.TestResult.addFailure(self, test, err)
 
453
        """Tell result that test failed.
 
454
 
 
455
        Called from the TestCase run() method when the test
 
456
        fails because e.g. an assert() method failed.
 
457
        """
 
458
        self._post_mortem(self._traceback_from_test)
 
459
        super(ExtendedTestResult, self).addFailure(test, err)
265
460
        self.failure_count += 1
266
461
        self.report_failure(test, err)
267
462
        if self.stop_early:
268
463
            self.stop()
269
464
 
270
 
    def addKnownFailure(self, test, err):
 
465
    def addSuccess(self, test, details=None):
 
466
        """Tell result that test completed successfully.
 
467
 
 
468
        Called from the TestCase run()
 
469
        """
 
470
        if self._bench_history is not None:
 
471
            benchmark_time = self._extractBenchmarkTime(test, details)
 
472
            if benchmark_time is not None:
 
473
                self._bench_history.write("%s %s\n" % (
 
474
                    self._formatTime(benchmark_time),
 
475
                    test.id()))
 
476
        self.report_success(test)
 
477
        super(ExtendedTestResult, self).addSuccess(test)
 
478
        test._log_contents = ''
 
479
 
 
480
    def addExpectedFailure(self, test, err):
271
481
        self.known_failure_count += 1
272
482
        self.report_known_failure(test, err)
273
483
 
 
484
    def addUnexpectedSuccess(self, test, details=None):
 
485
        """Tell result the test unexpectedly passed, counting as a failure
 
486
 
 
487
        When the minimum version of testtools required becomes 0.9.8 this
 
488
        can be updated to use the new handling there.
 
489
        """
 
490
        super(ExtendedTestResult, self).addFailure(test, details=details)
 
491
        self.failure_count += 1
 
492
        self.report_unexpected_success(test,
 
493
            "".join(details["reason"].iter_text()))
 
494
        if self.stop_early:
 
495
            self.stop()
 
496
 
274
497
    def addNotSupported(self, test, feature):
 
498
        """The test will not be run because of a missing feature.
 
499
        """
 
500
        # this can be called in two different ways: it may be that the
 
501
        # test started running, and then raised (through requireFeature)
 
502
        # UnavailableFeature.  Alternatively this method can be called
 
503
        # while probing for features before running the test code proper; in
 
504
        # that case we will see startTest and stopTest, but the test will
 
505
        # never actually run.
275
506
        self.unsupported.setdefault(str(feature), 0)
276
507
        self.unsupported[str(feature)] += 1
277
508
        self.report_unsupported(test, feature)
278
509
 
279
 
    def addSuccess(self, test):
280
 
        self.extractBenchmarkTime(test)
281
 
        if self._bench_history is not None:
282
 
            if self._benchmarkTime is not None:
283
 
                self._bench_history.write("%s %s\n" % (
284
 
                    self._formatTime(self._benchmarkTime),
285
 
                    test.id()))
286
 
        self.report_success(test)
287
 
        unittest.TestResult.addSuccess(self, test)
288
 
 
289
 
    def addSkipped(self, test, skip_excinfo):
290
 
        self.report_skip(test, skip_excinfo)
291
 
        # seems best to treat this as success from point-of-view of unittest
292
 
        # -- it actually does nothing so it barely matters :)
293
 
        try:
294
 
            test.tearDown()
295
 
        except KeyboardInterrupt:
296
 
            raise
297
 
        except:
298
 
            self.addError(test, test.__exc_info())
299
 
        else:
300
 
            unittest.TestResult.addSuccess(self, test)
301
 
 
302
 
    def printErrorList(self, flavour, errors):
303
 
        for test, err in errors:
304
 
            self.stream.writeln(self.separator1)
305
 
            self.stream.write("%s: " % flavour)
306
 
            if self.use_numbered_dirs:
307
 
                self.stream.write('#%d ' % test.number)
308
 
            self.stream.writeln(self.getDescription(test))
309
 
            if getattr(test, '_get_log', None) is not None:
310
 
                print >>self.stream
311
 
                print >>self.stream, \
312
 
                        ('vvvv[log from %s]' % test.id()).ljust(78,'-')
313
 
                print >>self.stream, test._get_log()
314
 
                print >>self.stream, \
315
 
                        ('^^^^[log from %s]' % test.id()).ljust(78,'-')
316
 
            self.stream.writeln(self.separator2)
317
 
            self.stream.writeln("%s" % err)
318
 
 
319
 
    def finished(self):
320
 
        pass
321
 
 
322
 
    def report_cleaning_up(self):
323
 
        pass
 
510
    def addSkip(self, test, reason):
 
511
        """A test has not run for 'reason'."""
 
512
        self.skip_count += 1
 
513
        self.report_skip(test, reason)
 
514
 
 
515
    def addNotApplicable(self, test, reason):
 
516
        self.not_applicable_count += 1
 
517
        self.report_not_applicable(test, reason)
 
518
 
 
519
    def _count_stored_tests(self):
 
520
        """Count of tests instances kept alive due to not succeeding"""
 
521
        return self.error_count + self.failure_count + self.known_failure_count
 
522
 
 
523
    def _post_mortem(self, tb=None):
 
524
        """Start a PDB post mortem session."""
 
525
        if os.environ.get('BZR_TEST_PDB', None):
 
526
            import pdb
 
527
            pdb.post_mortem(tb)
 
528
 
 
529
    def progress(self, offset, whence):
 
530
        """The test is adjusting the count of tests to run."""
 
531
        if whence == SUBUNIT_SEEK_SET:
 
532
            self.num_tests = offset
 
533
        elif whence == SUBUNIT_SEEK_CUR:
 
534
            self.num_tests += offset
 
535
        else:
 
536
            raise errors.BzrError("Unknown whence %r" % whence)
 
537
 
 
538
    def report_tests_starting(self):
 
539
        """Display information before the test run begins"""
 
540
        if getattr(sys, 'frozen', None) is None:
 
541
            bzr_path = osutils.realpath(sys.argv[0])
 
542
        else:
 
543
            bzr_path = sys.executable
 
544
        self.stream.write(
 
545
            'bzr selftest: %s\n' % (bzr_path,))
 
546
        self.stream.write(
 
547
            '   %s\n' % (
 
548
                    bzrlib.__path__[0],))
 
549
        self.stream.write(
 
550
            '   bzr-%s python-%s %s\n' % (
 
551
                    bzrlib.version_string,
 
552
                    bzrlib._format_version_tuple(sys.version_info),
 
553
                    platform.platform(aliased=1),
 
554
                    ))
 
555
        self.stream.write('\n')
 
556
 
 
557
    def report_test_start(self, test):
 
558
        """Display information on the test just about to be run"""
 
559
 
 
560
    def _report_thread_leak(self, test, leaked_threads, active_threads):
 
561
        """Display information on a test that leaked one or more threads"""
 
562
        # GZ 2010-09-09: A leak summary reported separately from the general
 
563
        #                thread debugging would be nice. Tests under subunit
 
564
        #                need something not using stream, perhaps adding a
 
565
        #                testtools details object would be fitting.
 
566
        if 'threads' in selftest_debug_flags:
 
567
            self.stream.write('%s is leaking, active is now %d\n' %
 
568
                (test.id(), len(active_threads)))
 
569
 
 
570
    def startTestRun(self):
 
571
        self.startTime = time.time()
324
572
 
325
573
    def report_success(self, test):
326
574
        pass
327
575
 
 
576
    def wasStrictlySuccessful(self):
 
577
        if self.unsupported or self.known_failure_count:
 
578
            return False
 
579
        return self.wasSuccessful()
 
580
 
328
581
 
329
582
class TextTestResult(ExtendedTestResult):
330
583
    """Displays progress and results of tests in text form"""
331
584
 
332
585
    def __init__(self, stream, descriptions, verbosity,
333
586
                 bench_history=None,
334
 
                 num_tests=None,
335
587
                 pb=None,
336
 
                 use_numbered_dirs=False,
 
588
                 strict=None,
337
589
                 ):
338
590
        ExtendedTestResult.__init__(self, stream, descriptions, verbosity,
339
 
            bench_history, num_tests, use_numbered_dirs)
340
 
        if pb is None:
341
 
            self.pb = self.ui.nested_progress_bar()
342
 
            self._supplied_pb = False
343
 
        else:
344
 
            self.pb = pb
345
 
            self._supplied_pb = True
 
591
            bench_history, strict)
 
592
        # We no longer pass them around, but just rely on the UIFactory stack
 
593
        # for state
 
594
        if pb is not None:
 
595
            warnings.warn("Passing pb to TextTestResult is deprecated")
 
596
        self.pb = self.ui.nested_progress_bar()
346
597
        self.pb.show_pct = False
347
598
        self.pb.show_spinner = False
348
599
        self.pb.show_eta = False,
349
600
        self.pb.show_count = False
350
601
        self.pb.show_bar = False
351
 
 
352
 
    def report_starting(self):
353
 
        self.pb.update('[test 0/%d] starting...' % (self.num_tests))
 
602
        self.pb.update_latency = 0
 
603
        self.pb.show_transport_activity = False
 
604
 
 
605
    def stopTestRun(self):
 
606
        # called when the tests that are going to run have run
 
607
        self.pb.clear()
 
608
        self.pb.finished()
 
609
        super(TextTestResult, self).stopTestRun()
 
610
 
 
611
    def report_tests_starting(self):
 
612
        super(TextTestResult, self).report_tests_starting()
 
613
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
354
614
 
355
615
    def _progress_prefix_text(self):
356
 
        a = '[%d' % self.count
357
 
        if self.num_tests is not None:
 
616
        # the longer this text, the less space we have to show the test
 
617
        # name...
 
618
        a = '[%d' % self.count              # total that have been run
 
619
        # tests skipped as known not to be relevant are not important enough
 
620
        # to show here
 
621
        ## if self.skip_count:
 
622
        ##     a += ', %d skip' % self.skip_count
 
623
        ## if self.known_failure_count:
 
624
        ##     a += '+%dX' % self.known_failure_count
 
625
        if self.num_tests:
358
626
            a +='/%d' % self.num_tests
359
 
        a += ' in %ds' % (time.time() - self._overall_start_time)
360
 
        if self.error_count:
361
 
            a += ', %d errors' % self.error_count
362
 
        if self.failure_count:
363
 
            a += ', %d failed' % self.failure_count
364
 
        if self.known_failure_count:
365
 
            a += ', %d known failures' % self.known_failure_count
366
 
        if self.skip_count:
367
 
            a += ', %d skipped' % self.skip_count
368
 
        if self.unsupported:
369
 
            a += ', %d missing features' % len(self.unsupported)
 
627
        a += ' in '
 
628
        runtime = time.time() - self._overall_start_time
 
629
        if runtime >= 60:
 
630
            a += '%dm%ds' % (runtime / 60, runtime % 60)
 
631
        else:
 
632
            a += '%ds' % runtime
 
633
        total_fail_count = self.error_count + self.failure_count
 
634
        if total_fail_count:
 
635
            a += ', %d failed' % total_fail_count
 
636
        # if self.unsupported:
 
637
        #     a += ', %d missing' % len(self.unsupported)
370
638
        a += ']'
371
639
        return a
372
640
 
373
641
    def report_test_start(self, test):
374
 
        self.count += 1
375
642
        self.pb.update(
376
643
                self._progress_prefix_text()
377
 
                + ' ' 
 
644
                + ' '
378
645
                + self._shortened_test_description(test))
379
646
 
380
647
    def _test_description(self, test):
381
 
        if self.use_numbered_dirs:
382
 
            return '#%d %s' % (self.count,
383
 
                               self._shortened_test_description(test))
384
 
        else:
385
 
            return self._shortened_test_description(test)
 
648
        return self._shortened_test_description(test)
386
649
 
387
650
    def report_error(self, test, err):
388
 
        self.pb.note('ERROR: %s\n    %s\n', 
 
651
        self.stream.write('ERROR: %s\n    %s\n' % (
389
652
            self._test_description(test),
390
653
            err[1],
391
 
            )
 
654
            ))
392
655
 
393
656
    def report_failure(self, test, err):
394
 
        self.pb.note('FAIL: %s\n    %s\n', 
 
657
        self.stream.write('FAIL: %s\n    %s\n' % (
395
658
            self._test_description(test),
396
659
            err[1],
397
 
            )
 
660
            ))
398
661
 
399
662
    def report_known_failure(self, test, err):
400
 
        self.pb.note('XFAIL: %s\n%s\n',
401
 
            self._test_description(test), err[1])
402
 
 
403
 
    def report_skip(self, test, skip_excinfo):
404
 
        self.skip_count += 1
405
 
        if False:
406
 
            # at the moment these are mostly not things we can fix
407
 
            # and so they just produce stipple; use the verbose reporter
408
 
            # to see them.
409
 
            if False:
410
 
                # show test and reason for skip
411
 
                self.pb.note('SKIP: %s\n    %s\n', 
412
 
                    self._shortened_test_description(test),
413
 
                    skip_excinfo[1])
414
 
            else:
415
 
                # since the class name was left behind in the still-visible
416
 
                # progress bar...
417
 
                self.pb.note('SKIP: %s', skip_excinfo[1])
 
663
        pass
 
664
 
 
665
    def report_unexpected_success(self, test, reason):
 
666
        self.stream.write('FAIL: %s\n    %s: %s\n' % (
 
667
            self._test_description(test),
 
668
            "Unexpected success. Should have failed",
 
669
            reason,
 
670
            ))
 
671
 
 
672
    def report_skip(self, test, reason):
 
673
        pass
 
674
 
 
675
    def report_not_applicable(self, test, reason):
 
676
        pass
418
677
 
419
678
    def report_unsupported(self, test, feature):
420
679
        """test cannot be run because feature is missing."""
421
 
                  
422
 
    def report_cleaning_up(self):
423
 
        self.pb.update('cleaning up...')
424
 
 
425
 
    def finished(self):
426
 
        if not self._supplied_pb:
427
 
            self.pb.finished()
428
680
 
429
681
 
430
682
class VerboseTestResult(ExtendedTestResult):
438
690
            result = a_string
439
691
        return result.ljust(final_width)
440
692
 
441
 
    def report_starting(self):
 
693
    def report_tests_starting(self):
442
694
        self.stream.write('running %d tests...\n' % self.num_tests)
 
695
        super(VerboseTestResult, self).report_tests_starting()
443
696
 
444
697
    def report_test_start(self, test):
445
 
        self.count += 1
446
698
        name = self._shortened_test_description(test)
447
 
        # width needs space for 6 char status, plus 1 for slash, plus 2 10-char
448
 
        # numbers, plus a trailing blank
449
 
        # when NUMBERED_DIRS: plus 5 chars on test number, plus 1 char on space
450
 
        if self.use_numbered_dirs:
451
 
            self.stream.write('%5d ' % self.count)
452
 
            self.stream.write(self._ellipsize_to_right(name,
453
 
                                osutils.terminal_width()-36))
 
699
        width = osutils.terminal_width()
 
700
        if width is not None:
 
701
            # width needs space for 6 char status, plus 1 for slash, plus an
 
702
            # 11-char time string, plus a trailing blank
 
703
            # when NUMBERED_DIRS: plus 5 chars on test number, plus 1 char on
 
704
            # space
 
705
            self.stream.write(self._ellipsize_to_right(name, width-18))
454
706
        else:
455
 
            self.stream.write(self._ellipsize_to_right(name,
456
 
                                osutils.terminal_width()-30))
 
707
            self.stream.write(name)
457
708
        self.stream.flush()
458
709
 
459
710
    def _error_summary(self, err):
460
711
        indent = ' ' * 4
461
 
        if self.use_numbered_dirs:
462
 
            indent += ' ' * 6
463
712
        return '%s%s' % (indent, err[1])
464
713
 
465
714
    def report_error(self, test, err):
466
 
        self.stream.writeln('ERROR %s\n%s'
467
 
                % (self._testTimeString(),
 
715
        self.stream.write('ERROR %s\n%s\n'
 
716
                % (self._testTimeString(test),
468
717
                   self._error_summary(err)))
469
718
 
470
719
    def report_failure(self, test, err):
471
 
        self.stream.writeln(' FAIL %s\n%s'
472
 
                % (self._testTimeString(),
 
720
        self.stream.write(' FAIL %s\n%s\n'
 
721
                % (self._testTimeString(test),
473
722
                   self._error_summary(err)))
474
723
 
475
724
    def report_known_failure(self, test, err):
476
 
        self.stream.writeln('XFAIL %s\n%s'
477
 
                % (self._testTimeString(),
 
725
        self.stream.write('XFAIL %s\n%s\n'
 
726
                % (self._testTimeString(test),
478
727
                   self._error_summary(err)))
479
728
 
 
729
    def report_unexpected_success(self, test, reason):
 
730
        self.stream.write(' FAIL %s\n%s: %s\n'
 
731
                % (self._testTimeString(test),
 
732
                   "Unexpected success. Should have failed",
 
733
                   reason))
 
734
 
480
735
    def report_success(self, test):
481
 
        self.stream.writeln('   OK %s' % self._testTimeString())
 
736
        self.stream.write('   OK %s\n' % self._testTimeString(test))
482
737
        for bench_called, stats in getattr(test, '_benchcalls', []):
483
 
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
 
738
            self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
484
739
            stats.pprint(file=self.stream)
485
740
        # flush the stream so that we get smooth output. This verbose mode is
486
741
        # used to show the output in PQM.
487
742
        self.stream.flush()
488
743
 
489
 
    def report_skip(self, test, skip_excinfo):
490
 
        self.skip_count += 1
491
 
        self.stream.writeln(' SKIP %s\n%s'
492
 
                % (self._testTimeString(),
493
 
                   self._error_summary(skip_excinfo)))
 
744
    def report_skip(self, test, reason):
 
745
        self.stream.write(' SKIP %s\n%s\n'
 
746
                % (self._testTimeString(test), reason))
 
747
 
 
748
    def report_not_applicable(self, test, reason):
 
749
        self.stream.write('  N/A %s\n    %s\n'
 
750
                % (self._testTimeString(test), reason))
494
751
 
495
752
    def report_unsupported(self, test, feature):
496
753
        """test cannot be run because feature is missing."""
497
 
        self.stream.writeln("NODEP %s\n    The feature '%s' is not available."
498
 
                %(self._testTimeString(), feature))
499
 
                  
 
754
        self.stream.write("NODEP %s\n    The feature '%s' is not available.\n"
 
755
                %(self._testTimeString(test), feature))
500
756
 
501
757
 
502
758
class TextTestRunner(object):
507
763
                 descriptions=0,
508
764
                 verbosity=1,
509
765
                 bench_history=None,
510
 
                 use_numbered_dirs=False,
511
 
                 list_only=False
 
766
                 strict=False,
 
767
                 result_decorators=None,
512
768
                 ):
513
 
        self.stream = unittest._WritelnDecorator(stream)
 
769
        """Create a TextTestRunner.
 
770
 
 
771
        :param result_decorators: An optional list of decorators to apply
 
772
            to the result object being used by the runner. Decorators are
 
773
            applied left to right - the first element in the list is the 
 
774
            innermost decorator.
 
775
        """
 
776
        # stream may know claim to know to write unicode strings, but in older
 
777
        # pythons this goes sufficiently wrong that it is a bad idea. (
 
778
        # specifically a built in file with encoding 'UTF-8' will still try
 
779
        # to encode using ascii.
 
780
        new_encoding = osutils.get_terminal_encoding()
 
781
        codec = codecs.lookup(new_encoding)
 
782
        if type(codec) is tuple:
 
783
            # Python 2.4
 
784
            encode = codec[0]
 
785
        else:
 
786
            encode = codec.encode
 
787
        # GZ 2010-09-08: Really we don't want to be writing arbitrary bytes,
 
788
        #                so should swap to the plain codecs.StreamWriter
 
789
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream,
 
790
            "backslashreplace")
 
791
        stream.encoding = new_encoding
 
792
        self.stream = stream
514
793
        self.descriptions = descriptions
515
794
        self.verbosity = verbosity
516
795
        self._bench_history = bench_history
517
 
        self.use_numbered_dirs = use_numbered_dirs
518
 
        self.list_only = list_only
 
796
        self._strict = strict
 
797
        self._result_decorators = result_decorators or []
519
798
 
520
799
    def run(self, test):
521
800
        "Run the given test case or test suite."
522
 
        startTime = time.time()
523
801
        if self.verbosity == 1:
524
802
            result_class = TextTestResult
525
803
        elif self.verbosity >= 2:
526
804
            result_class = VerboseTestResult
527
 
        result = result_class(self.stream,
 
805
        original_result = result_class(self.stream,
528
806
                              self.descriptions,
529
807
                              self.verbosity,
530
808
                              bench_history=self._bench_history,
531
 
                              num_tests=test.countTestCases(),
532
 
                              use_numbered_dirs=self.use_numbered_dirs,
 
809
                              strict=self._strict,
533
810
                              )
534
 
        result.stop_early = self.stop_on_failure
535
 
        result.report_starting()
536
 
        if self.list_only:
537
 
            if self.verbosity >= 2:
538
 
                self.stream.writeln("Listing tests only ...\n")
539
 
            run = 0
540
 
            for t in iter_suite_tests(test):
541
 
                self.stream.writeln("%s" % (t.id()))
542
 
                run += 1
543
 
            actionTaken = "Listed"
544
 
        else: 
 
811
        # Signal to result objects that look at stop early policy to stop,
 
812
        original_result.stop_early = self.stop_on_failure
 
813
        result = original_result
 
814
        for decorator in self._result_decorators:
 
815
            result = decorator(result)
 
816
            result.stop_early = self.stop_on_failure
 
817
        result.startTestRun()
 
818
        try:
545
819
            test.run(result)
546
 
            run = result.testsRun
547
 
            actionTaken = "Ran"
548
 
        stopTime = time.time()
549
 
        timeTaken = stopTime - startTime
550
 
        result.printErrors()
551
 
        self.stream.writeln(result.separator2)
552
 
        self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
553
 
                            run, run != 1 and "s" or "", timeTaken))
554
 
        self.stream.writeln()
555
 
        if not result.wasSuccessful():
556
 
            self.stream.write("FAILED (")
557
 
            failed, errored = map(len, (result.failures, result.errors))
558
 
            if failed:
559
 
                self.stream.write("failures=%d" % failed)
560
 
            if errored:
561
 
                if failed: self.stream.write(", ")
562
 
                self.stream.write("errors=%d" % errored)
563
 
            if result.known_failure_count:
564
 
                if failed or errored: self.stream.write(", ")
565
 
                self.stream.write("known_failure_count=%d" %
566
 
                    result.known_failure_count)
567
 
            self.stream.writeln(")")
568
 
        else:
569
 
            if result.known_failure_count:
570
 
                self.stream.writeln("OK (known_failures=%d)" %
571
 
                    result.known_failure_count)
572
 
            else:
573
 
                self.stream.writeln("OK")
574
 
        if result.skip_count > 0:
575
 
            skipped = result.skip_count
576
 
            self.stream.writeln('%d test%s skipped' %
577
 
                                (skipped, skipped != 1 and "s" or ""))
578
 
        if result.unsupported:
579
 
            for feature, count in sorted(result.unsupported.items()):
580
 
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
581
 
                    (feature, count))
582
 
        result.finished()
583
 
        return result
 
820
        finally:
 
821
            result.stopTestRun()
 
822
        # higher level code uses our extended protocol to determine
 
823
        # what exit code to give.
 
824
        return original_result
584
825
 
585
826
 
586
827
def iter_suite_tests(suite):
587
828
    """Return all tests in a suite, recursing through nested suites"""
588
 
    for item in suite._tests:
589
 
        if isinstance(item, unittest.TestCase):
590
 
            yield item
591
 
        elif isinstance(item, unittest.TestSuite):
 
829
    if isinstance(suite, unittest.TestCase):
 
830
        yield suite
 
831
    elif isinstance(suite, unittest.TestSuite):
 
832
        for item in suite:
592
833
            for r in iter_suite_tests(item):
593
834
                yield r
594
 
        else:
595
 
            raise Exception('unknown object %r inside test suite %r'
596
 
                            % (item, suite))
597
 
 
598
 
 
599
 
class TestSkipped(Exception):
600
 
    """Indicates that a test was intentionally skipped, rather than failing."""
601
 
 
602
 
 
603
 
class KnownFailure(AssertionError):
604
 
    """Indicates that a test failed in a precisely expected manner.
605
 
 
606
 
    Such failures dont block the whole test suite from passing because they are
607
 
    indicators of partially completed code or of future work. We have an
608
 
    explicit error for them so that we can ensure that they are always visible:
609
 
    KnownFailures are always shown in the output of bzr selftest.
 
835
    else:
 
836
        raise Exception('unknown type %r for object %r'
 
837
                        % (type(suite), suite))
 
838
 
 
839
 
 
840
TestSkipped = testtools.testcase.TestSkipped
 
841
 
 
842
 
 
843
class TestNotApplicable(TestSkipped):
 
844
    """A test is not applicable to the situation where it was run.
 
845
 
 
846
    This is only normally raised by parameterized tests, if they find that
 
847
    the instance they're constructed upon does not support one aspect
 
848
    of its interface.
610
849
    """
611
850
 
612
851
 
 
852
# traceback._some_str fails to format exceptions that have the default
 
853
# __str__ which does an implicit ascii conversion. However, repr() on those
 
854
# objects works, for all that its not quite what the doctor may have ordered.
 
855
def _clever_some_str(value):
 
856
    try:
 
857
        return str(value)
 
858
    except:
 
859
        try:
 
860
            return repr(value).replace('\\n', '\n')
 
861
        except:
 
862
            return '<unprintable %s object>' % type(value).__name__
 
863
 
 
864
traceback._some_str = _clever_some_str
 
865
 
 
866
 
 
867
# deprecated - use self.knownFailure(), or self.expectFailure.
 
868
KnownFailure = testtools.testcase._ExpectedFailure
 
869
 
 
870
 
613
871
class UnavailableFeature(Exception):
614
872
    """A feature required for this test was not available.
615
873
 
 
874
    This can be considered a specialised form of SkippedTest.
 
875
 
616
876
    The feature should be used to construct the exception.
617
877
    """
618
878
 
619
879
 
620
 
class CommandFailed(Exception):
621
 
    pass
622
 
 
623
 
 
624
880
class StringIOWrapper(object):
625
881
    """A wrapper around cStringIO which just adds an encoding attribute.
626
 
    
 
882
 
627
883
    Internally we can check sys.stdout to see what the output encoding
628
884
    should be. However, cStringIO has no encoding attribute that we can
629
885
    set. So we wrap it instead.
647
903
            return setattr(self._cstring, name, val)
648
904
 
649
905
 
650
 
class TestUIFactory(ui.CLIUIFactory):
 
906
class TestUIFactory(TextUIFactory):
651
907
    """A UI Factory for testing.
652
908
 
653
909
    Hide the progress bar but emit note()s.
654
910
    Redirect stdin.
655
911
    Allows get_password to be tested without real tty attached.
 
912
 
 
913
    See also CannedInputUIFactory which lets you provide programmatic input in
 
914
    a structured way.
656
915
    """
 
916
    # TODO: Capture progress events at the model level and allow them to be
 
917
    # observed by tests that care.
 
918
    #
 
919
    # XXX: Should probably unify more with CannedInputUIFactory or a
 
920
    # particular configuration of TextUIFactory, or otherwise have a clearer
 
921
    # idea of how they're supposed to be different.
 
922
    # See https://bugs.launchpad.net/bzr/+bug/408213
657
923
 
658
 
    def __init__(self,
659
 
                 stdout=None,
660
 
                 stderr=None,
661
 
                 stdin=None):
662
 
        super(TestUIFactory, self).__init__()
 
924
    def __init__(self, stdout=None, stderr=None, stdin=None):
663
925
        if stdin is not None:
664
926
            # We use a StringIOWrapper to be able to test various
665
927
            # encodings, but the user is still responsible to
666
928
            # encode the string and to set the encoding attribute
667
929
            # of StringIOWrapper.
668
 
            self.stdin = StringIOWrapper(stdin)
669
 
        if stdout is None:
670
 
            self.stdout = sys.stdout
671
 
        else:
672
 
            self.stdout = stdout
673
 
        if stderr is None:
674
 
            self.stderr = sys.stderr
675
 
        else:
676
 
            self.stderr = stderr
677
 
 
678
 
    def clear(self):
679
 
        """See progress.ProgressBar.clear()."""
680
 
 
681
 
    def clear_term(self):
682
 
        """See progress.ProgressBar.clear_term()."""
683
 
 
684
 
    def clear_term(self):
685
 
        """See progress.ProgressBar.clear_term()."""
686
 
 
687
 
    def finished(self):
688
 
        """See progress.ProgressBar.finished()."""
689
 
 
690
 
    def note(self, fmt_string, *args, **kwargs):
691
 
        """See progress.ProgressBar.note()."""
692
 
        self.stdout.write((fmt_string + "\n") % args)
693
 
 
694
 
    def progress_bar(self):
695
 
        return self
696
 
 
697
 
    def nested_progress_bar(self):
698
 
        return self
699
 
 
700
 
    def update(self, message, count=None, total=None):
701
 
        """See progress.ProgressBar.update()."""
702
 
 
703
 
    def get_non_echoed_password(self, prompt):
 
930
            stdin = StringIOWrapper(stdin)
 
931
        super(TestUIFactory, self).__init__(stdin, stdout, stderr)
 
932
 
 
933
    def get_non_echoed_password(self):
704
934
        """Get password from stdin without trying to handle the echo mode"""
705
 
        if prompt:
706
 
            self.stdout.write(prompt.encode(self.stdout.encoding, 'replace'))
707
935
        password = self.stdin.readline()
708
936
        if not password:
709
937
            raise EOFError
711
939
            password = password[:-1]
712
940
        return password
713
941
 
714
 
 
715
 
class TestCase(unittest.TestCase):
 
942
    def make_progress_view(self):
 
943
        return NullProgressView()
 
944
 
 
945
 
 
946
def isolated_doctest_setUp(test):
 
947
    override_os_environ(test)
 
948
 
 
949
 
 
950
def isolated_doctest_tearDown(test):
 
951
    restore_os_environ(test)
 
952
 
 
953
 
 
954
def IsolatedDocTestSuite(*args, **kwargs):
 
955
    """Overrides doctest.DocTestSuite to handle isolation.
 
956
 
 
957
    The method is really a factory and users are expected to use it as such.
 
958
    """
 
959
 
 
960
    kwargs['setUp'] = isolated_doctest_setUp
 
961
    kwargs['tearDown'] = isolated_doctest_tearDown
 
962
    return doctest.DocTestSuite(*args, **kwargs)
 
963
 
 
964
 
 
965
class TestCase(testtools.TestCase):
716
966
    """Base class for bzr unit tests.
717
 
    
718
 
    Tests that need access to disk resources should subclass 
 
967
 
 
968
    Tests that need access to disk resources should subclass
719
969
    TestCaseInTempDir not TestCase.
720
970
 
721
971
    Error and debug log messages are redirected from their usual
723
973
    retrieved by _get_log().  We use a real OS file, not an in-memory object,
724
974
    so that it can also capture file IO.  When the test completes this file
725
975
    is read into memory and removed from disk.
726
 
       
 
976
 
727
977
    There are also convenience functions to invoke bzr's command-line
728
978
    routine, and to build and check bzr trees.
729
 
   
 
979
 
730
980
    In addition to the usual method of overriding tearDown(), this class also
731
 
    allows subclasses to register functions into the _cleanups list, which is
 
981
    allows subclasses to register cleanup functions via addCleanup, which are
732
982
    run in order as the object is torn down.  It's less likely this will be
733
983
    accidentally overlooked.
734
984
    """
735
985
 
736
 
    _log_file_name = None
737
 
    _log_contents = ''
738
 
    _keep_log_file = False
 
986
    _log_file = None
739
987
    # record lsprof data when performing benchmark calls.
740
988
    _gather_lsprof_in_benchmarks = False
741
989
 
742
990
    def __init__(self, methodName='testMethod'):
743
991
        super(TestCase, self).__init__(methodName)
744
 
        self._cleanups = []
 
992
        self._directory_isolation = True
 
993
        self.exception_handlers.insert(0,
 
994
            (UnavailableFeature, self._do_unsupported_or_skip))
 
995
        self.exception_handlers.insert(0,
 
996
            (TestNotApplicable, self._do_not_applicable))
745
997
 
746
998
    def setUp(self):
747
 
        unittest.TestCase.setUp(self)
 
999
        super(TestCase, self).setUp()
 
1000
 
 
1001
        timeout = config.GlobalStack().get('selftest.timeout')
 
1002
        if timeout:
 
1003
            timeout_fixture = fixtures.TimeoutFixture(timeout)
 
1004
            timeout_fixture.setUp()
 
1005
            self.addCleanup(timeout_fixture.cleanUp)
 
1006
 
 
1007
        for feature in getattr(self, '_test_needs_features', []):
 
1008
            self.requireFeature(feature)
748
1009
        self._cleanEnvironment()
749
 
        bzrlib.trace.disable_default_logging()
 
1010
 
 
1011
        if bzrlib.global_state is not None:
 
1012
            self.overrideAttr(bzrlib.global_state, 'cmdline_overrides',
 
1013
                              config.CommandLineStore())
 
1014
 
750
1015
        self._silenceUI()
751
1016
        self._startLogFile()
752
1017
        self._benchcalls = []
753
1018
        self._benchtime = None
754
1019
        self._clear_hooks()
 
1020
        self._track_transports()
 
1021
        self._track_locks()
755
1022
        self._clear_debug_flags()
 
1023
        # Isolate global verbosity level, to make sure it's reproducible
 
1024
        # between tests.  We should get rid of this altogether: bug 656694. --
 
1025
        # mbp 20101008
 
1026
        self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
 
1027
        # Isolate config option expansion until its default value for bzrlib is
 
1028
        # settled on or a the FIXME associated with _get_expand_default_value
 
1029
        # is addressed -- vila 20110219
 
1030
        self.overrideAttr(config, '_expand_default_value', None)
 
1031
        self._log_files = set()
 
1032
        # Each key in the ``_counters`` dict holds a value for a different
 
1033
        # counter. When the test ends, addDetail() should be used to output the
 
1034
        # counter values. This happens in install_counter_hook().
 
1035
        self._counters = {}
 
1036
        if 'config_stats' in selftest_debug_flags:
 
1037
            self._install_config_stats_hooks()
 
1038
        # Do not use i18n for tests (unless the test reverses this)
 
1039
        i18n.disable_i18n()
 
1040
 
 
1041
    def debug(self):
 
1042
        # debug a frame up.
 
1043
        import pdb
 
1044
        # The sys preserved stdin/stdout should allow blackbox tests debugging
 
1045
        pdb.Pdb(stdin=sys.__stdin__, stdout=sys.__stdout__
 
1046
                ).set_trace(sys._getframe().f_back)
 
1047
 
 
1048
    def discardDetail(self, name):
 
1049
        """Extend the addDetail, getDetails api so we can remove a detail.
 
1050
 
 
1051
        eg. bzr always adds the 'log' detail at startup, but we don't want to
 
1052
        include it for skipped, xfail, etc tests.
 
1053
 
 
1054
        It is safe to call this for a detail that doesn't exist, in case this
 
1055
        gets called multiple times.
 
1056
        """
 
1057
        # We cheat. details is stored in __details which means we shouldn't
 
1058
        # touch it. but getDetails() returns the dict directly, so we can
 
1059
        # mutate it.
 
1060
        details = self.getDetails()
 
1061
        if name in details:
 
1062
            del details[name]
 
1063
 
 
1064
    def install_counter_hook(self, hooks, name, counter_name=None):
 
1065
        """Install a counting hook.
 
1066
 
 
1067
        Any hook can be counted as long as it doesn't need to return a value.
 
1068
 
 
1069
        :param hooks: Where the hook should be installed.
 
1070
 
 
1071
        :param name: The hook name that will be counted.
 
1072
 
 
1073
        :param counter_name: The counter identifier in ``_counters``, defaults
 
1074
            to ``name``.
 
1075
        """
 
1076
        _counters = self._counters # Avoid closing over self
 
1077
        if counter_name is None:
 
1078
            counter_name = name
 
1079
        if _counters.has_key(counter_name):
 
1080
            raise AssertionError('%s is already used as a counter name'
 
1081
                                  % (counter_name,))
 
1082
        _counters[counter_name] = 0
 
1083
        self.addDetail(counter_name, content.Content(content.UTF8_TEXT,
 
1084
            lambda: ['%d' % (_counters[counter_name],)]))
 
1085
        def increment_counter(*args, **kwargs):
 
1086
            _counters[counter_name] += 1
 
1087
        label = 'count %s calls' % (counter_name,)
 
1088
        hooks.install_named_hook(name, increment_counter, label)
 
1089
        self.addCleanup(hooks.uninstall_named_hook, name, label)
 
1090
 
 
1091
    def _install_config_stats_hooks(self):
 
1092
        """Install config hooks to count hook calls.
 
1093
 
 
1094
        """
 
1095
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
 
1096
            self.install_counter_hook(config.ConfigHooks, hook_name,
 
1097
                                       'config.%s' % (hook_name,))
 
1098
 
 
1099
        # The OldConfigHooks are private and need special handling to protect
 
1100
        # against recursive tests (tests that run other tests), so we just do
 
1101
        # manually what registering them into _builtin_known_hooks will provide
 
1102
        # us.
 
1103
        self.overrideAttr(config, 'OldConfigHooks', config._OldConfigHooks())
 
1104
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
 
1105
            self.install_counter_hook(config.OldConfigHooks, hook_name,
 
1106
                                      'old_config.%s' % (hook_name,))
756
1107
 
757
1108
    def _clear_debug_flags(self):
758
1109
        """Prevent externally set debug flags affecting tests.
759
 
        
 
1110
 
760
1111
        Tests that want to use debug flags can just set them in the
761
1112
        debug_flags set during setup/teardown.
762
1113
        """
763
 
        self._preserved_debug_flags = set(debug.debug_flags)
764
 
        debug.debug_flags.clear()
765
 
        self.addCleanup(self._restore_debug_flags)
 
1114
        # Start with a copy of the current debug flags we can safely modify.
 
1115
        self.overrideAttr(debug, 'debug_flags', set(debug.debug_flags))
 
1116
        if 'allow_debug' not in selftest_debug_flags:
 
1117
            debug.debug_flags.clear()
 
1118
        if 'disable_lock_checks' not in selftest_debug_flags:
 
1119
            debug.debug_flags.add('strict_locks')
766
1120
 
767
1121
    def _clear_hooks(self):
768
1122
        # prevent hooks affecting tests
769
 
        import bzrlib.branch
770
 
        import bzrlib.smart.server
771
 
        self._preserved_hooks = {
772
 
            bzrlib.branch.Branch: bzrlib.branch.Branch.hooks,
773
 
            bzrlib.smart.server.SmartTCPServer: bzrlib.smart.server.SmartTCPServer.hooks,
774
 
            }
 
1123
        known_hooks = hooks.known_hooks
 
1124
        self._preserved_hooks = {}
 
1125
        for key, (parent, name) in known_hooks.iter_parent_objects():
 
1126
            current_hooks = getattr(parent, name)
 
1127
            self._preserved_hooks[parent] = (name, current_hooks)
 
1128
        self._preserved_lazy_hooks = hooks._lazy_hooks
 
1129
        hooks._lazy_hooks = {}
775
1130
        self.addCleanup(self._restoreHooks)
776
 
        # reset all hooks to an empty instance of the appropriate type
777
 
        bzrlib.branch.Branch.hooks = bzrlib.branch.BranchHooks()
778
 
        bzrlib.smart.server.SmartTCPServer.hooks = bzrlib.smart.server.SmartServerHooks()
 
1131
        for key, (parent, name) in known_hooks.iter_parent_objects():
 
1132
            factory = known_hooks.get(key)
 
1133
            setattr(parent, name, factory())
 
1134
        # this hook should always be installed
 
1135
        request._install_hook()
 
1136
 
 
1137
    def disable_directory_isolation(self):
 
1138
        """Turn off directory isolation checks."""
 
1139
        self._directory_isolation = False
 
1140
 
 
1141
    def enable_directory_isolation(self):
 
1142
        """Enable directory isolation checks."""
 
1143
        self._directory_isolation = True
779
1144
 
780
1145
    def _silenceUI(self):
781
1146
        """Turn off UI for duration of test"""
782
1147
        # by default the UI is off; tests can turn it on if they want it.
783
 
        saved = ui.ui_factory
784
 
        def _restore():
785
 
            ui.ui_factory = saved
786
 
        ui.ui_factory = ui.SilentUIFactory()
787
 
        self.addCleanup(_restore)
 
1148
        self.overrideAttr(ui, 'ui_factory', ui.SilentUIFactory())
 
1149
 
 
1150
    def _check_locks(self):
 
1151
        """Check that all lock take/release actions have been paired."""
 
1152
        # We always check for mismatched locks. If a mismatch is found, we
 
1153
        # fail unless -Edisable_lock_checks is supplied to selftest, in which
 
1154
        # case we just print a warning.
 
1155
        # unhook:
 
1156
        acquired_locks = [lock for action, lock in self._lock_actions
 
1157
                          if action == 'acquired']
 
1158
        released_locks = [lock for action, lock in self._lock_actions
 
1159
                          if action == 'released']
 
1160
        broken_locks = [lock for action, lock in self._lock_actions
 
1161
                        if action == 'broken']
 
1162
        # trivially, given the tests for lock acquistion and release, if we
 
1163
        # have as many in each list, it should be ok. Some lock tests also
 
1164
        # break some locks on purpose and should be taken into account by
 
1165
        # considering that breaking a lock is just a dirty way of releasing it.
 
1166
        if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
 
1167
            message = (
 
1168
                'Different number of acquired and '
 
1169
                'released or broken locks.\n'
 
1170
                'acquired=%s\n'
 
1171
                'released=%s\n'
 
1172
                'broken=%s\n' %
 
1173
                (acquired_locks, released_locks, broken_locks))
 
1174
            if not self._lock_check_thorough:
 
1175
                # Rather than fail, just warn
 
1176
                print "Broken test %s: %s" % (self, message)
 
1177
                return
 
1178
            self.fail(message)
 
1179
 
 
1180
    def _track_locks(self):
 
1181
        """Track lock activity during tests."""
 
1182
        self._lock_actions = []
 
1183
        if 'disable_lock_checks' in selftest_debug_flags:
 
1184
            self._lock_check_thorough = False
 
1185
        else:
 
1186
            self._lock_check_thorough = True
 
1187
 
 
1188
        self.addCleanup(self._check_locks)
 
1189
        _mod_lock.Lock.hooks.install_named_hook('lock_acquired',
 
1190
                                                self._lock_acquired, None)
 
1191
        _mod_lock.Lock.hooks.install_named_hook('lock_released',
 
1192
                                                self._lock_released, None)
 
1193
        _mod_lock.Lock.hooks.install_named_hook('lock_broken',
 
1194
                                                self._lock_broken, None)
 
1195
 
 
1196
    def _lock_acquired(self, result):
 
1197
        self._lock_actions.append(('acquired', result))
 
1198
 
 
1199
    def _lock_released(self, result):
 
1200
        self._lock_actions.append(('released', result))
 
1201
 
 
1202
    def _lock_broken(self, result):
 
1203
        self._lock_actions.append(('broken', result))
 
1204
 
 
1205
    def permit_dir(self, name):
 
1206
        """Permit a directory to be used by this test. See permit_url."""
 
1207
        name_transport = _mod_transport.get_transport_from_path(name)
 
1208
        self.permit_url(name)
 
1209
        self.permit_url(name_transport.base)
 
1210
 
 
1211
    def permit_url(self, url):
 
1212
        """Declare that url is an ok url to use in this test.
 
1213
        
 
1214
        Do this for memory transports, temporary test directory etc.
 
1215
        
 
1216
        Do not do this for the current working directory, /tmp, or any other
 
1217
        preexisting non isolated url.
 
1218
        """
 
1219
        if not url.endswith('/'):
 
1220
            url += '/'
 
1221
        self._bzr_selftest_roots.append(url)
 
1222
 
 
1223
    def permit_source_tree_branch_repo(self):
 
1224
        """Permit the source tree bzr is running from to be opened.
 
1225
 
 
1226
        Some code such as bzrlib.version attempts to read from the bzr branch
 
1227
        that bzr is executing from (if any). This method permits that directory
 
1228
        to be used in the test suite.
 
1229
        """
 
1230
        path = self.get_source_path()
 
1231
        self.record_directory_isolation()
 
1232
        try:
 
1233
            try:
 
1234
                workingtree.WorkingTree.open(path)
 
1235
            except (errors.NotBranchError, errors.NoWorkingTree):
 
1236
                raise TestSkipped('Needs a working tree of bzr sources')
 
1237
        finally:
 
1238
            self.enable_directory_isolation()
 
1239
 
 
1240
    def _preopen_isolate_transport(self, transport):
 
1241
        """Check that all transport openings are done in the test work area."""
 
1242
        while isinstance(transport, pathfilter.PathFilteringTransport):
 
1243
            # Unwrap pathfiltered transports
 
1244
            transport = transport.server.backing_transport.clone(
 
1245
                transport._filter('.'))
 
1246
        url = transport.base
 
1247
        # ReadonlySmartTCPServer_for_testing decorates the backing transport
 
1248
        # urls it is given by prepending readonly+. This is appropriate as the
 
1249
        # client shouldn't know that the server is readonly (or not readonly).
 
1250
        # We could register all servers twice, with readonly+ prepending, but
 
1251
        # that makes for a long list; this is about the same but easier to
 
1252
        # read.
 
1253
        if url.startswith('readonly+'):
 
1254
            url = url[len('readonly+'):]
 
1255
        self._preopen_isolate_url(url)
 
1256
 
 
1257
    def _preopen_isolate_url(self, url):
 
1258
        if not self._directory_isolation:
 
1259
            return
 
1260
        if self._directory_isolation == 'record':
 
1261
            self._bzr_selftest_roots.append(url)
 
1262
            return
 
1263
        # This prevents all transports, including e.g. sftp ones backed on disk
 
1264
        # from working unless they are explicitly granted permission. We then
 
1265
        # depend on the code that sets up test transports to check that they are
 
1266
        # appropriately isolated and enable their use by calling
 
1267
        # self.permit_transport()
 
1268
        if not osutils.is_inside_any(self._bzr_selftest_roots, url):
 
1269
            raise errors.BzrError("Attempt to escape test isolation: %r %r"
 
1270
                % (url, self._bzr_selftest_roots))
 
1271
 
 
1272
    def record_directory_isolation(self):
 
1273
        """Gather accessed directories to permit later access.
 
1274
        
 
1275
        This is used for tests that access the branch bzr is running from.
 
1276
        """
 
1277
        self._directory_isolation = "record"
 
1278
 
 
1279
    def start_server(self, transport_server, backing_server=None):
 
1280
        """Start transport_server for this test.
 
1281
 
 
1282
        This starts the server, registers a cleanup for it and permits the
 
1283
        server's urls to be used.
 
1284
        """
 
1285
        if backing_server is None:
 
1286
            transport_server.start_server()
 
1287
        else:
 
1288
            transport_server.start_server(backing_server)
 
1289
        self.addCleanup(transport_server.stop_server)
 
1290
        # Obtain a real transport because if the server supplies a password, it
 
1291
        # will be hidden from the base on the client side.
 
1292
        t = _mod_transport.get_transport_from_url(transport_server.get_url())
 
1293
        # Some transport servers effectively chroot the backing transport;
 
1294
        # others like SFTPServer don't - users of the transport can walk up the
 
1295
        # transport to read the entire backing transport. This wouldn't matter
 
1296
        # except that the workdir tests are given - and that they expect the
 
1297
        # server's url to point at - is one directory under the safety net. So
 
1298
        # Branch operations into the transport will attempt to walk up one
 
1299
        # directory. Chrooting all servers would avoid this but also mean that
 
1300
        # we wouldn't be testing directly against non-root urls. Alternatively
 
1301
        # getting the test framework to start the server with a backing server
 
1302
        # at the actual safety net directory would work too, but this then
 
1303
        # means that the self.get_url/self.get_transport methods would need
 
1304
        # to transform all their results. On balance its cleaner to handle it
 
1305
        # here, and permit a higher url when we have one of these transports.
 
1306
        if t.base.endswith('/work/'):
 
1307
            # we have safety net/test root/work
 
1308
            t = t.clone('../..')
 
1309
        elif isinstance(transport_server,
 
1310
                        test_server.SmartTCPServer_for_testing):
 
1311
            # The smart server adds a path similar to work, which is traversed
 
1312
            # up from by the client. But the server is chrooted - the actual
 
1313
            # backing transport is not escaped from, and VFS requests to the
 
1314
            # root will error (because they try to escape the chroot).
 
1315
            t2 = t.clone('..')
 
1316
            while t2.base != t.base:
 
1317
                t = t2
 
1318
                t2 = t.clone('..')
 
1319
        self.permit_url(t.base)
 
1320
 
 
1321
    def _track_transports(self):
 
1322
        """Install checks for transport usage."""
 
1323
        # TestCase has no safe place it can write to.
 
1324
        self._bzr_selftest_roots = []
 
1325
        # Currently the easiest way to be sure that nothing is going on is to
 
1326
        # hook into bzr dir opening. This leaves a small window of error for
 
1327
        # transport tests, but they are well known, and we can improve on this
 
1328
        # step.
 
1329
        bzrdir.BzrDir.hooks.install_named_hook("pre_open",
 
1330
            self._preopen_isolate_transport, "Check bzr directories are safe.")
788
1331
 
789
1332
    def _ndiff_strings(self, a, b):
790
1333
        """Return ndiff between two strings containing lines.
791
 
        
 
1334
 
792
1335
        A trailing newline is added if missing to make the strings
793
1336
        print properly."""
794
1337
        if b and b[-1] != '\n':
808
1351
        except UnicodeError, e:
809
1352
            # If we can't compare without getting a UnicodeError, then
810
1353
            # obviously they are different
811
 
            mutter('UnicodeError: %s', e)
 
1354
            trace.mutter('UnicodeError: %s', e)
812
1355
        if message:
813
1356
            message += '\n'
814
1357
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
815
1358
            % (message,
816
 
               pformat(a), pformat(b)))
 
1359
               pprint.pformat(a), pprint.pformat(b)))
817
1360
 
818
1361
    assertEquals = assertEqual
819
1362
 
820
1363
    def assertEqualDiff(self, a, b, message=None):
821
1364
        """Assert two texts are equal, if not raise an exception.
822
 
        
823
 
        This is intended for use with multi-line strings where it can 
 
1365
 
 
1366
        This is intended for use with multi-line strings where it can
824
1367
        be hard to find the differences by eye.
825
1368
        """
826
1369
        # TODO: perhaps override assertEquals to call this for strings?
828
1371
            return
829
1372
        if message is None:
830
1373
            message = "texts not equal:\n"
831
 
        raise AssertionError(message + 
832
 
                             self._ndiff_strings(a, b))      
833
 
        
 
1374
        if a + '\n' == b:
 
1375
            message = 'first string is missing a final newline.\n'
 
1376
        if a == b + '\n':
 
1377
            message = 'second string is missing a final newline.\n'
 
1378
        raise AssertionError(message +
 
1379
                             self._ndiff_strings(a, b))
 
1380
 
834
1381
    def assertEqualMode(self, mode, mode_test):
835
1382
        self.assertEqual(mode, mode_test,
836
1383
                         'mode mismatch %o != %o' % (mode, mode_test))
837
1384
 
 
1385
    def assertEqualStat(self, expected, actual):
 
1386
        """assert that expected and actual are the same stat result.
 
1387
 
 
1388
        :param expected: A stat result.
 
1389
        :param actual: A stat result.
 
1390
        :raises AssertionError: If the expected and actual stat values differ
 
1391
            other than by atime.
 
1392
        """
 
1393
        self.assertEqual(expected.st_size, actual.st_size,
 
1394
                         'st_size did not match')
 
1395
        self.assertEqual(expected.st_mtime, actual.st_mtime,
 
1396
                         'st_mtime did not match')
 
1397
        self.assertEqual(expected.st_ctime, actual.st_ctime,
 
1398
                         'st_ctime did not match')
 
1399
        if sys.platform == 'win32':
 
1400
            # On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
 
1401
            # is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
 
1402
            # odd. We just force it to always be 0 to avoid any problems.
 
1403
            self.assertEqual(0, expected.st_dev)
 
1404
            self.assertEqual(0, actual.st_dev)
 
1405
            self.assertEqual(0, expected.st_ino)
 
1406
            self.assertEqual(0, actual.st_ino)
 
1407
        else:
 
1408
            self.assertEqual(expected.st_dev, actual.st_dev,
 
1409
                             'st_dev did not match')
 
1410
            self.assertEqual(expected.st_ino, actual.st_ino,
 
1411
                             'st_ino did not match')
 
1412
        self.assertEqual(expected.st_mode, actual.st_mode,
 
1413
                         'st_mode did not match')
 
1414
 
 
1415
    def assertLength(self, length, obj_with_len):
 
1416
        """Assert that obj_with_len is of length length."""
 
1417
        if len(obj_with_len) != length:
 
1418
            self.fail("Incorrect length: wanted %d, got %d for %r" % (
 
1419
                length, len(obj_with_len), obj_with_len))
 
1420
 
 
1421
    def assertLogsError(self, exception_class, func, *args, **kwargs):
 
1422
        """Assert that `func(*args, **kwargs)` quietly logs a specific error.
 
1423
        """
 
1424
        captured = []
 
1425
        orig_log_exception_quietly = trace.log_exception_quietly
 
1426
        try:
 
1427
            def capture():
 
1428
                orig_log_exception_quietly()
 
1429
                captured.append(sys.exc_info()[1])
 
1430
            trace.log_exception_quietly = capture
 
1431
            func(*args, **kwargs)
 
1432
        finally:
 
1433
            trace.log_exception_quietly = orig_log_exception_quietly
 
1434
        self.assertLength(1, captured)
 
1435
        err = captured[0]
 
1436
        self.assertIsInstance(err, exception_class)
 
1437
        return err
 
1438
 
 
1439
    def assertPositive(self, val):
 
1440
        """Assert that val is greater than 0."""
 
1441
        self.assertTrue(val > 0, 'expected a positive value, but got %s' % val)
 
1442
 
 
1443
    def assertNegative(self, val):
 
1444
        """Assert that val is less than 0."""
 
1445
        self.assertTrue(val < 0, 'expected a negative value, but got %s' % val)
 
1446
 
838
1447
    def assertStartsWith(self, s, prefix):
839
1448
        if not s.startswith(prefix):
840
1449
            raise AssertionError('string %r does not start with %r' % (s, prefix))
844
1453
        if not s.endswith(suffix):
845
1454
            raise AssertionError('string %r does not end with %r' % (s, suffix))
846
1455
 
847
 
    def assertContainsRe(self, haystack, needle_re):
 
1456
    def assertContainsRe(self, haystack, needle_re, flags=0):
848
1457
        """Assert that a contains something matching a regular expression."""
849
 
        if not re.search(needle_re, haystack):
850
 
            raise AssertionError('pattern "%r" not found in "%r"'
851
 
                    % (needle_re, haystack))
 
1458
        if not re.search(needle_re, haystack, flags):
 
1459
            if '\n' in haystack or len(haystack) > 60:
 
1460
                # a long string, format it in a more readable way
 
1461
                raise AssertionError(
 
1462
                        'pattern "%s" not found in\n"""\\\n%s"""\n'
 
1463
                        % (needle_re, haystack))
 
1464
            else:
 
1465
                raise AssertionError('pattern "%s" not found in "%s"'
 
1466
                        % (needle_re, haystack))
852
1467
 
853
 
    def assertNotContainsRe(self, haystack, needle_re):
 
1468
    def assertNotContainsRe(self, haystack, needle_re, flags=0):
854
1469
        """Assert that a does not match a regular expression"""
855
 
        if re.search(needle_re, haystack):
 
1470
        if re.search(needle_re, haystack, flags):
856
1471
            raise AssertionError('pattern "%s" found in "%s"'
857
1472
                    % (needle_re, haystack))
858
1473
 
 
1474
    def assertContainsString(self, haystack, needle):
 
1475
        if haystack.find(needle) == -1:
 
1476
            self.fail("string %r not found in '''%s'''" % (needle, haystack))
 
1477
 
 
1478
    def assertNotContainsString(self, haystack, needle):
 
1479
        if haystack.find(needle) != -1:
 
1480
            self.fail("string %r found in '''%s'''" % (needle, haystack))
 
1481
 
859
1482
    def assertSubset(self, sublist, superlist):
860
1483
        """Assert that every entry in sublist is present in superlist."""
861
 
        missing = []
862
 
        for entry in sublist:
863
 
            if entry not in superlist:
864
 
                missing.append(entry)
 
1484
        missing = set(sublist) - set(superlist)
865
1485
        if len(missing) > 0:
866
 
            raise AssertionError("value(s) %r not present in container %r" % 
 
1486
            raise AssertionError("value(s) %r not present in container %r" %
867
1487
                                 (missing, superlist))
868
1488
 
869
1489
    def assertListRaises(self, excClass, func, *args, **kwargs):
870
1490
        """Fail unless excClass is raised when the iterator from func is used.
871
 
        
 
1491
 
872
1492
        Many functions can return generators this makes sure
873
1493
        to wrap them in a list() call to make sure the whole generator
874
1494
        is run, and that the proper exception is raised.
875
1495
        """
876
1496
        try:
877
1497
            list(func(*args, **kwargs))
878
 
        except excClass:
879
 
            return
 
1498
        except excClass, e:
 
1499
            return e
880
1500
        else:
881
1501
            if getattr(excClass,'__name__', None) is not None:
882
1502
                excName = excClass.__name__
921
1541
                raise AssertionError("%r is %r." % (left, right))
922
1542
 
923
1543
    def assertTransportMode(self, transport, path, mode):
924
 
        """Fail if a path does not have mode mode.
925
 
        
 
1544
        """Fail if a path does not have mode "mode".
 
1545
 
926
1546
        If modes are not supported on this transport, the assertion is ignored.
927
1547
        """
928
1548
        if not transport._can_roundtrip_unix_modebits():
930
1550
        path_stat = transport.stat(path)
931
1551
        actual_mode = stat.S_IMODE(path_stat.st_mode)
932
1552
        self.assertEqual(mode, actual_mode,
933
 
            'mode of %r incorrect (%o != %o)' % (path, mode, actual_mode))
934
 
 
935
 
    def assertIsInstance(self, obj, kls):
936
 
        """Fail if obj is not an instance of kls"""
 
1553
                         'mode of %r incorrect (%s != %s)'
 
1554
                         % (path, oct(mode), oct(actual_mode)))
 
1555
 
 
1556
    def assertIsSameRealPath(self, path1, path2):
 
1557
        """Fail if path1 and path2 points to different files"""
 
1558
        self.assertEqual(osutils.realpath(path1),
 
1559
                         osutils.realpath(path2),
 
1560
                         "apparent paths:\na = %s\nb = %s\n," % (path1, path2))
 
1561
 
 
1562
    def assertIsInstance(self, obj, kls, msg=None):
 
1563
        """Fail if obj is not an instance of kls
 
1564
        
 
1565
        :param msg: Supplementary message to show if the assertion fails.
 
1566
        """
937
1567
        if not isinstance(obj, kls):
938
 
            self.fail("%r is an instance of %s rather than %s" % (
939
 
                obj, obj.__class__, kls))
940
 
 
941
 
    def expectFailure(self, reason, assertion, *args, **kwargs):
942
 
        """Invoke a test, expecting it to fail for the given reason.
943
 
 
944
 
        This is for assertions that ought to succeed, but currently fail.
945
 
        (The failure is *expected* but not *wanted*.)  Please be very precise
946
 
        about the failure you're expecting.  If a new bug is introduced,
947
 
        AssertionError should be raised, not KnownFailure.
948
 
 
949
 
        Frequently, expectFailure should be followed by an opposite assertion.
950
 
        See example below.
951
 
 
952
 
        Intended to be used with a callable that raises AssertionError as the
953
 
        'assertion' parameter.  args and kwargs are passed to the 'assertion'.
954
 
 
955
 
        Raises KnownFailure if the test fails.  Raises AssertionError if the
956
 
        test succeeds.
957
 
 
958
 
        example usage::
959
 
 
960
 
          self.expectFailure('Math is broken', self.assertNotEqual, 54,
961
 
                             dynamic_val)
962
 
          self.assertEqual(42, dynamic_val)
963
 
 
964
 
          This means that a dynamic_val of 54 will cause the test to raise
965
 
          a KnownFailure.  Once math is fixed and the expectFailure is removed,
966
 
          only a dynamic_val of 42 will allow the test to pass.  Anything other
967
 
          than 54 or 42 will cause an AssertionError.
968
 
        """
 
1568
            m = "%r is an instance of %s rather than %s" % (
 
1569
                obj, obj.__class__, kls)
 
1570
            if msg:
 
1571
                m += ": " + msg
 
1572
            self.fail(m)
 
1573
 
 
1574
    def assertFileEqual(self, content, path):
 
1575
        """Fail if path does not contain 'content'."""
 
1576
        self.assertPathExists(path)
 
1577
        f = file(path, 'rb')
969
1578
        try:
970
 
            assertion(*args, **kwargs)
971
 
        except AssertionError:
972
 
            raise KnownFailure(reason)
973
 
        else:
974
 
            self.fail('Unexpected success.  Should have failed: %s' % reason)
975
 
 
976
 
    def _capture_warnings(self, a_callable, *args, **kwargs):
 
1579
            s = f.read()
 
1580
        finally:
 
1581
            f.close()
 
1582
        self.assertEqualDiff(content, s)
 
1583
 
 
1584
    def assertDocstring(self, expected_docstring, obj):
 
1585
        """Fail if obj does not have expected_docstring"""
 
1586
        if __doc__ is None:
 
1587
            # With -OO the docstring should be None instead
 
1588
            self.assertIs(obj.__doc__, None)
 
1589
        else:
 
1590
            self.assertEqual(expected_docstring, obj.__doc__)
 
1591
 
 
1592
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
 
1593
    def failUnlessExists(self, path):
 
1594
        return self.assertPathExists(path)
 
1595
 
 
1596
    def assertPathExists(self, path):
 
1597
        """Fail unless path or paths, which may be abs or relative, exist."""
 
1598
        if not isinstance(path, basestring):
 
1599
            for p in path:
 
1600
                self.assertPathExists(p)
 
1601
        else:
 
1602
            self.assertTrue(osutils.lexists(path),
 
1603
                path + " does not exist")
 
1604
 
 
1605
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
 
1606
    def failIfExists(self, path):
 
1607
        return self.assertPathDoesNotExist(path)
 
1608
 
 
1609
    def assertPathDoesNotExist(self, path):
 
1610
        """Fail if path or paths, which may be abs or relative, exist."""
 
1611
        if not isinstance(path, basestring):
 
1612
            for p in path:
 
1613
                self.assertPathDoesNotExist(p)
 
1614
        else:
 
1615
            self.assertFalse(osutils.lexists(path),
 
1616
                path + " exists")
 
1617
 
 
1618
    def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
977
1619
        """A helper for callDeprecated and applyDeprecated.
978
1620
 
979
1621
        :param a_callable: A callable to call.
1002
1644
        Note that this only captures warnings raised by symbol_versioning.warn,
1003
1645
        not other callers that go direct to the warning module.
1004
1646
 
 
1647
        To test that a deprecated method raises an error, do something like
 
1648
        this (remember that both assertRaises and applyDeprecated delays *args
 
1649
        and **kwargs passing)::
 
1650
 
 
1651
            self.assertRaises(errors.ReservedId,
 
1652
                self.applyDeprecated,
 
1653
                deprecated_in((1, 5, 0)),
 
1654
                br.append_revision,
 
1655
                'current:')
 
1656
 
1005
1657
        :param deprecation_format: The deprecation format that the callable
1006
1658
            should have been deprecated with. This is the same type as the
1007
1659
            parameter to deprecated_method/deprecated_function. If the
1014
1666
        :param kwargs: The keyword arguments for the callable
1015
1667
        :return: The result of a_callable(``*args``, ``**kwargs``)
1016
1668
        """
1017
 
        call_warnings, result = self._capture_warnings(a_callable,
 
1669
        call_warnings, result = self._capture_deprecation_warnings(a_callable,
1018
1670
            *args, **kwargs)
1019
1671
        expected_first_warning = symbol_versioning.deprecation_string(
1020
1672
            a_callable, deprecation_format)
1024
1676
        self.assertEqual(expected_first_warning, call_warnings[0])
1025
1677
        return result
1026
1678
 
 
1679
    def callCatchWarnings(self, fn, *args, **kw):
 
1680
        """Call a callable that raises python warnings.
 
1681
 
 
1682
        The caller's responsible for examining the returned warnings.
 
1683
 
 
1684
        If the callable raises an exception, the exception is not
 
1685
        caught and propagates up to the caller.  In that case, the list
 
1686
        of warnings is not available.
 
1687
 
 
1688
        :returns: ([warning_object, ...], fn_result)
 
1689
        """
 
1690
        # XXX: This is not perfect, because it completely overrides the
 
1691
        # warnings filters, and some code may depend on suppressing particular
 
1692
        # warnings.  It's the easiest way to insulate ourselves from -Werror,
 
1693
        # though.  -- Andrew, 20071062
 
1694
        wlist = []
 
1695
        def _catcher(message, category, filename, lineno, file=None, line=None):
 
1696
            # despite the name, 'message' is normally(?) a Warning subclass
 
1697
            # instance
 
1698
            wlist.append(message)
 
1699
        saved_showwarning = warnings.showwarning
 
1700
        saved_filters = warnings.filters
 
1701
        try:
 
1702
            warnings.showwarning = _catcher
 
1703
            warnings.filters = []
 
1704
            result = fn(*args, **kw)
 
1705
        finally:
 
1706
            warnings.showwarning = saved_showwarning
 
1707
            warnings.filters = saved_filters
 
1708
        return wlist, result
 
1709
 
1027
1710
    def callDeprecated(self, expected, callable, *args, **kwargs):
1028
1711
        """Assert that a callable is deprecated in a particular way.
1029
1712
 
1030
 
        This is a very precise test for unusual requirements. The 
 
1713
        This is a very precise test for unusual requirements. The
1031
1714
        applyDeprecated helper function is probably more suited for most tests
1032
1715
        as it allows you to simply specify the deprecation format being used
1033
1716
        and will ensure that that is issued for the function being called.
1034
1717
 
1035
1718
        Note that this only captures warnings raised by symbol_versioning.warn,
1036
 
        not other callers that go direct to the warning module.
 
1719
        not other callers that go direct to the warning module.  To catch
 
1720
        general warnings, use callCatchWarnings.
1037
1721
 
1038
1722
        :param expected: a list of the deprecation warnings expected, in order
1039
1723
        :param callable: The callable to call
1040
1724
        :param args: The positional arguments for the callable
1041
1725
        :param kwargs: The keyword arguments for the callable
1042
1726
        """
1043
 
        call_warnings, result = self._capture_warnings(callable,
 
1727
        call_warnings, result = self._capture_deprecation_warnings(callable,
1044
1728
            *args, **kwargs)
1045
1729
        self.assertEqual(expected, call_warnings)
1046
1730
        return result
1047
1731
 
1048
1732
    def _startLogFile(self):
1049
 
        """Send bzr and test log messages to a temporary file.
1050
 
 
1051
 
        The file is removed as the test is torn down.
1052
 
        """
1053
 
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
1054
 
        self._log_file = os.fdopen(fileno, 'w+')
1055
 
        self._log_nonce = bzrlib.trace.enable_test_log(self._log_file)
1056
 
        self._log_file_name = name
 
1733
        """Setup a in-memory target for bzr and testcase log messages"""
 
1734
        pseudo_log_file = StringIO()
 
1735
        def _get_log_contents_for_weird_testtools_api():
 
1736
            return [pseudo_log_file.getvalue().decode(
 
1737
                "utf-8", "replace").encode("utf-8")]
 
1738
        self.addDetail("log", content.Content(content.ContentType("text",
 
1739
            "plain", {"charset": "utf8"}),
 
1740
            _get_log_contents_for_weird_testtools_api))
 
1741
        self._log_file = pseudo_log_file
 
1742
        self._log_memento = trace.push_log_file(self._log_file)
1057
1743
        self.addCleanup(self._finishLogFile)
1058
1744
 
1059
1745
    def _finishLogFile(self):
1060
 
        """Finished with the log file.
1061
 
 
1062
 
        Close the file and delete it, unless setKeepLogfile was called.
1063
 
        """
1064
 
        if self._log_file is None:
1065
 
            return
1066
 
        bzrlib.trace.disable_test_log(self._log_nonce)
1067
 
        self._log_file.close()
1068
 
        self._log_file = None
1069
 
        if not self._keep_log_file:
1070
 
            os.remove(self._log_file_name)
1071
 
            self._log_file_name = None
1072
 
 
1073
 
    def setKeepLogfile(self):
1074
 
        """Make the logfile not be deleted when _finishLogFile is called."""
1075
 
        self._keep_log_file = True
1076
 
 
1077
 
    def addCleanup(self, callable):
1078
 
        """Arrange to run a callable when this case is torn down.
1079
 
 
1080
 
        Callables are run in the reverse of the order they are registered, 
1081
 
        ie last-in first-out.
1082
 
        """
1083
 
        if callable in self._cleanups:
1084
 
            raise ValueError("cleanup function %r already registered on %s" 
1085
 
                    % (callable, self))
1086
 
        self._cleanups.append(callable)
 
1746
        """Flush and dereference the in-memory log for this testcase"""
 
1747
        if trace._trace_file:
 
1748
            # flush the log file, to get all content
 
1749
            trace._trace_file.flush()
 
1750
        trace.pop_log_file(self._log_memento)
 
1751
        # The logging module now tracks references for cleanup so discard ours
 
1752
        del self._log_memento
 
1753
 
 
1754
    def thisFailsStrictLockCheck(self):
 
1755
        """It is known that this test would fail with -Dstrict_locks.
 
1756
 
 
1757
        By default, all tests are run with strict lock checking unless
 
1758
        -Edisable_lock_checks is supplied. However there are some tests which
 
1759
        we know fail strict locks at this point that have not been fixed.
 
1760
        They should call this function to disable the strict checking.
 
1761
 
 
1762
        This should be used sparingly, it is much better to fix the locking
 
1763
        issues rather than papering over the problem by calling this function.
 
1764
        """
 
1765
        debug.debug_flags.discard('strict_locks')
 
1766
 
 
1767
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
 
1768
        """Overrides an object attribute restoring it after the test.
 
1769
 
 
1770
        :note: This should be used with discretion; you should think about
 
1771
        whether it's better to make the code testable without monkey-patching.
 
1772
 
 
1773
        :param obj: The object that will be mutated.
 
1774
 
 
1775
        :param attr_name: The attribute name we want to preserve/override in
 
1776
            the object.
 
1777
 
 
1778
        :param new: The optional value we want to set the attribute to.
 
1779
 
 
1780
        :returns: The actual attr value.
 
1781
        """
 
1782
        value = getattr(obj, attr_name)
 
1783
        # The actual value is captured by the call below
 
1784
        self.addCleanup(setattr, obj, attr_name, value)
 
1785
        if new is not _unitialized_attr:
 
1786
            setattr(obj, attr_name, new)
 
1787
        return value
 
1788
 
 
1789
    def overrideEnv(self, name, new):
 
1790
        """Set an environment variable, and reset it after the test.
 
1791
 
 
1792
        :param name: The environment variable name.
 
1793
 
 
1794
        :param new: The value to set the variable to. If None, the 
 
1795
            variable is deleted from the environment.
 
1796
 
 
1797
        :returns: The actual variable value.
 
1798
        """
 
1799
        value = osutils.set_or_unset_env(name, new)
 
1800
        self.addCleanup(osutils.set_or_unset_env, name, value)
 
1801
        return value
 
1802
 
 
1803
    def recordCalls(self, obj, attr_name):
 
1804
        """Monkeypatch in a wrapper that will record calls.
 
1805
 
 
1806
        The monkeypatch is automatically removed when the test concludes.
 
1807
 
 
1808
        :param obj: The namespace holding the reference to be replaced;
 
1809
            typically a module, class, or object.
 
1810
        :param attr_name: A string for the name of the attribute to 
 
1811
            patch.
 
1812
        :returns: A list that will be extended with one item every time the
 
1813
            function is called, with a tuple of (args, kwargs).
 
1814
        """
 
1815
        calls = []
 
1816
 
 
1817
        def decorator(*args, **kwargs):
 
1818
            calls.append((args, kwargs))
 
1819
            return orig(*args, **kwargs)
 
1820
        orig = self.overrideAttr(obj, attr_name, decorator)
 
1821
        return calls
1087
1822
 
1088
1823
    def _cleanEnvironment(self):
1089
 
        new_env = {
1090
 
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
1091
 
            'HOME': os.getcwd(),
1092
 
            'APPDATA': None,  # bzr now use Win32 API and don't rely on APPDATA
1093
 
            'BZR_EMAIL': None,
1094
 
            'BZREMAIL': None, # may still be present in the environment
1095
 
            'EMAIL': None,
1096
 
            'BZR_PROGRESS_BAR': None,
1097
 
            # Proxies
1098
 
            'http_proxy': None,
1099
 
            'HTTP_PROXY': None,
1100
 
            'https_proxy': None,
1101
 
            'HTTPS_PROXY': None,
1102
 
            'no_proxy': None,
1103
 
            'NO_PROXY': None,
1104
 
            'all_proxy': None,
1105
 
            'ALL_PROXY': None,
1106
 
            # Nobody cares about these ones AFAIK. So far at
1107
 
            # least. If you do (care), please update this comment
1108
 
            # -- vila 20061212
1109
 
            'ftp_proxy': None,
1110
 
            'FTP_PROXY': None,
1111
 
            'BZR_REMOTE_PATH': None,
1112
 
        }
1113
 
        self.__old_env = {}
1114
 
        self.addCleanup(self._restoreEnvironment)
1115
 
        for name, value in new_env.iteritems():
1116
 
            self._captureVar(name, value)
1117
 
 
1118
 
    def _captureVar(self, name, newvalue):
1119
 
        """Set an environment variable, and reset it when finished."""
1120
 
        self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
1121
 
 
1122
 
    def _restore_debug_flags(self):
1123
 
        debug.debug_flags.clear()
1124
 
        debug.debug_flags.update(self._preserved_debug_flags)
1125
 
 
1126
 
    def _restoreEnvironment(self):
1127
 
        for name, value in self.__old_env.iteritems():
1128
 
            osutils.set_or_unset_env(name, value)
 
1824
        for name, value in isolated_environ.iteritems():
 
1825
            self.overrideEnv(name, value)
1129
1826
 
1130
1827
    def _restoreHooks(self):
1131
 
        for klass, hooks in self._preserved_hooks.items():
1132
 
            setattr(klass, 'hooks', hooks)
 
1828
        for klass, (name, hooks) in self._preserved_hooks.items():
 
1829
            setattr(klass, name, hooks)
 
1830
        self._preserved_hooks.clear()
 
1831
        bzrlib.hooks._lazy_hooks = self._preserved_lazy_hooks
 
1832
        self._preserved_lazy_hooks.clear()
1133
1833
 
1134
1834
    def knownFailure(self, reason):
1135
 
        """This test has failed for some known reason."""
1136
 
        raise KnownFailure(reason)
1137
 
 
1138
 
    def run(self, result=None):
1139
 
        if result is None: result = self.defaultTestResult()
1140
 
        for feature in getattr(self, '_test_needs_features', []):
1141
 
            if not feature.available():
1142
 
                result.startTest(self)
1143
 
                if getattr(result, 'addNotSupported', None):
1144
 
                    result.addNotSupported(self, feature)
1145
 
                else:
1146
 
                    result.addSuccess(self)
1147
 
                result.stopTest(self)
1148
 
                return
1149
 
        return unittest.TestCase.run(self, result)
1150
 
 
1151
 
    def tearDown(self):
1152
 
        self._runCleanups()
1153
 
        unittest.TestCase.tearDown(self)
 
1835
        """Declare that this test fails for a known reason
 
1836
 
 
1837
        Tests that are known to fail should generally be using expectedFailure
 
1838
        with an appropriate reverse assertion if a change could cause the test
 
1839
        to start passing. Conversely if the test has no immediate prospect of
 
1840
        succeeding then using skip is more suitable.
 
1841
 
 
1842
        When this method is called while an exception is being handled, that
 
1843
        traceback will be used, otherwise a new exception will be thrown to
 
1844
        provide one but won't be reported.
 
1845
        """
 
1846
        self._add_reason(reason)
 
1847
        try:
 
1848
            exc_info = sys.exc_info()
 
1849
            if exc_info != (None, None, None):
 
1850
                self._report_traceback(exc_info)
 
1851
            else:
 
1852
                try:
 
1853
                    raise self.failureException(reason)
 
1854
                except self.failureException:
 
1855
                    exc_info = sys.exc_info()
 
1856
            # GZ 02-08-2011: Maybe cleanup this err.exc_info attribute too?
 
1857
            raise testtools.testcase._ExpectedFailure(exc_info)
 
1858
        finally:
 
1859
            del exc_info
 
1860
 
 
1861
    def _suppress_log(self):
 
1862
        """Remove the log info from details."""
 
1863
        self.discardDetail('log')
 
1864
 
 
1865
    def _do_skip(self, result, reason):
 
1866
        self._suppress_log()
 
1867
        addSkip = getattr(result, 'addSkip', None)
 
1868
        if not callable(addSkip):
 
1869
            result.addSuccess(result)
 
1870
        else:
 
1871
            addSkip(self, reason)
 
1872
 
 
1873
    @staticmethod
 
1874
    def _do_known_failure(self, result, e):
 
1875
        self._suppress_log()
 
1876
        err = sys.exc_info()
 
1877
        addExpectedFailure = getattr(result, 'addExpectedFailure', None)
 
1878
        if addExpectedFailure is not None:
 
1879
            addExpectedFailure(self, err)
 
1880
        else:
 
1881
            result.addSuccess(self)
 
1882
 
 
1883
    @staticmethod
 
1884
    def _do_not_applicable(self, result, e):
 
1885
        if not e.args:
 
1886
            reason = 'No reason given'
 
1887
        else:
 
1888
            reason = e.args[0]
 
1889
        self._suppress_log ()
 
1890
        addNotApplicable = getattr(result, 'addNotApplicable', None)
 
1891
        if addNotApplicable is not None:
 
1892
            result.addNotApplicable(self, reason)
 
1893
        else:
 
1894
            self._do_skip(result, reason)
 
1895
 
 
1896
    @staticmethod
 
1897
    def _report_skip(self, result, err):
 
1898
        """Override the default _report_skip.
 
1899
 
 
1900
        We want to strip the 'log' detail. If we waint until _do_skip, it has
 
1901
        already been formatted into the 'reason' string, and we can't pull it
 
1902
        out again.
 
1903
        """
 
1904
        self._suppress_log()
 
1905
        super(TestCase, self)._report_skip(self, result, err)
 
1906
 
 
1907
    @staticmethod
 
1908
    def _report_expected_failure(self, result, err):
 
1909
        """Strip the log.
 
1910
 
 
1911
        See _report_skip for motivation.
 
1912
        """
 
1913
        self._suppress_log()
 
1914
        super(TestCase, self)._report_expected_failure(self, result, err)
 
1915
 
 
1916
    @staticmethod
 
1917
    def _do_unsupported_or_skip(self, result, e):
 
1918
        reason = e.args[0]
 
1919
        self._suppress_log()
 
1920
        addNotSupported = getattr(result, 'addNotSupported', None)
 
1921
        if addNotSupported is not None:
 
1922
            result.addNotSupported(self, reason)
 
1923
        else:
 
1924
            self._do_skip(result, reason)
1154
1925
 
1155
1926
    def time(self, callable, *args, **kwargs):
1156
1927
        """Run callable and accrue the time it takes to the benchmark time.
1157
 
        
 
1928
 
1158
1929
        If lsprofiling is enabled (i.e. by --lsprof-time to bzr selftest) then
1159
1930
        this will cause lsprofile statistics to be gathered and stored in
1160
1931
        self._benchcalls.
1161
1932
        """
1162
1933
        if self._benchtime is None:
 
1934
            self.addDetail('benchtime', content.Content(content.ContentType(
 
1935
                "text", "plain"), lambda:[str(self._benchtime)]))
1163
1936
            self._benchtime = 0
1164
1937
        start = time.time()
1165
1938
        try:
1174
1947
        finally:
1175
1948
            self._benchtime += time.time() - start
1176
1949
 
1177
 
    def _runCleanups(self):
1178
 
        """Run registered cleanup functions. 
1179
 
 
1180
 
        This should only be called from TestCase.tearDown.
1181
 
        """
1182
 
        # TODO: Perhaps this should keep running cleanups even if 
1183
 
        # one of them fails?
1184
 
 
1185
 
        # Actually pop the cleanups from the list so tearDown running
1186
 
        # twice is safe (this happens for skipped tests).
1187
 
        while self._cleanups:
1188
 
            self._cleanups.pop()()
1189
 
 
1190
1950
    def log(self, *args):
1191
 
        mutter(*args)
1192
 
 
1193
 
    def _get_log(self, keep_log_file=False):
1194
 
        """Return as a string the log for this test. If the file is still
1195
 
        on disk and keep_log_file=False, delete the log file and store the
1196
 
        content in self._log_contents."""
1197
 
        # flush the log file, to get all content
1198
 
        import bzrlib.trace
1199
 
        bzrlib.trace._trace_file.flush()
1200
 
        if self._log_contents:
1201
 
            return self._log_contents
1202
 
        if self._log_file_name is not None:
1203
 
            logfile = open(self._log_file_name)
1204
 
            try:
1205
 
                log_contents = logfile.read()
1206
 
            finally:
1207
 
                logfile.close()
1208
 
            if not keep_log_file:
1209
 
                self._log_contents = log_contents
1210
 
                try:
1211
 
                    os.remove(self._log_file_name)
1212
 
                except OSError, e:
1213
 
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
1214
 
                        print >>sys.stderr, ('Unable to delete log file '
1215
 
                                             ' %r' % self._log_file_name)
1216
 
                    else:
1217
 
                        raise
1218
 
            return log_contents
1219
 
        else:
1220
 
            return "DELETED log file to reduce memory footprint"
1221
 
 
1222
 
    @deprecated_method(zero_eighteen)
1223
 
    def capture(self, cmd, retcode=0):
1224
 
        """Shortcut that splits cmd into words, runs, and returns stdout"""
1225
 
        return self.run_bzr_captured(cmd.split(), retcode=retcode)[0]
 
1951
        trace.mutter(*args)
 
1952
 
 
1953
    def get_log(self):
 
1954
        """Get a unicode string containing the log from bzrlib.trace.
 
1955
 
 
1956
        Undecodable characters are replaced.
 
1957
        """
 
1958
        return u"".join(self.getDetails()['log'].iter_text())
1226
1959
 
1227
1960
    def requireFeature(self, feature):
1228
1961
        """This test requires a specific feature is available.
1232
1965
        if not feature.available():
1233
1966
            raise UnavailableFeature(feature)
1234
1967
 
1235
 
    @deprecated_method(zero_eighteen)
1236
 
    def run_bzr_captured(self, argv, retcode=0, encoding=None, stdin=None,
1237
 
                         working_dir=None):
1238
 
        """Invoke bzr and return (stdout, stderr).
1239
 
 
1240
 
        Don't call this method, just use run_bzr() which is equivalent.
1241
 
 
1242
 
        :param argv: Arguments to invoke bzr.  This may be either a 
1243
 
            single string, in which case it is split by shlex into words, 
1244
 
            or a list of arguments.
1245
 
        :param retcode: Expected return code, or None for don't-care.
1246
 
        :param encoding: Encoding for sys.stdout and sys.stderr
1247
 
        :param stdin: A string to be used as stdin for the command.
1248
 
        :param working_dir: Change to this directory before running
1249
 
        """
1250
 
        return self._run_bzr_autosplit(argv, retcode=retcode,
1251
 
                encoding=encoding, stdin=stdin, working_dir=working_dir,
1252
 
                )
1253
 
 
1254
1968
    def _run_bzr_autosplit(self, args, retcode, encoding, stdin,
1255
1969
            working_dir):
1256
1970
        """Run bazaar command line, splitting up a string command line."""
1257
1971
        if isinstance(args, basestring):
1258
 
            args = list(shlex.split(args))
 
1972
            # shlex don't understand unicode strings,
 
1973
            # so args should be plain string (bialix 20070906)
 
1974
            args = list(shlex.split(str(args)))
1259
1975
        return self._run_bzr_core(args, retcode=retcode,
1260
1976
                encoding=encoding, stdin=stdin, working_dir=working_dir,
1261
1977
                )
1262
1978
 
1263
1979
    def _run_bzr_core(self, args, retcode, encoding, stdin,
1264
1980
            working_dir):
 
1981
        # Clear chk_map page cache, because the contents are likely to mask
 
1982
        # locking errors.
 
1983
        chk_map.clear_cache()
1265
1984
        if encoding is None:
1266
 
            encoding = bzrlib.user_encoding
 
1985
            encoding = osutils.get_user_encoding()
1267
1986
        stdout = StringIOWrapper()
1268
1987
        stderr = StringIOWrapper()
1269
1988
        stdout.encoding = encoding
1271
1990
 
1272
1991
        self.log('run bzr: %r', args)
1273
1992
        # FIXME: don't call into logging here
1274
 
        handler = logging.StreamHandler(stderr)
1275
 
        handler.setLevel(logging.INFO)
 
1993
        handler = trace.EncodedStreamHandler(stderr, errors="replace",
 
1994
            level=logging.INFO)
1276
1995
        logger = logging.getLogger('')
1277
1996
        logger.addHandler(handler)
1278
1997
        old_ui_factory = ui.ui_factory
1284
2003
            os.chdir(working_dir)
1285
2004
 
1286
2005
        try:
1287
 
            result = self.apply_redirected(ui.ui_factory.stdin,
1288
 
                stdout, stderr,
1289
 
                bzrlib.commands.run_bzr_catch_errors,
1290
 
                args)
 
2006
            try:
 
2007
                result = self.apply_redirected(
 
2008
                    ui.ui_factory.stdin,
 
2009
                    stdout, stderr,
 
2010
                    _mod_commands.run_bzr_catch_user_errors,
 
2011
                    args)
 
2012
            except KeyboardInterrupt:
 
2013
                # Reraise KeyboardInterrupt with contents of redirected stdout
 
2014
                # and stderr as arguments, for tests which are interested in
 
2015
                # stdout and stderr and are expecting the exception.
 
2016
                out = stdout.getvalue()
 
2017
                err = stderr.getvalue()
 
2018
                if out:
 
2019
                    self.log('output:\n%r', out)
 
2020
                if err:
 
2021
                    self.log('errors:\n%r', err)
 
2022
                raise KeyboardInterrupt(out, err)
1291
2023
        finally:
1292
2024
            logger.removeHandler(handler)
1293
2025
            ui.ui_factory = old_ui_factory
1303
2035
        if retcode is not None:
1304
2036
            self.assertEquals(retcode, result,
1305
2037
                              message='Unexpected return code')
1306
 
        return out, err
 
2038
        return result, out, err
1307
2039
 
1308
 
    def run_bzr(self, *args, **kwargs):
 
2040
    def run_bzr(self, args, retcode=0, encoding=None, stdin=None,
 
2041
                working_dir=None, error_regexes=[], output_encoding=None):
1309
2042
        """Invoke bzr, as if it were run from the command line.
1310
2043
 
1311
2044
        The argument list should not include the bzr program name - the
1313
2046
        passed in three ways:
1314
2047
 
1315
2048
        1- A list of strings, eg ["commit", "a"].  This is recommended
1316
 
        when the command contains whitespace or metacharacters, or 
 
2049
        when the command contains whitespace or metacharacters, or
1317
2050
        is built up at run time.
1318
2051
 
1319
 
        2- A single string, eg "add a".  This is the most convenient 
 
2052
        2- A single string, eg "add a".  This is the most convenient
1320
2053
        for hardcoded commands.
1321
2054
 
1322
 
        3- Several varargs parameters, eg run_bzr("add", "a").  
1323
 
        This is not recommended for new code.
1324
 
 
1325
2055
        This runs bzr through the interface that catches and reports
1326
2056
        errors, and with logging set to something approximating the
1327
2057
        default, so that error reporting can be checked.
1340
2070
        :keyword error_regexes: A list of expected error messages.  If
1341
2071
            specified they must be seen in the error output of the command.
1342
2072
        """
1343
 
        retcode = kwargs.pop('retcode', 0)
1344
 
        encoding = kwargs.pop('encoding', None)
1345
 
        stdin = kwargs.pop('stdin', None)
1346
 
        working_dir = kwargs.pop('working_dir', None)
1347
 
        error_regexes = kwargs.pop('error_regexes', [])
1348
 
 
1349
 
        if len(args) == 1:
1350
 
            if isinstance(args[0], (list, basestring)):
1351
 
                args = args[0]
1352
 
        else:
1353
 
            ## symbol_versioning.warn(zero_eighteen % "passing varargs to run_bzr",
1354
 
            ##         DeprecationWarning, stacklevel=2)
1355
 
            # not done yet, because too many tests would need to  be updated -
1356
 
            # but please don't do this in new code.  -- mbp 20070626
1357
 
            pass
1358
 
 
1359
 
        out, err = self._run_bzr_autosplit(args=args,
 
2073
        retcode, out, err = self._run_bzr_autosplit(
 
2074
            args=args,
1360
2075
            retcode=retcode,
1361
 
            encoding=encoding, stdin=stdin, working_dir=working_dir,
 
2076
            encoding=encoding,
 
2077
            stdin=stdin,
 
2078
            working_dir=working_dir,
1362
2079
            )
1363
 
 
 
2080
        self.assertIsInstance(error_regexes, (list, tuple))
1364
2081
        for regex in error_regexes:
1365
2082
            self.assertContainsRe(err, regex)
1366
2083
        return out, err
1367
2084
 
1368
 
    def run_bzr_decode(self, *args, **kwargs):
1369
 
        if 'encoding' in kwargs:
1370
 
            encoding = kwargs['encoding']
1371
 
        else:
1372
 
            encoding = bzrlib.user_encoding
1373
 
        return self.run_bzr(*args, **kwargs)[0].decode(encoding)
1374
 
 
1375
2085
    def run_bzr_error(self, error_regexes, *args, **kwargs):
1376
2086
        """Run bzr, and check that stderr contains the supplied regexes
1377
2087
 
1382
2092
        :param kwargs: Keyword arguments which are interpreted by run_bzr
1383
2093
            This function changes the default value of retcode to be 3,
1384
2094
            since in most cases this is run when you expect bzr to fail.
 
2095
 
1385
2096
        :return: (out, err) The actual output of running the command (in case
1386
2097
            you want to do more inspection)
1387
2098
 
1389
2100
 
1390
2101
            # Make sure that commit is failing because there is nothing to do
1391
2102
            self.run_bzr_error(['no changes to commit'],
1392
 
                               'commit', '-m', 'my commit comment')
 
2103
                               ['commit', '-m', 'my commit comment'])
1393
2104
            # Make sure --strict is handling an unknown file, rather than
1394
2105
            # giving us the 'nothing to do' error
1395
2106
            self.build_tree(['unknown'])
1396
2107
            self.run_bzr_error(['Commit refused because there are unknown files'],
1397
 
                               'commit', '--strict', '-m', 'my commit comment')
 
2108
                               ['commit', --strict', '-m', 'my commit comment'])
1398
2109
        """
1399
2110
        kwargs.setdefault('retcode', 3)
1400
 
        out, err = self.run_bzr(error_regexes=error_regexes, *args, **kwargs)
 
2111
        kwargs['error_regexes'] = error_regexes
 
2112
        out, err = self.run_bzr(*args, **kwargs)
1401
2113
        return out, err
1402
2114
 
1403
2115
    def run_bzr_subprocess(self, *args, **kwargs):
1404
2116
        """Run bzr in a subprocess for testing.
1405
2117
 
1406
 
        This starts a new Python interpreter and runs bzr in there. 
 
2118
        This starts a new Python interpreter and runs bzr in there.
1407
2119
        This should only be used for tests that have a justifiable need for
1408
2120
        this isolation: e.g. they are testing startup time, or signal
1409
 
        handling, or early startup code, etc.  Subprocess code can't be 
 
2121
        handling, or early startup code, etc.  Subprocess code can't be
1410
2122
        profiled or debugged so easily.
1411
2123
 
1412
2124
        :keyword retcode: The status code that is expected.  Defaults to 0.  If
1424
2136
        env_changes = kwargs.get('env_changes', {})
1425
2137
        working_dir = kwargs.get('working_dir', None)
1426
2138
        allow_plugins = kwargs.get('allow_plugins', False)
 
2139
        if len(args) == 1:
 
2140
            if isinstance(args[0], list):
 
2141
                args = args[0]
 
2142
            elif isinstance(args[0], basestring):
 
2143
                args = list(shlex.split(args[0]))
 
2144
        else:
 
2145
            raise ValueError("passing varargs to run_bzr_subprocess")
1427
2146
        process = self.start_bzr_subprocess(args, env_changes=env_changes,
1428
2147
                                            working_dir=working_dir,
1429
2148
                                            allow_plugins=allow_plugins)
1436
2155
    def start_bzr_subprocess(self, process_args, env_changes=None,
1437
2156
                             skip_if_plan_to_signal=False,
1438
2157
                             working_dir=None,
1439
 
                             allow_plugins=False):
 
2158
                             allow_plugins=False, stderr=subprocess.PIPE):
1440
2159
        """Start bzr in a subprocess for testing.
1441
2160
 
1442
2161
        This starts a new Python interpreter and runs bzr in there.
1451
2170
            variables. A value of None will unset the env variable.
1452
2171
            The values must be strings. The change will only occur in the
1453
2172
            child, so you don't need to fix the environment after running.
1454
 
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
1455
 
            is not available.
 
2173
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
 
2174
            doesn't support signalling subprocesses.
1456
2175
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
 
2176
        :param stderr: file to use for the subprocess's stderr.  Valid values
 
2177
            are those valid for the stderr argument of `subprocess.Popen`.
 
2178
            Default value is ``subprocess.PIPE``.
1457
2179
 
1458
2180
        :returns: Popen object for the started process.
1459
2181
        """
1460
2182
        if skip_if_plan_to_signal:
1461
 
            if not getattr(os, 'kill', None):
1462
 
                raise TestSkipped("os.kill not available.")
 
2183
            if os.name != "posix":
 
2184
                raise TestSkipped("Sending signals not supported")
1463
2185
 
1464
2186
        if env_changes is None:
1465
2187
            env_changes = {}
 
2188
        # Because $HOME is set to a tempdir for the context of a test, modules
 
2189
        # installed in the user dir will not be found unless $PYTHONUSERBASE
 
2190
        # gets set to the computed directory of this parent process.
 
2191
        if site.USER_BASE is not None:
 
2192
            env_changes["PYTHONUSERBASE"] = site.USER_BASE
1466
2193
        old_env = {}
1467
2194
 
1468
2195
        def cleanup_environment():
1485
2212
            # so we will avoid using it on all platforms, just to
1486
2213
            # make sure the code path is used, and we don't break on win32
1487
2214
            cleanup_environment()
1488
 
            command = [sys.executable, bzr_path]
 
2215
            # Include the subprocess's log file in the test details, in case
 
2216
            # the test fails due to an error in the subprocess.
 
2217
            self._add_subprocess_log(trace._get_bzr_log_filename())
 
2218
            command = [sys.executable]
 
2219
            # frozen executables don't need the path to bzr
 
2220
            if getattr(sys, "frozen", None) is None:
 
2221
                command.append(bzr_path)
1489
2222
            if not allow_plugins:
1490
2223
                command.append('--no-plugins')
1491
2224
            command.extend(process_args)
1492
 
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
 
2225
            process = self._popen(command, stdin=subprocess.PIPE,
 
2226
                                  stdout=subprocess.PIPE,
 
2227
                                  stderr=stderr)
1493
2228
        finally:
1494
2229
            restore_environment()
1495
2230
            if cwd is not None:
1497
2232
 
1498
2233
        return process
1499
2234
 
 
2235
    def _add_subprocess_log(self, log_file_path):
 
2236
        if len(self._log_files) == 0:
 
2237
            # Register an addCleanup func.  We do this on the first call to
 
2238
            # _add_subprocess_log rather than in TestCase.setUp so that this
 
2239
            # addCleanup is registered after any cleanups for tempdirs that
 
2240
            # subclasses might create, which will probably remove the log file
 
2241
            # we want to read.
 
2242
            self.addCleanup(self._subprocess_log_cleanup)
 
2243
        # self._log_files is a set, so if a log file is reused we won't grab it
 
2244
        # twice.
 
2245
        self._log_files.add(log_file_path)
 
2246
 
 
2247
    def _subprocess_log_cleanup(self):
 
2248
        for count, log_file_path in enumerate(self._log_files):
 
2249
            # We use buffer_now=True to avoid holding the file open beyond
 
2250
            # the life of this function, which might interfere with e.g.
 
2251
            # cleaning tempdirs on Windows.
 
2252
            # XXX: Testtools 0.9.5 doesn't have the content_from_file helper
 
2253
            #detail_content = content.content_from_file(
 
2254
            #    log_file_path, buffer_now=True)
 
2255
            with open(log_file_path, 'rb') as log_file:
 
2256
                log_file_bytes = log_file.read()
 
2257
            detail_content = content.Content(content.ContentType("text",
 
2258
                "plain", {"charset": "utf8"}), lambda: [log_file_bytes])
 
2259
            self.addDetail("start_bzr_subprocess-log-%d" % (count,),
 
2260
                detail_content)
 
2261
 
1500
2262
    def _popen(self, *args, **kwargs):
1501
2263
        """Place a call to Popen.
1502
2264
 
1503
2265
        Allows tests to override this method to intercept the calls made to
1504
2266
        Popen for introspection.
1505
2267
        """
1506
 
        return Popen(*args, **kwargs)
 
2268
        return subprocess.Popen(*args, **kwargs)
 
2269
 
 
2270
    def get_source_path(self):
 
2271
        """Return the path of the directory containing bzrlib."""
 
2272
        return os.path.dirname(os.path.dirname(bzrlib.__file__))
1507
2273
 
1508
2274
    def get_bzr_path(self):
1509
2275
        """Return the path of the 'bzr' executable for this test suite."""
1510
 
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
 
2276
        bzr_path = os.path.join(self.get_source_path(), "bzr")
1511
2277
        if not os.path.isfile(bzr_path):
1512
2278
            # We are probably installed. Assume sys.argv is the right file
1513
2279
            bzr_path = sys.argv[0]
1535
2301
        if retcode is not None and retcode != process.returncode:
1536
2302
            if process_args is None:
1537
2303
                process_args = "(unknown args)"
1538
 
            mutter('Output of bzr %s:\n%s', process_args, out)
1539
 
            mutter('Error for bzr %s:\n%s', process_args, err)
 
2304
            trace.mutter('Output of bzr %s:\n%s', process_args, out)
 
2305
            trace.mutter('Error for bzr %s:\n%s', process_args, err)
1540
2306
            self.fail('Command bzr %s failed with retcode %s != %s'
1541
2307
                      % (process_args, retcode, process.returncode))
1542
2308
        return [out, err]
1543
2309
 
1544
 
    def check_inventory_shape(self, inv, shape):
1545
 
        """Compare an inventory to a list of expected names.
 
2310
    def check_tree_shape(self, tree, shape):
 
2311
        """Compare a tree to a list of expected names.
1546
2312
 
1547
2313
        Fail if they are not precisely equal.
1548
2314
        """
1549
2315
        extras = []
1550
2316
        shape = list(shape)             # copy
1551
 
        for path, ie in inv.entries():
 
2317
        for path, ie in tree.iter_entries_by_dir():
1552
2318
            name = path.replace('\\', '/')
1553
2319
            if ie.kind == 'directory':
1554
2320
                name = name + '/'
1555
 
            if name in shape:
 
2321
            if name == "/":
 
2322
                pass # ignore root entry
 
2323
            elif name in shape:
1556
2324
                shape.remove(name)
1557
2325
            else:
1558
2326
                extras.append(name)
1599
2367
 
1600
2368
        Tests that expect to provoke LockContention errors should call this.
1601
2369
        """
1602
 
        orig_timeout = bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS
1603
 
        def resetTimeout():
1604
 
            bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = orig_timeout
1605
 
        self.addCleanup(resetTimeout)
1606
 
        bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = 0
 
2370
        self.overrideAttr(lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
 
2371
 
 
2372
    def make_utf8_encoded_stringio(self, encoding_type=None):
 
2373
        """Return a StringIOWrapper instance, that will encode Unicode
 
2374
        input to UTF-8.
 
2375
        """
 
2376
        if encoding_type is None:
 
2377
            encoding_type = 'strict'
 
2378
        sio = StringIO()
 
2379
        output_encoding = 'utf-8'
 
2380
        sio = codecs.getwriter(output_encoding)(sio, errors=encoding_type)
 
2381
        sio.encoding = output_encoding
 
2382
        return sio
 
2383
 
 
2384
    def disable_verb(self, verb):
 
2385
        """Disable a smart server verb for one test."""
 
2386
        from bzrlib.smart import request
 
2387
        request_handlers = request.request_handlers
 
2388
        orig_method = request_handlers.get(verb)
 
2389
        orig_info = request_handlers.get_info(verb)
 
2390
        request_handlers.remove(verb)
 
2391
        self.addCleanup(request_handlers.register, verb, orig_method,
 
2392
            info=orig_info)
 
2393
 
 
2394
 
 
2395
class CapturedCall(object):
 
2396
    """A helper for capturing smart server calls for easy debug analysis."""
 
2397
 
 
2398
    def __init__(self, params, prefix_length):
 
2399
        """Capture the call with params and skip prefix_length stack frames."""
 
2400
        self.call = params
 
2401
        import traceback
 
2402
        # The last 5 frames are the __init__, the hook frame, and 3 smart
 
2403
        # client frames. Beyond this we could get more clever, but this is good
 
2404
        # enough for now.
 
2405
        stack = traceback.extract_stack()[prefix_length:-5]
 
2406
        self.stack = ''.join(traceback.format_list(stack))
 
2407
 
 
2408
    def __str__(self):
 
2409
        return self.call.method
 
2410
 
 
2411
    def __repr__(self):
 
2412
        return self.call.method
 
2413
 
 
2414
    def stack(self):
 
2415
        return self.stack
1607
2416
 
1608
2417
 
1609
2418
class TestCaseWithMemoryTransport(TestCase):
1610
2419
    """Common test class for tests that do not need disk resources.
1611
2420
 
1612
 
    Tests that need disk resources should derive from TestCaseWithTransport.
 
2421
    Tests that need disk resources should derive from TestCaseInTempDir
 
2422
    orTestCaseWithTransport.
1613
2423
 
1614
2424
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
1615
2425
 
1616
 
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
 
2426
    For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
1617
2427
    a directory which does not exist. This serves to help ensure test isolation
1618
 
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
1619
 
    must exist. However, TestCaseWithMemoryTransport does not offer local
1620
 
    file defaults for the transport in tests, nor does it obey the command line
 
2428
    is preserved. ``test_dir`` is set to the TEST_ROOT, as is cwd, because they
 
2429
    must exist. However, TestCaseWithMemoryTransport does not offer local file
 
2430
    defaults for the transport in tests, nor does it obey the command line
1621
2431
    override, so tests that accidentally write to the common directory should
1622
2432
    be rare.
1623
2433
 
1624
 
    :cvar TEST_ROOT: Directory containing all temporary directories, plus
1625
 
    a .bzr directory that stops us ascending higher into the filesystem.
 
2434
    :cvar TEST_ROOT: Directory containing all temporary directories, plus a
 
2435
        ``.bzr`` directory that stops us ascending higher into the filesystem.
1626
2436
    """
1627
2437
 
1628
2438
    TEST_ROOT = None
1629
2439
    _TEST_NAME = 'test'
1630
2440
 
1631
2441
    def __init__(self, methodName='runTest'):
1632
 
        # allow test parameterisation after test construction and before test
1633
 
        # execution. Variables that the parameteriser sets need to be 
 
2442
        # allow test parameterization after test construction and before test
 
2443
        # execution. Variables that the parameterizer sets need to be
1634
2444
        # ones that are not set by setUp, or setUp will trash them.
1635
2445
        super(TestCaseWithMemoryTransport, self).__init__(methodName)
1636
2446
        self.vfs_transport_factory = default_transport
1638
2448
        self.transport_readonly_server = None
1639
2449
        self.__vfs_server = None
1640
2450
 
1641
 
    def get_transport(self):
1642
 
        """Return a writeable transport for the test scratch space"""
1643
 
        t = get_transport(self.get_url())
 
2451
    def get_transport(self, relpath=None):
 
2452
        """Return a writeable transport.
 
2453
 
 
2454
        This transport is for the test scratch space relative to
 
2455
        "self._test_root"
 
2456
 
 
2457
        :param relpath: a path relative to the base url.
 
2458
        """
 
2459
        t = _mod_transport.get_transport_from_url(self.get_url(relpath))
1644
2460
        self.assertFalse(t.is_readonly())
1645
2461
        return t
1646
2462
 
1647
 
    def get_readonly_transport(self):
 
2463
    def get_readonly_transport(self, relpath=None):
1648
2464
        """Return a readonly transport for the test scratch space
1649
 
        
 
2465
 
1650
2466
        This can be used to test that operations which should only need
1651
2467
        readonly access in fact do not try to write.
 
2468
 
 
2469
        :param relpath: a path relative to the base url.
1652
2470
        """
1653
 
        t = get_transport(self.get_readonly_url())
 
2471
        t = _mod_transport.get_transport_from_url(
 
2472
            self.get_readonly_url(relpath))
1654
2473
        self.assertTrue(t.is_readonly())
1655
2474
        return t
1656
2475
 
1669
2488
        if self.__readonly_server is None:
1670
2489
            if self.transport_readonly_server is None:
1671
2490
                # readonly decorator requested
1672
 
                # bring up the server
1673
 
                self.__readonly_server = ReadonlyServer()
1674
 
                self.__readonly_server.setUp(self.get_vfs_only_server())
 
2491
                self.__readonly_server = test_server.ReadonlyServer()
1675
2492
            else:
 
2493
                # explicit readonly transport.
1676
2494
                self.__readonly_server = self.create_transport_readonly_server()
1677
 
                self.__readonly_server.setUp(self.get_vfs_only_server())
1678
 
            self.addCleanup(self.__readonly_server.tearDown)
 
2495
            self.start_server(self.__readonly_server,
 
2496
                self.get_vfs_only_server())
1679
2497
        return self.__readonly_server
1680
2498
 
1681
2499
    def get_readonly_url(self, relpath=None):
1682
2500
        """Get a URL for the readonly transport.
1683
2501
 
1684
 
        This will either be backed by '.' or a decorator to the transport 
 
2502
        This will either be backed by '.' or a decorator to the transport
1685
2503
        used by self.get_url()
1686
2504
        relpath provides for clients to get a path relative to the base url.
1687
2505
        These should only be downwards relative, not upwards.
1688
2506
        """
1689
2507
        base = self.get_readonly_server().get_url()
1690
 
        if relpath is not None:
1691
 
            if not base.endswith('/'):
1692
 
                base = base + '/'
1693
 
            base = base + relpath
1694
 
        return base
 
2508
        return self._adjust_url(base, relpath)
1695
2509
 
1696
2510
    def get_vfs_only_server(self):
1697
2511
        """Get the vfs only read/write server instance.
1703
2517
        is no means to override it.
1704
2518
        """
1705
2519
        if self.__vfs_server is None:
1706
 
            self.__vfs_server = MemoryServer()
1707
 
            self.__vfs_server.setUp()
1708
 
            self.addCleanup(self.__vfs_server.tearDown)
 
2520
            self.__vfs_server = memory.MemoryServer()
 
2521
            self.start_server(self.__vfs_server)
1709
2522
        return self.__vfs_server
1710
2523
 
1711
2524
    def get_server(self):
1718
2531
        then the self.get_vfs_server is returned.
1719
2532
        """
1720
2533
        if self.__server is None:
1721
 
            if self.transport_server is None or self.transport_server is self.vfs_transport_factory:
1722
 
                return self.get_vfs_only_server()
 
2534
            if (self.transport_server is None or self.transport_server is
 
2535
                self.vfs_transport_factory):
 
2536
                self.__server = self.get_vfs_only_server()
1723
2537
            else:
1724
2538
                # bring up a decorated means of access to the vfs only server.
1725
2539
                self.__server = self.transport_server()
1726
 
                try:
1727
 
                    self.__server.setUp(self.get_vfs_only_server())
1728
 
                except TypeError, e:
1729
 
                    # This should never happen; the try:Except here is to assist
1730
 
                    # developers having to update code rather than seeing an
1731
 
                    # uninformative TypeError.
1732
 
                    raise Exception, "Old server API in use: %s, %s" % (self.__server, e)
1733
 
            self.addCleanup(self.__server.tearDown)
 
2540
                self.start_server(self.__server, self.get_vfs_only_server())
1734
2541
        return self.__server
1735
2542
 
1736
2543
    def _adjust_url(self, base, relpath):
1782
2589
        base = self.get_vfs_only_server().get_url()
1783
2590
        return self._adjust_url(base, relpath)
1784
2591
 
 
2592
    def _create_safety_net(self):
 
2593
        """Make a fake bzr directory.
 
2594
 
 
2595
        This prevents any tests propagating up onto the TEST_ROOT directory's
 
2596
        real branch.
 
2597
        """
 
2598
        root = TestCaseWithMemoryTransport.TEST_ROOT
 
2599
        # Make sure we get a readable and accessible home for .bzr.log
 
2600
        # and/or config files, and not fallback to weird defaults (see
 
2601
        # http://pad.lv/825027).
 
2602
        self.assertIs(None, os.environ.get('BZR_HOME', None))
 
2603
        os.environ['BZR_HOME'] = root
 
2604
        wt = bzrdir.BzrDir.create_standalone_workingtree(root)
 
2605
        del os.environ['BZR_HOME']
 
2606
        # Hack for speed: remember the raw bytes of the dirstate file so that
 
2607
        # we don't need to re-open the wt to check it hasn't changed.
 
2608
        TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE = (
 
2609
            wt.control_transport.get_bytes('dirstate'))
 
2610
 
 
2611
    def _check_safety_net(self):
 
2612
        """Check that the safety .bzr directory have not been touched.
 
2613
 
 
2614
        _make_test_root have created a .bzr directory to prevent tests from
 
2615
        propagating. This method ensures than a test did not leaked.
 
2616
        """
 
2617
        root = TestCaseWithMemoryTransport.TEST_ROOT
 
2618
        t = _mod_transport.get_transport_from_path(root)
 
2619
        self.permit_url(t.base)
 
2620
        if (t.get_bytes('.bzr/checkout/dirstate') != 
 
2621
                TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE):
 
2622
            # The current test have modified the /bzr directory, we need to
 
2623
            # recreate a new one or all the followng tests will fail.
 
2624
            # If you need to inspect its content uncomment the following line
 
2625
            # import pdb; pdb.set_trace()
 
2626
            _rmtree_temp_dir(root + '/.bzr', test_id=self.id())
 
2627
            self._create_safety_net()
 
2628
            raise AssertionError('%s/.bzr should not be modified' % root)
 
2629
 
1785
2630
    def _make_test_root(self):
1786
 
        if TestCaseWithMemoryTransport.TEST_ROOT is not None:
1787
 
            return
1788
 
        root = tempfile.mkdtemp(prefix='testbzr-', suffix='.tmp')
1789
 
        TestCaseWithMemoryTransport.TEST_ROOT = root
1790
 
        
1791
 
        # make a fake bzr directory there to prevent any tests propagating
1792
 
        # up onto the source directory's real branch
1793
 
        bzrdir.BzrDir.create_standalone_workingtree(root)
1794
 
 
1795
 
        # The same directory is used by all tests, and we're not specifically
1796
 
        # told when all tests are finished.  This will do.
1797
 
        atexit.register(_rmtree_temp_dir, root)
 
2631
        if TestCaseWithMemoryTransport.TEST_ROOT is None:
 
2632
            # Watch out for tricky test dir (on OSX /tmp -> /private/tmp)
 
2633
            root = osutils.realpath(osutils.mkdtemp(prefix='testbzr-',
 
2634
                                                    suffix='.tmp'))
 
2635
            TestCaseWithMemoryTransport.TEST_ROOT = root
 
2636
 
 
2637
            self._create_safety_net()
 
2638
 
 
2639
            # The same directory is used by all tests, and we're not
 
2640
            # specifically told when all tests are finished.  This will do.
 
2641
            atexit.register(_rmtree_temp_dir, root)
 
2642
 
 
2643
        self.permit_dir(TestCaseWithMemoryTransport.TEST_ROOT)
 
2644
        self.addCleanup(self._check_safety_net)
1798
2645
 
1799
2646
    def makeAndChdirToTestDir(self):
1800
2647
        """Create a temporary directories for this one test.
1801
 
        
 
2648
 
1802
2649
        This must set self.test_home_dir and self.test_dir and chdir to
1803
2650
        self.test_dir.
1804
 
        
 
2651
 
1805
2652
        For TestCaseWithMemoryTransport we chdir to the TEST_ROOT for this test.
1806
2653
        """
1807
2654
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
1808
2655
        self.test_dir = TestCaseWithMemoryTransport.TEST_ROOT
1809
2656
        self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
1810
 
        
 
2657
        self.permit_dir(self.test_dir)
 
2658
 
1811
2659
    def make_branch(self, relpath, format=None):
1812
2660
        """Create a branch on the transport at relpath."""
1813
2661
        repo = self.make_repository(relpath, format=format)
1814
 
        return repo.bzrdir.create_branch()
 
2662
        return repo.bzrdir.create_branch(append_revisions_only=False)
 
2663
 
 
2664
    def get_default_format(self):
 
2665
        return 'default'
 
2666
 
 
2667
    def resolve_format(self, format):
 
2668
        """Resolve an object to a ControlDir format object.
 
2669
 
 
2670
        The initial format object can either already be
 
2671
        a ControlDirFormat, None (for the default format),
 
2672
        or a string with the name of the control dir format.
 
2673
 
 
2674
        :param format: Object to resolve
 
2675
        :return A ControlDirFormat instance
 
2676
        """
 
2677
        if format is None:
 
2678
            format = self.get_default_format()
 
2679
        if isinstance(format, basestring):
 
2680
            format = bzrdir.format_registry.make_bzrdir(format)
 
2681
        return format
1815
2682
 
1816
2683
    def make_bzrdir(self, relpath, format=None):
1817
2684
        try:
1818
2685
            # might be a relative or absolute path
1819
2686
            maybe_a_url = self.get_url(relpath)
1820
2687
            segments = maybe_a_url.rsplit('/', 1)
1821
 
            t = get_transport(maybe_a_url)
 
2688
            t = _mod_transport.get_transport(maybe_a_url)
1822
2689
            if len(segments) > 1 and segments[-1] not in ('', '.'):
1823
2690
                t.ensure_base()
1824
 
            if format is None:
1825
 
                format = 'default'
1826
 
            if isinstance(format, basestring):
1827
 
                format = bzrdir.format_registry.make_bzrdir(format)
 
2691
            format = self.resolve_format(format)
1828
2692
            return format.initialize_on_transport(t)
1829
2693
        except errors.UninitializableFormat:
1830
2694
            raise TestSkipped("Format %s is not initializable." % format)
1831
2695
 
1832
 
    def make_repository(self, relpath, shared=False, format=None):
 
2696
    def make_repository(self, relpath, shared=None, format=None):
1833
2697
        """Create a repository on our default transport at relpath.
1834
 
        
 
2698
 
1835
2699
        Note that relpath must be a relative path, not a full url.
1836
2700
        """
1837
2701
        # FIXME: If you create a remoterepository this returns the underlying
1838
 
        # real format, which is incorrect.  Actually we should make sure that 
 
2702
        # real format, which is incorrect.  Actually we should make sure that
1839
2703
        # RemoteBzrDir returns a RemoteRepository.
1840
2704
        # maybe  mbp 20070410
1841
2705
        made_control = self.make_bzrdir(relpath, format=format)
1842
2706
        return made_control.create_repository(shared=shared)
1843
2707
 
 
2708
    def make_smart_server(self, path, backing_server=None):
 
2709
        if backing_server is None:
 
2710
            backing_server = self.get_server()
 
2711
        smart_server = test_server.SmartTCPServer_for_testing()
 
2712
        self.start_server(smart_server, backing_server)
 
2713
        remote_transport = _mod_transport.get_transport_from_url(smart_server.get_url()
 
2714
                                                   ).clone(path)
 
2715
        return remote_transport
 
2716
 
1844
2717
    def make_branch_and_memory_tree(self, relpath, format=None):
1845
2718
        """Create a branch on the default transport and a MemoryTree for it."""
1846
2719
        b = self.make_branch(relpath, format=format)
1847
2720
        return memorytree.MemoryTree.create_on_branch(b)
1848
2721
 
 
2722
    def make_branch_builder(self, relpath, format=None):
 
2723
        branch = self.make_branch(relpath, format=format)
 
2724
        return branchbuilder.BranchBuilder(branch=branch)
 
2725
 
1849
2726
    def overrideEnvironmentForTesting(self):
1850
 
        os.environ['HOME'] = self.test_home_dir
1851
 
        os.environ['BZR_HOME'] = self.test_home_dir
1852
 
        
 
2727
        test_home_dir = self.test_home_dir
 
2728
        if isinstance(test_home_dir, unicode):
 
2729
            test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
 
2730
        self.overrideEnv('HOME', test_home_dir)
 
2731
        self.overrideEnv('BZR_HOME', test_home_dir)
 
2732
 
1853
2733
    def setUp(self):
1854
2734
        super(TestCaseWithMemoryTransport, self).setUp()
 
2735
 
 
2736
        def _add_disconnect_cleanup(transport):
 
2737
            """Schedule disconnection of given transport at test cleanup
 
2738
 
 
2739
            This needs to happen for all connected transports or leaks occur.
 
2740
 
 
2741
            Note reconnections may mean we call disconnect multiple times per
 
2742
            transport which is suboptimal but seems harmless.
 
2743
            """
 
2744
            self.addCleanup(transport.disconnect)
 
2745
 
 
2746
        _mod_transport.Transport.hooks.install_named_hook('post_connect',
 
2747
            _add_disconnect_cleanup, None)
 
2748
 
1855
2749
        self._make_test_root()
1856
 
        _currentdir = os.getcwdu()
1857
 
        def _leaveDirectory():
1858
 
            os.chdir(_currentdir)
1859
 
        self.addCleanup(_leaveDirectory)
 
2750
        self.addCleanup(os.chdir, os.getcwdu())
1860
2751
        self.makeAndChdirToTestDir()
1861
2752
        self.overrideEnvironmentForTesting()
1862
2753
        self.__readonly_server = None
1863
2754
        self.__server = None
1864
2755
        self.reduceLockdirTimeout()
1865
2756
 
1866
 
     
 
2757
    def setup_smart_server_with_call_log(self):
 
2758
        """Sets up a smart server as the transport server with a call log."""
 
2759
        self.transport_server = test_server.SmartTCPServer_for_testing
 
2760
        self.hpss_calls = []
 
2761
        import traceback
 
2762
        # Skip the current stack down to the caller of
 
2763
        # setup_smart_server_with_call_log
 
2764
        prefix_length = len(traceback.extract_stack()) - 2
 
2765
        def capture_hpss_call(params):
 
2766
            self.hpss_calls.append(
 
2767
                CapturedCall(params, prefix_length))
 
2768
        client._SmartClient.hooks.install_named_hook(
 
2769
            'call', capture_hpss_call, None)
 
2770
 
 
2771
    def reset_smart_call_log(self):
 
2772
        self.hpss_calls = []
 
2773
 
 
2774
 
1867
2775
class TestCaseInTempDir(TestCaseWithMemoryTransport):
1868
2776
    """Derived class that runs a test within a temporary directory.
1869
2777
 
1874
2782
    All test cases create their own directory within that.  If the
1875
2783
    tests complete successfully, the directory is removed.
1876
2784
 
1877
 
    :ivar test_base_dir: The path of the top-level directory for this 
 
2785
    :ivar test_base_dir: The path of the top-level directory for this
1878
2786
    test, which contains a home directory and a work directory.
1879
2787
 
1880
2788
    :ivar test_home_dir: An initially empty directory under test_base_dir
1885
2793
    """
1886
2794
 
1887
2795
    OVERRIDE_PYTHON = 'python'
1888
 
    use_numbered_dirs = False
 
2796
 
 
2797
    def setUp(self):
 
2798
        super(TestCaseInTempDir, self).setUp()
 
2799
        # Remove the protection set in isolated_environ, we have a proper
 
2800
        # access to disk resources now.
 
2801
        self.overrideEnv('BZR_LOG', None)
1889
2802
 
1890
2803
    def check_file_contents(self, filename, expect):
1891
2804
        self.log("check contents of file %s" % filename)
1892
 
        contents = file(filename, 'r').read()
 
2805
        f = file(filename)
 
2806
        try:
 
2807
            contents = f.read()
 
2808
        finally:
 
2809
            f.close()
1893
2810
        if contents != expect:
1894
2811
            self.log("expected: %r" % expect)
1895
2812
            self.log("actually: %r" % contents)
1896
2813
            self.fail("contents of %s not as expected" % filename)
1897
2814
 
 
2815
    def _getTestDirPrefix(self):
 
2816
        # create a directory within the top level test directory
 
2817
        if sys.platform in ('win32', 'cygwin'):
 
2818
            name_prefix = re.sub('[<>*=+",:;_/\\-]', '_', self.id())
 
2819
            # windows is likely to have path-length limits so use a short name
 
2820
            name_prefix = name_prefix[-30:]
 
2821
        else:
 
2822
            name_prefix = re.sub('[/]', '_', self.id())
 
2823
        return name_prefix
 
2824
 
1898
2825
    def makeAndChdirToTestDir(self):
1899
2826
        """See TestCaseWithMemoryTransport.makeAndChdirToTestDir().
1900
 
        
 
2827
 
1901
2828
        For TestCaseInTempDir we create a temporary directory based on the test
1902
2829
        name and then create two subdirs - test and home under it.
1903
2830
        """
1904
 
        # create a directory within the top level test directory
1905
 
        candidate_dir = tempfile.mkdtemp(dir=self.TEST_ROOT)
1906
 
        # now create test and home directories within this dir
1907
 
        self.test_base_dir = candidate_dir
 
2831
        name_prefix = osutils.pathjoin(TestCaseWithMemoryTransport.TEST_ROOT,
 
2832
            self._getTestDirPrefix())
 
2833
        name = name_prefix
 
2834
        for i in range(100):
 
2835
            if os.path.exists(name):
 
2836
                name = name_prefix + '_' + str(i)
 
2837
            else:
 
2838
                # now create test and home directories within this dir
 
2839
                self.test_base_dir = name
 
2840
                self.addCleanup(self.deleteTestDir)
 
2841
                os.mkdir(self.test_base_dir)
 
2842
                break
 
2843
        self.permit_dir(self.test_base_dir)
 
2844
        # 'sprouting' and 'init' of a branch both walk up the tree to find
 
2845
        # stacking policy to honour; create a bzr dir with an unshared
 
2846
        # repository (but not a branch - our code would be trying to escape
 
2847
        # then!) to stop them, and permit it to be read.
 
2848
        # control = bzrdir.BzrDir.create(self.test_base_dir)
 
2849
        # control.create_repository()
1908
2850
        self.test_home_dir = self.test_base_dir + '/home'
1909
2851
        os.mkdir(self.test_home_dir)
1910
2852
        self.test_dir = self.test_base_dir + '/work'
1916
2858
            f.write(self.id())
1917
2859
        finally:
1918
2860
            f.close()
1919
 
        self.addCleanup(self.deleteTestDir)
1920
2861
 
1921
2862
    def deleteTestDir(self):
1922
 
        os.chdir(self.TEST_ROOT)
1923
 
        _rmtree_temp_dir(self.test_base_dir)
 
2863
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
 
2864
        _rmtree_temp_dir(self.test_base_dir, test_id=self.id())
1924
2865
 
1925
2866
    def build_tree(self, shape, line_endings='binary', transport=None):
1926
2867
        """Build a test tree according to a pattern.
1932
2873
 
1933
2874
        This doesn't add anything to a branch.
1934
2875
 
 
2876
        :type shape:    list or tuple.
1935
2877
        :param line_endings: Either 'binary' or 'native'
1936
2878
            in binary mode, exact contents are written in native mode, the
1937
2879
            line endings match the default platform endings.
1939
2881
            If the transport is readonly or None, "." is opened automatically.
1940
2882
        :return: None
1941
2883
        """
 
2884
        if type(shape) not in (list, tuple):
 
2885
            raise AssertionError("Parameter 'shape' should be "
 
2886
                "a list or a tuple. Got %r instead" % (shape,))
1942
2887
        # It's OK to just create them using forward slashes on windows.
1943
2888
        if transport is None or transport.is_readonly():
1944
 
            transport = get_transport(".")
 
2889
            transport = _mod_transport.get_transport_from_path(".")
1945
2890
        for name in shape:
1946
 
            self.assert_(isinstance(name, basestring))
 
2891
            self.assertIsInstance(name, basestring)
1947
2892
            if name[-1] == '/':
1948
2893
                transport.mkdir(urlutils.escape(name[:-1]))
1949
2894
            else:
1957
2902
                content = "contents of %s%s" % (name.encode('utf-8'), end)
1958
2903
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
1959
2904
 
1960
 
    def build_tree_contents(self, shape):
1961
 
        build_tree_contents(shape)
1962
 
 
1963
 
    def assertFileEqual(self, content, path):
1964
 
        """Fail if path does not contain 'content'."""
1965
 
        self.failUnlessExists(path)
1966
 
        f = file(path, 'rb')
1967
 
        try:
1968
 
            s = f.read()
1969
 
        finally:
1970
 
            f.close()
1971
 
        self.assertEqualDiff(content, s)
1972
 
 
1973
 
    def failUnlessExists(self, path):
1974
 
        """Fail unless path or paths, which may be abs or relative, exist."""
1975
 
        if not isinstance(path, basestring):
1976
 
            for p in path:
1977
 
                self.failUnlessExists(p)
1978
 
        else:
1979
 
            self.failUnless(osutils.lexists(path),path+" does not exist")
1980
 
 
1981
 
    def failIfExists(self, path):
1982
 
        """Fail if path or paths, which may be abs or relative, exist."""
1983
 
        if not isinstance(path, basestring):
1984
 
            for p in path:
1985
 
                self.failIfExists(p)
1986
 
        else:
1987
 
            self.failIf(osutils.lexists(path),path+" exists")
1988
 
 
1989
 
    def assertInWorkingTree(self,path,root_path='.',tree=None):
 
2905
    build_tree_contents = staticmethod(treeshape.build_tree_contents)
 
2906
 
 
2907
    def assertInWorkingTree(self, path, root_path='.', tree=None):
1990
2908
        """Assert whether path or paths are in the WorkingTree"""
1991
2909
        if tree is None:
1992
2910
            tree = workingtree.WorkingTree.open(root_path)
1993
2911
        if not isinstance(path, basestring):
1994
2912
            for p in path:
1995
 
                self.assertInWorkingTree(p,tree=tree)
 
2913
                self.assertInWorkingTree(p, tree=tree)
1996
2914
        else:
1997
2915
            self.assertIsNot(tree.path2id(path), None,
1998
2916
                path+' not in working tree.')
1999
2917
 
2000
 
    def assertNotInWorkingTree(self,path,root_path='.',tree=None):
 
2918
    def assertNotInWorkingTree(self, path, root_path='.', tree=None):
2001
2919
        """Assert whether path or paths are not in the WorkingTree"""
2002
2920
        if tree is None:
2003
2921
            tree = workingtree.WorkingTree.open(root_path)
2018
2936
    ReadonlyTransportDecorator is used instead which allows the use of non disk
2019
2937
    based read write transports.
2020
2938
 
2021
 
    If an explicit class is provided for readonly access, that server and the 
 
2939
    If an explicit class is provided for readonly access, that server and the
2022
2940
    readwrite one must both define get_url() as resolving to os.getcwd().
2023
2941
    """
2024
2942
 
2030
2948
        """
2031
2949
        if self.__vfs_server is None:
2032
2950
            self.__vfs_server = self.vfs_transport_factory()
2033
 
            self.__vfs_server.setUp()
2034
 
            self.addCleanup(self.__vfs_server.tearDown)
 
2951
            self.start_server(self.__vfs_server)
2035
2952
        return self.__vfs_server
2036
2953
 
2037
2954
    def make_branch_and_tree(self, relpath, format=None):
2044
2961
        repository will also be accessed locally. Otherwise a lightweight
2045
2962
        checkout is created and returned.
2046
2963
 
 
2964
        We do this because we can't physically create a tree in the local
 
2965
        path, with a branch reference to the transport_factory url, and
 
2966
        a branch + repository in the vfs_transport, unless the vfs_transport
 
2967
        namespace is distinct from the local disk - the two branch objects
 
2968
        would collide. While we could construct a tree with its branch object
 
2969
        pointing at the transport_factory transport in memory, reopening it
 
2970
        would behaving unexpectedly, and has in the past caused testing bugs
 
2971
        when we tried to do it that way.
 
2972
 
2047
2973
        :param format: The BzrDirFormat.
2048
2974
        :returns: the WorkingTree.
2049
2975
        """
2051
2977
        # this obviously requires a format that supports branch references
2052
2978
        # so check for that by checking bzrdir.BzrDirFormat.get_default_format()
2053
2979
        # RBC 20060208
 
2980
        format = self.resolve_format(format=format)
 
2981
        if not format.supports_workingtrees:
 
2982
            b = self.make_branch(relpath+'.branch', format=format)
 
2983
            return b.create_checkout(relpath, lightweight=True)
2054
2984
        b = self.make_branch(relpath, format=format)
2055
2985
        try:
2056
2986
            return b.bzrdir.create_workingtree()
2058
2988
            # We can only make working trees locally at the moment.  If the
2059
2989
            # transport can't support them, then we keep the non-disk-backed
2060
2990
            # branch and create a local checkout.
2061
 
            if self.vfs_transport_factory is LocalURLServer:
 
2991
            if self.vfs_transport_factory is test_server.LocalURLServer:
2062
2992
                # the branch is colocated on disk, we cannot create a checkout.
2063
2993
                # hopefully callers will expect this.
2064
2994
                local_controldir= bzrdir.BzrDir.open(self.get_vfs_only_url(relpath))
2065
 
                return local_controldir.create_workingtree()
 
2995
                wt = local_controldir.create_workingtree()
 
2996
                if wt.branch._format != b._format:
 
2997
                    wt._branch = b
 
2998
                    # Make sure that assigning to wt._branch fixes wt.branch,
 
2999
                    # in case the implementation details of workingtree objects
 
3000
                    # change.
 
3001
                    self.assertIs(b, wt.branch)
 
3002
                return wt
2066
3003
            else:
2067
3004
                return b.create_checkout(relpath, lightweight=True)
2068
3005
 
2094
3031
        super(TestCaseWithTransport, self).setUp()
2095
3032
        self.__vfs_server = None
2096
3033
 
 
3034
    def disable_missing_extensions_warning(self):
 
3035
        """Some tests expect a precise stderr content.
 
3036
 
 
3037
        There is no point in forcing them to duplicate the extension related
 
3038
        warning.
 
3039
        """
 
3040
        config.GlobalConfig().set_user_option('ignore_missing_extensions', True)
 
3041
 
2097
3042
 
2098
3043
class ChrootedTestCase(TestCaseWithTransport):
2099
3044
    """A support class that provides readonly urls outside the local namespace.
2103
3048
    for readonly urls.
2104
3049
 
2105
3050
    TODO RBC 20060127: make this an option to TestCaseWithTransport so it can
2106
 
                       be used without needed to redo it when a different 
 
3051
                       be used without needed to redo it when a different
2107
3052
                       subclass is in use ?
2108
3053
    """
2109
3054
 
2110
3055
    def setUp(self):
 
3056
        from bzrlib.tests import http_server
2111
3057
        super(ChrootedTestCase, self).setUp()
2112
 
        if not self.vfs_transport_factory == MemoryServer:
2113
 
            self.transport_readonly_server = HttpServer
2114
 
 
2115
 
 
2116
 
def filter_suite_by_re(suite, pattern, exclude_pattern=None,
2117
 
                       random_order=False):
2118
 
    """Create a test suite by filtering another one.
2119
 
    
 
3058
        if not self.vfs_transport_factory == memory.MemoryServer:
 
3059
            self.transport_readonly_server = http_server.HttpServer
 
3060
 
 
3061
 
 
3062
def condition_id_re(pattern):
 
3063
    """Create a condition filter which performs a re check on a test's id.
 
3064
 
 
3065
    :param pattern: A regular expression string.
 
3066
    :return: A callable that returns True if the re matches.
 
3067
    """
 
3068
    filter_re = re.compile(pattern, 0)
 
3069
    def condition(test):
 
3070
        test_id = test.id()
 
3071
        return filter_re.search(test_id)
 
3072
    return condition
 
3073
 
 
3074
 
 
3075
def condition_isinstance(klass_or_klass_list):
 
3076
    """Create a condition filter which returns isinstance(param, klass).
 
3077
 
 
3078
    :return: A callable which when called with one parameter obj return the
 
3079
        result of isinstance(obj, klass_or_klass_list).
 
3080
    """
 
3081
    def condition(obj):
 
3082
        return isinstance(obj, klass_or_klass_list)
 
3083
    return condition
 
3084
 
 
3085
 
 
3086
def condition_id_in_list(id_list):
 
3087
    """Create a condition filter which verify that test's id in a list.
 
3088
 
 
3089
    :param id_list: A TestIdList object.
 
3090
    :return: A callable that returns True if the test's id appears in the list.
 
3091
    """
 
3092
    def condition(test):
 
3093
        return id_list.includes(test.id())
 
3094
    return condition
 
3095
 
 
3096
 
 
3097
def condition_id_startswith(starts):
 
3098
    """Create a condition filter verifying that test's id starts with a string.
 
3099
 
 
3100
    :param starts: A list of string.
 
3101
    :return: A callable that returns True if the test's id starts with one of
 
3102
        the given strings.
 
3103
    """
 
3104
    def condition(test):
 
3105
        for start in starts:
 
3106
            if test.id().startswith(start):
 
3107
                return True
 
3108
        return False
 
3109
    return condition
 
3110
 
 
3111
 
 
3112
def exclude_tests_by_condition(suite, condition):
 
3113
    """Create a test suite which excludes some tests from suite.
 
3114
 
 
3115
    :param suite: The suite to get tests from.
 
3116
    :param condition: A callable whose result evaluates True when called with a
 
3117
        test case which should be excluded from the result.
 
3118
    :return: A suite which contains the tests found in suite that fail
 
3119
        condition.
 
3120
    """
 
3121
    result = []
 
3122
    for test in iter_suite_tests(suite):
 
3123
        if not condition(test):
 
3124
            result.append(test)
 
3125
    return TestUtil.TestSuite(result)
 
3126
 
 
3127
 
 
3128
def filter_suite_by_condition(suite, condition):
 
3129
    """Create a test suite by filtering another one.
 
3130
 
 
3131
    :param suite: The source suite.
 
3132
    :param condition: A callable whose result evaluates True when called with a
 
3133
        test case which should be included in the result.
 
3134
    :return: A suite which contains the tests found in suite that pass
 
3135
        condition.
 
3136
    """
 
3137
    result = []
 
3138
    for test in iter_suite_tests(suite):
 
3139
        if condition(test):
 
3140
            result.append(test)
 
3141
    return TestUtil.TestSuite(result)
 
3142
 
 
3143
 
 
3144
def filter_suite_by_re(suite, pattern):
 
3145
    """Create a test suite by filtering another one.
 
3146
 
2120
3147
    :param suite:           the source suite
2121
3148
    :param pattern:         pattern that names must match
2122
 
    :param exclude_pattern: pattern that names must not match, if any
2123
 
    :param random_order:    if True, tests in the new suite will be put in
2124
 
                            random order
2125
 
    :returns: the newly created suite
2126
 
    """ 
2127
 
    return sort_suite_by_re(suite, pattern, exclude_pattern,
2128
 
        random_order, False)
2129
 
 
2130
 
 
2131
 
def sort_suite_by_re(suite, pattern, exclude_pattern=None,
2132
 
                     random_order=False, append_rest=True):
2133
 
    """Create a test suite by sorting another one.
2134
 
    
2135
 
    :param suite:           the source suite
2136
 
    :param pattern:         pattern that names must match in order to go
2137
 
                            first in the new suite
2138
 
    :param exclude_pattern: pattern that names must not match, if any
2139
 
    :param random_order:    if True, tests in the new suite will be put in
2140
 
                            random order
2141
 
    :param append_rest:     if False, pattern is a strict filter and not
2142
 
                            just an ordering directive
2143
 
    :returns: the newly created suite
2144
 
    """ 
2145
 
    first = []
2146
 
    second = []
2147
 
    filter_re = re.compile(pattern)
2148
 
    if exclude_pattern is not None:
2149
 
        exclude_re = re.compile(exclude_pattern)
 
3149
    :returns: the newly created suite
 
3150
    """
 
3151
    condition = condition_id_re(pattern)
 
3152
    result_suite = filter_suite_by_condition(suite, condition)
 
3153
    return result_suite
 
3154
 
 
3155
 
 
3156
def filter_suite_by_id_list(suite, test_id_list):
 
3157
    """Create a test suite by filtering another one.
 
3158
 
 
3159
    :param suite: The source suite.
 
3160
    :param test_id_list: A list of the test ids to keep as strings.
 
3161
    :returns: the newly created suite
 
3162
    """
 
3163
    condition = condition_id_in_list(test_id_list)
 
3164
    result_suite = filter_suite_by_condition(suite, condition)
 
3165
    return result_suite
 
3166
 
 
3167
 
 
3168
def filter_suite_by_id_startswith(suite, start):
 
3169
    """Create a test suite by filtering another one.
 
3170
 
 
3171
    :param suite: The source suite.
 
3172
    :param start: A list of string the test id must start with one of.
 
3173
    :returns: the newly created suite
 
3174
    """
 
3175
    condition = condition_id_startswith(start)
 
3176
    result_suite = filter_suite_by_condition(suite, condition)
 
3177
    return result_suite
 
3178
 
 
3179
 
 
3180
def exclude_tests_by_re(suite, pattern):
 
3181
    """Create a test suite which excludes some tests from suite.
 
3182
 
 
3183
    :param suite: The suite to get tests from.
 
3184
    :param pattern: A regular expression string. Test ids that match this
 
3185
        pattern will be excluded from the result.
 
3186
    :return: A TestSuite that contains all the tests from suite without the
 
3187
        tests that matched pattern. The order of tests is the same as it was in
 
3188
        suite.
 
3189
    """
 
3190
    return exclude_tests_by_condition(suite, condition_id_re(pattern))
 
3191
 
 
3192
 
 
3193
def preserve_input(something):
 
3194
    """A helper for performing test suite transformation chains.
 
3195
 
 
3196
    :param something: Anything you want to preserve.
 
3197
    :return: Something.
 
3198
    """
 
3199
    return something
 
3200
 
 
3201
 
 
3202
def randomize_suite(suite):
 
3203
    """Return a new TestSuite with suite's tests in random order.
 
3204
 
 
3205
    The tests in the input suite are flattened into a single suite in order to
 
3206
    accomplish this. Any nested TestSuites are removed to provide global
 
3207
    randomness.
 
3208
    """
 
3209
    tests = list(iter_suite_tests(suite))
 
3210
    random.shuffle(tests)
 
3211
    return TestUtil.TestSuite(tests)
 
3212
 
 
3213
 
 
3214
def split_suite_by_condition(suite, condition):
 
3215
    """Split a test suite into two by a condition.
 
3216
 
 
3217
    :param suite: The suite to split.
 
3218
    :param condition: The condition to match on. Tests that match this
 
3219
        condition are returned in the first test suite, ones that do not match
 
3220
        are in the second suite.
 
3221
    :return: A tuple of two test suites, where the first contains tests from
 
3222
        suite matching the condition, and the second contains the remainder
 
3223
        from suite. The order within each output suite is the same as it was in
 
3224
        suite.
 
3225
    """
 
3226
    matched = []
 
3227
    did_not_match = []
2150
3228
    for test in iter_suite_tests(suite):
2151
 
        test_id = test.id()
2152
 
        if exclude_pattern is None or not exclude_re.search(test_id):
2153
 
            if filter_re.search(test_id):
2154
 
                first.append(test)
2155
 
            elif append_rest:
2156
 
                second.append(test)
2157
 
    if random_order:
2158
 
        random.shuffle(first)
2159
 
        random.shuffle(second)
2160
 
    return TestUtil.TestSuite(first + second)
 
3229
        if condition(test):
 
3230
            matched.append(test)
 
3231
        else:
 
3232
            did_not_match.append(test)
 
3233
    return TestUtil.TestSuite(matched), TestUtil.TestSuite(did_not_match)
 
3234
 
 
3235
 
 
3236
def split_suite_by_re(suite, pattern):
 
3237
    """Split a test suite into two by a regular expression.
 
3238
 
 
3239
    :param suite: The suite to split.
 
3240
    :param pattern: A regular expression string. Test ids that match this
 
3241
        pattern will be in the first test suite returned, and the others in the
 
3242
        second test suite returned.
 
3243
    :return: A tuple of two test suites, where the first contains tests from
 
3244
        suite matching pattern, and the second contains the remainder from
 
3245
        suite. The order within each output suite is the same as it was in
 
3246
        suite.
 
3247
    """
 
3248
    return split_suite_by_condition(suite, condition_id_re(pattern))
2161
3249
 
2162
3250
 
2163
3251
def run_suite(suite, name='test', verbose=False, pattern=".*",
2164
3252
              stop_on_failure=False,
2165
3253
              transport=None, lsprof_timed=None, bench_history=None,
2166
3254
              matching_tests_first=None,
2167
 
              numbered_dirs=None,
2168
3255
              list_only=False,
2169
3256
              random_seed=None,
2170
3257
              exclude_pattern=None,
 
3258
              strict=False,
 
3259
              runner_class=None,
 
3260
              suite_decorators=None,
 
3261
              stream=None,
 
3262
              result_decorators=None,
2171
3263
              ):
2172
 
    use_numbered_dirs = bool(numbered_dirs)
 
3264
    """Run a test suite for bzr selftest.
2173
3265
 
 
3266
    :param runner_class: The class of runner to use. Must support the
 
3267
        constructor arguments passed by run_suite which are more than standard
 
3268
        python uses.
 
3269
    :return: A boolean indicating success.
 
3270
    """
2174
3271
    TestCase._gather_lsprof_in_benchmarks = lsprof_timed
2175
 
    if numbered_dirs is not None:
2176
 
        TestCaseInTempDir.use_numbered_dirs = use_numbered_dirs
2177
3272
    if verbose:
2178
3273
        verbosity = 2
2179
3274
    else:
2180
3275
        verbosity = 1
2181
 
    runner = TextTestRunner(stream=sys.stdout,
 
3276
    if runner_class is None:
 
3277
        runner_class = TextTestRunner
 
3278
    if stream is None:
 
3279
        stream = sys.stdout
 
3280
    runner = runner_class(stream=stream,
2182
3281
                            descriptions=0,
2183
3282
                            verbosity=verbosity,
2184
3283
                            bench_history=bench_history,
2185
 
                            use_numbered_dirs=use_numbered_dirs,
2186
 
                            list_only=list_only,
 
3284
                            strict=strict,
 
3285
                            result_decorators=result_decorators,
2187
3286
                            )
2188
3287
    runner.stop_on_failure=stop_on_failure
2189
 
    # Initialise the random number generator and display the seed used.
2190
 
    # We convert the seed to a long to make it reuseable across invocations.
2191
 
    random_order = False
2192
 
    if random_seed is not None:
2193
 
        random_order = True
2194
 
        if random_seed == "now":
2195
 
            random_seed = long(time.time())
 
3288
    if isinstance(suite, unittest.TestSuite):
 
3289
        # Empty out _tests list of passed suite and populate new TestSuite
 
3290
        suite._tests[:], suite = [], TestSuite(suite)
 
3291
    # built in decorator factories:
 
3292
    decorators = [
 
3293
        random_order(random_seed, runner),
 
3294
        exclude_tests(exclude_pattern),
 
3295
        ]
 
3296
    if matching_tests_first:
 
3297
        decorators.append(tests_first(pattern))
 
3298
    else:
 
3299
        decorators.append(filter_tests(pattern))
 
3300
    if suite_decorators:
 
3301
        decorators.extend(suite_decorators)
 
3302
    # tell the result object how many tests will be running: (except if
 
3303
    # --parallel=fork is being used. Robert said he will provide a better
 
3304
    # progress design later -- vila 20090817)
 
3305
    if fork_decorator not in decorators:
 
3306
        decorators.append(CountingDecorator)
 
3307
    for decorator in decorators:
 
3308
        suite = decorator(suite)
 
3309
    if list_only:
 
3310
        # Done after test suite decoration to allow randomisation etc
 
3311
        # to take effect, though that is of marginal benefit.
 
3312
        if verbosity >= 2:
 
3313
            stream.write("Listing tests only ...\n")
 
3314
        for t in iter_suite_tests(suite):
 
3315
            stream.write("%s\n" % (t.id()))
 
3316
        return True
 
3317
    result = runner.run(suite)
 
3318
    if strict:
 
3319
        return result.wasStrictlySuccessful()
 
3320
    else:
 
3321
        return result.wasSuccessful()
 
3322
 
 
3323
 
 
3324
# A registry where get() returns a suite decorator.
 
3325
parallel_registry = registry.Registry()
 
3326
 
 
3327
 
 
3328
def fork_decorator(suite):
 
3329
    if getattr(os, "fork", None) is None:
 
3330
        raise errors.BzrCommandError("platform does not support fork,"
 
3331
            " try --parallel=subprocess instead.")
 
3332
    concurrency = osutils.local_concurrency()
 
3333
    if concurrency == 1:
 
3334
        return suite
 
3335
    from testtools import ConcurrentTestSuite
 
3336
    return ConcurrentTestSuite(suite, fork_for_tests)
 
3337
parallel_registry.register('fork', fork_decorator)
 
3338
 
 
3339
 
 
3340
def subprocess_decorator(suite):
 
3341
    concurrency = osutils.local_concurrency()
 
3342
    if concurrency == 1:
 
3343
        return suite
 
3344
    from testtools import ConcurrentTestSuite
 
3345
    return ConcurrentTestSuite(suite, reinvoke_for_tests)
 
3346
parallel_registry.register('subprocess', subprocess_decorator)
 
3347
 
 
3348
 
 
3349
def exclude_tests(exclude_pattern):
 
3350
    """Return a test suite decorator that excludes tests."""
 
3351
    if exclude_pattern is None:
 
3352
        return identity_decorator
 
3353
    def decorator(suite):
 
3354
        return ExcludeDecorator(suite, exclude_pattern)
 
3355
    return decorator
 
3356
 
 
3357
 
 
3358
def filter_tests(pattern):
 
3359
    if pattern == '.*':
 
3360
        return identity_decorator
 
3361
    def decorator(suite):
 
3362
        return FilterTestsDecorator(suite, pattern)
 
3363
    return decorator
 
3364
 
 
3365
 
 
3366
def random_order(random_seed, runner):
 
3367
    """Return a test suite decorator factory for randomising tests order.
 
3368
    
 
3369
    :param random_seed: now, a string which casts to a long, or a long.
 
3370
    :param runner: A test runner with a stream attribute to report on.
 
3371
    """
 
3372
    if random_seed is None:
 
3373
        return identity_decorator
 
3374
    def decorator(suite):
 
3375
        return RandomDecorator(suite, random_seed, runner.stream)
 
3376
    return decorator
 
3377
 
 
3378
 
 
3379
def tests_first(pattern):
 
3380
    if pattern == '.*':
 
3381
        return identity_decorator
 
3382
    def decorator(suite):
 
3383
        return TestFirstDecorator(suite, pattern)
 
3384
    return decorator
 
3385
 
 
3386
 
 
3387
def identity_decorator(suite):
 
3388
    """Return suite."""
 
3389
    return suite
 
3390
 
 
3391
 
 
3392
class TestDecorator(TestUtil.TestSuite):
 
3393
    """A decorator for TestCase/TestSuite objects.
 
3394
 
 
3395
    Contains rather than flattening suite passed on construction
 
3396
    """
 
3397
 
 
3398
    def __init__(self, suite=None):
 
3399
        super(TestDecorator, self).__init__()
 
3400
        if suite is not None:
 
3401
            self.addTest(suite)
 
3402
 
 
3403
    # Don't need subclass run method with suite emptying
 
3404
    run = unittest.TestSuite.run
 
3405
 
 
3406
 
 
3407
class CountingDecorator(TestDecorator):
 
3408
    """A decorator which calls result.progress(self.countTestCases)."""
 
3409
 
 
3410
    def run(self, result):
 
3411
        progress_method = getattr(result, 'progress', None)
 
3412
        if callable(progress_method):
 
3413
            progress_method(self.countTestCases(), SUBUNIT_SEEK_SET)
 
3414
        return super(CountingDecorator, self).run(result)
 
3415
 
 
3416
 
 
3417
class ExcludeDecorator(TestDecorator):
 
3418
    """A decorator which excludes test matching an exclude pattern."""
 
3419
 
 
3420
    def __init__(self, suite, exclude_pattern):
 
3421
        super(ExcludeDecorator, self).__init__(
 
3422
            exclude_tests_by_re(suite, exclude_pattern))
 
3423
 
 
3424
 
 
3425
class FilterTestsDecorator(TestDecorator):
 
3426
    """A decorator which filters tests to those matching a pattern."""
 
3427
 
 
3428
    def __init__(self, suite, pattern):
 
3429
        super(FilterTestsDecorator, self).__init__(
 
3430
            filter_suite_by_re(suite, pattern))
 
3431
 
 
3432
 
 
3433
class RandomDecorator(TestDecorator):
 
3434
    """A decorator which randomises the order of its tests."""
 
3435
 
 
3436
    def __init__(self, suite, random_seed, stream):
 
3437
        random_seed = self.actual_seed(random_seed)
 
3438
        stream.write("Randomizing test order using seed %s\n\n" %
 
3439
            (random_seed,))
 
3440
        # Initialise the random number generator.
 
3441
        random.seed(random_seed)
 
3442
        super(RandomDecorator, self).__init__(randomize_suite(suite))
 
3443
 
 
3444
    @staticmethod
 
3445
    def actual_seed(seed):
 
3446
        if seed == "now":
 
3447
            # We convert the seed to a long to make it reuseable across
 
3448
            # invocations (because the user can reenter it).
 
3449
            return long(time.time())
2196
3450
        else:
2197
3451
            # Convert the seed to a long if we can
2198
3452
            try:
2199
 
                random_seed = long(random_seed)
 
3453
                return long(seed)
 
3454
            except (TypeError, ValueError):
 
3455
                pass
 
3456
        return seed
 
3457
 
 
3458
 
 
3459
class TestFirstDecorator(TestDecorator):
 
3460
    """A decorator which moves named tests to the front."""
 
3461
 
 
3462
    def __init__(self, suite, pattern):
 
3463
        super(TestFirstDecorator, self).__init__()
 
3464
        self.addTests(split_suite_by_re(suite, pattern))
 
3465
 
 
3466
 
 
3467
def partition_tests(suite, count):
 
3468
    """Partition suite into count lists of tests."""
 
3469
    # This just assigns tests in a round-robin fashion.  On one hand this
 
3470
    # splits up blocks of related tests that might run faster if they shared
 
3471
    # resources, but on the other it avoids assigning blocks of slow tests to
 
3472
    # just one partition.  So the slowest partition shouldn't be much slower
 
3473
    # than the fastest.
 
3474
    partitions = [list() for i in range(count)]
 
3475
    tests = iter_suite_tests(suite)
 
3476
    for partition, test in itertools.izip(itertools.cycle(partitions), tests):
 
3477
        partition.append(test)
 
3478
    return partitions
 
3479
 
 
3480
 
 
3481
def workaround_zealous_crypto_random():
 
3482
    """Crypto.Random want to help us being secure, but we don't care here.
 
3483
 
 
3484
    This workaround some test failure related to the sftp server. Once paramiko
 
3485
    stop using the controversial API in Crypto.Random, we may get rid of it.
 
3486
    """
 
3487
    try:
 
3488
        from Crypto.Random import atfork
 
3489
        atfork()
 
3490
    except ImportError:
 
3491
        pass
 
3492
 
 
3493
 
 
3494
def fork_for_tests(suite):
 
3495
    """Take suite and start up one runner per CPU by forking()
 
3496
 
 
3497
    :return: An iterable of TestCase-like objects which can each have
 
3498
        run(result) called on them to feed tests to result.
 
3499
    """
 
3500
    concurrency = osutils.local_concurrency()
 
3501
    result = []
 
3502
    from subunit import ProtocolTestCase
 
3503
    from subunit.test_results import AutoTimingTestResultDecorator
 
3504
    class TestInOtherProcess(ProtocolTestCase):
 
3505
        # Should be in subunit, I think. RBC.
 
3506
        def __init__(self, stream, pid):
 
3507
            ProtocolTestCase.__init__(self, stream)
 
3508
            self.pid = pid
 
3509
 
 
3510
        def run(self, result):
 
3511
            try:
 
3512
                ProtocolTestCase.run(self, result)
 
3513
            finally:
 
3514
                pid, status = os.waitpid(self.pid, 0)
 
3515
            # GZ 2011-10-18: If status is nonzero, should report to the result
 
3516
            #                that something went wrong.
 
3517
 
 
3518
    test_blocks = partition_tests(suite, concurrency)
 
3519
    # Clear the tests from the original suite so it doesn't keep them alive
 
3520
    suite._tests[:] = []
 
3521
    for process_tests in test_blocks:
 
3522
        process_suite = TestUtil.TestSuite(process_tests)
 
3523
        # Also clear each split list so new suite has only reference
 
3524
        process_tests[:] = []
 
3525
        c2pread, c2pwrite = os.pipe()
 
3526
        pid = os.fork()
 
3527
        if pid == 0:
 
3528
            try:
 
3529
                stream = os.fdopen(c2pwrite, 'wb', 1)
 
3530
                workaround_zealous_crypto_random()
 
3531
                os.close(c2pread)
 
3532
                # Leave stderr and stdout open so we can see test noise
 
3533
                # Close stdin so that the child goes away if it decides to
 
3534
                # read from stdin (otherwise its a roulette to see what
 
3535
                # child actually gets keystrokes for pdb etc).
 
3536
                sys.stdin.close()
 
3537
                subunit_result = AutoTimingTestResultDecorator(
 
3538
                    SubUnitBzrProtocolClient(stream))
 
3539
                process_suite.run(subunit_result)
2200
3540
            except:
2201
 
                pass
2202
 
        runner.stream.writeln("Randomizing test order using seed %s\n" %
2203
 
            (random_seed))
2204
 
        random.seed(random_seed)
2205
 
    # Customise the list of tests if requested
2206
 
    if pattern != '.*' or exclude_pattern is not None or random_order:
2207
 
        if matching_tests_first:
2208
 
            suite = sort_suite_by_re(suite, pattern, exclude_pattern,
2209
 
                random_order)
 
3541
                # Try and report traceback on stream, but exit with error even
 
3542
                # if stream couldn't be created or something else goes wrong.
 
3543
                # The traceback is formatted to a string and written in one go
 
3544
                # to avoid interleaving lines from multiple failing children.
 
3545
                try:
 
3546
                    stream.write(traceback.format_exc())
 
3547
                finally:
 
3548
                    os._exit(1)
 
3549
            os._exit(0)
2210
3550
        else:
2211
 
            suite = filter_suite_by_re(suite, pattern, exclude_pattern,
2212
 
                random_order)
2213
 
    result = runner.run(suite)
2214
 
    return result.wasSuccessful()
 
3551
            os.close(c2pwrite)
 
3552
            stream = os.fdopen(c2pread, 'rb', 1)
 
3553
            test = TestInOtherProcess(stream, pid)
 
3554
            result.append(test)
 
3555
    return result
 
3556
 
 
3557
 
 
3558
def reinvoke_for_tests(suite):
 
3559
    """Take suite and start up one runner per CPU using subprocess().
 
3560
 
 
3561
    :return: An iterable of TestCase-like objects which can each have
 
3562
        run(result) called on them to feed tests to result.
 
3563
    """
 
3564
    concurrency = osutils.local_concurrency()
 
3565
    result = []
 
3566
    from subunit import ProtocolTestCase
 
3567
    class TestInSubprocess(ProtocolTestCase):
 
3568
        def __init__(self, process, name):
 
3569
            ProtocolTestCase.__init__(self, process.stdout)
 
3570
            self.process = process
 
3571
            self.process.stdin.close()
 
3572
            self.name = name
 
3573
 
 
3574
        def run(self, result):
 
3575
            try:
 
3576
                ProtocolTestCase.run(self, result)
 
3577
            finally:
 
3578
                self.process.wait()
 
3579
                os.unlink(self.name)
 
3580
            # print "pid %d finished" % finished_process
 
3581
    test_blocks = partition_tests(suite, concurrency)
 
3582
    for process_tests in test_blocks:
 
3583
        # ugly; currently reimplement rather than reuses TestCase methods.
 
3584
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
 
3585
        if not os.path.isfile(bzr_path):
 
3586
            # We are probably installed. Assume sys.argv is the right file
 
3587
            bzr_path = sys.argv[0]
 
3588
        bzr_path = [bzr_path]
 
3589
        if sys.platform == "win32":
 
3590
            # if we're on windows, we can't execute the bzr script directly
 
3591
            bzr_path = [sys.executable] + bzr_path
 
3592
        fd, test_list_file_name = tempfile.mkstemp()
 
3593
        test_list_file = os.fdopen(fd, 'wb', 1)
 
3594
        for test in process_tests:
 
3595
            test_list_file.write(test.id() + '\n')
 
3596
        test_list_file.close()
 
3597
        try:
 
3598
            argv = bzr_path + ['selftest', '--load-list', test_list_file_name,
 
3599
                '--subunit']
 
3600
            if '--no-plugins' in sys.argv:
 
3601
                argv.append('--no-plugins')
 
3602
            # stderr=subprocess.STDOUT would be ideal, but until we prevent
 
3603
            # noise on stderr it can interrupt the subunit protocol.
 
3604
            process = subprocess.Popen(argv, stdin=subprocess.PIPE,
 
3605
                                      stdout=subprocess.PIPE,
 
3606
                                      stderr=subprocess.PIPE,
 
3607
                                      bufsize=1)
 
3608
            test = TestInSubprocess(process, test_list_file_name)
 
3609
            result.append(test)
 
3610
        except:
 
3611
            os.unlink(test_list_file_name)
 
3612
            raise
 
3613
    return result
 
3614
 
 
3615
 
 
3616
class ProfileResult(testtools.ExtendedToOriginalDecorator):
 
3617
    """Generate profiling data for all activity between start and success.
 
3618
    
 
3619
    The profile data is appended to the test's _benchcalls attribute and can
 
3620
    be accessed by the forwarded-to TestResult.
 
3621
 
 
3622
    While it might be cleaner do accumulate this in stopTest, addSuccess is
 
3623
    where our existing output support for lsprof is, and this class aims to
 
3624
    fit in with that: while it could be moved it's not necessary to accomplish
 
3625
    test profiling, nor would it be dramatically cleaner.
 
3626
    """
 
3627
 
 
3628
    def startTest(self, test):
 
3629
        self.profiler = bzrlib.lsprof.BzrProfiler()
 
3630
        # Prevent deadlocks in tests that use lsprof: those tests will
 
3631
        # unavoidably fail.
 
3632
        bzrlib.lsprof.BzrProfiler.profiler_block = 0
 
3633
        self.profiler.start()
 
3634
        testtools.ExtendedToOriginalDecorator.startTest(self, test)
 
3635
 
 
3636
    def addSuccess(self, test):
 
3637
        stats = self.profiler.stop()
 
3638
        try:
 
3639
            calls = test._benchcalls
 
3640
        except AttributeError:
 
3641
            test._benchcalls = []
 
3642
            calls = test._benchcalls
 
3643
        calls.append(((test.id(), "", ""), stats))
 
3644
        testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
 
3645
 
 
3646
    def stopTest(self, test):
 
3647
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
 
3648
        self.profiler = None
 
3649
 
 
3650
 
 
3651
# Controlled by "bzr selftest -E=..." option
 
3652
# Currently supported:
 
3653
#   -Eallow_debug           Will no longer clear debug.debug_flags() so it
 
3654
#                           preserves any flags supplied at the command line.
 
3655
#   -Edisable_lock_checks   Turns errors in mismatched locks into simple prints
 
3656
#                           rather than failing tests. And no longer raise
 
3657
#                           LockContention when fctnl locks are not being used
 
3658
#                           with proper exclusion rules.
 
3659
#   -Ethreads               Will display thread ident at creation/join time to
 
3660
#                           help track thread leaks
 
3661
#   -Euncollected_cases     Display the identity of any test cases that weren't
 
3662
#                           deallocated after being completed.
 
3663
#   -Econfig_stats          Will collect statistics using addDetail
 
3664
selftest_debug_flags = set()
2215
3665
 
2216
3666
 
2217
3667
def selftest(verbose=False, pattern=".*", stop_on_failure=True,
2220
3670
             lsprof_timed=None,
2221
3671
             bench_history=None,
2222
3672
             matching_tests_first=None,
2223
 
             numbered_dirs=None,
2224
3673
             list_only=False,
2225
3674
             random_seed=None,
2226
 
             exclude_pattern=None):
 
3675
             exclude_pattern=None,
 
3676
             strict=False,
 
3677
             load_list=None,
 
3678
             debug_flags=None,
 
3679
             starting_with=None,
 
3680
             runner_class=None,
 
3681
             suite_decorators=None,
 
3682
             stream=None,
 
3683
             lsprof_tests=False,
 
3684
             ):
2227
3685
    """Run the whole test suite under the enhanced runner"""
2228
3686
    # XXX: Very ugly way to do this...
2229
3687
    # Disable warning about old formats because we don't want it to disturb
2236
3694
        transport = default_transport
2237
3695
    old_transport = default_transport
2238
3696
    default_transport = transport
 
3697
    global selftest_debug_flags
 
3698
    old_debug_flags = selftest_debug_flags
 
3699
    if debug_flags is not None:
 
3700
        selftest_debug_flags = set(debug_flags)
2239
3701
    try:
 
3702
        if load_list is None:
 
3703
            keep_only = None
 
3704
        else:
 
3705
            keep_only = load_test_id_list(load_list)
 
3706
        if starting_with:
 
3707
            starting_with = [test_prefix_alias_registry.resolve_alias(start)
 
3708
                             for start in starting_with]
2240
3709
        if test_suite_factory is None:
2241
 
            suite = test_suite()
 
3710
            # Reduce loading time by loading modules based on the starting_with
 
3711
            # patterns.
 
3712
            suite = test_suite(keep_only, starting_with)
2242
3713
        else:
2243
3714
            suite = test_suite_factory()
 
3715
        if starting_with:
 
3716
            # But always filter as requested.
 
3717
            suite = filter_suite_by_id_startswith(suite, starting_with)
 
3718
        result_decorators = []
 
3719
        if lsprof_tests:
 
3720
            result_decorators.append(ProfileResult)
2244
3721
        return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
2245
3722
                     stop_on_failure=stop_on_failure,
2246
3723
                     transport=transport,
2247
3724
                     lsprof_timed=lsprof_timed,
2248
3725
                     bench_history=bench_history,
2249
3726
                     matching_tests_first=matching_tests_first,
2250
 
                     numbered_dirs=numbered_dirs,
2251
3727
                     list_only=list_only,
2252
3728
                     random_seed=random_seed,
2253
 
                     exclude_pattern=exclude_pattern)
 
3729
                     exclude_pattern=exclude_pattern,
 
3730
                     strict=strict,
 
3731
                     runner_class=runner_class,
 
3732
                     suite_decorators=suite_decorators,
 
3733
                     stream=stream,
 
3734
                     result_decorators=result_decorators,
 
3735
                     )
2254
3736
    finally:
2255
3737
        default_transport = old_transport
2256
 
 
2257
 
 
2258
 
def test_suite():
 
3738
        selftest_debug_flags = old_debug_flags
 
3739
 
 
3740
 
 
3741
def load_test_id_list(file_name):
 
3742
    """Load a test id list from a text file.
 
3743
 
 
3744
    The format is one test id by line.  No special care is taken to impose
 
3745
    strict rules, these test ids are used to filter the test suite so a test id
 
3746
    that do not match an existing test will do no harm. This allows user to add
 
3747
    comments, leave blank lines, etc.
 
3748
    """
 
3749
    test_list = []
 
3750
    try:
 
3751
        ftest = open(file_name, 'rt')
 
3752
    except IOError, e:
 
3753
        if e.errno != errno.ENOENT:
 
3754
            raise
 
3755
        else:
 
3756
            raise errors.NoSuchFile(file_name)
 
3757
 
 
3758
    for test_name in ftest.readlines():
 
3759
        test_list.append(test_name.strip())
 
3760
    ftest.close()
 
3761
    return test_list
 
3762
 
 
3763
 
 
3764
def suite_matches_id_list(test_suite, id_list):
 
3765
    """Warns about tests not appearing or appearing more than once.
 
3766
 
 
3767
    :param test_suite: A TestSuite object.
 
3768
    :param test_id_list: The list of test ids that should be found in
 
3769
         test_suite.
 
3770
 
 
3771
    :return: (absents, duplicates) absents is a list containing the test found
 
3772
        in id_list but not in test_suite, duplicates is a list containing the
 
3773
        test found multiple times in test_suite.
 
3774
 
 
3775
    When using a prefined test id list, it may occurs that some tests do not
 
3776
    exist anymore or that some tests use the same id. This function warns the
 
3777
    tester about potential problems in his workflow (test lists are volatile)
 
3778
    or in the test suite itself (using the same id for several tests does not
 
3779
    help to localize defects).
 
3780
    """
 
3781
    # Build a dict counting id occurrences
 
3782
    tests = dict()
 
3783
    for test in iter_suite_tests(test_suite):
 
3784
        id = test.id()
 
3785
        tests[id] = tests.get(id, 0) + 1
 
3786
 
 
3787
    not_found = []
 
3788
    duplicates = []
 
3789
    for id in id_list:
 
3790
        occurs = tests.get(id, 0)
 
3791
        if not occurs:
 
3792
            not_found.append(id)
 
3793
        elif occurs > 1:
 
3794
            duplicates.append(id)
 
3795
 
 
3796
    return not_found, duplicates
 
3797
 
 
3798
 
 
3799
class TestIdList(object):
 
3800
    """Test id list to filter a test suite.
 
3801
 
 
3802
    Relying on the assumption that test ids are built as:
 
3803
    <module>[.<class>.<method>][(<param>+)], <module> being in python dotted
 
3804
    notation, this class offers methods to :
 
3805
    - avoid building a test suite for modules not refered to in the test list,
 
3806
    - keep only the tests listed from the module test suite.
 
3807
    """
 
3808
 
 
3809
    def __init__(self, test_id_list):
 
3810
        # When a test suite needs to be filtered against us we compare test ids
 
3811
        # for equality, so a simple dict offers a quick and simple solution.
 
3812
        self.tests = dict().fromkeys(test_id_list, True)
 
3813
 
 
3814
        # While unittest.TestCase have ids like:
 
3815
        # <module>.<class>.<method>[(<param+)],
 
3816
        # doctest.DocTestCase can have ids like:
 
3817
        # <module>
 
3818
        # <module>.<class>
 
3819
        # <module>.<function>
 
3820
        # <module>.<class>.<method>
 
3821
 
 
3822
        # Since we can't predict a test class from its name only, we settle on
 
3823
        # a simple constraint: a test id always begins with its module name.
 
3824
 
 
3825
        modules = {}
 
3826
        for test_id in test_id_list:
 
3827
            parts = test_id.split('.')
 
3828
            mod_name = parts.pop(0)
 
3829
            modules[mod_name] = True
 
3830
            for part in parts:
 
3831
                mod_name += '.' + part
 
3832
                modules[mod_name] = True
 
3833
        self.modules = modules
 
3834
 
 
3835
    def refers_to(self, module_name):
 
3836
        """Is there tests for the module or one of its sub modules."""
 
3837
        return self.modules.has_key(module_name)
 
3838
 
 
3839
    def includes(self, test_id):
 
3840
        return self.tests.has_key(test_id)
 
3841
 
 
3842
 
 
3843
class TestPrefixAliasRegistry(registry.Registry):
 
3844
    """A registry for test prefix aliases.
 
3845
 
 
3846
    This helps implement shorcuts for the --starting-with selftest
 
3847
    option. Overriding existing prefixes is not allowed but not fatal (a
 
3848
    warning will be emitted).
 
3849
    """
 
3850
 
 
3851
    def register(self, key, obj, help=None, info=None,
 
3852
                 override_existing=False):
 
3853
        """See Registry.register.
 
3854
 
 
3855
        Trying to override an existing alias causes a warning to be emitted,
 
3856
        not a fatal execption.
 
3857
        """
 
3858
        try:
 
3859
            super(TestPrefixAliasRegistry, self).register(
 
3860
                key, obj, help=help, info=info, override_existing=False)
 
3861
        except KeyError:
 
3862
            actual = self.get(key)
 
3863
            trace.note(
 
3864
                'Test prefix alias %s is already used for %s, ignoring %s'
 
3865
                % (key, actual, obj))
 
3866
 
 
3867
    def resolve_alias(self, id_start):
 
3868
        """Replace the alias by the prefix in the given string.
 
3869
 
 
3870
        Using an unknown prefix is an error to help catching typos.
 
3871
        """
 
3872
        parts = id_start.split('.')
 
3873
        try:
 
3874
            parts[0] = self.get(parts[0])
 
3875
        except KeyError:
 
3876
            raise errors.BzrCommandError(
 
3877
                '%s is not a known test prefix alias' % parts[0])
 
3878
        return '.'.join(parts)
 
3879
 
 
3880
 
 
3881
test_prefix_alias_registry = TestPrefixAliasRegistry()
 
3882
"""Registry of test prefix aliases."""
 
3883
 
 
3884
 
 
3885
# This alias allows to detect typos ('bzrlin.') by making all valid test ids
 
3886
# appear prefixed ('bzrlib.' is "replaced" by 'bzrlib.').
 
3887
test_prefix_alias_registry.register('bzrlib', 'bzrlib')
 
3888
 
 
3889
# Obvious highest levels prefixes, feel free to add your own via a plugin
 
3890
test_prefix_alias_registry.register('bd', 'bzrlib.doc')
 
3891
test_prefix_alias_registry.register('bu', 'bzrlib.utils')
 
3892
test_prefix_alias_registry.register('bt', 'bzrlib.tests')
 
3893
test_prefix_alias_registry.register('bb', 'bzrlib.tests.blackbox')
 
3894
test_prefix_alias_registry.register('bp', 'bzrlib.plugins')
 
3895
 
 
3896
 
 
3897
def _test_suite_testmod_names():
 
3898
    """Return the standard list of test module names to test."""
 
3899
    return [
 
3900
        'bzrlib.doc',
 
3901
        'bzrlib.tests.blackbox',
 
3902
        'bzrlib.tests.commands',
 
3903
        'bzrlib.tests.doc_generate',
 
3904
        'bzrlib.tests.per_branch',
 
3905
        'bzrlib.tests.per_bzrdir',
 
3906
        'bzrlib.tests.per_controldir',
 
3907
        'bzrlib.tests.per_controldir_colo',
 
3908
        'bzrlib.tests.per_foreign_vcs',
 
3909
        'bzrlib.tests.per_interrepository',
 
3910
        'bzrlib.tests.per_intertree',
 
3911
        'bzrlib.tests.per_inventory',
 
3912
        'bzrlib.tests.per_interbranch',
 
3913
        'bzrlib.tests.per_lock',
 
3914
        'bzrlib.tests.per_merger',
 
3915
        'bzrlib.tests.per_transport',
 
3916
        'bzrlib.tests.per_tree',
 
3917
        'bzrlib.tests.per_pack_repository',
 
3918
        'bzrlib.tests.per_repository',
 
3919
        'bzrlib.tests.per_repository_chk',
 
3920
        'bzrlib.tests.per_repository_reference',
 
3921
        'bzrlib.tests.per_repository_vf',
 
3922
        'bzrlib.tests.per_uifactory',
 
3923
        'bzrlib.tests.per_versionedfile',
 
3924
        'bzrlib.tests.per_workingtree',
 
3925
        'bzrlib.tests.test__annotator',
 
3926
        'bzrlib.tests.test__bencode',
 
3927
        'bzrlib.tests.test__btree_serializer',
 
3928
        'bzrlib.tests.test__chk_map',
 
3929
        'bzrlib.tests.test__dirstate_helpers',
 
3930
        'bzrlib.tests.test__groupcompress',
 
3931
        'bzrlib.tests.test__known_graph',
 
3932
        'bzrlib.tests.test__rio',
 
3933
        'bzrlib.tests.test__simple_set',
 
3934
        'bzrlib.tests.test__static_tuple',
 
3935
        'bzrlib.tests.test__walkdirs_win32',
 
3936
        'bzrlib.tests.test_ancestry',
 
3937
        'bzrlib.tests.test_annotate',
 
3938
        'bzrlib.tests.test_api',
 
3939
        'bzrlib.tests.test_atomicfile',
 
3940
        'bzrlib.tests.test_bad_files',
 
3941
        'bzrlib.tests.test_bisect_multi',
 
3942
        'bzrlib.tests.test_branch',
 
3943
        'bzrlib.tests.test_branchbuilder',
 
3944
        'bzrlib.tests.test_btree_index',
 
3945
        'bzrlib.tests.test_bugtracker',
 
3946
        'bzrlib.tests.test_bundle',
 
3947
        'bzrlib.tests.test_bzrdir',
 
3948
        'bzrlib.tests.test__chunks_to_lines',
 
3949
        'bzrlib.tests.test_cache_utf8',
 
3950
        'bzrlib.tests.test_chk_map',
 
3951
        'bzrlib.tests.test_chk_serializer',
 
3952
        'bzrlib.tests.test_chunk_writer',
 
3953
        'bzrlib.tests.test_clean_tree',
 
3954
        'bzrlib.tests.test_cleanup',
 
3955
        'bzrlib.tests.test_cmdline',
 
3956
        'bzrlib.tests.test_commands',
 
3957
        'bzrlib.tests.test_commit',
 
3958
        'bzrlib.tests.test_commit_merge',
 
3959
        'bzrlib.tests.test_config',
 
3960
        'bzrlib.tests.test_conflicts',
 
3961
        'bzrlib.tests.test_controldir',
 
3962
        'bzrlib.tests.test_counted_lock',
 
3963
        'bzrlib.tests.test_crash',
 
3964
        'bzrlib.tests.test_decorators',
 
3965
        'bzrlib.tests.test_delta',
 
3966
        'bzrlib.tests.test_debug',
 
3967
        'bzrlib.tests.test_diff',
 
3968
        'bzrlib.tests.test_directory_service',
 
3969
        'bzrlib.tests.test_dirstate',
 
3970
        'bzrlib.tests.test_email_message',
 
3971
        'bzrlib.tests.test_eol_filters',
 
3972
        'bzrlib.tests.test_errors',
 
3973
        'bzrlib.tests.test_estimate_compressed_size',
 
3974
        'bzrlib.tests.test_export',
 
3975
        'bzrlib.tests.test_export_pot',
 
3976
        'bzrlib.tests.test_extract',
 
3977
        'bzrlib.tests.test_features',
 
3978
        'bzrlib.tests.test_fetch',
 
3979
        'bzrlib.tests.test_fixtures',
 
3980
        'bzrlib.tests.test_fifo_cache',
 
3981
        'bzrlib.tests.test_filters',
 
3982
        'bzrlib.tests.test_filter_tree',
 
3983
        'bzrlib.tests.test_ftp_transport',
 
3984
        'bzrlib.tests.test_foreign',
 
3985
        'bzrlib.tests.test_generate_docs',
 
3986
        'bzrlib.tests.test_generate_ids',
 
3987
        'bzrlib.tests.test_globbing',
 
3988
        'bzrlib.tests.test_gpg',
 
3989
        'bzrlib.tests.test_graph',
 
3990
        'bzrlib.tests.test_groupcompress',
 
3991
        'bzrlib.tests.test_hashcache',
 
3992
        'bzrlib.tests.test_help',
 
3993
        'bzrlib.tests.test_hooks',
 
3994
        'bzrlib.tests.test_http',
 
3995
        'bzrlib.tests.test_http_response',
 
3996
        'bzrlib.tests.test_https_ca_bundle',
 
3997
        'bzrlib.tests.test_i18n',
 
3998
        'bzrlib.tests.test_identitymap',
 
3999
        'bzrlib.tests.test_ignores',
 
4000
        'bzrlib.tests.test_index',
 
4001
        'bzrlib.tests.test_import_tariff',
 
4002
        'bzrlib.tests.test_info',
 
4003
        'bzrlib.tests.test_inv',
 
4004
        'bzrlib.tests.test_inventory_delta',
 
4005
        'bzrlib.tests.test_knit',
 
4006
        'bzrlib.tests.test_lazy_import',
 
4007
        'bzrlib.tests.test_lazy_regex',
 
4008
        'bzrlib.tests.test_library_state',
 
4009
        'bzrlib.tests.test_lock',
 
4010
        'bzrlib.tests.test_lockable_files',
 
4011
        'bzrlib.tests.test_lockdir',
 
4012
        'bzrlib.tests.test_log',
 
4013
        'bzrlib.tests.test_lru_cache',
 
4014
        'bzrlib.tests.test_lsprof',
 
4015
        'bzrlib.tests.test_mail_client',
 
4016
        'bzrlib.tests.test_matchers',
 
4017
        'bzrlib.tests.test_memorytree',
 
4018
        'bzrlib.tests.test_merge',
 
4019
        'bzrlib.tests.test_merge3',
 
4020
        'bzrlib.tests.test_merge_core',
 
4021
        'bzrlib.tests.test_merge_directive',
 
4022
        'bzrlib.tests.test_mergetools',
 
4023
        'bzrlib.tests.test_missing',
 
4024
        'bzrlib.tests.test_msgeditor',
 
4025
        'bzrlib.tests.test_multiparent',
 
4026
        'bzrlib.tests.test_mutabletree',
 
4027
        'bzrlib.tests.test_nonascii',
 
4028
        'bzrlib.tests.test_options',
 
4029
        'bzrlib.tests.test_osutils',
 
4030
        'bzrlib.tests.test_osutils_encodings',
 
4031
        'bzrlib.tests.test_pack',
 
4032
        'bzrlib.tests.test_patch',
 
4033
        'bzrlib.tests.test_patches',
 
4034
        'bzrlib.tests.test_permissions',
 
4035
        'bzrlib.tests.test_plugins',
 
4036
        'bzrlib.tests.test_progress',
 
4037
        'bzrlib.tests.test_pyutils',
 
4038
        'bzrlib.tests.test_read_bundle',
 
4039
        'bzrlib.tests.test_reconcile',
 
4040
        'bzrlib.tests.test_reconfigure',
 
4041
        'bzrlib.tests.test_registry',
 
4042
        'bzrlib.tests.test_remote',
 
4043
        'bzrlib.tests.test_rename_map',
 
4044
        'bzrlib.tests.test_repository',
 
4045
        'bzrlib.tests.test_revert',
 
4046
        'bzrlib.tests.test_revision',
 
4047
        'bzrlib.tests.test_revisionspec',
 
4048
        'bzrlib.tests.test_revisiontree',
 
4049
        'bzrlib.tests.test_rio',
 
4050
        'bzrlib.tests.test_rules',
 
4051
        'bzrlib.tests.test_sampler',
 
4052
        'bzrlib.tests.test_scenarios',
 
4053
        'bzrlib.tests.test_script',
 
4054
        'bzrlib.tests.test_selftest',
 
4055
        'bzrlib.tests.test_serializer',
 
4056
        'bzrlib.tests.test_setup',
 
4057
        'bzrlib.tests.test_sftp_transport',
 
4058
        'bzrlib.tests.test_shelf',
 
4059
        'bzrlib.tests.test_shelf_ui',
 
4060
        'bzrlib.tests.test_smart',
 
4061
        'bzrlib.tests.test_smart_add',
 
4062
        'bzrlib.tests.test_smart_request',
 
4063
        'bzrlib.tests.test_smart_signals',
 
4064
        'bzrlib.tests.test_smart_transport',
 
4065
        'bzrlib.tests.test_smtp_connection',
 
4066
        'bzrlib.tests.test_source',
 
4067
        'bzrlib.tests.test_ssh_transport',
 
4068
        'bzrlib.tests.test_status',
 
4069
        'bzrlib.tests.test_store',
 
4070
        'bzrlib.tests.test_strace',
 
4071
        'bzrlib.tests.test_subsume',
 
4072
        'bzrlib.tests.test_switch',
 
4073
        'bzrlib.tests.test_symbol_versioning',
 
4074
        'bzrlib.tests.test_tag',
 
4075
        'bzrlib.tests.test_test_server',
 
4076
        'bzrlib.tests.test_testament',
 
4077
        'bzrlib.tests.test_textfile',
 
4078
        'bzrlib.tests.test_textmerge',
 
4079
        'bzrlib.tests.test_cethread',
 
4080
        'bzrlib.tests.test_timestamp',
 
4081
        'bzrlib.tests.test_trace',
 
4082
        'bzrlib.tests.test_transactions',
 
4083
        'bzrlib.tests.test_transform',
 
4084
        'bzrlib.tests.test_transport',
 
4085
        'bzrlib.tests.test_transport_log',
 
4086
        'bzrlib.tests.test_tree',
 
4087
        'bzrlib.tests.test_treebuilder',
 
4088
        'bzrlib.tests.test_treeshape',
 
4089
        'bzrlib.tests.test_tsort',
 
4090
        'bzrlib.tests.test_tuned_gzip',
 
4091
        'bzrlib.tests.test_ui',
 
4092
        'bzrlib.tests.test_uncommit',
 
4093
        'bzrlib.tests.test_upgrade',
 
4094
        'bzrlib.tests.test_upgrade_stacked',
 
4095
        'bzrlib.tests.test_urlutils',
 
4096
        'bzrlib.tests.test_utextwrap',
 
4097
        'bzrlib.tests.test_version',
 
4098
        'bzrlib.tests.test_version_info',
 
4099
        'bzrlib.tests.test_versionedfile',
 
4100
        'bzrlib.tests.test_vf_search',
 
4101
        'bzrlib.tests.test_weave',
 
4102
        'bzrlib.tests.test_whitebox',
 
4103
        'bzrlib.tests.test_win32utils',
 
4104
        'bzrlib.tests.test_workingtree',
 
4105
        'bzrlib.tests.test_workingtree_4',
 
4106
        'bzrlib.tests.test_wsgi',
 
4107
        'bzrlib.tests.test_xml',
 
4108
        ]
 
4109
 
 
4110
 
 
4111
def _test_suite_modules_to_doctest():
 
4112
    """Return the list of modules to doctest."""
 
4113
    if __doc__ is None:
 
4114
        # GZ 2009-03-31: No docstrings with -OO so there's nothing to doctest
 
4115
        return []
 
4116
    return [
 
4117
        'bzrlib',
 
4118
        'bzrlib.branchbuilder',
 
4119
        'bzrlib.decorators',
 
4120
        'bzrlib.inventory',
 
4121
        'bzrlib.iterablefile',
 
4122
        'bzrlib.lockdir',
 
4123
        'bzrlib.merge3',
 
4124
        'bzrlib.option',
 
4125
        'bzrlib.pyutils',
 
4126
        'bzrlib.symbol_versioning',
 
4127
        'bzrlib.tests',
 
4128
        'bzrlib.tests.fixtures',
 
4129
        'bzrlib.timestamp',
 
4130
        'bzrlib.transport.http',
 
4131
        'bzrlib.version_info_formats.format_custom',
 
4132
        ]
 
4133
 
 
4134
 
 
4135
def test_suite(keep_only=None, starting_with=None):
2259
4136
    """Build and return TestSuite for the whole of bzrlib.
2260
 
    
 
4137
 
 
4138
    :param keep_only: A list of test ids limiting the suite returned.
 
4139
 
 
4140
    :param starting_with: An id limiting the suite returned to the tests
 
4141
         starting with it.
 
4142
 
2261
4143
    This function can be replaced if you need to change the default test
2262
4144
    suite on a global basis, but it is not encouraged.
2263
4145
    """
2264
 
    testmod_names = [
2265
 
                   'bzrlib.tests.test_ancestry',
2266
 
                   'bzrlib.tests.test_annotate',
2267
 
                   'bzrlib.tests.test_api',
2268
 
                   'bzrlib.tests.test_atomicfile',
2269
 
                   'bzrlib.tests.test_bad_files',
2270
 
                   'bzrlib.tests.test_branch',
2271
 
                   'bzrlib.tests.test_branchbuilder',
2272
 
                   'bzrlib.tests.test_bugtracker',
2273
 
                   'bzrlib.tests.test_bundle',
2274
 
                   'bzrlib.tests.test_bzrdir',
2275
 
                   'bzrlib.tests.test_cache_utf8',
2276
 
                   'bzrlib.tests.test_commands',
2277
 
                   'bzrlib.tests.test_commit',
2278
 
                   'bzrlib.tests.test_commit_merge',
2279
 
                   'bzrlib.tests.test_config',
2280
 
                   'bzrlib.tests.test_conflicts',
2281
 
                   'bzrlib.tests.test_counted_lock',
2282
 
                   'bzrlib.tests.test_decorators',
2283
 
                   'bzrlib.tests.test_delta',
2284
 
                   'bzrlib.tests.test_deprecated_graph',
2285
 
                   'bzrlib.tests.test_diff',
2286
 
                   'bzrlib.tests.test_dirstate',
2287
 
                   'bzrlib.tests.test_errors',
2288
 
                   'bzrlib.tests.test_escaped_store',
2289
 
                   'bzrlib.tests.test_extract',
2290
 
                   'bzrlib.tests.test_fetch',
2291
 
                   'bzrlib.tests.test_ftp_transport',
2292
 
                   'bzrlib.tests.test_generate_docs',
2293
 
                   'bzrlib.tests.test_generate_ids',
2294
 
                   'bzrlib.tests.test_globbing',
2295
 
                   'bzrlib.tests.test_gpg',
2296
 
                   'bzrlib.tests.test_graph',
2297
 
                   'bzrlib.tests.test_hashcache',
2298
 
                   'bzrlib.tests.test_help',
2299
 
                   'bzrlib.tests.test_hooks',
2300
 
                   'bzrlib.tests.test_http',
2301
 
                   'bzrlib.tests.test_http_response',
2302
 
                   'bzrlib.tests.test_https_ca_bundle',
2303
 
                   'bzrlib.tests.test_identitymap',
2304
 
                   'bzrlib.tests.test_ignores',
2305
 
                   'bzrlib.tests.test_info',
2306
 
                   'bzrlib.tests.test_inv',
2307
 
                   'bzrlib.tests.test_knit',
2308
 
                   'bzrlib.tests.test_lazy_import',
2309
 
                   'bzrlib.tests.test_lazy_regex',
2310
 
                   'bzrlib.tests.test_lockdir',
2311
 
                   'bzrlib.tests.test_lockable_files',
2312
 
                   'bzrlib.tests.test_log',
2313
 
                   'bzrlib.tests.test_lsprof',
2314
 
                   'bzrlib.tests.test_memorytree',
2315
 
                   'bzrlib.tests.test_merge',
2316
 
                   'bzrlib.tests.test_merge3',
2317
 
                   'bzrlib.tests.test_merge_core',
2318
 
                   'bzrlib.tests.test_merge_directive',
2319
 
                   'bzrlib.tests.test_missing',
2320
 
                   'bzrlib.tests.test_msgeditor',
2321
 
                   'bzrlib.tests.test_nonascii',
2322
 
                   'bzrlib.tests.test_options',
2323
 
                   'bzrlib.tests.test_osutils',
2324
 
                   'bzrlib.tests.test_osutils_encodings',
2325
 
                   'bzrlib.tests.test_patch',
2326
 
                   'bzrlib.tests.test_patches',
2327
 
                   'bzrlib.tests.test_permissions',
2328
 
                   'bzrlib.tests.test_plugins',
2329
 
                   'bzrlib.tests.test_progress',
2330
 
                   'bzrlib.tests.test_reconcile',
2331
 
                   'bzrlib.tests.test_registry',
2332
 
                   'bzrlib.tests.test_remote',
2333
 
                   'bzrlib.tests.test_repository',
2334
 
                   'bzrlib.tests.test_revert',
2335
 
                   'bzrlib.tests.test_revision',
2336
 
                   'bzrlib.tests.test_revisionnamespaces',
2337
 
                   'bzrlib.tests.test_revisiontree',
2338
 
                   'bzrlib.tests.test_rio',
2339
 
                   'bzrlib.tests.test_sampler',
2340
 
                   'bzrlib.tests.test_selftest',
2341
 
                   'bzrlib.tests.test_setup',
2342
 
                   'bzrlib.tests.test_sftp_transport',
2343
 
                   'bzrlib.tests.test_smart',
2344
 
                   'bzrlib.tests.test_smart_add',
2345
 
                   'bzrlib.tests.test_smart_transport',
2346
 
                   'bzrlib.tests.test_smtp_connection',
2347
 
                   'bzrlib.tests.test_source',
2348
 
                   'bzrlib.tests.test_ssh_transport',
2349
 
                   'bzrlib.tests.test_status',
2350
 
                   'bzrlib.tests.test_store',
2351
 
                   'bzrlib.tests.test_strace',
2352
 
                   'bzrlib.tests.test_subsume',
2353
 
                   'bzrlib.tests.test_symbol_versioning',
2354
 
                   'bzrlib.tests.test_tag',
2355
 
                   'bzrlib.tests.test_testament',
2356
 
                   'bzrlib.tests.test_textfile',
2357
 
                   'bzrlib.tests.test_textmerge',
2358
 
                   'bzrlib.tests.test_timestamp',
2359
 
                   'bzrlib.tests.test_trace',
2360
 
                   'bzrlib.tests.test_transactions',
2361
 
                   'bzrlib.tests.test_transform',
2362
 
                   'bzrlib.tests.test_transport',
2363
 
                   'bzrlib.tests.test_tree',
2364
 
                   'bzrlib.tests.test_treebuilder',
2365
 
                   'bzrlib.tests.test_tsort',
2366
 
                   'bzrlib.tests.test_tuned_gzip',
2367
 
                   'bzrlib.tests.test_ui',
2368
 
                   'bzrlib.tests.test_upgrade',
2369
 
                   'bzrlib.tests.test_urlutils',
2370
 
                   'bzrlib.tests.test_versionedfile',
2371
 
                   'bzrlib.tests.test_version',
2372
 
                   'bzrlib.tests.test_version_info',
2373
 
                   'bzrlib.tests.test_weave',
2374
 
                   'bzrlib.tests.test_whitebox',
2375
 
                   'bzrlib.tests.test_workingtree',
2376
 
                   'bzrlib.tests.test_workingtree_4',
2377
 
                   'bzrlib.tests.test_wsgi',
2378
 
                   'bzrlib.tests.test_xml',
2379
 
                   ]
2380
 
    test_transport_implementations = [
2381
 
        'bzrlib.tests.test_transport_implementations',
2382
 
        'bzrlib.tests.test_read_bundle',
2383
 
        ]
2384
 
    suite = TestUtil.TestSuite()
 
4146
 
2385
4147
    loader = TestUtil.TestLoader()
2386
 
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
2387
 
    from bzrlib.tests.test_transport_implementations import TransportTestProviderAdapter
2388
 
    adapter = TransportTestProviderAdapter()
2389
 
    adapt_modules(test_transport_implementations, adapter, loader, suite)
2390
 
    for package in packages_to_test():
2391
 
        suite.addTest(package.test_suite())
2392
 
    for m in MODULES_TO_TEST:
2393
 
        suite.addTest(loader.loadTestsFromModule(m))
2394
 
    for m in MODULES_TO_DOCTEST:
 
4148
 
 
4149
    if keep_only is not None:
 
4150
        id_filter = TestIdList(keep_only)
 
4151
    if starting_with:
 
4152
        # We take precedence over keep_only because *at loading time* using
 
4153
        # both options means we will load less tests for the same final result.
 
4154
        def interesting_module(name):
 
4155
            for start in starting_with:
 
4156
                if (
 
4157
                    # Either the module name starts with the specified string
 
4158
                    name.startswith(start)
 
4159
                    # or it may contain tests starting with the specified string
 
4160
                    or start.startswith(name)
 
4161
                    ):
 
4162
                    return True
 
4163
            return False
 
4164
        loader = TestUtil.FilteredByModuleTestLoader(interesting_module)
 
4165
 
 
4166
    elif keep_only is not None:
 
4167
        loader = TestUtil.FilteredByModuleTestLoader(id_filter.refers_to)
 
4168
        def interesting_module(name):
 
4169
            return id_filter.refers_to(name)
 
4170
 
 
4171
    else:
 
4172
        loader = TestUtil.TestLoader()
 
4173
        def interesting_module(name):
 
4174
            # No filtering, all modules are interesting
 
4175
            return True
 
4176
 
 
4177
    suite = loader.suiteClass()
 
4178
 
 
4179
    # modules building their suite with loadTestsFromModuleNames
 
4180
    suite.addTest(loader.loadTestsFromModuleNames(_test_suite_testmod_names()))
 
4181
 
 
4182
    for mod in _test_suite_modules_to_doctest():
 
4183
        if not interesting_module(mod):
 
4184
            # No tests to keep here, move along
 
4185
            continue
2395
4186
        try:
2396
 
            suite.addTest(doctest.DocTestSuite(m))
 
4187
            # note that this really does mean "report only" -- doctest
 
4188
            # still runs the rest of the examples
 
4189
            doc_suite = IsolatedDocTestSuite(
 
4190
                mod, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
2397
4191
        except ValueError, e:
2398
 
            print '**failed to get doctest for: %s\n%s' %(m,e)
 
4192
            print '**failed to get doctest for: %s\n%s' % (mod, e)
2399
4193
            raise
2400
 
    for name, plugin in bzrlib.plugin.all_plugins().items():
2401
 
        if getattr(plugin, 'test_suite', None) is not None:
2402
 
            default_encoding = sys.getdefaultencoding()
2403
 
            try:
2404
 
                plugin_suite = plugin.test_suite()
2405
 
            except ImportError, e:
2406
 
                bzrlib.trace.warning(
2407
 
                    'Unable to test plugin "%s": %s', name, e)
2408
 
            else:
2409
 
                suite.addTest(plugin_suite)
2410
 
            if default_encoding != sys.getdefaultencoding():
2411
 
                bzrlib.trace.warning(
2412
 
                    'Plugin "%s" tried to reset default encoding to: %s', name,
2413
 
                    sys.getdefaultencoding())
2414
 
                reload(sys)
2415
 
                sys.setdefaultencoding(default_encoding)
 
4194
        if len(doc_suite._tests) == 0:
 
4195
            raise errors.BzrError("no doctests found in %s" % (mod,))
 
4196
        suite.addTest(doc_suite)
 
4197
 
 
4198
    default_encoding = sys.getdefaultencoding()
 
4199
    for name, plugin in _mod_plugin.plugins().items():
 
4200
        if not interesting_module(plugin.module.__name__):
 
4201
            continue
 
4202
        plugin_suite = plugin.test_suite()
 
4203
        # We used to catch ImportError here and turn it into just a warning,
 
4204
        # but really if you don't have --no-plugins this should be a failure.
 
4205
        # mbp 20080213 - see http://bugs.launchpad.net/bugs/189771
 
4206
        if plugin_suite is None:
 
4207
            plugin_suite = plugin.load_plugin_tests(loader)
 
4208
        if plugin_suite is not None:
 
4209
            suite.addTest(plugin_suite)
 
4210
        if default_encoding != sys.getdefaultencoding():
 
4211
            trace.warning(
 
4212
                'Plugin "%s" tried to reset default encoding to: %s', name,
 
4213
                sys.getdefaultencoding())
 
4214
            reload(sys)
 
4215
            sys.setdefaultencoding(default_encoding)
 
4216
 
 
4217
    if keep_only is not None:
 
4218
        # Now that the referred modules have loaded their tests, keep only the
 
4219
        # requested ones.
 
4220
        suite = filter_suite_by_id_list(suite, id_filter)
 
4221
        # Do some sanity checks on the id_list filtering
 
4222
        not_found, duplicates = suite_matches_id_list(suite, keep_only)
 
4223
        if starting_with:
 
4224
            # The tester has used both keep_only and starting_with, so he is
 
4225
            # already aware that some tests are excluded from the list, there
 
4226
            # is no need to tell him which.
 
4227
            pass
 
4228
        else:
 
4229
            # Some tests mentioned in the list are not in the test suite. The
 
4230
            # list may be out of date, report to the tester.
 
4231
            for id in not_found:
 
4232
                trace.warning('"%s" not found in the test suite', id)
 
4233
        for id in duplicates:
 
4234
            trace.warning('"%s" is used as an id by several tests', id)
 
4235
 
2416
4236
    return suite
2417
4237
 
2418
4238
 
2419
 
def adapt_modules(mods_list, adapter, loader, suite):
2420
 
    """Adapt the modules in mods_list using adapter and add to suite."""
2421
 
    for test in iter_suite_tests(loader.loadTestsFromModuleNames(mods_list)):
2422
 
        suite.addTests(adapter.adapt(test))
2423
 
 
2424
 
 
2425
 
def _rmtree_temp_dir(dirname):
 
4239
def multiply_scenarios(*scenarios):
 
4240
    """Multiply two or more iterables of scenarios.
 
4241
 
 
4242
    It is safe to pass scenario generators or iterators.
 
4243
 
 
4244
    :returns: A list of compound scenarios: the cross-product of all 
 
4245
        scenarios, with the names concatenated and the parameters
 
4246
        merged together.
 
4247
    """
 
4248
    return reduce(_multiply_two_scenarios, map(list, scenarios))
 
4249
 
 
4250
 
 
4251
def _multiply_two_scenarios(scenarios_left, scenarios_right):
 
4252
    """Multiply two sets of scenarios.
 
4253
 
 
4254
    :returns: the cartesian product of the two sets of scenarios, that is
 
4255
        a scenario for every possible combination of a left scenario and a
 
4256
        right scenario.
 
4257
    """
 
4258
    return [
 
4259
        ('%s,%s' % (left_name, right_name),
 
4260
         dict(left_dict.items() + right_dict.items()))
 
4261
        for left_name, left_dict in scenarios_left
 
4262
        for right_name, right_dict in scenarios_right]
 
4263
 
 
4264
 
 
4265
def multiply_tests(tests, scenarios, result):
 
4266
    """Multiply tests_list by scenarios into result.
 
4267
 
 
4268
    This is the core workhorse for test parameterisation.
 
4269
 
 
4270
    Typically the load_tests() method for a per-implementation test suite will
 
4271
    call multiply_tests and return the result.
 
4272
 
 
4273
    :param tests: The tests to parameterise.
 
4274
    :param scenarios: The scenarios to apply: pairs of (scenario_name,
 
4275
        scenario_param_dict).
 
4276
    :param result: A TestSuite to add created tests to.
 
4277
 
 
4278
    This returns the passed in result TestSuite with the cross product of all
 
4279
    the tests repeated once for each scenario.  Each test is adapted by adding
 
4280
    the scenario name at the end of its id(), and updating the test object's
 
4281
    __dict__ with the scenario_param_dict.
 
4282
 
 
4283
    >>> import bzrlib.tests.test_sampler
 
4284
    >>> r = multiply_tests(
 
4285
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
 
4286
    ...     [('one', dict(param=1)),
 
4287
    ...      ('two', dict(param=2))],
 
4288
    ...     TestUtil.TestSuite())
 
4289
    >>> tests = list(iter_suite_tests(r))
 
4290
    >>> len(tests)
 
4291
    2
 
4292
    >>> tests[0].id()
 
4293
    'bzrlib.tests.test_sampler.DemoTest.test_nothing(one)'
 
4294
    >>> tests[0].param
 
4295
    1
 
4296
    >>> tests[1].param
 
4297
    2
 
4298
    """
 
4299
    for test in iter_suite_tests(tests):
 
4300
        apply_scenarios(test, scenarios, result)
 
4301
    return result
 
4302
 
 
4303
 
 
4304
def apply_scenarios(test, scenarios, result):
 
4305
    """Apply the scenarios in scenarios to test and add to result.
 
4306
 
 
4307
    :param test: The test to apply scenarios to.
 
4308
    :param scenarios: An iterable of scenarios to apply to test.
 
4309
    :return: result
 
4310
    :seealso: apply_scenario
 
4311
    """
 
4312
    for scenario in scenarios:
 
4313
        result.addTest(apply_scenario(test, scenario))
 
4314
    return result
 
4315
 
 
4316
 
 
4317
def apply_scenario(test, scenario):
 
4318
    """Copy test and apply scenario to it.
 
4319
 
 
4320
    :param test: A test to adapt.
 
4321
    :param scenario: A tuple describing the scenarion.
 
4322
        The first element of the tuple is the new test id.
 
4323
        The second element is a dict containing attributes to set on the
 
4324
        test.
 
4325
    :return: The adapted test.
 
4326
    """
 
4327
    new_id = "%s(%s)" % (test.id(), scenario[0])
 
4328
    new_test = clone_test(test, new_id)
 
4329
    for name, value in scenario[1].items():
 
4330
        setattr(new_test, name, value)
 
4331
    return new_test
 
4332
 
 
4333
 
 
4334
def clone_test(test, new_id):
 
4335
    """Clone a test giving it a new id.
 
4336
 
 
4337
    :param test: The test to clone.
 
4338
    :param new_id: The id to assign to it.
 
4339
    :return: The new test.
 
4340
    """
 
4341
    new_test = copy.copy(test)
 
4342
    new_test.id = lambda: new_id
 
4343
    # XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
 
4344
    # causes cloned tests to share the 'details' dict.  This makes it hard to
 
4345
    # read the test output for parameterized tests, because tracebacks will be
 
4346
    # associated with irrelevant tests.
 
4347
    try:
 
4348
        details = new_test._TestCase__details
 
4349
    except AttributeError:
 
4350
        # must be a different version of testtools than expected.  Do nothing.
 
4351
        pass
 
4352
    else:
 
4353
        # Reset the '__details' dict.
 
4354
        new_test._TestCase__details = {}
 
4355
    return new_test
 
4356
 
 
4357
 
 
4358
def permute_tests_for_extension(standard_tests, loader, py_module_name,
 
4359
                                ext_module_name):
 
4360
    """Helper for permutating tests against an extension module.
 
4361
 
 
4362
    This is meant to be used inside a modules 'load_tests()' function. It will
 
4363
    create 2 scenarios, and cause all tests in the 'standard_tests' to be run
 
4364
    against both implementations. Setting 'test.module' to the appropriate
 
4365
    module. See bzrlib.tests.test__chk_map.load_tests as an example.
 
4366
 
 
4367
    :param standard_tests: A test suite to permute
 
4368
    :param loader: A TestLoader
 
4369
    :param py_module_name: The python path to a python module that can always
 
4370
        be loaded, and will be considered the 'python' implementation. (eg
 
4371
        'bzrlib._chk_map_py')
 
4372
    :param ext_module_name: The python path to an extension module. If the
 
4373
        module cannot be loaded, a single test will be added, which notes that
 
4374
        the module is not available. If it can be loaded, all standard_tests
 
4375
        will be run against that module.
 
4376
    :return: (suite, feature) suite is a test-suite that has all the permuted
 
4377
        tests. feature is the Feature object that can be used to determine if
 
4378
        the module is available.
 
4379
    """
 
4380
 
 
4381
    from bzrlib.tests.features import ModuleAvailableFeature
 
4382
    py_module = pyutils.get_named_object(py_module_name)
 
4383
    scenarios = [
 
4384
        ('python', {'module': py_module}),
 
4385
    ]
 
4386
    suite = loader.suiteClass()
 
4387
    feature = ModuleAvailableFeature(ext_module_name)
 
4388
    if feature.available():
 
4389
        scenarios.append(('C', {'module': feature.module}))
 
4390
    else:
 
4391
        # the compiled module isn't available, so we add a failing test
 
4392
        class FailWithoutFeature(TestCase):
 
4393
            def test_fail(self):
 
4394
                self.requireFeature(feature)
 
4395
        suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
 
4396
    result = multiply_tests(standard_tests, scenarios, suite)
 
4397
    return result, feature
 
4398
 
 
4399
 
 
4400
def _rmtree_temp_dir(dirname, test_id=None):
2426
4401
    # If LANG=C we probably have created some bogus paths
2427
4402
    # which rmtree(unicode) will fail to delete
2428
4403
    # so make sure we are using rmtree(str) to delete everything
2437
4412
    try:
2438
4413
        osutils.rmtree(dirname)
2439
4414
    except OSError, e:
2440
 
        if sys.platform == 'win32' and e.errno == errno.EACCES:
2441
 
            print >>sys.stderr, ('Permission denied: '
2442
 
                                 'unable to remove testing dir '
2443
 
                                 '%s' % os.path.basename(dirname))
 
4415
        # We don't want to fail here because some useful display will be lost
 
4416
        # otherwise. Polluting the tmp dir is bad, but not giving all the
 
4417
        # possible info to the test runner is even worse.
 
4418
        if test_id != None:
 
4419
            ui.ui_factory.clear_term()
 
4420
            sys.stderr.write('\nWhile running: %s\n' % (test_id,))
 
4421
        # Ugly, but the last thing we want here is fail, so bear with it.
 
4422
        printable_e = str(e).decode(osutils.get_user_encoding(), 'replace'
 
4423
                                    ).encode('ascii', 'replace')
 
4424
        sys.stderr.write('Unable to remove testing dir %s\n%s'
 
4425
                         % (os.path.basename(dirname), printable_e))
 
4426
 
 
4427
 
 
4428
def probe_unicode_in_user_encoding():
 
4429
    """Try to encode several unicode strings to use in unicode-aware tests.
 
4430
    Return first successfull match.
 
4431
 
 
4432
    :return:  (unicode value, encoded plain string value) or (None, None)
 
4433
    """
 
4434
    possible_vals = [u'm\xb5', u'\xe1', u'\u0410']
 
4435
    for uni_val in possible_vals:
 
4436
        try:
 
4437
            str_val = uni_val.encode(osutils.get_user_encoding())
 
4438
        except UnicodeEncodeError:
 
4439
            # Try a different character
 
4440
            pass
2444
4441
        else:
2445
 
            raise
2446
 
 
2447
 
 
2448
 
def clean_selftest_output(root=None, quiet=False):
2449
 
    """Remove all selftest output directories from root directory.
2450
 
 
2451
 
    :param  root:   root directory for clean
2452
 
                    (if ommitted or None then clean current directory).
2453
 
    :param  quiet:  suppress report about deleting directories
 
4442
            return uni_val, str_val
 
4443
    return None, None
 
4444
 
 
4445
 
 
4446
def probe_bad_non_ascii(encoding):
 
4447
    """Try to find [bad] character with code [128..255]
 
4448
    that cannot be decoded to unicode in some encoding.
 
4449
    Return None if all non-ascii characters is valid
 
4450
    for given encoding.
2454
4451
    """
2455
 
    import re
2456
 
    re_dir = re.compile(r'''test\d\d\d\d\.tmp''')
2457
 
    if root is None:
2458
 
        root = u'.'
2459
 
    for i in os.listdir(root):
2460
 
        if os.path.isdir(i) and re_dir.match(i):
2461
 
            if not quiet:
2462
 
                print 'delete directory:', i
2463
 
            _rmtree_temp_dir(i)
2464
 
 
2465
 
 
2466
 
class Feature(object):
2467
 
    """An operating system Feature."""
2468
 
 
2469
 
    def __init__(self):
2470
 
        self._available = None
2471
 
 
2472
 
    def available(self):
2473
 
        """Is the feature available?
2474
 
 
2475
 
        :return: True if the feature is available.
2476
 
        """
2477
 
        if self._available is None:
2478
 
            self._available = self._probe()
2479
 
        return self._available
2480
 
 
2481
 
    def _probe(self):
2482
 
        """Implement this method in concrete features.
2483
 
 
2484
 
        :return: True if the feature is available.
2485
 
        """
2486
 
        raise NotImplementedError
2487
 
 
2488
 
    def __str__(self):
2489
 
        if getattr(self, 'feature_name', None):
2490
 
            return self.feature_name()
2491
 
        return self.__class__.__name__
2492
 
 
2493
 
 
2494
 
class TestScenarioApplier(object):
2495
 
    """A tool to apply scenarios to tests."""
2496
 
 
2497
 
    def adapt(self, test):
2498
 
        """Return a TestSuite containing a copy of test for each scenario."""
2499
 
        result = unittest.TestSuite()
2500
 
        for scenario in self.scenarios:
2501
 
            result.addTest(self.adapt_test_to_scenario(test, scenario))
2502
 
        return result
2503
 
 
2504
 
    def adapt_test_to_scenario(self, test, scenario):
2505
 
        """Copy test and apply scenario to it.
2506
 
 
2507
 
        :param test: A test to adapt.
2508
 
        :param scenario: A tuple describing the scenarion.
2509
 
            The first element of the tuple is the new test id.
2510
 
            The second element is a dict containing attributes to set on the
2511
 
            test.
2512
 
        :return: The adapted test.
2513
 
        """
2514
 
        from copy import deepcopy
2515
 
        new_test = deepcopy(test)
2516
 
        for name, value in scenario[1].items():
2517
 
            setattr(new_test, name, value)
2518
 
        new_id = "%s(%s)" % (new_test.id(), scenario[0])
2519
 
        new_test.id = lambda: new_id
2520
 
        return new_test
 
4452
    for i in xrange(128, 256):
 
4453
        char = chr(i)
 
4454
        try:
 
4455
            char.decode(encoding)
 
4456
        except UnicodeDecodeError:
 
4457
            return char
 
4458
    return None
 
4459
 
 
4460
 
 
4461
# Only define SubUnitBzrRunner if subunit is available.
 
4462
try:
 
4463
    from subunit import TestProtocolClient
 
4464
    from subunit.test_results import AutoTimingTestResultDecorator
 
4465
    class SubUnitBzrProtocolClient(TestProtocolClient):
 
4466
 
 
4467
        def stopTest(self, test):
 
4468
            super(SubUnitBzrProtocolClient, self).stopTest(test)
 
4469
            _clear__type_equality_funcs(test)
 
4470
 
 
4471
        def addSuccess(self, test, details=None):
 
4472
            # The subunit client always includes the details in the subunit
 
4473
            # stream, but we don't want to include it in ours.
 
4474
            if details is not None and 'log' in details:
 
4475
                del details['log']
 
4476
            return super(SubUnitBzrProtocolClient, self).addSuccess(
 
4477
                test, details)
 
4478
 
 
4479
    class SubUnitBzrRunner(TextTestRunner):
 
4480
        def run(self, test):
 
4481
            result = AutoTimingTestResultDecorator(
 
4482
                SubUnitBzrProtocolClient(self.stream))
 
4483
            test.run(result)
 
4484
            return result
 
4485
except ImportError:
 
4486
    pass
 
4487
 
 
4488
 
 
4489
# API compatibility for old plugins; see bug 892622.
 
4490
for name in [
 
4491
    'Feature',
 
4492
    'HTTPServerFeature', 
 
4493
    'ModuleAvailableFeature',
 
4494
    'HTTPSServerFeature', 'SymlinkFeature', 'HardlinkFeature',
 
4495
    'OsFifoFeature', 'UnicodeFilenameFeature',
 
4496
    'ByteStringNamedFilesystem', 'UTF8Filesystem',
 
4497
    'BreakinFeature', 'CaseInsCasePresFilenameFeature',
 
4498
    'CaseInsensitiveFilesystemFeature', 'case_sensitive_filesystem_feature',
 
4499
    'posix_permissions_feature',
 
4500
    ]:
 
4501
    globals()[name] = _CompatabilityThunkFeature(
 
4502
        symbol_versioning.deprecated_in((2, 5, 0)),
 
4503
        'bzrlib.tests', name,
 
4504
        name, 'bzrlib.tests.features')
 
4505
 
 
4506
 
 
4507
for (old_name, new_name) in [
 
4508
    ('UnicodeFilename', 'UnicodeFilenameFeature'),
 
4509
    ]:
 
4510
    globals()[name] = _CompatabilityThunkFeature(
 
4511
        symbol_versioning.deprecated_in((2, 5, 0)),
 
4512
        'bzrlib.tests', old_name,
 
4513
        new_name, 'bzrlib.tests.features')