~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-02-17 05:57:15 UTC
  • mfrom: (5036.1.1 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20100217055715-5b8xt6dfbov0bbgz
(mbp) merge 2.1 back to trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
"""Testing framework extensions"""
 
17
 
 
18
# TODO: Perhaps there should be an API to find out if bzr running under the
 
19
# test suite -- some plugins might want to avoid making intrusive changes if
 
20
# this is the case.  However, we want behaviour under to test to diverge as
 
21
# little as possible, so this should be used rarely if it's added at all.
 
22
# (Suggestion from j-a-meinel, 2005-11-24)
18
23
 
19
24
# NOTE: Some classes in here use camelCaseNaming() rather than
20
25
# underscore_naming().  That's for consistency with unittest; it's not the
23
28
 
24
29
import atexit
25
30
import codecs
26
 
import copy
 
31
from copy import copy
27
32
from cStringIO import StringIO
28
33
import difflib
29
34
import doctest
30
35
import errno
31
 
import itertools
32
36
import logging
 
37
import math
33
38
import os
34
 
import platform
35
 
import pprint
 
39
from pprint import pformat
36
40
import random
37
41
import re
38
42
import shlex
39
43
import stat
40
 
import subprocess
 
44
from subprocess import Popen, PIPE, STDOUT
41
45
import sys
42
46
import tempfile
43
47
import threading
49
53
import testtools
50
54
# nb: check this before importing anything else from within it
51
55
_testtools_version = getattr(testtools, '__version__', ())
52
 
if _testtools_version < (0, 9, 5):
53
 
    raise ImportError("need at least testtools 0.9.5: %s is %r"
 
56
if _testtools_version < (0, 9, 2):
 
57
    raise ImportError("need at least testtools 0.9.2: %s is %r"
54
58
        % (testtools.__file__, _testtools_version))
55
59
from testtools import content
56
60
 
57
 
import bzrlib
58
61
from bzrlib import (
59
62
    branchbuilder,
60
63
    bzrdir,
61
64
    chk_map,
62
 
    commands as _mod_commands,
63
65
    config,
64
66
    debug,
65
67
    errors,
66
68
    hooks,
67
69
    lock as _mod_lock,
68
 
    lockdir,
69
70
    memorytree,
70
71
    osutils,
71
 
    plugin as _mod_plugin,
72
 
    pyutils,
 
72
    progress,
73
73
    ui,
74
74
    urlutils,
75
75
    registry,
76
 
    symbol_versioning,
77
 
    trace,
78
 
    transport as _mod_transport,
79
76
    workingtree,
80
77
    )
 
78
import bzrlib.branch
 
79
import bzrlib.commands
 
80
import bzrlib.timestamp
 
81
import bzrlib.export
 
82
import bzrlib.inventory
 
83
import bzrlib.iterablefile
 
84
import bzrlib.lockdir
81
85
try:
82
86
    import bzrlib.lsprof
83
87
except ImportError:
84
88
    # lsprof not available
85
89
    pass
86
 
from bzrlib.smart import client, request
 
90
from bzrlib.merge import merge_inner
 
91
import bzrlib.merge3
 
92
import bzrlib.plugin
 
93
from bzrlib.smart import client, request, server
 
94
import bzrlib.store
 
95
from bzrlib import symbol_versioning
 
96
from bzrlib.symbol_versioning import (
 
97
    DEPRECATED_PARAMETER,
 
98
    deprecated_function,
 
99
    deprecated_in,
 
100
    deprecated_method,
 
101
    deprecated_passed,
 
102
    )
 
103
import bzrlib.trace
87
104
from bzrlib.transport import (
 
105
    get_transport,
88
106
    memory,
89
107
    pathfilter,
90
108
    )
91
 
from bzrlib.symbol_versioning import (
92
 
    deprecated_function,
93
 
    deprecated_in,
94
 
    )
 
109
import bzrlib.transport
 
110
from bzrlib.trace import mutter, note
95
111
from bzrlib.tests import (
96
112
    test_server,
97
113
    TestUtil,
98
 
    treeshape,
99
114
    )
 
115
from bzrlib.tests.http_server import HttpServer
 
116
from bzrlib.tests.TestUtil import (
 
117
                          TestSuite,
 
118
                          TestLoader,
 
119
                          )
 
120
from bzrlib.tests.treeshape import build_tree_contents
100
121
from bzrlib.ui import NullProgressView
101
122
from bzrlib.ui.text import TextUIFactory
 
123
import bzrlib.version_info_formats.format_custom
 
124
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
102
125
 
103
126
# Mark this python module as being part of the implementation
104
127
# of unittest: this gives us better tracebacks where the last
116
139
SUBUNIT_SEEK_SET = 0
117
140
SUBUNIT_SEEK_CUR = 1
118
141
 
119
 
# These are intentionally brought into this namespace. That way plugins, etc
120
 
# can just "from bzrlib.tests import TestCase, TestLoader, etc"
121
 
TestSuite = TestUtil.TestSuite
122
 
TestLoader = TestUtil.TestLoader
123
 
 
124
 
# Tests should run in a clean and clearly defined environment. The goal is to
125
 
# keep them isolated from the running environment as mush as possible. The test
126
 
# framework ensures the variables defined below are set (or deleted if the
127
 
# value is None) before a test is run and reset to their original value after
128
 
# the test is run. Generally if some code depends on an environment variable,
129
 
# the tests should start without this variable in the environment. There are a
130
 
# few exceptions but you shouldn't violate this rule lightly.
131
 
isolated_environ = {
132
 
    'BZR_HOME': None,
133
 
    'HOME': None,
134
 
    # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
135
 
    # tests do check our impls match APPDATA
136
 
    'BZR_EDITOR': None, # test_msgeditor manipulates this variable
137
 
    'VISUAL': None,
138
 
    'EDITOR': None,
139
 
    'BZR_EMAIL': None,
140
 
    'BZREMAIL': None, # may still be present in the environment
141
 
    'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
142
 
    'BZR_PROGRESS_BAR': None,
143
 
    # This should trap leaks to ~/.bzr.log. This occurs when tests use TestCase
144
 
    # as a base class instead of TestCaseInTempDir. Tests inheriting from
145
 
    # TestCase should not use disk resources, BZR_LOG is one.
146
 
    'BZR_LOG': '/you-should-use-TestCaseInTempDir-if-you-need-a-log-file',
147
 
    'BZR_PLUGIN_PATH': None,
148
 
    'BZR_DISABLE_PLUGINS': None,
149
 
    'BZR_PLUGINS_AT': None,
150
 
    'BZR_CONCURRENCY': None,
151
 
    # Make sure that any text ui tests are consistent regardless of
152
 
    # the environment the test case is run in; you may want tests that
153
 
    # test other combinations.  'dumb' is a reasonable guess for tests
154
 
    # going to a pipe or a StringIO.
155
 
    'TERM': 'dumb',
156
 
    'LINES': '25',
157
 
    'COLUMNS': '80',
158
 
    'BZR_COLUMNS': '80',
159
 
    # Disable SSH Agent
160
 
    'SSH_AUTH_SOCK': None,
161
 
    # Proxies
162
 
    'http_proxy': None,
163
 
    'HTTP_PROXY': None,
164
 
    'https_proxy': None,
165
 
    'HTTPS_PROXY': None,
166
 
    'no_proxy': None,
167
 
    'NO_PROXY': None,
168
 
    'all_proxy': None,
169
 
    'ALL_PROXY': None,
170
 
    # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
171
 
    # least. If you do (care), please update this comment
172
 
    # -- vila 20080401
173
 
    'ftp_proxy': None,
174
 
    'FTP_PROXY': None,
175
 
    'BZR_REMOTE_PATH': None,
176
 
    # Generally speaking, we don't want apport reporting on crashes in
177
 
    # the test envirnoment unless we're specifically testing apport,
178
 
    # so that it doesn't leak into the real system environment.  We
179
 
    # use an env var so it propagates to subprocesses.
180
 
    'APPORT_DISABLE': '1',
181
 
    }
182
 
 
183
 
 
184
 
def override_os_environ(test, env=None):
185
 
    """Modify os.environ keeping a copy.
186
 
    
187
 
    :param test: A test instance
188
 
 
189
 
    :param env: A dict containing variable definitions to be installed
190
 
    """
191
 
    if env is None:
192
 
        env = isolated_environ
193
 
    test._original_os_environ = dict([(var, value)
194
 
                                      for var, value in os.environ.iteritems()])
195
 
    for var, value in env.iteritems():
196
 
        osutils.set_or_unset_env(var, value)
197
 
        if var not in test._original_os_environ:
198
 
            # The var is new, add it with a value of None, so
199
 
            # restore_os_environ will delete it
200
 
            test._original_os_environ[var] = None
201
 
 
202
 
 
203
 
def restore_os_environ(test):
204
 
    """Restore os.environ to its original state.
205
 
 
206
 
    :param test: A test instance previously passed to override_os_environ.
207
 
    """
208
 
    for var, value in test._original_os_environ.iteritems():
209
 
        # Restore the original value (or delete it if the value has been set to
210
 
        # None in override_os_environ).
211
 
        osutils.set_or_unset_env(var, value)
212
 
 
213
 
 
214
 
class ExtendedTestResult(testtools.TextTestResult):
 
142
 
 
143
class ExtendedTestResult(unittest._TextTestResult):
215
144
    """Accepts, reports and accumulates the results of running tests.
216
145
 
217
146
    Compared to the unittest version this class adds support for
238
167
        :param bench_history: Optionally, a writable file object to accumulate
239
168
            benchmark results.
240
169
        """
241
 
        testtools.TextTestResult.__init__(self, stream)
 
170
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
242
171
        if bench_history is not None:
243
172
            from bzrlib.version import _get_bzr_source_tree
244
173
            src_tree = _get_bzr_source_tree()
265
194
        self.count = 0
266
195
        self._overall_start_time = time.time()
267
196
        self._strict = strict
268
 
        self._first_thread_leaker_id = None
269
 
        self._tests_leaking_threads_count = 0
270
 
        self._traceback_from_test = None
271
197
 
272
198
    def stopTestRun(self):
273
199
        run = self.testsRun
274
200
        actionTaken = "Ran"
275
201
        stopTime = time.time()
276
202
        timeTaken = stopTime - self.startTime
277
 
        # GZ 2010-07-19: Seems testtools has no printErrors method, and though
278
 
        #                the parent class method is similar have to duplicate
279
 
        self._show_list('ERROR', self.errors)
280
 
        self._show_list('FAIL', self.failures)
281
 
        self.stream.write(self.sep2)
282
 
        self.stream.write("%s %d test%s in %.3fs\n\n" % (actionTaken,
 
203
        self.printErrors()
 
204
        self.stream.writeln(self.separator2)
 
205
        self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
283
206
                            run, run != 1 and "s" or "", timeTaken))
 
207
        self.stream.writeln()
284
208
        if not self.wasSuccessful():
285
209
            self.stream.write("FAILED (")
286
210
            failed, errored = map(len, (self.failures, self.errors))
293
217
                if failed or errored: self.stream.write(", ")
294
218
                self.stream.write("known_failure_count=%d" %
295
219
                    self.known_failure_count)
296
 
            self.stream.write(")\n")
 
220
            self.stream.writeln(")")
297
221
        else:
298
222
            if self.known_failure_count:
299
 
                self.stream.write("OK (known_failures=%d)\n" %
 
223
                self.stream.writeln("OK (known_failures=%d)" %
300
224
                    self.known_failure_count)
301
225
            else:
302
 
                self.stream.write("OK\n")
 
226
                self.stream.writeln("OK")
303
227
        if self.skip_count > 0:
304
228
            skipped = self.skip_count
305
 
            self.stream.write('%d test%s skipped\n' %
 
229
            self.stream.writeln('%d test%s skipped' %
306
230
                                (skipped, skipped != 1 and "s" or ""))
307
231
        if self.unsupported:
308
232
            for feature, count in sorted(self.unsupported.items()):
309
 
                self.stream.write("Missing feature '%s' skipped %d tests.\n" %
 
233
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
310
234
                    (feature, count))
311
235
        if self._strict:
312
236
            ok = self.wasStrictlySuccessful()
313
237
        else:
314
238
            ok = self.wasSuccessful()
315
 
        if self._first_thread_leaker_id:
 
239
        if TestCase._first_thread_leaker_id:
316
240
            self.stream.write(
317
241
                '%s is leaking threads among %d leaking tests.\n' % (
318
 
                self._first_thread_leaker_id,
319
 
                self._tests_leaking_threads_count))
 
242
                TestCase._first_thread_leaker_id,
 
243
                TestCase._leaking_threads_tests))
320
244
            # We don't report the main thread as an active one.
321
245
            self.stream.write(
322
246
                '%d non-main threads were left active in the end.\n'
323
 
                % (len(self._active_threads) - 1))
 
247
                % (TestCase._active_threads - 1))
324
248
 
325
249
    def getDescription(self, test):
326
250
        return test.id()
333
257
 
334
258
    def _elapsedTestTimeString(self):
335
259
        """Return a time string for the overall time the current test has taken."""
336
 
        return self._formatTime(self._delta_to_float(
337
 
            self._now() - self._start_datetime))
 
260
        return self._formatTime(time.time() - self._start_time)
338
261
 
339
262
    def _testTimeString(self, testCase):
340
263
        benchmark_time = self._extractBenchmarkTime(testCase)
351
274
 
352
275
    def _shortened_test_description(self, test):
353
276
        what = test.id()
354
 
        what = re.sub(r'^bzrlib\.tests\.', '', what)
 
277
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
355
278
        return what
356
279
 
357
 
    # GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
358
 
    #                multiple times in a row, because the handler is added for
359
 
    #                each test but the container list is shared between cases.
360
 
    #                See lp:498869 lp:625574 and lp:637725 for background.
361
 
    def _record_traceback_from_test(self, exc_info):
362
 
        """Store the traceback from passed exc_info tuple till"""
363
 
        self._traceback_from_test = exc_info[2]
364
 
 
365
280
    def startTest(self, test):
366
 
        super(ExtendedTestResult, self).startTest(test)
 
281
        unittest.TestResult.startTest(self, test)
367
282
        if self.count == 0:
368
283
            self.startTests()
369
 
        self.count += 1
370
284
        self.report_test_start(test)
371
285
        test.number = self.count
372
286
        self._recordTestStartTime()
373
 
        # Make testtools cases give us the real traceback on failure
374
 
        addOnException = getattr(test, "addOnException", None)
375
 
        if addOnException is not None:
376
 
            addOnException(self._record_traceback_from_test)
377
 
        # Only check for thread leaks on bzrlib derived test cases
378
 
        if isinstance(test, TestCase):
379
 
            test.addCleanup(self._check_leaked_threads, test)
380
 
 
381
 
    def stopTest(self, test):
382
 
        super(ExtendedTestResult, self).stopTest(test)
383
 
        # Manually break cycles, means touching various private things but hey
384
 
        getDetails = getattr(test, "getDetails", None)
385
 
        if getDetails is not None:
386
 
            getDetails().clear()
387
 
        # Clear _type_equality_funcs to try to stop TestCase instances
388
 
        # from wasting memory. 'clear' is not available in all Python
389
 
        # versions (bug 809048)
390
 
        type_equality_funcs = getattr(test, "_type_equality_funcs", None)
391
 
        if type_equality_funcs is not None:
392
 
            tef_clear = getattr(type_equality_funcs, "clear", None)
393
 
            if tef_clear is None:
394
 
                tef_instance_dict = getattr(type_equality_funcs, "__dict__", None)
395
 
                if tef_instance_dict is not None:
396
 
                    tef_clear = tef_instance_dict.clear
397
 
            if tef_clear is not None:
398
 
                tef_clear()
399
 
        self._traceback_from_test = None
400
287
 
401
288
    def startTests(self):
402
 
        self.report_tests_starting()
403
 
        self._active_threads = threading.enumerate()
404
 
 
405
 
    def _check_leaked_threads(self, test):
406
 
        """See if any threads have leaked since last call
407
 
 
408
 
        A sample of live threads is stored in the _active_threads attribute,
409
 
        when this method runs it compares the current live threads and any not
410
 
        in the previous sample are treated as having leaked.
411
 
        """
412
 
        now_active_threads = set(threading.enumerate())
413
 
        threads_leaked = now_active_threads.difference(self._active_threads)
414
 
        if threads_leaked:
415
 
            self._report_thread_leak(test, threads_leaked, now_active_threads)
416
 
            self._tests_leaking_threads_count += 1
417
 
            if self._first_thread_leaker_id is None:
418
 
                self._first_thread_leaker_id = test.id()
419
 
            self._active_threads = now_active_threads
 
289
        import platform
 
290
        if getattr(sys, 'frozen', None) is None:
 
291
            bzr_path = osutils.realpath(sys.argv[0])
 
292
        else:
 
293
            bzr_path = sys.executable
 
294
        self.stream.write(
 
295
            'bzr selftest: %s\n' % (bzr_path,))
 
296
        self.stream.write(
 
297
            '   %s\n' % (
 
298
                    bzrlib.__path__[0],))
 
299
        self.stream.write(
 
300
            '   bzr-%s python-%s %s\n' % (
 
301
                    bzrlib.version_string,
 
302
                    bzrlib._format_version_tuple(sys.version_info),
 
303
                    platform.platform(aliased=1),
 
304
                    ))
 
305
        self.stream.write('\n')
420
306
 
421
307
    def _recordTestStartTime(self):
422
308
        """Record that a test has started."""
423
 
        self._start_datetime = self._now()
 
309
        self._start_time = time.time()
 
310
 
 
311
    def _cleanupLogFile(self, test):
 
312
        # We can only do this if we have one of our TestCases, not if
 
313
        # we have a doctest.
 
314
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
315
        if setKeepLogfile is not None:
 
316
            setKeepLogfile()
424
317
 
425
318
    def addError(self, test, err):
426
319
        """Tell result that test finished with an error.
428
321
        Called from the TestCase run() method when the test
429
322
        fails with an unexpected error.
430
323
        """
431
 
        self._post_mortem(self._traceback_from_test)
432
 
        super(ExtendedTestResult, self).addError(test, err)
 
324
        self._post_mortem()
 
325
        unittest.TestResult.addError(self, test, err)
433
326
        self.error_count += 1
434
327
        self.report_error(test, err)
435
328
        if self.stop_early:
436
329
            self.stop()
 
330
        self._cleanupLogFile(test)
437
331
 
438
332
    def addFailure(self, test, err):
439
333
        """Tell result that test failed.
441
335
        Called from the TestCase run() method when the test
442
336
        fails because e.g. an assert() method failed.
443
337
        """
444
 
        self._post_mortem(self._traceback_from_test)
445
 
        super(ExtendedTestResult, self).addFailure(test, err)
 
338
        self._post_mortem()
 
339
        unittest.TestResult.addFailure(self, test, err)
446
340
        self.failure_count += 1
447
341
        self.report_failure(test, err)
448
342
        if self.stop_early:
449
343
            self.stop()
 
344
        self._cleanupLogFile(test)
450
345
 
451
346
    def addSuccess(self, test, details=None):
452
347
        """Tell result that test completed successfully.
460
355
                    self._formatTime(benchmark_time),
461
356
                    test.id()))
462
357
        self.report_success(test)
463
 
        super(ExtendedTestResult, self).addSuccess(test)
 
358
        self._cleanupLogFile(test)
 
359
        unittest.TestResult.addSuccess(self, test)
464
360
        test._log_contents = ''
465
361
 
466
362
    def addExpectedFailure(self, test, err):
467
363
        self.known_failure_count += 1
468
364
        self.report_known_failure(test, err)
469
365
 
470
 
    def addUnexpectedSuccess(self, test, details=None):
471
 
        """Tell result the test unexpectedly passed, counting as a failure
472
 
 
473
 
        When the minimum version of testtools required becomes 0.9.8 this
474
 
        can be updated to use the new handling there.
475
 
        """
476
 
        super(ExtendedTestResult, self).addFailure(test, details=details)
477
 
        self.failure_count += 1
478
 
        self.report_unexpected_success(test,
479
 
            "".join(details["reason"].iter_text()))
480
 
        if self.stop_early:
481
 
            self.stop()
482
 
 
483
366
    def addNotSupported(self, test, feature):
484
367
        """The test will not be run because of a missing feature.
485
368
        """
502
385
        self.not_applicable_count += 1
503
386
        self.report_not_applicable(test, reason)
504
387
 
505
 
    def _post_mortem(self, tb=None):
 
388
    def _post_mortem(self):
506
389
        """Start a PDB post mortem session."""
507
390
        if os.environ.get('BZR_TEST_PDB', None):
508
 
            import pdb
509
 
            pdb.post_mortem(tb)
 
391
            import pdb;pdb.post_mortem()
510
392
 
511
393
    def progress(self, offset, whence):
512
394
        """The test is adjusting the count of tests to run."""
517
399
        else:
518
400
            raise errors.BzrError("Unknown whence %r" % whence)
519
401
 
520
 
    def report_tests_starting(self):
521
 
        """Display information before the test run begins"""
522
 
        if getattr(sys, 'frozen', None) is None:
523
 
            bzr_path = osutils.realpath(sys.argv[0])
524
 
        else:
525
 
            bzr_path = sys.executable
526
 
        self.stream.write(
527
 
            'bzr selftest: %s\n' % (bzr_path,))
528
 
        self.stream.write(
529
 
            '   %s\n' % (
530
 
                    bzrlib.__path__[0],))
531
 
        self.stream.write(
532
 
            '   bzr-%s python-%s %s\n' % (
533
 
                    bzrlib.version_string,
534
 
                    bzrlib._format_version_tuple(sys.version_info),
535
 
                    platform.platform(aliased=1),
536
 
                    ))
537
 
        self.stream.write('\n')
538
 
 
539
 
    def report_test_start(self, test):
540
 
        """Display information on the test just about to be run"""
541
 
 
542
 
    def _report_thread_leak(self, test, leaked_threads, active_threads):
543
 
        """Display information on a test that leaked one or more threads"""
544
 
        # GZ 2010-09-09: A leak summary reported separately from the general
545
 
        #                thread debugging would be nice. Tests under subunit
546
 
        #                need something not using stream, perhaps adding a
547
 
        #                testtools details object would be fitting.
548
 
        if 'threads' in selftest_debug_flags:
549
 
            self.stream.write('%s is leaking, active is now %d\n' %
550
 
                (test.id(), len(active_threads)))
 
402
    def report_cleaning_up(self):
 
403
        pass
551
404
 
552
405
    def startTestRun(self):
553
406
        self.startTime = time.time()
590
443
        self.pb.finished()
591
444
        super(TextTestResult, self).stopTestRun()
592
445
 
593
 
    def report_tests_starting(self):
594
 
        super(TextTestResult, self).report_tests_starting()
 
446
    def startTestRun(self):
 
447
        super(TextTestResult, self).startTestRun()
595
448
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
596
449
 
 
450
    def printErrors(self):
 
451
        # clear the pb to make room for the error listing
 
452
        self.pb.clear()
 
453
        super(TextTestResult, self).printErrors()
 
454
 
597
455
    def _progress_prefix_text(self):
598
456
        # the longer this text, the less space we have to show the test
599
457
        # name...
621
479
        return a
622
480
 
623
481
    def report_test_start(self, test):
 
482
        self.count += 1
624
483
        self.pb.update(
625
484
                self._progress_prefix_text()
626
485
                + ' '
630
489
        return self._shortened_test_description(test)
631
490
 
632
491
    def report_error(self, test, err):
633
 
        self.stream.write('ERROR: %s\n    %s\n' % (
 
492
        self.ui.note('ERROR: %s\n    %s\n' % (
634
493
            self._test_description(test),
635
494
            err[1],
636
495
            ))
637
496
 
638
497
    def report_failure(self, test, err):
639
 
        self.stream.write('FAIL: %s\n    %s\n' % (
 
498
        self.ui.note('FAIL: %s\n    %s\n' % (
640
499
            self._test_description(test),
641
500
            err[1],
642
501
            ))
644
503
    def report_known_failure(self, test, err):
645
504
        pass
646
505
 
647
 
    def report_unexpected_success(self, test, reason):
648
 
        self.stream.write('FAIL: %s\n    %s: %s\n' % (
649
 
            self._test_description(test),
650
 
            "Unexpected success. Should have failed",
651
 
            reason,
652
 
            ))
653
 
 
654
506
    def report_skip(self, test, reason):
655
507
        pass
656
508
 
660
512
    def report_unsupported(self, test, feature):
661
513
        """test cannot be run because feature is missing."""
662
514
 
 
515
    def report_cleaning_up(self):
 
516
        self.pb.update('Cleaning up')
 
517
 
663
518
 
664
519
class VerboseTestResult(ExtendedTestResult):
665
520
    """Produce long output, with one line per test run plus times"""
672
527
            result = a_string
673
528
        return result.ljust(final_width)
674
529
 
675
 
    def report_tests_starting(self):
 
530
    def startTestRun(self):
 
531
        super(VerboseTestResult, self).startTestRun()
676
532
        self.stream.write('running %d tests...\n' % self.num_tests)
677
 
        super(VerboseTestResult, self).report_tests_starting()
678
533
 
679
534
    def report_test_start(self, test):
 
535
        self.count += 1
680
536
        name = self._shortened_test_description(test)
681
537
        width = osutils.terminal_width()
682
538
        if width is not None:
694
550
        return '%s%s' % (indent, err[1])
695
551
 
696
552
    def report_error(self, test, err):
697
 
        self.stream.write('ERROR %s\n%s\n'
 
553
        self.stream.writeln('ERROR %s\n%s'
698
554
                % (self._testTimeString(test),
699
555
                   self._error_summary(err)))
700
556
 
701
557
    def report_failure(self, test, err):
702
 
        self.stream.write(' FAIL %s\n%s\n'
 
558
        self.stream.writeln(' FAIL %s\n%s'
703
559
                % (self._testTimeString(test),
704
560
                   self._error_summary(err)))
705
561
 
706
562
    def report_known_failure(self, test, err):
707
 
        self.stream.write('XFAIL %s\n%s\n'
 
563
        self.stream.writeln('XFAIL %s\n%s'
708
564
                % (self._testTimeString(test),
709
565
                   self._error_summary(err)))
710
566
 
711
 
    def report_unexpected_success(self, test, reason):
712
 
        self.stream.write(' FAIL %s\n%s: %s\n'
713
 
                % (self._testTimeString(test),
714
 
                   "Unexpected success. Should have failed",
715
 
                   reason))
716
 
 
717
567
    def report_success(self, test):
718
 
        self.stream.write('   OK %s\n' % self._testTimeString(test))
 
568
        self.stream.writeln('   OK %s' % self._testTimeString(test))
719
569
        for bench_called, stats in getattr(test, '_benchcalls', []):
720
 
            self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
 
570
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
721
571
            stats.pprint(file=self.stream)
722
572
        # flush the stream so that we get smooth output. This verbose mode is
723
573
        # used to show the output in PQM.
724
574
        self.stream.flush()
725
575
 
726
576
    def report_skip(self, test, reason):
727
 
        self.stream.write(' SKIP %s\n%s\n'
 
577
        self.stream.writeln(' SKIP %s\n%s'
728
578
                % (self._testTimeString(test), reason))
729
579
 
730
580
    def report_not_applicable(self, test, reason):
731
 
        self.stream.write('  N/A %s\n    %s\n'
 
581
        self.stream.writeln('  N/A %s\n    %s'
732
582
                % (self._testTimeString(test), reason))
733
583
 
734
584
    def report_unsupported(self, test, feature):
735
585
        """test cannot be run because feature is missing."""
736
 
        self.stream.write("NODEP %s\n    The feature '%s' is not available.\n"
 
586
        self.stream.writeln("NODEP %s\n    The feature '%s' is not available."
737
587
                %(self._testTimeString(test), feature))
738
588
 
739
589
 
766
616
            encode = codec[0]
767
617
        else:
768
618
            encode = codec.encode
769
 
        # GZ 2010-09-08: Really we don't want to be writing arbitrary bytes,
770
 
        #                so should swap to the plain codecs.StreamWriter
771
 
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream,
772
 
            "backslashreplace")
 
619
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
773
620
        stream.encoding = new_encoding
774
 
        self.stream = stream
 
621
        self.stream = unittest._WritelnDecorator(stream)
775
622
        self.descriptions = descriptions
776
623
        self.verbosity = verbosity
777
624
        self._bench_history = bench_history
901
748
    # XXX: Should probably unify more with CannedInputUIFactory or a
902
749
    # particular configuration of TextUIFactory, or otherwise have a clearer
903
750
    # idea of how they're supposed to be different.
904
 
    # See https://bugs.launchpad.net/bzr/+bug/408213
 
751
    # See https://bugs.edge.launchpad.net/bzr/+bug/408213
905
752
 
906
753
    def __init__(self, stdout=None, stderr=None, stdin=None):
907
754
        if stdin is not None:
925
772
        return NullProgressView()
926
773
 
927
774
 
928
 
def isolated_doctest_setUp(test):
929
 
    override_os_environ(test)
930
 
 
931
 
 
932
 
def isolated_doctest_tearDown(test):
933
 
    restore_os_environ(test)
934
 
 
935
 
 
936
 
def IsolatedDocTestSuite(*args, **kwargs):
937
 
    """Overrides doctest.DocTestSuite to handle isolation.
938
 
 
939
 
    The method is really a factory and users are expected to use it as such.
940
 
    """
941
 
 
942
 
    kwargs['setUp'] = isolated_doctest_setUp
943
 
    kwargs['tearDown'] = isolated_doctest_tearDown
944
 
    return doctest.DocTestSuite(*args, **kwargs)
945
 
 
946
 
 
947
775
class TestCase(testtools.TestCase):
948
776
    """Base class for bzr unit tests.
949
777
 
960
788
    routine, and to build and check bzr trees.
961
789
 
962
790
    In addition to the usual method of overriding tearDown(), this class also
963
 
    allows subclasses to register cleanup functions via addCleanup, which are
 
791
    allows subclasses to register functions into the _cleanups list, which is
964
792
    run in order as the object is torn down.  It's less likely this will be
965
793
    accidentally overlooked.
966
794
    """
967
795
 
968
 
    _log_file = None
 
796
    _active_threads = None
 
797
    _leaking_threads_tests = 0
 
798
    _first_thread_leaker_id = None
 
799
    _log_file_name = None
969
800
    # record lsprof data when performing benchmark calls.
970
801
    _gather_lsprof_in_benchmarks = False
971
802
 
972
803
    def __init__(self, methodName='testMethod'):
973
804
        super(TestCase, self).__init__(methodName)
 
805
        self._cleanups = []
974
806
        self._directory_isolation = True
975
807
        self.exception_handlers.insert(0,
976
808
            (UnavailableFeature, self._do_unsupported_or_skip))
981
813
        super(TestCase, self).setUp()
982
814
        for feature in getattr(self, '_test_needs_features', []):
983
815
            self.requireFeature(feature)
 
816
        self._log_contents = None
 
817
        self.addDetail("log", content.Content(content.ContentType("text",
 
818
            "plain", {"charset": "utf8"}),
 
819
            lambda:[self._get_log(keep_log_file=True)]))
984
820
        self._cleanEnvironment()
985
821
        self._silenceUI()
986
822
        self._startLogFile()
990
826
        self._track_transports()
991
827
        self._track_locks()
992
828
        self._clear_debug_flags()
993
 
        # Isolate global verbosity level, to make sure it's reproducible
994
 
        # between tests.  We should get rid of this altogether: bug 656694. --
995
 
        # mbp 20101008
996
 
        self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
997
 
        # Isolate config option expansion until its default value for bzrlib is
998
 
        # settled on or a the FIXME associated with _get_expand_default_value
999
 
        # is addressed -- vila 20110219
1000
 
        self.overrideAttr(config, '_expand_default_value', None)
1001
 
        self._log_files = set()
1002
 
        # Each key in the ``_counters`` dict holds a value for a different
1003
 
        # counter. When the test ends, addDetail() should be used to output the
1004
 
        # counter values. This happens in install_counter_hook().
1005
 
        self._counters = {}
1006
 
        if 'config_stats' in selftest_debug_flags:
1007
 
            self._install_config_stats_hooks()
 
829
        TestCase._active_threads = threading.activeCount()
 
830
        self.addCleanup(self._check_leaked_threads)
1008
831
 
1009
832
    def debug(self):
1010
833
        # debug a frame up.
1011
834
        import pdb
1012
835
        pdb.Pdb().set_trace(sys._getframe().f_back)
1013
836
 
1014
 
    def discardDetail(self, name):
1015
 
        """Extend the addDetail, getDetails api so we can remove a detail.
1016
 
 
1017
 
        eg. bzr always adds the 'log' detail at startup, but we don't want to
1018
 
        include it for skipped, xfail, etc tests.
1019
 
 
1020
 
        It is safe to call this for a detail that doesn't exist, in case this
1021
 
        gets called multiple times.
1022
 
        """
1023
 
        # We cheat. details is stored in __details which means we shouldn't
1024
 
        # touch it. but getDetails() returns the dict directly, so we can
1025
 
        # mutate it.
1026
 
        details = self.getDetails()
1027
 
        if name in details:
1028
 
            del details[name]
1029
 
 
1030
 
    def install_counter_hook(self, hooks, name, counter_name=None):
1031
 
        """Install a counting hook.
1032
 
 
1033
 
        Any hook can be counted as long as it doesn't need to return a value.
1034
 
 
1035
 
        :param hooks: Where the hook should be installed.
1036
 
 
1037
 
        :param name: The hook name that will be counted.
1038
 
 
1039
 
        :param counter_name: The counter identifier in ``_counters``, defaults
1040
 
            to ``name``.
1041
 
        """
1042
 
        _counters = self._counters # Avoid closing over self
1043
 
        if counter_name is None:
1044
 
            counter_name = name
1045
 
        if _counters.has_key(counter_name):
1046
 
            raise AssertionError('%s is already used as a counter name'
1047
 
                                  % (counter_name,))
1048
 
        _counters[counter_name] = 0
1049
 
        self.addDetail(counter_name, content.Content(content.UTF8_TEXT,
1050
 
            lambda: ['%d' % (_counters[counter_name],)]))
1051
 
        def increment_counter(*args, **kwargs):
1052
 
            _counters[counter_name] += 1
1053
 
        label = 'count %s calls' % (counter_name,)
1054
 
        hooks.install_named_hook(name, increment_counter, label)
1055
 
        self.addCleanup(hooks.uninstall_named_hook, name, label)
1056
 
 
1057
 
    def _install_config_stats_hooks(self):
1058
 
        """Install config hooks to count hook calls.
1059
 
 
1060
 
        """
1061
 
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1062
 
            self.install_counter_hook(config.ConfigHooks, hook_name,
1063
 
                                       'config.%s' % (hook_name,))
1064
 
 
1065
 
        # The OldConfigHooks are private and need special handling to protect
1066
 
        # against recursive tests (tests that run other tests), so we just do
1067
 
        # manually what registering them into _builtin_known_hooks will provide
1068
 
        # us.
1069
 
        self.overrideAttr(config, 'OldConfigHooks', config._OldConfigHooks())
1070
 
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1071
 
            self.install_counter_hook(config.OldConfigHooks, hook_name,
1072
 
                                      'old_config.%s' % (hook_name,))
 
837
    def _check_leaked_threads(self):
 
838
        active = threading.activeCount()
 
839
        leaked_threads = active - TestCase._active_threads
 
840
        TestCase._active_threads = active
 
841
        # If some tests make the number of threads *decrease*, we'll consider
 
842
        # that they are just observing old threads dieing, not agressively kill
 
843
        # random threads. So we don't report these tests as leaking. The risk
 
844
        # is that we have false positives that way (the test see 2 threads
 
845
        # going away but leak one) but it seems less likely than the actual
 
846
        # false positives (the test see threads going away and does not leak).
 
847
        if leaked_threads > 0:
 
848
            TestCase._leaking_threads_tests += 1
 
849
            if TestCase._first_thread_leaker_id is None:
 
850
                TestCase._first_thread_leaker_id = self.id()
1073
851
 
1074
852
    def _clear_debug_flags(self):
1075
853
        """Prevent externally set debug flags affecting tests.
1086
864
 
1087
865
    def _clear_hooks(self):
1088
866
        # prevent hooks affecting tests
1089
 
        known_hooks = hooks.known_hooks
1090
867
        self._preserved_hooks = {}
1091
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1092
 
            current_hooks = getattr(parent, name)
 
868
        for key, factory in hooks.known_hooks.items():
 
869
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
870
            current_hooks = hooks.known_hooks_key_to_object(key)
1093
871
            self._preserved_hooks[parent] = (name, current_hooks)
1094
 
        self._preserved_lazy_hooks = hooks._lazy_hooks
1095
 
        hooks._lazy_hooks = {}
1096
872
        self.addCleanup(self._restoreHooks)
1097
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1098
 
            factory = known_hooks.get(key)
 
873
        for key, factory in hooks.known_hooks.items():
 
874
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
1099
875
            setattr(parent, name, factory())
1100
876
        # this hook should always be installed
1101
877
        request._install_hook()
1130
906
        # break some locks on purpose and should be taken into account by
1131
907
        # considering that breaking a lock is just a dirty way of releasing it.
1132
908
        if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
1133
 
            message = (
1134
 
                'Different number of acquired and '
1135
 
                'released or broken locks.\n'
1136
 
                'acquired=%s\n'
1137
 
                'released=%s\n'
1138
 
                'broken=%s\n' %
1139
 
                (acquired_locks, released_locks, broken_locks))
 
909
            message = ('Different number of acquired and '
 
910
                       'released or broken locks. (%s, %s + %s)' %
 
911
                       (acquired_locks, released_locks, broken_locks))
1140
912
            if not self._lock_check_thorough:
1141
913
                # Rather than fail, just warn
1142
914
                print "Broken test %s: %s" % (self, message)
1170
942
 
1171
943
    def permit_dir(self, name):
1172
944
        """Permit a directory to be used by this test. See permit_url."""
1173
 
        name_transport = _mod_transport.get_transport_from_path(name)
 
945
        name_transport = get_transport(name)
1174
946
        self.permit_url(name)
1175
947
        self.permit_url(name_transport.base)
1176
948
 
1199
971
            try:
1200
972
                workingtree.WorkingTree.open(path)
1201
973
            except (errors.NotBranchError, errors.NoWorkingTree):
1202
 
                raise TestSkipped('Needs a working tree of bzr sources')
 
974
                return
1203
975
        finally:
1204
976
            self.enable_directory_isolation()
1205
977
 
1255
1027
        self.addCleanup(transport_server.stop_server)
1256
1028
        # Obtain a real transport because if the server supplies a password, it
1257
1029
        # will be hidden from the base on the client side.
1258
 
        t = _mod_transport.get_transport_from_url(transport_server.get_url())
 
1030
        t = get_transport(transport_server.get_url())
1259
1031
        # Some transport servers effectively chroot the backing transport;
1260
1032
        # others like SFTPServer don't - users of the transport can walk up the
1261
1033
        # transport to read the entire backing transport. This wouldn't matter
1317
1089
        except UnicodeError, e:
1318
1090
            # If we can't compare without getting a UnicodeError, then
1319
1091
            # obviously they are different
1320
 
            trace.mutter('UnicodeError: %s', e)
 
1092
            mutter('UnicodeError: %s', e)
1321
1093
        if message:
1322
1094
            message += '\n'
1323
1095
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1324
1096
            % (message,
1325
 
               pprint.pformat(a), pprint.pformat(b)))
 
1097
               pformat(a), pformat(b)))
1326
1098
 
1327
1099
    assertEquals = assertEqual
1328
1100
 
1362
1134
                         'st_mtime did not match')
1363
1135
        self.assertEqual(expected.st_ctime, actual.st_ctime,
1364
1136
                         'st_ctime did not match')
1365
 
        if sys.platform == 'win32':
 
1137
        if sys.platform != 'win32':
1366
1138
            # On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1367
1139
            # is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
1368
 
            # odd. We just force it to always be 0 to avoid any problems.
1369
 
            self.assertEqual(0, expected.st_dev)
1370
 
            self.assertEqual(0, actual.st_dev)
1371
 
            self.assertEqual(0, expected.st_ino)
1372
 
            self.assertEqual(0, actual.st_ino)
1373
 
        else:
 
1140
            # odd. Regardless we shouldn't actually try to assert anything
 
1141
            # about their values
1374
1142
            self.assertEqual(expected.st_dev, actual.st_dev,
1375
1143
                             'st_dev did not match')
1376
1144
            self.assertEqual(expected.st_ino, actual.st_ino,
1385
1153
                length, len(obj_with_len), obj_with_len))
1386
1154
 
1387
1155
    def assertLogsError(self, exception_class, func, *args, **kwargs):
1388
 
        """Assert that `func(*args, **kwargs)` quietly logs a specific error.
 
1156
        """Assert that func(*args, **kwargs) quietly logs a specific exception.
1389
1157
        """
 
1158
        from bzrlib import trace
1390
1159
        captured = []
1391
1160
        orig_log_exception_quietly = trace.log_exception_quietly
1392
1161
        try:
1393
1162
            def capture():
1394
1163
                orig_log_exception_quietly()
1395
 
                captured.append(sys.exc_info()[1])
 
1164
                captured.append(sys.exc_info())
1396
1165
            trace.log_exception_quietly = capture
1397
1166
            func(*args, **kwargs)
1398
1167
        finally:
1399
1168
            trace.log_exception_quietly = orig_log_exception_quietly
1400
1169
        self.assertLength(1, captured)
1401
 
        err = captured[0]
 
1170
        err = captured[0][1]
1402
1171
        self.assertIsInstance(err, exception_class)
1403
1172
        return err
1404
1173
 
1441
1210
        if haystack.find(needle) == -1:
1442
1211
            self.fail("string %r not found in '''%s'''" % (needle, haystack))
1443
1212
 
1444
 
    def assertNotContainsString(self, haystack, needle):
1445
 
        if haystack.find(needle) != -1:
1446
 
            self.fail("string %r found in '''%s'''" % (needle, haystack))
1447
 
 
1448
1213
    def assertSubset(self, sublist, superlist):
1449
1214
        """Assert that every entry in sublist is present in superlist."""
1450
1215
        missing = set(sublist) - set(superlist)
1539
1304
 
1540
1305
    def assertFileEqual(self, content, path):
1541
1306
        """Fail if path does not contain 'content'."""
1542
 
        self.assertPathExists(path)
 
1307
        self.failUnlessExists(path)
1543
1308
        f = file(path, 'rb')
1544
1309
        try:
1545
1310
            s = f.read()
1547
1312
            f.close()
1548
1313
        self.assertEqualDiff(content, s)
1549
1314
 
1550
 
    def assertDocstring(self, expected_docstring, obj):
1551
 
        """Fail if obj does not have expected_docstring"""
1552
 
        if __doc__ is None:
1553
 
            # With -OO the docstring should be None instead
1554
 
            self.assertIs(obj.__doc__, None)
1555
 
        else:
1556
 
            self.assertEqual(expected_docstring, obj.__doc__)
1557
 
 
1558
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1559
1315
    def failUnlessExists(self, path):
1560
 
        return self.assertPathExists(path)
1561
 
 
1562
 
    def assertPathExists(self, path):
1563
1316
        """Fail unless path or paths, which may be abs or relative, exist."""
1564
1317
        if not isinstance(path, basestring):
1565
1318
            for p in path:
1566
 
                self.assertPathExists(p)
 
1319
                self.failUnlessExists(p)
1567
1320
        else:
1568
 
            self.assertTrue(osutils.lexists(path),
1569
 
                path + " does not exist")
 
1321
            self.failUnless(osutils.lexists(path),path+" does not exist")
1570
1322
 
1571
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1572
1323
    def failIfExists(self, path):
1573
 
        return self.assertPathDoesNotExist(path)
1574
 
 
1575
 
    def assertPathDoesNotExist(self, path):
1576
1324
        """Fail if path or paths, which may be abs or relative, exist."""
1577
1325
        if not isinstance(path, basestring):
1578
1326
            for p in path:
1579
 
                self.assertPathDoesNotExist(p)
 
1327
                self.failIfExists(p)
1580
1328
        else:
1581
 
            self.assertFalse(osutils.lexists(path),
1582
 
                path + " exists")
 
1329
            self.failIf(osutils.lexists(path),path+" exists")
1583
1330
 
1584
1331
    def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
1585
1332
        """A helper for callDeprecated and applyDeprecated.
1611
1358
        not other callers that go direct to the warning module.
1612
1359
 
1613
1360
        To test that a deprecated method raises an error, do something like
1614
 
        this (remember that both assertRaises and applyDeprecated delays *args
1615
 
        and **kwargs passing)::
 
1361
        this::
1616
1362
 
1617
1363
            self.assertRaises(errors.ReservedId,
1618
1364
                self.applyDeprecated,
1700
1446
 
1701
1447
        The file is removed as the test is torn down.
1702
1448
        """
1703
 
        pseudo_log_file = StringIO()
1704
 
        def _get_log_contents_for_weird_testtools_api():
1705
 
            return [pseudo_log_file.getvalue().decode(
1706
 
                "utf-8", "replace").encode("utf-8")]
1707
 
        self.addDetail("log", content.Content(content.ContentType("text",
1708
 
            "plain", {"charset": "utf8"}),
1709
 
            _get_log_contents_for_weird_testtools_api))
1710
 
        self._log_file = pseudo_log_file
1711
 
        self._log_memento = trace.push_log_file(self._log_file)
 
1449
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
 
1450
        self._log_file = os.fdopen(fileno, 'w+')
 
1451
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
 
1452
        self._log_file_name = name
1712
1453
        self.addCleanup(self._finishLogFile)
1713
1454
 
1714
1455
    def _finishLogFile(self):
1715
1456
        """Finished with the log file.
1716
1457
 
1717
 
        Close the file and delete it.
 
1458
        Close the file and delete it, unless setKeepLogfile was called.
1718
1459
        """
1719
 
        if trace._trace_file:
 
1460
        if bzrlib.trace._trace_file:
1720
1461
            # flush the log file, to get all content
1721
 
            trace._trace_file.flush()
1722
 
        trace.pop_log_file(self._log_memento)
 
1462
            bzrlib.trace._trace_file.flush()
 
1463
        bzrlib.trace.pop_log_file(self._log_memento)
 
1464
        # Cache the log result and delete the file on disk
 
1465
        self._get_log(False)
1723
1466
 
1724
1467
    def thisFailsStrictLockCheck(self):
1725
1468
        """It is known that this test would fail with -Dstrict_locks.
1734
1477
        """
1735
1478
        debug.debug_flags.discard('strict_locks')
1736
1479
 
 
1480
    def addCleanup(self, callable, *args, **kwargs):
 
1481
        """Arrange to run a callable when this case is torn down.
 
1482
 
 
1483
        Callables are run in the reverse of the order they are registered,
 
1484
        ie last-in first-out.
 
1485
        """
 
1486
        self._cleanups.append((callable, args, kwargs))
 
1487
 
1737
1488
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1738
1489
        """Overrides an object attribute restoring it after the test.
1739
1490
 
1740
 
        :note: This should be used with discretion; you should think about
1741
 
        whether it's better to make the code testable without monkey-patching.
1742
 
 
1743
1491
        :param obj: The object that will be mutated.
1744
1492
 
1745
1493
        :param attr_name: The attribute name we want to preserve/override in
1756
1504
            setattr(obj, attr_name, new)
1757
1505
        return value
1758
1506
 
1759
 
    def overrideEnv(self, name, new):
1760
 
        """Set an environment variable, and reset it after the test.
1761
 
 
1762
 
        :param name: The environment variable name.
1763
 
 
1764
 
        :param new: The value to set the variable to. If None, the 
1765
 
            variable is deleted from the environment.
1766
 
 
1767
 
        :returns: The actual variable value.
1768
 
        """
1769
 
        value = osutils.set_or_unset_env(name, new)
1770
 
        self.addCleanup(osutils.set_or_unset_env, name, value)
1771
 
        return value
1772
 
 
1773
 
    def recordCalls(self, obj, attr_name):
1774
 
        """Monkeypatch in a wrapper that will record calls.
1775
 
 
1776
 
        The monkeypatch is automatically removed when the test concludes.
1777
 
 
1778
 
        :param obj: The namespace holding the reference to be replaced;
1779
 
            typically a module, class, or object.
1780
 
        :param attr_name: A string for the name of the attribute to 
1781
 
            patch.
1782
 
        :returns: A list that will be extended with one item every time the
1783
 
            function is called, with a tuple of (args, kwargs).
1784
 
        """
1785
 
        calls = []
1786
 
 
1787
 
        def decorator(*args, **kwargs):
1788
 
            calls.append((args, kwargs))
1789
 
            return orig(*args, **kwargs)
1790
 
        orig = self.overrideAttr(obj, attr_name, decorator)
1791
 
        return calls
1792
 
 
1793
1507
    def _cleanEnvironment(self):
1794
 
        for name, value in isolated_environ.iteritems():
1795
 
            self.overrideEnv(name, value)
 
1508
        new_env = {
 
1509
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
 
1510
            'HOME': os.getcwd(),
 
1511
            # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
 
1512
            # tests do check our impls match APPDATA
 
1513
            'BZR_EDITOR': None, # test_msgeditor manipulates this variable
 
1514
            'VISUAL': None,
 
1515
            'EDITOR': None,
 
1516
            'BZR_EMAIL': None,
 
1517
            'BZREMAIL': None, # may still be present in the environment
 
1518
            'EMAIL': None,
 
1519
            'BZR_PROGRESS_BAR': None,
 
1520
            'BZR_LOG': None,
 
1521
            'BZR_PLUGIN_PATH': None,
 
1522
            'BZR_CONCURRENCY': None,
 
1523
            # Make sure that any text ui tests are consistent regardless of
 
1524
            # the environment the test case is run in; you may want tests that
 
1525
            # test other combinations.  'dumb' is a reasonable guess for tests
 
1526
            # going to a pipe or a StringIO.
 
1527
            'TERM': 'dumb',
 
1528
            'LINES': '25',
 
1529
            'COLUMNS': '80',
 
1530
            'BZR_COLUMNS': '80',
 
1531
            # SSH Agent
 
1532
            'SSH_AUTH_SOCK': None,
 
1533
            # Proxies
 
1534
            'http_proxy': None,
 
1535
            'HTTP_PROXY': None,
 
1536
            'https_proxy': None,
 
1537
            'HTTPS_PROXY': None,
 
1538
            'no_proxy': None,
 
1539
            'NO_PROXY': None,
 
1540
            'all_proxy': None,
 
1541
            'ALL_PROXY': None,
 
1542
            # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
 
1543
            # least. If you do (care), please update this comment
 
1544
            # -- vila 20080401
 
1545
            'ftp_proxy': None,
 
1546
            'FTP_PROXY': None,
 
1547
            'BZR_REMOTE_PATH': None,
 
1548
            # Generally speaking, we don't want apport reporting on crashes in
 
1549
            # the test envirnoment unless we're specifically testing apport,
 
1550
            # so that it doesn't leak into the real system environment.  We
 
1551
            # use an env var so it propagates to subprocesses.
 
1552
            'APPORT_DISABLE': '1',
 
1553
        }
 
1554
        self._old_env = {}
 
1555
        self.addCleanup(self._restoreEnvironment)
 
1556
        for name, value in new_env.iteritems():
 
1557
            self._captureVar(name, value)
 
1558
 
 
1559
    def _captureVar(self, name, newvalue):
 
1560
        """Set an environment variable, and reset it when finished."""
 
1561
        self._old_env[name] = osutils.set_or_unset_env(name, newvalue)
 
1562
 
 
1563
    def _restoreEnvironment(self):
 
1564
        for name, value in self._old_env.iteritems():
 
1565
            osutils.set_or_unset_env(name, value)
1796
1566
 
1797
1567
    def _restoreHooks(self):
1798
1568
        for klass, (name, hooks) in self._preserved_hooks.items():
1799
1569
            setattr(klass, name, hooks)
1800
 
        self._preserved_hooks.clear()
1801
 
        bzrlib.hooks._lazy_hooks = self._preserved_lazy_hooks
1802
 
        self._preserved_lazy_hooks.clear()
1803
1570
 
1804
1571
    def knownFailure(self, reason):
1805
 
        """Declare that this test fails for a known reason
1806
 
 
1807
 
        Tests that are known to fail should generally be using expectedFailure
1808
 
        with an appropriate reverse assertion if a change could cause the test
1809
 
        to start passing. Conversely if the test has no immediate prospect of
1810
 
        succeeding then using skip is more suitable.
1811
 
 
1812
 
        When this method is called while an exception is being handled, that
1813
 
        traceback will be used, otherwise a new exception will be thrown to
1814
 
        provide one but won't be reported.
1815
 
        """
1816
 
        self._add_reason(reason)
1817
 
        try:
1818
 
            exc_info = sys.exc_info()
1819
 
            if exc_info != (None, None, None):
1820
 
                self._report_traceback(exc_info)
1821
 
            else:
1822
 
                try:
1823
 
                    raise self.failureException(reason)
1824
 
                except self.failureException:
1825
 
                    exc_info = sys.exc_info()
1826
 
            # GZ 02-08-2011: Maybe cleanup this err.exc_info attribute too?
1827
 
            raise testtools.testcase._ExpectedFailure(exc_info)
1828
 
        finally:
1829
 
            del exc_info
1830
 
 
1831
 
    def _suppress_log(self):
1832
 
        """Remove the log info from details."""
1833
 
        self.discardDetail('log')
 
1572
        """This test has failed for some known reason."""
 
1573
        raise KnownFailure(reason)
1834
1574
 
1835
1575
    def _do_skip(self, result, reason):
1836
 
        self._suppress_log()
1837
1576
        addSkip = getattr(result, 'addSkip', None)
1838
1577
        if not callable(addSkip):
1839
1578
            result.addSuccess(result)
1842
1581
 
1843
1582
    @staticmethod
1844
1583
    def _do_known_failure(self, result, e):
1845
 
        self._suppress_log()
1846
1584
        err = sys.exc_info()
1847
1585
        addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1848
1586
        if addExpectedFailure is not None:
1856
1594
            reason = 'No reason given'
1857
1595
        else:
1858
1596
            reason = e.args[0]
1859
 
        self._suppress_log ()
1860
1597
        addNotApplicable = getattr(result, 'addNotApplicable', None)
1861
1598
        if addNotApplicable is not None:
1862
1599
            result.addNotApplicable(self, reason)
1864
1601
            self._do_skip(result, reason)
1865
1602
 
1866
1603
    @staticmethod
1867
 
    def _report_skip(self, result, err):
1868
 
        """Override the default _report_skip.
1869
 
 
1870
 
        We want to strip the 'log' detail. If we waint until _do_skip, it has
1871
 
        already been formatted into the 'reason' string, and we can't pull it
1872
 
        out again.
1873
 
        """
1874
 
        self._suppress_log()
1875
 
        super(TestCase, self)._report_skip(self, result, err)
1876
 
 
1877
 
    @staticmethod
1878
 
    def _report_expected_failure(self, result, err):
1879
 
        """Strip the log.
1880
 
 
1881
 
        See _report_skip for motivation.
1882
 
        """
1883
 
        self._suppress_log()
1884
 
        super(TestCase, self)._report_expected_failure(self, result, err)
1885
 
 
1886
 
    @staticmethod
1887
1604
    def _do_unsupported_or_skip(self, result, e):
1888
1605
        reason = e.args[0]
1889
 
        self._suppress_log()
1890
1606
        addNotSupported = getattr(result, 'addNotSupported', None)
1891
1607
        if addNotSupported is not None:
1892
1608
            result.addNotSupported(self, reason)
1918
1634
            self._benchtime += time.time() - start
1919
1635
 
1920
1636
    def log(self, *args):
1921
 
        trace.mutter(*args)
 
1637
        mutter(*args)
 
1638
 
 
1639
    def _get_log(self, keep_log_file=False):
 
1640
        """Internal helper to get the log from bzrlib.trace for this test.
 
1641
 
 
1642
        Please use self.getDetails, or self.get_log to access this in test case
 
1643
        code.
 
1644
 
 
1645
        :param keep_log_file: When True, if the log is still a file on disk
 
1646
            leave it as a file on disk. When False, if the log is still a file
 
1647
            on disk, the log file is deleted and the log preserved as
 
1648
            self._log_contents.
 
1649
        :return: A string containing the log.
 
1650
        """
 
1651
        if self._log_contents is not None:
 
1652
            try:
 
1653
                self._log_contents.decode('utf8')
 
1654
            except UnicodeDecodeError:
 
1655
                unicodestr = self._log_contents.decode('utf8', 'replace')
 
1656
                self._log_contents = unicodestr.encode('utf8')
 
1657
            return self._log_contents
 
1658
        import bzrlib.trace
 
1659
        if bzrlib.trace._trace_file:
 
1660
            # flush the log file, to get all content
 
1661
            bzrlib.trace._trace_file.flush()
 
1662
        if self._log_file_name is not None:
 
1663
            logfile = open(self._log_file_name)
 
1664
            try:
 
1665
                log_contents = logfile.read()
 
1666
            finally:
 
1667
                logfile.close()
 
1668
            try:
 
1669
                log_contents.decode('utf8')
 
1670
            except UnicodeDecodeError:
 
1671
                unicodestr = log_contents.decode('utf8', 'replace')
 
1672
                log_contents = unicodestr.encode('utf8')
 
1673
            if not keep_log_file:
 
1674
                self._log_file.close()
 
1675
                self._log_file = None
 
1676
                # Permit multiple calls to get_log until we clean it up in
 
1677
                # finishLogFile
 
1678
                self._log_contents = log_contents
 
1679
                try:
 
1680
                    os.remove(self._log_file_name)
 
1681
                except OSError, e:
 
1682
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
 
1683
                        sys.stderr.write(('Unable to delete log file '
 
1684
                                             ' %r\n' % self._log_file_name))
 
1685
                    else:
 
1686
                        raise
 
1687
                self._log_file_name = None
 
1688
            return log_contents
 
1689
        else:
 
1690
            return "No log file content and no log file name."
1922
1691
 
1923
1692
    def get_log(self):
1924
1693
        """Get a unicode string containing the log from bzrlib.trace.
1974
1743
 
1975
1744
        try:
1976
1745
            try:
1977
 
                result = self.apply_redirected(
1978
 
                    ui.ui_factory.stdin,
 
1746
                result = self.apply_redirected(ui.ui_factory.stdin,
1979
1747
                    stdout, stderr,
1980
 
                    _mod_commands.run_bzr_catch_user_errors,
 
1748
                    bzrlib.commands.run_bzr_catch_user_errors,
1981
1749
                    args)
1982
1750
            except KeyboardInterrupt:
1983
1751
                # Reraise KeyboardInterrupt with contents of redirected stdout
2125
1893
    def start_bzr_subprocess(self, process_args, env_changes=None,
2126
1894
                             skip_if_plan_to_signal=False,
2127
1895
                             working_dir=None,
2128
 
                             allow_plugins=False, stderr=subprocess.PIPE):
 
1896
                             allow_plugins=False):
2129
1897
        """Start bzr in a subprocess for testing.
2130
1898
 
2131
1899
        This starts a new Python interpreter and runs bzr in there.
2140
1908
            variables. A value of None will unset the env variable.
2141
1909
            The values must be strings. The change will only occur in the
2142
1910
            child, so you don't need to fix the environment after running.
2143
 
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
2144
 
            doesn't support signalling subprocesses.
 
1911
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
 
1912
            is not available.
2145
1913
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
2146
 
        :param stderr: file to use for the subprocess's stderr.  Valid values
2147
 
            are those valid for the stderr argument of `subprocess.Popen`.
2148
 
            Default value is ``subprocess.PIPE``.
2149
1914
 
2150
1915
        :returns: Popen object for the started process.
2151
1916
        """
2152
1917
        if skip_if_plan_to_signal:
2153
 
            if os.name != "posix":
2154
 
                raise TestSkipped("Sending signals not supported")
 
1918
            if not getattr(os, 'kill', None):
 
1919
                raise TestSkipped("os.kill not available.")
2155
1920
 
2156
1921
        if env_changes is None:
2157
1922
            env_changes = {}
2177
1942
            # so we will avoid using it on all platforms, just to
2178
1943
            # make sure the code path is used, and we don't break on win32
2179
1944
            cleanup_environment()
2180
 
            # Include the subprocess's log file in the test details, in case
2181
 
            # the test fails due to an error in the subprocess.
2182
 
            self._add_subprocess_log(trace._get_bzr_log_filename())
2183
1945
            command = [sys.executable]
2184
1946
            # frozen executables don't need the path to bzr
2185
1947
            if getattr(sys, "frozen", None) is None:
2187
1949
            if not allow_plugins:
2188
1950
                command.append('--no-plugins')
2189
1951
            command.extend(process_args)
2190
 
            process = self._popen(command, stdin=subprocess.PIPE,
2191
 
                                  stdout=subprocess.PIPE,
2192
 
                                  stderr=stderr)
 
1952
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
2193
1953
        finally:
2194
1954
            restore_environment()
2195
1955
            if cwd is not None:
2197
1957
 
2198
1958
        return process
2199
1959
 
2200
 
    def _add_subprocess_log(self, log_file_path):
2201
 
        if len(self._log_files) == 0:
2202
 
            # Register an addCleanup func.  We do this on the first call to
2203
 
            # _add_subprocess_log rather than in TestCase.setUp so that this
2204
 
            # addCleanup is registered after any cleanups for tempdirs that
2205
 
            # subclasses might create, which will probably remove the log file
2206
 
            # we want to read.
2207
 
            self.addCleanup(self._subprocess_log_cleanup)
2208
 
        # self._log_files is a set, so if a log file is reused we won't grab it
2209
 
        # twice.
2210
 
        self._log_files.add(log_file_path)
2211
 
 
2212
 
    def _subprocess_log_cleanup(self):
2213
 
        for count, log_file_path in enumerate(self._log_files):
2214
 
            # We use buffer_now=True to avoid holding the file open beyond
2215
 
            # the life of this function, which might interfere with e.g.
2216
 
            # cleaning tempdirs on Windows.
2217
 
            # XXX: Testtools 0.9.5 doesn't have the content_from_file helper
2218
 
            #detail_content = content.content_from_file(
2219
 
            #    log_file_path, buffer_now=True)
2220
 
            with open(log_file_path, 'rb') as log_file:
2221
 
                log_file_bytes = log_file.read()
2222
 
            detail_content = content.Content(content.ContentType("text",
2223
 
                "plain", {"charset": "utf8"}), lambda: [log_file_bytes])
2224
 
            self.addDetail("start_bzr_subprocess-log-%d" % (count,),
2225
 
                detail_content)
2226
 
 
2227
1960
    def _popen(self, *args, **kwargs):
2228
1961
        """Place a call to Popen.
2229
1962
 
2230
1963
        Allows tests to override this method to intercept the calls made to
2231
1964
        Popen for introspection.
2232
1965
        """
2233
 
        return subprocess.Popen(*args, **kwargs)
 
1966
        return Popen(*args, **kwargs)
2234
1967
 
2235
1968
    def get_source_path(self):
2236
1969
        """Return the path of the directory containing bzrlib."""
2238
1971
 
2239
1972
    def get_bzr_path(self):
2240
1973
        """Return the path of the 'bzr' executable for this test suite."""
2241
 
        bzr_path = os.path.join(self.get_source_path(), "bzr")
 
1974
        bzr_path = self.get_source_path()+'/bzr'
2242
1975
        if not os.path.isfile(bzr_path):
2243
1976
            # We are probably installed. Assume sys.argv is the right file
2244
1977
            bzr_path = sys.argv[0]
2266
1999
        if retcode is not None and retcode != process.returncode:
2267
2000
            if process_args is None:
2268
2001
                process_args = "(unknown args)"
2269
 
            trace.mutter('Output of bzr %s:\n%s', process_args, out)
2270
 
            trace.mutter('Error for bzr %s:\n%s', process_args, err)
 
2002
            mutter('Output of bzr %s:\n%s', process_args, out)
 
2003
            mutter('Error for bzr %s:\n%s', process_args, err)
2271
2004
            self.fail('Command bzr %s failed with retcode %s != %s'
2272
2005
                      % (process_args, retcode, process.returncode))
2273
2006
        return [out, err]
2274
2007
 
2275
 
    def check_tree_shape(self, tree, shape):
2276
 
        """Compare a tree to a list of expected names.
 
2008
    def check_inventory_shape(self, inv, shape):
 
2009
        """Compare an inventory to a list of expected names.
2277
2010
 
2278
2011
        Fail if they are not precisely equal.
2279
2012
        """
2280
2013
        extras = []
2281
2014
        shape = list(shape)             # copy
2282
 
        for path, ie in tree.iter_entries_by_dir():
 
2015
        for path, ie in inv.entries():
2283
2016
            name = path.replace('\\', '/')
2284
2017
            if ie.kind == 'directory':
2285
2018
                name = name + '/'
2286
 
            if name == "/":
2287
 
                pass # ignore root entry
2288
 
            elif name in shape:
 
2019
            if name in shape:
2289
2020
                shape.remove(name)
2290
2021
            else:
2291
2022
                extras.append(name)
2332
2063
 
2333
2064
        Tests that expect to provoke LockContention errors should call this.
2334
2065
        """
2335
 
        self.overrideAttr(lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
 
2066
        self.overrideAttr(bzrlib.lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
2336
2067
 
2337
2068
    def make_utf8_encoded_stringio(self, encoding_type=None):
2338
2069
        """Return a StringIOWrapper instance, that will encode Unicode
2381
2112
class TestCaseWithMemoryTransport(TestCase):
2382
2113
    """Common test class for tests that do not need disk resources.
2383
2114
 
2384
 
    Tests that need disk resources should derive from TestCaseInTempDir
2385
 
    orTestCaseWithTransport.
 
2115
    Tests that need disk resources should derive from TestCaseWithTransport.
2386
2116
 
2387
2117
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2388
2118
 
2389
 
    For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
 
2119
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
2390
2120
    a directory which does not exist. This serves to help ensure test isolation
2391
 
    is preserved. ``test_dir`` is set to the TEST_ROOT, as is cwd, because they
2392
 
    must exist. However, TestCaseWithMemoryTransport does not offer local file
2393
 
    defaults for the transport in tests, nor does it obey the command line
 
2121
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
 
2122
    must exist. However, TestCaseWithMemoryTransport does not offer local
 
2123
    file defaults for the transport in tests, nor does it obey the command line
2394
2124
    override, so tests that accidentally write to the common directory should
2395
2125
    be rare.
2396
2126
 
2397
 
    :cvar TEST_ROOT: Directory containing all temporary directories, plus a
2398
 
        ``.bzr`` directory that stops us ascending higher into the filesystem.
 
2127
    :cvar TEST_ROOT: Directory containing all temporary directories, plus
 
2128
    a .bzr directory that stops us ascending higher into the filesystem.
2399
2129
    """
2400
2130
 
2401
2131
    TEST_ROOT = None
2419
2149
 
2420
2150
        :param relpath: a path relative to the base url.
2421
2151
        """
2422
 
        t = _mod_transport.get_transport_from_url(self.get_url(relpath))
 
2152
        t = get_transport(self.get_url(relpath))
2423
2153
        self.assertFalse(t.is_readonly())
2424
2154
        return t
2425
2155
 
2431
2161
 
2432
2162
        :param relpath: a path relative to the base url.
2433
2163
        """
2434
 
        t = _mod_transport.get_transport(self.get_readonly_url(relpath))
 
2164
        t = get_transport(self.get_readonly_url(relpath))
2435
2165
        self.assertTrue(t.is_readonly())
2436
2166
        return t
2437
2167
 
2558
2288
        real branch.
2559
2289
        """
2560
2290
        root = TestCaseWithMemoryTransport.TEST_ROOT
2561
 
        wt = bzrdir.BzrDir.create_standalone_workingtree(root)
2562
 
        # Hack for speed: remember the raw bytes of the dirstate file so that
2563
 
        # we don't need to re-open the wt to check it hasn't changed.
2564
 
        TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE = (
2565
 
            wt.control_transport.get_bytes('dirstate'))
 
2291
        bzrdir.BzrDir.create_standalone_workingtree(root)
2566
2292
 
2567
2293
    def _check_safety_net(self):
2568
2294
        """Check that the safety .bzr directory have not been touched.
2571
2297
        propagating. This method ensures than a test did not leaked.
2572
2298
        """
2573
2299
        root = TestCaseWithMemoryTransport.TEST_ROOT
2574
 
        t = _mod_transport.get_transport(root)
2575
 
        self.permit_url(t.base)
2576
 
        if (t.get_bytes('.bzr/checkout/dirstate') != 
2577
 
                TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE):
 
2300
        self.permit_url(get_transport(root).base)
 
2301
        wt = workingtree.WorkingTree.open(root)
 
2302
        last_rev = wt.last_revision()
 
2303
        if last_rev != 'null:':
2578
2304
            # The current test have modified the /bzr directory, we need to
2579
2305
            # recreate a new one or all the followng tests will fail.
2580
2306
            # If you need to inspect its content uncomment the following line
2622
2348
            # might be a relative or absolute path
2623
2349
            maybe_a_url = self.get_url(relpath)
2624
2350
            segments = maybe_a_url.rsplit('/', 1)
2625
 
            t = _mod_transport.get_transport(maybe_a_url)
 
2351
            t = get_transport(maybe_a_url)
2626
2352
            if len(segments) > 1 and segments[-1] not in ('', '.'):
2627
2353
                t.ensure_base()
2628
2354
            if format is None:
2645
2371
        made_control = self.make_bzrdir(relpath, format=format)
2646
2372
        return made_control.create_repository(shared=shared)
2647
2373
 
2648
 
    def make_smart_server(self, path, backing_server=None):
2649
 
        if backing_server is None:
2650
 
            backing_server = self.get_server()
 
2374
    def make_smart_server(self, path):
2651
2375
        smart_server = test_server.SmartTCPServer_for_testing()
2652
 
        self.start_server(smart_server, backing_server)
2653
 
        remote_transport = _mod_transport.get_transport_from_url(smart_server.get_url()
2654
 
                                                   ).clone(path)
 
2376
        self.start_server(smart_server, self.get_server())
 
2377
        remote_transport = get_transport(smart_server.get_url()).clone(path)
2655
2378
        return remote_transport
2656
2379
 
2657
2380
    def make_branch_and_memory_tree(self, relpath, format=None):
2667
2390
        test_home_dir = self.test_home_dir
2668
2391
        if isinstance(test_home_dir, unicode):
2669
2392
            test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
2670
 
        self.overrideEnv('HOME', test_home_dir)
2671
 
        self.overrideEnv('BZR_HOME', test_home_dir)
 
2393
        os.environ['HOME'] = test_home_dir
 
2394
        os.environ['BZR_HOME'] = test_home_dir
2672
2395
 
2673
2396
    def setUp(self):
2674
2397
        super(TestCaseWithMemoryTransport, self).setUp()
2675
 
        # Ensure that ConnectedTransport doesn't leak sockets
2676
 
        def get_transport_from_url_with_cleanup(*args, **kwargs):
2677
 
            t = orig_get_transport_from_url(*args, **kwargs)
2678
 
            if isinstance(t, _mod_transport.ConnectedTransport):
2679
 
                self.addCleanup(t.disconnect)
2680
 
            return t
2681
 
 
2682
 
        orig_get_transport_from_url = self.overrideAttr(
2683
 
            _mod_transport, 'get_transport_from_url',
2684
 
            get_transport_from_url_with_cleanup)
2685
2398
        self._make_test_root()
2686
2399
        self.addCleanup(os.chdir, os.getcwdu())
2687
2400
        self.makeAndChdirToTestDir()
2730
2443
 
2731
2444
    OVERRIDE_PYTHON = 'python'
2732
2445
 
2733
 
    def setUp(self):
2734
 
        super(TestCaseInTempDir, self).setUp()
2735
 
        # Remove the protection set in isolated_environ, we have a proper
2736
 
        # access to disk resources now.
2737
 
        self.overrideEnv('BZR_LOG', None)
2738
 
 
2739
2446
    def check_file_contents(self, filename, expect):
2740
2447
        self.log("check contents of file %s" % filename)
2741
 
        f = file(filename)
2742
 
        try:
2743
 
            contents = f.read()
2744
 
        finally:
2745
 
            f.close()
 
2448
        contents = file(filename, 'r').read()
2746
2449
        if contents != expect:
2747
2450
            self.log("expected: %r" % expect)
2748
2451
            self.log("actually: %r" % contents)
2822
2525
                "a list or a tuple. Got %r instead" % (shape,))
2823
2526
        # It's OK to just create them using forward slashes on windows.
2824
2527
        if transport is None or transport.is_readonly():
2825
 
            transport = _mod_transport.get_transport(".")
 
2528
            transport = get_transport(".")
2826
2529
        for name in shape:
2827
2530
            self.assertIsInstance(name, basestring)
2828
2531
            if name[-1] == '/':
2838
2541
                content = "contents of %s%s" % (name.encode('utf-8'), end)
2839
2542
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
2840
2543
 
2841
 
    build_tree_contents = staticmethod(treeshape.build_tree_contents)
 
2544
    def build_tree_contents(self, shape):
 
2545
        build_tree_contents(shape)
2842
2546
 
2843
2547
    def assertInWorkingTree(self, path, root_path='.', tree=None):
2844
2548
        """Assert whether path or paths are in the WorkingTree"""
2985
2689
    """
2986
2690
 
2987
2691
    def setUp(self):
2988
 
        from bzrlib.tests import http_server
2989
2692
        super(ChrootedTestCase, self).setUp()
2990
2693
        if not self.vfs_transport_factory == memory.MemoryServer:
2991
 
            self.transport_readonly_server = http_server.HttpServer
 
2694
            self.transport_readonly_server = HttpServer
2992
2695
 
2993
2696
 
2994
2697
def condition_id_re(pattern):
2997
2700
    :param pattern: A regular expression string.
2998
2701
    :return: A callable that returns True if the re matches.
2999
2702
    """
3000
 
    filter_re = re.compile(pattern, 0)
 
2703
    filter_re = osutils.re_compile_checked(pattern, 0,
 
2704
        'test filter')
3001
2705
    def condition(test):
3002
2706
        test_id = test.id()
3003
2707
        return filter_re.search(test_id)
3255
2959
 
3256
2960
 
3257
2961
def fork_decorator(suite):
3258
 
    if getattr(os, "fork", None) is None:
3259
 
        raise errors.BzrCommandError("platform does not support fork,"
3260
 
            " try --parallel=subprocess instead.")
3261
2962
    concurrency = osutils.local_concurrency()
3262
2963
    if concurrency == 1:
3263
2964
        return suite
3318
3019
    return suite
3319
3020
 
3320
3021
 
3321
 
class TestDecorator(TestUtil.TestSuite):
 
3022
class TestDecorator(TestSuite):
3322
3023
    """A decorator for TestCase/TestSuite objects.
3323
3024
    
3324
3025
    Usually, subclasses should override __iter__(used when flattening test
3327
3028
    """
3328
3029
 
3329
3030
    def __init__(self, suite):
3330
 
        TestUtil.TestSuite.__init__(self)
 
3031
        TestSuite.__init__(self)
3331
3032
        self.addTest(suite)
3332
3033
 
3333
3034
    def countTestCases(self):
3452
3153
 
3453
3154
def partition_tests(suite, count):
3454
3155
    """Partition suite into count lists of tests."""
3455
 
    # This just assigns tests in a round-robin fashion.  On one hand this
3456
 
    # splits up blocks of related tests that might run faster if they shared
3457
 
    # resources, but on the other it avoids assigning blocks of slow tests to
3458
 
    # just one partition.  So the slowest partition shouldn't be much slower
3459
 
    # than the fastest.
3460
 
    partitions = [list() for i in range(count)]
3461
 
    tests = iter_suite_tests(suite)
3462
 
    for partition, test in itertools.izip(itertools.cycle(partitions), tests):
3463
 
        partition.append(test)
3464
 
    return partitions
3465
 
 
3466
 
 
3467
 
def workaround_zealous_crypto_random():
3468
 
    """Crypto.Random want to help us being secure, but we don't care here.
3469
 
 
3470
 
    This workaround some test failure related to the sftp server. Once paramiko
3471
 
    stop using the controversial API in Crypto.Random, we may get rid of it.
3472
 
    """
3473
 
    try:
3474
 
        from Crypto.Random import atfork
3475
 
        atfork()
3476
 
    except ImportError:
3477
 
        pass
 
3156
    result = []
 
3157
    tests = list(iter_suite_tests(suite))
 
3158
    tests_per_process = int(math.ceil(float(len(tests)) / count))
 
3159
    for block in range(count):
 
3160
        low_test = block * tests_per_process
 
3161
        high_test = low_test + tests_per_process
 
3162
        process_tests = tests[low_test:high_test]
 
3163
        result.append(process_tests)
 
3164
    return result
3478
3165
 
3479
3166
 
3480
3167
def fork_for_tests(suite):
3497
3184
            try:
3498
3185
                ProtocolTestCase.run(self, result)
3499
3186
            finally:
3500
 
                os.waitpid(self.pid, 0)
 
3187
                os.waitpid(self.pid, os.WNOHANG)
3501
3188
 
3502
3189
    test_blocks = partition_tests(suite, concurrency)
3503
3190
    for process_tests in test_blocks:
3504
 
        process_suite = TestUtil.TestSuite()
 
3191
        process_suite = TestSuite()
3505
3192
        process_suite.addTests(process_tests)
3506
3193
        c2pread, c2pwrite = os.pipe()
3507
3194
        pid = os.fork()
3508
3195
        if pid == 0:
3509
 
            workaround_zealous_crypto_random()
3510
3196
            try:
3511
3197
                os.close(c2pread)
3512
3198
                # Leave stderr and stdout open so we can see test noise
3573
3259
                '--subunit']
3574
3260
            if '--no-plugins' in sys.argv:
3575
3261
                argv.append('--no-plugins')
3576
 
            # stderr=subprocess.STDOUT would be ideal, but until we prevent
3577
 
            # noise on stderr it can interrupt the subunit protocol.
3578
 
            process = subprocess.Popen(argv, stdin=subprocess.PIPE,
3579
 
                                      stdout=subprocess.PIPE,
3580
 
                                      stderr=subprocess.PIPE,
3581
 
                                      bufsize=1)
 
3262
            # stderr=STDOUT would be ideal, but until we prevent noise on
 
3263
            # stderr it can interrupt the subunit protocol.
 
3264
            process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
 
3265
                bufsize=1)
3582
3266
            test = TestInSubprocess(process, test_list_file_name)
3583
3267
            result.append(test)
3584
3268
        except:
3587
3271
    return result
3588
3272
 
3589
3273
 
3590
 
class ProfileResult(testtools.ExtendedToOriginalDecorator):
 
3274
class ForwardingResult(unittest.TestResult):
 
3275
 
 
3276
    def __init__(self, target):
 
3277
        unittest.TestResult.__init__(self)
 
3278
        self.result = target
 
3279
 
 
3280
    def startTest(self, test):
 
3281
        self.result.startTest(test)
 
3282
 
 
3283
    def stopTest(self, test):
 
3284
        self.result.stopTest(test)
 
3285
 
 
3286
    def startTestRun(self):
 
3287
        self.result.startTestRun()
 
3288
 
 
3289
    def stopTestRun(self):
 
3290
        self.result.stopTestRun()
 
3291
 
 
3292
    def addSkip(self, test, reason):
 
3293
        self.result.addSkip(test, reason)
 
3294
 
 
3295
    def addSuccess(self, test):
 
3296
        self.result.addSuccess(test)
 
3297
 
 
3298
    def addError(self, test, err):
 
3299
        self.result.addError(test, err)
 
3300
 
 
3301
    def addFailure(self, test, err):
 
3302
        self.result.addFailure(test, err)
 
3303
ForwardingResult = testtools.ExtendedToOriginalDecorator
 
3304
 
 
3305
 
 
3306
class ProfileResult(ForwardingResult):
3591
3307
    """Generate profiling data for all activity between start and success.
3592
3308
    
3593
3309
    The profile data is appended to the test's _benchcalls attribute and can
3601
3317
 
3602
3318
    def startTest(self, test):
3603
3319
        self.profiler = bzrlib.lsprof.BzrProfiler()
3604
 
        # Prevent deadlocks in tests that use lsprof: those tests will
3605
 
        # unavoidably fail.
3606
 
        bzrlib.lsprof.BzrProfiler.profiler_block = 0
3607
3320
        self.profiler.start()
3608
 
        testtools.ExtendedToOriginalDecorator.startTest(self, test)
 
3321
        ForwardingResult.startTest(self, test)
3609
3322
 
3610
3323
    def addSuccess(self, test):
3611
3324
        stats = self.profiler.stop()
3615
3328
            test._benchcalls = []
3616
3329
            calls = test._benchcalls
3617
3330
        calls.append(((test.id(), "", ""), stats))
3618
 
        testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
 
3331
        ForwardingResult.addSuccess(self, test)
3619
3332
 
3620
3333
    def stopTest(self, test):
3621
 
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
 
3334
        ForwardingResult.stopTest(self, test)
3622
3335
        self.profiler = None
3623
3336
 
3624
3337
 
3630
3343
#                           rather than failing tests. And no longer raise
3631
3344
#                           LockContention when fctnl locks are not being used
3632
3345
#                           with proper exclusion rules.
3633
 
#   -Ethreads               Will display thread ident at creation/join time to
3634
 
#                           help track thread leaks
3635
 
 
3636
 
#   -Econfig_stats          Will collect statistics using addDetail
3637
3346
selftest_debug_flags = set()
3638
3347
 
3639
3348
 
3833
3542
                key, obj, help=help, info=info, override_existing=False)
3834
3543
        except KeyError:
3835
3544
            actual = self.get(key)
3836
 
            trace.note(
3837
 
                'Test prefix alias %s is already used for %s, ignoring %s'
3838
 
                % (key, actual, obj))
 
3545
            note('Test prefix alias %s is already used for %s, ignoring %s'
 
3546
                 % (key, actual, obj))
3839
3547
 
3840
3548
    def resolve_alias(self, id_start):
3841
3549
        """Replace the alias by the prefix in the given string.
3873
3581
        'bzrlib.doc',
3874
3582
        'bzrlib.tests.blackbox',
3875
3583
        'bzrlib.tests.commands',
3876
 
        'bzrlib.tests.doc_generate',
3877
3584
        'bzrlib.tests.per_branch',
3878
3585
        'bzrlib.tests.per_bzrdir',
3879
 
        'bzrlib.tests.per_controldir',
3880
 
        'bzrlib.tests.per_controldir_colo',
3881
3586
        'bzrlib.tests.per_foreign_vcs',
3882
3587
        'bzrlib.tests.per_interrepository',
3883
3588
        'bzrlib.tests.per_intertree',
3891
3596
        'bzrlib.tests.per_repository',
3892
3597
        'bzrlib.tests.per_repository_chk',
3893
3598
        'bzrlib.tests.per_repository_reference',
3894
 
        'bzrlib.tests.per_repository_vf',
3895
3599
        'bzrlib.tests.per_uifactory',
3896
3600
        'bzrlib.tests.per_versionedfile',
3897
3601
        'bzrlib.tests.per_workingtree',
3898
3602
        'bzrlib.tests.test__annotator',
3899
3603
        'bzrlib.tests.test__bencode',
3900
 
        'bzrlib.tests.test__btree_serializer',
3901
3604
        'bzrlib.tests.test__chk_map',
3902
3605
        'bzrlib.tests.test__dirstate_helpers',
3903
3606
        'bzrlib.tests.test__groupcompress',
3925
3628
        'bzrlib.tests.test_chunk_writer',
3926
3629
        'bzrlib.tests.test_clean_tree',
3927
3630
        'bzrlib.tests.test_cleanup',
3928
 
        'bzrlib.tests.test_cmdline',
3929
3631
        'bzrlib.tests.test_commands',
3930
3632
        'bzrlib.tests.test_commit',
3931
3633
        'bzrlib.tests.test_commit_merge',
3932
3634
        'bzrlib.tests.test_config',
3933
3635
        'bzrlib.tests.test_conflicts',
3934
 
        'bzrlib.tests.test_controldir',
3935
3636
        'bzrlib.tests.test_counted_lock',
3936
3637
        'bzrlib.tests.test_crash',
3937
3638
        'bzrlib.tests.test_decorators',
3938
3639
        'bzrlib.tests.test_delta',
3939
3640
        'bzrlib.tests.test_debug',
 
3641
        'bzrlib.tests.test_deprecated_graph',
3940
3642
        'bzrlib.tests.test_diff',
3941
3643
        'bzrlib.tests.test_directory_service',
3942
3644
        'bzrlib.tests.test_dirstate',
3944
3646
        'bzrlib.tests.test_eol_filters',
3945
3647
        'bzrlib.tests.test_errors',
3946
3648
        'bzrlib.tests.test_export',
3947
 
        'bzrlib.tests.test_export_pot',
3948
3649
        'bzrlib.tests.test_extract',
3949
 
        'bzrlib.tests.test_features',
3950
3650
        'bzrlib.tests.test_fetch',
3951
 
        'bzrlib.tests.test_fixtures',
3952
3651
        'bzrlib.tests.test_fifo_cache',
3953
3652
        'bzrlib.tests.test_filters',
3954
 
        'bzrlib.tests.test_filter_tree',
3955
3653
        'bzrlib.tests.test_ftp_transport',
3956
3654
        'bzrlib.tests.test_foreign',
3957
3655
        'bzrlib.tests.test_generate_docs',
3966
3664
        'bzrlib.tests.test_http',
3967
3665
        'bzrlib.tests.test_http_response',
3968
3666
        'bzrlib.tests.test_https_ca_bundle',
3969
 
        'bzrlib.tests.test_i18n',
3970
3667
        'bzrlib.tests.test_identitymap',
3971
3668
        'bzrlib.tests.test_ignores',
3972
3669
        'bzrlib.tests.test_index',
3977
3674
        'bzrlib.tests.test_knit',
3978
3675
        'bzrlib.tests.test_lazy_import',
3979
3676
        'bzrlib.tests.test_lazy_regex',
3980
 
        'bzrlib.tests.test_library_state',
3981
3677
        'bzrlib.tests.test_lock',
3982
3678
        'bzrlib.tests.test_lockable_files',
3983
3679
        'bzrlib.tests.test_lockdir',
3985
3681
        'bzrlib.tests.test_lru_cache',
3986
3682
        'bzrlib.tests.test_lsprof',
3987
3683
        'bzrlib.tests.test_mail_client',
3988
 
        'bzrlib.tests.test_matchers',
3989
3684
        'bzrlib.tests.test_memorytree',
3990
3685
        'bzrlib.tests.test_merge',
3991
3686
        'bzrlib.tests.test_merge3',
3992
3687
        'bzrlib.tests.test_merge_core',
3993
3688
        'bzrlib.tests.test_merge_directive',
3994
 
        'bzrlib.tests.test_mergetools',
3995
3689
        'bzrlib.tests.test_missing',
3996
3690
        'bzrlib.tests.test_msgeditor',
3997
3691
        'bzrlib.tests.test_multiparent',
4006
3700
        'bzrlib.tests.test_permissions',
4007
3701
        'bzrlib.tests.test_plugins',
4008
3702
        'bzrlib.tests.test_progress',
4009
 
        'bzrlib.tests.test_pyutils',
4010
3703
        'bzrlib.tests.test_read_bundle',
4011
3704
        'bzrlib.tests.test_reconcile',
4012
3705
        'bzrlib.tests.test_reconfigure',
4021
3714
        'bzrlib.tests.test_rio',
4022
3715
        'bzrlib.tests.test_rules',
4023
3716
        'bzrlib.tests.test_sampler',
4024
 
        'bzrlib.tests.test_scenarios',
4025
3717
        'bzrlib.tests.test_script',
4026
3718
        'bzrlib.tests.test_selftest',
4027
3719
        'bzrlib.tests.test_serializer',
4043
3735
        'bzrlib.tests.test_switch',
4044
3736
        'bzrlib.tests.test_symbol_versioning',
4045
3737
        'bzrlib.tests.test_tag',
4046
 
        'bzrlib.tests.test_test_server',
4047
3738
        'bzrlib.tests.test_testament',
4048
3739
        'bzrlib.tests.test_textfile',
4049
3740
        'bzrlib.tests.test_textmerge',
4050
 
        'bzrlib.tests.test_cethread',
4051
3741
        'bzrlib.tests.test_timestamp',
4052
3742
        'bzrlib.tests.test_trace',
4053
3743
        'bzrlib.tests.test_transactions',
4056
3746
        'bzrlib.tests.test_transport_log',
4057
3747
        'bzrlib.tests.test_tree',
4058
3748
        'bzrlib.tests.test_treebuilder',
4059
 
        'bzrlib.tests.test_treeshape',
4060
3749
        'bzrlib.tests.test_tsort',
4061
3750
        'bzrlib.tests.test_tuned_gzip',
4062
3751
        'bzrlib.tests.test_ui',
4064
3753
        'bzrlib.tests.test_upgrade',
4065
3754
        'bzrlib.tests.test_upgrade_stacked',
4066
3755
        'bzrlib.tests.test_urlutils',
4067
 
        'bzrlib.tests.test_utextwrap',
4068
3756
        'bzrlib.tests.test_version',
4069
3757
        'bzrlib.tests.test_version_info',
4070
 
        'bzrlib.tests.test_versionedfile',
4071
3758
        'bzrlib.tests.test_weave',
4072
3759
        'bzrlib.tests.test_whitebox',
4073
3760
        'bzrlib.tests.test_win32utils',
4079
3766
 
4080
3767
 
4081
3768
def _test_suite_modules_to_doctest():
4082
 
    """Return the list of modules to doctest."""
4083
 
    if __doc__ is None:
4084
 
        # GZ 2009-03-31: No docstrings with -OO so there's nothing to doctest
4085
 
        return []
 
3769
    """Return the list of modules to doctest."""   
4086
3770
    return [
4087
3771
        'bzrlib',
4088
3772
        'bzrlib.branchbuilder',
4089
3773
        'bzrlib.decorators',
 
3774
        'bzrlib.export',
4090
3775
        'bzrlib.inventory',
4091
3776
        'bzrlib.iterablefile',
4092
3777
        'bzrlib.lockdir',
4093
3778
        'bzrlib.merge3',
4094
3779
        'bzrlib.option',
4095
 
        'bzrlib.pyutils',
4096
3780
        'bzrlib.symbol_versioning',
4097
3781
        'bzrlib.tests',
4098
 
        'bzrlib.tests.fixtures',
4099
3782
        'bzrlib.timestamp',
4100
 
        'bzrlib.transport.http',
4101
3783
        'bzrlib.version_info_formats.format_custom',
4102
3784
        ]
4103
3785
 
4156
3838
        try:
4157
3839
            # note that this really does mean "report only" -- doctest
4158
3840
            # still runs the rest of the examples
4159
 
            doc_suite = IsolatedDocTestSuite(
4160
 
                mod, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
 
3841
            doc_suite = doctest.DocTestSuite(mod,
 
3842
                optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
4161
3843
        except ValueError, e:
4162
3844
            print '**failed to get doctest for: %s\n%s' % (mod, e)
4163
3845
            raise
4166
3848
        suite.addTest(doc_suite)
4167
3849
 
4168
3850
    default_encoding = sys.getdefaultencoding()
4169
 
    for name, plugin in _mod_plugin.plugins().items():
 
3851
    for name, plugin in bzrlib.plugin.plugins().items():
4170
3852
        if not interesting_module(plugin.module.__name__):
4171
3853
            continue
4172
3854
        plugin_suite = plugin.test_suite()
4178
3860
        if plugin_suite is not None:
4179
3861
            suite.addTest(plugin_suite)
4180
3862
        if default_encoding != sys.getdefaultencoding():
4181
 
            trace.warning(
 
3863
            bzrlib.trace.warning(
4182
3864
                'Plugin "%s" tried to reset default encoding to: %s', name,
4183
3865
                sys.getdefaultencoding())
4184
3866
            reload(sys)
4199
3881
            # Some tests mentioned in the list are not in the test suite. The
4200
3882
            # list may be out of date, report to the tester.
4201
3883
            for id in not_found:
4202
 
                trace.warning('"%s" not found in the test suite', id)
 
3884
                bzrlib.trace.warning('"%s" not found in the test suite', id)
4203
3885
        for id in duplicates:
4204
 
            trace.warning('"%s" is used as an id by several tests', id)
 
3886
            bzrlib.trace.warning('"%s" is used as an id by several tests', id)
4205
3887
 
4206
3888
    return suite
4207
3889
 
4208
3890
 
4209
 
def multiply_scenarios(*scenarios):
4210
 
    """Multiply two or more iterables of scenarios.
4211
 
 
4212
 
    It is safe to pass scenario generators or iterators.
4213
 
 
4214
 
    :returns: A list of compound scenarios: the cross-product of all 
4215
 
        scenarios, with the names concatenated and the parameters
4216
 
        merged together.
4217
 
    """
4218
 
    return reduce(_multiply_two_scenarios, map(list, scenarios))
4219
 
 
4220
 
 
4221
 
def _multiply_two_scenarios(scenarios_left, scenarios_right):
 
3891
def multiply_scenarios(scenarios_left, scenarios_right):
4222
3892
    """Multiply two sets of scenarios.
4223
3893
 
4224
3894
    :returns: the cartesian product of the two sets of scenarios, that is
4255
3925
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
4256
3926
    ...     [('one', dict(param=1)),
4257
3927
    ...      ('two', dict(param=2))],
4258
 
    ...     TestUtil.TestSuite())
 
3928
    ...     TestSuite())
4259
3929
    >>> tests = list(iter_suite_tests(r))
4260
3930
    >>> len(tests)
4261
3931
    2
4308
3978
    :param new_id: The id to assign to it.
4309
3979
    :return: The new test.
4310
3980
    """
4311
 
    new_test = copy.copy(test)
 
3981
    new_test = copy(test)
4312
3982
    new_test.id = lambda: new_id
4313
 
    # XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
4314
 
    # causes cloned tests to share the 'details' dict.  This makes it hard to
4315
 
    # read the test output for parameterized tests, because tracebacks will be
4316
 
    # associated with irrelevant tests.
4317
 
    try:
4318
 
        details = new_test._TestCase__details
4319
 
    except AttributeError:
4320
 
        # must be a different version of testtools than expected.  Do nothing.
4321
 
        pass
4322
 
    else:
4323
 
        # Reset the '__details' dict.
4324
 
        new_test._TestCase__details = {}
4325
3983
    return new_test
4326
3984
 
4327
3985
 
4348
4006
        the module is available.
4349
4007
    """
4350
4008
 
4351
 
    from bzrlib.tests.features import ModuleAvailableFeature
4352
 
    py_module = pyutils.get_named_object(py_module_name)
 
4009
    py_module = __import__(py_module_name, {}, {}, ['NO_SUCH_ATTRIB'])
4353
4010
    scenarios = [
4354
4011
        ('python', {'module': py_module}),
4355
4012
    ]
4388
4045
        if test_id != None:
4389
4046
            ui.ui_factory.clear_term()
4390
4047
            sys.stderr.write('\nWhile running: %s\n' % (test_id,))
4391
 
        # Ugly, but the last thing we want here is fail, so bear with it.
4392
 
        printable_e = str(e).decode(osutils.get_user_encoding(), 'replace'
4393
 
                                    ).encode('ascii', 'replace')
4394
4048
        sys.stderr.write('Unable to remove testing dir %s\n%s'
4395
 
                         % (os.path.basename(dirname), printable_e))
 
4049
                         % (os.path.basename(dirname), e))
 
4050
 
 
4051
 
 
4052
class Feature(object):
 
4053
    """An operating system Feature."""
 
4054
 
 
4055
    def __init__(self):
 
4056
        self._available = None
 
4057
 
 
4058
    def available(self):
 
4059
        """Is the feature available?
 
4060
 
 
4061
        :return: True if the feature is available.
 
4062
        """
 
4063
        if self._available is None:
 
4064
            self._available = self._probe()
 
4065
        return self._available
 
4066
 
 
4067
    def _probe(self):
 
4068
        """Implement this method in concrete features.
 
4069
 
 
4070
        :return: True if the feature is available.
 
4071
        """
 
4072
        raise NotImplementedError
 
4073
 
 
4074
    def __str__(self):
 
4075
        if getattr(self, 'feature_name', None):
 
4076
            return self.feature_name()
 
4077
        return self.__class__.__name__
 
4078
 
 
4079
 
 
4080
class _SymlinkFeature(Feature):
 
4081
 
 
4082
    def _probe(self):
 
4083
        return osutils.has_symlinks()
 
4084
 
 
4085
    def feature_name(self):
 
4086
        return 'symlinks'
 
4087
 
 
4088
SymlinkFeature = _SymlinkFeature()
 
4089
 
 
4090
 
 
4091
class _HardlinkFeature(Feature):
 
4092
 
 
4093
    def _probe(self):
 
4094
        return osutils.has_hardlinks()
 
4095
 
 
4096
    def feature_name(self):
 
4097
        return 'hardlinks'
 
4098
 
 
4099
HardlinkFeature = _HardlinkFeature()
 
4100
 
 
4101
 
 
4102
class _OsFifoFeature(Feature):
 
4103
 
 
4104
    def _probe(self):
 
4105
        return getattr(os, 'mkfifo', None)
 
4106
 
 
4107
    def feature_name(self):
 
4108
        return 'filesystem fifos'
 
4109
 
 
4110
OsFifoFeature = _OsFifoFeature()
 
4111
 
 
4112
 
 
4113
class _UnicodeFilenameFeature(Feature):
 
4114
    """Does the filesystem support Unicode filenames?"""
 
4115
 
 
4116
    def _probe(self):
 
4117
        try:
 
4118
            # Check for character combinations unlikely to be covered by any
 
4119
            # single non-unicode encoding. We use the characters
 
4120
            # - greek small letter alpha (U+03B1) and
 
4121
            # - braille pattern dots-123456 (U+283F).
 
4122
            os.stat(u'\u03b1\u283f')
 
4123
        except UnicodeEncodeError:
 
4124
            return False
 
4125
        except (IOError, OSError):
 
4126
            # The filesystem allows the Unicode filename but the file doesn't
 
4127
            # exist.
 
4128
            return True
 
4129
        else:
 
4130
            # The filesystem allows the Unicode filename and the file exists,
 
4131
            # for some reason.
 
4132
            return True
 
4133
 
 
4134
UnicodeFilenameFeature = _UnicodeFilenameFeature()
 
4135
 
 
4136
 
 
4137
class _CompatabilityThunkFeature(Feature):
 
4138
    """This feature is just a thunk to another feature.
 
4139
 
 
4140
    It issues a deprecation warning if it is accessed, to let you know that you
 
4141
    should really use a different feature.
 
4142
    """
 
4143
 
 
4144
    def __init__(self, dep_version, module, name,
 
4145
                 replacement_name, replacement_module=None):
 
4146
        super(_CompatabilityThunkFeature, self).__init__()
 
4147
        self._module = module
 
4148
        if replacement_module is None:
 
4149
            replacement_module = module
 
4150
        self._replacement_module = replacement_module
 
4151
        self._name = name
 
4152
        self._replacement_name = replacement_name
 
4153
        self._dep_version = dep_version
 
4154
        self._feature = None
 
4155
 
 
4156
    def _ensure(self):
 
4157
        if self._feature is None:
 
4158
            depr_msg = self._dep_version % ('%s.%s'
 
4159
                                            % (self._module, self._name))
 
4160
            use_msg = ' Use %s.%s instead.' % (self._replacement_module,
 
4161
                                               self._replacement_name)
 
4162
            symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
 
4163
            # Import the new feature and use it as a replacement for the
 
4164
            # deprecated one.
 
4165
            mod = __import__(self._replacement_module, {}, {},
 
4166
                             [self._replacement_name])
 
4167
            self._feature = getattr(mod, self._replacement_name)
 
4168
 
 
4169
    def _probe(self):
 
4170
        self._ensure()
 
4171
        return self._feature._probe()
 
4172
 
 
4173
 
 
4174
class ModuleAvailableFeature(Feature):
 
4175
    """This is a feature than describes a module we want to be available.
 
4176
 
 
4177
    Declare the name of the module in __init__(), and then after probing, the
 
4178
    module will be available as 'self.module'.
 
4179
 
 
4180
    :ivar module: The module if it is available, else None.
 
4181
    """
 
4182
 
 
4183
    def __init__(self, module_name):
 
4184
        super(ModuleAvailableFeature, self).__init__()
 
4185
        self.module_name = module_name
 
4186
 
 
4187
    def _probe(self):
 
4188
        try:
 
4189
            self._module = __import__(self.module_name, {}, {}, [''])
 
4190
            return True
 
4191
        except ImportError:
 
4192
            return False
 
4193
 
 
4194
    @property
 
4195
    def module(self):
 
4196
        if self.available(): # Make sure the probe has been done
 
4197
            return self._module
 
4198
        return None
 
4199
 
 
4200
    def feature_name(self):
 
4201
        return self.module_name
 
4202
 
 
4203
 
 
4204
# This is kept here for compatibility, it is recommended to use
 
4205
# 'bzrlib.tests.feature.paramiko' instead
 
4206
ParamikoFeature = _CompatabilityThunkFeature(
 
4207
    deprecated_in((2,1,0)),
 
4208
    'bzrlib.tests.features', 'ParamikoFeature', 'paramiko')
4396
4209
 
4397
4210
 
4398
4211
def probe_unicode_in_user_encoding():
4428
4241
    return None
4429
4242
 
4430
4243
 
 
4244
class _HTTPSServerFeature(Feature):
 
4245
    """Some tests want an https Server, check if one is available.
 
4246
 
 
4247
    Right now, the only way this is available is under python2.6 which provides
 
4248
    an ssl module.
 
4249
    """
 
4250
 
 
4251
    def _probe(self):
 
4252
        try:
 
4253
            import ssl
 
4254
            return True
 
4255
        except ImportError:
 
4256
            return False
 
4257
 
 
4258
    def feature_name(self):
 
4259
        return 'HTTPSServer'
 
4260
 
 
4261
 
 
4262
HTTPSServerFeature = _HTTPSServerFeature()
 
4263
 
 
4264
 
 
4265
class _UnicodeFilename(Feature):
 
4266
    """Does the filesystem support Unicode filenames?"""
 
4267
 
 
4268
    def _probe(self):
 
4269
        try:
 
4270
            os.stat(u'\u03b1')
 
4271
        except UnicodeEncodeError:
 
4272
            return False
 
4273
        except (IOError, OSError):
 
4274
            # The filesystem allows the Unicode filename but the file doesn't
 
4275
            # exist.
 
4276
            return True
 
4277
        else:
 
4278
            # The filesystem allows the Unicode filename and the file exists,
 
4279
            # for some reason.
 
4280
            return True
 
4281
 
 
4282
UnicodeFilename = _UnicodeFilename()
 
4283
 
 
4284
 
 
4285
class _UTF8Filesystem(Feature):
 
4286
    """Is the filesystem UTF-8?"""
 
4287
 
 
4288
    def _probe(self):
 
4289
        if osutils._fs_enc.upper() in ('UTF-8', 'UTF8'):
 
4290
            return True
 
4291
        return False
 
4292
 
 
4293
UTF8Filesystem = _UTF8Filesystem()
 
4294
 
 
4295
 
 
4296
class _BreakinFeature(Feature):
 
4297
    """Does this platform support the breakin feature?"""
 
4298
 
 
4299
    def _probe(self):
 
4300
        from bzrlib import breakin
 
4301
        if breakin.determine_signal() is None:
 
4302
            return False
 
4303
        if sys.platform == 'win32':
 
4304
            # Windows doesn't have os.kill, and we catch the SIGBREAK signal.
 
4305
            # We trigger SIGBREAK via a Console api so we need ctypes to
 
4306
            # access the function
 
4307
            try:
 
4308
                import ctypes
 
4309
            except OSError:
 
4310
                return False
 
4311
        return True
 
4312
 
 
4313
    def feature_name(self):
 
4314
        return "SIGQUIT or SIGBREAK w/ctypes on win32"
 
4315
 
 
4316
 
 
4317
BreakinFeature = _BreakinFeature()
 
4318
 
 
4319
 
 
4320
class _CaseInsCasePresFilenameFeature(Feature):
 
4321
    """Is the file-system case insensitive, but case-preserving?"""
 
4322
 
 
4323
    def _probe(self):
 
4324
        fileno, name = tempfile.mkstemp(prefix='MixedCase')
 
4325
        try:
 
4326
            # first check truly case-preserving for created files, then check
 
4327
            # case insensitive when opening existing files.
 
4328
            name = osutils.normpath(name)
 
4329
            base, rel = osutils.split(name)
 
4330
            found_rel = osutils.canonical_relpath(base, name)
 
4331
            return (found_rel == rel
 
4332
                    and os.path.isfile(name.upper())
 
4333
                    and os.path.isfile(name.lower()))
 
4334
        finally:
 
4335
            os.close(fileno)
 
4336
            os.remove(name)
 
4337
 
 
4338
    def feature_name(self):
 
4339
        return "case-insensitive case-preserving filesystem"
 
4340
 
 
4341
CaseInsCasePresFilenameFeature = _CaseInsCasePresFilenameFeature()
 
4342
 
 
4343
 
 
4344
class _CaseInsensitiveFilesystemFeature(Feature):
 
4345
    """Check if underlying filesystem is case-insensitive but *not* case
 
4346
    preserving.
 
4347
    """
 
4348
    # Note that on Windows, Cygwin, MacOS etc, the file-systems are far
 
4349
    # more likely to be case preserving, so this case is rare.
 
4350
 
 
4351
    def _probe(self):
 
4352
        if CaseInsCasePresFilenameFeature.available():
 
4353
            return False
 
4354
 
 
4355
        if TestCaseWithMemoryTransport.TEST_ROOT is None:
 
4356
            root = osutils.mkdtemp(prefix='testbzr-', suffix='.tmp')
 
4357
            TestCaseWithMemoryTransport.TEST_ROOT = root
 
4358
        else:
 
4359
            root = TestCaseWithMemoryTransport.TEST_ROOT
 
4360
        tdir = osutils.mkdtemp(prefix='case-sensitive-probe-', suffix='',
 
4361
            dir=root)
 
4362
        name_a = osutils.pathjoin(tdir, 'a')
 
4363
        name_A = osutils.pathjoin(tdir, 'A')
 
4364
        os.mkdir(name_a)
 
4365
        result = osutils.isdir(name_A)
 
4366
        _rmtree_temp_dir(tdir)
 
4367
        return result
 
4368
 
 
4369
    def feature_name(self):
 
4370
        return 'case-insensitive filesystem'
 
4371
 
 
4372
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
 
4373
 
 
4374
 
 
4375
class _CaseSensitiveFilesystemFeature(Feature):
 
4376
 
 
4377
    def _probe(self):
 
4378
        if CaseInsCasePresFilenameFeature.available():
 
4379
            return False
 
4380
        elif CaseInsensitiveFilesystemFeature.available():
 
4381
            return False
 
4382
        else:
 
4383
            return True
 
4384
 
 
4385
    def feature_name(self):
 
4386
        return 'case-sensitive filesystem'
 
4387
 
 
4388
# new coding style is for feature instances to be lowercase
 
4389
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
 
4390
 
 
4391
 
 
4392
# Kept for compatibility, use bzrlib.tests.features.subunit instead
 
4393
SubUnitFeature = _CompatabilityThunkFeature(
 
4394
    deprecated_in((2,1,0)),
 
4395
    'bzrlib.tests.features', 'SubUnitFeature', 'subunit')
4431
4396
# Only define SubUnitBzrRunner if subunit is available.
4432
4397
try:
4433
4398
    from subunit import TestProtocolClient
4434
4399
    from subunit.test_results import AutoTimingTestResultDecorator
4435
 
    class SubUnitBzrProtocolClient(TestProtocolClient):
4436
 
 
4437
 
        def addSuccess(self, test, details=None):
4438
 
            # The subunit client always includes the details in the subunit
4439
 
            # stream, but we don't want to include it in ours.
4440
 
            if details is not None and 'log' in details:
4441
 
                del details['log']
4442
 
            return super(SubUnitBzrProtocolClient, self).addSuccess(
4443
 
                test, details)
4444
 
 
4445
4400
    class SubUnitBzrRunner(TextTestRunner):
4446
4401
        def run(self, test):
4447
4402
            result = AutoTimingTestResultDecorator(
4448
 
                SubUnitBzrProtocolClient(self.stream))
 
4403
                TestProtocolClient(self.stream))
4449
4404
            test.run(result)
4450
4405
            return result
4451
4406
except ImportError:
4452
4407
    pass
4453
 
 
4454
 
 
4455
 
@deprecated_function(deprecated_in((2, 5, 0)))
4456
 
def ModuleAvailableFeature(name):
4457
 
    from bzrlib.tests import features
4458
 
    return features.ModuleAvailableFeature(name)
4459