~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Jelmer Vernooij
  • Date: 2011-12-16 19:18:39 UTC
  • mto: This revision was merged to the branch mainline in revision 6391.
  • Revision ID: jelmer@samba.org-20111216191839-eg681lxqibi1qxu1
Fix remaining tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
16
16
 
17
17
"""Testing framework extensions"""
18
18
 
19
 
# TODO: Perhaps there should be an API to find out if bzr running under the
20
 
# test suite -- some plugins might want to avoid making intrusive changes if
21
 
# this is the case.  However, we want behaviour under to test to diverge as
22
 
# little as possible, so this should be used rarely if it's added at all.
23
 
# (Suggestion from j-a-meinel, 2005-11-24)
24
 
 
25
19
# NOTE: Some classes in here use camelCaseNaming() rather than
26
20
# underscore_naming().  That's for consistency with unittest; it's not the
27
21
# general style of bzrlib.  Please continue that consistency when adding e.g.
42
36
import random
43
37
import re
44
38
import shlex
 
39
import site
45
40
import stat
46
41
import subprocess
47
42
import sys
55
50
import testtools
56
51
# nb: check this before importing anything else from within it
57
52
_testtools_version = getattr(testtools, '__version__', ())
58
 
if _testtools_version < (0, 9, 2):
59
 
    raise ImportError("need at least testtools 0.9.2: %s is %r"
 
53
if _testtools_version < (0, 9, 5):
 
54
    raise ImportError("need at least testtools 0.9.5: %s is %r"
60
55
        % (testtools.__file__, _testtools_version))
61
56
from testtools import content
62
57
 
 
58
import bzrlib
63
59
from bzrlib import (
64
60
    branchbuilder,
65
61
    bzrdir,
66
62
    chk_map,
 
63
    commands as _mod_commands,
67
64
    config,
 
65
    i18n,
68
66
    debug,
69
67
    errors,
70
68
    hooks,
71
69
    lock as _mod_lock,
 
70
    lockdir,
72
71
    memorytree,
73
72
    osutils,
 
73
    plugin as _mod_plugin,
 
74
    pyutils,
74
75
    ui,
75
76
    urlutils,
76
77
    registry,
 
78
    symbol_versioning,
 
79
    trace,
77
80
    transport as _mod_transport,
78
81
    workingtree,
79
82
    )
80
 
import bzrlib.branch
81
 
import bzrlib.commands
82
 
import bzrlib.timestamp
83
 
import bzrlib.export
84
 
import bzrlib.inventory
85
 
import bzrlib.iterablefile
86
 
import bzrlib.lockdir
87
83
try:
88
84
    import bzrlib.lsprof
89
85
except ImportError:
90
86
    # lsprof not available
91
87
    pass
92
 
from bzrlib.merge import merge_inner
93
 
import bzrlib.merge3
94
 
import bzrlib.plugin
95
 
from bzrlib.smart import client, request, server
96
 
import bzrlib.store
97
 
from bzrlib import symbol_versioning
 
88
from bzrlib.smart import client, request
 
89
from bzrlib.transport import (
 
90
    memory,
 
91
    pathfilter,
 
92
    )
98
93
from bzrlib.symbol_versioning import (
99
 
    DEPRECATED_PARAMETER,
100
94
    deprecated_function,
101
95
    deprecated_in,
102
 
    deprecated_method,
103
 
    deprecated_passed,
104
 
    )
105
 
import bzrlib.trace
106
 
from bzrlib.transport import (
107
 
    memory,
108
 
    pathfilter,
109
 
    )
110
 
from bzrlib.trace import mutter, note
 
96
    )
111
97
from bzrlib.tests import (
 
98
    fixtures,
112
99
    test_server,
113
100
    TestUtil,
114
101
    treeshape,
115
102
    )
116
103
from bzrlib.ui import NullProgressView
117
104
from bzrlib.ui.text import TextUIFactory
118
 
import bzrlib.version_info_formats.format_custom
119
 
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
 
105
from bzrlib.tests.features import _CompatabilityThunkFeature
120
106
 
121
107
# Mark this python module as being part of the implementation
122
108
# of unittest: this gives us better tracebacks where the last
139
125
TestSuite = TestUtil.TestSuite
140
126
TestLoader = TestUtil.TestLoader
141
127
 
 
128
# Tests should run in a clean and clearly defined environment. The goal is to
 
129
# keep them isolated from the running environment as mush as possible. The test
 
130
# framework ensures the variables defined below are set (or deleted if the
 
131
# value is None) before a test is run and reset to their original value after
 
132
# the test is run. Generally if some code depends on an environment variable,
 
133
# the tests should start without this variable in the environment. There are a
 
134
# few exceptions but you shouldn't violate this rule lightly.
 
135
isolated_environ = {
 
136
    'BZR_HOME': None,
 
137
    'HOME': None,
 
138
    # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
 
139
    # tests do check our impls match APPDATA
 
140
    'BZR_EDITOR': None, # test_msgeditor manipulates this variable
 
141
    'VISUAL': None,
 
142
    'EDITOR': None,
 
143
    'BZR_EMAIL': None,
 
144
    'BZREMAIL': None, # may still be present in the environment
 
145
    'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
 
146
    'BZR_PROGRESS_BAR': None,
 
147
    # This should trap leaks to ~/.bzr.log. This occurs when tests use TestCase
 
148
    # as a base class instead of TestCaseInTempDir. Tests inheriting from
 
149
    # TestCase should not use disk resources, BZR_LOG is one.
 
150
    'BZR_LOG': '/you-should-use-TestCaseInTempDir-if-you-need-a-log-file',
 
151
    'BZR_PLUGIN_PATH': None,
 
152
    'BZR_DISABLE_PLUGINS': None,
 
153
    'BZR_PLUGINS_AT': None,
 
154
    'BZR_CONCURRENCY': None,
 
155
    # Make sure that any text ui tests are consistent regardless of
 
156
    # the environment the test case is run in; you may want tests that
 
157
    # test other combinations.  'dumb' is a reasonable guess for tests
 
158
    # going to a pipe or a StringIO.
 
159
    'TERM': 'dumb',
 
160
    'LINES': '25',
 
161
    'COLUMNS': '80',
 
162
    'BZR_COLUMNS': '80',
 
163
    # Disable SSH Agent
 
164
    'SSH_AUTH_SOCK': None,
 
165
    # Proxies
 
166
    'http_proxy': None,
 
167
    'HTTP_PROXY': None,
 
168
    'https_proxy': None,
 
169
    'HTTPS_PROXY': None,
 
170
    'no_proxy': None,
 
171
    'NO_PROXY': None,
 
172
    'all_proxy': None,
 
173
    'ALL_PROXY': None,
 
174
    # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
 
175
    # least. If you do (care), please update this comment
 
176
    # -- vila 20080401
 
177
    'ftp_proxy': None,
 
178
    'FTP_PROXY': None,
 
179
    'BZR_REMOTE_PATH': None,
 
180
    # Generally speaking, we don't want apport reporting on crashes in
 
181
    # the test envirnoment unless we're specifically testing apport,
 
182
    # so that it doesn't leak into the real system environment.  We
 
183
    # use an env var so it propagates to subprocesses.
 
184
    'APPORT_DISABLE': '1',
 
185
    }
 
186
 
 
187
 
 
188
def override_os_environ(test, env=None):
 
189
    """Modify os.environ keeping a copy.
 
190
    
 
191
    :param test: A test instance
 
192
 
 
193
    :param env: A dict containing variable definitions to be installed
 
194
    """
 
195
    if env is None:
 
196
        env = isolated_environ
 
197
    test._original_os_environ = dict([(var, value)
 
198
                                      for var, value in os.environ.iteritems()])
 
199
    for var, value in env.iteritems():
 
200
        osutils.set_or_unset_env(var, value)
 
201
        if var not in test._original_os_environ:
 
202
            # The var is new, add it with a value of None, so
 
203
            # restore_os_environ will delete it
 
204
            test._original_os_environ[var] = None
 
205
 
 
206
 
 
207
def restore_os_environ(test):
 
208
    """Restore os.environ to its original state.
 
209
 
 
210
    :param test: A test instance previously passed to override_os_environ.
 
211
    """
 
212
    for var, value in test._original_os_environ.iteritems():
 
213
        # Restore the original value (or delete it if the value has been set to
 
214
        # None in override_os_environ).
 
215
        osutils.set_or_unset_env(var, value)
 
216
 
 
217
 
 
218
def _clear__type_equality_funcs(test):
 
219
    """Cleanup bound methods stored on TestCase instances
 
220
 
 
221
    Clear the dict breaking a few (mostly) harmless cycles in the affected
 
222
    unittests released with Python 2.6 and initial Python 2.7 versions.
 
223
 
 
224
    For a few revisions between Python 2.7.1 and Python 2.7.2 that annoyingly
 
225
    shipped in Oneiric, an object with no clear method was used, hence the
 
226
    extra complications, see bug 809048 for details.
 
227
    """
 
228
    type_equality_funcs = getattr(test, "_type_equality_funcs", None)
 
229
    if type_equality_funcs is not None:
 
230
        tef_clear = getattr(type_equality_funcs, "clear", None)
 
231
        if tef_clear is None:
 
232
            tef_instance_dict = getattr(type_equality_funcs, "__dict__", None)
 
233
            if tef_instance_dict is not None:
 
234
                tef_clear = tef_instance_dict.clear
 
235
        if tef_clear is not None:
 
236
            tef_clear()
 
237
 
 
238
 
142
239
class ExtendedTestResult(testtools.TextTestResult):
143
240
    """Accepts, reports and accumulates the results of running tests.
144
241
 
195
292
        self._strict = strict
196
293
        self._first_thread_leaker_id = None
197
294
        self._tests_leaking_threads_count = 0
 
295
        self._traceback_from_test = None
198
296
 
199
297
    def stopTestRun(self):
200
298
        run = self.testsRun
260
358
 
261
359
    def _elapsedTestTimeString(self):
262
360
        """Return a time string for the overall time the current test has taken."""
263
 
        return self._formatTime(time.time() - self._start_time)
 
361
        return self._formatTime(self._delta_to_float(
 
362
            self._now() - self._start_datetime))
264
363
 
265
364
    def _testTimeString(self, testCase):
266
365
        benchmark_time = self._extractBenchmarkTime(testCase)
280
379
        what = re.sub(r'^bzrlib\.tests\.', '', what)
281
380
        return what
282
381
 
 
382
    # GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
 
383
    #                multiple times in a row, because the handler is added for
 
384
    #                each test but the container list is shared between cases.
 
385
    #                See lp:498869 lp:625574 and lp:637725 for background.
 
386
    def _record_traceback_from_test(self, exc_info):
 
387
        """Store the traceback from passed exc_info tuple till"""
 
388
        self._traceback_from_test = exc_info[2]
 
389
 
283
390
    def startTest(self, test):
284
391
        super(ExtendedTestResult, self).startTest(test)
285
392
        if self.count == 0:
288
395
        self.report_test_start(test)
289
396
        test.number = self.count
290
397
        self._recordTestStartTime()
291
 
        # Only check for thread leaks if the test case supports cleanups
292
 
        addCleanup = getattr(test, "addCleanup", None)
293
 
        if addCleanup is not None:
294
 
            addCleanup(self._check_leaked_threads, test)
 
398
        # Make testtools cases give us the real traceback on failure
 
399
        addOnException = getattr(test, "addOnException", None)
 
400
        if addOnException is not None:
 
401
            addOnException(self._record_traceback_from_test)
 
402
        # Only check for thread leaks on bzrlib derived test cases
 
403
        if isinstance(test, TestCase):
 
404
            test.addCleanup(self._check_leaked_threads, test)
 
405
 
 
406
    def stopTest(self, test):
 
407
        super(ExtendedTestResult, self).stopTest(test)
 
408
        # Manually break cycles, means touching various private things but hey
 
409
        getDetails = getattr(test, "getDetails", None)
 
410
        if getDetails is not None:
 
411
            getDetails().clear()
 
412
        _clear__type_equality_funcs(test)
 
413
        self._traceback_from_test = None
295
414
 
296
415
    def startTests(self):
297
416
        self.report_tests_starting()
315
434
 
316
435
    def _recordTestStartTime(self):
317
436
        """Record that a test has started."""
318
 
        self._start_time = time.time()
 
437
        self._start_datetime = self._now()
319
438
 
320
439
    def addError(self, test, err):
321
440
        """Tell result that test finished with an error.
323
442
        Called from the TestCase run() method when the test
324
443
        fails with an unexpected error.
325
444
        """
326
 
        self._post_mortem()
 
445
        self._post_mortem(self._traceback_from_test)
327
446
        super(ExtendedTestResult, self).addError(test, err)
328
447
        self.error_count += 1
329
448
        self.report_error(test, err)
336
455
        Called from the TestCase run() method when the test
337
456
        fails because e.g. an assert() method failed.
338
457
        """
339
 
        self._post_mortem()
 
458
        self._post_mortem(self._traceback_from_test)
340
459
        super(ExtendedTestResult, self).addFailure(test, err)
341
460
        self.failure_count += 1
342
461
        self.report_failure(test, err)
362
481
        self.known_failure_count += 1
363
482
        self.report_known_failure(test, err)
364
483
 
 
484
    def addUnexpectedSuccess(self, test, details=None):
 
485
        """Tell result the test unexpectedly passed, counting as a failure
 
486
 
 
487
        When the minimum version of testtools required becomes 0.9.8 this
 
488
        can be updated to use the new handling there.
 
489
        """
 
490
        super(ExtendedTestResult, self).addFailure(test, details=details)
 
491
        self.failure_count += 1
 
492
        self.report_unexpected_success(test,
 
493
            "".join(details["reason"].iter_text()))
 
494
        if self.stop_early:
 
495
            self.stop()
 
496
 
365
497
    def addNotSupported(self, test, feature):
366
498
        """The test will not be run because of a missing feature.
367
499
        """
384
516
        self.not_applicable_count += 1
385
517
        self.report_not_applicable(test, reason)
386
518
 
387
 
    def _post_mortem(self):
 
519
    def _count_stored_tests(self):
 
520
        """Count of tests instances kept alive due to not succeeding"""
 
521
        return self.error_count + self.failure_count + self.known_failure_count
 
522
 
 
523
    def _post_mortem(self, tb=None):
388
524
        """Start a PDB post mortem session."""
389
525
        if os.environ.get('BZR_TEST_PDB', None):
390
 
            import pdb;pdb.post_mortem()
 
526
            import pdb
 
527
            pdb.post_mortem(tb)
391
528
 
392
529
    def progress(self, offset, whence):
393
530
        """The test is adjusting the count of tests to run."""
525
662
    def report_known_failure(self, test, err):
526
663
        pass
527
664
 
 
665
    def report_unexpected_success(self, test, reason):
 
666
        self.stream.write('FAIL: %s\n    %s: %s\n' % (
 
667
            self._test_description(test),
 
668
            "Unexpected success. Should have failed",
 
669
            reason,
 
670
            ))
 
671
 
528
672
    def report_skip(self, test, reason):
529
673
        pass
530
674
 
582
726
                % (self._testTimeString(test),
583
727
                   self._error_summary(err)))
584
728
 
 
729
    def report_unexpected_success(self, test, reason):
 
730
        self.stream.write(' FAIL %s\n%s: %s\n'
 
731
                % (self._testTimeString(test),
 
732
                   "Unexpected success. Should have failed",
 
733
                   reason))
 
734
 
585
735
    def report_success(self, test):
586
736
        self.stream.write('   OK %s\n' % self._testTimeString(test))
587
737
        for bench_called, stats in getattr(test, '_benchcalls', []):
634
784
            encode = codec[0]
635
785
        else:
636
786
            encode = codec.encode
637
 
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
 
787
        # GZ 2010-09-08: Really we don't want to be writing arbitrary bytes,
 
788
        #                so should swap to the plain codecs.StreamWriter
 
789
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream,
 
790
            "backslashreplace")
638
791
        stream.encoding = new_encoding
639
792
        self.stream = stream
640
793
        self.descriptions = descriptions
790
943
        return NullProgressView()
791
944
 
792
945
 
 
946
def isolated_doctest_setUp(test):
 
947
    override_os_environ(test)
 
948
 
 
949
 
 
950
def isolated_doctest_tearDown(test):
 
951
    restore_os_environ(test)
 
952
 
 
953
 
 
954
def IsolatedDocTestSuite(*args, **kwargs):
 
955
    """Overrides doctest.DocTestSuite to handle isolation.
 
956
 
 
957
    The method is really a factory and users are expected to use it as such.
 
958
    """
 
959
 
 
960
    kwargs['setUp'] = isolated_doctest_setUp
 
961
    kwargs['tearDown'] = isolated_doctest_tearDown
 
962
    return doctest.DocTestSuite(*args, **kwargs)
 
963
 
 
964
 
793
965
class TestCase(testtools.TestCase):
794
966
    """Base class for bzr unit tests.
795
967
 
825
997
 
826
998
    def setUp(self):
827
999
        super(TestCase, self).setUp()
 
1000
 
 
1001
        timeout = config.GlobalStack().get('selftest.timeout')
 
1002
        if timeout:
 
1003
            timeout_fixture = fixtures.TimeoutFixture(timeout)
 
1004
            timeout_fixture.setUp()
 
1005
            self.addCleanup(timeout_fixture.cleanUp)
 
1006
 
828
1007
        for feature in getattr(self, '_test_needs_features', []):
829
1008
            self.requireFeature(feature)
830
 
        self._log_contents = None
831
 
        self.addDetail("log", content.Content(content.ContentType("text",
832
 
            "plain", {"charset": "utf8"}),
833
 
            lambda:[self._get_log(keep_log_file=True)]))
834
1009
        self._cleanEnvironment()
 
1010
 
 
1011
        if bzrlib.global_state is not None:
 
1012
            self.overrideAttr(bzrlib.global_state, 'cmdline_overrides',
 
1013
                              config.CommandLineStore())
 
1014
 
835
1015
        self._silenceUI()
836
1016
        self._startLogFile()
837
1017
        self._benchcalls = []
840
1020
        self._track_transports()
841
1021
        self._track_locks()
842
1022
        self._clear_debug_flags()
 
1023
        # Isolate global verbosity level, to make sure it's reproducible
 
1024
        # between tests.  We should get rid of this altogether: bug 656694. --
 
1025
        # mbp 20101008
 
1026
        self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
 
1027
        # Isolate config option expansion until its default value for bzrlib is
 
1028
        # settled on or a the FIXME associated with _get_expand_default_value
 
1029
        # is addressed -- vila 20110219
 
1030
        self.overrideAttr(config, '_expand_default_value', None)
 
1031
        self._log_files = set()
 
1032
        # Each key in the ``_counters`` dict holds a value for a different
 
1033
        # counter. When the test ends, addDetail() should be used to output the
 
1034
        # counter values. This happens in install_counter_hook().
 
1035
        self._counters = {}
 
1036
        if 'config_stats' in selftest_debug_flags:
 
1037
            self._install_config_stats_hooks()
 
1038
        # Do not use i18n for tests (unless the test reverses this)
 
1039
        i18n.disable_i18n()
843
1040
 
844
1041
    def debug(self):
845
1042
        # debug a frame up.
846
1043
        import pdb
847
 
        pdb.Pdb().set_trace(sys._getframe().f_back)
 
1044
        # The sys preserved stdin/stdout should allow blackbox tests debugging
 
1045
        pdb.Pdb(stdin=sys.__stdin__, stdout=sys.__stdout__
 
1046
                ).set_trace(sys._getframe().f_back)
848
1047
 
849
1048
    def discardDetail(self, name):
850
1049
        """Extend the addDetail, getDetails api so we can remove a detail.
862
1061
        if name in details:
863
1062
            del details[name]
864
1063
 
 
1064
    def install_counter_hook(self, hooks, name, counter_name=None):
 
1065
        """Install a counting hook.
 
1066
 
 
1067
        Any hook can be counted as long as it doesn't need to return a value.
 
1068
 
 
1069
        :param hooks: Where the hook should be installed.
 
1070
 
 
1071
        :param name: The hook name that will be counted.
 
1072
 
 
1073
        :param counter_name: The counter identifier in ``_counters``, defaults
 
1074
            to ``name``.
 
1075
        """
 
1076
        _counters = self._counters # Avoid closing over self
 
1077
        if counter_name is None:
 
1078
            counter_name = name
 
1079
        if _counters.has_key(counter_name):
 
1080
            raise AssertionError('%s is already used as a counter name'
 
1081
                                  % (counter_name,))
 
1082
        _counters[counter_name] = 0
 
1083
        self.addDetail(counter_name, content.Content(content.UTF8_TEXT,
 
1084
            lambda: ['%d' % (_counters[counter_name],)]))
 
1085
        def increment_counter(*args, **kwargs):
 
1086
            _counters[counter_name] += 1
 
1087
        label = 'count %s calls' % (counter_name,)
 
1088
        hooks.install_named_hook(name, increment_counter, label)
 
1089
        self.addCleanup(hooks.uninstall_named_hook, name, label)
 
1090
 
 
1091
    def _install_config_stats_hooks(self):
 
1092
        """Install config hooks to count hook calls.
 
1093
 
 
1094
        """
 
1095
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
 
1096
            self.install_counter_hook(config.ConfigHooks, hook_name,
 
1097
                                       'config.%s' % (hook_name,))
 
1098
 
 
1099
        # The OldConfigHooks are private and need special handling to protect
 
1100
        # against recursive tests (tests that run other tests), so we just do
 
1101
        # manually what registering them into _builtin_known_hooks will provide
 
1102
        # us.
 
1103
        self.overrideAttr(config, 'OldConfigHooks', config._OldConfigHooks())
 
1104
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
 
1105
            self.install_counter_hook(config.OldConfigHooks, hook_name,
 
1106
                                      'old_config.%s' % (hook_name,))
 
1107
 
865
1108
    def _clear_debug_flags(self):
866
1109
        """Prevent externally set debug flags affecting tests.
867
1110
 
877
1120
 
878
1121
    def _clear_hooks(self):
879
1122
        # prevent hooks affecting tests
 
1123
        known_hooks = hooks.known_hooks
880
1124
        self._preserved_hooks = {}
881
 
        for key, factory in hooks.known_hooks.items():
882
 
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
883
 
            current_hooks = hooks.known_hooks_key_to_object(key)
 
1125
        for key, (parent, name) in known_hooks.iter_parent_objects():
 
1126
            current_hooks = getattr(parent, name)
884
1127
            self._preserved_hooks[parent] = (name, current_hooks)
 
1128
        self._preserved_lazy_hooks = hooks._lazy_hooks
 
1129
        hooks._lazy_hooks = {}
885
1130
        self.addCleanup(self._restoreHooks)
886
 
        for key, factory in hooks.known_hooks.items():
887
 
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
1131
        for key, (parent, name) in known_hooks.iter_parent_objects():
 
1132
            factory = known_hooks.get(key)
888
1133
            setattr(parent, name, factory())
889
1134
        # this hook should always be installed
890
1135
        request._install_hook()
919
1164
        # break some locks on purpose and should be taken into account by
920
1165
        # considering that breaking a lock is just a dirty way of releasing it.
921
1166
        if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
922
 
            message = ('Different number of acquired and '
923
 
                       'released or broken locks. (%s, %s + %s)' %
924
 
                       (acquired_locks, released_locks, broken_locks))
 
1167
            message = (
 
1168
                'Different number of acquired and '
 
1169
                'released or broken locks.\n'
 
1170
                'acquired=%s\n'
 
1171
                'released=%s\n'
 
1172
                'broken=%s\n' %
 
1173
                (acquired_locks, released_locks, broken_locks))
925
1174
            if not self._lock_check_thorough:
926
1175
                # Rather than fail, just warn
927
1176
                print "Broken test %s: %s" % (self, message)
955
1204
 
956
1205
    def permit_dir(self, name):
957
1206
        """Permit a directory to be used by this test. See permit_url."""
958
 
        name_transport = _mod_transport.get_transport(name)
 
1207
        name_transport = _mod_transport.get_transport_from_path(name)
959
1208
        self.permit_url(name)
960
1209
        self.permit_url(name_transport.base)
961
1210
 
1040
1289
        self.addCleanup(transport_server.stop_server)
1041
1290
        # Obtain a real transport because if the server supplies a password, it
1042
1291
        # will be hidden from the base on the client side.
1043
 
        t = _mod_transport.get_transport(transport_server.get_url())
 
1292
        t = _mod_transport.get_transport_from_url(transport_server.get_url())
1044
1293
        # Some transport servers effectively chroot the backing transport;
1045
1294
        # others like SFTPServer don't - users of the transport can walk up the
1046
1295
        # transport to read the entire backing transport. This wouldn't matter
1102
1351
        except UnicodeError, e:
1103
1352
            # If we can't compare without getting a UnicodeError, then
1104
1353
            # obviously they are different
1105
 
            mutter('UnicodeError: %s', e)
 
1354
            trace.mutter('UnicodeError: %s', e)
1106
1355
        if message:
1107
1356
            message += '\n'
1108
1357
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1147
1396
                         'st_mtime did not match')
1148
1397
        self.assertEqual(expected.st_ctime, actual.st_ctime,
1149
1398
                         'st_ctime did not match')
1150
 
        if sys.platform != 'win32':
 
1399
        if sys.platform == 'win32':
1151
1400
            # On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1152
1401
            # is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
1153
 
            # odd. Regardless we shouldn't actually try to assert anything
1154
 
            # about their values
 
1402
            # odd. We just force it to always be 0 to avoid any problems.
 
1403
            self.assertEqual(0, expected.st_dev)
 
1404
            self.assertEqual(0, actual.st_dev)
 
1405
            self.assertEqual(0, expected.st_ino)
 
1406
            self.assertEqual(0, actual.st_ino)
 
1407
        else:
1155
1408
            self.assertEqual(expected.st_dev, actual.st_dev,
1156
1409
                             'st_dev did not match')
1157
1410
            self.assertEqual(expected.st_ino, actual.st_ino,
1166
1419
                length, len(obj_with_len), obj_with_len))
1167
1420
 
1168
1421
    def assertLogsError(self, exception_class, func, *args, **kwargs):
1169
 
        """Assert that func(*args, **kwargs) quietly logs a specific exception.
 
1422
        """Assert that `func(*args, **kwargs)` quietly logs a specific error.
1170
1423
        """
1171
 
        from bzrlib import trace
1172
1424
        captured = []
1173
1425
        orig_log_exception_quietly = trace.log_exception_quietly
1174
1426
        try:
1175
1427
            def capture():
1176
1428
                orig_log_exception_quietly()
1177
 
                captured.append(sys.exc_info())
 
1429
                captured.append(sys.exc_info()[1])
1178
1430
            trace.log_exception_quietly = capture
1179
1431
            func(*args, **kwargs)
1180
1432
        finally:
1181
1433
            trace.log_exception_quietly = orig_log_exception_quietly
1182
1434
        self.assertLength(1, captured)
1183
 
        err = captured[0][1]
 
1435
        err = captured[0]
1184
1436
        self.assertIsInstance(err, exception_class)
1185
1437
        return err
1186
1438
 
1223
1475
        if haystack.find(needle) == -1:
1224
1476
            self.fail("string %r not found in '''%s'''" % (needle, haystack))
1225
1477
 
 
1478
    def assertNotContainsString(self, haystack, needle):
 
1479
        if haystack.find(needle) != -1:
 
1480
            self.fail("string %r found in '''%s'''" % (needle, haystack))
 
1481
 
1226
1482
    def assertSubset(self, sublist, superlist):
1227
1483
        """Assert that every entry in sublist is present in superlist."""
1228
1484
        missing = set(sublist) - set(superlist)
1317
1573
 
1318
1574
    def assertFileEqual(self, content, path):
1319
1575
        """Fail if path does not contain 'content'."""
1320
 
        self.failUnlessExists(path)
 
1576
        self.assertPathExists(path)
1321
1577
        f = file(path, 'rb')
1322
1578
        try:
1323
1579
            s = f.read()
1333
1589
        else:
1334
1590
            self.assertEqual(expected_docstring, obj.__doc__)
1335
1591
 
 
1592
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1336
1593
    def failUnlessExists(self, path):
 
1594
        return self.assertPathExists(path)
 
1595
 
 
1596
    def assertPathExists(self, path):
1337
1597
        """Fail unless path or paths, which may be abs or relative, exist."""
1338
1598
        if not isinstance(path, basestring):
1339
1599
            for p in path:
1340
 
                self.failUnlessExists(p)
 
1600
                self.assertPathExists(p)
1341
1601
        else:
1342
 
            self.failUnless(osutils.lexists(path),path+" does not exist")
 
1602
            self.assertTrue(osutils.lexists(path),
 
1603
                path + " does not exist")
1343
1604
 
 
1605
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1344
1606
    def failIfExists(self, path):
 
1607
        return self.assertPathDoesNotExist(path)
 
1608
 
 
1609
    def assertPathDoesNotExist(self, path):
1345
1610
        """Fail if path or paths, which may be abs or relative, exist."""
1346
1611
        if not isinstance(path, basestring):
1347
1612
            for p in path:
1348
 
                self.failIfExists(p)
 
1613
                self.assertPathDoesNotExist(p)
1349
1614
        else:
1350
 
            self.failIf(osutils.lexists(path),path+" exists")
 
1615
            self.assertFalse(osutils.lexists(path),
 
1616
                path + " exists")
1351
1617
 
1352
1618
    def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
1353
1619
        """A helper for callDeprecated and applyDeprecated.
1379
1645
        not other callers that go direct to the warning module.
1380
1646
 
1381
1647
        To test that a deprecated method raises an error, do something like
1382
 
        this::
 
1648
        this (remember that both assertRaises and applyDeprecated delays *args
 
1649
        and **kwargs passing)::
1383
1650
 
1384
1651
            self.assertRaises(errors.ReservedId,
1385
1652
                self.applyDeprecated,
1463
1730
        return result
1464
1731
 
1465
1732
    def _startLogFile(self):
1466
 
        """Send bzr and test log messages to a temporary file.
1467
 
 
1468
 
        The file is removed as the test is torn down.
1469
 
        """
1470
 
        self._log_file = StringIO()
1471
 
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
 
1733
        """Setup a in-memory target for bzr and testcase log messages"""
 
1734
        pseudo_log_file = StringIO()
 
1735
        def _get_log_contents_for_weird_testtools_api():
 
1736
            return [pseudo_log_file.getvalue().decode(
 
1737
                "utf-8", "replace").encode("utf-8")]
 
1738
        self.addDetail("log", content.Content(content.ContentType("text",
 
1739
            "plain", {"charset": "utf8"}),
 
1740
            _get_log_contents_for_weird_testtools_api))
 
1741
        self._log_file = pseudo_log_file
 
1742
        self._log_memento = trace.push_log_file(self._log_file)
1472
1743
        self.addCleanup(self._finishLogFile)
1473
1744
 
1474
1745
    def _finishLogFile(self):
1475
 
        """Finished with the log file.
1476
 
 
1477
 
        Close the file and delete it, unless setKeepLogfile was called.
1478
 
        """
1479
 
        if bzrlib.trace._trace_file:
 
1746
        """Flush and dereference the in-memory log for this testcase"""
 
1747
        if trace._trace_file:
1480
1748
            # flush the log file, to get all content
1481
 
            bzrlib.trace._trace_file.flush()
1482
 
        bzrlib.trace.pop_log_file(self._log_memento)
1483
 
        # Cache the log result and delete the file on disk
1484
 
        self._get_log(False)
 
1749
            trace._trace_file.flush()
 
1750
        trace.pop_log_file(self._log_memento)
 
1751
        # The logging module now tracks references for cleanup so discard ours
 
1752
        del self._log_memento
1485
1753
 
1486
1754
    def thisFailsStrictLockCheck(self):
1487
1755
        """It is known that this test would fail with -Dstrict_locks.
1499
1767
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1500
1768
        """Overrides an object attribute restoring it after the test.
1501
1769
 
 
1770
        :note: This should be used with discretion; you should think about
 
1771
        whether it's better to make the code testable without monkey-patching.
 
1772
 
1502
1773
        :param obj: The object that will be mutated.
1503
1774
 
1504
1775
        :param attr_name: The attribute name we want to preserve/override in
1515
1786
            setattr(obj, attr_name, new)
1516
1787
        return value
1517
1788
 
 
1789
    def overrideEnv(self, name, new):
 
1790
        """Set an environment variable, and reset it after the test.
 
1791
 
 
1792
        :param name: The environment variable name.
 
1793
 
 
1794
        :param new: The value to set the variable to. If None, the 
 
1795
            variable is deleted from the environment.
 
1796
 
 
1797
        :returns: The actual variable value.
 
1798
        """
 
1799
        value = osutils.set_or_unset_env(name, new)
 
1800
        self.addCleanup(osutils.set_or_unset_env, name, value)
 
1801
        return value
 
1802
 
 
1803
    def recordCalls(self, obj, attr_name):
 
1804
        """Monkeypatch in a wrapper that will record calls.
 
1805
 
 
1806
        The monkeypatch is automatically removed when the test concludes.
 
1807
 
 
1808
        :param obj: The namespace holding the reference to be replaced;
 
1809
            typically a module, class, or object.
 
1810
        :param attr_name: A string for the name of the attribute to 
 
1811
            patch.
 
1812
        :returns: A list that will be extended with one item every time the
 
1813
            function is called, with a tuple of (args, kwargs).
 
1814
        """
 
1815
        calls = []
 
1816
 
 
1817
        def decorator(*args, **kwargs):
 
1818
            calls.append((args, kwargs))
 
1819
            return orig(*args, **kwargs)
 
1820
        orig = self.overrideAttr(obj, attr_name, decorator)
 
1821
        return calls
 
1822
 
1518
1823
    def _cleanEnvironment(self):
1519
 
        new_env = {
1520
 
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
1521
 
            'HOME': os.getcwd(),
1522
 
            # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
1523
 
            # tests do check our impls match APPDATA
1524
 
            'BZR_EDITOR': None, # test_msgeditor manipulates this variable
1525
 
            'VISUAL': None,
1526
 
            'EDITOR': None,
1527
 
            'BZR_EMAIL': None,
1528
 
            'BZREMAIL': None, # may still be present in the environment
1529
 
            'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
1530
 
            'BZR_PROGRESS_BAR': None,
1531
 
            'BZR_LOG': None,
1532
 
            'BZR_PLUGIN_PATH': None,
1533
 
            'BZR_DISABLE_PLUGINS': None,
1534
 
            'BZR_PLUGINS_AT': None,
1535
 
            'BZR_CONCURRENCY': None,
1536
 
            # Make sure that any text ui tests are consistent regardless of
1537
 
            # the environment the test case is run in; you may want tests that
1538
 
            # test other combinations.  'dumb' is a reasonable guess for tests
1539
 
            # going to a pipe or a StringIO.
1540
 
            'TERM': 'dumb',
1541
 
            'LINES': '25',
1542
 
            'COLUMNS': '80',
1543
 
            'BZR_COLUMNS': '80',
1544
 
            # SSH Agent
1545
 
            'SSH_AUTH_SOCK': None,
1546
 
            # Proxies
1547
 
            'http_proxy': None,
1548
 
            'HTTP_PROXY': None,
1549
 
            'https_proxy': None,
1550
 
            'HTTPS_PROXY': None,
1551
 
            'no_proxy': None,
1552
 
            'NO_PROXY': None,
1553
 
            'all_proxy': None,
1554
 
            'ALL_PROXY': None,
1555
 
            # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
1556
 
            # least. If you do (care), please update this comment
1557
 
            # -- vila 20080401
1558
 
            'ftp_proxy': None,
1559
 
            'FTP_PROXY': None,
1560
 
            'BZR_REMOTE_PATH': None,
1561
 
            # Generally speaking, we don't want apport reporting on crashes in
1562
 
            # the test envirnoment unless we're specifically testing apport,
1563
 
            # so that it doesn't leak into the real system environment.  We
1564
 
            # use an env var so it propagates to subprocesses.
1565
 
            'APPORT_DISABLE': '1',
1566
 
        }
1567
 
        self._old_env = {}
1568
 
        self.addCleanup(self._restoreEnvironment)
1569
 
        for name, value in new_env.iteritems():
1570
 
            self._captureVar(name, value)
1571
 
 
1572
 
    def _captureVar(self, name, newvalue):
1573
 
        """Set an environment variable, and reset it when finished."""
1574
 
        self._old_env[name] = osutils.set_or_unset_env(name, newvalue)
1575
 
 
1576
 
    def _restoreEnvironment(self):
1577
 
        for name, value in self._old_env.iteritems():
1578
 
            osutils.set_or_unset_env(name, value)
 
1824
        for name, value in isolated_environ.iteritems():
 
1825
            self.overrideEnv(name, value)
1579
1826
 
1580
1827
    def _restoreHooks(self):
1581
1828
        for klass, (name, hooks) in self._preserved_hooks.items():
1582
1829
            setattr(klass, name, hooks)
 
1830
        self._preserved_hooks.clear()
 
1831
        bzrlib.hooks._lazy_hooks = self._preserved_lazy_hooks
 
1832
        self._preserved_lazy_hooks.clear()
1583
1833
 
1584
1834
    def knownFailure(self, reason):
1585
 
        """This test has failed for some known reason."""
1586
 
        raise KnownFailure(reason)
 
1835
        """Declare that this test fails for a known reason
 
1836
 
 
1837
        Tests that are known to fail should generally be using expectedFailure
 
1838
        with an appropriate reverse assertion if a change could cause the test
 
1839
        to start passing. Conversely if the test has no immediate prospect of
 
1840
        succeeding then using skip is more suitable.
 
1841
 
 
1842
        When this method is called while an exception is being handled, that
 
1843
        traceback will be used, otherwise a new exception will be thrown to
 
1844
        provide one but won't be reported.
 
1845
        """
 
1846
        self._add_reason(reason)
 
1847
        try:
 
1848
            exc_info = sys.exc_info()
 
1849
            if exc_info != (None, None, None):
 
1850
                self._report_traceback(exc_info)
 
1851
            else:
 
1852
                try:
 
1853
                    raise self.failureException(reason)
 
1854
                except self.failureException:
 
1855
                    exc_info = sys.exc_info()
 
1856
            # GZ 02-08-2011: Maybe cleanup this err.exc_info attribute too?
 
1857
            raise testtools.testcase._ExpectedFailure(exc_info)
 
1858
        finally:
 
1859
            del exc_info
1587
1860
 
1588
1861
    def _suppress_log(self):
1589
1862
        """Remove the log info from details."""
1675
1948
            self._benchtime += time.time() - start
1676
1949
 
1677
1950
    def log(self, *args):
1678
 
        mutter(*args)
1679
 
 
1680
 
    def _get_log(self, keep_log_file=False):
1681
 
        """Internal helper to get the log from bzrlib.trace for this test.
1682
 
 
1683
 
        Please use self.getDetails, or self.get_log to access this in test case
1684
 
        code.
1685
 
 
1686
 
        :param keep_log_file: When True, if the log is still a file on disk
1687
 
            leave it as a file on disk. When False, if the log is still a file
1688
 
            on disk, the log file is deleted and the log preserved as
1689
 
            self._log_contents.
1690
 
        :return: A string containing the log.
1691
 
        """
1692
 
        if self._log_contents is not None:
1693
 
            try:
1694
 
                self._log_contents.decode('utf8')
1695
 
            except UnicodeDecodeError:
1696
 
                unicodestr = self._log_contents.decode('utf8', 'replace')
1697
 
                self._log_contents = unicodestr.encode('utf8')
1698
 
            return self._log_contents
1699
 
        if self._log_file is not None:
1700
 
            log_contents = self._log_file.getvalue()
1701
 
            try:
1702
 
                log_contents.decode('utf8')
1703
 
            except UnicodeDecodeError:
1704
 
                unicodestr = log_contents.decode('utf8', 'replace')
1705
 
                log_contents = unicodestr.encode('utf8')
1706
 
            if not keep_log_file:
1707
 
                self._log_file = None
1708
 
                # Permit multiple calls to get_log until we clean it up in
1709
 
                # finishLogFile
1710
 
                self._log_contents = log_contents
1711
 
            return log_contents
1712
 
        else:
1713
 
            return "No log file content."
 
1951
        trace.mutter(*args)
1714
1952
 
1715
1953
    def get_log(self):
1716
1954
        """Get a unicode string containing the log from bzrlib.trace.
1752
1990
 
1753
1991
        self.log('run bzr: %r', args)
1754
1992
        # FIXME: don't call into logging here
1755
 
        handler = logging.StreamHandler(stderr)
1756
 
        handler.setLevel(logging.INFO)
 
1993
        handler = trace.EncodedStreamHandler(stderr, errors="replace",
 
1994
            level=logging.INFO)
1757
1995
        logger = logging.getLogger('')
1758
1996
        logger.addHandler(handler)
1759
1997
        old_ui_factory = ui.ui_factory
1766
2004
 
1767
2005
        try:
1768
2006
            try:
1769
 
                result = self.apply_redirected(ui.ui_factory.stdin,
 
2007
                result = self.apply_redirected(
 
2008
                    ui.ui_factory.stdin,
1770
2009
                    stdout, stderr,
1771
 
                    bzrlib.commands.run_bzr_catch_user_errors,
 
2010
                    _mod_commands.run_bzr_catch_user_errors,
1772
2011
                    args)
1773
2012
            except KeyboardInterrupt:
1774
2013
                # Reraise KeyboardInterrupt with contents of redirected stdout
1916
2155
    def start_bzr_subprocess(self, process_args, env_changes=None,
1917
2156
                             skip_if_plan_to_signal=False,
1918
2157
                             working_dir=None,
1919
 
                             allow_plugins=False):
 
2158
                             allow_plugins=False, stderr=subprocess.PIPE):
1920
2159
        """Start bzr in a subprocess for testing.
1921
2160
 
1922
2161
        This starts a new Python interpreter and runs bzr in there.
1934
2173
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
1935
2174
            doesn't support signalling subprocesses.
1936
2175
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
 
2176
        :param stderr: file to use for the subprocess's stderr.  Valid values
 
2177
            are those valid for the stderr argument of `subprocess.Popen`.
 
2178
            Default value is ``subprocess.PIPE``.
1937
2179
 
1938
2180
        :returns: Popen object for the started process.
1939
2181
        """
1943
2185
 
1944
2186
        if env_changes is None:
1945
2187
            env_changes = {}
 
2188
        # Because $HOME is set to a tempdir for the context of a test, modules
 
2189
        # installed in the user dir will not be found unless $PYTHONUSERBASE
 
2190
        # gets set to the computed directory of this parent process.
 
2191
        if site.USER_BASE is not None:
 
2192
            env_changes["PYTHONUSERBASE"] = site.USER_BASE
1946
2193
        old_env = {}
1947
2194
 
1948
2195
        def cleanup_environment():
1965
2212
            # so we will avoid using it on all platforms, just to
1966
2213
            # make sure the code path is used, and we don't break on win32
1967
2214
            cleanup_environment()
 
2215
            # Include the subprocess's log file in the test details, in case
 
2216
            # the test fails due to an error in the subprocess.
 
2217
            self._add_subprocess_log(trace._get_bzr_log_filename())
1968
2218
            command = [sys.executable]
1969
2219
            # frozen executables don't need the path to bzr
1970
2220
            if getattr(sys, "frozen", None) is None:
1974
2224
            command.extend(process_args)
1975
2225
            process = self._popen(command, stdin=subprocess.PIPE,
1976
2226
                                  stdout=subprocess.PIPE,
1977
 
                                  stderr=subprocess.PIPE)
 
2227
                                  stderr=stderr)
1978
2228
        finally:
1979
2229
            restore_environment()
1980
2230
            if cwd is not None:
1982
2232
 
1983
2233
        return process
1984
2234
 
 
2235
    def _add_subprocess_log(self, log_file_path):
 
2236
        if len(self._log_files) == 0:
 
2237
            # Register an addCleanup func.  We do this on the first call to
 
2238
            # _add_subprocess_log rather than in TestCase.setUp so that this
 
2239
            # addCleanup is registered after any cleanups for tempdirs that
 
2240
            # subclasses might create, which will probably remove the log file
 
2241
            # we want to read.
 
2242
            self.addCleanup(self._subprocess_log_cleanup)
 
2243
        # self._log_files is a set, so if a log file is reused we won't grab it
 
2244
        # twice.
 
2245
        self._log_files.add(log_file_path)
 
2246
 
 
2247
    def _subprocess_log_cleanup(self):
 
2248
        for count, log_file_path in enumerate(self._log_files):
 
2249
            # We use buffer_now=True to avoid holding the file open beyond
 
2250
            # the life of this function, which might interfere with e.g.
 
2251
            # cleaning tempdirs on Windows.
 
2252
            # XXX: Testtools 0.9.5 doesn't have the content_from_file helper
 
2253
            #detail_content = content.content_from_file(
 
2254
            #    log_file_path, buffer_now=True)
 
2255
            with open(log_file_path, 'rb') as log_file:
 
2256
                log_file_bytes = log_file.read()
 
2257
            detail_content = content.Content(content.ContentType("text",
 
2258
                "plain", {"charset": "utf8"}), lambda: [log_file_bytes])
 
2259
            self.addDetail("start_bzr_subprocess-log-%d" % (count,),
 
2260
                detail_content)
 
2261
 
1985
2262
    def _popen(self, *args, **kwargs):
1986
2263
        """Place a call to Popen.
1987
2264
 
2024
2301
        if retcode is not None and retcode != process.returncode:
2025
2302
            if process_args is None:
2026
2303
                process_args = "(unknown args)"
2027
 
            mutter('Output of bzr %s:\n%s', process_args, out)
2028
 
            mutter('Error for bzr %s:\n%s', process_args, err)
 
2304
            trace.mutter('Output of bzr %s:\n%s', process_args, out)
 
2305
            trace.mutter('Error for bzr %s:\n%s', process_args, err)
2029
2306
            self.fail('Command bzr %s failed with retcode %s != %s'
2030
2307
                      % (process_args, retcode, process.returncode))
2031
2308
        return [out, err]
2032
2309
 
2033
 
    def check_inventory_shape(self, inv, shape):
2034
 
        """Compare an inventory to a list of expected names.
 
2310
    def check_tree_shape(self, tree, shape):
 
2311
        """Compare a tree to a list of expected names.
2035
2312
 
2036
2313
        Fail if they are not precisely equal.
2037
2314
        """
2038
2315
        extras = []
2039
2316
        shape = list(shape)             # copy
2040
 
        for path, ie in inv.entries():
 
2317
        for path, ie in tree.iter_entries_by_dir():
2041
2318
            name = path.replace('\\', '/')
2042
2319
            if ie.kind == 'directory':
2043
2320
                name = name + '/'
2044
 
            if name in shape:
 
2321
            if name == "/":
 
2322
                pass # ignore root entry
 
2323
            elif name in shape:
2045
2324
                shape.remove(name)
2046
2325
            else:
2047
2326
                extras.append(name)
2088
2367
 
2089
2368
        Tests that expect to provoke LockContention errors should call this.
2090
2369
        """
2091
 
        self.overrideAttr(bzrlib.lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
 
2370
        self.overrideAttr(lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
2092
2371
 
2093
2372
    def make_utf8_encoded_stringio(self, encoding_type=None):
2094
2373
        """Return a StringIOWrapper instance, that will encode Unicode
2107
2386
        from bzrlib.smart import request
2108
2387
        request_handlers = request.request_handlers
2109
2388
        orig_method = request_handlers.get(verb)
 
2389
        orig_info = request_handlers.get_info(verb)
2110
2390
        request_handlers.remove(verb)
2111
 
        self.addCleanup(request_handlers.register, verb, orig_method)
 
2391
        self.addCleanup(request_handlers.register, verb, orig_method,
 
2392
            info=orig_info)
2112
2393
 
2113
2394
 
2114
2395
class CapturedCall(object):
2137
2418
class TestCaseWithMemoryTransport(TestCase):
2138
2419
    """Common test class for tests that do not need disk resources.
2139
2420
 
2140
 
    Tests that need disk resources should derive from TestCaseWithTransport.
 
2421
    Tests that need disk resources should derive from TestCaseInTempDir
 
2422
    orTestCaseWithTransport.
2141
2423
 
2142
2424
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2143
2425
 
2144
 
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
 
2426
    For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
2145
2427
    a directory which does not exist. This serves to help ensure test isolation
2146
 
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
2147
 
    must exist. However, TestCaseWithMemoryTransport does not offer local
2148
 
    file defaults for the transport in tests, nor does it obey the command line
 
2428
    is preserved. ``test_dir`` is set to the TEST_ROOT, as is cwd, because they
 
2429
    must exist. However, TestCaseWithMemoryTransport does not offer local file
 
2430
    defaults for the transport in tests, nor does it obey the command line
2149
2431
    override, so tests that accidentally write to the common directory should
2150
2432
    be rare.
2151
2433
 
2152
 
    :cvar TEST_ROOT: Directory containing all temporary directories, plus
2153
 
    a .bzr directory that stops us ascending higher into the filesystem.
 
2434
    :cvar TEST_ROOT: Directory containing all temporary directories, plus a
 
2435
        ``.bzr`` directory that stops us ascending higher into the filesystem.
2154
2436
    """
2155
2437
 
2156
2438
    TEST_ROOT = None
2174
2456
 
2175
2457
        :param relpath: a path relative to the base url.
2176
2458
        """
2177
 
        t = _mod_transport.get_transport(self.get_url(relpath))
 
2459
        t = _mod_transport.get_transport_from_url(self.get_url(relpath))
2178
2460
        self.assertFalse(t.is_readonly())
2179
2461
        return t
2180
2462
 
2186
2468
 
2187
2469
        :param relpath: a path relative to the base url.
2188
2470
        """
2189
 
        t = _mod_transport.get_transport(self.get_readonly_url(relpath))
 
2471
        t = _mod_transport.get_transport_from_url(
 
2472
            self.get_readonly_url(relpath))
2190
2473
        self.assertTrue(t.is_readonly())
2191
2474
        return t
2192
2475
 
2313
2596
        real branch.
2314
2597
        """
2315
2598
        root = TestCaseWithMemoryTransport.TEST_ROOT
2316
 
        bzrdir.BzrDir.create_standalone_workingtree(root)
 
2599
        # Make sure we get a readable and accessible home for .bzr.log
 
2600
        # and/or config files, and not fallback to weird defaults (see
 
2601
        # http://pad.lv/825027).
 
2602
        self.assertIs(None, os.environ.get('BZR_HOME', None))
 
2603
        os.environ['BZR_HOME'] = root
 
2604
        wt = bzrdir.BzrDir.create_standalone_workingtree(root)
 
2605
        del os.environ['BZR_HOME']
 
2606
        # Hack for speed: remember the raw bytes of the dirstate file so that
 
2607
        # we don't need to re-open the wt to check it hasn't changed.
 
2608
        TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE = (
 
2609
            wt.control_transport.get_bytes('dirstate'))
2317
2610
 
2318
2611
    def _check_safety_net(self):
2319
2612
        """Check that the safety .bzr directory have not been touched.
2322
2615
        propagating. This method ensures than a test did not leaked.
2323
2616
        """
2324
2617
        root = TestCaseWithMemoryTransport.TEST_ROOT
2325
 
        self.permit_url(_mod_transport.get_transport(root).base)
2326
 
        wt = workingtree.WorkingTree.open(root)
2327
 
        last_rev = wt.last_revision()
2328
 
        if last_rev != 'null:':
 
2618
        t = _mod_transport.get_transport_from_path(root)
 
2619
        self.permit_url(t.base)
 
2620
        if (t.get_bytes('.bzr/checkout/dirstate') != 
 
2621
                TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE):
2329
2622
            # The current test have modified the /bzr directory, we need to
2330
2623
            # recreate a new one or all the followng tests will fail.
2331
2624
            # If you need to inspect its content uncomment the following line
2366
2659
    def make_branch(self, relpath, format=None):
2367
2660
        """Create a branch on the transport at relpath."""
2368
2661
        repo = self.make_repository(relpath, format=format)
2369
 
        return repo.bzrdir.create_branch()
 
2662
        return repo.bzrdir.create_branch(append_revisions_only=False)
 
2663
 
 
2664
    def get_default_format(self):
 
2665
        return 'default'
 
2666
 
 
2667
    def resolve_format(self, format):
 
2668
        """Resolve an object to a ControlDir format object.
 
2669
 
 
2670
        The initial format object can either already be
 
2671
        a ControlDirFormat, None (for the default format),
 
2672
        or a string with the name of the control dir format.
 
2673
 
 
2674
        :param format: Object to resolve
 
2675
        :return A ControlDirFormat instance
 
2676
        """
 
2677
        if format is None:
 
2678
            format = self.get_default_format()
 
2679
        if isinstance(format, basestring):
 
2680
            format = bzrdir.format_registry.make_bzrdir(format)
 
2681
        return format
2370
2682
 
2371
2683
    def make_bzrdir(self, relpath, format=None):
2372
2684
        try:
2376
2688
            t = _mod_transport.get_transport(maybe_a_url)
2377
2689
            if len(segments) > 1 and segments[-1] not in ('', '.'):
2378
2690
                t.ensure_base()
2379
 
            if format is None:
2380
 
                format = 'default'
2381
 
            if isinstance(format, basestring):
2382
 
                format = bzrdir.format_registry.make_bzrdir(format)
 
2691
            format = self.resolve_format(format)
2383
2692
            return format.initialize_on_transport(t)
2384
2693
        except errors.UninitializableFormat:
2385
2694
            raise TestSkipped("Format %s is not initializable." % format)
2386
2695
 
2387
 
    def make_repository(self, relpath, shared=False, format=None):
 
2696
    def make_repository(self, relpath, shared=None, format=None):
2388
2697
        """Create a repository on our default transport at relpath.
2389
2698
 
2390
2699
        Note that relpath must be a relative path, not a full url.
2401
2710
            backing_server = self.get_server()
2402
2711
        smart_server = test_server.SmartTCPServer_for_testing()
2403
2712
        self.start_server(smart_server, backing_server)
2404
 
        remote_transport = _mod_transport.get_transport(smart_server.get_url()
 
2713
        remote_transport = _mod_transport.get_transport_from_url(smart_server.get_url()
2405
2714
                                                   ).clone(path)
2406
2715
        return remote_transport
2407
2716
 
2418
2727
        test_home_dir = self.test_home_dir
2419
2728
        if isinstance(test_home_dir, unicode):
2420
2729
            test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
2421
 
        os.environ['HOME'] = test_home_dir
2422
 
        os.environ['BZR_HOME'] = test_home_dir
 
2730
        self.overrideEnv('HOME', test_home_dir)
 
2731
        self.overrideEnv('BZR_HOME', test_home_dir)
2423
2732
 
2424
2733
    def setUp(self):
2425
2734
        super(TestCaseWithMemoryTransport, self).setUp()
2426
2735
        # Ensure that ConnectedTransport doesn't leak sockets
2427
 
        def get_transport_with_cleanup(*args, **kwargs):
2428
 
            t = orig_get_transport(*args, **kwargs)
 
2736
        def get_transport_from_url_with_cleanup(*args, **kwargs):
 
2737
            t = orig_get_transport_from_url(*args, **kwargs)
2429
2738
            if isinstance(t, _mod_transport.ConnectedTransport):
2430
2739
                self.addCleanup(t.disconnect)
2431
2740
            return t
2432
2741
 
2433
 
        orig_get_transport = self.overrideAttr(_mod_transport, 'get_transport',
2434
 
                                               get_transport_with_cleanup)
 
2742
        orig_get_transport_from_url = self.overrideAttr(
 
2743
            _mod_transport, 'get_transport_from_url',
 
2744
            get_transport_from_url_with_cleanup)
2435
2745
        self._make_test_root()
2436
2746
        self.addCleanup(os.chdir, os.getcwdu())
2437
2747
        self.makeAndChdirToTestDir()
2480
2790
 
2481
2791
    OVERRIDE_PYTHON = 'python'
2482
2792
 
 
2793
    def setUp(self):
 
2794
        super(TestCaseInTempDir, self).setUp()
 
2795
        # Remove the protection set in isolated_environ, we have a proper
 
2796
        # access to disk resources now.
 
2797
        self.overrideEnv('BZR_LOG', None)
 
2798
 
2483
2799
    def check_file_contents(self, filename, expect):
2484
2800
        self.log("check contents of file %s" % filename)
2485
2801
        f = file(filename)
2566
2882
                "a list or a tuple. Got %r instead" % (shape,))
2567
2883
        # It's OK to just create them using forward slashes on windows.
2568
2884
        if transport is None or transport.is_readonly():
2569
 
            transport = _mod_transport.get_transport(".")
 
2885
            transport = _mod_transport.get_transport_from_path(".")
2570
2886
        for name in shape:
2571
2887
            self.assertIsInstance(name, basestring)
2572
2888
            if name[-1] == '/':
2657
2973
        # this obviously requires a format that supports branch references
2658
2974
        # so check for that by checking bzrdir.BzrDirFormat.get_default_format()
2659
2975
        # RBC 20060208
 
2976
        format = self.resolve_format(format=format)
 
2977
        if not format.supports_workingtrees:
 
2978
            b = self.make_branch(relpath+'.branch', format=format)
 
2979
            return b.create_checkout(relpath, lightweight=True)
2660
2980
        b = self.make_branch(relpath, format=format)
2661
2981
        try:
2662
2982
            return b.bzrdir.create_workingtree()
2961
3281
                            result_decorators=result_decorators,
2962
3282
                            )
2963
3283
    runner.stop_on_failure=stop_on_failure
 
3284
    if isinstance(suite, unittest.TestSuite):
 
3285
        # Empty out _tests list of passed suite and populate new TestSuite
 
3286
        suite._tests[:], suite = [], TestSuite(suite)
2964
3287
    # built in decorator factories:
2965
3288
    decorators = [
2966
3289
        random_order(random_seed, runner),
3064
3387
 
3065
3388
class TestDecorator(TestUtil.TestSuite):
3066
3389
    """A decorator for TestCase/TestSuite objects.
3067
 
    
3068
 
    Usually, subclasses should override __iter__(used when flattening test
3069
 
    suites), which we do to filter, reorder, parallelise and so on, run() and
3070
 
    debug().
 
3390
 
 
3391
    Contains rather than flattening suite passed on construction
3071
3392
    """
3072
3393
 
3073
 
    def __init__(self, suite):
3074
 
        TestUtil.TestSuite.__init__(self)
3075
 
        self.addTest(suite)
3076
 
 
3077
 
    def countTestCases(self):
3078
 
        cases = 0
3079
 
        for test in self:
3080
 
            cases += test.countTestCases()
3081
 
        return cases
3082
 
 
3083
 
    def debug(self):
3084
 
        for test in self:
3085
 
            test.debug()
3086
 
 
3087
 
    def run(self, result):
3088
 
        # Use iteration on self, not self._tests, to allow subclasses to hook
3089
 
        # into __iter__.
3090
 
        for test in self:
3091
 
            if result.shouldStop:
3092
 
                break
3093
 
            test.run(result)
3094
 
        return result
 
3394
    def __init__(self, suite=None):
 
3395
        super(TestDecorator, self).__init__()
 
3396
        if suite is not None:
 
3397
            self.addTest(suite)
 
3398
 
 
3399
    # Don't need subclass run method with suite emptying
 
3400
    run = unittest.TestSuite.run
3095
3401
 
3096
3402
 
3097
3403
class CountingDecorator(TestDecorator):
3108
3414
    """A decorator which excludes test matching an exclude pattern."""
3109
3415
 
3110
3416
    def __init__(self, suite, exclude_pattern):
3111
 
        TestDecorator.__init__(self, suite)
3112
 
        self.exclude_pattern = exclude_pattern
3113
 
        self.excluded = False
3114
 
 
3115
 
    def __iter__(self):
3116
 
        if self.excluded:
3117
 
            return iter(self._tests)
3118
 
        self.excluded = True
3119
 
        suite = exclude_tests_by_re(self, self.exclude_pattern)
3120
 
        del self._tests[:]
3121
 
        self.addTests(suite)
3122
 
        return iter(self._tests)
 
3417
        super(ExcludeDecorator, self).__init__(
 
3418
            exclude_tests_by_re(suite, exclude_pattern))
3123
3419
 
3124
3420
 
3125
3421
class FilterTestsDecorator(TestDecorator):
3126
3422
    """A decorator which filters tests to those matching a pattern."""
3127
3423
 
3128
3424
    def __init__(self, suite, pattern):
3129
 
        TestDecorator.__init__(self, suite)
3130
 
        self.pattern = pattern
3131
 
        self.filtered = False
3132
 
 
3133
 
    def __iter__(self):
3134
 
        if self.filtered:
3135
 
            return iter(self._tests)
3136
 
        self.filtered = True
3137
 
        suite = filter_suite_by_re(self, self.pattern)
3138
 
        del self._tests[:]
3139
 
        self.addTests(suite)
3140
 
        return iter(self._tests)
 
3425
        super(FilterTestsDecorator, self).__init__(
 
3426
            filter_suite_by_re(suite, pattern))
3141
3427
 
3142
3428
 
3143
3429
class RandomDecorator(TestDecorator):
3144
3430
    """A decorator which randomises the order of its tests."""
3145
3431
 
3146
3432
    def __init__(self, suite, random_seed, stream):
3147
 
        TestDecorator.__init__(self, suite)
3148
 
        self.random_seed = random_seed
3149
 
        self.randomised = False
3150
 
        self.stream = stream
3151
 
 
3152
 
    def __iter__(self):
3153
 
        if self.randomised:
3154
 
            return iter(self._tests)
3155
 
        self.randomised = True
3156
 
        self.stream.write("Randomizing test order using seed %s\n\n" %
3157
 
            (self.actual_seed()))
 
3433
        random_seed = self.actual_seed(random_seed)
 
3434
        stream.write("Randomizing test order using seed %s\n\n" %
 
3435
            (random_seed,))
3158
3436
        # Initialise the random number generator.
3159
 
        random.seed(self.actual_seed())
3160
 
        suite = randomize_suite(self)
3161
 
        del self._tests[:]
3162
 
        self.addTests(suite)
3163
 
        return iter(self._tests)
 
3437
        random.seed(random_seed)
 
3438
        super(RandomDecorator, self).__init__(randomize_suite(suite))
3164
3439
 
3165
 
    def actual_seed(self):
3166
 
        if self.random_seed == "now":
 
3440
    @staticmethod
 
3441
    def actual_seed(seed):
 
3442
        if seed == "now":
3167
3443
            # We convert the seed to a long to make it reuseable across
3168
3444
            # invocations (because the user can reenter it).
3169
 
            self.random_seed = long(time.time())
 
3445
            return long(time.time())
3170
3446
        else:
3171
3447
            # Convert the seed to a long if we can
3172
3448
            try:
3173
 
                self.random_seed = long(self.random_seed)
3174
 
            except:
 
3449
                return long(seed)
 
3450
            except (TypeError, ValueError):
3175
3451
                pass
3176
 
        return self.random_seed
 
3452
        return seed
3177
3453
 
3178
3454
 
3179
3455
class TestFirstDecorator(TestDecorator):
3180
3456
    """A decorator which moves named tests to the front."""
3181
3457
 
3182
3458
    def __init__(self, suite, pattern):
3183
 
        TestDecorator.__init__(self, suite)
3184
 
        self.pattern = pattern
3185
 
        self.filtered = False
3186
 
 
3187
 
    def __iter__(self):
3188
 
        if self.filtered:
3189
 
            return iter(self._tests)
3190
 
        self.filtered = True
3191
 
        suites = split_suite_by_re(self, self.pattern)
3192
 
        del self._tests[:]
3193
 
        self.addTests(suites)
3194
 
        return iter(self._tests)
 
3459
        super(TestFirstDecorator, self).__init__()
 
3460
        self.addTests(split_suite_by_re(suite, pattern))
3195
3461
 
3196
3462
 
3197
3463
def partition_tests(suite, count):
3229
3495
    """
3230
3496
    concurrency = osutils.local_concurrency()
3231
3497
    result = []
3232
 
    from subunit import TestProtocolClient, ProtocolTestCase
 
3498
    from subunit import ProtocolTestCase
3233
3499
    from subunit.test_results import AutoTimingTestResultDecorator
3234
3500
    class TestInOtherProcess(ProtocolTestCase):
3235
3501
        # Should be in subunit, I think. RBC.
3241
3507
            try:
3242
3508
                ProtocolTestCase.run(self, result)
3243
3509
            finally:
3244
 
                os.waitpid(self.pid, 0)
 
3510
                pid, status = os.waitpid(self.pid, 0)
 
3511
            # GZ 2011-10-18: If status is nonzero, should report to the result
 
3512
            #                that something went wrong.
3245
3513
 
3246
3514
    test_blocks = partition_tests(suite, concurrency)
 
3515
    # Clear the tests from the original suite so it doesn't keep them alive
 
3516
    suite._tests[:] = []
3247
3517
    for process_tests in test_blocks:
3248
 
        process_suite = TestUtil.TestSuite()
3249
 
        process_suite.addTests(process_tests)
 
3518
        process_suite = TestUtil.TestSuite(process_tests)
 
3519
        # Also clear each split list so new suite has only reference
 
3520
        process_tests[:] = []
3250
3521
        c2pread, c2pwrite = os.pipe()
3251
3522
        pid = os.fork()
3252
3523
        if pid == 0:
3253
 
            workaround_zealous_crypto_random()
3254
3524
            try:
 
3525
                stream = os.fdopen(c2pwrite, 'wb', 1)
 
3526
                workaround_zealous_crypto_random()
3255
3527
                os.close(c2pread)
3256
3528
                # Leave stderr and stdout open so we can see test noise
3257
3529
                # Close stdin so that the child goes away if it decides to
3258
3530
                # read from stdin (otherwise its a roulette to see what
3259
3531
                # child actually gets keystrokes for pdb etc).
3260
3532
                sys.stdin.close()
3261
 
                sys.stdin = None
3262
 
                stream = os.fdopen(c2pwrite, 'wb', 1)
3263
3533
                subunit_result = AutoTimingTestResultDecorator(
3264
 
                    TestProtocolClient(stream))
 
3534
                    SubUnitBzrProtocolClient(stream))
3265
3535
                process_suite.run(subunit_result)
3266
 
            finally:
3267
 
                os._exit(0)
 
3536
            except:
 
3537
                # Try and report traceback on stream, but exit with error even
 
3538
                # if stream couldn't be created or something else goes wrong.
 
3539
                # The traceback is formatted to a string and written in one go
 
3540
                # to avoid interleaving lines from multiple failing children.
 
3541
                try:
 
3542
                    stream.write(traceback.format_exc())
 
3543
                finally:
 
3544
                    os._exit(1)
 
3545
            os._exit(0)
3268
3546
        else:
3269
3547
            os.close(c2pwrite)
3270
3548
            stream = os.fdopen(c2pread, 'rb', 1)
3331
3609
    return result
3332
3610
 
3333
3611
 
3334
 
class ForwardingResult(unittest.TestResult):
3335
 
 
3336
 
    def __init__(self, target):
3337
 
        unittest.TestResult.__init__(self)
3338
 
        self.result = target
3339
 
 
3340
 
    def startTest(self, test):
3341
 
        self.result.startTest(test)
3342
 
 
3343
 
    def stopTest(self, test):
3344
 
        self.result.stopTest(test)
3345
 
 
3346
 
    def startTestRun(self):
3347
 
        self.result.startTestRun()
3348
 
 
3349
 
    def stopTestRun(self):
3350
 
        self.result.stopTestRun()
3351
 
 
3352
 
    def addSkip(self, test, reason):
3353
 
        self.result.addSkip(test, reason)
3354
 
 
3355
 
    def addSuccess(self, test):
3356
 
        self.result.addSuccess(test)
3357
 
 
3358
 
    def addError(self, test, err):
3359
 
        self.result.addError(test, err)
3360
 
 
3361
 
    def addFailure(self, test, err):
3362
 
        self.result.addFailure(test, err)
3363
 
ForwardingResult = testtools.ExtendedToOriginalDecorator
3364
 
 
3365
 
 
3366
 
class ProfileResult(ForwardingResult):
 
3612
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3367
3613
    """Generate profiling data for all activity between start and success.
3368
3614
    
3369
3615
    The profile data is appended to the test's _benchcalls attribute and can
3381
3627
        # unavoidably fail.
3382
3628
        bzrlib.lsprof.BzrProfiler.profiler_block = 0
3383
3629
        self.profiler.start()
3384
 
        ForwardingResult.startTest(self, test)
 
3630
        testtools.ExtendedToOriginalDecorator.startTest(self, test)
3385
3631
 
3386
3632
    def addSuccess(self, test):
3387
3633
        stats = self.profiler.stop()
3391
3637
            test._benchcalls = []
3392
3638
            calls = test._benchcalls
3393
3639
        calls.append(((test.id(), "", ""), stats))
3394
 
        ForwardingResult.addSuccess(self, test)
 
3640
        testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
3395
3641
 
3396
3642
    def stopTest(self, test):
3397
 
        ForwardingResult.stopTest(self, test)
 
3643
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
3398
3644
        self.profiler = None
3399
3645
 
3400
3646
 
3408
3654
#                           with proper exclusion rules.
3409
3655
#   -Ethreads               Will display thread ident at creation/join time to
3410
3656
#                           help track thread leaks
 
3657
#   -Euncollected_cases     Display the identity of any test cases that weren't
 
3658
#                           deallocated after being completed.
 
3659
#   -Econfig_stats          Will collect statistics using addDetail
3411
3660
selftest_debug_flags = set()
3412
3661
 
3413
3662
 
3607
3856
                key, obj, help=help, info=info, override_existing=False)
3608
3857
        except KeyError:
3609
3858
            actual = self.get(key)
3610
 
            note('Test prefix alias %s is already used for %s, ignoring %s'
3611
 
                 % (key, actual, obj))
 
3859
            trace.note(
 
3860
                'Test prefix alias %s is already used for %s, ignoring %s'
 
3861
                % (key, actual, obj))
3612
3862
 
3613
3863
    def resolve_alias(self, id_start):
3614
3864
        """Replace the alias by the prefix in the given string.
3664
3914
        'bzrlib.tests.per_repository',
3665
3915
        'bzrlib.tests.per_repository_chk',
3666
3916
        'bzrlib.tests.per_repository_reference',
 
3917
        'bzrlib.tests.per_repository_vf',
3667
3918
        'bzrlib.tests.per_uifactory',
3668
3919
        'bzrlib.tests.per_versionedfile',
3669
3920
        'bzrlib.tests.per_workingtree',
3703
3954
        'bzrlib.tests.test_commit_merge',
3704
3955
        'bzrlib.tests.test_config',
3705
3956
        'bzrlib.tests.test_conflicts',
 
3957
        'bzrlib.tests.test_controldir',
3706
3958
        'bzrlib.tests.test_counted_lock',
3707
3959
        'bzrlib.tests.test_crash',
3708
3960
        'bzrlib.tests.test_decorators',
3709
3961
        'bzrlib.tests.test_delta',
3710
3962
        'bzrlib.tests.test_debug',
3711
 
        'bzrlib.tests.test_deprecated_graph',
3712
3963
        'bzrlib.tests.test_diff',
3713
3964
        'bzrlib.tests.test_directory_service',
3714
3965
        'bzrlib.tests.test_dirstate',
3715
3966
        'bzrlib.tests.test_email_message',
3716
3967
        'bzrlib.tests.test_eol_filters',
3717
3968
        'bzrlib.tests.test_errors',
 
3969
        'bzrlib.tests.test_estimate_compressed_size',
3718
3970
        'bzrlib.tests.test_export',
 
3971
        'bzrlib.tests.test_export_pot',
3719
3972
        'bzrlib.tests.test_extract',
 
3973
        'bzrlib.tests.test_features',
3720
3974
        'bzrlib.tests.test_fetch',
3721
3975
        'bzrlib.tests.test_fixtures',
3722
3976
        'bzrlib.tests.test_fifo_cache',
3723
3977
        'bzrlib.tests.test_filters',
 
3978
        'bzrlib.tests.test_filter_tree',
3724
3979
        'bzrlib.tests.test_ftp_transport',
3725
3980
        'bzrlib.tests.test_foreign',
3726
3981
        'bzrlib.tests.test_generate_docs',
3735
3990
        'bzrlib.tests.test_http',
3736
3991
        'bzrlib.tests.test_http_response',
3737
3992
        'bzrlib.tests.test_https_ca_bundle',
 
3993
        'bzrlib.tests.test_i18n',
3738
3994
        'bzrlib.tests.test_identitymap',
3739
3995
        'bzrlib.tests.test_ignores',
3740
3996
        'bzrlib.tests.test_index',
3759
4015
        'bzrlib.tests.test_merge3',
3760
4016
        'bzrlib.tests.test_merge_core',
3761
4017
        'bzrlib.tests.test_merge_directive',
 
4018
        'bzrlib.tests.test_mergetools',
3762
4019
        'bzrlib.tests.test_missing',
3763
4020
        'bzrlib.tests.test_msgeditor',
3764
4021
        'bzrlib.tests.test_multiparent',
3773
4030
        'bzrlib.tests.test_permissions',
3774
4031
        'bzrlib.tests.test_plugins',
3775
4032
        'bzrlib.tests.test_progress',
 
4033
        'bzrlib.tests.test_pyutils',
3776
4034
        'bzrlib.tests.test_read_bundle',
3777
4035
        'bzrlib.tests.test_reconcile',
3778
4036
        'bzrlib.tests.test_reconfigure',
3787
4045
        'bzrlib.tests.test_rio',
3788
4046
        'bzrlib.tests.test_rules',
3789
4047
        'bzrlib.tests.test_sampler',
 
4048
        'bzrlib.tests.test_scenarios',
3790
4049
        'bzrlib.tests.test_script',
3791
4050
        'bzrlib.tests.test_selftest',
3792
4051
        'bzrlib.tests.test_serializer',
3797
4056
        'bzrlib.tests.test_smart',
3798
4057
        'bzrlib.tests.test_smart_add',
3799
4058
        'bzrlib.tests.test_smart_request',
 
4059
        'bzrlib.tests.test_smart_signals',
3800
4060
        'bzrlib.tests.test_smart_transport',
3801
4061
        'bzrlib.tests.test_smtp_connection',
3802
4062
        'bzrlib.tests.test_source',
3812
4072
        'bzrlib.tests.test_testament',
3813
4073
        'bzrlib.tests.test_textfile',
3814
4074
        'bzrlib.tests.test_textmerge',
 
4075
        'bzrlib.tests.test_cethread',
3815
4076
        'bzrlib.tests.test_timestamp',
3816
4077
        'bzrlib.tests.test_trace',
3817
4078
        'bzrlib.tests.test_transactions',
3828
4089
        'bzrlib.tests.test_upgrade',
3829
4090
        'bzrlib.tests.test_upgrade_stacked',
3830
4091
        'bzrlib.tests.test_urlutils',
 
4092
        'bzrlib.tests.test_utextwrap',
3831
4093
        'bzrlib.tests.test_version',
3832
4094
        'bzrlib.tests.test_version_info',
3833
4095
        'bzrlib.tests.test_versionedfile',
 
4096
        'bzrlib.tests.test_vf_search',
3834
4097
        'bzrlib.tests.test_weave',
3835
4098
        'bzrlib.tests.test_whitebox',
3836
4099
        'bzrlib.tests.test_win32utils',
3850
4113
        'bzrlib',
3851
4114
        'bzrlib.branchbuilder',
3852
4115
        'bzrlib.decorators',
3853
 
        'bzrlib.export',
3854
4116
        'bzrlib.inventory',
3855
4117
        'bzrlib.iterablefile',
3856
4118
        'bzrlib.lockdir',
3857
4119
        'bzrlib.merge3',
3858
4120
        'bzrlib.option',
 
4121
        'bzrlib.pyutils',
3859
4122
        'bzrlib.symbol_versioning',
3860
4123
        'bzrlib.tests',
3861
4124
        'bzrlib.tests.fixtures',
3862
4125
        'bzrlib.timestamp',
 
4126
        'bzrlib.transport.http',
3863
4127
        'bzrlib.version_info_formats.format_custom',
3864
4128
        ]
3865
4129
 
3918
4182
        try:
3919
4183
            # note that this really does mean "report only" -- doctest
3920
4184
            # still runs the rest of the examples
3921
 
            doc_suite = doctest.DocTestSuite(mod,
3922
 
                optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
 
4185
            doc_suite = IsolatedDocTestSuite(
 
4186
                mod, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
3923
4187
        except ValueError, e:
3924
4188
            print '**failed to get doctest for: %s\n%s' % (mod, e)
3925
4189
            raise
3928
4192
        suite.addTest(doc_suite)
3929
4193
 
3930
4194
    default_encoding = sys.getdefaultencoding()
3931
 
    for name, plugin in bzrlib.plugin.plugins().items():
 
4195
    for name, plugin in _mod_plugin.plugins().items():
3932
4196
        if not interesting_module(plugin.module.__name__):
3933
4197
            continue
3934
4198
        plugin_suite = plugin.test_suite()
3940
4204
        if plugin_suite is not None:
3941
4205
            suite.addTest(plugin_suite)
3942
4206
        if default_encoding != sys.getdefaultencoding():
3943
 
            bzrlib.trace.warning(
 
4207
            trace.warning(
3944
4208
                'Plugin "%s" tried to reset default encoding to: %s', name,
3945
4209
                sys.getdefaultencoding())
3946
4210
            reload(sys)
3961
4225
            # Some tests mentioned in the list are not in the test suite. The
3962
4226
            # list may be out of date, report to the tester.
3963
4227
            for id in not_found:
3964
 
                bzrlib.trace.warning('"%s" not found in the test suite', id)
 
4228
                trace.warning('"%s" not found in the test suite', id)
3965
4229
        for id in duplicates:
3966
 
            bzrlib.trace.warning('"%s" is used as an id by several tests', id)
 
4230
            trace.warning('"%s" is used as an id by several tests', id)
3967
4231
 
3968
4232
    return suite
3969
4233
 
3970
4234
 
3971
 
def multiply_scenarios(scenarios_left, scenarios_right):
 
4235
def multiply_scenarios(*scenarios):
 
4236
    """Multiply two or more iterables of scenarios.
 
4237
 
 
4238
    It is safe to pass scenario generators or iterators.
 
4239
 
 
4240
    :returns: A list of compound scenarios: the cross-product of all 
 
4241
        scenarios, with the names concatenated and the parameters
 
4242
        merged together.
 
4243
    """
 
4244
    return reduce(_multiply_two_scenarios, map(list, scenarios))
 
4245
 
 
4246
 
 
4247
def _multiply_two_scenarios(scenarios_left, scenarios_right):
3972
4248
    """Multiply two sets of scenarios.
3973
4249
 
3974
4250
    :returns: the cartesian product of the two sets of scenarios, that is
4098
4374
        the module is available.
4099
4375
    """
4100
4376
 
4101
 
    py_module = __import__(py_module_name, {}, {}, ['NO_SUCH_ATTRIB'])
 
4377
    from bzrlib.tests.features import ModuleAvailableFeature
 
4378
    py_module = pyutils.get_named_object(py_module_name)
4102
4379
    scenarios = [
4103
4380
        ('python', {'module': py_module}),
4104
4381
    ]
4144
4421
                         % (os.path.basename(dirname), printable_e))
4145
4422
 
4146
4423
 
4147
 
class Feature(object):
4148
 
    """An operating system Feature."""
4149
 
 
4150
 
    def __init__(self):
4151
 
        self._available = None
4152
 
 
4153
 
    def available(self):
4154
 
        """Is the feature available?
4155
 
 
4156
 
        :return: True if the feature is available.
4157
 
        """
4158
 
        if self._available is None:
4159
 
            self._available = self._probe()
4160
 
        return self._available
4161
 
 
4162
 
    def _probe(self):
4163
 
        """Implement this method in concrete features.
4164
 
 
4165
 
        :return: True if the feature is available.
4166
 
        """
4167
 
        raise NotImplementedError
4168
 
 
4169
 
    def __str__(self):
4170
 
        if getattr(self, 'feature_name', None):
4171
 
            return self.feature_name()
4172
 
        return self.__class__.__name__
4173
 
 
4174
 
 
4175
 
class _SymlinkFeature(Feature):
4176
 
 
4177
 
    def _probe(self):
4178
 
        return osutils.has_symlinks()
4179
 
 
4180
 
    def feature_name(self):
4181
 
        return 'symlinks'
4182
 
 
4183
 
SymlinkFeature = _SymlinkFeature()
4184
 
 
4185
 
 
4186
 
class _HardlinkFeature(Feature):
4187
 
 
4188
 
    def _probe(self):
4189
 
        return osutils.has_hardlinks()
4190
 
 
4191
 
    def feature_name(self):
4192
 
        return 'hardlinks'
4193
 
 
4194
 
HardlinkFeature = _HardlinkFeature()
4195
 
 
4196
 
 
4197
 
class _OsFifoFeature(Feature):
4198
 
 
4199
 
    def _probe(self):
4200
 
        return getattr(os, 'mkfifo', None)
4201
 
 
4202
 
    def feature_name(self):
4203
 
        return 'filesystem fifos'
4204
 
 
4205
 
OsFifoFeature = _OsFifoFeature()
4206
 
 
4207
 
 
4208
 
class _UnicodeFilenameFeature(Feature):
4209
 
    """Does the filesystem support Unicode filenames?"""
4210
 
 
4211
 
    def _probe(self):
4212
 
        try:
4213
 
            # Check for character combinations unlikely to be covered by any
4214
 
            # single non-unicode encoding. We use the characters
4215
 
            # - greek small letter alpha (U+03B1) and
4216
 
            # - braille pattern dots-123456 (U+283F).
4217
 
            os.stat(u'\u03b1\u283f')
4218
 
        except UnicodeEncodeError:
4219
 
            return False
4220
 
        except (IOError, OSError):
4221
 
            # The filesystem allows the Unicode filename but the file doesn't
4222
 
            # exist.
4223
 
            return True
4224
 
        else:
4225
 
            # The filesystem allows the Unicode filename and the file exists,
4226
 
            # for some reason.
4227
 
            return True
4228
 
 
4229
 
UnicodeFilenameFeature = _UnicodeFilenameFeature()
4230
 
 
4231
 
 
4232
 
class _CompatabilityThunkFeature(Feature):
4233
 
    """This feature is just a thunk to another feature.
4234
 
 
4235
 
    It issues a deprecation warning if it is accessed, to let you know that you
4236
 
    should really use a different feature.
4237
 
    """
4238
 
 
4239
 
    def __init__(self, dep_version, module, name,
4240
 
                 replacement_name, replacement_module=None):
4241
 
        super(_CompatabilityThunkFeature, self).__init__()
4242
 
        self._module = module
4243
 
        if replacement_module is None:
4244
 
            replacement_module = module
4245
 
        self._replacement_module = replacement_module
4246
 
        self._name = name
4247
 
        self._replacement_name = replacement_name
4248
 
        self._dep_version = dep_version
4249
 
        self._feature = None
4250
 
 
4251
 
    def _ensure(self):
4252
 
        if self._feature is None:
4253
 
            depr_msg = self._dep_version % ('%s.%s'
4254
 
                                            % (self._module, self._name))
4255
 
            use_msg = ' Use %s.%s instead.' % (self._replacement_module,
4256
 
                                               self._replacement_name)
4257
 
            symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4258
 
            # Import the new feature and use it as a replacement for the
4259
 
            # deprecated one.
4260
 
            mod = __import__(self._replacement_module, {}, {},
4261
 
                             [self._replacement_name])
4262
 
            self._feature = getattr(mod, self._replacement_name)
4263
 
 
4264
 
    def _probe(self):
4265
 
        self._ensure()
4266
 
        return self._feature._probe()
4267
 
 
4268
 
 
4269
 
class ModuleAvailableFeature(Feature):
4270
 
    """This is a feature than describes a module we want to be available.
4271
 
 
4272
 
    Declare the name of the module in __init__(), and then after probing, the
4273
 
    module will be available as 'self.module'.
4274
 
 
4275
 
    :ivar module: The module if it is available, else None.
4276
 
    """
4277
 
 
4278
 
    def __init__(self, module_name):
4279
 
        super(ModuleAvailableFeature, self).__init__()
4280
 
        self.module_name = module_name
4281
 
 
4282
 
    def _probe(self):
4283
 
        try:
4284
 
            self._module = __import__(self.module_name, {}, {}, [''])
4285
 
            return True
4286
 
        except ImportError:
4287
 
            return False
4288
 
 
4289
 
    @property
4290
 
    def module(self):
4291
 
        if self.available(): # Make sure the probe has been done
4292
 
            return self._module
4293
 
        return None
4294
 
 
4295
 
    def feature_name(self):
4296
 
        return self.module_name
4297
 
 
4298
 
 
4299
 
# This is kept here for compatibility, it is recommended to use
4300
 
# 'bzrlib.tests.feature.paramiko' instead
4301
 
ParamikoFeature = _CompatabilityThunkFeature(
4302
 
    deprecated_in((2,1,0)),
4303
 
    'bzrlib.tests.features', 'ParamikoFeature', 'paramiko')
4304
 
 
4305
 
 
4306
4424
def probe_unicode_in_user_encoding():
4307
4425
    """Try to encode several unicode strings to use in unicode-aware tests.
4308
4426
    Return first successfull match.
4336
4454
    return None
4337
4455
 
4338
4456
 
4339
 
class _HTTPSServerFeature(Feature):
4340
 
    """Some tests want an https Server, check if one is available.
4341
 
 
4342
 
    Right now, the only way this is available is under python2.6 which provides
4343
 
    an ssl module.
4344
 
    """
4345
 
 
4346
 
    def _probe(self):
4347
 
        try:
4348
 
            import ssl
4349
 
            return True
4350
 
        except ImportError:
4351
 
            return False
4352
 
 
4353
 
    def feature_name(self):
4354
 
        return 'HTTPSServer'
4355
 
 
4356
 
 
4357
 
HTTPSServerFeature = _HTTPSServerFeature()
4358
 
 
4359
 
 
4360
 
class _UnicodeFilename(Feature):
4361
 
    """Does the filesystem support Unicode filenames?"""
4362
 
 
4363
 
    def _probe(self):
4364
 
        try:
4365
 
            os.stat(u'\u03b1')
4366
 
        except UnicodeEncodeError:
4367
 
            return False
4368
 
        except (IOError, OSError):
4369
 
            # The filesystem allows the Unicode filename but the file doesn't
4370
 
            # exist.
4371
 
            return True
4372
 
        else:
4373
 
            # The filesystem allows the Unicode filename and the file exists,
4374
 
            # for some reason.
4375
 
            return True
4376
 
 
4377
 
UnicodeFilename = _UnicodeFilename()
4378
 
 
4379
 
 
4380
 
class _ByteStringNamedFilesystem(Feature):
4381
 
    """Is the filesystem based on bytes?"""
4382
 
 
4383
 
    def _probe(self):
4384
 
        if os.name == "posix":
4385
 
            return True
4386
 
        return False
4387
 
 
4388
 
ByteStringNamedFilesystem = _ByteStringNamedFilesystem()
4389
 
 
4390
 
 
4391
 
class _UTF8Filesystem(Feature):
4392
 
    """Is the filesystem UTF-8?"""
4393
 
 
4394
 
    def _probe(self):
4395
 
        if osutils._fs_enc.upper() in ('UTF-8', 'UTF8'):
4396
 
            return True
4397
 
        return False
4398
 
 
4399
 
UTF8Filesystem = _UTF8Filesystem()
4400
 
 
4401
 
 
4402
 
class _BreakinFeature(Feature):
4403
 
    """Does this platform support the breakin feature?"""
4404
 
 
4405
 
    def _probe(self):
4406
 
        from bzrlib import breakin
4407
 
        if breakin.determine_signal() is None:
4408
 
            return False
4409
 
        if sys.platform == 'win32':
4410
 
            # Windows doesn't have os.kill, and we catch the SIGBREAK signal.
4411
 
            # We trigger SIGBREAK via a Console api so we need ctypes to
4412
 
            # access the function
4413
 
            try:
4414
 
                import ctypes
4415
 
            except OSError:
4416
 
                return False
4417
 
        return True
4418
 
 
4419
 
    def feature_name(self):
4420
 
        return "SIGQUIT or SIGBREAK w/ctypes on win32"
4421
 
 
4422
 
 
4423
 
BreakinFeature = _BreakinFeature()
4424
 
 
4425
 
 
4426
 
class _CaseInsCasePresFilenameFeature(Feature):
4427
 
    """Is the file-system case insensitive, but case-preserving?"""
4428
 
 
4429
 
    def _probe(self):
4430
 
        fileno, name = tempfile.mkstemp(prefix='MixedCase')
4431
 
        try:
4432
 
            # first check truly case-preserving for created files, then check
4433
 
            # case insensitive when opening existing files.
4434
 
            name = osutils.normpath(name)
4435
 
            base, rel = osutils.split(name)
4436
 
            found_rel = osutils.canonical_relpath(base, name)
4437
 
            return (found_rel == rel
4438
 
                    and os.path.isfile(name.upper())
4439
 
                    and os.path.isfile(name.lower()))
4440
 
        finally:
4441
 
            os.close(fileno)
4442
 
            os.remove(name)
4443
 
 
4444
 
    def feature_name(self):
4445
 
        return "case-insensitive case-preserving filesystem"
4446
 
 
4447
 
CaseInsCasePresFilenameFeature = _CaseInsCasePresFilenameFeature()
4448
 
 
4449
 
 
4450
 
class _CaseInsensitiveFilesystemFeature(Feature):
4451
 
    """Check if underlying filesystem is case-insensitive but *not* case
4452
 
    preserving.
4453
 
    """
4454
 
    # Note that on Windows, Cygwin, MacOS etc, the file-systems are far
4455
 
    # more likely to be case preserving, so this case is rare.
4456
 
 
4457
 
    def _probe(self):
4458
 
        if CaseInsCasePresFilenameFeature.available():
4459
 
            return False
4460
 
 
4461
 
        if TestCaseWithMemoryTransport.TEST_ROOT is None:
4462
 
            root = osutils.mkdtemp(prefix='testbzr-', suffix='.tmp')
4463
 
            TestCaseWithMemoryTransport.TEST_ROOT = root
4464
 
        else:
4465
 
            root = TestCaseWithMemoryTransport.TEST_ROOT
4466
 
        tdir = osutils.mkdtemp(prefix='case-sensitive-probe-', suffix='',
4467
 
            dir=root)
4468
 
        name_a = osutils.pathjoin(tdir, 'a')
4469
 
        name_A = osutils.pathjoin(tdir, 'A')
4470
 
        os.mkdir(name_a)
4471
 
        result = osutils.isdir(name_A)
4472
 
        _rmtree_temp_dir(tdir)
4473
 
        return result
4474
 
 
4475
 
    def feature_name(self):
4476
 
        return 'case-insensitive filesystem'
4477
 
 
4478
 
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
4479
 
 
4480
 
 
4481
 
class _CaseSensitiveFilesystemFeature(Feature):
4482
 
 
4483
 
    def _probe(self):
4484
 
        if CaseInsCasePresFilenameFeature.available():
4485
 
            return False
4486
 
        elif CaseInsensitiveFilesystemFeature.available():
4487
 
            return False
4488
 
        else:
4489
 
            return True
4490
 
 
4491
 
    def feature_name(self):
4492
 
        return 'case-sensitive filesystem'
4493
 
 
4494
 
# new coding style is for feature instances to be lowercase
4495
 
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
4496
 
 
4497
 
 
4498
 
# Kept for compatibility, use bzrlib.tests.features.subunit instead
4499
 
SubUnitFeature = _CompatabilityThunkFeature(
4500
 
    deprecated_in((2,1,0)),
4501
 
    'bzrlib.tests.features', 'SubUnitFeature', 'subunit')
4502
4457
# Only define SubUnitBzrRunner if subunit is available.
4503
4458
try:
4504
4459
    from subunit import TestProtocolClient
4505
4460
    from subunit.test_results import AutoTimingTestResultDecorator
4506
4461
    class SubUnitBzrProtocolClient(TestProtocolClient):
4507
4462
 
 
4463
        def stopTest(self, test):
 
4464
            super(SubUnitBzrProtocolClient, self).stopTest(test)
 
4465
            _clear__type_equality_funcs(test)
 
4466
 
4508
4467
        def addSuccess(self, test, details=None):
4509
4468
            # The subunit client always includes the details in the subunit
4510
4469
            # stream, but we don't want to include it in ours.
4522
4481
except ImportError:
4523
4482
    pass
4524
4483
 
4525
 
class _PosixPermissionsFeature(Feature):
4526
 
 
4527
 
    def _probe(self):
4528
 
        def has_perms():
4529
 
            # create temporary file and check if specified perms are maintained.
4530
 
            import tempfile
4531
 
 
4532
 
            write_perms = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
4533
 
            f = tempfile.mkstemp(prefix='bzr_perms_chk_')
4534
 
            fd, name = f
4535
 
            os.close(fd)
4536
 
            os.chmod(name, write_perms)
4537
 
 
4538
 
            read_perms = os.stat(name).st_mode & 0777
4539
 
            os.unlink(name)
4540
 
            return (write_perms == read_perms)
4541
 
 
4542
 
        return (os.name == 'posix') and has_perms()
4543
 
 
4544
 
    def feature_name(self):
4545
 
        return 'POSIX permissions support'
4546
 
 
4547
 
posix_permissions_feature = _PosixPermissionsFeature()
 
4484
 
 
4485
# API compatibility for old plugins; see bug 892622.
 
4486
for name in [
 
4487
    'Feature',
 
4488
    'HTTPServerFeature', 
 
4489
    'ModuleAvailableFeature',
 
4490
    'HTTPSServerFeature', 'SymlinkFeature', 'HardlinkFeature',
 
4491
    'OsFifoFeature', 'UnicodeFilenameFeature',
 
4492
    'ByteStringNamedFilesystem', 'UTF8Filesystem',
 
4493
    'BreakinFeature', 'CaseInsCasePresFilenameFeature',
 
4494
    'CaseInsensitiveFilesystemFeature', 'case_sensitive_filesystem_feature',
 
4495
    'posix_permissions_feature',
 
4496
    ]:
 
4497
    globals()[name] = _CompatabilityThunkFeature(
 
4498
        symbol_versioning.deprecated_in((2, 5, 0)),
 
4499
        'bzrlib.tests', name,
 
4500
        name, 'bzrlib.tests.features')
 
4501
 
 
4502
 
 
4503
for (old_name, new_name) in [
 
4504
    ('UnicodeFilename', 'UnicodeFilenameFeature'),
 
4505
    ]:
 
4506
    globals()[name] = _CompatabilityThunkFeature(
 
4507
        symbol_versioning.deprecated_in((2, 5, 0)),
 
4508
        'bzrlib.tests', old_name,
 
4509
        new_name, 'bzrlib.tests.features')