~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Robert Collins
  • Date: 2009-03-27 04:10:25 UTC
  • mfrom: (4208 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4216.
  • Revision ID: robertc@robertcollins.net-20090327041025-rgutx4q03xo4pq6l
Resolve NEWS conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
"""Testing framework extensions"""
18
17
 
19
18
# TODO: Perhaps there should be an API to find out if bzr running under the
20
19
# test suite -- some plugins might want to avoid making intrusive changes if
29
28
 
30
29
import atexit
31
30
import codecs
32
 
import copy
33
31
from cStringIO import StringIO
34
32
import difflib
35
33
import doctest
36
34
import errno
37
 
import itertools
38
35
import logging
39
36
import os
40
 
import platform
41
 
import pprint
 
37
from pprint import pformat
42
38
import random
43
39
import re
44
40
import shlex
45
41
import stat
46
 
import subprocess
 
42
from subprocess import Popen, PIPE
47
43
import sys
48
44
import tempfile
49
45
import threading
50
46
import time
51
 
import traceback
52
47
import unittest
53
48
import warnings
54
49
 
55
 
import testtools
56
 
# nb: check this before importing anything else from within it
57
 
_testtools_version = getattr(testtools, '__version__', ())
58
 
if _testtools_version < (0, 9, 5):
59
 
    raise ImportError("need at least testtools 0.9.5: %s is %r"
60
 
        % (testtools.__file__, _testtools_version))
61
 
from testtools import content
62
50
 
63
 
import bzrlib
64
51
from bzrlib import (
65
52
    branchbuilder,
66
53
    bzrdir,
67
 
    chk_map,
68
 
    commands as _mod_commands,
69
 
    config,
70
54
    debug,
71
55
    errors,
72
56
    hooks,
73
 
    lock as _mod_lock,
74
 
    lockdir,
75
57
    memorytree,
76
58
    osutils,
77
 
    plugin as _mod_plugin,
78
 
    pyutils,
 
59
    progress,
79
60
    ui,
80
61
    urlutils,
81
62
    registry,
82
 
    symbol_versioning,
83
 
    trace,
84
 
    transport as _mod_transport,
85
63
    workingtree,
86
64
    )
 
65
import bzrlib.branch
 
66
import bzrlib.commands
 
67
import bzrlib.timestamp
 
68
import bzrlib.export
 
69
import bzrlib.inventory
 
70
import bzrlib.iterablefile
 
71
import bzrlib.lockdir
87
72
try:
88
73
    import bzrlib.lsprof
89
74
except ImportError:
90
75
    # lsprof not available
91
76
    pass
92
 
from bzrlib.smart import client, request
93
 
from bzrlib.transport import (
94
 
    memory,
95
 
    pathfilter,
96
 
    )
97
 
from bzrlib.tests import (
98
 
    test_server,
99
 
    TestUtil,
100
 
    treeshape,
101
 
    )
102
 
from bzrlib.ui import NullProgressView
103
 
from bzrlib.ui.text import TextUIFactory
 
77
from bzrlib.merge import merge_inner
 
78
import bzrlib.merge3
 
79
import bzrlib.plugin
 
80
from bzrlib.smart import client, request, server
 
81
import bzrlib.store
 
82
from bzrlib import symbol_versioning
 
83
from bzrlib.symbol_versioning import (
 
84
    DEPRECATED_PARAMETER,
 
85
    deprecated_function,
 
86
    deprecated_method,
 
87
    deprecated_passed,
 
88
    )
 
89
import bzrlib.trace
 
90
from bzrlib.transport import get_transport
 
91
import bzrlib.transport
 
92
from bzrlib.transport.local import LocalURLServer
 
93
from bzrlib.transport.memory import MemoryServer
 
94
from bzrlib.transport.readonly import ReadonlyServer
 
95
from bzrlib.trace import mutter, note
 
96
from bzrlib.tests import TestUtil
 
97
from bzrlib.tests.http_server import HttpServer
 
98
from bzrlib.tests.TestUtil import (
 
99
                          TestSuite,
 
100
                          TestLoader,
 
101
                          )
 
102
from bzrlib.tests.treeshape import build_tree_contents
 
103
import bzrlib.version_info_formats.format_custom
 
104
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
104
105
 
105
106
# Mark this python module as being part of the implementation
106
107
# of unittest: this gives us better tracebacks where the last
107
108
# shown frame is the test code, not our assertXYZ.
108
109
__unittest = 1
109
110
 
110
 
default_transport = test_server.LocalURLServer
111
 
 
112
 
 
113
 
_unitialized_attr = object()
114
 
"""A sentinel needed to act as a default value in a method signature."""
115
 
 
116
 
 
117
 
# Subunit result codes, defined here to prevent a hard dependency on subunit.
118
 
SUBUNIT_SEEK_SET = 0
119
 
SUBUNIT_SEEK_CUR = 1
120
 
 
121
 
# These are intentionally brought into this namespace. That way plugins, etc
122
 
# can just "from bzrlib.tests import TestCase, TestLoader, etc"
123
 
TestSuite = TestUtil.TestSuite
124
 
TestLoader = TestUtil.TestLoader
125
 
 
126
 
# Tests should run in a clean and clearly defined environment. The goal is to
127
 
# keep them isolated from the running environment as mush as possible. The test
128
 
# framework ensures the variables defined below are set (or deleted if the
129
 
# value is None) before a test is run and reset to their original value after
130
 
# the test is run. Generally if some code depends on an environment variable,
131
 
# the tests should start without this variable in the environment. There are a
132
 
# few exceptions but you shouldn't violate this rule lightly.
133
 
isolated_environ = {
134
 
    'BZR_HOME': None,
135
 
    'HOME': None,
136
 
    # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
137
 
    # tests do check our impls match APPDATA
138
 
    'BZR_EDITOR': None, # test_msgeditor manipulates this variable
139
 
    'VISUAL': None,
140
 
    'EDITOR': None,
141
 
    'BZR_EMAIL': None,
142
 
    'BZREMAIL': None, # may still be present in the environment
143
 
    'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
144
 
    'BZR_PROGRESS_BAR': None,
145
 
    # This should trap leaks to ~/.bzr.log. This occurs when tests use TestCase
146
 
    # as a base class instead of TestCaseInTempDir. Tests inheriting from
147
 
    # TestCase should not use disk resources, BZR_LOG is one.
148
 
    'BZR_LOG': '/you-should-use-TestCaseInTempDir-if-you-need-a-log-file',
149
 
    'BZR_PLUGIN_PATH': None,
150
 
    'BZR_DISABLE_PLUGINS': None,
151
 
    'BZR_PLUGINS_AT': None,
152
 
    'BZR_CONCURRENCY': None,
153
 
    # Make sure that any text ui tests are consistent regardless of
154
 
    # the environment the test case is run in; you may want tests that
155
 
    # test other combinations.  'dumb' is a reasonable guess for tests
156
 
    # going to a pipe or a StringIO.
157
 
    'TERM': 'dumb',
158
 
    'LINES': '25',
159
 
    'COLUMNS': '80',
160
 
    'BZR_COLUMNS': '80',
161
 
    # Disable SSH Agent
162
 
    'SSH_AUTH_SOCK': None,
163
 
    # Proxies
164
 
    'http_proxy': None,
165
 
    'HTTP_PROXY': None,
166
 
    'https_proxy': None,
167
 
    'HTTPS_PROXY': None,
168
 
    'no_proxy': None,
169
 
    'NO_PROXY': None,
170
 
    'all_proxy': None,
171
 
    'ALL_PROXY': None,
172
 
    # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
173
 
    # least. If you do (care), please update this comment
174
 
    # -- vila 20080401
175
 
    'ftp_proxy': None,
176
 
    'FTP_PROXY': None,
177
 
    'BZR_REMOTE_PATH': None,
178
 
    # Generally speaking, we don't want apport reporting on crashes in
179
 
    # the test envirnoment unless we're specifically testing apport,
180
 
    # so that it doesn't leak into the real system environment.  We
181
 
    # use an env var so it propagates to subprocesses.
182
 
    'APPORT_DISABLE': '1',
183
 
    }
184
 
 
185
 
 
186
 
def override_os_environ(test, env=None):
187
 
    """Modify os.environ keeping a copy.
188
 
    
189
 
    :param test: A test instance
190
 
 
191
 
    :param env: A dict containing variable definitions to be installed
192
 
    """
193
 
    if env is None:
194
 
        env = isolated_environ
195
 
    test._original_os_environ = dict([(var, value)
196
 
                                      for var, value in os.environ.iteritems()])
197
 
    for var, value in env.iteritems():
198
 
        osutils.set_or_unset_env(var, value)
199
 
        if var not in test._original_os_environ:
200
 
            # The var is new, add it with a value of None, so
201
 
            # restore_os_environ will delete it
202
 
            test._original_os_environ[var] = None
203
 
 
204
 
 
205
 
def restore_os_environ(test):
206
 
    """Restore os.environ to its original state.
207
 
 
208
 
    :param test: A test instance previously passed to override_os_environ.
209
 
    """
210
 
    for var, value in test._original_os_environ.iteritems():
211
 
        # Restore the original value (or delete it if the value has been set to
212
 
        # None in override_os_environ).
213
 
        osutils.set_or_unset_env(var, value)
214
 
 
215
 
 
216
 
class ExtendedTestResult(testtools.TextTestResult):
 
111
default_transport = LocalURLServer
 
112
 
 
113
 
 
114
class ExtendedTestResult(unittest._TextTestResult):
217
115
    """Accepts, reports and accumulates the results of running tests.
218
116
 
219
117
    Compared to the unittest version this class adds support for
233
131
 
234
132
    def __init__(self, stream, descriptions, verbosity,
235
133
                 bench_history=None,
236
 
                 strict=False,
 
134
                 num_tests=None,
237
135
                 ):
238
136
        """Construct new TestResult.
239
137
 
240
138
        :param bench_history: Optionally, a writable file object to accumulate
241
139
            benchmark results.
242
140
        """
243
 
        testtools.TextTestResult.__init__(self, stream)
 
141
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
244
142
        if bench_history is not None:
245
143
            from bzrlib.version import _get_bzr_source_tree
246
144
            src_tree = _get_bzr_source_tree()
257
155
            bench_history.write("--date %s %s\n" % (time.time(), revision_id))
258
156
        self._bench_history = bench_history
259
157
        self.ui = ui.ui_factory
260
 
        self.num_tests = 0
 
158
        self.num_tests = num_tests
261
159
        self.error_count = 0
262
160
        self.failure_count = 0
263
161
        self.known_failure_count = 0
266
164
        self.unsupported = {}
267
165
        self.count = 0
268
166
        self._overall_start_time = time.time()
269
 
        self._strict = strict
270
 
        self._first_thread_leaker_id = None
271
 
        self._tests_leaking_threads_count = 0
272
 
        self._traceback_from_test = None
273
 
 
274
 
    def stopTestRun(self):
275
 
        run = self.testsRun
276
 
        actionTaken = "Ran"
277
 
        stopTime = time.time()
278
 
        timeTaken = stopTime - self.startTime
279
 
        # GZ 2010-07-19: Seems testtools has no printErrors method, and though
280
 
        #                the parent class method is similar have to duplicate
281
 
        self._show_list('ERROR', self.errors)
282
 
        self._show_list('FAIL', self.failures)
283
 
        self.stream.write(self.sep2)
284
 
        self.stream.write("%s %d test%s in %.3fs\n\n" % (actionTaken,
285
 
                            run, run != 1 and "s" or "", timeTaken))
286
 
        if not self.wasSuccessful():
287
 
            self.stream.write("FAILED (")
288
 
            failed, errored = map(len, (self.failures, self.errors))
289
 
            if failed:
290
 
                self.stream.write("failures=%d" % failed)
291
 
            if errored:
292
 
                if failed: self.stream.write(", ")
293
 
                self.stream.write("errors=%d" % errored)
294
 
            if self.known_failure_count:
295
 
                if failed or errored: self.stream.write(", ")
296
 
                self.stream.write("known_failure_count=%d" %
297
 
                    self.known_failure_count)
298
 
            self.stream.write(")\n")
299
 
        else:
300
 
            if self.known_failure_count:
301
 
                self.stream.write("OK (known_failures=%d)\n" %
302
 
                    self.known_failure_count)
303
 
            else:
304
 
                self.stream.write("OK\n")
305
 
        if self.skip_count > 0:
306
 
            skipped = self.skip_count
307
 
            self.stream.write('%d test%s skipped\n' %
308
 
                                (skipped, skipped != 1 and "s" or ""))
309
 
        if self.unsupported:
310
 
            for feature, count in sorted(self.unsupported.items()):
311
 
                self.stream.write("Missing feature '%s' skipped %d tests.\n" %
312
 
                    (feature, count))
313
 
        if self._strict:
314
 
            ok = self.wasStrictlySuccessful()
315
 
        else:
316
 
            ok = self.wasSuccessful()
317
 
        if self._first_thread_leaker_id:
318
 
            self.stream.write(
319
 
                '%s is leaking threads among %d leaking tests.\n' % (
320
 
                self._first_thread_leaker_id,
321
 
                self._tests_leaking_threads_count))
322
 
            # We don't report the main thread as an active one.
323
 
            self.stream.write(
324
 
                '%d non-main threads were left active in the end.\n'
325
 
                % (len(self._active_threads) - 1))
326
 
 
327
 
    def getDescription(self, test):
328
 
        return test.id()
329
 
 
330
 
    def _extractBenchmarkTime(self, testCase, details=None):
 
167
 
 
168
    def _extractBenchmarkTime(self, testCase):
331
169
        """Add a benchmark time for the current test case."""
332
 
        if details and 'benchtime' in details:
333
 
            return float(''.join(details['benchtime'].iter_bytes()))
334
170
        return getattr(testCase, "_benchtime", None)
335
171
 
336
172
    def _elapsedTestTimeString(self):
337
173
        """Return a time string for the overall time the current test has taken."""
338
 
        return self._formatTime(self._delta_to_float(
339
 
            self._now() - self._start_datetime))
 
174
        return self._formatTime(time.time() - self._start_time)
340
175
 
341
176
    def _testTimeString(self, testCase):
342
177
        benchmark_time = self._extractBenchmarkTime(testCase)
343
178
        if benchmark_time is not None:
344
 
            return self._formatTime(benchmark_time) + "*"
 
179
            return "%s/%s" % (
 
180
                self._formatTime(benchmark_time),
 
181
                self._elapsedTestTimeString())
345
182
        else:
346
 
            return self._elapsedTestTimeString()
 
183
            return "           %s" % self._elapsedTestTimeString()
347
184
 
348
185
    def _formatTime(self, seconds):
349
186
        """Format seconds as milliseconds with leading spaces."""
353
190
 
354
191
    def _shortened_test_description(self, test):
355
192
        what = test.id()
356
 
        what = re.sub(r'^bzrlib\.tests\.', '', what)
 
193
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
357
194
        return what
358
195
 
359
 
    # GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
360
 
    #                multiple times in a row, because the handler is added for
361
 
    #                each test but the container list is shared between cases.
362
 
    #                See lp:498869 lp:625574 and lp:637725 for background.
363
 
    def _record_traceback_from_test(self, exc_info):
364
 
        """Store the traceback from passed exc_info tuple till"""
365
 
        self._traceback_from_test = exc_info[2]
366
 
 
367
196
    def startTest(self, test):
368
 
        super(ExtendedTestResult, self).startTest(test)
369
 
        if self.count == 0:
370
 
            self.startTests()
371
 
        self.count += 1
 
197
        unittest.TestResult.startTest(self, test)
372
198
        self.report_test_start(test)
373
199
        test.number = self.count
374
200
        self._recordTestStartTime()
375
 
        # Make testtools cases give us the real traceback on failure
376
 
        addOnException = getattr(test, "addOnException", None)
377
 
        if addOnException is not None:
378
 
            addOnException(self._record_traceback_from_test)
379
 
        # Only check for thread leaks on bzrlib derived test cases
380
 
        if isinstance(test, TestCase):
381
 
            test.addCleanup(self._check_leaked_threads, test)
382
 
 
383
 
    def stopTest(self, test):
384
 
        super(ExtendedTestResult, self).stopTest(test)
385
 
        # Manually break cycles, means touching various private things but hey
386
 
        getDetails = getattr(test, "getDetails", None)
387
 
        if getDetails is not None:
388
 
            getDetails().clear()
389
 
        type_equality_funcs = getattr(test, "_type_equality_funcs", None)
390
 
        if type_equality_funcs is not None:
391
 
            type_equality_funcs.clear()
392
 
        self._traceback_from_test = None
393
 
 
394
 
    def startTests(self):
395
 
        self.report_tests_starting()
396
 
        self._active_threads = threading.enumerate()
397
 
 
398
 
    def _check_leaked_threads(self, test):
399
 
        """See if any threads have leaked since last call
400
 
 
401
 
        A sample of live threads is stored in the _active_threads attribute,
402
 
        when this method runs it compares the current live threads and any not
403
 
        in the previous sample are treated as having leaked.
404
 
        """
405
 
        now_active_threads = set(threading.enumerate())
406
 
        threads_leaked = now_active_threads.difference(self._active_threads)
407
 
        if threads_leaked:
408
 
            self._report_thread_leak(test, threads_leaked, now_active_threads)
409
 
            self._tests_leaking_threads_count += 1
410
 
            if self._first_thread_leaker_id is None:
411
 
                self._first_thread_leaker_id = test.id()
412
 
            self._active_threads = now_active_threads
413
201
 
414
202
    def _recordTestStartTime(self):
415
203
        """Record that a test has started."""
416
 
        self._start_datetime = self._now()
 
204
        self._start_time = time.time()
 
205
 
 
206
    def _cleanupLogFile(self, test):
 
207
        # We can only do this if we have one of our TestCases, not if
 
208
        # we have a doctest.
 
209
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
210
        if setKeepLogfile is not None:
 
211
            setKeepLogfile()
417
212
 
418
213
    def addError(self, test, err):
419
214
        """Tell result that test finished with an error.
421
216
        Called from the TestCase run() method when the test
422
217
        fails with an unexpected error.
423
218
        """
424
 
        self._post_mortem(self._traceback_from_test)
425
 
        super(ExtendedTestResult, self).addError(test, err)
426
 
        self.error_count += 1
427
 
        self.report_error(test, err)
428
 
        if self.stop_early:
429
 
            self.stop()
 
219
        self._testConcluded(test)
 
220
        if isinstance(err[1], TestNotApplicable):
 
221
            return self._addNotApplicable(test, err)
 
222
        elif isinstance(err[1], UnavailableFeature):
 
223
            return self.addNotSupported(test, err[1].args[0])
 
224
        else:
 
225
            unittest.TestResult.addError(self, test, err)
 
226
            self.error_count += 1
 
227
            self.report_error(test, err)
 
228
            if self.stop_early:
 
229
                self.stop()
 
230
            self._cleanupLogFile(test)
430
231
 
431
232
    def addFailure(self, test, err):
432
233
        """Tell result that test failed.
434
235
        Called from the TestCase run() method when the test
435
236
        fails because e.g. an assert() method failed.
436
237
        """
437
 
        self._post_mortem(self._traceback_from_test)
438
 
        super(ExtendedTestResult, self).addFailure(test, err)
439
 
        self.failure_count += 1
440
 
        self.report_failure(test, err)
441
 
        if self.stop_early:
442
 
            self.stop()
 
238
        self._testConcluded(test)
 
239
        if isinstance(err[1], KnownFailure):
 
240
            return self._addKnownFailure(test, err)
 
241
        else:
 
242
            unittest.TestResult.addFailure(self, test, err)
 
243
            self.failure_count += 1
 
244
            self.report_failure(test, err)
 
245
            if self.stop_early:
 
246
                self.stop()
 
247
            self._cleanupLogFile(test)
443
248
 
444
 
    def addSuccess(self, test, details=None):
 
249
    def addSuccess(self, test):
445
250
        """Tell result that test completed successfully.
446
251
 
447
252
        Called from the TestCase run()
448
253
        """
 
254
        self._testConcluded(test)
449
255
        if self._bench_history is not None:
450
 
            benchmark_time = self._extractBenchmarkTime(test, details)
 
256
            benchmark_time = self._extractBenchmarkTime(test)
451
257
            if benchmark_time is not None:
452
258
                self._bench_history.write("%s %s\n" % (
453
259
                    self._formatTime(benchmark_time),
454
260
                    test.id()))
455
261
        self.report_success(test)
456
 
        super(ExtendedTestResult, self).addSuccess(test)
 
262
        self._cleanupLogFile(test)
 
263
        unittest.TestResult.addSuccess(self, test)
457
264
        test._log_contents = ''
458
265
 
459
 
    def addExpectedFailure(self, test, err):
 
266
    def _testConcluded(self, test):
 
267
        """Common code when a test has finished.
 
268
 
 
269
        Called regardless of whether it succeded, failed, etc.
 
270
        """
 
271
        pass
 
272
 
 
273
    def _addKnownFailure(self, test, err):
460
274
        self.known_failure_count += 1
461
275
        self.report_known_failure(test, err)
462
276
 
463
 
    def addUnexpectedSuccess(self, test, details=None):
464
 
        """Tell result the test unexpectedly passed, counting as a failure
465
 
 
466
 
        When the minimum version of testtools required becomes 0.9.8 this
467
 
        can be updated to use the new handling there.
468
 
        """
469
 
        super(ExtendedTestResult, self).addFailure(test, details=details)
470
 
        self.failure_count += 1
471
 
        self.report_unexpected_success(test,
472
 
            "".join(details["reason"].iter_text()))
473
 
        if self.stop_early:
474
 
            self.stop()
475
 
 
476
277
    def addNotSupported(self, test, feature):
477
278
        """The test will not be run because of a missing feature.
478
279
        """
479
280
        # this can be called in two different ways: it may be that the
480
 
        # test started running, and then raised (through requireFeature)
 
281
        # test started running, and then raised (through addError)
481
282
        # UnavailableFeature.  Alternatively this method can be called
482
 
        # while probing for features before running the test code proper; in
483
 
        # that case we will see startTest and stopTest, but the test will
484
 
        # never actually run.
 
283
        # while probing for features before running the tests; in that
 
284
        # case we will see startTest and stopTest, but the test will never
 
285
        # actually run.
485
286
        self.unsupported.setdefault(str(feature), 0)
486
287
        self.unsupported[str(feature)] += 1
487
288
        self.report_unsupported(test, feature)
491
292
        self.skip_count += 1
492
293
        self.report_skip(test, reason)
493
294
 
494
 
    def addNotApplicable(self, test, reason):
495
 
        self.not_applicable_count += 1
496
 
        self.report_not_applicable(test, reason)
497
 
 
498
 
    def _post_mortem(self, tb=None):
499
 
        """Start a PDB post mortem session."""
500
 
        if os.environ.get('BZR_TEST_PDB', None):
501
 
            import pdb
502
 
            pdb.post_mortem(tb)
503
 
 
504
 
    def progress(self, offset, whence):
505
 
        """The test is adjusting the count of tests to run."""
506
 
        if whence == SUBUNIT_SEEK_SET:
507
 
            self.num_tests = offset
508
 
        elif whence == SUBUNIT_SEEK_CUR:
509
 
            self.num_tests += offset
510
 
        else:
511
 
            raise errors.BzrError("Unknown whence %r" % whence)
512
 
 
513
 
    def report_tests_starting(self):
514
 
        """Display information before the test run begins"""
515
 
        if getattr(sys, 'frozen', None) is None:
516
 
            bzr_path = osutils.realpath(sys.argv[0])
517
 
        else:
518
 
            bzr_path = sys.executable
519
 
        self.stream.write(
520
 
            'bzr selftest: %s\n' % (bzr_path,))
521
 
        self.stream.write(
522
 
            '   %s\n' % (
523
 
                    bzrlib.__path__[0],))
524
 
        self.stream.write(
525
 
            '   bzr-%s python-%s %s\n' % (
526
 
                    bzrlib.version_string,
527
 
                    bzrlib._format_version_tuple(sys.version_info),
528
 
                    platform.platform(aliased=1),
529
 
                    ))
530
 
        self.stream.write('\n')
531
 
 
532
 
    def report_test_start(self, test):
533
 
        """Display information on the test just about to be run"""
534
 
 
535
 
    def _report_thread_leak(self, test, leaked_threads, active_threads):
536
 
        """Display information on a test that leaked one or more threads"""
537
 
        # GZ 2010-09-09: A leak summary reported separately from the general
538
 
        #                thread debugging would be nice. Tests under subunit
539
 
        #                need something not using stream, perhaps adding a
540
 
        #                testtools details object would be fitting.
541
 
        if 'threads' in selftest_debug_flags:
542
 
            self.stream.write('%s is leaking, active is now %d\n' %
543
 
                (test.id(), len(active_threads)))
544
 
 
545
 
    def startTestRun(self):
546
 
        self.startTime = time.time()
 
295
    def _addNotApplicable(self, test, skip_excinfo):
 
296
        if isinstance(skip_excinfo[1], TestNotApplicable):
 
297
            self.not_applicable_count += 1
 
298
            self.report_not_applicable(test, skip_excinfo)
 
299
        try:
 
300
            test.tearDown()
 
301
        except KeyboardInterrupt:
 
302
            raise
 
303
        except:
 
304
            self.addError(test, test.exc_info())
 
305
        else:
 
306
            # seems best to treat this as success from point-of-view of unittest
 
307
            # -- it actually does nothing so it barely matters :)
 
308
            unittest.TestResult.addSuccess(self, test)
 
309
            test._log_contents = ''
 
310
 
 
311
    def printErrorList(self, flavour, errors):
 
312
        for test, err in errors:
 
313
            self.stream.writeln(self.separator1)
 
314
            self.stream.write("%s: " % flavour)
 
315
            self.stream.writeln(self.getDescription(test))
 
316
            if getattr(test, '_get_log', None) is not None:
 
317
                self.stream.write('\n')
 
318
                self.stream.write(
 
319
                        ('vvvv[log from %s]' % test.id()).ljust(78,'-'))
 
320
                self.stream.write('\n')
 
321
                self.stream.write(test._get_log())
 
322
                self.stream.write('\n')
 
323
                self.stream.write(
 
324
                        ('^^^^[log from %s]' % test.id()).ljust(78,'-'))
 
325
                self.stream.write('\n')
 
326
            self.stream.writeln(self.separator2)
 
327
            self.stream.writeln("%s" % err)
 
328
 
 
329
    def finished(self):
 
330
        pass
 
331
 
 
332
    def report_cleaning_up(self):
 
333
        pass
547
334
 
548
335
    def report_success(self, test):
549
336
        pass
559
346
 
560
347
    def __init__(self, stream, descriptions, verbosity,
561
348
                 bench_history=None,
 
349
                 num_tests=None,
562
350
                 pb=None,
563
 
                 strict=None,
564
351
                 ):
565
352
        ExtendedTestResult.__init__(self, stream, descriptions, verbosity,
566
 
            bench_history, strict)
567
 
        # We no longer pass them around, but just rely on the UIFactory stack
568
 
        # for state
569
 
        if pb is not None:
570
 
            warnings.warn("Passing pb to TextTestResult is deprecated")
571
 
        self.pb = self.ui.nested_progress_bar()
 
353
            bench_history, num_tests)
 
354
        if pb is None:
 
355
            self.pb = self.ui.nested_progress_bar()
 
356
            self._supplied_pb = False
 
357
        else:
 
358
            self.pb = pb
 
359
            self._supplied_pb = True
572
360
        self.pb.show_pct = False
573
361
        self.pb.show_spinner = False
574
362
        self.pb.show_eta = False,
575
363
        self.pb.show_count = False
576
364
        self.pb.show_bar = False
577
 
        self.pb.update_latency = 0
578
 
        self.pb.show_transport_activity = False
579
 
 
580
 
    def stopTestRun(self):
581
 
        # called when the tests that are going to run have run
582
 
        self.pb.clear()
583
 
        self.pb.finished()
584
 
        super(TextTestResult, self).stopTestRun()
585
 
 
586
 
    def report_tests_starting(self):
587
 
        super(TextTestResult, self).report_tests_starting()
 
365
 
 
366
    def report_starting(self):
588
367
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
589
368
 
590
369
    def _progress_prefix_text(self):
597
376
        ##     a += ', %d skip' % self.skip_count
598
377
        ## if self.known_failure_count:
599
378
        ##     a += '+%dX' % self.known_failure_count
600
 
        if self.num_tests:
 
379
        if self.num_tests is not None:
601
380
            a +='/%d' % self.num_tests
602
381
        a += ' in '
603
382
        runtime = time.time() - self._overall_start_time
605
384
            a += '%dm%ds' % (runtime / 60, runtime % 60)
606
385
        else:
607
386
            a += '%ds' % runtime
608
 
        total_fail_count = self.error_count + self.failure_count
609
 
        if total_fail_count:
610
 
            a += ', %d failed' % total_fail_count
611
 
        # if self.unsupported:
612
 
        #     a += ', %d missing' % len(self.unsupported)
 
387
        if self.error_count:
 
388
            a += ', %d err' % self.error_count
 
389
        if self.failure_count:
 
390
            a += ', %d fail' % self.failure_count
 
391
        if self.unsupported:
 
392
            a += ', %d missing' % len(self.unsupported)
613
393
        a += ']'
614
394
        return a
615
395
 
616
396
    def report_test_start(self, test):
 
397
        self.count += 1
617
398
        self.pb.update(
618
399
                self._progress_prefix_text()
619
400
                + ' '
623
404
        return self._shortened_test_description(test)
624
405
 
625
406
    def report_error(self, test, err):
626
 
        self.stream.write('ERROR: %s\n    %s\n' % (
 
407
        self.pb.note('ERROR: %s\n    %s\n',
627
408
            self._test_description(test),
628
409
            err[1],
629
 
            ))
 
410
            )
630
411
 
631
412
    def report_failure(self, test, err):
632
 
        self.stream.write('FAIL: %s\n    %s\n' % (
 
413
        self.pb.note('FAIL: %s\n    %s\n',
633
414
            self._test_description(test),
634
415
            err[1],
635
 
            ))
 
416
            )
636
417
 
637
418
    def report_known_failure(self, test, err):
638
 
        pass
639
 
 
640
 
    def report_unexpected_success(self, test, reason):
641
 
        self.stream.write('FAIL: %s\n    %s: %s\n' % (
642
 
            self._test_description(test),
643
 
            "Unexpected success. Should have failed",
644
 
            reason,
645
 
            ))
 
419
        self.pb.note('XFAIL: %s\n%s\n',
 
420
            self._test_description(test), err[1])
646
421
 
647
422
    def report_skip(self, test, reason):
648
423
        pass
649
424
 
650
 
    def report_not_applicable(self, test, reason):
 
425
    def report_not_applicable(self, test, skip_excinfo):
651
426
        pass
652
427
 
653
428
    def report_unsupported(self, test, feature):
654
429
        """test cannot be run because feature is missing."""
655
430
 
 
431
    def report_cleaning_up(self):
 
432
        self.pb.update('Cleaning up')
 
433
 
 
434
    def finished(self):
 
435
        if not self._supplied_pb:
 
436
            self.pb.finished()
 
437
 
656
438
 
657
439
class VerboseTestResult(ExtendedTestResult):
658
440
    """Produce long output, with one line per test run plus times"""
665
447
            result = a_string
666
448
        return result.ljust(final_width)
667
449
 
668
 
    def report_tests_starting(self):
 
450
    def report_starting(self):
669
451
        self.stream.write('running %d tests...\n' % self.num_tests)
670
 
        super(VerboseTestResult, self).report_tests_starting()
671
452
 
672
453
    def report_test_start(self, test):
 
454
        self.count += 1
673
455
        name = self._shortened_test_description(test)
674
 
        width = osutils.terminal_width()
675
 
        if width is not None:
676
 
            # width needs space for 6 char status, plus 1 for slash, plus an
677
 
            # 11-char time string, plus a trailing blank
678
 
            # when NUMBERED_DIRS: plus 5 chars on test number, plus 1 char on
679
 
            # space
680
 
            self.stream.write(self._ellipsize_to_right(name, width-18))
681
 
        else:
682
 
            self.stream.write(name)
 
456
        # width needs space for 6 char status, plus 1 for slash, plus 2 10-char
 
457
        # numbers, plus a trailing blank
 
458
        # when NUMBERED_DIRS: plus 5 chars on test number, plus 1 char on space
 
459
        self.stream.write(self._ellipsize_to_right(name,
 
460
                          osutils.terminal_width()-30))
683
461
        self.stream.flush()
684
462
 
685
463
    def _error_summary(self, err):
687
465
        return '%s%s' % (indent, err[1])
688
466
 
689
467
    def report_error(self, test, err):
690
 
        self.stream.write('ERROR %s\n%s\n'
 
468
        self.stream.writeln('ERROR %s\n%s'
691
469
                % (self._testTimeString(test),
692
470
                   self._error_summary(err)))
693
471
 
694
472
    def report_failure(self, test, err):
695
 
        self.stream.write(' FAIL %s\n%s\n'
 
473
        self.stream.writeln(' FAIL %s\n%s'
696
474
                % (self._testTimeString(test),
697
475
                   self._error_summary(err)))
698
476
 
699
477
    def report_known_failure(self, test, err):
700
 
        self.stream.write('XFAIL %s\n%s\n'
 
478
        self.stream.writeln('XFAIL %s\n%s'
701
479
                % (self._testTimeString(test),
702
480
                   self._error_summary(err)))
703
481
 
704
 
    def report_unexpected_success(self, test, reason):
705
 
        self.stream.write(' FAIL %s\n%s: %s\n'
706
 
                % (self._testTimeString(test),
707
 
                   "Unexpected success. Should have failed",
708
 
                   reason))
709
 
 
710
482
    def report_success(self, test):
711
 
        self.stream.write('   OK %s\n' % self._testTimeString(test))
 
483
        self.stream.writeln('   OK %s' % self._testTimeString(test))
712
484
        for bench_called, stats in getattr(test, '_benchcalls', []):
713
 
            self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
 
485
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
714
486
            stats.pprint(file=self.stream)
715
487
        # flush the stream so that we get smooth output. This verbose mode is
716
488
        # used to show the output in PQM.
717
489
        self.stream.flush()
718
490
 
719
491
    def report_skip(self, test, reason):
720
 
        self.stream.write(' SKIP %s\n%s\n'
 
492
        self.stream.writeln(' SKIP %s\n%s'
721
493
                % (self._testTimeString(test), reason))
722
494
 
723
 
    def report_not_applicable(self, test, reason):
724
 
        self.stream.write('  N/A %s\n    %s\n'
725
 
                % (self._testTimeString(test), reason))
 
495
    def report_not_applicable(self, test, skip_excinfo):
 
496
        self.stream.writeln('  N/A %s\n%s'
 
497
                % (self._testTimeString(test),
 
498
                   self._error_summary(skip_excinfo)))
726
499
 
727
500
    def report_unsupported(self, test, feature):
728
501
        """test cannot be run because feature is missing."""
729
 
        self.stream.write("NODEP %s\n    The feature '%s' is not available.\n"
 
502
        self.stream.writeln("NODEP %s\n    The feature '%s' is not available."
730
503
                %(self._testTimeString(test), feature))
731
504
 
732
505
 
738
511
                 descriptions=0,
739
512
                 verbosity=1,
740
513
                 bench_history=None,
741
 
                 strict=False,
742
 
                 result_decorators=None,
 
514
                 list_only=False
743
515
                 ):
744
 
        """Create a TextTestRunner.
745
 
 
746
 
        :param result_decorators: An optional list of decorators to apply
747
 
            to the result object being used by the runner. Decorators are
748
 
            applied left to right - the first element in the list is the 
749
 
            innermost decorator.
750
 
        """
751
 
        # stream may know claim to know to write unicode strings, but in older
752
 
        # pythons this goes sufficiently wrong that it is a bad idea. (
753
 
        # specifically a built in file with encoding 'UTF-8' will still try
754
 
        # to encode using ascii.
755
 
        new_encoding = osutils.get_terminal_encoding()
756
 
        codec = codecs.lookup(new_encoding)
757
 
        if type(codec) is tuple:
758
 
            # Python 2.4
759
 
            encode = codec[0]
760
 
        else:
761
 
            encode = codec.encode
762
 
        # GZ 2010-09-08: Really we don't want to be writing arbitrary bytes,
763
 
        #                so should swap to the plain codecs.StreamWriter
764
 
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream,
765
 
            "backslashreplace")
766
 
        stream.encoding = new_encoding
767
 
        self.stream = stream
 
516
        self.stream = unittest._WritelnDecorator(stream)
768
517
        self.descriptions = descriptions
769
518
        self.verbosity = verbosity
770
519
        self._bench_history = bench_history
771
 
        self._strict = strict
772
 
        self._result_decorators = result_decorators or []
 
520
        self.list_only = list_only
773
521
 
774
522
    def run(self, test):
775
523
        "Run the given test case or test suite."
 
524
        startTime = time.time()
776
525
        if self.verbosity == 1:
777
526
            result_class = TextTestResult
778
527
        elif self.verbosity >= 2:
779
528
            result_class = VerboseTestResult
780
 
        original_result = result_class(self.stream,
 
529
        result = result_class(self.stream,
781
530
                              self.descriptions,
782
531
                              self.verbosity,
783
532
                              bench_history=self._bench_history,
784
 
                              strict=self._strict,
 
533
                              num_tests=test.countTestCases(),
785
534
                              )
786
 
        # Signal to result objects that look at stop early policy to stop,
787
 
        original_result.stop_early = self.stop_on_failure
788
 
        result = original_result
789
 
        for decorator in self._result_decorators:
790
 
            result = decorator(result)
791
 
            result.stop_early = self.stop_on_failure
792
 
        result.startTestRun()
793
 
        try:
 
535
        result.stop_early = self.stop_on_failure
 
536
        result.report_starting()
 
537
        if self.list_only:
 
538
            if self.verbosity >= 2:
 
539
                self.stream.writeln("Listing tests only ...\n")
 
540
            run = 0
 
541
            for t in iter_suite_tests(test):
 
542
                self.stream.writeln("%s" % (t.id()))
 
543
                run += 1
 
544
            actionTaken = "Listed"
 
545
        else:
794
546
            test.run(result)
795
 
        finally:
796
 
            result.stopTestRun()
797
 
        # higher level code uses our extended protocol to determine
798
 
        # what exit code to give.
799
 
        return original_result
 
547
            run = result.testsRun
 
548
            actionTaken = "Ran"
 
549
        stopTime = time.time()
 
550
        timeTaken = stopTime - startTime
 
551
        result.printErrors()
 
552
        self.stream.writeln(result.separator2)
 
553
        self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
 
554
                            run, run != 1 and "s" or "", timeTaken))
 
555
        self.stream.writeln()
 
556
        if not result.wasSuccessful():
 
557
            self.stream.write("FAILED (")
 
558
            failed, errored = map(len, (result.failures, result.errors))
 
559
            if failed:
 
560
                self.stream.write("failures=%d" % failed)
 
561
            if errored:
 
562
                if failed: self.stream.write(", ")
 
563
                self.stream.write("errors=%d" % errored)
 
564
            if result.known_failure_count:
 
565
                if failed or errored: self.stream.write(", ")
 
566
                self.stream.write("known_failure_count=%d" %
 
567
                    result.known_failure_count)
 
568
            self.stream.writeln(")")
 
569
        else:
 
570
            if result.known_failure_count:
 
571
                self.stream.writeln("OK (known_failures=%d)" %
 
572
                    result.known_failure_count)
 
573
            else:
 
574
                self.stream.writeln("OK")
 
575
        if result.skip_count > 0:
 
576
            skipped = result.skip_count
 
577
            self.stream.writeln('%d test%s skipped' %
 
578
                                (skipped, skipped != 1 and "s" or ""))
 
579
        if result.unsupported:
 
580
            for feature, count in sorted(result.unsupported.items()):
 
581
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
 
582
                    (feature, count))
 
583
        result.finished()
 
584
        return result
800
585
 
801
586
 
802
587
def iter_suite_tests(suite):
812
597
                        % (type(suite), suite))
813
598
 
814
599
 
815
 
TestSkipped = testtools.testcase.TestSkipped
 
600
class TestSkipped(Exception):
 
601
    """Indicates that a test was intentionally skipped, rather than failing."""
816
602
 
817
603
 
818
604
class TestNotApplicable(TestSkipped):
824
610
    """
825
611
 
826
612
 
827
 
# traceback._some_str fails to format exceptions that have the default
828
 
# __str__ which does an implicit ascii conversion. However, repr() on those
829
 
# objects works, for all that its not quite what the doctor may have ordered.
830
 
def _clever_some_str(value):
831
 
    try:
832
 
        return str(value)
833
 
    except:
834
 
        try:
835
 
            return repr(value).replace('\\n', '\n')
836
 
        except:
837
 
            return '<unprintable %s object>' % type(value).__name__
838
 
 
839
 
traceback._some_str = _clever_some_str
840
 
 
841
 
 
842
 
# deprecated - use self.knownFailure(), or self.expectFailure.
843
 
KnownFailure = testtools.testcase._ExpectedFailure
 
613
class KnownFailure(AssertionError):
 
614
    """Indicates that a test failed in a precisely expected manner.
 
615
 
 
616
    Such failures dont block the whole test suite from passing because they are
 
617
    indicators of partially completed code or of future work. We have an
 
618
    explicit error for them so that we can ensure that they are always visible:
 
619
    KnownFailures are always shown in the output of bzr selftest.
 
620
    """
844
621
 
845
622
 
846
623
class UnavailableFeature(Exception):
847
624
    """A feature required for this test was not available.
848
625
 
849
 
    This can be considered a specialised form of SkippedTest.
850
 
 
851
626
    The feature should be used to construct the exception.
852
627
    """
853
628
 
854
629
 
 
630
class CommandFailed(Exception):
 
631
    pass
 
632
 
 
633
 
855
634
class StringIOWrapper(object):
856
635
    """A wrapper around cStringIO which just adds an encoding attribute.
857
636
 
878
657
            return setattr(self._cstring, name, val)
879
658
 
880
659
 
881
 
class TestUIFactory(TextUIFactory):
 
660
class TestUIFactory(ui.CLIUIFactory):
882
661
    """A UI Factory for testing.
883
662
 
884
663
    Hide the progress bar but emit note()s.
885
664
    Redirect stdin.
886
665
    Allows get_password to be tested without real tty attached.
887
 
 
888
 
    See also CannedInputUIFactory which lets you provide programmatic input in
889
 
    a structured way.
890
666
    """
891
 
    # TODO: Capture progress events at the model level and allow them to be
892
 
    # observed by tests that care.
893
 
    #
894
 
    # XXX: Should probably unify more with CannedInputUIFactory or a
895
 
    # particular configuration of TextUIFactory, or otherwise have a clearer
896
 
    # idea of how they're supposed to be different.
897
 
    # See https://bugs.launchpad.net/bzr/+bug/408213
898
667
 
899
 
    def __init__(self, stdout=None, stderr=None, stdin=None):
 
668
    def __init__(self,
 
669
                 stdout=None,
 
670
                 stderr=None,
 
671
                 stdin=None):
 
672
        super(TestUIFactory, self).__init__()
900
673
        if stdin is not None:
901
674
            # We use a StringIOWrapper to be able to test various
902
675
            # encodings, but the user is still responsible to
903
676
            # encode the string and to set the encoding attribute
904
677
            # of StringIOWrapper.
905
 
            stdin = StringIOWrapper(stdin)
906
 
        super(TestUIFactory, self).__init__(stdin, stdout, stderr)
907
 
 
908
 
    def get_non_echoed_password(self):
 
678
            self.stdin = StringIOWrapper(stdin)
 
679
        if stdout is None:
 
680
            self.stdout = sys.stdout
 
681
        else:
 
682
            self.stdout = stdout
 
683
        if stderr is None:
 
684
            self.stderr = sys.stderr
 
685
        else:
 
686
            self.stderr = stderr
 
687
 
 
688
    def clear(self):
 
689
        """See progress.ProgressBar.clear()."""
 
690
 
 
691
    def clear_term(self):
 
692
        """See progress.ProgressBar.clear_term()."""
 
693
 
 
694
    def clear_term(self):
 
695
        """See progress.ProgressBar.clear_term()."""
 
696
 
 
697
    def finished(self):
 
698
        """See progress.ProgressBar.finished()."""
 
699
 
 
700
    def note(self, fmt_string, *args, **kwargs):
 
701
        """See progress.ProgressBar.note()."""
 
702
        self.stdout.write((fmt_string + "\n") % args)
 
703
 
 
704
    def progress_bar(self):
 
705
        return self
 
706
 
 
707
    def nested_progress_bar(self):
 
708
        return self
 
709
 
 
710
    def update(self, message, count=None, total=None):
 
711
        """See progress.ProgressBar.update()."""
 
712
 
 
713
    def get_non_echoed_password(self, prompt):
909
714
        """Get password from stdin without trying to handle the echo mode"""
 
715
        if prompt:
 
716
            self.stdout.write(prompt.encode(self.stdout.encoding, 'replace'))
910
717
        password = self.stdin.readline()
911
718
        if not password:
912
719
            raise EOFError
914
721
            password = password[:-1]
915
722
        return password
916
723
 
917
 
    def make_progress_view(self):
918
 
        return NullProgressView()
919
 
 
920
 
 
921
 
def isolated_doctest_setUp(test):
922
 
    override_os_environ(test)
923
 
 
924
 
 
925
 
def isolated_doctest_tearDown(test):
926
 
    restore_os_environ(test)
927
 
 
928
 
 
929
 
def IsolatedDocTestSuite(*args, **kwargs):
930
 
    """Overrides doctest.DocTestSuite to handle isolation.
931
 
 
932
 
    The method is really a factory and users are expected to use it as such.
933
 
    """
934
 
 
935
 
    kwargs['setUp'] = isolated_doctest_setUp
936
 
    kwargs['tearDown'] = isolated_doctest_tearDown
937
 
    return doctest.DocTestSuite(*args, **kwargs)
938
 
 
939
 
 
940
 
class TestCase(testtools.TestCase):
 
724
 
 
725
def _report_leaked_threads():
 
726
    bzrlib.trace.warning('%s is leaking threads among %d leaking tests',
 
727
                         TestCase._first_thread_leaker_id,
 
728
                         TestCase._leaking_threads_tests)
 
729
 
 
730
 
 
731
class TestCase(unittest.TestCase):
941
732
    """Base class for bzr unit tests.
942
733
 
943
734
    Tests that need access to disk resources should subclass
953
744
    routine, and to build and check bzr trees.
954
745
 
955
746
    In addition to the usual method of overriding tearDown(), this class also
956
 
    allows subclasses to register cleanup functions via addCleanup, which are
 
747
    allows subclasses to register functions into the _cleanups list, which is
957
748
    run in order as the object is torn down.  It's less likely this will be
958
749
    accidentally overlooked.
959
750
    """
960
751
 
961
 
    _log_file = None
 
752
    _active_threads = None
 
753
    _leaking_threads_tests = 0
 
754
    _first_thread_leaker_id = None
 
755
    _log_file_name = None
 
756
    _log_contents = ''
 
757
    _keep_log_file = False
962
758
    # record lsprof data when performing benchmark calls.
963
759
    _gather_lsprof_in_benchmarks = False
 
760
    attrs_to_keep = ('id', '_testMethodName', '_testMethodDoc',
 
761
                     '_log_contents', '_log_file_name', '_benchtime',
 
762
                     '_TestCase__testMethodName')
964
763
 
965
764
    def __init__(self, methodName='testMethod'):
966
765
        super(TestCase, self).__init__(methodName)
967
 
        self._directory_isolation = True
968
 
        self.exception_handlers.insert(0,
969
 
            (UnavailableFeature, self._do_unsupported_or_skip))
970
 
        self.exception_handlers.insert(0,
971
 
            (TestNotApplicable, self._do_not_applicable))
 
766
        self._cleanups = []
 
767
        self._bzr_test_setUp_run = False
 
768
        self._bzr_test_tearDown_run = False
972
769
 
973
770
    def setUp(self):
974
 
        super(TestCase, self).setUp()
975
 
        for feature in getattr(self, '_test_needs_features', []):
976
 
            self.requireFeature(feature)
 
771
        unittest.TestCase.setUp(self)
 
772
        self._bzr_test_setUp_run = True
977
773
        self._cleanEnvironment()
978
774
        self._silenceUI()
979
775
        self._startLogFile()
980
776
        self._benchcalls = []
981
777
        self._benchtime = None
982
778
        self._clear_hooks()
983
 
        self._track_transports()
984
 
        self._track_locks()
985
779
        self._clear_debug_flags()
986
 
        # Isolate global verbosity level, to make sure it's reproducible
987
 
        # between tests.  We should get rid of this altogether: bug 656694. --
988
 
        # mbp 20101008
989
 
        self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
990
 
        # Isolate config option expansion until its default value for bzrlib is
991
 
        # settled on or a the FIXME associated with _get_expand_default_value
992
 
        # is addressed -- vila 20110219
993
 
        self.overrideAttr(config, '_expand_default_value', None)
994
 
        self._log_files = set()
995
 
        # Each key in the ``_counters`` dict holds a value for a different
996
 
        # counter. When the test ends, addDetail() should be used to output the
997
 
        # counter values. This happens in install_counter_hook().
998
 
        self._counters = {}
999
 
        if 'config_stats' in selftest_debug_flags:
1000
 
            self._install_config_stats_hooks()
 
780
        TestCase._active_threads = threading.activeCount()
 
781
        self.addCleanup(self._check_leaked_threads)
1001
782
 
1002
783
    def debug(self):
1003
784
        # debug a frame up.
1004
785
        import pdb
1005
786
        pdb.Pdb().set_trace(sys._getframe().f_back)
1006
787
 
1007
 
    def discardDetail(self, name):
1008
 
        """Extend the addDetail, getDetails api so we can remove a detail.
1009
 
 
1010
 
        eg. bzr always adds the 'log' detail at startup, but we don't want to
1011
 
        include it for skipped, xfail, etc tests.
1012
 
 
1013
 
        It is safe to call this for a detail that doesn't exist, in case this
1014
 
        gets called multiple times.
1015
 
        """
1016
 
        # We cheat. details is stored in __details which means we shouldn't
1017
 
        # touch it. but getDetails() returns the dict directly, so we can
1018
 
        # mutate it.
1019
 
        details = self.getDetails()
1020
 
        if name in details:
1021
 
            del details[name]
1022
 
 
1023
 
    def install_counter_hook(self, hooks, name, counter_name=None):
1024
 
        """Install a counting hook.
1025
 
 
1026
 
        Any hook can be counted as long as it doesn't need to return a value.
1027
 
 
1028
 
        :param hooks: Where the hook should be installed.
1029
 
 
1030
 
        :param name: The hook name that will be counted.
1031
 
 
1032
 
        :param counter_name: The counter identifier in ``_counters``, defaults
1033
 
            to ``name``.
1034
 
        """
1035
 
        _counters = self._counters # Avoid closing over self
1036
 
        if counter_name is None:
1037
 
            counter_name = name
1038
 
        if _counters.has_key(counter_name):
1039
 
            raise AssertionError('%s is already used as a counter name'
1040
 
                                  % (counter_name,))
1041
 
        _counters[counter_name] = 0
1042
 
        self.addDetail(counter_name, content.Content(content.UTF8_TEXT,
1043
 
            lambda: ['%d' % (_counters[counter_name],)]))
1044
 
        def increment_counter(*args, **kwargs):
1045
 
            _counters[counter_name] += 1
1046
 
        label = 'count %s calls' % (counter_name,)
1047
 
        hooks.install_named_hook(name, increment_counter, label)
1048
 
        self.addCleanup(hooks.uninstall_named_hook, name, label)
1049
 
 
1050
 
    def _install_config_stats_hooks(self):
1051
 
        """Install config hooks to count hook calls.
1052
 
 
1053
 
        """
1054
 
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1055
 
            self.install_counter_hook(config.ConfigHooks, hook_name,
1056
 
                                       'config.%s' % (hook_name,))
1057
 
 
1058
 
        # The OldConfigHooks are private and need special handling to protect
1059
 
        # against recursive tests (tests that run other tests), so we just do
1060
 
        # manually what registering them into _builtin_known_hooks will provide
1061
 
        # us.
1062
 
        self.overrideAttr(config, 'OldConfigHooks', config._OldConfigHooks())
1063
 
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1064
 
            self.install_counter_hook(config.OldConfigHooks, hook_name,
1065
 
                                      'old_config.%s' % (hook_name,))
 
788
    def exc_info(self):
 
789
        absent_attr = object()
 
790
        exc_info = getattr(self, '_exc_info', absent_attr)
 
791
        if exc_info is absent_attr:
 
792
            exc_info = getattr(self, '_TestCase__exc_info')
 
793
        return exc_info()
 
794
 
 
795
    def _check_leaked_threads(self):
 
796
        active = threading.activeCount()
 
797
        leaked_threads = active - TestCase._active_threads
 
798
        TestCase._active_threads = active
 
799
        if leaked_threads:
 
800
            TestCase._leaking_threads_tests += 1
 
801
            if TestCase._first_thread_leaker_id is None:
 
802
                TestCase._first_thread_leaker_id = self.id()
 
803
                # we're not specifically told when all tests are finished.
 
804
                # This will do. We use a function to avoid keeping a reference
 
805
                # to a TestCase object.
 
806
                atexit.register(_report_leaked_threads)
1066
807
 
1067
808
    def _clear_debug_flags(self):
1068
809
        """Prevent externally set debug flags affecting tests.
1070
811
        Tests that want to use debug flags can just set them in the
1071
812
        debug_flags set during setup/teardown.
1072
813
        """
1073
 
        # Start with a copy of the current debug flags we can safely modify.
1074
 
        self.overrideAttr(debug, 'debug_flags', set(debug.debug_flags))
 
814
        self._preserved_debug_flags = set(debug.debug_flags)
1075
815
        if 'allow_debug' not in selftest_debug_flags:
1076
816
            debug.debug_flags.clear()
1077
 
        if 'disable_lock_checks' not in selftest_debug_flags:
1078
 
            debug.debug_flags.add('strict_locks')
 
817
        self.addCleanup(self._restore_debug_flags)
1079
818
 
1080
819
    def _clear_hooks(self):
1081
820
        # prevent hooks affecting tests
1082
 
        known_hooks = hooks.known_hooks
1083
821
        self._preserved_hooks = {}
1084
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1085
 
            current_hooks = getattr(parent, name)
 
822
        for key, factory in hooks.known_hooks.items():
 
823
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
824
            current_hooks = hooks.known_hooks_key_to_object(key)
1086
825
            self._preserved_hooks[parent] = (name, current_hooks)
1087
 
        self._preserved_lazy_hooks = hooks._lazy_hooks
1088
 
        hooks._lazy_hooks = {}
1089
826
        self.addCleanup(self._restoreHooks)
1090
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1091
 
            factory = known_hooks.get(key)
 
827
        for key, factory in hooks.known_hooks.items():
 
828
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
1092
829
            setattr(parent, name, factory())
1093
830
        # this hook should always be installed
1094
831
        request._install_hook()
1095
832
 
1096
 
    def disable_directory_isolation(self):
1097
 
        """Turn off directory isolation checks."""
1098
 
        self._directory_isolation = False
1099
 
 
1100
 
    def enable_directory_isolation(self):
1101
 
        """Enable directory isolation checks."""
1102
 
        self._directory_isolation = True
1103
 
 
1104
833
    def _silenceUI(self):
1105
834
        """Turn off UI for duration of test"""
1106
835
        # by default the UI is off; tests can turn it on if they want it.
1107
 
        self.overrideAttr(ui, 'ui_factory', ui.SilentUIFactory())
1108
 
 
1109
 
    def _check_locks(self):
1110
 
        """Check that all lock take/release actions have been paired."""
1111
 
        # We always check for mismatched locks. If a mismatch is found, we
1112
 
        # fail unless -Edisable_lock_checks is supplied to selftest, in which
1113
 
        # case we just print a warning.
1114
 
        # unhook:
1115
 
        acquired_locks = [lock for action, lock in self._lock_actions
1116
 
                          if action == 'acquired']
1117
 
        released_locks = [lock for action, lock in self._lock_actions
1118
 
                          if action == 'released']
1119
 
        broken_locks = [lock for action, lock in self._lock_actions
1120
 
                        if action == 'broken']
1121
 
        # trivially, given the tests for lock acquistion and release, if we
1122
 
        # have as many in each list, it should be ok. Some lock tests also
1123
 
        # break some locks on purpose and should be taken into account by
1124
 
        # considering that breaking a lock is just a dirty way of releasing it.
1125
 
        if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
1126
 
            message = (
1127
 
                'Different number of acquired and '
1128
 
                'released or broken locks.\n'
1129
 
                'acquired=%s\n'
1130
 
                'released=%s\n'
1131
 
                'broken=%s\n' %
1132
 
                (acquired_locks, released_locks, broken_locks))
1133
 
            if not self._lock_check_thorough:
1134
 
                # Rather than fail, just warn
1135
 
                print "Broken test %s: %s" % (self, message)
1136
 
                return
1137
 
            self.fail(message)
1138
 
 
1139
 
    def _track_locks(self):
1140
 
        """Track lock activity during tests."""
1141
 
        self._lock_actions = []
1142
 
        if 'disable_lock_checks' in selftest_debug_flags:
1143
 
            self._lock_check_thorough = False
1144
 
        else:
1145
 
            self._lock_check_thorough = True
1146
 
 
1147
 
        self.addCleanup(self._check_locks)
1148
 
        _mod_lock.Lock.hooks.install_named_hook('lock_acquired',
1149
 
                                                self._lock_acquired, None)
1150
 
        _mod_lock.Lock.hooks.install_named_hook('lock_released',
1151
 
                                                self._lock_released, None)
1152
 
        _mod_lock.Lock.hooks.install_named_hook('lock_broken',
1153
 
                                                self._lock_broken, None)
1154
 
 
1155
 
    def _lock_acquired(self, result):
1156
 
        self._lock_actions.append(('acquired', result))
1157
 
 
1158
 
    def _lock_released(self, result):
1159
 
        self._lock_actions.append(('released', result))
1160
 
 
1161
 
    def _lock_broken(self, result):
1162
 
        self._lock_actions.append(('broken', result))
1163
 
 
1164
 
    def permit_dir(self, name):
1165
 
        """Permit a directory to be used by this test. See permit_url."""
1166
 
        name_transport = _mod_transport.get_transport(name)
1167
 
        self.permit_url(name)
1168
 
        self.permit_url(name_transport.base)
1169
 
 
1170
 
    def permit_url(self, url):
1171
 
        """Declare that url is an ok url to use in this test.
1172
 
        
1173
 
        Do this for memory transports, temporary test directory etc.
1174
 
        
1175
 
        Do not do this for the current working directory, /tmp, or any other
1176
 
        preexisting non isolated url.
1177
 
        """
1178
 
        if not url.endswith('/'):
1179
 
            url += '/'
1180
 
        self._bzr_selftest_roots.append(url)
1181
 
 
1182
 
    def permit_source_tree_branch_repo(self):
1183
 
        """Permit the source tree bzr is running from to be opened.
1184
 
 
1185
 
        Some code such as bzrlib.version attempts to read from the bzr branch
1186
 
        that bzr is executing from (if any). This method permits that directory
1187
 
        to be used in the test suite.
1188
 
        """
1189
 
        path = self.get_source_path()
1190
 
        self.record_directory_isolation()
1191
 
        try:
1192
 
            try:
1193
 
                workingtree.WorkingTree.open(path)
1194
 
            except (errors.NotBranchError, errors.NoWorkingTree):
1195
 
                raise TestSkipped('Needs a working tree of bzr sources')
1196
 
        finally:
1197
 
            self.enable_directory_isolation()
1198
 
 
1199
 
    def _preopen_isolate_transport(self, transport):
1200
 
        """Check that all transport openings are done in the test work area."""
1201
 
        while isinstance(transport, pathfilter.PathFilteringTransport):
1202
 
            # Unwrap pathfiltered transports
1203
 
            transport = transport.server.backing_transport.clone(
1204
 
                transport._filter('.'))
1205
 
        url = transport.base
1206
 
        # ReadonlySmartTCPServer_for_testing decorates the backing transport
1207
 
        # urls it is given by prepending readonly+. This is appropriate as the
1208
 
        # client shouldn't know that the server is readonly (or not readonly).
1209
 
        # We could register all servers twice, with readonly+ prepending, but
1210
 
        # that makes for a long list; this is about the same but easier to
1211
 
        # read.
1212
 
        if url.startswith('readonly+'):
1213
 
            url = url[len('readonly+'):]
1214
 
        self._preopen_isolate_url(url)
1215
 
 
1216
 
    def _preopen_isolate_url(self, url):
1217
 
        if not self._directory_isolation:
1218
 
            return
1219
 
        if self._directory_isolation == 'record':
1220
 
            self._bzr_selftest_roots.append(url)
1221
 
            return
1222
 
        # This prevents all transports, including e.g. sftp ones backed on disk
1223
 
        # from working unless they are explicitly granted permission. We then
1224
 
        # depend on the code that sets up test transports to check that they are
1225
 
        # appropriately isolated and enable their use by calling
1226
 
        # self.permit_transport()
1227
 
        if not osutils.is_inside_any(self._bzr_selftest_roots, url):
1228
 
            raise errors.BzrError("Attempt to escape test isolation: %r %r"
1229
 
                % (url, self._bzr_selftest_roots))
1230
 
 
1231
 
    def record_directory_isolation(self):
1232
 
        """Gather accessed directories to permit later access.
1233
 
        
1234
 
        This is used for tests that access the branch bzr is running from.
1235
 
        """
1236
 
        self._directory_isolation = "record"
1237
 
 
1238
 
    def start_server(self, transport_server, backing_server=None):
1239
 
        """Start transport_server for this test.
1240
 
 
1241
 
        This starts the server, registers a cleanup for it and permits the
1242
 
        server's urls to be used.
1243
 
        """
1244
 
        if backing_server is None:
1245
 
            transport_server.start_server()
1246
 
        else:
1247
 
            transport_server.start_server(backing_server)
1248
 
        self.addCleanup(transport_server.stop_server)
1249
 
        # Obtain a real transport because if the server supplies a password, it
1250
 
        # will be hidden from the base on the client side.
1251
 
        t = _mod_transport.get_transport(transport_server.get_url())
1252
 
        # Some transport servers effectively chroot the backing transport;
1253
 
        # others like SFTPServer don't - users of the transport can walk up the
1254
 
        # transport to read the entire backing transport. This wouldn't matter
1255
 
        # except that the workdir tests are given - and that they expect the
1256
 
        # server's url to point at - is one directory under the safety net. So
1257
 
        # Branch operations into the transport will attempt to walk up one
1258
 
        # directory. Chrooting all servers would avoid this but also mean that
1259
 
        # we wouldn't be testing directly against non-root urls. Alternatively
1260
 
        # getting the test framework to start the server with a backing server
1261
 
        # at the actual safety net directory would work too, but this then
1262
 
        # means that the self.get_url/self.get_transport methods would need
1263
 
        # to transform all their results. On balance its cleaner to handle it
1264
 
        # here, and permit a higher url when we have one of these transports.
1265
 
        if t.base.endswith('/work/'):
1266
 
            # we have safety net/test root/work
1267
 
            t = t.clone('../..')
1268
 
        elif isinstance(transport_server,
1269
 
                        test_server.SmartTCPServer_for_testing):
1270
 
            # The smart server adds a path similar to work, which is traversed
1271
 
            # up from by the client. But the server is chrooted - the actual
1272
 
            # backing transport is not escaped from, and VFS requests to the
1273
 
            # root will error (because they try to escape the chroot).
1274
 
            t2 = t.clone('..')
1275
 
            while t2.base != t.base:
1276
 
                t = t2
1277
 
                t2 = t.clone('..')
1278
 
        self.permit_url(t.base)
1279
 
 
1280
 
    def _track_transports(self):
1281
 
        """Install checks for transport usage."""
1282
 
        # TestCase has no safe place it can write to.
1283
 
        self._bzr_selftest_roots = []
1284
 
        # Currently the easiest way to be sure that nothing is going on is to
1285
 
        # hook into bzr dir opening. This leaves a small window of error for
1286
 
        # transport tests, but they are well known, and we can improve on this
1287
 
        # step.
1288
 
        bzrdir.BzrDir.hooks.install_named_hook("pre_open",
1289
 
            self._preopen_isolate_transport, "Check bzr directories are safe.")
 
836
        saved = ui.ui_factory
 
837
        def _restore():
 
838
            ui.ui_factory = saved
 
839
        ui.ui_factory = ui.SilentUIFactory()
 
840
        self.addCleanup(_restore)
1290
841
 
1291
842
    def _ndiff_strings(self, a, b):
1292
843
        """Return ndiff between two strings containing lines.
1310
861
        except UnicodeError, e:
1311
862
            # If we can't compare without getting a UnicodeError, then
1312
863
            # obviously they are different
1313
 
            trace.mutter('UnicodeError: %s', e)
 
864
            mutter('UnicodeError: %s', e)
1314
865
        if message:
1315
866
            message += '\n'
1316
867
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1317
868
            % (message,
1318
 
               pprint.pformat(a), pprint.pformat(b)))
 
869
               pformat(a), pformat(b)))
1319
870
 
1320
871
    assertEquals = assertEqual
1321
872
 
1330
881
            return
1331
882
        if message is None:
1332
883
            message = "texts not equal:\n"
 
884
        if a == b + '\n':
 
885
            message = 'first string is missing a final newline.\n'
1333
886
        if a + '\n' == b:
1334
 
            message = 'first string is missing a final newline.\n'
1335
 
        if a == b + '\n':
1336
887
            message = 'second string is missing a final newline.\n'
1337
888
        raise AssertionError(message +
1338
889
                             self._ndiff_strings(a, b))
1349
900
        :raises AssertionError: If the expected and actual stat values differ
1350
901
            other than by atime.
1351
902
        """
1352
 
        self.assertEqual(expected.st_size, actual.st_size,
1353
 
                         'st_size did not match')
1354
 
        self.assertEqual(expected.st_mtime, actual.st_mtime,
1355
 
                         'st_mtime did not match')
1356
 
        self.assertEqual(expected.st_ctime, actual.st_ctime,
1357
 
                         'st_ctime did not match')
1358
 
        if sys.platform == 'win32':
1359
 
            # On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1360
 
            # is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
1361
 
            # odd. We just force it to always be 0 to avoid any problems.
1362
 
            self.assertEqual(0, expected.st_dev)
1363
 
            self.assertEqual(0, actual.st_dev)
1364
 
            self.assertEqual(0, expected.st_ino)
1365
 
            self.assertEqual(0, actual.st_ino)
1366
 
        else:
1367
 
            self.assertEqual(expected.st_dev, actual.st_dev,
1368
 
                             'st_dev did not match')
1369
 
            self.assertEqual(expected.st_ino, actual.st_ino,
1370
 
                             'st_ino did not match')
1371
 
        self.assertEqual(expected.st_mode, actual.st_mode,
1372
 
                         'st_mode did not match')
 
903
        self.assertEqual(expected.st_size, actual.st_size)
 
904
        self.assertEqual(expected.st_mtime, actual.st_mtime)
 
905
        self.assertEqual(expected.st_ctime, actual.st_ctime)
 
906
        self.assertEqual(expected.st_dev, actual.st_dev)
 
907
        self.assertEqual(expected.st_ino, actual.st_ino)
 
908
        self.assertEqual(expected.st_mode, actual.st_mode)
1373
909
 
1374
910
    def assertLength(self, length, obj_with_len):
1375
911
        """Assert that obj_with_len is of length length."""
1377
913
            self.fail("Incorrect length: wanted %d, got %d for %r" % (
1378
914
                length, len(obj_with_len), obj_with_len))
1379
915
 
1380
 
    def assertLogsError(self, exception_class, func, *args, **kwargs):
1381
 
        """Assert that `func(*args, **kwargs)` quietly logs a specific error.
1382
 
        """
1383
 
        captured = []
1384
 
        orig_log_exception_quietly = trace.log_exception_quietly
1385
 
        try:
1386
 
            def capture():
1387
 
                orig_log_exception_quietly()
1388
 
                captured.append(sys.exc_info()[1])
1389
 
            trace.log_exception_quietly = capture
1390
 
            func(*args, **kwargs)
1391
 
        finally:
1392
 
            trace.log_exception_quietly = orig_log_exception_quietly
1393
 
        self.assertLength(1, captured)
1394
 
        err = captured[0]
1395
 
        self.assertIsInstance(err, exception_class)
1396
 
        return err
1397
 
 
1398
916
    def assertPositive(self, val):
1399
917
        """Assert that val is greater than 0."""
1400
918
        self.assertTrue(val > 0, 'expected a positive value, but got %s' % val)
1430
948
            raise AssertionError('pattern "%s" found in "%s"'
1431
949
                    % (needle_re, haystack))
1432
950
 
1433
 
    def assertContainsString(self, haystack, needle):
1434
 
        if haystack.find(needle) == -1:
1435
 
            self.fail("string %r not found in '''%s'''" % (needle, haystack))
1436
 
 
1437
 
    def assertNotContainsString(self, haystack, needle):
1438
 
        if haystack.find(needle) != -1:
1439
 
            self.fail("string %r found in '''%s'''" % (needle, haystack))
1440
 
 
1441
951
    def assertSubset(self, sublist, superlist):
1442
952
        """Assert that every entry in sublist is present in superlist."""
1443
953
        missing = set(sublist) - set(superlist)
1500
1010
                raise AssertionError("%r is %r." % (left, right))
1501
1011
 
1502
1012
    def assertTransportMode(self, transport, path, mode):
1503
 
        """Fail if a path does not have mode "mode".
 
1013
        """Fail if a path does not have mode mode.
1504
1014
 
1505
1015
        If modes are not supported on this transport, the assertion is ignored.
1506
1016
        """
1518
1028
                         osutils.realpath(path2),
1519
1029
                         "apparent paths:\na = %s\nb = %s\n," % (path1, path2))
1520
1030
 
1521
 
    def assertIsInstance(self, obj, kls, msg=None):
1522
 
        """Fail if obj is not an instance of kls
1523
 
        
1524
 
        :param msg: Supplementary message to show if the assertion fails.
1525
 
        """
 
1031
    def assertIsInstance(self, obj, kls):
 
1032
        """Fail if obj is not an instance of kls"""
1526
1033
        if not isinstance(obj, kls):
1527
 
            m = "%r is an instance of %s rather than %s" % (
1528
 
                obj, obj.__class__, kls)
1529
 
            if msg:
1530
 
                m += ": " + msg
1531
 
            self.fail(m)
 
1034
            self.fail("%r is an instance of %s rather than %s" % (
 
1035
                obj, obj.__class__, kls))
 
1036
 
 
1037
    def expectFailure(self, reason, assertion, *args, **kwargs):
 
1038
        """Invoke a test, expecting it to fail for the given reason.
 
1039
 
 
1040
        This is for assertions that ought to succeed, but currently fail.
 
1041
        (The failure is *expected* but not *wanted*.)  Please be very precise
 
1042
        about the failure you're expecting.  If a new bug is introduced,
 
1043
        AssertionError should be raised, not KnownFailure.
 
1044
 
 
1045
        Frequently, expectFailure should be followed by an opposite assertion.
 
1046
        See example below.
 
1047
 
 
1048
        Intended to be used with a callable that raises AssertionError as the
 
1049
        'assertion' parameter.  args and kwargs are passed to the 'assertion'.
 
1050
 
 
1051
        Raises KnownFailure if the test fails.  Raises AssertionError if the
 
1052
        test succeeds.
 
1053
 
 
1054
        example usage::
 
1055
 
 
1056
          self.expectFailure('Math is broken', self.assertNotEqual, 54,
 
1057
                             dynamic_val)
 
1058
          self.assertEqual(42, dynamic_val)
 
1059
 
 
1060
          This means that a dynamic_val of 54 will cause the test to raise
 
1061
          a KnownFailure.  Once math is fixed and the expectFailure is removed,
 
1062
          only a dynamic_val of 42 will allow the test to pass.  Anything other
 
1063
          than 54 or 42 will cause an AssertionError.
 
1064
        """
 
1065
        try:
 
1066
            assertion(*args, **kwargs)
 
1067
        except AssertionError:
 
1068
            raise KnownFailure(reason)
 
1069
        else:
 
1070
            self.fail('Unexpected success.  Should have failed: %s' % reason)
1532
1071
 
1533
1072
    def assertFileEqual(self, content, path):
1534
1073
        """Fail if path does not contain 'content'."""
1535
 
        self.assertPathExists(path)
 
1074
        self.failUnlessExists(path)
1536
1075
        f = file(path, 'rb')
1537
1076
        try:
1538
1077
            s = f.read()
1540
1079
            f.close()
1541
1080
        self.assertEqualDiff(content, s)
1542
1081
 
1543
 
    def assertDocstring(self, expected_docstring, obj):
1544
 
        """Fail if obj does not have expected_docstring"""
1545
 
        if __doc__ is None:
1546
 
            # With -OO the docstring should be None instead
1547
 
            self.assertIs(obj.__doc__, None)
1548
 
        else:
1549
 
            self.assertEqual(expected_docstring, obj.__doc__)
1550
 
 
1551
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1552
1082
    def failUnlessExists(self, path):
1553
 
        return self.assertPathExists(path)
1554
 
 
1555
 
    def assertPathExists(self, path):
1556
1083
        """Fail unless path or paths, which may be abs or relative, exist."""
1557
1084
        if not isinstance(path, basestring):
1558
1085
            for p in path:
1559
 
                self.assertPathExists(p)
 
1086
                self.failUnlessExists(p)
1560
1087
        else:
1561
 
            self.assertTrue(osutils.lexists(path),
1562
 
                path + " does not exist")
 
1088
            self.failUnless(osutils.lexists(path),path+" does not exist")
1563
1089
 
1564
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1565
1090
    def failIfExists(self, path):
1566
 
        return self.assertPathDoesNotExist(path)
1567
 
 
1568
 
    def assertPathDoesNotExist(self, path):
1569
1091
        """Fail if path or paths, which may be abs or relative, exist."""
1570
1092
        if not isinstance(path, basestring):
1571
1093
            for p in path:
1572
 
                self.assertPathDoesNotExist(p)
 
1094
                self.failIfExists(p)
1573
1095
        else:
1574
 
            self.assertFalse(osutils.lexists(path),
1575
 
                path + " exists")
 
1096
            self.failIf(osutils.lexists(path),path+" exists")
1576
1097
 
1577
1098
    def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
1578
1099
        """A helper for callDeprecated and applyDeprecated.
1604
1125
        not other callers that go direct to the warning module.
1605
1126
 
1606
1127
        To test that a deprecated method raises an error, do something like
1607
 
        this (remember that both assertRaises and applyDeprecated delays *args
1608
 
        and **kwargs passing)::
 
1128
        this::
1609
1129
 
1610
1130
            self.assertRaises(errors.ReservedId,
1611
1131
                self.applyDeprecated,
1693
1213
 
1694
1214
        The file is removed as the test is torn down.
1695
1215
        """
1696
 
        pseudo_log_file = StringIO()
1697
 
        def _get_log_contents_for_weird_testtools_api():
1698
 
            return [pseudo_log_file.getvalue().decode(
1699
 
                "utf-8", "replace").encode("utf-8")]
1700
 
        self.addDetail("log", content.Content(content.ContentType("text",
1701
 
            "plain", {"charset": "utf8"}),
1702
 
            _get_log_contents_for_weird_testtools_api))
1703
 
        self._log_file = pseudo_log_file
1704
 
        self._log_memento = trace.push_log_file(self._log_file)
 
1216
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
 
1217
        self._log_file = os.fdopen(fileno, 'w+')
 
1218
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
 
1219
        self._log_file_name = name
1705
1220
        self.addCleanup(self._finishLogFile)
1706
1221
 
1707
1222
    def _finishLogFile(self):
1708
1223
        """Finished with the log file.
1709
1224
 
1710
 
        Close the file and delete it.
1711
 
        """
1712
 
        if trace._trace_file:
1713
 
            # flush the log file, to get all content
1714
 
            trace._trace_file.flush()
1715
 
        trace.pop_log_file(self._log_memento)
1716
 
 
1717
 
    def thisFailsStrictLockCheck(self):
1718
 
        """It is known that this test would fail with -Dstrict_locks.
1719
 
 
1720
 
        By default, all tests are run with strict lock checking unless
1721
 
        -Edisable_lock_checks is supplied. However there are some tests which
1722
 
        we know fail strict locks at this point that have not been fixed.
1723
 
        They should call this function to disable the strict checking.
1724
 
 
1725
 
        This should be used sparingly, it is much better to fix the locking
1726
 
        issues rather than papering over the problem by calling this function.
1727
 
        """
1728
 
        debug.debug_flags.discard('strict_locks')
1729
 
 
1730
 
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1731
 
        """Overrides an object attribute restoring it after the test.
1732
 
 
1733
 
        :param obj: The object that will be mutated.
1734
 
 
1735
 
        :param attr_name: The attribute name we want to preserve/override in
1736
 
            the object.
1737
 
 
1738
 
        :param new: The optional value we want to set the attribute to.
1739
 
 
1740
 
        :returns: The actual attr value.
1741
 
        """
1742
 
        value = getattr(obj, attr_name)
1743
 
        # The actual value is captured by the call below
1744
 
        self.addCleanup(setattr, obj, attr_name, value)
1745
 
        if new is not _unitialized_attr:
1746
 
            setattr(obj, attr_name, new)
1747
 
        return value
1748
 
 
1749
 
    def overrideEnv(self, name, new):
1750
 
        """Set an environment variable, and reset it after the test.
1751
 
 
1752
 
        :param name: The environment variable name.
1753
 
 
1754
 
        :param new: The value to set the variable to. If None, the 
1755
 
            variable is deleted from the environment.
1756
 
 
1757
 
        :returns: The actual variable value.
1758
 
        """
1759
 
        value = osutils.set_or_unset_env(name, new)
1760
 
        self.addCleanup(osutils.set_or_unset_env, name, value)
1761
 
        return value
 
1225
        Close the file and delete it, unless setKeepLogfile was called.
 
1226
        """
 
1227
        if self._log_file is None:
 
1228
            return
 
1229
        bzrlib.trace.pop_log_file(self._log_memento)
 
1230
        self._log_file.close()
 
1231
        self._log_file = None
 
1232
        if not self._keep_log_file:
 
1233
            os.remove(self._log_file_name)
 
1234
            self._log_file_name = None
 
1235
 
 
1236
    def setKeepLogfile(self):
 
1237
        """Make the logfile not be deleted when _finishLogFile is called."""
 
1238
        self._keep_log_file = True
 
1239
 
 
1240
    def addCleanup(self, callable, *args, **kwargs):
 
1241
        """Arrange to run a callable when this case is torn down.
 
1242
 
 
1243
        Callables are run in the reverse of the order they are registered,
 
1244
        ie last-in first-out.
 
1245
        """
 
1246
        self._cleanups.append((callable, args, kwargs))
1762
1247
 
1763
1248
    def _cleanEnvironment(self):
1764
 
        for name, value in isolated_environ.iteritems():
1765
 
            self.overrideEnv(name, value)
 
1249
        new_env = {
 
1250
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
 
1251
            'HOME': os.getcwd(),
 
1252
            # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
 
1253
            # tests do check our impls match APPDATA
 
1254
            'BZR_EDITOR': None, # test_msgeditor manipulates this variable
 
1255
            'VISUAL': None,
 
1256
            'EDITOR': None,
 
1257
            'BZR_EMAIL': None,
 
1258
            'BZREMAIL': None, # may still be present in the environment
 
1259
            'EMAIL': None,
 
1260
            'BZR_PROGRESS_BAR': None,
 
1261
            'BZR_LOG': None,
 
1262
            'BZR_PLUGIN_PATH': None,
 
1263
            # SSH Agent
 
1264
            'SSH_AUTH_SOCK': None,
 
1265
            # Proxies
 
1266
            'http_proxy': None,
 
1267
            'HTTP_PROXY': None,
 
1268
            'https_proxy': None,
 
1269
            'HTTPS_PROXY': None,
 
1270
            'no_proxy': None,
 
1271
            'NO_PROXY': None,
 
1272
            'all_proxy': None,
 
1273
            'ALL_PROXY': None,
 
1274
            # Nobody cares about these ones AFAIK. So far at
 
1275
            # least. If you do (care), please update this comment
 
1276
            # -- vila 20061212
 
1277
            'ftp_proxy': None,
 
1278
            'FTP_PROXY': None,
 
1279
            'BZR_REMOTE_PATH': None,
 
1280
        }
 
1281
        self.__old_env = {}
 
1282
        self.addCleanup(self._restoreEnvironment)
 
1283
        for name, value in new_env.iteritems():
 
1284
            self._captureVar(name, value)
 
1285
 
 
1286
    def _captureVar(self, name, newvalue):
 
1287
        """Set an environment variable, and reset it when finished."""
 
1288
        self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
 
1289
 
 
1290
    def _restore_debug_flags(self):
 
1291
        debug.debug_flags.clear()
 
1292
        debug.debug_flags.update(self._preserved_debug_flags)
 
1293
 
 
1294
    def _restoreEnvironment(self):
 
1295
        for name, value in self.__old_env.iteritems():
 
1296
            osutils.set_or_unset_env(name, value)
1766
1297
 
1767
1298
    def _restoreHooks(self):
1768
1299
        for klass, (name, hooks) in self._preserved_hooks.items():
1769
1300
            setattr(klass, name, hooks)
1770
 
        self._preserved_hooks.clear()
1771
 
        bzrlib.hooks._lazy_hooks = self._preserved_lazy_hooks
1772
 
        self._preserved_lazy_hooks.clear()
1773
1301
 
1774
1302
    def knownFailure(self, reason):
1775
1303
        """This test has failed for some known reason."""
1776
1304
        raise KnownFailure(reason)
1777
1305
 
1778
 
    def _suppress_log(self):
1779
 
        """Remove the log info from details."""
1780
 
        self.discardDetail('log')
1781
 
 
1782
1306
    def _do_skip(self, result, reason):
1783
 
        self._suppress_log()
1784
1307
        addSkip = getattr(result, 'addSkip', None)
1785
1308
        if not callable(addSkip):
1786
 
            result.addSuccess(result)
 
1309
            result.addError(self, self.exc_info())
1787
1310
        else:
1788
1311
            addSkip(self, reason)
1789
1312
 
1790
 
    @staticmethod
1791
 
    def _do_known_failure(self, result, e):
1792
 
        self._suppress_log()
1793
 
        err = sys.exc_info()
1794
 
        addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1795
 
        if addExpectedFailure is not None:
1796
 
            addExpectedFailure(self, err)
1797
 
        else:
1798
 
            result.addSuccess(self)
1799
 
 
1800
 
    @staticmethod
1801
 
    def _do_not_applicable(self, result, e):
1802
 
        if not e.args:
1803
 
            reason = 'No reason given'
1804
 
        else:
1805
 
            reason = e.args[0]
1806
 
        self._suppress_log ()
1807
 
        addNotApplicable = getattr(result, 'addNotApplicable', None)
1808
 
        if addNotApplicable is not None:
1809
 
            result.addNotApplicable(self, reason)
1810
 
        else:
1811
 
            self._do_skip(result, reason)
1812
 
 
1813
 
    @staticmethod
1814
 
    def _report_skip(self, result, err):
1815
 
        """Override the default _report_skip.
1816
 
 
1817
 
        We want to strip the 'log' detail. If we waint until _do_skip, it has
1818
 
        already been formatted into the 'reason' string, and we can't pull it
1819
 
        out again.
1820
 
        """
1821
 
        self._suppress_log()
1822
 
        super(TestCase, self)._report_skip(self, result, err)
1823
 
 
1824
 
    @staticmethod
1825
 
    def _report_expected_failure(self, result, err):
1826
 
        """Strip the log.
1827
 
 
1828
 
        See _report_skip for motivation.
1829
 
        """
1830
 
        self._suppress_log()
1831
 
        super(TestCase, self)._report_expected_failure(self, result, err)
1832
 
 
1833
 
    @staticmethod
1834
 
    def _do_unsupported_or_skip(self, result, e):
1835
 
        reason = e.args[0]
1836
 
        self._suppress_log()
1837
 
        addNotSupported = getattr(result, 'addNotSupported', None)
1838
 
        if addNotSupported is not None:
1839
 
            result.addNotSupported(self, reason)
1840
 
        else:
1841
 
            self._do_skip(result, reason)
 
1313
    def run(self, result=None):
 
1314
        if result is None: result = self.defaultTestResult()
 
1315
        for feature in getattr(self, '_test_needs_features', []):
 
1316
            if not feature.available():
 
1317
                result.startTest(self)
 
1318
                if getattr(result, 'addNotSupported', None):
 
1319
                    result.addNotSupported(self, feature)
 
1320
                else:
 
1321
                    result.addSuccess(self)
 
1322
                result.stopTest(self)
 
1323
                return
 
1324
        try:
 
1325
            try:
 
1326
                result.startTest(self)
 
1327
                absent_attr = object()
 
1328
                # Python 2.5
 
1329
                method_name = getattr(self, '_testMethodName', absent_attr)
 
1330
                if method_name is absent_attr:
 
1331
                    # Python 2.4
 
1332
                    method_name = getattr(self, '_TestCase__testMethodName')
 
1333
                testMethod = getattr(self, method_name)
 
1334
                try:
 
1335
                    try:
 
1336
                        self.setUp()
 
1337
                        if not self._bzr_test_setUp_run:
 
1338
                            self.fail(
 
1339
                                "test setUp did not invoke "
 
1340
                                "bzrlib.tests.TestCase's setUp")
 
1341
                    except KeyboardInterrupt:
 
1342
                        raise
 
1343
                    except TestSkipped, e:
 
1344
                        self._do_skip(result, e.args[0])
 
1345
                        self.tearDown()
 
1346
                        return
 
1347
                    except:
 
1348
                        result.addError(self, self.exc_info())
 
1349
                        return
 
1350
 
 
1351
                    ok = False
 
1352
                    try:
 
1353
                        testMethod()
 
1354
                        ok = True
 
1355
                    except self.failureException:
 
1356
                        result.addFailure(self, self.exc_info())
 
1357
                    except TestSkipped, e:
 
1358
                        if not e.args:
 
1359
                            reason = "No reason given."
 
1360
                        else:
 
1361
                            reason = e.args[0]
 
1362
                        self._do_skip(result, reason)
 
1363
                    except KeyboardInterrupt:
 
1364
                        raise
 
1365
                    except:
 
1366
                        result.addError(self, self.exc_info())
 
1367
 
 
1368
                    try:
 
1369
                        self.tearDown()
 
1370
                        if not self._bzr_test_tearDown_run:
 
1371
                            self.fail(
 
1372
                                "test tearDown did not invoke "
 
1373
                                "bzrlib.tests.TestCase's tearDown")
 
1374
                    except KeyboardInterrupt:
 
1375
                        raise
 
1376
                    except:
 
1377
                        result.addError(self, self.exc_info())
 
1378
                        ok = False
 
1379
                    if ok: result.addSuccess(self)
 
1380
                finally:
 
1381
                    result.stopTest(self)
 
1382
                return
 
1383
            except TestNotApplicable:
 
1384
                # Not moved from the result [yet].
 
1385
                raise
 
1386
            except KeyboardInterrupt:
 
1387
                raise
 
1388
        finally:
 
1389
            saved_attrs = {}
 
1390
            absent_attr = object()
 
1391
            for attr_name in self.attrs_to_keep:
 
1392
                attr = getattr(self, attr_name, absent_attr)
 
1393
                if attr is not absent_attr:
 
1394
                    saved_attrs[attr_name] = attr
 
1395
            self.__dict__ = saved_attrs
 
1396
 
 
1397
    def tearDown(self):
 
1398
        self._bzr_test_tearDown_run = True
 
1399
        self._runCleanups()
 
1400
        self._log_contents = ''
 
1401
        unittest.TestCase.tearDown(self)
1842
1402
 
1843
1403
    def time(self, callable, *args, **kwargs):
1844
1404
        """Run callable and accrue the time it takes to the benchmark time.
1848
1408
        self._benchcalls.
1849
1409
        """
1850
1410
        if self._benchtime is None:
1851
 
            self.addDetail('benchtime', content.Content(content.ContentType(
1852
 
                "text", "plain"), lambda:[str(self._benchtime)]))
1853
1411
            self._benchtime = 0
1854
1412
        start = time.time()
1855
1413
        try:
1864
1422
        finally:
1865
1423
            self._benchtime += time.time() - start
1866
1424
 
 
1425
    def _runCleanups(self):
 
1426
        """Run registered cleanup functions.
 
1427
 
 
1428
        This should only be called from TestCase.tearDown.
 
1429
        """
 
1430
        # TODO: Perhaps this should keep running cleanups even if
 
1431
        # one of them fails?
 
1432
 
 
1433
        # Actually pop the cleanups from the list so tearDown running
 
1434
        # twice is safe (this happens for skipped tests).
 
1435
        while self._cleanups:
 
1436
            cleanup, args, kwargs = self._cleanups.pop()
 
1437
            cleanup(*args, **kwargs)
 
1438
 
1867
1439
    def log(self, *args):
1868
 
        trace.mutter(*args)
1869
 
 
1870
 
    def get_log(self):
1871
 
        """Get a unicode string containing the log from bzrlib.trace.
1872
 
 
1873
 
        Undecodable characters are replaced.
 
1440
        mutter(*args)
 
1441
 
 
1442
    def _get_log(self, keep_log_file=False):
 
1443
        """Get the log from bzrlib.trace calls from this test.
 
1444
 
 
1445
        :param keep_log_file: When True, if the log is still a file on disk
 
1446
            leave it as a file on disk. When False, if the log is still a file
 
1447
            on disk, the log file is deleted and the log preserved as
 
1448
            self._log_contents.
 
1449
        :return: A string containing the log.
1874
1450
        """
1875
 
        return u"".join(self.getDetails()['log'].iter_text())
 
1451
        # flush the log file, to get all content
 
1452
        import bzrlib.trace
 
1453
        if bzrlib.trace._trace_file:
 
1454
            bzrlib.trace._trace_file.flush()
 
1455
        if self._log_contents:
 
1456
            # XXX: this can hardly contain the content flushed above --vila
 
1457
            # 20080128
 
1458
            return self._log_contents
 
1459
        if self._log_file_name is not None:
 
1460
            logfile = open(self._log_file_name)
 
1461
            try:
 
1462
                log_contents = logfile.read()
 
1463
            finally:
 
1464
                logfile.close()
 
1465
            if not keep_log_file:
 
1466
                self._log_contents = log_contents
 
1467
                try:
 
1468
                    os.remove(self._log_file_name)
 
1469
                except OSError, e:
 
1470
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
 
1471
                        sys.stderr.write(('Unable to delete log file '
 
1472
                                             ' %r\n' % self._log_file_name))
 
1473
                    else:
 
1474
                        raise
 
1475
            return log_contents
 
1476
        else:
 
1477
            return "DELETED log file to reduce memory footprint"
1876
1478
 
1877
1479
    def requireFeature(self, feature):
1878
1480
        """This test requires a specific feature is available.
1895
1497
 
1896
1498
    def _run_bzr_core(self, args, retcode, encoding, stdin,
1897
1499
            working_dir):
1898
 
        # Clear chk_map page cache, because the contents are likely to mask
1899
 
        # locking errors.
1900
 
        chk_map.clear_cache()
1901
1500
        if encoding is None:
1902
1501
            encoding = osutils.get_user_encoding()
1903
1502
        stdout = StringIOWrapper()
1920
1519
            os.chdir(working_dir)
1921
1520
 
1922
1521
        try:
1923
 
            try:
1924
 
                result = self.apply_redirected(
1925
 
                    ui.ui_factory.stdin,
1926
 
                    stdout, stderr,
1927
 
                    _mod_commands.run_bzr_catch_user_errors,
1928
 
                    args)
1929
 
            except KeyboardInterrupt:
1930
 
                # Reraise KeyboardInterrupt with contents of redirected stdout
1931
 
                # and stderr as arguments, for tests which are interested in
1932
 
                # stdout and stderr and are expecting the exception.
1933
 
                out = stdout.getvalue()
1934
 
                err = stderr.getvalue()
1935
 
                if out:
1936
 
                    self.log('output:\n%r', out)
1937
 
                if err:
1938
 
                    self.log('errors:\n%r', err)
1939
 
                raise KeyboardInterrupt(out, err)
 
1522
            result = self.apply_redirected(ui.ui_factory.stdin,
 
1523
                stdout, stderr,
 
1524
                bzrlib.commands.run_bzr_catch_user_errors,
 
1525
                args)
1940
1526
        finally:
1941
1527
            logger.removeHandler(handler)
1942
1528
            ui.ui_factory = old_ui_factory
1952
1538
        if retcode is not None:
1953
1539
            self.assertEquals(retcode, result,
1954
1540
                              message='Unexpected return code')
1955
 
        return result, out, err
 
1541
        return out, err
1956
1542
 
1957
1543
    def run_bzr(self, args, retcode=0, encoding=None, stdin=None,
1958
1544
                working_dir=None, error_regexes=[], output_encoding=None):
1987
1573
        :keyword error_regexes: A list of expected error messages.  If
1988
1574
            specified they must be seen in the error output of the command.
1989
1575
        """
1990
 
        retcode, out, err = self._run_bzr_autosplit(
 
1576
        out, err = self._run_bzr_autosplit(
1991
1577
            args=args,
1992
1578
            retcode=retcode,
1993
1579
            encoding=encoding,
1994
1580
            stdin=stdin,
1995
1581
            working_dir=working_dir,
1996
1582
            )
1997
 
        self.assertIsInstance(error_regexes, (list, tuple))
1998
1583
        for regex in error_regexes:
1999
1584
            self.assertContainsRe(err, regex)
2000
1585
        return out, err
2072
1657
    def start_bzr_subprocess(self, process_args, env_changes=None,
2073
1658
                             skip_if_plan_to_signal=False,
2074
1659
                             working_dir=None,
2075
 
                             allow_plugins=False, stderr=subprocess.PIPE):
 
1660
                             allow_plugins=False):
2076
1661
        """Start bzr in a subprocess for testing.
2077
1662
 
2078
1663
        This starts a new Python interpreter and runs bzr in there.
2087
1672
            variables. A value of None will unset the env variable.
2088
1673
            The values must be strings. The change will only occur in the
2089
1674
            child, so you don't need to fix the environment after running.
2090
 
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
2091
 
            doesn't support signalling subprocesses.
 
1675
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
 
1676
            is not available.
2092
1677
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
2093
 
        :param stderr: file to use for the subprocess's stderr.  Valid values
2094
 
            are those valid for the stderr argument of `subprocess.Popen`.
2095
 
            Default value is ``subprocess.PIPE``.
2096
1678
 
2097
1679
        :returns: Popen object for the started process.
2098
1680
        """
2099
1681
        if skip_if_plan_to_signal:
2100
 
            if os.name != "posix":
2101
 
                raise TestSkipped("Sending signals not supported")
 
1682
            if not getattr(os, 'kill', None):
 
1683
                raise TestSkipped("os.kill not available.")
2102
1684
 
2103
1685
        if env_changes is None:
2104
1686
            env_changes = {}
2124
1706
            # so we will avoid using it on all platforms, just to
2125
1707
            # make sure the code path is used, and we don't break on win32
2126
1708
            cleanup_environment()
2127
 
            # Include the subprocess's log file in the test details, in case
2128
 
            # the test fails due to an error in the subprocess.
2129
 
            self._add_subprocess_log(trace._get_bzr_log_filename())
2130
1709
            command = [sys.executable]
2131
1710
            # frozen executables don't need the path to bzr
2132
1711
            if getattr(sys, "frozen", None) is None:
2134
1713
            if not allow_plugins:
2135
1714
                command.append('--no-plugins')
2136
1715
            command.extend(process_args)
2137
 
            process = self._popen(command, stdin=subprocess.PIPE,
2138
 
                                  stdout=subprocess.PIPE,
2139
 
                                  stderr=stderr)
 
1716
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
2140
1717
        finally:
2141
1718
            restore_environment()
2142
1719
            if cwd is not None:
2144
1721
 
2145
1722
        return process
2146
1723
 
2147
 
    def _add_subprocess_log(self, log_file_path):
2148
 
        if len(self._log_files) == 0:
2149
 
            # Register an addCleanup func.  We do this on the first call to
2150
 
            # _add_subprocess_log rather than in TestCase.setUp so that this
2151
 
            # addCleanup is registered after any cleanups for tempdirs that
2152
 
            # subclasses might create, which will probably remove the log file
2153
 
            # we want to read.
2154
 
            self.addCleanup(self._subprocess_log_cleanup)
2155
 
        # self._log_files is a set, so if a log file is reused we won't grab it
2156
 
        # twice.
2157
 
        self._log_files.add(log_file_path)
2158
 
 
2159
 
    def _subprocess_log_cleanup(self):
2160
 
        for count, log_file_path in enumerate(self._log_files):
2161
 
            # We use buffer_now=True to avoid holding the file open beyond
2162
 
            # the life of this function, which might interfere with e.g.
2163
 
            # cleaning tempdirs on Windows.
2164
 
            # XXX: Testtools 0.9.5 doesn't have the content_from_file helper
2165
 
            #detail_content = content.content_from_file(
2166
 
            #    log_file_path, buffer_now=True)
2167
 
            with open(log_file_path, 'rb') as log_file:
2168
 
                log_file_bytes = log_file.read()
2169
 
            detail_content = content.Content(content.ContentType("text",
2170
 
                "plain", {"charset": "utf8"}), lambda: [log_file_bytes])
2171
 
            self.addDetail("start_bzr_subprocess-log-%d" % (count,),
2172
 
                detail_content)
2173
 
 
2174
1724
    def _popen(self, *args, **kwargs):
2175
1725
        """Place a call to Popen.
2176
1726
 
2177
1727
        Allows tests to override this method to intercept the calls made to
2178
1728
        Popen for introspection.
2179
1729
        """
2180
 
        return subprocess.Popen(*args, **kwargs)
2181
 
 
2182
 
    def get_source_path(self):
2183
 
        """Return the path of the directory containing bzrlib."""
2184
 
        return os.path.dirname(os.path.dirname(bzrlib.__file__))
 
1730
        return Popen(*args, **kwargs)
2185
1731
 
2186
1732
    def get_bzr_path(self):
2187
1733
        """Return the path of the 'bzr' executable for this test suite."""
2188
 
        bzr_path = os.path.join(self.get_source_path(), "bzr")
 
1734
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
2189
1735
        if not os.path.isfile(bzr_path):
2190
1736
            # We are probably installed. Assume sys.argv is the right file
2191
1737
            bzr_path = sys.argv[0]
2213
1759
        if retcode is not None and retcode != process.returncode:
2214
1760
            if process_args is None:
2215
1761
                process_args = "(unknown args)"
2216
 
            trace.mutter('Output of bzr %s:\n%s', process_args, out)
2217
 
            trace.mutter('Error for bzr %s:\n%s', process_args, err)
 
1762
            mutter('Output of bzr %s:\n%s', process_args, out)
 
1763
            mutter('Error for bzr %s:\n%s', process_args, err)
2218
1764
            self.fail('Command bzr %s failed with retcode %s != %s'
2219
1765
                      % (process_args, retcode, process.returncode))
2220
1766
        return [out, err]
2221
1767
 
2222
 
    def check_tree_shape(self, tree, shape):
2223
 
        """Compare a tree to a list of expected names.
 
1768
    def check_inventory_shape(self, inv, shape):
 
1769
        """Compare an inventory to a list of expected names.
2224
1770
 
2225
1771
        Fail if they are not precisely equal.
2226
1772
        """
2227
1773
        extras = []
2228
1774
        shape = list(shape)             # copy
2229
 
        for path, ie in tree.iter_entries_by_dir():
 
1775
        for path, ie in inv.entries():
2230
1776
            name = path.replace('\\', '/')
2231
1777
            if ie.kind == 'directory':
2232
1778
                name = name + '/'
2233
 
            if name == "/":
2234
 
                pass # ignore root entry
2235
 
            elif name in shape:
 
1779
            if name in shape:
2236
1780
                shape.remove(name)
2237
1781
            else:
2238
1782
                extras.append(name)
2279
1823
 
2280
1824
        Tests that expect to provoke LockContention errors should call this.
2281
1825
        """
2282
 
        self.overrideAttr(lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
 
1826
        orig_timeout = bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS
 
1827
        def resetTimeout():
 
1828
            bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = orig_timeout
 
1829
        self.addCleanup(resetTimeout)
 
1830
        bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = 0
2283
1831
 
2284
1832
    def make_utf8_encoded_stringio(self, encoding_type=None):
2285
1833
        """Return a StringIOWrapper instance, that will encode Unicode
2293
1841
        sio.encoding = output_encoding
2294
1842
        return sio
2295
1843
 
2296
 
    def disable_verb(self, verb):
2297
 
        """Disable a smart server verb for one test."""
2298
 
        from bzrlib.smart import request
2299
 
        request_handlers = request.request_handlers
2300
 
        orig_method = request_handlers.get(verb)
2301
 
        request_handlers.remove(verb)
2302
 
        self.addCleanup(request_handlers.register, verb, orig_method)
2303
 
 
2304
1844
 
2305
1845
class CapturedCall(object):
2306
1846
    """A helper for capturing smart server calls for easy debug analysis."""
2328
1868
class TestCaseWithMemoryTransport(TestCase):
2329
1869
    """Common test class for tests that do not need disk resources.
2330
1870
 
2331
 
    Tests that need disk resources should derive from TestCaseInTempDir
2332
 
    orTestCaseWithTransport.
 
1871
    Tests that need disk resources should derive from TestCaseWithTransport.
2333
1872
 
2334
1873
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2335
1874
 
2336
 
    For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
 
1875
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
2337
1876
    a directory which does not exist. This serves to help ensure test isolation
2338
 
    is preserved. ``test_dir`` is set to the TEST_ROOT, as is cwd, because they
2339
 
    must exist. However, TestCaseWithMemoryTransport does not offer local file
2340
 
    defaults for the transport in tests, nor does it obey the command line
 
1877
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
 
1878
    must exist. However, TestCaseWithMemoryTransport does not offer local
 
1879
    file defaults for the transport in tests, nor does it obey the command line
2341
1880
    override, so tests that accidentally write to the common directory should
2342
1881
    be rare.
2343
1882
 
2344
 
    :cvar TEST_ROOT: Directory containing all temporary directories, plus a
2345
 
        ``.bzr`` directory that stops us ascending higher into the filesystem.
 
1883
    :cvar TEST_ROOT: Directory containing all temporary directories, plus
 
1884
    a .bzr directory that stops us ascending higher into the filesystem.
2346
1885
    """
2347
1886
 
2348
1887
    TEST_ROOT = None
2366
1905
 
2367
1906
        :param relpath: a path relative to the base url.
2368
1907
        """
2369
 
        t = _mod_transport.get_transport(self.get_url(relpath))
 
1908
        t = get_transport(self.get_url(relpath))
2370
1909
        self.assertFalse(t.is_readonly())
2371
1910
        return t
2372
1911
 
2378
1917
 
2379
1918
        :param relpath: a path relative to the base url.
2380
1919
        """
2381
 
        t = _mod_transport.get_transport(self.get_readonly_url(relpath))
 
1920
        t = get_transport(self.get_readonly_url(relpath))
2382
1921
        self.assertTrue(t.is_readonly())
2383
1922
        return t
2384
1923
 
2397
1936
        if self.__readonly_server is None:
2398
1937
            if self.transport_readonly_server is None:
2399
1938
                # readonly decorator requested
2400
 
                self.__readonly_server = test_server.ReadonlyServer()
 
1939
                # bring up the server
 
1940
                self.__readonly_server = ReadonlyServer()
 
1941
                self.__readonly_server.setUp(self.get_vfs_only_server())
2401
1942
            else:
2402
 
                # explicit readonly transport.
2403
1943
                self.__readonly_server = self.create_transport_readonly_server()
2404
 
            self.start_server(self.__readonly_server,
2405
 
                self.get_vfs_only_server())
 
1944
                self.__readonly_server.setUp(self.get_vfs_only_server())
 
1945
            self.addCleanup(self.__readonly_server.tearDown)
2406
1946
        return self.__readonly_server
2407
1947
 
2408
1948
    def get_readonly_url(self, relpath=None):
2426
1966
        is no means to override it.
2427
1967
        """
2428
1968
        if self.__vfs_server is None:
2429
 
            self.__vfs_server = memory.MemoryServer()
2430
 
            self.start_server(self.__vfs_server)
 
1969
            self.__vfs_server = MemoryServer()
 
1970
            self.__vfs_server.setUp()
 
1971
            self.addCleanup(self.__vfs_server.tearDown)
2431
1972
        return self.__vfs_server
2432
1973
 
2433
1974
    def get_server(self):
2440
1981
        then the self.get_vfs_server is returned.
2441
1982
        """
2442
1983
        if self.__server is None:
2443
 
            if (self.transport_server is None or self.transport_server is
2444
 
                self.vfs_transport_factory):
2445
 
                self.__server = self.get_vfs_only_server()
 
1984
            if self.transport_server is None or self.transport_server is self.vfs_transport_factory:
 
1985
                return self.get_vfs_only_server()
2446
1986
            else:
2447
1987
                # bring up a decorated means of access to the vfs only server.
2448
1988
                self.__server = self.transport_server()
2449
 
                self.start_server(self.__server, self.get_vfs_only_server())
 
1989
                try:
 
1990
                    self.__server.setUp(self.get_vfs_only_server())
 
1991
                except TypeError, e:
 
1992
                    # This should never happen; the try:Except here is to assist
 
1993
                    # developers having to update code rather than seeing an
 
1994
                    # uninformative TypeError.
 
1995
                    raise Exception, "Old server API in use: %s, %s" % (self.__server, e)
 
1996
            self.addCleanup(self.__server.tearDown)
2450
1997
        return self.__server
2451
1998
 
2452
1999
    def _adjust_url(self, base, relpath):
2514
2061
        propagating. This method ensures than a test did not leaked.
2515
2062
        """
2516
2063
        root = TestCaseWithMemoryTransport.TEST_ROOT
2517
 
        self.permit_url(_mod_transport.get_transport(root).base)
2518
2064
        wt = workingtree.WorkingTree.open(root)
2519
2065
        last_rev = wt.last_revision()
2520
2066
        if last_rev != 'null:':
2522
2068
            # recreate a new one or all the followng tests will fail.
2523
2069
            # If you need to inspect its content uncomment the following line
2524
2070
            # import pdb; pdb.set_trace()
2525
 
            _rmtree_temp_dir(root + '/.bzr', test_id=self.id())
 
2071
            _rmtree_temp_dir(root + '/.bzr')
2526
2072
            self._create_safety_net()
2527
2073
            raise AssertionError('%s/.bzr should not be modified' % root)
2528
2074
 
2529
2075
    def _make_test_root(self):
2530
2076
        if TestCaseWithMemoryTransport.TEST_ROOT is None:
2531
 
            # Watch out for tricky test dir (on OSX /tmp -> /private/tmp)
2532
 
            root = osutils.realpath(osutils.mkdtemp(prefix='testbzr-',
2533
 
                                                    suffix='.tmp'))
 
2077
            root = osutils.mkdtemp(prefix='testbzr-', suffix='.tmp')
2534
2078
            TestCaseWithMemoryTransport.TEST_ROOT = root
2535
2079
 
2536
2080
            self._create_safety_net()
2539
2083
            # specifically told when all tests are finished.  This will do.
2540
2084
            atexit.register(_rmtree_temp_dir, root)
2541
2085
 
2542
 
        self.permit_dir(TestCaseWithMemoryTransport.TEST_ROOT)
2543
2086
        self.addCleanup(self._check_safety_net)
2544
2087
 
2545
2088
    def makeAndChdirToTestDir(self):
2553
2096
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
2554
2097
        self.test_dir = TestCaseWithMemoryTransport.TEST_ROOT
2555
2098
        self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
2556
 
        self.permit_dir(self.test_dir)
2557
2099
 
2558
2100
    def make_branch(self, relpath, format=None):
2559
2101
        """Create a branch on the transport at relpath."""
2565
2107
            # might be a relative or absolute path
2566
2108
            maybe_a_url = self.get_url(relpath)
2567
2109
            segments = maybe_a_url.rsplit('/', 1)
2568
 
            t = _mod_transport.get_transport(maybe_a_url)
 
2110
            t = get_transport(maybe_a_url)
2569
2111
            if len(segments) > 1 and segments[-1] not in ('', '.'):
2570
2112
                t.ensure_base()
2571
2113
            if format is None:
2588
2130
        made_control = self.make_bzrdir(relpath, format=format)
2589
2131
        return made_control.create_repository(shared=shared)
2590
2132
 
2591
 
    def make_smart_server(self, path, backing_server=None):
2592
 
        if backing_server is None:
2593
 
            backing_server = self.get_server()
2594
 
        smart_server = test_server.SmartTCPServer_for_testing()
2595
 
        self.start_server(smart_server, backing_server)
2596
 
        remote_transport = _mod_transport.get_transport(smart_server.get_url()
2597
 
                                                   ).clone(path)
 
2133
    def make_smart_server(self, path):
 
2134
        smart_server = server.SmartTCPServer_for_testing()
 
2135
        smart_server.setUp(self.get_server())
 
2136
        remote_transport = get_transport(smart_server.get_url()).clone(path)
 
2137
        self.addCleanup(smart_server.tearDown)
2598
2138
        return remote_transport
2599
2139
 
2600
2140
    def make_branch_and_memory_tree(self, relpath, format=None):
2603
2143
        return memorytree.MemoryTree.create_on_branch(b)
2604
2144
 
2605
2145
    def make_branch_builder(self, relpath, format=None):
2606
 
        branch = self.make_branch(relpath, format=format)
2607
 
        return branchbuilder.BranchBuilder(branch=branch)
 
2146
        return branchbuilder.BranchBuilder(self.get_transport(relpath),
 
2147
            format=format)
2608
2148
 
2609
2149
    def overrideEnvironmentForTesting(self):
2610
 
        test_home_dir = self.test_home_dir
2611
 
        if isinstance(test_home_dir, unicode):
2612
 
            test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
2613
 
        self.overrideEnv('HOME', test_home_dir)
2614
 
        self.overrideEnv('BZR_HOME', test_home_dir)
 
2150
        os.environ['HOME'] = self.test_home_dir
 
2151
        os.environ['BZR_HOME'] = self.test_home_dir
2615
2152
 
2616
2153
    def setUp(self):
2617
2154
        super(TestCaseWithMemoryTransport, self).setUp()
2618
 
        # Ensure that ConnectedTransport doesn't leak sockets
2619
 
        def get_transport_with_cleanup(*args, **kwargs):
2620
 
            t = orig_get_transport(*args, **kwargs)
2621
 
            if isinstance(t, _mod_transport.ConnectedTransport):
2622
 
                self.addCleanup(t.disconnect)
2623
 
            return t
2624
 
 
2625
 
        orig_get_transport = self.overrideAttr(_mod_transport, 'get_transport',
2626
 
                                               get_transport_with_cleanup)
2627
2155
        self._make_test_root()
2628
 
        self.addCleanup(os.chdir, os.getcwdu())
 
2156
        _currentdir = os.getcwdu()
 
2157
        def _leaveDirectory():
 
2158
            os.chdir(_currentdir)
 
2159
        self.addCleanup(_leaveDirectory)
2629
2160
        self.makeAndChdirToTestDir()
2630
2161
        self.overrideEnvironmentForTesting()
2631
2162
        self.__readonly_server = None
2634
2165
 
2635
2166
    def setup_smart_server_with_call_log(self):
2636
2167
        """Sets up a smart server as the transport server with a call log."""
2637
 
        self.transport_server = test_server.SmartTCPServer_for_testing
 
2168
        self.transport_server = server.SmartTCPServer_for_testing
2638
2169
        self.hpss_calls = []
2639
2170
        import traceback
2640
2171
        # Skip the current stack down to the caller of
2672
2203
 
2673
2204
    OVERRIDE_PYTHON = 'python'
2674
2205
 
2675
 
    def setUp(self):
2676
 
        super(TestCaseInTempDir, self).setUp()
2677
 
        # Remove the protection set in isolated_environ, we have a proper
2678
 
        # access to disk resources now.
2679
 
        self.overrideEnv('BZR_LOG', None)
2680
 
 
2681
2206
    def check_file_contents(self, filename, expect):
2682
2207
        self.log("check contents of file %s" % filename)
2683
 
        f = file(filename)
2684
 
        try:
2685
 
            contents = f.read()
2686
 
        finally:
2687
 
            f.close()
 
2208
        contents = file(filename, 'r').read()
2688
2209
        if contents != expect:
2689
2210
            self.log("expected: %r" % expect)
2690
2211
            self.log("actually: %r" % contents)
2692
2213
 
2693
2214
    def _getTestDirPrefix(self):
2694
2215
        # create a directory within the top level test directory
2695
 
        if sys.platform in ('win32', 'cygwin'):
 
2216
        if sys.platform == 'win32':
2696
2217
            name_prefix = re.sub('[<>*=+",:;_/\\-]', '_', self.id())
2697
2218
            # windows is likely to have path-length limits so use a short name
2698
2219
            name_prefix = name_prefix[-30:]
2706
2227
        For TestCaseInTempDir we create a temporary directory based on the test
2707
2228
        name and then create two subdirs - test and home under it.
2708
2229
        """
2709
 
        name_prefix = osutils.pathjoin(TestCaseWithMemoryTransport.TEST_ROOT,
2710
 
            self._getTestDirPrefix())
 
2230
        name_prefix = osutils.pathjoin(self.TEST_ROOT, self._getTestDirPrefix())
2711
2231
        name = name_prefix
2712
2232
        for i in range(100):
2713
2233
            if os.path.exists(name):
2714
2234
                name = name_prefix + '_' + str(i)
2715
2235
            else:
2716
 
                # now create test and home directories within this dir
2717
 
                self.test_base_dir = name
2718
 
                self.addCleanup(self.deleteTestDir)
2719
 
                os.mkdir(self.test_base_dir)
 
2236
                os.mkdir(name)
2720
2237
                break
2721
 
        self.permit_dir(self.test_base_dir)
2722
 
        # 'sprouting' and 'init' of a branch both walk up the tree to find
2723
 
        # stacking policy to honour; create a bzr dir with an unshared
2724
 
        # repository (but not a branch - our code would be trying to escape
2725
 
        # then!) to stop them, and permit it to be read.
2726
 
        # control = bzrdir.BzrDir.create(self.test_base_dir)
2727
 
        # control.create_repository()
 
2238
        # now create test and home directories within this dir
 
2239
        self.test_base_dir = name
2728
2240
        self.test_home_dir = self.test_base_dir + '/home'
2729
2241
        os.mkdir(self.test_home_dir)
2730
2242
        self.test_dir = self.test_base_dir + '/work'
2736
2248
            f.write(self.id())
2737
2249
        finally:
2738
2250
            f.close()
 
2251
        self.addCleanup(self.deleteTestDir)
2739
2252
 
2740
2253
    def deleteTestDir(self):
2741
 
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
2742
 
        _rmtree_temp_dir(self.test_base_dir, test_id=self.id())
 
2254
        os.chdir(self.TEST_ROOT)
 
2255
        _rmtree_temp_dir(self.test_base_dir)
2743
2256
 
2744
2257
    def build_tree(self, shape, line_endings='binary', transport=None):
2745
2258
        """Build a test tree according to a pattern.
2764
2277
                "a list or a tuple. Got %r instead" % (shape,))
2765
2278
        # It's OK to just create them using forward slashes on windows.
2766
2279
        if transport is None or transport.is_readonly():
2767
 
            transport = _mod_transport.get_transport(".")
 
2280
            transport = get_transport(".")
2768
2281
        for name in shape:
2769
2282
            self.assertIsInstance(name, basestring)
2770
2283
            if name[-1] == '/':
2780
2293
                content = "contents of %s%s" % (name.encode('utf-8'), end)
2781
2294
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
2782
2295
 
2783
 
    build_tree_contents = staticmethod(treeshape.build_tree_contents)
 
2296
    def build_tree_contents(self, shape):
 
2297
        build_tree_contents(shape)
2784
2298
 
2785
2299
    def assertInWorkingTree(self, path, root_path='.', tree=None):
2786
2300
        """Assert whether path or paths are in the WorkingTree"""
2826
2340
        """
2827
2341
        if self.__vfs_server is None:
2828
2342
            self.__vfs_server = self.vfs_transport_factory()
2829
 
            self.start_server(self.__vfs_server)
 
2343
            self.__vfs_server.setUp()
 
2344
            self.addCleanup(self.__vfs_server.tearDown)
2830
2345
        return self.__vfs_server
2831
2346
 
2832
2347
    def make_branch_and_tree(self, relpath, format=None):
2839
2354
        repository will also be accessed locally. Otherwise a lightweight
2840
2355
        checkout is created and returned.
2841
2356
 
2842
 
        We do this because we can't physically create a tree in the local
2843
 
        path, with a branch reference to the transport_factory url, and
2844
 
        a branch + repository in the vfs_transport, unless the vfs_transport
2845
 
        namespace is distinct from the local disk - the two branch objects
2846
 
        would collide. While we could construct a tree with its branch object
2847
 
        pointing at the transport_factory transport in memory, reopening it
2848
 
        would behaving unexpectedly, and has in the past caused testing bugs
2849
 
        when we tried to do it that way.
2850
 
 
2851
2357
        :param format: The BzrDirFormat.
2852
2358
        :returns: the WorkingTree.
2853
2359
        """
2862
2368
            # We can only make working trees locally at the moment.  If the
2863
2369
            # transport can't support them, then we keep the non-disk-backed
2864
2370
            # branch and create a local checkout.
2865
 
            if self.vfs_transport_factory is test_server.LocalURLServer:
 
2371
            if self.vfs_transport_factory is LocalURLServer:
2866
2372
                # the branch is colocated on disk, we cannot create a checkout.
2867
2373
                # hopefully callers will expect this.
2868
2374
                local_controldir= bzrdir.BzrDir.open(self.get_vfs_only_url(relpath))
2905
2411
        super(TestCaseWithTransport, self).setUp()
2906
2412
        self.__vfs_server = None
2907
2413
 
2908
 
    def disable_missing_extensions_warning(self):
2909
 
        """Some tests expect a precise stderr content.
2910
 
 
2911
 
        There is no point in forcing them to duplicate the extension related
2912
 
        warning.
2913
 
        """
2914
 
        config.GlobalConfig().set_user_option('ignore_missing_extensions', True)
2915
 
 
2916
2414
 
2917
2415
class ChrootedTestCase(TestCaseWithTransport):
2918
2416
    """A support class that provides readonly urls outside the local namespace.
2927
2425
    """
2928
2426
 
2929
2427
    def setUp(self):
2930
 
        from bzrlib.tests import http_server
2931
2428
        super(ChrootedTestCase, self).setUp()
2932
 
        if not self.vfs_transport_factory == memory.MemoryServer:
2933
 
            self.transport_readonly_server = http_server.HttpServer
 
2429
        if not self.vfs_transport_factory == MemoryServer:
 
2430
            self.transport_readonly_server = HttpServer
2934
2431
 
2935
2432
 
2936
2433
def condition_id_re(pattern):
2939
2436
    :param pattern: A regular expression string.
2940
2437
    :return: A callable that returns True if the re matches.
2941
2438
    """
2942
 
    filter_re = re.compile(pattern, 0)
 
2439
    filter_re = osutils.re_compile_checked(pattern, 0,
 
2440
        'test filter')
2943
2441
    def condition(test):
2944
2442
        test_id = test.id()
2945
2443
        return filter_re.search(test_id)
3131
2629
              exclude_pattern=None,
3132
2630
              strict=False,
3133
2631
              runner_class=None,
3134
 
              suite_decorators=None,
3135
 
              stream=None,
3136
 
              result_decorators=None,
3137
 
              ):
 
2632
              suite_decorators=None):
3138
2633
    """Run a test suite for bzr selftest.
3139
2634
 
3140
2635
    :param runner_class: The class of runner to use. Must support the
3149
2644
        verbosity = 1
3150
2645
    if runner_class is None:
3151
2646
        runner_class = TextTestRunner
3152
 
    if stream is None:
3153
 
        stream = sys.stdout
3154
 
    runner = runner_class(stream=stream,
 
2647
    runner = runner_class(stream=sys.stdout,
3155
2648
                            descriptions=0,
3156
2649
                            verbosity=verbosity,
3157
2650
                            bench_history=bench_history,
3158
 
                            strict=strict,
3159
 
                            result_decorators=result_decorators,
 
2651
                            list_only=list_only,
3160
2652
                            )
3161
2653
    runner.stop_on_failure=stop_on_failure
3162
2654
    # built in decorator factories:
3170
2662
        decorators.append(filter_tests(pattern))
3171
2663
    if suite_decorators:
3172
2664
        decorators.extend(suite_decorators)
3173
 
    # tell the result object how many tests will be running: (except if
3174
 
    # --parallel=fork is being used. Robert said he will provide a better
3175
 
    # progress design later -- vila 20090817)
3176
 
    if fork_decorator not in decorators:
3177
 
        decorators.append(CountingDecorator)
3178
2665
    for decorator in decorators:
3179
2666
        suite = decorator(suite)
3180
 
    if list_only:
3181
 
        # Done after test suite decoration to allow randomisation etc
3182
 
        # to take effect, though that is of marginal benefit.
3183
 
        if verbosity >= 2:
3184
 
            stream.write("Listing tests only ...\n")
3185
 
        for t in iter_suite_tests(suite):
3186
 
            stream.write("%s\n" % (t.id()))
3187
 
        return True
3188
2667
    result = runner.run(suite)
3189
2668
    if strict:
3190
2669
        return result.wasStrictlySuccessful()
3192
2671
        return result.wasSuccessful()
3193
2672
 
3194
2673
 
3195
 
# A registry where get() returns a suite decorator.
3196
 
parallel_registry = registry.Registry()
3197
 
 
3198
 
 
3199
 
def fork_decorator(suite):
3200
 
    if getattr(os, "fork", None) is None:
3201
 
        raise errors.BzrCommandError("platform does not support fork,"
3202
 
            " try --parallel=subprocess instead.")
3203
 
    concurrency = osutils.local_concurrency()
3204
 
    if concurrency == 1:
3205
 
        return suite
3206
 
    from testtools import ConcurrentTestSuite
3207
 
    return ConcurrentTestSuite(suite, fork_for_tests)
3208
 
parallel_registry.register('fork', fork_decorator)
3209
 
 
3210
 
 
3211
 
def subprocess_decorator(suite):
3212
 
    concurrency = osutils.local_concurrency()
3213
 
    if concurrency == 1:
3214
 
        return suite
3215
 
    from testtools import ConcurrentTestSuite
3216
 
    return ConcurrentTestSuite(suite, reinvoke_for_tests)
3217
 
parallel_registry.register('subprocess', subprocess_decorator)
3218
 
 
3219
 
 
3220
2674
def exclude_tests(exclude_pattern):
3221
2675
    """Return a test suite decorator that excludes tests."""
3222
2676
    if exclude_pattern is None:
3260
2714
    return suite
3261
2715
 
3262
2716
 
3263
 
class TestDecorator(TestUtil.TestSuite):
 
2717
class TestDecorator(TestSuite):
3264
2718
    """A decorator for TestCase/TestSuite objects.
3265
2719
    
3266
2720
    Usually, subclasses should override __iter__(used when flattening test
3269
2723
    """
3270
2724
 
3271
2725
    def __init__(self, suite):
3272
 
        TestUtil.TestSuite.__init__(self)
 
2726
        TestSuite.__init__(self)
3273
2727
        self.addTest(suite)
3274
2728
 
3275
2729
    def countTestCases(self):
3292
2746
        return result
3293
2747
 
3294
2748
 
3295
 
class CountingDecorator(TestDecorator):
3296
 
    """A decorator which calls result.progress(self.countTestCases)."""
3297
 
 
3298
 
    def run(self, result):
3299
 
        progress_method = getattr(result, 'progress', None)
3300
 
        if callable(progress_method):
3301
 
            progress_method(self.countTestCases(), SUBUNIT_SEEK_SET)
3302
 
        return super(CountingDecorator, self).run(result)
3303
 
 
3304
 
 
3305
2749
class ExcludeDecorator(TestDecorator):
3306
2750
    """A decorator which excludes test matching an exclude pattern."""
3307
2751
 
3351
2795
        if self.randomised:
3352
2796
            return iter(self._tests)
3353
2797
        self.randomised = True
3354
 
        self.stream.write("Randomizing test order using seed %s\n\n" %
 
2798
        self.stream.writeln("Randomizing test order using seed %s\n" %
3355
2799
            (self.actual_seed()))
3356
2800
        # Initialise the random number generator.
3357
2801
        random.seed(self.actual_seed())
3392
2836
        return iter(self._tests)
3393
2837
 
3394
2838
 
3395
 
def partition_tests(suite, count):
3396
 
    """Partition suite into count lists of tests."""
3397
 
    # This just assigns tests in a round-robin fashion.  On one hand this
3398
 
    # splits up blocks of related tests that might run faster if they shared
3399
 
    # resources, but on the other it avoids assigning blocks of slow tests to
3400
 
    # just one partition.  So the slowest partition shouldn't be much slower
3401
 
    # than the fastest.
3402
 
    partitions = [list() for i in range(count)]
3403
 
    tests = iter_suite_tests(suite)
3404
 
    for partition, test in itertools.izip(itertools.cycle(partitions), tests):
3405
 
        partition.append(test)
3406
 
    return partitions
3407
 
 
3408
 
 
3409
 
def workaround_zealous_crypto_random():
3410
 
    """Crypto.Random want to help us being secure, but we don't care here.
3411
 
 
3412
 
    This workaround some test failure related to the sftp server. Once paramiko
3413
 
    stop using the controversial API in Crypto.Random, we may get rid of it.
3414
 
    """
3415
 
    try:
3416
 
        from Crypto.Random import atfork
3417
 
        atfork()
3418
 
    except ImportError:
3419
 
        pass
3420
 
 
3421
 
 
3422
 
def fork_for_tests(suite):
3423
 
    """Take suite and start up one runner per CPU by forking()
3424
 
 
3425
 
    :return: An iterable of TestCase-like objects which can each have
3426
 
        run(result) called on them to feed tests to result.
3427
 
    """
3428
 
    concurrency = osutils.local_concurrency()
3429
 
    result = []
3430
 
    from subunit import TestProtocolClient, ProtocolTestCase
3431
 
    from subunit.test_results import AutoTimingTestResultDecorator
3432
 
    class TestInOtherProcess(ProtocolTestCase):
3433
 
        # Should be in subunit, I think. RBC.
3434
 
        def __init__(self, stream, pid):
3435
 
            ProtocolTestCase.__init__(self, stream)
3436
 
            self.pid = pid
3437
 
 
3438
 
        def run(self, result):
3439
 
            try:
3440
 
                ProtocolTestCase.run(self, result)
3441
 
            finally:
3442
 
                os.waitpid(self.pid, 0)
3443
 
 
3444
 
    test_blocks = partition_tests(suite, concurrency)
3445
 
    for process_tests in test_blocks:
3446
 
        process_suite = TestUtil.TestSuite()
3447
 
        process_suite.addTests(process_tests)
3448
 
        c2pread, c2pwrite = os.pipe()
3449
 
        pid = os.fork()
3450
 
        if pid == 0:
3451
 
            workaround_zealous_crypto_random()
3452
 
            try:
3453
 
                os.close(c2pread)
3454
 
                # Leave stderr and stdout open so we can see test noise
3455
 
                # Close stdin so that the child goes away if it decides to
3456
 
                # read from stdin (otherwise its a roulette to see what
3457
 
                # child actually gets keystrokes for pdb etc).
3458
 
                sys.stdin.close()
3459
 
                sys.stdin = None
3460
 
                stream = os.fdopen(c2pwrite, 'wb', 1)
3461
 
                subunit_result = AutoTimingTestResultDecorator(
3462
 
                    TestProtocolClient(stream))
3463
 
                process_suite.run(subunit_result)
3464
 
            finally:
3465
 
                os._exit(0)
3466
 
        else:
3467
 
            os.close(c2pwrite)
3468
 
            stream = os.fdopen(c2pread, 'rb', 1)
3469
 
            test = TestInOtherProcess(stream, pid)
3470
 
            result.append(test)
3471
 
    return result
3472
 
 
3473
 
 
3474
 
def reinvoke_for_tests(suite):
3475
 
    """Take suite and start up one runner per CPU using subprocess().
3476
 
 
3477
 
    :return: An iterable of TestCase-like objects which can each have
3478
 
        run(result) called on them to feed tests to result.
3479
 
    """
3480
 
    concurrency = osutils.local_concurrency()
3481
 
    result = []
3482
 
    from subunit import ProtocolTestCase
3483
 
    class TestInSubprocess(ProtocolTestCase):
3484
 
        def __init__(self, process, name):
3485
 
            ProtocolTestCase.__init__(self, process.stdout)
3486
 
            self.process = process
3487
 
            self.process.stdin.close()
3488
 
            self.name = name
3489
 
 
3490
 
        def run(self, result):
3491
 
            try:
3492
 
                ProtocolTestCase.run(self, result)
3493
 
            finally:
3494
 
                self.process.wait()
3495
 
                os.unlink(self.name)
3496
 
            # print "pid %d finished" % finished_process
3497
 
    test_blocks = partition_tests(suite, concurrency)
3498
 
    for process_tests in test_blocks:
3499
 
        # ugly; currently reimplement rather than reuses TestCase methods.
3500
 
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
3501
 
        if not os.path.isfile(bzr_path):
3502
 
            # We are probably installed. Assume sys.argv is the right file
3503
 
            bzr_path = sys.argv[0]
3504
 
        bzr_path = [bzr_path]
3505
 
        if sys.platform == "win32":
3506
 
            # if we're on windows, we can't execute the bzr script directly
3507
 
            bzr_path = [sys.executable] + bzr_path
3508
 
        fd, test_list_file_name = tempfile.mkstemp()
3509
 
        test_list_file = os.fdopen(fd, 'wb', 1)
3510
 
        for test in process_tests:
3511
 
            test_list_file.write(test.id() + '\n')
3512
 
        test_list_file.close()
3513
 
        try:
3514
 
            argv = bzr_path + ['selftest', '--load-list', test_list_file_name,
3515
 
                '--subunit']
3516
 
            if '--no-plugins' in sys.argv:
3517
 
                argv.append('--no-plugins')
3518
 
            # stderr=subprocess.STDOUT would be ideal, but until we prevent
3519
 
            # noise on stderr it can interrupt the subunit protocol.
3520
 
            process = subprocess.Popen(argv, stdin=subprocess.PIPE,
3521
 
                                      stdout=subprocess.PIPE,
3522
 
                                      stderr=subprocess.PIPE,
3523
 
                                      bufsize=1)
3524
 
            test = TestInSubprocess(process, test_list_file_name)
3525
 
            result.append(test)
3526
 
        except:
3527
 
            os.unlink(test_list_file_name)
3528
 
            raise
3529
 
    return result
3530
 
 
3531
 
 
3532
 
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3533
 
    """Generate profiling data for all activity between start and success.
3534
 
    
3535
 
    The profile data is appended to the test's _benchcalls attribute and can
3536
 
    be accessed by the forwarded-to TestResult.
3537
 
 
3538
 
    While it might be cleaner do accumulate this in stopTest, addSuccess is
3539
 
    where our existing output support for lsprof is, and this class aims to
3540
 
    fit in with that: while it could be moved it's not necessary to accomplish
3541
 
    test profiling, nor would it be dramatically cleaner.
3542
 
    """
3543
 
 
3544
 
    def startTest(self, test):
3545
 
        self.profiler = bzrlib.lsprof.BzrProfiler()
3546
 
        # Prevent deadlocks in tests that use lsprof: those tests will
3547
 
        # unavoidably fail.
3548
 
        bzrlib.lsprof.BzrProfiler.profiler_block = 0
3549
 
        self.profiler.start()
3550
 
        testtools.ExtendedToOriginalDecorator.startTest(self, test)
3551
 
 
3552
 
    def addSuccess(self, test):
3553
 
        stats = self.profiler.stop()
3554
 
        try:
3555
 
            calls = test._benchcalls
3556
 
        except AttributeError:
3557
 
            test._benchcalls = []
3558
 
            calls = test._benchcalls
3559
 
        calls.append(((test.id(), "", ""), stats))
3560
 
        testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
3561
 
 
3562
 
    def stopTest(self, test):
3563
 
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
3564
 
        self.profiler = None
3565
 
 
3566
 
 
3567
2839
# Controlled by "bzr selftest -E=..." option
3568
 
# Currently supported:
3569
 
#   -Eallow_debug           Will no longer clear debug.debug_flags() so it
3570
 
#                           preserves any flags supplied at the command line.
3571
 
#   -Edisable_lock_checks   Turns errors in mismatched locks into simple prints
3572
 
#                           rather than failing tests. And no longer raise
3573
 
#                           LockContention when fctnl locks are not being used
3574
 
#                           with proper exclusion rules.
3575
 
#   -Ethreads               Will display thread ident at creation/join time to
3576
 
#                           help track thread leaks
3577
 
 
3578
 
#   -Econfig_stats          Will collect statistics using addDetail
3579
2840
selftest_debug_flags = set()
3580
2841
 
3581
2842
 
3593
2854
             debug_flags=None,
3594
2855
             starting_with=None,
3595
2856
             runner_class=None,
3596
 
             suite_decorators=None,
3597
 
             stream=None,
3598
 
             lsprof_tests=False,
3599
2857
             ):
3600
2858
    """Run the whole test suite under the enhanced runner"""
3601
2859
    # XXX: Very ugly way to do this...
3618
2876
            keep_only = None
3619
2877
        else:
3620
2878
            keep_only = load_test_id_list(load_list)
3621
 
        if starting_with:
3622
 
            starting_with = [test_prefix_alias_registry.resolve_alias(start)
3623
 
                             for start in starting_with]
3624
2879
        if test_suite_factory is None:
3625
 
            # Reduce loading time by loading modules based on the starting_with
3626
 
            # patterns.
3627
2880
            suite = test_suite(keep_only, starting_with)
3628
2881
        else:
3629
2882
            suite = test_suite_factory()
3630
 
        if starting_with:
3631
 
            # But always filter as requested.
3632
 
            suite = filter_suite_by_id_startswith(suite, starting_with)
3633
 
        result_decorators = []
3634
 
        if lsprof_tests:
3635
 
            result_decorators.append(ProfileResult)
3636
2883
        return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
3637
2884
                     stop_on_failure=stop_on_failure,
3638
2885
                     transport=transport,
3644
2891
                     exclude_pattern=exclude_pattern,
3645
2892
                     strict=strict,
3646
2893
                     runner_class=runner_class,
3647
 
                     suite_decorators=suite_decorators,
3648
 
                     stream=stream,
3649
 
                     result_decorators=result_decorators,
3650
2894
                     )
3651
2895
    finally:
3652
2896
        default_transport = old_transport
3775
3019
                key, obj, help=help, info=info, override_existing=False)
3776
3020
        except KeyError:
3777
3021
            actual = self.get(key)
3778
 
            trace.note(
3779
 
                'Test prefix alias %s is already used for %s, ignoring %s'
3780
 
                % (key, actual, obj))
 
3022
            note('Test prefix alias %s is already used for %s, ignoring %s'
 
3023
                 % (key, actual, obj))
3781
3024
 
3782
3025
    def resolve_alias(self, id_start):
3783
3026
        """Replace the alias by the prefix in the given string.
3801
3044
# appear prefixed ('bzrlib.' is "replaced" by 'bzrlib.').
3802
3045
test_prefix_alias_registry.register('bzrlib', 'bzrlib')
3803
3046
 
3804
 
# Obvious highest levels prefixes, feel free to add your own via a plugin
 
3047
# Obvious higest levels prefixes, feel free to add your own via a plugin
3805
3048
test_prefix_alias_registry.register('bd', 'bzrlib.doc')
3806
3049
test_prefix_alias_registry.register('bu', 'bzrlib.utils')
3807
3050
test_prefix_alias_registry.register('bt', 'bzrlib.tests')
3809
3052
test_prefix_alias_registry.register('bp', 'bzrlib.plugins')
3810
3053
 
3811
3054
 
3812
 
def _test_suite_testmod_names():
3813
 
    """Return the standard list of test module names to test."""
3814
 
    return [
3815
 
        'bzrlib.doc',
3816
 
        'bzrlib.tests.blackbox',
3817
 
        'bzrlib.tests.commands',
3818
 
        'bzrlib.tests.doc_generate',
3819
 
        'bzrlib.tests.per_branch',
3820
 
        'bzrlib.tests.per_bzrdir',
3821
 
        'bzrlib.tests.per_controldir',
3822
 
        'bzrlib.tests.per_controldir_colo',
3823
 
        'bzrlib.tests.per_foreign_vcs',
3824
 
        'bzrlib.tests.per_interrepository',
3825
 
        'bzrlib.tests.per_intertree',
3826
 
        'bzrlib.tests.per_inventory',
3827
 
        'bzrlib.tests.per_interbranch',
3828
 
        'bzrlib.tests.per_lock',
3829
 
        'bzrlib.tests.per_merger',
3830
 
        'bzrlib.tests.per_transport',
3831
 
        'bzrlib.tests.per_tree',
3832
 
        'bzrlib.tests.per_pack_repository',
3833
 
        'bzrlib.tests.per_repository',
3834
 
        'bzrlib.tests.per_repository_chk',
3835
 
        'bzrlib.tests.per_repository_reference',
3836
 
        'bzrlib.tests.per_repository_vf',
3837
 
        'bzrlib.tests.per_uifactory',
3838
 
        'bzrlib.tests.per_versionedfile',
3839
 
        'bzrlib.tests.per_workingtree',
3840
 
        'bzrlib.tests.test__annotator',
3841
 
        'bzrlib.tests.test__bencode',
3842
 
        'bzrlib.tests.test__btree_serializer',
3843
 
        'bzrlib.tests.test__chk_map',
3844
 
        'bzrlib.tests.test__dirstate_helpers',
3845
 
        'bzrlib.tests.test__groupcompress',
3846
 
        'bzrlib.tests.test__known_graph',
3847
 
        'bzrlib.tests.test__rio',
3848
 
        'bzrlib.tests.test__simple_set',
3849
 
        'bzrlib.tests.test__static_tuple',
3850
 
        'bzrlib.tests.test__walkdirs_win32',
3851
 
        'bzrlib.tests.test_ancestry',
3852
 
        'bzrlib.tests.test_annotate',
3853
 
        'bzrlib.tests.test_api',
3854
 
        'bzrlib.tests.test_atomicfile',
3855
 
        'bzrlib.tests.test_bad_files',
3856
 
        'bzrlib.tests.test_bisect_multi',
3857
 
        'bzrlib.tests.test_branch',
3858
 
        'bzrlib.tests.test_branchbuilder',
3859
 
        'bzrlib.tests.test_btree_index',
3860
 
        'bzrlib.tests.test_bugtracker',
3861
 
        'bzrlib.tests.test_bundle',
3862
 
        'bzrlib.tests.test_bzrdir',
3863
 
        'bzrlib.tests.test__chunks_to_lines',
3864
 
        'bzrlib.tests.test_cache_utf8',
3865
 
        'bzrlib.tests.test_chk_map',
3866
 
        'bzrlib.tests.test_chk_serializer',
3867
 
        'bzrlib.tests.test_chunk_writer',
3868
 
        'bzrlib.tests.test_clean_tree',
3869
 
        'bzrlib.tests.test_cleanup',
3870
 
        'bzrlib.tests.test_cmdline',
3871
 
        'bzrlib.tests.test_commands',
3872
 
        'bzrlib.tests.test_commit',
3873
 
        'bzrlib.tests.test_commit_merge',
3874
 
        'bzrlib.tests.test_config',
3875
 
        'bzrlib.tests.test_conflicts',
3876
 
        'bzrlib.tests.test_controldir',
3877
 
        'bzrlib.tests.test_counted_lock',
3878
 
        'bzrlib.tests.test_crash',
3879
 
        'bzrlib.tests.test_decorators',
3880
 
        'bzrlib.tests.test_delta',
3881
 
        'bzrlib.tests.test_debug',
3882
 
        'bzrlib.tests.test_diff',
3883
 
        'bzrlib.tests.test_directory_service',
3884
 
        'bzrlib.tests.test_dirstate',
3885
 
        'bzrlib.tests.test_email_message',
3886
 
        'bzrlib.tests.test_eol_filters',
3887
 
        'bzrlib.tests.test_errors',
3888
 
        'bzrlib.tests.test_export',
3889
 
        'bzrlib.tests.test_export_pot',
3890
 
        'bzrlib.tests.test_extract',
3891
 
        'bzrlib.tests.test_fetch',
3892
 
        'bzrlib.tests.test_fixtures',
3893
 
        'bzrlib.tests.test_fifo_cache',
3894
 
        'bzrlib.tests.test_filters',
3895
 
        'bzrlib.tests.test_ftp_transport',
3896
 
        'bzrlib.tests.test_foreign',
3897
 
        'bzrlib.tests.test_generate_docs',
3898
 
        'bzrlib.tests.test_generate_ids',
3899
 
        'bzrlib.tests.test_globbing',
3900
 
        'bzrlib.tests.test_gpg',
3901
 
        'bzrlib.tests.test_graph',
3902
 
        'bzrlib.tests.test_groupcompress',
3903
 
        'bzrlib.tests.test_hashcache',
3904
 
        'bzrlib.tests.test_help',
3905
 
        'bzrlib.tests.test_hooks',
3906
 
        'bzrlib.tests.test_http',
3907
 
        'bzrlib.tests.test_http_response',
3908
 
        'bzrlib.tests.test_https_ca_bundle',
3909
 
        'bzrlib.tests.test_i18n',
3910
 
        'bzrlib.tests.test_identitymap',
3911
 
        'bzrlib.tests.test_ignores',
3912
 
        'bzrlib.tests.test_index',
3913
 
        'bzrlib.tests.test_import_tariff',
3914
 
        'bzrlib.tests.test_info',
3915
 
        'bzrlib.tests.test_inv',
3916
 
        'bzrlib.tests.test_inventory_delta',
3917
 
        'bzrlib.tests.test_knit',
3918
 
        'bzrlib.tests.test_lazy_import',
3919
 
        'bzrlib.tests.test_lazy_regex',
3920
 
        'bzrlib.tests.test_library_state',
3921
 
        'bzrlib.tests.test_lock',
3922
 
        'bzrlib.tests.test_lockable_files',
3923
 
        'bzrlib.tests.test_lockdir',
3924
 
        'bzrlib.tests.test_log',
3925
 
        'bzrlib.tests.test_lru_cache',
3926
 
        'bzrlib.tests.test_lsprof',
3927
 
        'bzrlib.tests.test_mail_client',
3928
 
        'bzrlib.tests.test_matchers',
3929
 
        'bzrlib.tests.test_memorytree',
3930
 
        'bzrlib.tests.test_merge',
3931
 
        'bzrlib.tests.test_merge3',
3932
 
        'bzrlib.tests.test_merge_core',
3933
 
        'bzrlib.tests.test_merge_directive',
3934
 
        'bzrlib.tests.test_mergetools',
3935
 
        'bzrlib.tests.test_missing',
3936
 
        'bzrlib.tests.test_msgeditor',
3937
 
        'bzrlib.tests.test_multiparent',
3938
 
        'bzrlib.tests.test_mutabletree',
3939
 
        'bzrlib.tests.test_nonascii',
3940
 
        'bzrlib.tests.test_options',
3941
 
        'bzrlib.tests.test_osutils',
3942
 
        'bzrlib.tests.test_osutils_encodings',
3943
 
        'bzrlib.tests.test_pack',
3944
 
        'bzrlib.tests.test_patch',
3945
 
        'bzrlib.tests.test_patches',
3946
 
        'bzrlib.tests.test_permissions',
3947
 
        'bzrlib.tests.test_plugins',
3948
 
        'bzrlib.tests.test_progress',
3949
 
        'bzrlib.tests.test_pyutils',
3950
 
        'bzrlib.tests.test_read_bundle',
3951
 
        'bzrlib.tests.test_reconcile',
3952
 
        'bzrlib.tests.test_reconfigure',
3953
 
        'bzrlib.tests.test_registry',
3954
 
        'bzrlib.tests.test_remote',
3955
 
        'bzrlib.tests.test_rename_map',
3956
 
        'bzrlib.tests.test_repository',
3957
 
        'bzrlib.tests.test_revert',
3958
 
        'bzrlib.tests.test_revision',
3959
 
        'bzrlib.tests.test_revisionspec',
3960
 
        'bzrlib.tests.test_revisiontree',
3961
 
        'bzrlib.tests.test_rio',
3962
 
        'bzrlib.tests.test_rules',
3963
 
        'bzrlib.tests.test_sampler',
3964
 
        'bzrlib.tests.test_scenarios',
3965
 
        'bzrlib.tests.test_script',
3966
 
        'bzrlib.tests.test_selftest',
3967
 
        'bzrlib.tests.test_serializer',
3968
 
        'bzrlib.tests.test_setup',
3969
 
        'bzrlib.tests.test_sftp_transport',
3970
 
        'bzrlib.tests.test_shelf',
3971
 
        'bzrlib.tests.test_shelf_ui',
3972
 
        'bzrlib.tests.test_smart',
3973
 
        'bzrlib.tests.test_smart_add',
3974
 
        'bzrlib.tests.test_smart_request',
3975
 
        'bzrlib.tests.test_smart_transport',
3976
 
        'bzrlib.tests.test_smtp_connection',
3977
 
        'bzrlib.tests.test_source',
3978
 
        'bzrlib.tests.test_ssh_transport',
3979
 
        'bzrlib.tests.test_status',
3980
 
        'bzrlib.tests.test_store',
3981
 
        'bzrlib.tests.test_strace',
3982
 
        'bzrlib.tests.test_subsume',
3983
 
        'bzrlib.tests.test_switch',
3984
 
        'bzrlib.tests.test_symbol_versioning',
3985
 
        'bzrlib.tests.test_tag',
3986
 
        'bzrlib.tests.test_test_server',
3987
 
        'bzrlib.tests.test_testament',
3988
 
        'bzrlib.tests.test_textfile',
3989
 
        'bzrlib.tests.test_textmerge',
3990
 
        'bzrlib.tests.test_cethread',
3991
 
        'bzrlib.tests.test_timestamp',
3992
 
        'bzrlib.tests.test_trace',
3993
 
        'bzrlib.tests.test_transactions',
3994
 
        'bzrlib.tests.test_transform',
3995
 
        'bzrlib.tests.test_transport',
3996
 
        'bzrlib.tests.test_transport_log',
3997
 
        'bzrlib.tests.test_tree',
3998
 
        'bzrlib.tests.test_treebuilder',
3999
 
        'bzrlib.tests.test_treeshape',
4000
 
        'bzrlib.tests.test_tsort',
4001
 
        'bzrlib.tests.test_tuned_gzip',
4002
 
        'bzrlib.tests.test_ui',
4003
 
        'bzrlib.tests.test_uncommit',
4004
 
        'bzrlib.tests.test_upgrade',
4005
 
        'bzrlib.tests.test_upgrade_stacked',
4006
 
        'bzrlib.tests.test_urlutils',
4007
 
        'bzrlib.tests.test_utextwrap',
4008
 
        'bzrlib.tests.test_version',
4009
 
        'bzrlib.tests.test_version_info',
4010
 
        'bzrlib.tests.test_versionedfile',
4011
 
        'bzrlib.tests.test_weave',
4012
 
        'bzrlib.tests.test_whitebox',
4013
 
        'bzrlib.tests.test_win32utils',
4014
 
        'bzrlib.tests.test_workingtree',
4015
 
        'bzrlib.tests.test_workingtree_4',
4016
 
        'bzrlib.tests.test_wsgi',
4017
 
        'bzrlib.tests.test_xml',
4018
 
        ]
4019
 
 
4020
 
 
4021
 
def _test_suite_modules_to_doctest():
4022
 
    """Return the list of modules to doctest."""
4023
 
    if __doc__ is None:
4024
 
        # GZ 2009-03-31: No docstrings with -OO so there's nothing to doctest
4025
 
        return []
4026
 
    return [
4027
 
        'bzrlib',
4028
 
        'bzrlib.branchbuilder',
4029
 
        'bzrlib.decorators',
4030
 
        'bzrlib.inventory',
4031
 
        'bzrlib.iterablefile',
4032
 
        'bzrlib.lockdir',
4033
 
        'bzrlib.merge3',
4034
 
        'bzrlib.option',
4035
 
        'bzrlib.pyutils',
4036
 
        'bzrlib.symbol_versioning',
4037
 
        'bzrlib.tests',
4038
 
        'bzrlib.tests.fixtures',
4039
 
        'bzrlib.timestamp',
4040
 
        'bzrlib.transport.http',
4041
 
        'bzrlib.version_info_formats.format_custom',
4042
 
        ]
4043
 
 
4044
 
 
4045
3055
def test_suite(keep_only=None, starting_with=None):
4046
3056
    """Build and return TestSuite for the whole of bzrlib.
4047
3057
 
4053
3063
    This function can be replaced if you need to change the default test
4054
3064
    suite on a global basis, but it is not encouraged.
4055
3065
    """
 
3066
    testmod_names = [
 
3067
                   'bzrlib.doc',
 
3068
                   'bzrlib.tests.blackbox',
 
3069
                   'bzrlib.tests.branch_implementations',
 
3070
                   'bzrlib.tests.bzrdir_implementations',
 
3071
                   'bzrlib.tests.commands',
 
3072
                   'bzrlib.tests.interrepository_implementations',
 
3073
                   'bzrlib.tests.intertree_implementations',
 
3074
                   'bzrlib.tests.inventory_implementations',
 
3075
                   'bzrlib.tests.per_interbranch',
 
3076
                   'bzrlib.tests.per_lock',
 
3077
                   'bzrlib.tests.per_repository',
 
3078
                   'bzrlib.tests.per_repository_reference',
 
3079
                   'bzrlib.tests.test__dirstate_helpers',
 
3080
                   'bzrlib.tests.test__walkdirs_win32',
 
3081
                   'bzrlib.tests.test_ancestry',
 
3082
                   'bzrlib.tests.test_annotate',
 
3083
                   'bzrlib.tests.test_api',
 
3084
                   'bzrlib.tests.test_atomicfile',
 
3085
                   'bzrlib.tests.test_bad_files',
 
3086
                   'bzrlib.tests.test_bisect_multi',
 
3087
                   'bzrlib.tests.test_branch',
 
3088
                   'bzrlib.tests.test_branchbuilder',
 
3089
                   'bzrlib.tests.test_btree_index',
 
3090
                   'bzrlib.tests.test_bugtracker',
 
3091
                   'bzrlib.tests.test_bundle',
 
3092
                   'bzrlib.tests.test_bzrdir',
 
3093
                   'bzrlib.tests.test_cache_utf8',
 
3094
                   'bzrlib.tests.test_clean_tree',
 
3095
                   'bzrlib.tests.test_chunk_writer',
 
3096
                   'bzrlib.tests.test__chunks_to_lines',
 
3097
                   'bzrlib.tests.test_commands',
 
3098
                   'bzrlib.tests.test_commit',
 
3099
                   'bzrlib.tests.test_commit_merge',
 
3100
                   'bzrlib.tests.test_config',
 
3101
                   'bzrlib.tests.test_conflicts',
 
3102
                   'bzrlib.tests.test_counted_lock',
 
3103
                   'bzrlib.tests.test_decorators',
 
3104
                   'bzrlib.tests.test_delta',
 
3105
                   'bzrlib.tests.test_debug',
 
3106
                   'bzrlib.tests.test_deprecated_graph',
 
3107
                   'bzrlib.tests.test_diff',
 
3108
                   'bzrlib.tests.test_directory_service',
 
3109
                   'bzrlib.tests.test_dirstate',
 
3110
                   'bzrlib.tests.test_email_message',
 
3111
                   'bzrlib.tests.test_errors',
 
3112
                   'bzrlib.tests.test_export',
 
3113
                   'bzrlib.tests.test_extract',
 
3114
                   'bzrlib.tests.test_fetch',
 
3115
                   'bzrlib.tests.test_fifo_cache',
 
3116
                   'bzrlib.tests.test_filters',
 
3117
                   'bzrlib.tests.test_ftp_transport',
 
3118
                   'bzrlib.tests.test_foreign',
 
3119
                   'bzrlib.tests.test_generate_docs',
 
3120
                   'bzrlib.tests.test_generate_ids',
 
3121
                   'bzrlib.tests.test_globbing',
 
3122
                   'bzrlib.tests.test_gpg',
 
3123
                   'bzrlib.tests.test_graph',
 
3124
                   'bzrlib.tests.test_hashcache',
 
3125
                   'bzrlib.tests.test_help',
 
3126
                   'bzrlib.tests.test_hooks',
 
3127
                   'bzrlib.tests.test_http',
 
3128
                   'bzrlib.tests.test_http_implementations',
 
3129
                   'bzrlib.tests.test_http_response',
 
3130
                   'bzrlib.tests.test_https_ca_bundle',
 
3131
                   'bzrlib.tests.test_identitymap',
 
3132
                   'bzrlib.tests.test_ignores',
 
3133
                   'bzrlib.tests.test_index',
 
3134
                   'bzrlib.tests.test_info',
 
3135
                   'bzrlib.tests.test_inv',
 
3136
                   'bzrlib.tests.test_knit',
 
3137
                   'bzrlib.tests.test_lazy_import',
 
3138
                   'bzrlib.tests.test_lazy_regex',
 
3139
                   'bzrlib.tests.test_lockable_files',
 
3140
                   'bzrlib.tests.test_lockdir',
 
3141
                   'bzrlib.tests.test_log',
 
3142
                   'bzrlib.tests.test_lru_cache',
 
3143
                   'bzrlib.tests.test_lsprof',
 
3144
                   'bzrlib.tests.test_mail_client',
 
3145
                   'bzrlib.tests.test_memorytree',
 
3146
                   'bzrlib.tests.test_merge',
 
3147
                   'bzrlib.tests.test_merge3',
 
3148
                   'bzrlib.tests.test_merge_core',
 
3149
                   'bzrlib.tests.test_merge_directive',
 
3150
                   'bzrlib.tests.test_missing',
 
3151
                   'bzrlib.tests.test_msgeditor',
 
3152
                   'bzrlib.tests.test_multiparent',
 
3153
                   'bzrlib.tests.test_mutabletree',
 
3154
                   'bzrlib.tests.test_nonascii',
 
3155
                   'bzrlib.tests.test_options',
 
3156
                   'bzrlib.tests.test_osutils',
 
3157
                   'bzrlib.tests.test_osutils_encodings',
 
3158
                   'bzrlib.tests.test_pack',
 
3159
                   'bzrlib.tests.test_pack_repository',
 
3160
                   'bzrlib.tests.test_patch',
 
3161
                   'bzrlib.tests.test_patches',
 
3162
                   'bzrlib.tests.test_permissions',
 
3163
                   'bzrlib.tests.test_plugins',
 
3164
                   'bzrlib.tests.test_progress',
 
3165
                   'bzrlib.tests.test_read_bundle',
 
3166
                   'bzrlib.tests.test_reconcile',
 
3167
                   'bzrlib.tests.test_reconfigure',
 
3168
                   'bzrlib.tests.test_registry',
 
3169
                   'bzrlib.tests.test_remote',
 
3170
                   'bzrlib.tests.test_rename_map',
 
3171
                   'bzrlib.tests.test_repository',
 
3172
                   'bzrlib.tests.test_revert',
 
3173
                   'bzrlib.tests.test_revision',
 
3174
                   'bzrlib.tests.test_revisionspec',
 
3175
                   'bzrlib.tests.test_revisiontree',
 
3176
                   'bzrlib.tests.test_rio',
 
3177
                   'bzrlib.tests.test_rules',
 
3178
                   'bzrlib.tests.test_sampler',
 
3179
                   'bzrlib.tests.test_selftest',
 
3180
                   'bzrlib.tests.test_setup',
 
3181
                   'bzrlib.tests.test_sftp_transport',
 
3182
                   'bzrlib.tests.test_shelf',
 
3183
                   'bzrlib.tests.test_shelf_ui',
 
3184
                   'bzrlib.tests.test_smart',
 
3185
                   'bzrlib.tests.test_smart_add',
 
3186
                   'bzrlib.tests.test_smart_request',
 
3187
                   'bzrlib.tests.test_smart_transport',
 
3188
                   'bzrlib.tests.test_smtp_connection',
 
3189
                   'bzrlib.tests.test_source',
 
3190
                   'bzrlib.tests.test_ssh_transport',
 
3191
                   'bzrlib.tests.test_status',
 
3192
                   'bzrlib.tests.test_store',
 
3193
                   'bzrlib.tests.test_strace',
 
3194
                   'bzrlib.tests.test_subsume',
 
3195
                   'bzrlib.tests.test_switch',
 
3196
                   'bzrlib.tests.test_symbol_versioning',
 
3197
                   'bzrlib.tests.test_tag',
 
3198
                   'bzrlib.tests.test_testament',
 
3199
                   'bzrlib.tests.test_textfile',
 
3200
                   'bzrlib.tests.test_textmerge',
 
3201
                   'bzrlib.tests.test_timestamp',
 
3202
                   'bzrlib.tests.test_trace',
 
3203
                   'bzrlib.tests.test_transactions',
 
3204
                   'bzrlib.tests.test_transform',
 
3205
                   'bzrlib.tests.test_transport',
 
3206
                   'bzrlib.tests.test_transport_implementations',
 
3207
                   'bzrlib.tests.test_transport_log',
 
3208
                   'bzrlib.tests.test_tree',
 
3209
                   'bzrlib.tests.test_treebuilder',
 
3210
                   'bzrlib.tests.test_tsort',
 
3211
                   'bzrlib.tests.test_tuned_gzip',
 
3212
                   'bzrlib.tests.test_ui',
 
3213
                   'bzrlib.tests.test_uncommit',
 
3214
                   'bzrlib.tests.test_upgrade',
 
3215
                   'bzrlib.tests.test_upgrade_stacked',
 
3216
                   'bzrlib.tests.test_urlutils',
 
3217
                   'bzrlib.tests.test_version',
 
3218
                   'bzrlib.tests.test_version_info',
 
3219
                   'bzrlib.tests.test_versionedfile',
 
3220
                   'bzrlib.tests.test_weave',
 
3221
                   'bzrlib.tests.test_whitebox',
 
3222
                   'bzrlib.tests.test_win32utils',
 
3223
                   'bzrlib.tests.test_workingtree',
 
3224
                   'bzrlib.tests.test_workingtree_4',
 
3225
                   'bzrlib.tests.test_wsgi',
 
3226
                   'bzrlib.tests.test_xml',
 
3227
                   'bzrlib.tests.tree_implementations',
 
3228
                   'bzrlib.tests.workingtree_implementations',
 
3229
                   'bzrlib.util.tests.test_bencode',
 
3230
                   ]
4056
3231
 
4057
3232
    loader = TestUtil.TestLoader()
4058
3233
 
4059
 
    if keep_only is not None:
4060
 
        id_filter = TestIdList(keep_only)
4061
3234
    if starting_with:
 
3235
        starting_with = [test_prefix_alias_registry.resolve_alias(start)
 
3236
                         for start in starting_with]
4062
3237
        # We take precedence over keep_only because *at loading time* using
4063
3238
        # both options means we will load less tests for the same final result.
4064
3239
        def interesting_module(name):
4074
3249
        loader = TestUtil.FilteredByModuleTestLoader(interesting_module)
4075
3250
 
4076
3251
    elif keep_only is not None:
 
3252
        id_filter = TestIdList(keep_only)
4077
3253
        loader = TestUtil.FilteredByModuleTestLoader(id_filter.refers_to)
4078
3254
        def interesting_module(name):
4079
3255
            return id_filter.refers_to(name)
4087
3263
    suite = loader.suiteClass()
4088
3264
 
4089
3265
    # modules building their suite with loadTestsFromModuleNames
4090
 
    suite.addTest(loader.loadTestsFromModuleNames(_test_suite_testmod_names()))
4091
 
 
4092
 
    for mod in _test_suite_modules_to_doctest():
 
3266
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
 
3267
 
 
3268
    modules_to_doctest = [
 
3269
        'bzrlib',
 
3270
        'bzrlib.branchbuilder',
 
3271
        'bzrlib.export',
 
3272
        'bzrlib.inventory',
 
3273
        'bzrlib.iterablefile',
 
3274
        'bzrlib.lockdir',
 
3275
        'bzrlib.merge3',
 
3276
        'bzrlib.option',
 
3277
        'bzrlib.symbol_versioning',
 
3278
        'bzrlib.tests',
 
3279
        'bzrlib.timestamp',
 
3280
        'bzrlib.version_info_formats.format_custom',
 
3281
        ]
 
3282
 
 
3283
    for mod in modules_to_doctest:
4093
3284
        if not interesting_module(mod):
4094
3285
            # No tests to keep here, move along
4095
3286
            continue
4096
3287
        try:
4097
3288
            # note that this really does mean "report only" -- doctest
4098
3289
            # still runs the rest of the examples
4099
 
            doc_suite = IsolatedDocTestSuite(
4100
 
                mod, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
 
3290
            doc_suite = doctest.DocTestSuite(mod,
 
3291
                optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
4101
3292
        except ValueError, e:
4102
3293
            print '**failed to get doctest for: %s\n%s' % (mod, e)
4103
3294
            raise
4106
3297
        suite.addTest(doc_suite)
4107
3298
 
4108
3299
    default_encoding = sys.getdefaultencoding()
4109
 
    for name, plugin in _mod_plugin.plugins().items():
 
3300
    for name, plugin in bzrlib.plugin.plugins().items():
4110
3301
        if not interesting_module(plugin.module.__name__):
4111
3302
            continue
4112
3303
        plugin_suite = plugin.test_suite()
4118
3309
        if plugin_suite is not None:
4119
3310
            suite.addTest(plugin_suite)
4120
3311
        if default_encoding != sys.getdefaultencoding():
4121
 
            trace.warning(
 
3312
            bzrlib.trace.warning(
4122
3313
                'Plugin "%s" tried to reset default encoding to: %s', name,
4123
3314
                sys.getdefaultencoding())
4124
3315
            reload(sys)
4125
3316
            sys.setdefaultencoding(default_encoding)
4126
3317
 
 
3318
    if starting_with:
 
3319
        suite = filter_suite_by_id_startswith(suite, starting_with)
 
3320
 
4127
3321
    if keep_only is not None:
4128
3322
        # Now that the referred modules have loaded their tests, keep only the
4129
3323
        # requested ones.
4139
3333
            # Some tests mentioned in the list are not in the test suite. The
4140
3334
            # list may be out of date, report to the tester.
4141
3335
            for id in not_found:
4142
 
                trace.warning('"%s" not found in the test suite', id)
 
3336
                bzrlib.trace.warning('"%s" not found in the test suite', id)
4143
3337
        for id in duplicates:
4144
 
            trace.warning('"%s" is used as an id by several tests', id)
 
3338
            bzrlib.trace.warning('"%s" is used as an id by several tests', id)
4145
3339
 
4146
3340
    return suite
4147
3341
 
4148
3342
 
4149
 
def multiply_scenarios(*scenarios):
4150
 
    """Multiply two or more iterables of scenarios.
4151
 
 
4152
 
    It is safe to pass scenario generators or iterators.
4153
 
 
4154
 
    :returns: A list of compound scenarios: the cross-product of all 
4155
 
        scenarios, with the names concatenated and the parameters
4156
 
        merged together.
4157
 
    """
4158
 
    return reduce(_multiply_two_scenarios, map(list, scenarios))
4159
 
 
4160
 
 
4161
 
def _multiply_two_scenarios(scenarios_left, scenarios_right):
 
3343
def multiply_scenarios(scenarios_left, scenarios_right):
4162
3344
    """Multiply two sets of scenarios.
4163
3345
 
4164
3346
    :returns: the cartesian product of the two sets of scenarios, that is
4190
3372
    the scenario name at the end of its id(), and updating the test object's
4191
3373
    __dict__ with the scenario_param_dict.
4192
3374
 
4193
 
    >>> import bzrlib.tests.test_sampler
4194
3375
    >>> r = multiply_tests(
4195
3376
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
4196
3377
    ...     [('one', dict(param=1)),
4197
3378
    ...      ('two', dict(param=2))],
4198
 
    ...     TestUtil.TestSuite())
 
3379
    ...     TestSuite())
4199
3380
    >>> tests = list(iter_suite_tests(r))
4200
3381
    >>> len(tests)
4201
3382
    2
4248
3429
    :param new_id: The id to assign to it.
4249
3430
    :return: The new test.
4250
3431
    """
4251
 
    new_test = copy.copy(test)
 
3432
    from copy import deepcopy
 
3433
    new_test = deepcopy(test)
4252
3434
    new_test.id = lambda: new_id
4253
 
    # XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
4254
 
    # causes cloned tests to share the 'details' dict.  This makes it hard to
4255
 
    # read the test output for parameterized tests, because tracebacks will be
4256
 
    # associated with irrelevant tests.
4257
 
    try:
4258
 
        details = new_test._TestCase__details
4259
 
    except AttributeError:
4260
 
        # must be a different version of testtools than expected.  Do nothing.
4261
 
        pass
4262
 
    else:
4263
 
        # Reset the '__details' dict.
4264
 
        new_test._TestCase__details = {}
4265
3435
    return new_test
4266
3436
 
4267
3437
 
4268
 
def permute_tests_for_extension(standard_tests, loader, py_module_name,
4269
 
                                ext_module_name):
4270
 
    """Helper for permutating tests against an extension module.
4271
 
 
4272
 
    This is meant to be used inside a modules 'load_tests()' function. It will
4273
 
    create 2 scenarios, and cause all tests in the 'standard_tests' to be run
4274
 
    against both implementations. Setting 'test.module' to the appropriate
4275
 
    module. See bzrlib.tests.test__chk_map.load_tests as an example.
4276
 
 
4277
 
    :param standard_tests: A test suite to permute
4278
 
    :param loader: A TestLoader
4279
 
    :param py_module_name: The python path to a python module that can always
4280
 
        be loaded, and will be considered the 'python' implementation. (eg
4281
 
        'bzrlib._chk_map_py')
4282
 
    :param ext_module_name: The python path to an extension module. If the
4283
 
        module cannot be loaded, a single test will be added, which notes that
4284
 
        the module is not available. If it can be loaded, all standard_tests
4285
 
        will be run against that module.
4286
 
    :return: (suite, feature) suite is a test-suite that has all the permuted
4287
 
        tests. feature is the Feature object that can be used to determine if
4288
 
        the module is available.
4289
 
    """
4290
 
 
4291
 
    py_module = pyutils.get_named_object(py_module_name)
4292
 
    scenarios = [
4293
 
        ('python', {'module': py_module}),
4294
 
    ]
4295
 
    suite = loader.suiteClass()
4296
 
    feature = ModuleAvailableFeature(ext_module_name)
4297
 
    if feature.available():
4298
 
        scenarios.append(('C', {'module': feature.module}))
4299
 
    else:
4300
 
        # the compiled module isn't available, so we add a failing test
4301
 
        class FailWithoutFeature(TestCase):
4302
 
            def test_fail(self):
4303
 
                self.requireFeature(feature)
4304
 
        suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
4305
 
    result = multiply_tests(standard_tests, scenarios, suite)
4306
 
    return result, feature
4307
 
 
4308
 
 
4309
 
def _rmtree_temp_dir(dirname, test_id=None):
 
3438
def _rmtree_temp_dir(dirname):
4310
3439
    # If LANG=C we probably have created some bogus paths
4311
3440
    # which rmtree(unicode) will fail to delete
4312
3441
    # so make sure we are using rmtree(str) to delete everything
4321
3450
    try:
4322
3451
        osutils.rmtree(dirname)
4323
3452
    except OSError, e:
4324
 
        # We don't want to fail here because some useful display will be lost
4325
 
        # otherwise. Polluting the tmp dir is bad, but not giving all the
4326
 
        # possible info to the test runner is even worse.
4327
 
        if test_id != None:
4328
 
            ui.ui_factory.clear_term()
4329
 
            sys.stderr.write('\nWhile running: %s\n' % (test_id,))
4330
 
        # Ugly, but the last thing we want here is fail, so bear with it.
4331
 
        printable_e = str(e).decode(osutils.get_user_encoding(), 'replace'
4332
 
                                    ).encode('ascii', 'replace')
4333
 
        sys.stderr.write('Unable to remove testing dir %s\n%s'
4334
 
                         % (os.path.basename(dirname), printable_e))
 
3453
        if sys.platform == 'win32' and e.errno == errno.EACCES:
 
3454
            sys.stderr.write(('Permission denied: '
 
3455
                                 'unable to remove testing dir '
 
3456
                                 '%s\n' % os.path.basename(dirname)))
 
3457
        else:
 
3458
            raise
4335
3459
 
4336
3460
 
4337
3461
class Feature(object):
4419
3543
UnicodeFilenameFeature = _UnicodeFilenameFeature()
4420
3544
 
4421
3545
 
4422
 
class _CompatabilityThunkFeature(Feature):
4423
 
    """This feature is just a thunk to another feature.
4424
 
 
4425
 
    It issues a deprecation warning if it is accessed, to let you know that you
4426
 
    should really use a different feature.
4427
 
    """
4428
 
 
4429
 
    def __init__(self, dep_version, module, name,
4430
 
                 replacement_name, replacement_module=None):
4431
 
        super(_CompatabilityThunkFeature, self).__init__()
4432
 
        self._module = module
4433
 
        if replacement_module is None:
4434
 
            replacement_module = module
4435
 
        self._replacement_module = replacement_module
4436
 
        self._name = name
4437
 
        self._replacement_name = replacement_name
4438
 
        self._dep_version = dep_version
4439
 
        self._feature = None
4440
 
 
4441
 
    def _ensure(self):
4442
 
        if self._feature is None:
4443
 
            depr_msg = self._dep_version % ('%s.%s'
4444
 
                                            % (self._module, self._name))
4445
 
            use_msg = ' Use %s.%s instead.' % (self._replacement_module,
4446
 
                                               self._replacement_name)
4447
 
            symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4448
 
            # Import the new feature and use it as a replacement for the
4449
 
            # deprecated one.
4450
 
            self._feature = pyutils.get_named_object(
4451
 
                self._replacement_module, self._replacement_name)
4452
 
 
4453
 
    def _probe(self):
4454
 
        self._ensure()
4455
 
        return self._feature._probe()
4456
 
 
4457
 
 
4458
 
class ModuleAvailableFeature(Feature):
4459
 
    """This is a feature than describes a module we want to be available.
4460
 
 
4461
 
    Declare the name of the module in __init__(), and then after probing, the
4462
 
    module will be available as 'self.module'.
4463
 
 
4464
 
    :ivar module: The module if it is available, else None.
4465
 
    """
4466
 
 
4467
 
    def __init__(self, module_name):
4468
 
        super(ModuleAvailableFeature, self).__init__()
4469
 
        self.module_name = module_name
4470
 
 
4471
 
    def _probe(self):
4472
 
        try:
4473
 
            self._module = __import__(self.module_name, {}, {}, [''])
4474
 
            return True
4475
 
        except ImportError:
4476
 
            return False
4477
 
 
4478
 
    @property
4479
 
    def module(self):
4480
 
        if self.available(): # Make sure the probe has been done
4481
 
            return self._module
4482
 
        return None
4483
 
 
4484
 
    def feature_name(self):
4485
 
        return self.module_name
4486
 
 
4487
 
 
4488
3546
def probe_unicode_in_user_encoding():
4489
3547
    """Try to encode several unicode strings to use in unicode-aware tests.
4490
3548
    Return first successfull match.
4559
3617
UnicodeFilename = _UnicodeFilename()
4560
3618
 
4561
3619
 
4562
 
class _ByteStringNamedFilesystem(Feature):
4563
 
    """Is the filesystem based on bytes?"""
4564
 
 
4565
 
    def _probe(self):
4566
 
        if os.name == "posix":
4567
 
            return True
4568
 
        return False
4569
 
 
4570
 
ByteStringNamedFilesystem = _ByteStringNamedFilesystem()
4571
 
 
4572
 
 
4573
3620
class _UTF8Filesystem(Feature):
4574
3621
    """Is the filesystem UTF-8?"""
4575
3622
 
4581
3628
UTF8Filesystem = _UTF8Filesystem()
4582
3629
 
4583
3630
 
4584
 
class _BreakinFeature(Feature):
4585
 
    """Does this platform support the breakin feature?"""
4586
 
 
4587
 
    def _probe(self):
4588
 
        from bzrlib import breakin
4589
 
        if breakin.determine_signal() is None:
4590
 
            return False
4591
 
        if sys.platform == 'win32':
4592
 
            # Windows doesn't have os.kill, and we catch the SIGBREAK signal.
4593
 
            # We trigger SIGBREAK via a Console api so we need ctypes to
4594
 
            # access the function
4595
 
            try:
4596
 
                import ctypes
4597
 
            except OSError:
4598
 
                return False
4599
 
        return True
4600
 
 
4601
 
    def feature_name(self):
4602
 
        return "SIGQUIT or SIGBREAK w/ctypes on win32"
4603
 
 
4604
 
 
4605
 
BreakinFeature = _BreakinFeature()
4606
 
 
4607
 
 
4608
3631
class _CaseInsCasePresFilenameFeature(Feature):
4609
3632
    """Is the file-system case insensitive, but case-preserving?"""
4610
3633
 
4660
3683
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
4661
3684
 
4662
3685
 
4663
 
class _CaseSensitiveFilesystemFeature(Feature):
 
3686
class _SubUnitFeature(Feature):
 
3687
    """Check if subunit is available."""
4664
3688
 
4665
3689
    def _probe(self):
4666
 
        if CaseInsCasePresFilenameFeature.available():
4667
 
            return False
4668
 
        elif CaseInsensitiveFilesystemFeature.available():
4669
 
            return False
4670
 
        else:
 
3690
        try:
 
3691
            import subunit
4671
3692
            return True
 
3693
        except ImportError:
 
3694
            return False
4672
3695
 
4673
3696
    def feature_name(self):
4674
 
        return 'case-sensitive filesystem'
4675
 
 
4676
 
# new coding style is for feature instances to be lowercase
4677
 
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
4678
 
 
4679
 
 
 
3697
        return 'subunit'
 
3698
 
 
3699
SubUnitFeature = _SubUnitFeature()
4680
3700
# Only define SubUnitBzrRunner if subunit is available.
4681
3701
try:
4682
3702
    from subunit import TestProtocolClient
4683
 
    from subunit.test_results import AutoTimingTestResultDecorator
4684
 
    class SubUnitBzrProtocolClient(TestProtocolClient):
4685
 
 
4686
 
        def addSuccess(self, test, details=None):
4687
 
            # The subunit client always includes the details in the subunit
4688
 
            # stream, but we don't want to include it in ours.
4689
 
            if details is not None and 'log' in details:
4690
 
                del details['log']
4691
 
            return super(SubUnitBzrProtocolClient, self).addSuccess(
4692
 
                test, details)
4693
 
 
4694
3703
    class SubUnitBzrRunner(TextTestRunner):
4695
3704
        def run(self, test):
4696
 
            result = AutoTimingTestResultDecorator(
4697
 
                SubUnitBzrProtocolClient(self.stream))
 
3705
            # undo out claim for testing which looks like a test start to subunit
 
3706
            self.stream.write("success: %s\n" % (osutils.realpath(sys.argv[0]),))
 
3707
            result = TestProtocolClient(self.stream)
4698
3708
            test.run(result)
4699
3709
            return result
4700
3710
except ImportError:
4701
3711
    pass
4702
 
 
4703
 
class _PosixPermissionsFeature(Feature):
4704
 
 
4705
 
    def _probe(self):
4706
 
        def has_perms():
4707
 
            # create temporary file and check if specified perms are maintained.
4708
 
            import tempfile
4709
 
 
4710
 
            write_perms = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
4711
 
            f = tempfile.mkstemp(prefix='bzr_perms_chk_')
4712
 
            fd, name = f
4713
 
            os.close(fd)
4714
 
            os.chmod(name, write_perms)
4715
 
 
4716
 
            read_perms = os.stat(name).st_mode & 0777
4717
 
            os.unlink(name)
4718
 
            return (write_perms == read_perms)
4719
 
 
4720
 
        return (os.name == 'posix') and has_perms()
4721
 
 
4722
 
    def feature_name(self):
4723
 
        return 'POSIX permissions support'
4724
 
 
4725
 
posix_permissions_feature = _PosixPermissionsFeature()