~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Jelmer Vernooij
  • Date: 2009-04-10 15:58:09 UTC
  • mto: This revision was merged to the branch mainline in revision 4284.
  • Revision ID: jelmer@samba.org-20090410155809-kdibzcjvp7pdb83f
Fix missing import.

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
 
36
import math
39
37
import os
40
 
import platform
41
 
import pprint
 
38
from pprint import pformat
42
39
import random
43
40
import re
44
41
import shlex
45
42
import stat
46
 
import subprocess
 
43
from subprocess import Popen, PIPE, STDOUT
47
44
import sys
48
45
import tempfile
49
46
import threading
50
47
import time
51
 
import traceback
52
48
import unittest
53
49
import warnings
54
50
 
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
51
 
63
 
import bzrlib
64
52
from bzrlib import (
65
53
    branchbuilder,
66
54
    bzrdir,
67
 
    chk_map,
68
 
    commands as _mod_commands,
69
 
    config,
70
55
    debug,
71
56
    errors,
72
57
    hooks,
73
 
    lock as _mod_lock,
74
 
    lockdir,
75
58
    memorytree,
76
59
    osutils,
77
 
    plugin as _mod_plugin,
78
 
    pyutils,
 
60
    progress,
79
61
    ui,
80
62
    urlutils,
81
63
    registry,
82
 
    symbol_versioning,
83
 
    trace,
84
 
    transport as _mod_transport,
85
64
    workingtree,
86
65
    )
 
66
import bzrlib.branch
 
67
import bzrlib.commands
 
68
import bzrlib.timestamp
 
69
import bzrlib.export
 
70
import bzrlib.inventory
 
71
import bzrlib.iterablefile
 
72
import bzrlib.lockdir
87
73
try:
88
74
    import bzrlib.lsprof
89
75
except ImportError:
90
76
    # lsprof not available
91
77
    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
 
78
from bzrlib.merge import merge_inner
 
79
import bzrlib.merge3
 
80
import bzrlib.plugin
 
81
from bzrlib.smart import client, request, server
 
82
import bzrlib.store
 
83
from bzrlib import symbol_versioning
 
84
from bzrlib.symbol_versioning import (
 
85
    DEPRECATED_PARAMETER,
 
86
    deprecated_function,
 
87
    deprecated_method,
 
88
    deprecated_passed,
 
89
    )
 
90
import bzrlib.trace
 
91
from bzrlib.transport import get_transport
 
92
import bzrlib.transport
 
93
from bzrlib.transport.local import LocalURLServer
 
94
from bzrlib.transport.memory import MemoryServer
 
95
from bzrlib.transport.readonly import ReadonlyServer
 
96
from bzrlib.trace import mutter, note
 
97
from bzrlib.tests import TestUtil
 
98
from bzrlib.tests.http_server import HttpServer
 
99
from bzrlib.tests.TestUtil import (
 
100
                          TestSuite,
 
101
                          TestLoader,
 
102
                          )
 
103
from bzrlib.tests.treeshape import build_tree_contents
 
104
import bzrlib.version_info_formats.format_custom
 
105
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
104
106
 
105
107
# Mark this python module as being part of the implementation
106
108
# of unittest: this gives us better tracebacks where the last
107
109
# shown frame is the test code, not our assertXYZ.
108
110
__unittest = 1
109
111
 
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):
 
112
default_transport = LocalURLServer
 
113
 
 
114
 
 
115
class ExtendedTestResult(unittest._TextTestResult):
217
116
    """Accepts, reports and accumulates the results of running tests.
218
117
 
219
118
    Compared to the unittest version this class adds support for
233
132
 
234
133
    def __init__(self, stream, descriptions, verbosity,
235
134
                 bench_history=None,
236
 
                 strict=False,
 
135
                 num_tests=None,
237
136
                 ):
238
137
        """Construct new TestResult.
239
138
 
240
139
        :param bench_history: Optionally, a writable file object to accumulate
241
140
            benchmark results.
242
141
        """
243
 
        testtools.TextTestResult.__init__(self, stream)
 
142
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
244
143
        if bench_history is not None:
245
144
            from bzrlib.version import _get_bzr_source_tree
246
145
            src_tree = _get_bzr_source_tree()
257
156
            bench_history.write("--date %s %s\n" % (time.time(), revision_id))
258
157
        self._bench_history = bench_history
259
158
        self.ui = ui.ui_factory
260
 
        self.num_tests = 0
 
159
        self.num_tests = num_tests
261
160
        self.error_count = 0
262
161
        self.failure_count = 0
263
162
        self.known_failure_count = 0
266
165
        self.unsupported = {}
267
166
        self.count = 0
268
167
        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):
 
168
 
 
169
    def _extractBenchmarkTime(self, testCase):
331
170
        """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
171
        return getattr(testCase, "_benchtime", None)
335
172
 
336
173
    def _elapsedTestTimeString(self):
337
174
        """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))
 
175
        return self._formatTime(time.time() - self._start_time)
340
176
 
341
177
    def _testTimeString(self, testCase):
342
178
        benchmark_time = self._extractBenchmarkTime(testCase)
343
179
        if benchmark_time is not None:
344
 
            return self._formatTime(benchmark_time) + "*"
 
180
            return "%s/%s" % (
 
181
                self._formatTime(benchmark_time),
 
182
                self._elapsedTestTimeString())
345
183
        else:
346
 
            return self._elapsedTestTimeString()
 
184
            return "           %s" % self._elapsedTestTimeString()
347
185
 
348
186
    def _formatTime(self, seconds):
349
187
        """Format seconds as milliseconds with leading spaces."""
353
191
 
354
192
    def _shortened_test_description(self, test):
355
193
        what = test.id()
356
 
        what = re.sub(r'^bzrlib\.tests\.', '', what)
 
194
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
357
195
        return what
358
196
 
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
197
    def startTest(self, test):
368
 
        super(ExtendedTestResult, self).startTest(test)
369
 
        if self.count == 0:
370
 
            self.startTests()
371
 
        self.count += 1
 
198
        unittest.TestResult.startTest(self, test)
372
199
        self.report_test_start(test)
373
200
        test.number = self.count
374
201
        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
202
 
414
203
    def _recordTestStartTime(self):
415
204
        """Record that a test has started."""
416
 
        self._start_datetime = self._now()
 
205
        self._start_time = time.time()
 
206
 
 
207
    def _cleanupLogFile(self, test):
 
208
        # We can only do this if we have one of our TestCases, not if
 
209
        # we have a doctest.
 
210
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
211
        if setKeepLogfile is not None:
 
212
            setKeepLogfile()
417
213
 
418
214
    def addError(self, test, err):
419
215
        """Tell result that test finished with an error.
421
217
        Called from the TestCase run() method when the test
422
218
        fails with an unexpected error.
423
219
        """
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()
 
220
        self._testConcluded(test)
 
221
        if isinstance(err[1], TestNotApplicable):
 
222
            return self._addNotApplicable(test, err)
 
223
        elif isinstance(err[1], UnavailableFeature):
 
224
            return self.addNotSupported(test, err[1].args[0])
 
225
        else:
 
226
            unittest.TestResult.addError(self, test, err)
 
227
            self.error_count += 1
 
228
            self.report_error(test, err)
 
229
            if self.stop_early:
 
230
                self.stop()
 
231
            self._cleanupLogFile(test)
430
232
 
431
233
    def addFailure(self, test, err):
432
234
        """Tell result that test failed.
434
236
        Called from the TestCase run() method when the test
435
237
        fails because e.g. an assert() method failed.
436
238
        """
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()
 
239
        self._testConcluded(test)
 
240
        if isinstance(err[1], KnownFailure):
 
241
            return self._addKnownFailure(test, err)
 
242
        else:
 
243
            unittest.TestResult.addFailure(self, test, err)
 
244
            self.failure_count += 1
 
245
            self.report_failure(test, err)
 
246
            if self.stop_early:
 
247
                self.stop()
 
248
            self._cleanupLogFile(test)
443
249
 
444
 
    def addSuccess(self, test, details=None):
 
250
    def addSuccess(self, test):
445
251
        """Tell result that test completed successfully.
446
252
 
447
253
        Called from the TestCase run()
448
254
        """
 
255
        self._testConcluded(test)
449
256
        if self._bench_history is not None:
450
 
            benchmark_time = self._extractBenchmarkTime(test, details)
 
257
            benchmark_time = self._extractBenchmarkTime(test)
451
258
            if benchmark_time is not None:
452
259
                self._bench_history.write("%s %s\n" % (
453
260
                    self._formatTime(benchmark_time),
454
261
                    test.id()))
455
262
        self.report_success(test)
456
 
        super(ExtendedTestResult, self).addSuccess(test)
 
263
        self._cleanupLogFile(test)
 
264
        unittest.TestResult.addSuccess(self, test)
457
265
        test._log_contents = ''
458
266
 
459
 
    def addExpectedFailure(self, test, err):
 
267
    def _testConcluded(self, test):
 
268
        """Common code when a test has finished.
 
269
 
 
270
        Called regardless of whether it succeded, failed, etc.
 
271
        """
 
272
        pass
 
273
 
 
274
    def _addKnownFailure(self, test, err):
460
275
        self.known_failure_count += 1
461
276
        self.report_known_failure(test, err)
462
277
 
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
278
    def addNotSupported(self, test, feature):
477
279
        """The test will not be run because of a missing feature.
478
280
        """
479
281
        # this can be called in two different ways: it may be that the
480
 
        # test started running, and then raised (through requireFeature)
 
282
        # test started running, and then raised (through addError)
481
283
        # 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.
 
284
        # while probing for features before running the tests; in that
 
285
        # case we will see startTest and stopTest, but the test will never
 
286
        # actually run.
485
287
        self.unsupported.setdefault(str(feature), 0)
486
288
        self.unsupported[str(feature)] += 1
487
289
        self.report_unsupported(test, feature)
491
293
        self.skip_count += 1
492
294
        self.report_skip(test, reason)
493
295
 
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()
 
296
    def _addNotApplicable(self, test, skip_excinfo):
 
297
        if isinstance(skip_excinfo[1], TestNotApplicable):
 
298
            self.not_applicable_count += 1
 
299
            self.report_not_applicable(test, skip_excinfo)
 
300
        try:
 
301
            test.tearDown()
 
302
        except KeyboardInterrupt:
 
303
            raise
 
304
        except:
 
305
            self.addError(test, test.exc_info())
 
306
        else:
 
307
            # seems best to treat this as success from point-of-view of unittest
 
308
            # -- it actually does nothing so it barely matters :)
 
309
            unittest.TestResult.addSuccess(self, test)
 
310
            test._log_contents = ''
 
311
 
 
312
    def printErrorList(self, flavour, errors):
 
313
        for test, err in errors:
 
314
            self.stream.writeln(self.separator1)
 
315
            self.stream.write("%s: " % flavour)
 
316
            self.stream.writeln(self.getDescription(test))
 
317
            if getattr(test, '_get_log', None) is not None:
 
318
                self.stream.write('\n')
 
319
                self.stream.write(
 
320
                        ('vvvv[log from %s]' % test.id()).ljust(78,'-'))
 
321
                self.stream.write('\n')
 
322
                self.stream.write(test._get_log())
 
323
                self.stream.write('\n')
 
324
                self.stream.write(
 
325
                        ('^^^^[log from %s]' % test.id()).ljust(78,'-'))
 
326
                self.stream.write('\n')
 
327
            self.stream.writeln(self.separator2)
 
328
            self.stream.writeln("%s" % err)
 
329
 
 
330
    def finished(self):
 
331
        pass
 
332
 
 
333
    def report_cleaning_up(self):
 
334
        pass
547
335
 
548
336
    def report_success(self, test):
549
337
        pass
559
347
 
560
348
    def __init__(self, stream, descriptions, verbosity,
561
349
                 bench_history=None,
 
350
                 num_tests=None,
562
351
                 pb=None,
563
 
                 strict=None,
564
352
                 ):
565
353
        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()
 
354
            bench_history, num_tests)
 
355
        if pb is None:
 
356
            self.pb = self.ui.nested_progress_bar()
 
357
            self._supplied_pb = False
 
358
        else:
 
359
            self.pb = pb
 
360
            self._supplied_pb = True
572
361
        self.pb.show_pct = False
573
362
        self.pb.show_spinner = False
574
363
        self.pb.show_eta = False,
575
364
        self.pb.show_count = False
576
365
        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()
 
366
 
 
367
    def report_starting(self):
588
368
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
589
369
 
590
370
    def _progress_prefix_text(self):
597
377
        ##     a += ', %d skip' % self.skip_count
598
378
        ## if self.known_failure_count:
599
379
        ##     a += '+%dX' % self.known_failure_count
600
 
        if self.num_tests:
 
380
        if self.num_tests is not None:
601
381
            a +='/%d' % self.num_tests
602
382
        a += ' in '
603
383
        runtime = time.time() - self._overall_start_time
605
385
            a += '%dm%ds' % (runtime / 60, runtime % 60)
606
386
        else:
607
387
            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)
 
388
        if self.error_count:
 
389
            a += ', %d err' % self.error_count
 
390
        if self.failure_count:
 
391
            a += ', %d fail' % self.failure_count
 
392
        if self.unsupported:
 
393
            a += ', %d missing' % len(self.unsupported)
613
394
        a += ']'
614
395
        return a
615
396
 
616
397
    def report_test_start(self, test):
 
398
        self.count += 1
617
399
        self.pb.update(
618
400
                self._progress_prefix_text()
619
401
                + ' '
623
405
        return self._shortened_test_description(test)
624
406
 
625
407
    def report_error(self, test, err):
626
 
        self.stream.write('ERROR: %s\n    %s\n' % (
 
408
        self.pb.note('ERROR: %s\n    %s\n',
627
409
            self._test_description(test),
628
410
            err[1],
629
 
            ))
 
411
            )
630
412
 
631
413
    def report_failure(self, test, err):
632
 
        self.stream.write('FAIL: %s\n    %s\n' % (
 
414
        self.pb.note('FAIL: %s\n    %s\n',
633
415
            self._test_description(test),
634
416
            err[1],
635
 
            ))
 
417
            )
636
418
 
637
419
    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
 
            ))
 
420
        self.pb.note('XFAIL: %s\n%s\n',
 
421
            self._test_description(test), err[1])
646
422
 
647
423
    def report_skip(self, test, reason):
648
424
        pass
649
425
 
650
 
    def report_not_applicable(self, test, reason):
 
426
    def report_not_applicable(self, test, skip_excinfo):
651
427
        pass
652
428
 
653
429
    def report_unsupported(self, test, feature):
654
430
        """test cannot be run because feature is missing."""
655
431
 
 
432
    def report_cleaning_up(self):
 
433
        self.pb.update('Cleaning up')
 
434
 
 
435
    def finished(self):
 
436
        if not self._supplied_pb:
 
437
            self.pb.finished()
 
438
 
656
439
 
657
440
class VerboseTestResult(ExtendedTestResult):
658
441
    """Produce long output, with one line per test run plus times"""
665
448
            result = a_string
666
449
        return result.ljust(final_width)
667
450
 
668
 
    def report_tests_starting(self):
 
451
    def report_starting(self):
669
452
        self.stream.write('running %d tests...\n' % self.num_tests)
670
 
        super(VerboseTestResult, self).report_tests_starting()
671
453
 
672
454
    def report_test_start(self, test):
 
455
        self.count += 1
673
456
        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)
 
457
        # width needs space for 6 char status, plus 1 for slash, plus 2 10-char
 
458
        # numbers, plus a trailing blank
 
459
        # when NUMBERED_DIRS: plus 5 chars on test number, plus 1 char on space
 
460
        self.stream.write(self._ellipsize_to_right(name,
 
461
                          osutils.terminal_width()-30))
683
462
        self.stream.flush()
684
463
 
685
464
    def _error_summary(self, err):
687
466
        return '%s%s' % (indent, err[1])
688
467
 
689
468
    def report_error(self, test, err):
690
 
        self.stream.write('ERROR %s\n%s\n'
 
469
        self.stream.writeln('ERROR %s\n%s'
691
470
                % (self._testTimeString(test),
692
471
                   self._error_summary(err)))
693
472
 
694
473
    def report_failure(self, test, err):
695
 
        self.stream.write(' FAIL %s\n%s\n'
 
474
        self.stream.writeln(' FAIL %s\n%s'
696
475
                % (self._testTimeString(test),
697
476
                   self._error_summary(err)))
698
477
 
699
478
    def report_known_failure(self, test, err):
700
 
        self.stream.write('XFAIL %s\n%s\n'
 
479
        self.stream.writeln('XFAIL %s\n%s'
701
480
                % (self._testTimeString(test),
702
481
                   self._error_summary(err)))
703
482
 
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
483
    def report_success(self, test):
711
 
        self.stream.write('   OK %s\n' % self._testTimeString(test))
 
484
        self.stream.writeln('   OK %s' % self._testTimeString(test))
712
485
        for bench_called, stats in getattr(test, '_benchcalls', []):
713
 
            self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
 
486
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
714
487
            stats.pprint(file=self.stream)
715
488
        # flush the stream so that we get smooth output. This verbose mode is
716
489
        # used to show the output in PQM.
717
490
        self.stream.flush()
718
491
 
719
492
    def report_skip(self, test, reason):
720
 
        self.stream.write(' SKIP %s\n%s\n'
 
493
        self.stream.writeln(' SKIP %s\n%s'
721
494
                % (self._testTimeString(test), reason))
722
495
 
723
 
    def report_not_applicable(self, test, reason):
724
 
        self.stream.write('  N/A %s\n    %s\n'
725
 
                % (self._testTimeString(test), reason))
 
496
    def report_not_applicable(self, test, skip_excinfo):
 
497
        self.stream.writeln('  N/A %s\n%s'
 
498
                % (self._testTimeString(test),
 
499
                   self._error_summary(skip_excinfo)))
726
500
 
727
501
    def report_unsupported(self, test, feature):
728
502
        """test cannot be run because feature is missing."""
729
 
        self.stream.write("NODEP %s\n    The feature '%s' is not available.\n"
 
503
        self.stream.writeln("NODEP %s\n    The feature '%s' is not available."
730
504
                %(self._testTimeString(test), feature))
731
505
 
732
506
 
738
512
                 descriptions=0,
739
513
                 verbosity=1,
740
514
                 bench_history=None,
741
 
                 strict=False,
742
 
                 result_decorators=None,
 
515
                 list_only=False
743
516
                 ):
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
 
517
        self.stream = unittest._WritelnDecorator(stream)
768
518
        self.descriptions = descriptions
769
519
        self.verbosity = verbosity
770
520
        self._bench_history = bench_history
771
 
        self._strict = strict
772
 
        self._result_decorators = result_decorators or []
 
521
        self.list_only = list_only
773
522
 
774
523
    def run(self, test):
775
524
        "Run the given test case or test suite."
 
525
        startTime = time.time()
776
526
        if self.verbosity == 1:
777
527
            result_class = TextTestResult
778
528
        elif self.verbosity >= 2:
779
529
            result_class = VerboseTestResult
780
 
        original_result = result_class(self.stream,
 
530
        result = result_class(self.stream,
781
531
                              self.descriptions,
782
532
                              self.verbosity,
783
533
                              bench_history=self._bench_history,
784
 
                              strict=self._strict,
 
534
                              num_tests=test.countTestCases(),
785
535
                              )
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:
794
 
            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
 
536
        result.stop_early = self.stop_on_failure
 
537
        result.report_starting()
 
538
        if self.list_only:
 
539
            if self.verbosity >= 2:
 
540
                self.stream.writeln("Listing tests only ...\n")
 
541
            run = 0
 
542
            for t in iter_suite_tests(test):
 
543
                self.stream.writeln("%s" % (t.id()))
 
544
                run += 1
 
545
            actionTaken = "Listed"
 
546
        else:
 
547
            try:
 
548
                import testtools
 
549
            except ImportError:
 
550
                test.run(result)
 
551
            else:
 
552
                if isinstance(test, testtools.ConcurrentTestSuite):
 
553
                    # We need to catch bzr specific behaviors
 
554
                    test.run(BZRTransformingResult(result))
 
555
                else:
 
556
                    test.run(result)
 
557
            run = result.testsRun
 
558
            actionTaken = "Ran"
 
559
        stopTime = time.time()
 
560
        timeTaken = stopTime - startTime
 
561
        result.printErrors()
 
562
        self.stream.writeln(result.separator2)
 
563
        self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
 
564
                            run, run != 1 and "s" or "", timeTaken))
 
565
        self.stream.writeln()
 
566
        if not result.wasSuccessful():
 
567
            self.stream.write("FAILED (")
 
568
            failed, errored = map(len, (result.failures, result.errors))
 
569
            if failed:
 
570
                self.stream.write("failures=%d" % failed)
 
571
            if errored:
 
572
                if failed: self.stream.write(", ")
 
573
                self.stream.write("errors=%d" % errored)
 
574
            if result.known_failure_count:
 
575
                if failed or errored: self.stream.write(", ")
 
576
                self.stream.write("known_failure_count=%d" %
 
577
                    result.known_failure_count)
 
578
            self.stream.writeln(")")
 
579
        else:
 
580
            if result.known_failure_count:
 
581
                self.stream.writeln("OK (known_failures=%d)" %
 
582
                    result.known_failure_count)
 
583
            else:
 
584
                self.stream.writeln("OK")
 
585
        if result.skip_count > 0:
 
586
            skipped = result.skip_count
 
587
            self.stream.writeln('%d test%s skipped' %
 
588
                                (skipped, skipped != 1 and "s" or ""))
 
589
        if result.unsupported:
 
590
            for feature, count in sorted(result.unsupported.items()):
 
591
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
 
592
                    (feature, count))
 
593
        result.finished()
 
594
        return result
800
595
 
801
596
 
802
597
def iter_suite_tests(suite):
812
607
                        % (type(suite), suite))
813
608
 
814
609
 
815
 
TestSkipped = testtools.testcase.TestSkipped
 
610
class TestSkipped(Exception):
 
611
    """Indicates that a test was intentionally skipped, rather than failing."""
816
612
 
817
613
 
818
614
class TestNotApplicable(TestSkipped):
824
620
    """
825
621
 
826
622
 
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
 
623
class KnownFailure(AssertionError):
 
624
    """Indicates that a test failed in a precisely expected manner.
 
625
 
 
626
    Such failures dont block the whole test suite from passing because they are
 
627
    indicators of partially completed code or of future work. We have an
 
628
    explicit error for them so that we can ensure that they are always visible:
 
629
    KnownFailures are always shown in the output of bzr selftest.
 
630
    """
844
631
 
845
632
 
846
633
class UnavailableFeature(Exception):
847
634
    """A feature required for this test was not available.
848
635
 
849
 
    This can be considered a specialised form of SkippedTest.
850
 
 
851
636
    The feature should be used to construct the exception.
852
637
    """
853
638
 
854
639
 
 
640
class CommandFailed(Exception):
 
641
    pass
 
642
 
 
643
 
855
644
class StringIOWrapper(object):
856
645
    """A wrapper around cStringIO which just adds an encoding attribute.
857
646
 
878
667
            return setattr(self._cstring, name, val)
879
668
 
880
669
 
881
 
class TestUIFactory(TextUIFactory):
 
670
class TestUIFactory(ui.CLIUIFactory):
882
671
    """A UI Factory for testing.
883
672
 
884
673
    Hide the progress bar but emit note()s.
885
674
    Redirect stdin.
886
675
    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
676
    """
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
677
 
899
678
    def __init__(self, stdout=None, stderr=None, stdin=None):
900
679
        if stdin is not None:
905
684
            stdin = StringIOWrapper(stdin)
906
685
        super(TestUIFactory, self).__init__(stdin, stdout, stderr)
907
686
 
 
687
    def clear(self):
 
688
        """See progress.ProgressBar.clear()."""
 
689
 
 
690
    def clear_term(self):
 
691
        """See progress.ProgressBar.clear_term()."""
 
692
 
 
693
    def finished(self):
 
694
        """See progress.ProgressBar.finished()."""
 
695
 
 
696
    def note(self, fmt_string, *args, **kwargs):
 
697
        """See progress.ProgressBar.note()."""
 
698
        self.stdout.write((fmt_string + "\n") % args)
 
699
 
 
700
    def progress_bar(self):
 
701
        return self
 
702
 
 
703
    def nested_progress_bar(self):
 
704
        return self
 
705
 
 
706
    def update(self, message, count=None, total=None):
 
707
        """See progress.ProgressBar.update()."""
 
708
 
908
709
    def get_non_echoed_password(self):
909
710
        """Get password from stdin without trying to handle the echo mode"""
910
711
        password = self.stdin.readline()
914
715
            password = password[:-1]
915
716
        return password
916
717
 
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):
 
718
 
 
719
def _report_leaked_threads():
 
720
    bzrlib.trace.warning('%s is leaking threads among %d leaking tests',
 
721
                         TestCase._first_thread_leaker_id,
 
722
                         TestCase._leaking_threads_tests)
 
723
 
 
724
 
 
725
class TestCase(unittest.TestCase):
941
726
    """Base class for bzr unit tests.
942
727
 
943
728
    Tests that need access to disk resources should subclass
953
738
    routine, and to build and check bzr trees.
954
739
 
955
740
    In addition to the usual method of overriding tearDown(), this class also
956
 
    allows subclasses to register cleanup functions via addCleanup, which are
 
741
    allows subclasses to register functions into the _cleanups list, which is
957
742
    run in order as the object is torn down.  It's less likely this will be
958
743
    accidentally overlooked.
959
744
    """
960
745
 
961
 
    _log_file = None
 
746
    _active_threads = None
 
747
    _leaking_threads_tests = 0
 
748
    _first_thread_leaker_id = None
 
749
    _log_file_name = None
 
750
    _log_contents = ''
 
751
    _keep_log_file = False
962
752
    # record lsprof data when performing benchmark calls.
963
753
    _gather_lsprof_in_benchmarks = False
 
754
    attrs_to_keep = ('id', '_testMethodName', '_testMethodDoc',
 
755
                     '_log_contents', '_log_file_name', '_benchtime',
 
756
                     '_TestCase__testMethodName')
964
757
 
965
758
    def __init__(self, methodName='testMethod'):
966
759
        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))
 
760
        self._cleanups = []
 
761
        self._bzr_test_setUp_run = False
 
762
        self._bzr_test_tearDown_run = False
972
763
 
973
764
    def setUp(self):
974
 
        super(TestCase, self).setUp()
975
 
        for feature in getattr(self, '_test_needs_features', []):
976
 
            self.requireFeature(feature)
 
765
        unittest.TestCase.setUp(self)
 
766
        self._bzr_test_setUp_run = True
977
767
        self._cleanEnvironment()
978
768
        self._silenceUI()
979
769
        self._startLogFile()
980
770
        self._benchcalls = []
981
771
        self._benchtime = None
982
772
        self._clear_hooks()
983
 
        self._track_transports()
984
 
        self._track_locks()
985
773
        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()
 
774
        TestCase._active_threads = threading.activeCount()
 
775
        self.addCleanup(self._check_leaked_threads)
1001
776
 
1002
777
    def debug(self):
1003
778
        # debug a frame up.
1004
779
        import pdb
1005
780
        pdb.Pdb().set_trace(sys._getframe().f_back)
1006
781
 
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,))
 
782
    def _check_leaked_threads(self):
 
783
        active = threading.activeCount()
 
784
        leaked_threads = active - TestCase._active_threads
 
785
        TestCase._active_threads = active
 
786
        if leaked_threads:
 
787
            TestCase._leaking_threads_tests += 1
 
788
            if TestCase._first_thread_leaker_id is None:
 
789
                TestCase._first_thread_leaker_id = self.id()
 
790
                # we're not specifically told when all tests are finished.
 
791
                # This will do. We use a function to avoid keeping a reference
 
792
                # to a TestCase object.
 
793
                atexit.register(_report_leaked_threads)
1066
794
 
1067
795
    def _clear_debug_flags(self):
1068
796
        """Prevent externally set debug flags affecting tests.
1070
798
        Tests that want to use debug flags can just set them in the
1071
799
        debug_flags set during setup/teardown.
1072
800
        """
1073
 
        # Start with a copy of the current debug flags we can safely modify.
1074
 
        self.overrideAttr(debug, 'debug_flags', set(debug.debug_flags))
 
801
        self._preserved_debug_flags = set(debug.debug_flags)
1075
802
        if 'allow_debug' not in selftest_debug_flags:
1076
803
            debug.debug_flags.clear()
1077
 
        if 'disable_lock_checks' not in selftest_debug_flags:
1078
 
            debug.debug_flags.add('strict_locks')
 
804
        self.addCleanup(self._restore_debug_flags)
1079
805
 
1080
806
    def _clear_hooks(self):
1081
807
        # prevent hooks affecting tests
1082
 
        known_hooks = hooks.known_hooks
1083
808
        self._preserved_hooks = {}
1084
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1085
 
            current_hooks = getattr(parent, name)
 
809
        for key, factory in hooks.known_hooks.items():
 
810
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
811
            current_hooks = hooks.known_hooks_key_to_object(key)
1086
812
            self._preserved_hooks[parent] = (name, current_hooks)
1087
 
        self._preserved_lazy_hooks = hooks._lazy_hooks
1088
 
        hooks._lazy_hooks = {}
1089
813
        self.addCleanup(self._restoreHooks)
1090
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1091
 
            factory = known_hooks.get(key)
 
814
        for key, factory in hooks.known_hooks.items():
 
815
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
1092
816
            setattr(parent, name, factory())
1093
817
        # this hook should always be installed
1094
818
        request._install_hook()
1095
819
 
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
820
    def _silenceUI(self):
1105
821
        """Turn off UI for duration of test"""
1106
822
        # 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.")
 
823
        saved = ui.ui_factory
 
824
        def _restore():
 
825
            ui.ui_factory = saved
 
826
        ui.ui_factory = ui.SilentUIFactory()
 
827
        self.addCleanup(_restore)
1290
828
 
1291
829
    def _ndiff_strings(self, a, b):
1292
830
        """Return ndiff between two strings containing lines.
1310
848
        except UnicodeError, e:
1311
849
            # If we can't compare without getting a UnicodeError, then
1312
850
            # obviously they are different
1313
 
            trace.mutter('UnicodeError: %s', e)
 
851
            mutter('UnicodeError: %s', e)
1314
852
        if message:
1315
853
            message += '\n'
1316
854
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1317
855
            % (message,
1318
 
               pprint.pformat(a), pprint.pformat(b)))
 
856
               pformat(a), pformat(b)))
1319
857
 
1320
858
    assertEquals = assertEqual
1321
859
 
1330
868
            return
1331
869
        if message is None:
1332
870
            message = "texts not equal:\n"
 
871
        if a == b + '\n':
 
872
            message = 'first string is missing a final newline.\n'
1333
873
        if a + '\n' == b:
1334
 
            message = 'first string is missing a final newline.\n'
1335
 
        if a == b + '\n':
1336
874
            message = 'second string is missing a final newline.\n'
1337
875
        raise AssertionError(message +
1338
876
                             self._ndiff_strings(a, b))
1349
887
        :raises AssertionError: If the expected and actual stat values differ
1350
888
            other than by atime.
1351
889
        """
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')
 
890
        self.assertEqual(expected.st_size, actual.st_size)
 
891
        self.assertEqual(expected.st_mtime, actual.st_mtime)
 
892
        self.assertEqual(expected.st_ctime, actual.st_ctime)
 
893
        self.assertEqual(expected.st_dev, actual.st_dev)
 
894
        self.assertEqual(expected.st_ino, actual.st_ino)
 
895
        self.assertEqual(expected.st_mode, actual.st_mode)
1373
896
 
1374
897
    def assertLength(self, length, obj_with_len):
1375
898
        """Assert that obj_with_len is of length length."""
1377
900
            self.fail("Incorrect length: wanted %d, got %d for %r" % (
1378
901
                length, len(obj_with_len), obj_with_len))
1379
902
 
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
903
    def assertPositive(self, val):
1399
904
        """Assert that val is greater than 0."""
1400
905
        self.assertTrue(val > 0, 'expected a positive value, but got %s' % val)
1430
935
            raise AssertionError('pattern "%s" found in "%s"'
1431
936
                    % (needle_re, haystack))
1432
937
 
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
938
    def assertSubset(self, sublist, superlist):
1442
939
        """Assert that every entry in sublist is present in superlist."""
1443
940
        missing = set(sublist) - set(superlist)
1518
1015
                         osutils.realpath(path2),
1519
1016
                         "apparent paths:\na = %s\nb = %s\n," % (path1, path2))
1520
1017
 
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
 
        """
 
1018
    def assertIsInstance(self, obj, kls):
 
1019
        """Fail if obj is not an instance of kls"""
1526
1020
        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)
 
1021
            self.fail("%r is an instance of %s rather than %s" % (
 
1022
                obj, obj.__class__, kls))
 
1023
 
 
1024
    def expectFailure(self, reason, assertion, *args, **kwargs):
 
1025
        """Invoke a test, expecting it to fail for the given reason.
 
1026
 
 
1027
        This is for assertions that ought to succeed, but currently fail.
 
1028
        (The failure is *expected* but not *wanted*.)  Please be very precise
 
1029
        about the failure you're expecting.  If a new bug is introduced,
 
1030
        AssertionError should be raised, not KnownFailure.
 
1031
 
 
1032
        Frequently, expectFailure should be followed by an opposite assertion.
 
1033
        See example below.
 
1034
 
 
1035
        Intended to be used with a callable that raises AssertionError as the
 
1036
        'assertion' parameter.  args and kwargs are passed to the 'assertion'.
 
1037
 
 
1038
        Raises KnownFailure if the test fails.  Raises AssertionError if the
 
1039
        test succeeds.
 
1040
 
 
1041
        example usage::
 
1042
 
 
1043
          self.expectFailure('Math is broken', self.assertNotEqual, 54,
 
1044
                             dynamic_val)
 
1045
          self.assertEqual(42, dynamic_val)
 
1046
 
 
1047
          This means that a dynamic_val of 54 will cause the test to raise
 
1048
          a KnownFailure.  Once math is fixed and the expectFailure is removed,
 
1049
          only a dynamic_val of 42 will allow the test to pass.  Anything other
 
1050
          than 54 or 42 will cause an AssertionError.
 
1051
        """
 
1052
        try:
 
1053
            assertion(*args, **kwargs)
 
1054
        except AssertionError:
 
1055
            raise KnownFailure(reason)
 
1056
        else:
 
1057
            self.fail('Unexpected success.  Should have failed: %s' % reason)
1532
1058
 
1533
1059
    def assertFileEqual(self, content, path):
1534
1060
        """Fail if path does not contain 'content'."""
1535
 
        self.assertPathExists(path)
 
1061
        self.failUnlessExists(path)
1536
1062
        f = file(path, 'rb')
1537
1063
        try:
1538
1064
            s = f.read()
1540
1066
            f.close()
1541
1067
        self.assertEqualDiff(content, s)
1542
1068
 
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
1069
    def failUnlessExists(self, path):
1553
 
        return self.assertPathExists(path)
1554
 
 
1555
 
    def assertPathExists(self, path):
1556
1070
        """Fail unless path or paths, which may be abs or relative, exist."""
1557
1071
        if not isinstance(path, basestring):
1558
1072
            for p in path:
1559
 
                self.assertPathExists(p)
 
1073
                self.failUnlessExists(p)
1560
1074
        else:
1561
 
            self.assertTrue(osutils.lexists(path),
1562
 
                path + " does not exist")
 
1075
            self.failUnless(osutils.lexists(path),path+" does not exist")
1563
1076
 
1564
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1565
1077
    def failIfExists(self, path):
1566
 
        return self.assertPathDoesNotExist(path)
1567
 
 
1568
 
    def assertPathDoesNotExist(self, path):
1569
1078
        """Fail if path or paths, which may be abs or relative, exist."""
1570
1079
        if not isinstance(path, basestring):
1571
1080
            for p in path:
1572
 
                self.assertPathDoesNotExist(p)
 
1081
                self.failIfExists(p)
1573
1082
        else:
1574
 
            self.assertFalse(osutils.lexists(path),
1575
 
                path + " exists")
 
1083
            self.failIf(osutils.lexists(path),path+" exists")
1576
1084
 
1577
1085
    def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
1578
1086
        """A helper for callDeprecated and applyDeprecated.
1604
1112
        not other callers that go direct to the warning module.
1605
1113
 
1606
1114
        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)::
 
1115
        this::
1609
1116
 
1610
1117
            self.assertRaises(errors.ReservedId,
1611
1118
                self.applyDeprecated,
1693
1200
 
1694
1201
        The file is removed as the test is torn down.
1695
1202
        """
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)
 
1203
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
 
1204
        self._log_file = os.fdopen(fileno, 'w+')
 
1205
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
 
1206
        self._log_file_name = name
1705
1207
        self.addCleanup(self._finishLogFile)
1706
1208
 
1707
1209
    def _finishLogFile(self):
1708
1210
        """Finished with the log file.
1709
1211
 
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
 
1212
        Close the file and delete it, unless setKeepLogfile was called.
 
1213
        """
 
1214
        if self._log_file is None:
 
1215
            return
 
1216
        bzrlib.trace.pop_log_file(self._log_memento)
 
1217
        self._log_file.close()
 
1218
        self._log_file = None
 
1219
        if not self._keep_log_file:
 
1220
            os.remove(self._log_file_name)
 
1221
            self._log_file_name = None
 
1222
 
 
1223
    def setKeepLogfile(self):
 
1224
        """Make the logfile not be deleted when _finishLogFile is called."""
 
1225
        self._keep_log_file = True
 
1226
 
 
1227
    def addCleanup(self, callable, *args, **kwargs):
 
1228
        """Arrange to run a callable when this case is torn down.
 
1229
 
 
1230
        Callables are run in the reverse of the order they are registered,
 
1231
        ie last-in first-out.
 
1232
        """
 
1233
        self._cleanups.append((callable, args, kwargs))
1762
1234
 
1763
1235
    def _cleanEnvironment(self):
1764
 
        for name, value in isolated_environ.iteritems():
1765
 
            self.overrideEnv(name, value)
 
1236
        new_env = {
 
1237
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
 
1238
            'HOME': os.getcwd(),
 
1239
            # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
 
1240
            # tests do check our impls match APPDATA
 
1241
            'BZR_EDITOR': None, # test_msgeditor manipulates this variable
 
1242
            'VISUAL': None,
 
1243
            'EDITOR': None,
 
1244
            'BZR_EMAIL': None,
 
1245
            'BZREMAIL': None, # may still be present in the environment
 
1246
            'EMAIL': None,
 
1247
            'BZR_PROGRESS_BAR': None,
 
1248
            'BZR_LOG': None,
 
1249
            'BZR_PLUGIN_PATH': None,
 
1250
            # SSH Agent
 
1251
            'SSH_AUTH_SOCK': None,
 
1252
            # Proxies
 
1253
            'http_proxy': None,
 
1254
            'HTTP_PROXY': None,
 
1255
            'https_proxy': None,
 
1256
            'HTTPS_PROXY': None,
 
1257
            'no_proxy': None,
 
1258
            'NO_PROXY': None,
 
1259
            'all_proxy': None,
 
1260
            'ALL_PROXY': None,
 
1261
            # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
 
1262
            # least. If you do (care), please update this comment
 
1263
            # -- vila 20080401
 
1264
            'ftp_proxy': None,
 
1265
            'FTP_PROXY': None,
 
1266
            'BZR_REMOTE_PATH': None,
 
1267
        }
 
1268
        self.__old_env = {}
 
1269
        self.addCleanup(self._restoreEnvironment)
 
1270
        for name, value in new_env.iteritems():
 
1271
            self._captureVar(name, value)
 
1272
 
 
1273
    def _captureVar(self, name, newvalue):
 
1274
        """Set an environment variable, and reset it when finished."""
 
1275
        self.__old_env[name] = osutils.set_or_unset_env(name, newvalue)
 
1276
 
 
1277
    def _restore_debug_flags(self):
 
1278
        debug.debug_flags.clear()
 
1279
        debug.debug_flags.update(self._preserved_debug_flags)
 
1280
 
 
1281
    def _restoreEnvironment(self):
 
1282
        for name, value in self.__old_env.iteritems():
 
1283
            osutils.set_or_unset_env(name, value)
1766
1284
 
1767
1285
    def _restoreHooks(self):
1768
1286
        for klass, (name, hooks) in self._preserved_hooks.items():
1769
1287
            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
1288
 
1774
1289
    def knownFailure(self, reason):
1775
1290
        """This test has failed for some known reason."""
1776
1291
        raise KnownFailure(reason)
1777
1292
 
1778
 
    def _suppress_log(self):
1779
 
        """Remove the log info from details."""
1780
 
        self.discardDetail('log')
1781
 
 
1782
1293
    def _do_skip(self, result, reason):
1783
 
        self._suppress_log()
1784
1294
        addSkip = getattr(result, 'addSkip', None)
1785
1295
        if not callable(addSkip):
1786
 
            result.addSuccess(result)
 
1296
            result.addError(self, sys.exc_info())
1787
1297
        else:
1788
1298
            addSkip(self, reason)
1789
1299
 
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)
 
1300
    def run(self, result=None):
 
1301
        if result is None: result = self.defaultTestResult()
 
1302
        for feature in getattr(self, '_test_needs_features', []):
 
1303
            if not feature.available():
 
1304
                result.startTest(self)
 
1305
                if getattr(result, 'addNotSupported', None):
 
1306
                    result.addNotSupported(self, feature)
 
1307
                else:
 
1308
                    result.addSuccess(self)
 
1309
                result.stopTest(self)
 
1310
                return
 
1311
        try:
 
1312
            try:
 
1313
                result.startTest(self)
 
1314
                absent_attr = object()
 
1315
                # Python 2.5
 
1316
                method_name = getattr(self, '_testMethodName', absent_attr)
 
1317
                if method_name is absent_attr:
 
1318
                    # Python 2.4
 
1319
                    method_name = getattr(self, '_TestCase__testMethodName')
 
1320
                testMethod = getattr(self, method_name)
 
1321
                try:
 
1322
                    try:
 
1323
                        self.setUp()
 
1324
                        if not self._bzr_test_setUp_run:
 
1325
                            self.fail(
 
1326
                                "test setUp did not invoke "
 
1327
                                "bzrlib.tests.TestCase's setUp")
 
1328
                    except KeyboardInterrupt:
 
1329
                        raise
 
1330
                    except TestSkipped, e:
 
1331
                        self._do_skip(result, e.args[0])
 
1332
                        self.tearDown()
 
1333
                        return
 
1334
                    except:
 
1335
                        result.addError(self, sys.exc_info())
 
1336
                        return
 
1337
 
 
1338
                    ok = False
 
1339
                    try:
 
1340
                        testMethod()
 
1341
                        ok = True
 
1342
                    except self.failureException:
 
1343
                        result.addFailure(self, sys.exc_info())
 
1344
                    except TestSkipped, e:
 
1345
                        if not e.args:
 
1346
                            reason = "No reason given."
 
1347
                        else:
 
1348
                            reason = e.args[0]
 
1349
                        self._do_skip(result, reason)
 
1350
                    except KeyboardInterrupt:
 
1351
                        raise
 
1352
                    except:
 
1353
                        result.addError(self, sys.exc_info())
 
1354
 
 
1355
                    try:
 
1356
                        self.tearDown()
 
1357
                        if not self._bzr_test_tearDown_run:
 
1358
                            self.fail(
 
1359
                                "test tearDown did not invoke "
 
1360
                                "bzrlib.tests.TestCase's tearDown")
 
1361
                    except KeyboardInterrupt:
 
1362
                        raise
 
1363
                    except:
 
1364
                        result.addError(self, sys.exc_info())
 
1365
                        ok = False
 
1366
                    if ok: result.addSuccess(self)
 
1367
                finally:
 
1368
                    result.stopTest(self)
 
1369
                return
 
1370
            except TestNotApplicable:
 
1371
                # Not moved from the result [yet].
 
1372
                raise
 
1373
            except KeyboardInterrupt:
 
1374
                raise
 
1375
        finally:
 
1376
            saved_attrs = {}
 
1377
            absent_attr = object()
 
1378
            for attr_name in self.attrs_to_keep:
 
1379
                attr = getattr(self, attr_name, absent_attr)
 
1380
                if attr is not absent_attr:
 
1381
                    saved_attrs[attr_name] = attr
 
1382
            self.__dict__ = saved_attrs
 
1383
 
 
1384
    def tearDown(self):
 
1385
        self._bzr_test_tearDown_run = True
 
1386
        self._runCleanups()
 
1387
        self._log_contents = ''
 
1388
        unittest.TestCase.tearDown(self)
1842
1389
 
1843
1390
    def time(self, callable, *args, **kwargs):
1844
1391
        """Run callable and accrue the time it takes to the benchmark time.
1848
1395
        self._benchcalls.
1849
1396
        """
1850
1397
        if self._benchtime is None:
1851
 
            self.addDetail('benchtime', content.Content(content.ContentType(
1852
 
                "text", "plain"), lambda:[str(self._benchtime)]))
1853
1398
            self._benchtime = 0
1854
1399
        start = time.time()
1855
1400
        try:
1864
1409
        finally:
1865
1410
            self._benchtime += time.time() - start
1866
1411
 
 
1412
    def _runCleanups(self):
 
1413
        """Run registered cleanup functions.
 
1414
 
 
1415
        This should only be called from TestCase.tearDown.
 
1416
        """
 
1417
        # TODO: Perhaps this should keep running cleanups even if
 
1418
        # one of them fails?
 
1419
 
 
1420
        # Actually pop the cleanups from the list so tearDown running
 
1421
        # twice is safe (this happens for skipped tests).
 
1422
        while self._cleanups:
 
1423
            cleanup, args, kwargs = self._cleanups.pop()
 
1424
            cleanup(*args, **kwargs)
 
1425
 
1867
1426
    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.
 
1427
        mutter(*args)
 
1428
 
 
1429
    def _get_log(self, keep_log_file=False):
 
1430
        """Get the log from bzrlib.trace calls from this test.
 
1431
 
 
1432
        :param keep_log_file: When True, if the log is still a file on disk
 
1433
            leave it as a file on disk. When False, if the log is still a file
 
1434
            on disk, the log file is deleted and the log preserved as
 
1435
            self._log_contents.
 
1436
        :return: A string containing the log.
1874
1437
        """
1875
 
        return u"".join(self.getDetails()['log'].iter_text())
 
1438
        # flush the log file, to get all content
 
1439
        import bzrlib.trace
 
1440
        if bzrlib.trace._trace_file:
 
1441
            bzrlib.trace._trace_file.flush()
 
1442
        if self._log_contents:
 
1443
            # XXX: this can hardly contain the content flushed above --vila
 
1444
            # 20080128
 
1445
            return self._log_contents
 
1446
        if self._log_file_name is not None:
 
1447
            logfile = open(self._log_file_name)
 
1448
            try:
 
1449
                log_contents = logfile.read()
 
1450
            finally:
 
1451
                logfile.close()
 
1452
            if not keep_log_file:
 
1453
                self._log_contents = log_contents
 
1454
                try:
 
1455
                    os.remove(self._log_file_name)
 
1456
                except OSError, e:
 
1457
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
 
1458
                        sys.stderr.write(('Unable to delete log file '
 
1459
                                             ' %r\n' % self._log_file_name))
 
1460
                    else:
 
1461
                        raise
 
1462
            return log_contents
 
1463
        else:
 
1464
            return "DELETED log file to reduce memory footprint"
1876
1465
 
1877
1466
    def requireFeature(self, feature):
1878
1467
        """This test requires a specific feature is available.
1895
1484
 
1896
1485
    def _run_bzr_core(self, args, retcode, encoding, stdin,
1897
1486
            working_dir):
1898
 
        # Clear chk_map page cache, because the contents are likely to mask
1899
 
        # locking errors.
1900
 
        chk_map.clear_cache()
1901
1487
        if encoding is None:
1902
1488
            encoding = osutils.get_user_encoding()
1903
1489
        stdout = StringIOWrapper()
1920
1506
            os.chdir(working_dir)
1921
1507
 
1922
1508
        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)
 
1509
            result = self.apply_redirected(ui.ui_factory.stdin,
 
1510
                stdout, stderr,
 
1511
                bzrlib.commands.run_bzr_catch_user_errors,
 
1512
                args)
1940
1513
        finally:
1941
1514
            logger.removeHandler(handler)
1942
1515
            ui.ui_factory = old_ui_factory
1952
1525
        if retcode is not None:
1953
1526
            self.assertEquals(retcode, result,
1954
1527
                              message='Unexpected return code')
1955
 
        return result, out, err
 
1528
        return out, err
1956
1529
 
1957
1530
    def run_bzr(self, args, retcode=0, encoding=None, stdin=None,
1958
1531
                working_dir=None, error_regexes=[], output_encoding=None):
1987
1560
        :keyword error_regexes: A list of expected error messages.  If
1988
1561
            specified they must be seen in the error output of the command.
1989
1562
        """
1990
 
        retcode, out, err = self._run_bzr_autosplit(
 
1563
        out, err = self._run_bzr_autosplit(
1991
1564
            args=args,
1992
1565
            retcode=retcode,
1993
1566
            encoding=encoding,
1994
1567
            stdin=stdin,
1995
1568
            working_dir=working_dir,
1996
1569
            )
1997
 
        self.assertIsInstance(error_regexes, (list, tuple))
1998
1570
        for regex in error_regexes:
1999
1571
            self.assertContainsRe(err, regex)
2000
1572
        return out, err
2072
1644
    def start_bzr_subprocess(self, process_args, env_changes=None,
2073
1645
                             skip_if_plan_to_signal=False,
2074
1646
                             working_dir=None,
2075
 
                             allow_plugins=False, stderr=subprocess.PIPE):
 
1647
                             allow_plugins=False):
2076
1648
        """Start bzr in a subprocess for testing.
2077
1649
 
2078
1650
        This starts a new Python interpreter and runs bzr in there.
2087
1659
            variables. A value of None will unset the env variable.
2088
1660
            The values must be strings. The change will only occur in the
2089
1661
            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.
 
1662
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
 
1663
            is not available.
2092
1664
        :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
1665
 
2097
1666
        :returns: Popen object for the started process.
2098
1667
        """
2099
1668
        if skip_if_plan_to_signal:
2100
 
            if os.name != "posix":
2101
 
                raise TestSkipped("Sending signals not supported")
 
1669
            if not getattr(os, 'kill', None):
 
1670
                raise TestSkipped("os.kill not available.")
2102
1671
 
2103
1672
        if env_changes is None:
2104
1673
            env_changes = {}
2124
1693
            # so we will avoid using it on all platforms, just to
2125
1694
            # make sure the code path is used, and we don't break on win32
2126
1695
            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
1696
            command = [sys.executable]
2131
1697
            # frozen executables don't need the path to bzr
2132
1698
            if getattr(sys, "frozen", None) is None:
2134
1700
            if not allow_plugins:
2135
1701
                command.append('--no-plugins')
2136
1702
            command.extend(process_args)
2137
 
            process = self._popen(command, stdin=subprocess.PIPE,
2138
 
                                  stdout=subprocess.PIPE,
2139
 
                                  stderr=stderr)
 
1703
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
2140
1704
        finally:
2141
1705
            restore_environment()
2142
1706
            if cwd is not None:
2144
1708
 
2145
1709
        return process
2146
1710
 
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
1711
    def _popen(self, *args, **kwargs):
2175
1712
        """Place a call to Popen.
2176
1713
 
2177
1714
        Allows tests to override this method to intercept the calls made to
2178
1715
        Popen for introspection.
2179
1716
        """
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__))
 
1717
        return Popen(*args, **kwargs)
2185
1718
 
2186
1719
    def get_bzr_path(self):
2187
1720
        """Return the path of the 'bzr' executable for this test suite."""
2188
 
        bzr_path = os.path.join(self.get_source_path(), "bzr")
 
1721
        bzr_path = os.path.dirname(os.path.dirname(bzrlib.__file__))+'/bzr'
2189
1722
        if not os.path.isfile(bzr_path):
2190
1723
            # We are probably installed. Assume sys.argv is the right file
2191
1724
            bzr_path = sys.argv[0]
2213
1746
        if retcode is not None and retcode != process.returncode:
2214
1747
            if process_args is None:
2215
1748
                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)
 
1749
            mutter('Output of bzr %s:\n%s', process_args, out)
 
1750
            mutter('Error for bzr %s:\n%s', process_args, err)
2218
1751
            self.fail('Command bzr %s failed with retcode %s != %s'
2219
1752
                      % (process_args, retcode, process.returncode))
2220
1753
        return [out, err]
2221
1754
 
2222
 
    def check_tree_shape(self, tree, shape):
2223
 
        """Compare a tree to a list of expected names.
 
1755
    def check_inventory_shape(self, inv, shape):
 
1756
        """Compare an inventory to a list of expected names.
2224
1757
 
2225
1758
        Fail if they are not precisely equal.
2226
1759
        """
2227
1760
        extras = []
2228
1761
        shape = list(shape)             # copy
2229
 
        for path, ie in tree.iter_entries_by_dir():
 
1762
        for path, ie in inv.entries():
2230
1763
            name = path.replace('\\', '/')
2231
1764
            if ie.kind == 'directory':
2232
1765
                name = name + '/'
2233
 
            if name == "/":
2234
 
                pass # ignore root entry
2235
 
            elif name in shape:
 
1766
            if name in shape:
2236
1767
                shape.remove(name)
2237
1768
            else:
2238
1769
                extras.append(name)
2279
1810
 
2280
1811
        Tests that expect to provoke LockContention errors should call this.
2281
1812
        """
2282
 
        self.overrideAttr(lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
 
1813
        orig_timeout = bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS
 
1814
        def resetTimeout():
 
1815
            bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = orig_timeout
 
1816
        self.addCleanup(resetTimeout)
 
1817
        bzrlib.lockdir._DEFAULT_TIMEOUT_SECONDS = 0
2283
1818
 
2284
1819
    def make_utf8_encoded_stringio(self, encoding_type=None):
2285
1820
        """Return a StringIOWrapper instance, that will encode Unicode
2293
1828
        sio.encoding = output_encoding
2294
1829
        return sio
2295
1830
 
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
1831
 
2305
1832
class CapturedCall(object):
2306
1833
    """A helper for capturing smart server calls for easy debug analysis."""
2328
1855
class TestCaseWithMemoryTransport(TestCase):
2329
1856
    """Common test class for tests that do not need disk resources.
2330
1857
 
2331
 
    Tests that need disk resources should derive from TestCaseInTempDir
2332
 
    orTestCaseWithTransport.
 
1858
    Tests that need disk resources should derive from TestCaseWithTransport.
2333
1859
 
2334
1860
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2335
1861
 
2336
 
    For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
 
1862
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
2337
1863
    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
 
1864
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
 
1865
    must exist. However, TestCaseWithMemoryTransport does not offer local
 
1866
    file defaults for the transport in tests, nor does it obey the command line
2341
1867
    override, so tests that accidentally write to the common directory should
2342
1868
    be rare.
2343
1869
 
2344
 
    :cvar TEST_ROOT: Directory containing all temporary directories, plus a
2345
 
        ``.bzr`` directory that stops us ascending higher into the filesystem.
 
1870
    :cvar TEST_ROOT: Directory containing all temporary directories, plus
 
1871
    a .bzr directory that stops us ascending higher into the filesystem.
2346
1872
    """
2347
1873
 
2348
1874
    TEST_ROOT = None
2366
1892
 
2367
1893
        :param relpath: a path relative to the base url.
2368
1894
        """
2369
 
        t = _mod_transport.get_transport(self.get_url(relpath))
 
1895
        t = get_transport(self.get_url(relpath))
2370
1896
        self.assertFalse(t.is_readonly())
2371
1897
        return t
2372
1898
 
2378
1904
 
2379
1905
        :param relpath: a path relative to the base url.
2380
1906
        """
2381
 
        t = _mod_transport.get_transport(self.get_readonly_url(relpath))
 
1907
        t = get_transport(self.get_readonly_url(relpath))
2382
1908
        self.assertTrue(t.is_readonly())
2383
1909
        return t
2384
1910
 
2397
1923
        if self.__readonly_server is None:
2398
1924
            if self.transport_readonly_server is None:
2399
1925
                # readonly decorator requested
2400
 
                self.__readonly_server = test_server.ReadonlyServer()
 
1926
                # bring up the server
 
1927
                self.__readonly_server = ReadonlyServer()
 
1928
                self.__readonly_server.setUp(self.get_vfs_only_server())
2401
1929
            else:
2402
 
                # explicit readonly transport.
2403
1930
                self.__readonly_server = self.create_transport_readonly_server()
2404
 
            self.start_server(self.__readonly_server,
2405
 
                self.get_vfs_only_server())
 
1931
                self.__readonly_server.setUp(self.get_vfs_only_server())
 
1932
            self.addCleanup(self.__readonly_server.tearDown)
2406
1933
        return self.__readonly_server
2407
1934
 
2408
1935
    def get_readonly_url(self, relpath=None):
2426
1953
        is no means to override it.
2427
1954
        """
2428
1955
        if self.__vfs_server is None:
2429
 
            self.__vfs_server = memory.MemoryServer()
2430
 
            self.start_server(self.__vfs_server)
 
1956
            self.__vfs_server = MemoryServer()
 
1957
            self.__vfs_server.setUp()
 
1958
            self.addCleanup(self.__vfs_server.tearDown)
2431
1959
        return self.__vfs_server
2432
1960
 
2433
1961
    def get_server(self):
2440
1968
        then the self.get_vfs_server is returned.
2441
1969
        """
2442
1970
        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()
 
1971
            if self.transport_server is None or self.transport_server is self.vfs_transport_factory:
 
1972
                return self.get_vfs_only_server()
2446
1973
            else:
2447
1974
                # bring up a decorated means of access to the vfs only server.
2448
1975
                self.__server = self.transport_server()
2449
 
                self.start_server(self.__server, self.get_vfs_only_server())
 
1976
                try:
 
1977
                    self.__server.setUp(self.get_vfs_only_server())
 
1978
                except TypeError, e:
 
1979
                    # This should never happen; the try:Except here is to assist
 
1980
                    # developers having to update code rather than seeing an
 
1981
                    # uninformative TypeError.
 
1982
                    raise Exception, "Old server API in use: %s, %s" % (self.__server, e)
 
1983
            self.addCleanup(self.__server.tearDown)
2450
1984
        return self.__server
2451
1985
 
2452
1986
    def _adjust_url(self, base, relpath):
2514
2048
        propagating. This method ensures than a test did not leaked.
2515
2049
        """
2516
2050
        root = TestCaseWithMemoryTransport.TEST_ROOT
2517
 
        self.permit_url(_mod_transport.get_transport(root).base)
2518
2051
        wt = workingtree.WorkingTree.open(root)
2519
2052
        last_rev = wt.last_revision()
2520
2053
        if last_rev != 'null:':
2522
2055
            # recreate a new one or all the followng tests will fail.
2523
2056
            # If you need to inspect its content uncomment the following line
2524
2057
            # import pdb; pdb.set_trace()
2525
 
            _rmtree_temp_dir(root + '/.bzr', test_id=self.id())
 
2058
            _rmtree_temp_dir(root + '/.bzr')
2526
2059
            self._create_safety_net()
2527
2060
            raise AssertionError('%s/.bzr should not be modified' % root)
2528
2061
 
2529
2062
    def _make_test_root(self):
2530
2063
        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'))
 
2064
            root = osutils.mkdtemp(prefix='testbzr-', suffix='.tmp')
2534
2065
            TestCaseWithMemoryTransport.TEST_ROOT = root
2535
2066
 
2536
2067
            self._create_safety_net()
2539
2070
            # specifically told when all tests are finished.  This will do.
2540
2071
            atexit.register(_rmtree_temp_dir, root)
2541
2072
 
2542
 
        self.permit_dir(TestCaseWithMemoryTransport.TEST_ROOT)
2543
2073
        self.addCleanup(self._check_safety_net)
2544
2074
 
2545
2075
    def makeAndChdirToTestDir(self):
2553
2083
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
2554
2084
        self.test_dir = TestCaseWithMemoryTransport.TEST_ROOT
2555
2085
        self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
2556
 
        self.permit_dir(self.test_dir)
2557
2086
 
2558
2087
    def make_branch(self, relpath, format=None):
2559
2088
        """Create a branch on the transport at relpath."""
2565
2094
            # might be a relative or absolute path
2566
2095
            maybe_a_url = self.get_url(relpath)
2567
2096
            segments = maybe_a_url.rsplit('/', 1)
2568
 
            t = _mod_transport.get_transport(maybe_a_url)
 
2097
            t = get_transport(maybe_a_url)
2569
2098
            if len(segments) > 1 and segments[-1] not in ('', '.'):
2570
2099
                t.ensure_base()
2571
2100
            if format is None:
2588
2117
        made_control = self.make_bzrdir(relpath, format=format)
2589
2118
        return made_control.create_repository(shared=shared)
2590
2119
 
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)
 
2120
    def make_smart_server(self, path):
 
2121
        smart_server = server.SmartTCPServer_for_testing()
 
2122
        smart_server.setUp(self.get_server())
 
2123
        remote_transport = get_transport(smart_server.get_url()).clone(path)
 
2124
        self.addCleanup(smart_server.tearDown)
2598
2125
        return remote_transport
2599
2126
 
2600
2127
    def make_branch_and_memory_tree(self, relpath, format=None):
2603
2130
        return memorytree.MemoryTree.create_on_branch(b)
2604
2131
 
2605
2132
    def make_branch_builder(self, relpath, format=None):
2606
 
        branch = self.make_branch(relpath, format=format)
2607
 
        return branchbuilder.BranchBuilder(branch=branch)
 
2133
        return branchbuilder.BranchBuilder(self.get_transport(relpath),
 
2134
            format=format)
2608
2135
 
2609
2136
    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)
 
2137
        os.environ['HOME'] = self.test_home_dir
 
2138
        os.environ['BZR_HOME'] = self.test_home_dir
2615
2139
 
2616
2140
    def setUp(self):
2617
2141
        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
2142
        self._make_test_root()
2628
 
        self.addCleanup(os.chdir, os.getcwdu())
 
2143
        _currentdir = os.getcwdu()
 
2144
        def _leaveDirectory():
 
2145
            os.chdir(_currentdir)
 
2146
        self.addCleanup(_leaveDirectory)
2629
2147
        self.makeAndChdirToTestDir()
2630
2148
        self.overrideEnvironmentForTesting()
2631
2149
        self.__readonly_server = None
2634
2152
 
2635
2153
    def setup_smart_server_with_call_log(self):
2636
2154
        """Sets up a smart server as the transport server with a call log."""
2637
 
        self.transport_server = test_server.SmartTCPServer_for_testing
 
2155
        self.transport_server = server.SmartTCPServer_for_testing
2638
2156
        self.hpss_calls = []
2639
2157
        import traceback
2640
2158
        # Skip the current stack down to the caller of
2672
2190
 
2673
2191
    OVERRIDE_PYTHON = 'python'
2674
2192
 
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
2193
    def check_file_contents(self, filename, expect):
2682
2194
        self.log("check contents of file %s" % filename)
2683
 
        f = file(filename)
2684
 
        try:
2685
 
            contents = f.read()
2686
 
        finally:
2687
 
            f.close()
 
2195
        contents = file(filename, 'r').read()
2688
2196
        if contents != expect:
2689
2197
            self.log("expected: %r" % expect)
2690
2198
            self.log("actually: %r" % contents)
2692
2200
 
2693
2201
    def _getTestDirPrefix(self):
2694
2202
        # create a directory within the top level test directory
2695
 
        if sys.platform in ('win32', 'cygwin'):
 
2203
        if sys.platform == 'win32':
2696
2204
            name_prefix = re.sub('[<>*=+",:;_/\\-]', '_', self.id())
2697
2205
            # windows is likely to have path-length limits so use a short name
2698
2206
            name_prefix = name_prefix[-30:]
2713
2221
            if os.path.exists(name):
2714
2222
                name = name_prefix + '_' + str(i)
2715
2223
            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)
 
2224
                os.mkdir(name)
2720
2225
                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()
 
2226
        # now create test and home directories within this dir
 
2227
        self.test_base_dir = name
2728
2228
        self.test_home_dir = self.test_base_dir + '/home'
2729
2229
        os.mkdir(self.test_home_dir)
2730
2230
        self.test_dir = self.test_base_dir + '/work'
2736
2236
            f.write(self.id())
2737
2237
        finally:
2738
2238
            f.close()
 
2239
        self.addCleanup(self.deleteTestDir)
2739
2240
 
2740
2241
    def deleteTestDir(self):
2741
2242
        os.chdir(TestCaseWithMemoryTransport.TEST_ROOT)
2742
 
        _rmtree_temp_dir(self.test_base_dir, test_id=self.id())
 
2243
        _rmtree_temp_dir(self.test_base_dir)
2743
2244
 
2744
2245
    def build_tree(self, shape, line_endings='binary', transport=None):
2745
2246
        """Build a test tree according to a pattern.
2764
2265
                "a list or a tuple. Got %r instead" % (shape,))
2765
2266
        # It's OK to just create them using forward slashes on windows.
2766
2267
        if transport is None or transport.is_readonly():
2767
 
            transport = _mod_transport.get_transport(".")
 
2268
            transport = get_transport(".")
2768
2269
        for name in shape:
2769
2270
            self.assertIsInstance(name, basestring)
2770
2271
            if name[-1] == '/':
2780
2281
                content = "contents of %s%s" % (name.encode('utf-8'), end)
2781
2282
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
2782
2283
 
2783
 
    build_tree_contents = staticmethod(treeshape.build_tree_contents)
 
2284
    def build_tree_contents(self, shape):
 
2285
        build_tree_contents(shape)
2784
2286
 
2785
2287
    def assertInWorkingTree(self, path, root_path='.', tree=None):
2786
2288
        """Assert whether path or paths are in the WorkingTree"""
2826
2328
        """
2827
2329
        if self.__vfs_server is None:
2828
2330
            self.__vfs_server = self.vfs_transport_factory()
2829
 
            self.start_server(self.__vfs_server)
 
2331
            self.__vfs_server.setUp()
 
2332
            self.addCleanup(self.__vfs_server.tearDown)
2830
2333
        return self.__vfs_server
2831
2334
 
2832
2335
    def make_branch_and_tree(self, relpath, format=None):
2839
2342
        repository will also be accessed locally. Otherwise a lightweight
2840
2343
        checkout is created and returned.
2841
2344
 
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
2345
        :param format: The BzrDirFormat.
2852
2346
        :returns: the WorkingTree.
2853
2347
        """
2862
2356
            # We can only make working trees locally at the moment.  If the
2863
2357
            # transport can't support them, then we keep the non-disk-backed
2864
2358
            # branch and create a local checkout.
2865
 
            if self.vfs_transport_factory is test_server.LocalURLServer:
 
2359
            if self.vfs_transport_factory is LocalURLServer:
2866
2360
                # the branch is colocated on disk, we cannot create a checkout.
2867
2361
                # hopefully callers will expect this.
2868
2362
                local_controldir= bzrdir.BzrDir.open(self.get_vfs_only_url(relpath))
2905
2399
        super(TestCaseWithTransport, self).setUp()
2906
2400
        self.__vfs_server = None
2907
2401
 
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
2402
 
2917
2403
class ChrootedTestCase(TestCaseWithTransport):
2918
2404
    """A support class that provides readonly urls outside the local namespace.
2927
2413
    """
2928
2414
 
2929
2415
    def setUp(self):
2930
 
        from bzrlib.tests import http_server
2931
2416
        super(ChrootedTestCase, self).setUp()
2932
 
        if not self.vfs_transport_factory == memory.MemoryServer:
2933
 
            self.transport_readonly_server = http_server.HttpServer
 
2417
        if not self.vfs_transport_factory == MemoryServer:
 
2418
            self.transport_readonly_server = HttpServer
2934
2419
 
2935
2420
 
2936
2421
def condition_id_re(pattern):
2939
2424
    :param pattern: A regular expression string.
2940
2425
    :return: A callable that returns True if the re matches.
2941
2426
    """
2942
 
    filter_re = re.compile(pattern, 0)
 
2427
    filter_re = osutils.re_compile_checked(pattern, 0,
 
2428
        'test filter')
2943
2429
    def condition(test):
2944
2430
        test_id = test.id()
2945
2431
        return filter_re.search(test_id)
3131
2617
              exclude_pattern=None,
3132
2618
              strict=False,
3133
2619
              runner_class=None,
3134
 
              suite_decorators=None,
3135
 
              stream=None,
3136
 
              result_decorators=None,
3137
 
              ):
 
2620
              suite_decorators=None):
3138
2621
    """Run a test suite for bzr selftest.
3139
2622
 
3140
2623
    :param runner_class: The class of runner to use. Must support the
3149
2632
        verbosity = 1
3150
2633
    if runner_class is None:
3151
2634
        runner_class = TextTestRunner
3152
 
    if stream is None:
3153
 
        stream = sys.stdout
3154
 
    runner = runner_class(stream=stream,
 
2635
    runner = runner_class(stream=sys.stdout,
3155
2636
                            descriptions=0,
3156
2637
                            verbosity=verbosity,
3157
2638
                            bench_history=bench_history,
3158
 
                            strict=strict,
3159
 
                            result_decorators=result_decorators,
 
2639
                            list_only=list_only,
3160
2640
                            )
3161
2641
    runner.stop_on_failure=stop_on_failure
3162
2642
    # built in decorator factories:
3170
2650
        decorators.append(filter_tests(pattern))
3171
2651
    if suite_decorators:
3172
2652
        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
2653
    for decorator in decorators:
3179
2654
        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
2655
    result = runner.run(suite)
3189
2656
    if strict:
3190
2657
        return result.wasStrictlySuccessful()
3197
2664
 
3198
2665
 
3199
2666
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()
 
2667
    concurrency = local_concurrency()
3204
2668
    if concurrency == 1:
3205
2669
        return suite
3206
2670
    from testtools import ConcurrentTestSuite
3209
2673
 
3210
2674
 
3211
2675
def subprocess_decorator(suite):
3212
 
    concurrency = osutils.local_concurrency()
 
2676
    concurrency = local_concurrency()
3213
2677
    if concurrency == 1:
3214
2678
        return suite
3215
2679
    from testtools import ConcurrentTestSuite
3260
2724
    return suite
3261
2725
 
3262
2726
 
3263
 
class TestDecorator(TestUtil.TestSuite):
 
2727
class TestDecorator(TestSuite):
3264
2728
    """A decorator for TestCase/TestSuite objects.
3265
2729
    
3266
2730
    Usually, subclasses should override __iter__(used when flattening test
3269
2733
    """
3270
2734
 
3271
2735
    def __init__(self, suite):
3272
 
        TestUtil.TestSuite.__init__(self)
 
2736
        TestSuite.__init__(self)
3273
2737
        self.addTest(suite)
3274
2738
 
3275
2739
    def countTestCases(self):
3292
2756
        return result
3293
2757
 
3294
2758
 
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
2759
class ExcludeDecorator(TestDecorator):
3306
2760
    """A decorator which excludes test matching an exclude pattern."""
3307
2761
 
3351
2805
        if self.randomised:
3352
2806
            return iter(self._tests)
3353
2807
        self.randomised = True
3354
 
        self.stream.write("Randomizing test order using seed %s\n\n" %
 
2808
        self.stream.writeln("Randomizing test order using seed %s\n" %
3355
2809
            (self.actual_seed()))
3356
2810
        # Initialise the random number generator.
3357
2811
        random.seed(self.actual_seed())
3394
2848
 
3395
2849
def partition_tests(suite, count):
3396
2850
    """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
 
2851
    result = []
 
2852
    tests = list(iter_suite_tests(suite))
 
2853
    tests_per_process = int(math.ceil(float(len(tests)) / count))
 
2854
    for block in range(count):
 
2855
        low_test = block * tests_per_process
 
2856
        high_test = low_test + tests_per_process
 
2857
        process_tests = tests[low_test:high_test]
 
2858
        result.append(process_tests)
 
2859
    return result
3420
2860
 
3421
2861
 
3422
2862
def fork_for_tests(suite):
3425
2865
    :return: An iterable of TestCase-like objects which can each have
3426
2866
        run(result) called on them to feed tests to result.
3427
2867
    """
3428
 
    concurrency = osutils.local_concurrency()
 
2868
    concurrency = local_concurrency()
3429
2869
    result = []
3430
2870
    from subunit import TestProtocolClient, ProtocolTestCase
3431
 
    from subunit.test_results import AutoTimingTestResultDecorator
3432
2871
    class TestInOtherProcess(ProtocolTestCase):
3433
2872
        # Should be in subunit, I think. RBC.
3434
2873
        def __init__(self, stream, pid):
3439
2878
            try:
3440
2879
                ProtocolTestCase.run(self, result)
3441
2880
            finally:
3442
 
                os.waitpid(self.pid, 0)
 
2881
                os.waitpid(self.pid, os.WNOHANG)
3443
2882
 
3444
2883
    test_blocks = partition_tests(suite, concurrency)
3445
2884
    for process_tests in test_blocks:
3446
 
        process_suite = TestUtil.TestSuite()
 
2885
        process_suite = TestSuite()
3447
2886
        process_suite.addTests(process_tests)
3448
2887
        c2pread, c2pwrite = os.pipe()
3449
2888
        pid = os.fork()
3450
2889
        if pid == 0:
3451
 
            workaround_zealous_crypto_random()
3452
2890
            try:
3453
2891
                os.close(c2pread)
3454
2892
                # Leave stderr and stdout open so we can see test noise
3458
2896
                sys.stdin.close()
3459
2897
                sys.stdin = None
3460
2898
                stream = os.fdopen(c2pwrite, 'wb', 1)
3461
 
                subunit_result = AutoTimingTestResultDecorator(
3462
 
                    TestProtocolClient(stream))
 
2899
                subunit_result = TestProtocolClient(stream)
3463
2900
                process_suite.run(subunit_result)
3464
2901
            finally:
3465
2902
                os._exit(0)
3477
2914
    :return: An iterable of TestCase-like objects which can each have
3478
2915
        run(result) called on them to feed tests to result.
3479
2916
    """
3480
 
    concurrency = osutils.local_concurrency()
 
2917
    concurrency = local_concurrency()
3481
2918
    result = []
3482
 
    from subunit import ProtocolTestCase
 
2919
    from subunit import TestProtocolClient, ProtocolTestCase
3483
2920
    class TestInSubprocess(ProtocolTestCase):
3484
2921
        def __init__(self, process, name):
3485
2922
            ProtocolTestCase.__init__(self, process.stdout)
3501
2938
        if not os.path.isfile(bzr_path):
3502
2939
            # We are probably installed. Assume sys.argv is the right file
3503
2940
            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
2941
        fd, test_list_file_name = tempfile.mkstemp()
3509
2942
        test_list_file = os.fdopen(fd, 'wb', 1)
3510
2943
        for test in process_tests:
3511
2944
            test_list_file.write(test.id() + '\n')
3512
2945
        test_list_file.close()
3513
2946
        try:
3514
 
            argv = bzr_path + ['selftest', '--load-list', test_list_file_name,
 
2947
            argv = [bzr_path, 'selftest', '--load-list', test_list_file_name,
3515
2948
                '--subunit']
3516
2949
            if '--no-plugins' in sys.argv:
3517
2950
                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)
 
2951
            # stderr=STDOUT would be ideal, but until we prevent noise on
 
2952
            # stderr it can interrupt the subunit protocol.
 
2953
            process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
 
2954
                bufsize=1)
3524
2955
            test = TestInSubprocess(process, test_list_file_name)
3525
2956
            result.append(test)
3526
2957
        except:
3529
2960
    return result
3530
2961
 
3531
2962
 
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
 
    """
 
2963
def cpucount(content):
 
2964
    lines = content.splitlines()
 
2965
    prefix = 'processor'
 
2966
    for line in lines:
 
2967
        if line.startswith(prefix):
 
2968
            concurrency = int(line[line.find(':')+1:]) + 1
 
2969
    return concurrency
 
2970
 
 
2971
 
 
2972
def local_concurrency():
 
2973
    try:
 
2974
        content = file('/proc/cpuinfo', 'rb').read()
 
2975
        concurrency = cpucount(content)
 
2976
    except Exception, e:
 
2977
        concurrency = 1
 
2978
    return concurrency
 
2979
 
 
2980
 
 
2981
class BZRTransformingResult(unittest.TestResult):
 
2982
 
 
2983
    def __init__(self, target):
 
2984
        unittest.TestResult.__init__(self)
 
2985
        self.result = target
3543
2986
 
3544
2987
    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)
 
2988
        self.result.startTest(test)
 
2989
 
 
2990
    def stopTest(self, test):
 
2991
        self.result.stopTest(test)
 
2992
 
 
2993
    def addError(self, test, err):
 
2994
        feature = self._error_looks_like('UnavailableFeature: ', err)
 
2995
        if feature is not None:
 
2996
            self.result.addNotSupported(test, feature)
 
2997
        else:
 
2998
            self.result.addError(test, err)
 
2999
 
 
3000
    def addFailure(self, test, err):
 
3001
        known = self._error_looks_like('KnownFailure: ', err)
 
3002
        if known is not None:
 
3003
            self.result._addKnownFailure(test, [KnownFailure,
 
3004
                                                KnownFailure(known), None])
 
3005
        else:
 
3006
            self.result.addFailure(test, err)
 
3007
 
 
3008
    def addSkip(self, test, reason):
 
3009
        self.result.addSkip(test, reason)
3551
3010
 
3552
3011
    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)
 
3012
        self.result.addSuccess(test)
3561
3013
 
3562
 
    def stopTest(self, test):
3563
 
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
3564
 
        self.profiler = None
 
3014
    def _error_looks_like(self, prefix, err):
 
3015
        """Deserialize exception and returns the stringify value."""
 
3016
        import subunit
 
3017
        value = None
 
3018
        typ, exc, _ = err
 
3019
        if isinstance(exc, subunit.RemoteException):
 
3020
            # stringify the exception gives access to the remote traceback
 
3021
            # We search the last line for 'prefix'
 
3022
            lines = str(exc).split('\n')
 
3023
            if len(lines) > 1:
 
3024
                last = lines[-2] # -1 is empty, final \n
 
3025
            else:
 
3026
                last = lines[-1]
 
3027
            if last.startswith(prefix):
 
3028
                value = last[len(prefix):]
 
3029
        return value
3565
3030
 
3566
3031
 
3567
3032
# 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
3033
selftest_debug_flags = set()
3580
3034
 
3581
3035
 
3594
3048
             starting_with=None,
3595
3049
             runner_class=None,
3596
3050
             suite_decorators=None,
3597
 
             stream=None,
3598
 
             lsprof_tests=False,
3599
3051
             ):
3600
3052
    """Run the whole test suite under the enhanced runner"""
3601
3053
    # XXX: Very ugly way to do this...
3618
3070
            keep_only = None
3619
3071
        else:
3620
3072
            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
3073
        if test_suite_factory is None:
3625
 
            # Reduce loading time by loading modules based on the starting_with
3626
 
            # patterns.
3627
3074
            suite = test_suite(keep_only, starting_with)
3628
3075
        else:
3629
3076
            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
3077
        return run_suite(suite, 'testbzr', verbose=verbose, pattern=pattern,
3637
3078
                     stop_on_failure=stop_on_failure,
3638
3079
                     transport=transport,
3645
3086
                     strict=strict,
3646
3087
                     runner_class=runner_class,
3647
3088
                     suite_decorators=suite_decorators,
3648
 
                     stream=stream,
3649
 
                     result_decorators=result_decorators,
3650
3089
                     )
3651
3090
    finally:
3652
3091
        default_transport = old_transport
3775
3214
                key, obj, help=help, info=info, override_existing=False)
3776
3215
        except KeyError:
3777
3216
            actual = self.get(key)
3778
 
            trace.note(
3779
 
                'Test prefix alias %s is already used for %s, ignoring %s'
3780
 
                % (key, actual, obj))
 
3217
            note('Test prefix alias %s is already used for %s, ignoring %s'
 
3218
                 % (key, actual, obj))
3781
3219
 
3782
3220
    def resolve_alias(self, id_start):
3783
3221
        """Replace the alias by the prefix in the given string.
3801
3239
# appear prefixed ('bzrlib.' is "replaced" by 'bzrlib.').
3802
3240
test_prefix_alias_registry.register('bzrlib', 'bzrlib')
3803
3241
 
3804
 
# Obvious highest levels prefixes, feel free to add your own via a plugin
 
3242
# Obvious higest levels prefixes, feel free to add your own via a plugin
3805
3243
test_prefix_alias_registry.register('bd', 'bzrlib.doc')
3806
3244
test_prefix_alias_registry.register('bu', 'bzrlib.utils')
3807
3245
test_prefix_alias_registry.register('bt', 'bzrlib.tests')
3809
3247
test_prefix_alias_registry.register('bp', 'bzrlib.plugins')
3810
3248
 
3811
3249
 
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
3250
def test_suite(keep_only=None, starting_with=None):
4046
3251
    """Build and return TestSuite for the whole of bzrlib.
4047
3252
 
4053
3258
    This function can be replaced if you need to change the default test
4054
3259
    suite on a global basis, but it is not encouraged.
4055
3260
    """
 
3261
    testmod_names = [
 
3262
                   'bzrlib.doc',
 
3263
                   'bzrlib.tests.blackbox',
 
3264
                   'bzrlib.tests.branch_implementations',
 
3265
                   'bzrlib.tests.bzrdir_implementations',
 
3266
                   'bzrlib.tests.commands',
 
3267
                   'bzrlib.tests.interrepository_implementations',
 
3268
                   'bzrlib.tests.intertree_implementations',
 
3269
                   'bzrlib.tests.inventory_implementations',
 
3270
                   'bzrlib.tests.per_interbranch',
 
3271
                   'bzrlib.tests.per_lock',
 
3272
                   'bzrlib.tests.per_repository',
 
3273
                   'bzrlib.tests.per_repository_reference',
 
3274
                   'bzrlib.tests.test__chk_map',
 
3275
                   'bzrlib.tests.test__dirstate_helpers',
 
3276
                   'bzrlib.tests.test__groupcompress',
 
3277
                   'bzrlib.tests.test__walkdirs_win32',
 
3278
                   'bzrlib.tests.test_ancestry',
 
3279
                   'bzrlib.tests.test_annotate',
 
3280
                   'bzrlib.tests.test_api',
 
3281
                   'bzrlib.tests.test_atomicfile',
 
3282
                   'bzrlib.tests.test_bad_files',
 
3283
                   'bzrlib.tests.test_bisect_multi',
 
3284
                   'bzrlib.tests.test_branch',
 
3285
                   'bzrlib.tests.test_branchbuilder',
 
3286
                   'bzrlib.tests.test_btree_index',
 
3287
                   'bzrlib.tests.test_bugtracker',
 
3288
                   'bzrlib.tests.test_bundle',
 
3289
                   'bzrlib.tests.test_bzrdir',
 
3290
                   'bzrlib.tests.test__chunks_to_lines',
 
3291
                   'bzrlib.tests.test_cache_utf8',
 
3292
                   # These need to be excluded until the development5 format
 
3293
                   # lands. (That's waiting on the dependent inventory and
 
3294
                   # repository changes to land.)
 
3295
                   #'bzrlib.tests.test_chk_map',
 
3296
                   'bzrlib.tests.test_chunk_writer',
 
3297
                   'bzrlib.tests.test_clean_tree',
 
3298
                   'bzrlib.tests.test_commands',
 
3299
                   'bzrlib.tests.test_commit',
 
3300
                   'bzrlib.tests.test_commit_merge',
 
3301
                   'bzrlib.tests.test_config',
 
3302
                   'bzrlib.tests.test_conflicts',
 
3303
                   'bzrlib.tests.test_counted_lock',
 
3304
                   'bzrlib.tests.test_decorators',
 
3305
                   'bzrlib.tests.test_delta',
 
3306
                   'bzrlib.tests.test_debug',
 
3307
                   'bzrlib.tests.test_deprecated_graph',
 
3308
                   'bzrlib.tests.test_diff',
 
3309
                   'bzrlib.tests.test_directory_service',
 
3310
                   'bzrlib.tests.test_dirstate',
 
3311
                   'bzrlib.tests.test_email_message',
 
3312
                   'bzrlib.tests.test_eol_filters',
 
3313
                   'bzrlib.tests.test_errors',
 
3314
                   'bzrlib.tests.test_export',
 
3315
                   'bzrlib.tests.test_extract',
 
3316
                   'bzrlib.tests.test_fetch',
 
3317
                   'bzrlib.tests.test_fifo_cache',
 
3318
                   'bzrlib.tests.test_filters',
 
3319
                   'bzrlib.tests.test_ftp_transport',
 
3320
                   'bzrlib.tests.test_foreign',
 
3321
                   'bzrlib.tests.test_generate_docs',
 
3322
                   'bzrlib.tests.test_generate_ids',
 
3323
                   'bzrlib.tests.test_globbing',
 
3324
                   'bzrlib.tests.test_gpg',
 
3325
                   'bzrlib.tests.test_graph',
 
3326
                   'bzrlib.tests.test_groupcompress',
 
3327
                   'bzrlib.tests.test_hashcache',
 
3328
                   'bzrlib.tests.test_help',
 
3329
                   'bzrlib.tests.test_hooks',
 
3330
                   'bzrlib.tests.test_http',
 
3331
                   'bzrlib.tests.test_http_implementations',
 
3332
                   'bzrlib.tests.test_http_response',
 
3333
                   'bzrlib.tests.test_https_ca_bundle',
 
3334
                   'bzrlib.tests.test_identitymap',
 
3335
                   'bzrlib.tests.test_ignores',
 
3336
                   'bzrlib.tests.test_index',
 
3337
                   'bzrlib.tests.test_info',
 
3338
                   'bzrlib.tests.test_inv',
 
3339
                   'bzrlib.tests.test_inventory_delta',
 
3340
                   'bzrlib.tests.test_knit',
 
3341
                   'bzrlib.tests.test_lazy_import',
 
3342
                   'bzrlib.tests.test_lazy_regex',
 
3343
                   'bzrlib.tests.test_lockable_files',
 
3344
                   'bzrlib.tests.test_lockdir',
 
3345
                   'bzrlib.tests.test_log',
 
3346
                   'bzrlib.tests.test_lru_cache',
 
3347
                   'bzrlib.tests.test_lsprof',
 
3348
                   'bzrlib.tests.test_mail_client',
 
3349
                   'bzrlib.tests.test_memorytree',
 
3350
                   'bzrlib.tests.test_merge',
 
3351
                   'bzrlib.tests.test_merge3',
 
3352
                   'bzrlib.tests.test_merge_core',
 
3353
                   'bzrlib.tests.test_merge_directive',
 
3354
                   'bzrlib.tests.test_missing',
 
3355
                   'bzrlib.tests.test_msgeditor',
 
3356
                   'bzrlib.tests.test_multiparent',
 
3357
                   'bzrlib.tests.test_mutabletree',
 
3358
                   'bzrlib.tests.test_nonascii',
 
3359
                   'bzrlib.tests.test_options',
 
3360
                   'bzrlib.tests.test_osutils',
 
3361
                   'bzrlib.tests.test_osutils_encodings',
 
3362
                   'bzrlib.tests.test_pack',
 
3363
                   'bzrlib.tests.test_pack_repository',
 
3364
                   'bzrlib.tests.test_patch',
 
3365
                   'bzrlib.tests.test_patches',
 
3366
                   'bzrlib.tests.test_permissions',
 
3367
                   'bzrlib.tests.test_plugins',
 
3368
                   'bzrlib.tests.test_progress',
 
3369
                   'bzrlib.tests.test_read_bundle',
 
3370
                   'bzrlib.tests.test_reconcile',
 
3371
                   'bzrlib.tests.test_reconfigure',
 
3372
                   'bzrlib.tests.test_registry',
 
3373
                   'bzrlib.tests.test_remote',
 
3374
                   'bzrlib.tests.test_rename_map',
 
3375
                   'bzrlib.tests.test_repository',
 
3376
                   'bzrlib.tests.test_revert',
 
3377
                   'bzrlib.tests.test_revision',
 
3378
                   'bzrlib.tests.test_revisionspec',
 
3379
                   'bzrlib.tests.test_revisiontree',
 
3380
                   'bzrlib.tests.test_rio',
 
3381
                   'bzrlib.tests.test_rules',
 
3382
                   'bzrlib.tests.test_sampler',
 
3383
                   'bzrlib.tests.test_selftest',
 
3384
                   'bzrlib.tests.test_serializer',
 
3385
                   'bzrlib.tests.test_setup',
 
3386
                   'bzrlib.tests.test_sftp_transport',
 
3387
                   'bzrlib.tests.test_shelf',
 
3388
                   'bzrlib.tests.test_shelf_ui',
 
3389
                   'bzrlib.tests.test_smart',
 
3390
                   'bzrlib.tests.test_smart_add',
 
3391
                   'bzrlib.tests.test_smart_request',
 
3392
                   'bzrlib.tests.test_smart_transport',
 
3393
                   'bzrlib.tests.test_smtp_connection',
 
3394
                   'bzrlib.tests.test_source',
 
3395
                   'bzrlib.tests.test_ssh_transport',
 
3396
                   'bzrlib.tests.test_status',
 
3397
                   'bzrlib.tests.test_store',
 
3398
                   'bzrlib.tests.test_strace',
 
3399
                   'bzrlib.tests.test_subsume',
 
3400
                   'bzrlib.tests.test_switch',
 
3401
                   'bzrlib.tests.test_symbol_versioning',
 
3402
                   'bzrlib.tests.test_tag',
 
3403
                   'bzrlib.tests.test_testament',
 
3404
                   'bzrlib.tests.test_textfile',
 
3405
                   'bzrlib.tests.test_textmerge',
 
3406
                   'bzrlib.tests.test_timestamp',
 
3407
                   'bzrlib.tests.test_trace',
 
3408
                   'bzrlib.tests.test_transactions',
 
3409
                   'bzrlib.tests.test_transform',
 
3410
                   'bzrlib.tests.test_transport',
 
3411
                   'bzrlib.tests.test_transport_implementations',
 
3412
                   'bzrlib.tests.test_transport_log',
 
3413
                   'bzrlib.tests.test_tree',
 
3414
                   'bzrlib.tests.test_treebuilder',
 
3415
                   'bzrlib.tests.test_tsort',
 
3416
                   'bzrlib.tests.test_tuned_gzip',
 
3417
                   'bzrlib.tests.test_ui',
 
3418
                   'bzrlib.tests.test_uncommit',
 
3419
                   'bzrlib.tests.test_upgrade',
 
3420
                   'bzrlib.tests.test_upgrade_stacked',
 
3421
                   'bzrlib.tests.test_urlutils',
 
3422
                   'bzrlib.tests.test_version',
 
3423
                   'bzrlib.tests.test_version_info',
 
3424
                   'bzrlib.tests.test_versionedfile',
 
3425
                   'bzrlib.tests.test_weave',
 
3426
                   'bzrlib.tests.test_whitebox',
 
3427
                   'bzrlib.tests.test_win32utils',
 
3428
                   'bzrlib.tests.test_workingtree',
 
3429
                   'bzrlib.tests.test_workingtree_4',
 
3430
                   'bzrlib.tests.test_wsgi',
 
3431
                   'bzrlib.tests.test_xml',
 
3432
                   'bzrlib.tests.tree_implementations',
 
3433
                   'bzrlib.tests.workingtree_implementations',
 
3434
                   'bzrlib.util.tests.test_bencode',
 
3435
                   ]
4056
3436
 
4057
3437
    loader = TestUtil.TestLoader()
4058
3438
 
4059
 
    if keep_only is not None:
4060
 
        id_filter = TestIdList(keep_only)
4061
3439
    if starting_with:
 
3440
        starting_with = [test_prefix_alias_registry.resolve_alias(start)
 
3441
                         for start in starting_with]
4062
3442
        # We take precedence over keep_only because *at loading time* using
4063
3443
        # both options means we will load less tests for the same final result.
4064
3444
        def interesting_module(name):
4074
3454
        loader = TestUtil.FilteredByModuleTestLoader(interesting_module)
4075
3455
 
4076
3456
    elif keep_only is not None:
 
3457
        id_filter = TestIdList(keep_only)
4077
3458
        loader = TestUtil.FilteredByModuleTestLoader(id_filter.refers_to)
4078
3459
        def interesting_module(name):
4079
3460
            return id_filter.refers_to(name)
4087
3468
    suite = loader.suiteClass()
4088
3469
 
4089
3470
    # 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():
 
3471
    suite.addTest(loader.loadTestsFromModuleNames(testmod_names))
 
3472
 
 
3473
    modules_to_doctest = [
 
3474
        'bzrlib',
 
3475
        'bzrlib.branchbuilder',
 
3476
        'bzrlib.export',
 
3477
        'bzrlib.inventory',
 
3478
        'bzrlib.iterablefile',
 
3479
        'bzrlib.lockdir',
 
3480
        'bzrlib.merge3',
 
3481
        'bzrlib.option',
 
3482
        'bzrlib.symbol_versioning',
 
3483
        'bzrlib.tests',
 
3484
        'bzrlib.timestamp',
 
3485
        'bzrlib.version_info_formats.format_custom',
 
3486
        ]
 
3487
 
 
3488
    for mod in modules_to_doctest:
4093
3489
        if not interesting_module(mod):
4094
3490
            # No tests to keep here, move along
4095
3491
            continue
4096
3492
        try:
4097
3493
            # note that this really does mean "report only" -- doctest
4098
3494
            # still runs the rest of the examples
4099
 
            doc_suite = IsolatedDocTestSuite(
4100
 
                mod, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
 
3495
            doc_suite = doctest.DocTestSuite(mod,
 
3496
                optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
4101
3497
        except ValueError, e:
4102
3498
            print '**failed to get doctest for: %s\n%s' % (mod, e)
4103
3499
            raise
4106
3502
        suite.addTest(doc_suite)
4107
3503
 
4108
3504
    default_encoding = sys.getdefaultencoding()
4109
 
    for name, plugin in _mod_plugin.plugins().items():
 
3505
    for name, plugin in bzrlib.plugin.plugins().items():
4110
3506
        if not interesting_module(plugin.module.__name__):
4111
3507
            continue
4112
3508
        plugin_suite = plugin.test_suite()
4118
3514
        if plugin_suite is not None:
4119
3515
            suite.addTest(plugin_suite)
4120
3516
        if default_encoding != sys.getdefaultencoding():
4121
 
            trace.warning(
 
3517
            bzrlib.trace.warning(
4122
3518
                'Plugin "%s" tried to reset default encoding to: %s', name,
4123
3519
                sys.getdefaultencoding())
4124
3520
            reload(sys)
4125
3521
            sys.setdefaultencoding(default_encoding)
4126
3522
 
 
3523
    if starting_with:
 
3524
        suite = filter_suite_by_id_startswith(suite, starting_with)
 
3525
 
4127
3526
    if keep_only is not None:
4128
3527
        # Now that the referred modules have loaded their tests, keep only the
4129
3528
        # requested ones.
4139
3538
            # Some tests mentioned in the list are not in the test suite. The
4140
3539
            # list may be out of date, report to the tester.
4141
3540
            for id in not_found:
4142
 
                trace.warning('"%s" not found in the test suite', id)
 
3541
                bzrlib.trace.warning('"%s" not found in the test suite', id)
4143
3542
        for id in duplicates:
4144
 
            trace.warning('"%s" is used as an id by several tests', id)
 
3543
            bzrlib.trace.warning('"%s" is used as an id by several tests', id)
4145
3544
 
4146
3545
    return suite
4147
3546
 
4148
3547
 
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):
 
3548
def multiply_scenarios(scenarios_left, scenarios_right):
4162
3549
    """Multiply two sets of scenarios.
4163
3550
 
4164
3551
    :returns: the cartesian product of the two sets of scenarios, that is
4195
3582
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
4196
3583
    ...     [('one', dict(param=1)),
4197
3584
    ...      ('two', dict(param=2))],
4198
 
    ...     TestUtil.TestSuite())
 
3585
    ...     TestSuite())
4199
3586
    >>> tests = list(iter_suite_tests(r))
4200
3587
    >>> len(tests)
4201
3588
    2
4248
3635
    :param new_id: The id to assign to it.
4249
3636
    :return: The new test.
4250
3637
    """
4251
 
    new_test = copy.copy(test)
 
3638
    from copy import deepcopy
 
3639
    new_test = deepcopy(test)
4252
3640
    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
3641
    return new_test
4266
3642
 
4267
3643
 
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):
 
3644
def _rmtree_temp_dir(dirname):
4310
3645
    # If LANG=C we probably have created some bogus paths
4311
3646
    # which rmtree(unicode) will fail to delete
4312
3647
    # so make sure we are using rmtree(str) to delete everything
4321
3656
    try:
4322
3657
        osutils.rmtree(dirname)
4323
3658
    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))
 
3659
        if sys.platform == 'win32' and e.errno == errno.EACCES:
 
3660
            sys.stderr.write('Permission denied: '
 
3661
                             'unable to remove testing dir '
 
3662
                             '%s\n%s'
 
3663
                             % (os.path.basename(dirname), e))
 
3664
        else:
 
3665
            raise
4335
3666
 
4336
3667
 
4337
3668
class Feature(object):
4419
3750
UnicodeFilenameFeature = _UnicodeFilenameFeature()
4420
3751
 
4421
3752
 
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
3753
def probe_unicode_in_user_encoding():
4489
3754
    """Try to encode several unicode strings to use in unicode-aware tests.
4490
3755
    Return first successfull match.
4559
3824
UnicodeFilename = _UnicodeFilename()
4560
3825
 
4561
3826
 
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
3827
class _UTF8Filesystem(Feature):
4574
3828
    """Is the filesystem UTF-8?"""
4575
3829
 
4581
3835
UTF8Filesystem = _UTF8Filesystem()
4582
3836
 
4583
3837
 
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
3838
class _CaseInsCasePresFilenameFeature(Feature):
4609
3839
    """Is the file-system case insensitive, but case-preserving?"""
4610
3840
 
4660
3890
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
4661
3891
 
4662
3892
 
4663
 
class _CaseSensitiveFilesystemFeature(Feature):
 
3893
class _SubUnitFeature(Feature):
 
3894
    """Check if subunit is available."""
4664
3895
 
4665
3896
    def _probe(self):
4666
 
        if CaseInsCasePresFilenameFeature.available():
4667
 
            return False
4668
 
        elif CaseInsensitiveFilesystemFeature.available():
4669
 
            return False
4670
 
        else:
 
3897
        try:
 
3898
            import subunit
4671
3899
            return True
 
3900
        except ImportError:
 
3901
            return False
4672
3902
 
4673
3903
    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
 
 
 
3904
        return 'subunit'
 
3905
 
 
3906
SubUnitFeature = _SubUnitFeature()
4680
3907
# Only define SubUnitBzrRunner if subunit is available.
4681
3908
try:
4682
3909
    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
3910
    class SubUnitBzrRunner(TextTestRunner):
4695
3911
        def run(self, test):
4696
 
            result = AutoTimingTestResultDecorator(
4697
 
                SubUnitBzrProtocolClient(self.stream))
 
3912
            # undo out claim for testing which looks like a test start to subunit
 
3913
            self.stream.write("success: %s\n" % (osutils.realpath(sys.argv[0]),))
 
3914
            result = TestProtocolClient(self.stream)
4698
3915
            test.run(result)
4699
3916
            return result
4700
3917
except ImportError:
4701
3918
    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()