~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-05-03 09:07:50 UTC
  • mfrom: (5185.1.1 fix-515660)
  • Revision ID: pqm@pqm.ubuntu.com-20100503090750-ojeefmuph3yj8m5z
Update 'bzr bind' help to indicate what happens when no location is
 specified.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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
 
19
25
# NOTE: Some classes in here use camelCaseNaming() rather than
20
26
# underscore_naming().  That's for consistency with unittest; it's not the
21
27
# general style of bzrlib.  Please continue that consistency when adding e.g.
23
29
 
24
30
import atexit
25
31
import codecs
26
 
import copy
 
32
from copy import copy
27
33
from cStringIO import StringIO
28
34
import difflib
29
35
import doctest
30
36
import errno
31
 
import itertools
32
37
import logging
 
38
import math
33
39
import os
34
 
import platform
35
 
import pprint
 
40
from pprint import pformat
36
41
import random
37
42
import re
38
43
import shlex
39
44
import stat
40
 
import subprocess
 
45
from subprocess import Popen, PIPE, STDOUT
41
46
import sys
42
47
import tempfile
43
48
import threading
49
54
import testtools
50
55
# nb: check this before importing anything else from within it
51
56
_testtools_version = getattr(testtools, '__version__', ())
52
 
if _testtools_version < (0, 9, 5):
53
 
    raise ImportError("need at least testtools 0.9.5: %s is %r"
 
57
if _testtools_version < (0, 9, 2):
 
58
    raise ImportError("need at least testtools 0.9.2: %s is %r"
54
59
        % (testtools.__file__, _testtools_version))
55
60
from testtools import content
56
61
 
57
 
import bzrlib
58
62
from bzrlib import (
59
63
    branchbuilder,
60
64
    bzrdir,
61
65
    chk_map,
62
 
    commands as _mod_commands,
63
66
    config,
64
 
    i18n,
65
67
    debug,
66
68
    errors,
67
69
    hooks,
68
70
    lock as _mod_lock,
69
 
    lockdir,
70
71
    memorytree,
71
72
    osutils,
72
 
    plugin as _mod_plugin,
73
 
    pyutils,
 
73
    progress,
74
74
    ui,
75
75
    urlutils,
76
76
    registry,
77
 
    symbol_versioning,
78
 
    trace,
79
 
    transport as _mod_transport,
80
77
    workingtree,
81
78
    )
 
79
import bzrlib.branch
 
80
import bzrlib.commands
 
81
import bzrlib.timestamp
 
82
import bzrlib.export
 
83
import bzrlib.inventory
 
84
import bzrlib.iterablefile
 
85
import bzrlib.lockdir
82
86
try:
83
87
    import bzrlib.lsprof
84
88
except ImportError:
85
89
    # lsprof not available
86
90
    pass
87
 
from bzrlib.smart import client, request
 
91
from bzrlib.merge import merge_inner
 
92
import bzrlib.merge3
 
93
import bzrlib.plugin
 
94
from bzrlib.smart import client, request, server
 
95
import bzrlib.store
 
96
from bzrlib import symbol_versioning
 
97
from bzrlib.symbol_versioning import (
 
98
    DEPRECATED_PARAMETER,
 
99
    deprecated_function,
 
100
    deprecated_in,
 
101
    deprecated_method,
 
102
    deprecated_passed,
 
103
    )
 
104
import bzrlib.trace
88
105
from bzrlib.transport import (
 
106
    get_transport,
89
107
    memory,
90
108
    pathfilter,
91
109
    )
92
 
from bzrlib.symbol_versioning import (
93
 
    deprecated_function,
94
 
    deprecated_in,
95
 
    )
 
110
import bzrlib.transport
 
111
from bzrlib.trace import mutter, note
96
112
from bzrlib.tests import (
97
113
    test_server,
98
114
    TestUtil,
99
 
    treeshape,
100
115
    )
 
116
from bzrlib.tests.http_server import HttpServer
 
117
from bzrlib.tests.TestUtil import (
 
118
                          TestSuite,
 
119
                          TestLoader,
 
120
                          )
 
121
from bzrlib.tests.treeshape import build_tree_contents
101
122
from bzrlib.ui import NullProgressView
102
123
from bzrlib.ui.text import TextUIFactory
 
124
import bzrlib.version_info_formats.format_custom
 
125
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
103
126
 
104
127
# Mark this python module as being part of the implementation
105
128
# of unittest: this gives us better tracebacks where the last
117
140
SUBUNIT_SEEK_SET = 0
118
141
SUBUNIT_SEEK_CUR = 1
119
142
 
120
 
# These are intentionally brought into this namespace. That way plugins, etc
121
 
# can just "from bzrlib.tests import TestCase, TestLoader, etc"
122
 
TestSuite = TestUtil.TestSuite
123
 
TestLoader = TestUtil.TestLoader
124
 
 
125
 
# Tests should run in a clean and clearly defined environment. The goal is to
126
 
# keep them isolated from the running environment as mush as possible. The test
127
 
# framework ensures the variables defined below are set (or deleted if the
128
 
# value is None) before a test is run and reset to their original value after
129
 
# the test is run. Generally if some code depends on an environment variable,
130
 
# the tests should start without this variable in the environment. There are a
131
 
# few exceptions but you shouldn't violate this rule lightly.
132
 
isolated_environ = {
133
 
    'BZR_HOME': None,
134
 
    'HOME': None,
135
 
    # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
136
 
    # tests do check our impls match APPDATA
137
 
    'BZR_EDITOR': None, # test_msgeditor manipulates this variable
138
 
    'VISUAL': None,
139
 
    'EDITOR': None,
140
 
    'BZR_EMAIL': None,
141
 
    'BZREMAIL': None, # may still be present in the environment
142
 
    'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
143
 
    'BZR_PROGRESS_BAR': None,
144
 
    # This should trap leaks to ~/.bzr.log. This occurs when tests use TestCase
145
 
    # as a base class instead of TestCaseInTempDir. Tests inheriting from
146
 
    # TestCase should not use disk resources, BZR_LOG is one.
147
 
    'BZR_LOG': '/you-should-use-TestCaseInTempDir-if-you-need-a-log-file',
148
 
    'BZR_PLUGIN_PATH': None,
149
 
    'BZR_DISABLE_PLUGINS': None,
150
 
    'BZR_PLUGINS_AT': None,
151
 
    'BZR_CONCURRENCY': None,
152
 
    # Make sure that any text ui tests are consistent regardless of
153
 
    # the environment the test case is run in; you may want tests that
154
 
    # test other combinations.  'dumb' is a reasonable guess for tests
155
 
    # going to a pipe or a StringIO.
156
 
    'TERM': 'dumb',
157
 
    'LINES': '25',
158
 
    'COLUMNS': '80',
159
 
    'BZR_COLUMNS': '80',
160
 
    # Disable SSH Agent
161
 
    'SSH_AUTH_SOCK': None,
162
 
    # Proxies
163
 
    'http_proxy': None,
164
 
    'HTTP_PROXY': None,
165
 
    'https_proxy': None,
166
 
    'HTTPS_PROXY': None,
167
 
    'no_proxy': None,
168
 
    'NO_PROXY': None,
169
 
    'all_proxy': None,
170
 
    'ALL_PROXY': None,
171
 
    # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
172
 
    # least. If you do (care), please update this comment
173
 
    # -- vila 20080401
174
 
    'ftp_proxy': None,
175
 
    'FTP_PROXY': None,
176
 
    'BZR_REMOTE_PATH': None,
177
 
    # Generally speaking, we don't want apport reporting on crashes in
178
 
    # the test envirnoment unless we're specifically testing apport,
179
 
    # so that it doesn't leak into the real system environment.  We
180
 
    # use an env var so it propagates to subprocesses.
181
 
    'APPORT_DISABLE': '1',
182
 
    }
183
 
 
184
 
 
185
 
def override_os_environ(test, env=None):
186
 
    """Modify os.environ keeping a copy.
187
 
    
188
 
    :param test: A test instance
189
 
 
190
 
    :param env: A dict containing variable definitions to be installed
191
 
    """
192
 
    if env is None:
193
 
        env = isolated_environ
194
 
    test._original_os_environ = dict([(var, value)
195
 
                                      for var, value in os.environ.iteritems()])
196
 
    for var, value in env.iteritems():
197
 
        osutils.set_or_unset_env(var, value)
198
 
        if var not in test._original_os_environ:
199
 
            # The var is new, add it with a value of None, so
200
 
            # restore_os_environ will delete it
201
 
            test._original_os_environ[var] = None
202
 
 
203
 
 
204
 
def restore_os_environ(test):
205
 
    """Restore os.environ to its original state.
206
 
 
207
 
    :param test: A test instance previously passed to override_os_environ.
208
 
    """
209
 
    for var, value in test._original_os_environ.iteritems():
210
 
        # Restore the original value (or delete it if the value has been set to
211
 
        # None in override_os_environ).
212
 
        osutils.set_or_unset_env(var, value)
213
 
 
214
 
 
215
 
class ExtendedTestResult(testtools.TextTestResult):
 
143
 
 
144
class ExtendedTestResult(unittest._TextTestResult):
216
145
    """Accepts, reports and accumulates the results of running tests.
217
146
 
218
147
    Compared to the unittest version this class adds support for
239
168
        :param bench_history: Optionally, a writable file object to accumulate
240
169
            benchmark results.
241
170
        """
242
 
        testtools.TextTestResult.__init__(self, stream)
 
171
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
243
172
        if bench_history is not None:
244
173
            from bzrlib.version import _get_bzr_source_tree
245
174
            src_tree = _get_bzr_source_tree()
266
195
        self.count = 0
267
196
        self._overall_start_time = time.time()
268
197
        self._strict = strict
269
 
        self._first_thread_leaker_id = None
270
 
        self._tests_leaking_threads_count = 0
271
 
        self._traceback_from_test = None
272
198
 
273
199
    def stopTestRun(self):
274
200
        run = self.testsRun
275
201
        actionTaken = "Ran"
276
202
        stopTime = time.time()
277
203
        timeTaken = stopTime - self.startTime
278
 
        # GZ 2010-07-19: Seems testtools has no printErrors method, and though
279
 
        #                the parent class method is similar have to duplicate
280
 
        self._show_list('ERROR', self.errors)
281
 
        self._show_list('FAIL', self.failures)
282
 
        self.stream.write(self.sep2)
283
 
        self.stream.write("%s %d test%s in %.3fs\n\n" % (actionTaken,
 
204
        self.printErrors()
 
205
        self.stream.writeln(self.separator2)
 
206
        self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
284
207
                            run, run != 1 and "s" or "", timeTaken))
 
208
        self.stream.writeln()
285
209
        if not self.wasSuccessful():
286
210
            self.stream.write("FAILED (")
287
211
            failed, errored = map(len, (self.failures, self.errors))
294
218
                if failed or errored: self.stream.write(", ")
295
219
                self.stream.write("known_failure_count=%d" %
296
220
                    self.known_failure_count)
297
 
            self.stream.write(")\n")
 
221
            self.stream.writeln(")")
298
222
        else:
299
223
            if self.known_failure_count:
300
 
                self.stream.write("OK (known_failures=%d)\n" %
 
224
                self.stream.writeln("OK (known_failures=%d)" %
301
225
                    self.known_failure_count)
302
226
            else:
303
 
                self.stream.write("OK\n")
 
227
                self.stream.writeln("OK")
304
228
        if self.skip_count > 0:
305
229
            skipped = self.skip_count
306
 
            self.stream.write('%d test%s skipped\n' %
 
230
            self.stream.writeln('%d test%s skipped' %
307
231
                                (skipped, skipped != 1 and "s" or ""))
308
232
        if self.unsupported:
309
233
            for feature, count in sorted(self.unsupported.items()):
310
 
                self.stream.write("Missing feature '%s' skipped %d tests.\n" %
 
234
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
311
235
                    (feature, count))
312
236
        if self._strict:
313
237
            ok = self.wasStrictlySuccessful()
314
238
        else:
315
239
            ok = self.wasSuccessful()
316
 
        if self._first_thread_leaker_id:
 
240
        if TestCase._first_thread_leaker_id:
317
241
            self.stream.write(
318
242
                '%s is leaking threads among %d leaking tests.\n' % (
319
 
                self._first_thread_leaker_id,
320
 
                self._tests_leaking_threads_count))
 
243
                TestCase._first_thread_leaker_id,
 
244
                TestCase._leaking_threads_tests))
321
245
            # We don't report the main thread as an active one.
322
246
            self.stream.write(
323
247
                '%d non-main threads were left active in the end.\n'
324
 
                % (len(self._active_threads) - 1))
 
248
                % (TestCase._active_threads - 1))
325
249
 
326
250
    def getDescription(self, test):
327
251
        return test.id()
334
258
 
335
259
    def _elapsedTestTimeString(self):
336
260
        """Return a time string for the overall time the current test has taken."""
337
 
        return self._formatTime(self._delta_to_float(
338
 
            self._now() - self._start_datetime))
 
261
        return self._formatTime(time.time() - self._start_time)
339
262
 
340
263
    def _testTimeString(self, testCase):
341
264
        benchmark_time = self._extractBenchmarkTime(testCase)
352
275
 
353
276
    def _shortened_test_description(self, test):
354
277
        what = test.id()
355
 
        what = re.sub(r'^bzrlib\.tests\.', '', what)
 
278
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
356
279
        return what
357
280
 
358
 
    # GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
359
 
    #                multiple times in a row, because the handler is added for
360
 
    #                each test but the container list is shared between cases.
361
 
    #                See lp:498869 lp:625574 and lp:637725 for background.
362
 
    def _record_traceback_from_test(self, exc_info):
363
 
        """Store the traceback from passed exc_info tuple till"""
364
 
        self._traceback_from_test = exc_info[2]
365
 
 
366
281
    def startTest(self, test):
367
 
        super(ExtendedTestResult, self).startTest(test)
 
282
        unittest.TestResult.startTest(self, test)
368
283
        if self.count == 0:
369
284
            self.startTests()
370
 
        self.count += 1
371
285
        self.report_test_start(test)
372
286
        test.number = self.count
373
287
        self._recordTestStartTime()
374
 
        # Make testtools cases give us the real traceback on failure
375
 
        addOnException = getattr(test, "addOnException", None)
376
 
        if addOnException is not None:
377
 
            addOnException(self._record_traceback_from_test)
378
 
        # Only check for thread leaks on bzrlib derived test cases
379
 
        if isinstance(test, TestCase):
380
 
            test.addCleanup(self._check_leaked_threads, test)
381
 
 
382
 
    def stopTest(self, test):
383
 
        super(ExtendedTestResult, self).stopTest(test)
384
 
        # Manually break cycles, means touching various private things but hey
385
 
        getDetails = getattr(test, "getDetails", None)
386
 
        if getDetails is not None:
387
 
            getDetails().clear()
388
 
        # Clear _type_equality_funcs to try to stop TestCase instances
389
 
        # from wasting memory. 'clear' is not available in all Python
390
 
        # versions (bug 809048)
391
 
        type_equality_funcs = getattr(test, "_type_equality_funcs", None)
392
 
        if type_equality_funcs is not None:
393
 
            tef_clear = getattr(type_equality_funcs, "clear", None)
394
 
            if tef_clear is None:
395
 
                tef_instance_dict = getattr(type_equality_funcs, "__dict__", None)
396
 
                if tef_instance_dict is not None:
397
 
                    tef_clear = tef_instance_dict.clear
398
 
            if tef_clear is not None:
399
 
                tef_clear()
400
 
        self._traceback_from_test = None
401
288
 
402
289
    def startTests(self):
403
 
        self.report_tests_starting()
404
 
        self._active_threads = threading.enumerate()
405
 
 
406
 
    def _check_leaked_threads(self, test):
407
 
        """See if any threads have leaked since last call
408
 
 
409
 
        A sample of live threads is stored in the _active_threads attribute,
410
 
        when this method runs it compares the current live threads and any not
411
 
        in the previous sample are treated as having leaked.
412
 
        """
413
 
        now_active_threads = set(threading.enumerate())
414
 
        threads_leaked = now_active_threads.difference(self._active_threads)
415
 
        if threads_leaked:
416
 
            self._report_thread_leak(test, threads_leaked, now_active_threads)
417
 
            self._tests_leaking_threads_count += 1
418
 
            if self._first_thread_leaker_id is None:
419
 
                self._first_thread_leaker_id = test.id()
420
 
            self._active_threads = now_active_threads
 
290
        import platform
 
291
        if getattr(sys, 'frozen', None) is None:
 
292
            bzr_path = osutils.realpath(sys.argv[0])
 
293
        else:
 
294
            bzr_path = sys.executable
 
295
        self.stream.write(
 
296
            'bzr selftest: %s\n' % (bzr_path,))
 
297
        self.stream.write(
 
298
            '   %s\n' % (
 
299
                    bzrlib.__path__[0],))
 
300
        self.stream.write(
 
301
            '   bzr-%s python-%s %s\n' % (
 
302
                    bzrlib.version_string,
 
303
                    bzrlib._format_version_tuple(sys.version_info),
 
304
                    platform.platform(aliased=1),
 
305
                    ))
 
306
        self.stream.write('\n')
421
307
 
422
308
    def _recordTestStartTime(self):
423
309
        """Record that a test has started."""
424
 
        self._start_datetime = self._now()
 
310
        self._start_time = time.time()
 
311
 
 
312
    def _cleanupLogFile(self, test):
 
313
        # We can only do this if we have one of our TestCases, not if
 
314
        # we have a doctest.
 
315
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
316
        if setKeepLogfile is not None:
 
317
            setKeepLogfile()
425
318
 
426
319
    def addError(self, test, err):
427
320
        """Tell result that test finished with an error.
429
322
        Called from the TestCase run() method when the test
430
323
        fails with an unexpected error.
431
324
        """
432
 
        self._post_mortem(self._traceback_from_test)
433
 
        super(ExtendedTestResult, self).addError(test, err)
 
325
        self._post_mortem()
 
326
        unittest.TestResult.addError(self, test, err)
434
327
        self.error_count += 1
435
328
        self.report_error(test, err)
436
329
        if self.stop_early:
437
330
            self.stop()
 
331
        self._cleanupLogFile(test)
438
332
 
439
333
    def addFailure(self, test, err):
440
334
        """Tell result that test failed.
442
336
        Called from the TestCase run() method when the test
443
337
        fails because e.g. an assert() method failed.
444
338
        """
445
 
        self._post_mortem(self._traceback_from_test)
446
 
        super(ExtendedTestResult, self).addFailure(test, err)
 
339
        self._post_mortem()
 
340
        unittest.TestResult.addFailure(self, test, err)
447
341
        self.failure_count += 1
448
342
        self.report_failure(test, err)
449
343
        if self.stop_early:
450
344
            self.stop()
 
345
        self._cleanupLogFile(test)
451
346
 
452
347
    def addSuccess(self, test, details=None):
453
348
        """Tell result that test completed successfully.
461
356
                    self._formatTime(benchmark_time),
462
357
                    test.id()))
463
358
        self.report_success(test)
464
 
        super(ExtendedTestResult, self).addSuccess(test)
 
359
        self._cleanupLogFile(test)
 
360
        unittest.TestResult.addSuccess(self, test)
465
361
        test._log_contents = ''
466
362
 
467
363
    def addExpectedFailure(self, test, err):
468
364
        self.known_failure_count += 1
469
365
        self.report_known_failure(test, err)
470
366
 
471
 
    def addUnexpectedSuccess(self, test, details=None):
472
 
        """Tell result the test unexpectedly passed, counting as a failure
473
 
 
474
 
        When the minimum version of testtools required becomes 0.9.8 this
475
 
        can be updated to use the new handling there.
476
 
        """
477
 
        super(ExtendedTestResult, self).addFailure(test, details=details)
478
 
        self.failure_count += 1
479
 
        self.report_unexpected_success(test,
480
 
            "".join(details["reason"].iter_text()))
481
 
        if self.stop_early:
482
 
            self.stop()
483
 
 
484
367
    def addNotSupported(self, test, feature):
485
368
        """The test will not be run because of a missing feature.
486
369
        """
503
386
        self.not_applicable_count += 1
504
387
        self.report_not_applicable(test, reason)
505
388
 
506
 
    def _post_mortem(self, tb=None):
 
389
    def _post_mortem(self):
507
390
        """Start a PDB post mortem session."""
508
391
        if os.environ.get('BZR_TEST_PDB', None):
509
 
            import pdb
510
 
            pdb.post_mortem(tb)
 
392
            import pdb;pdb.post_mortem()
511
393
 
512
394
    def progress(self, offset, whence):
513
395
        """The test is adjusting the count of tests to run."""
518
400
        else:
519
401
            raise errors.BzrError("Unknown whence %r" % whence)
520
402
 
521
 
    def report_tests_starting(self):
522
 
        """Display information before the test run begins"""
523
 
        if getattr(sys, 'frozen', None) is None:
524
 
            bzr_path = osutils.realpath(sys.argv[0])
525
 
        else:
526
 
            bzr_path = sys.executable
527
 
        self.stream.write(
528
 
            'bzr selftest: %s\n' % (bzr_path,))
529
 
        self.stream.write(
530
 
            '   %s\n' % (
531
 
                    bzrlib.__path__[0],))
532
 
        self.stream.write(
533
 
            '   bzr-%s python-%s %s\n' % (
534
 
                    bzrlib.version_string,
535
 
                    bzrlib._format_version_tuple(sys.version_info),
536
 
                    platform.platform(aliased=1),
537
 
                    ))
538
 
        self.stream.write('\n')
539
 
 
540
 
    def report_test_start(self, test):
541
 
        """Display information on the test just about to be run"""
542
 
 
543
 
    def _report_thread_leak(self, test, leaked_threads, active_threads):
544
 
        """Display information on a test that leaked one or more threads"""
545
 
        # GZ 2010-09-09: A leak summary reported separately from the general
546
 
        #                thread debugging would be nice. Tests under subunit
547
 
        #                need something not using stream, perhaps adding a
548
 
        #                testtools details object would be fitting.
549
 
        if 'threads' in selftest_debug_flags:
550
 
            self.stream.write('%s is leaking, active is now %d\n' %
551
 
                (test.id(), len(active_threads)))
 
403
    def report_cleaning_up(self):
 
404
        pass
552
405
 
553
406
    def startTestRun(self):
554
407
        self.startTime = time.time()
591
444
        self.pb.finished()
592
445
        super(TextTestResult, self).stopTestRun()
593
446
 
594
 
    def report_tests_starting(self):
595
 
        super(TextTestResult, self).report_tests_starting()
 
447
    def startTestRun(self):
 
448
        super(TextTestResult, self).startTestRun()
596
449
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
597
450
 
 
451
    def printErrors(self):
 
452
        # clear the pb to make room for the error listing
 
453
        self.pb.clear()
 
454
        super(TextTestResult, self).printErrors()
 
455
 
598
456
    def _progress_prefix_text(self):
599
457
        # the longer this text, the less space we have to show the test
600
458
        # name...
622
480
        return a
623
481
 
624
482
    def report_test_start(self, test):
 
483
        self.count += 1
625
484
        self.pb.update(
626
485
                self._progress_prefix_text()
627
486
                + ' '
645
504
    def report_known_failure(self, test, err):
646
505
        pass
647
506
 
648
 
    def report_unexpected_success(self, test, reason):
649
 
        self.stream.write('FAIL: %s\n    %s: %s\n' % (
650
 
            self._test_description(test),
651
 
            "Unexpected success. Should have failed",
652
 
            reason,
653
 
            ))
654
 
 
655
507
    def report_skip(self, test, reason):
656
508
        pass
657
509
 
661
513
    def report_unsupported(self, test, feature):
662
514
        """test cannot be run because feature is missing."""
663
515
 
 
516
    def report_cleaning_up(self):
 
517
        self.pb.update('Cleaning up')
 
518
 
664
519
 
665
520
class VerboseTestResult(ExtendedTestResult):
666
521
    """Produce long output, with one line per test run plus times"""
673
528
            result = a_string
674
529
        return result.ljust(final_width)
675
530
 
676
 
    def report_tests_starting(self):
 
531
    def startTestRun(self):
 
532
        super(VerboseTestResult, self).startTestRun()
677
533
        self.stream.write('running %d tests...\n' % self.num_tests)
678
 
        super(VerboseTestResult, self).report_tests_starting()
679
534
 
680
535
    def report_test_start(self, test):
 
536
        self.count += 1
681
537
        name = self._shortened_test_description(test)
682
538
        width = osutils.terminal_width()
683
539
        if width is not None:
695
551
        return '%s%s' % (indent, err[1])
696
552
 
697
553
    def report_error(self, test, err):
698
 
        self.stream.write('ERROR %s\n%s\n'
 
554
        self.stream.writeln('ERROR %s\n%s'
699
555
                % (self._testTimeString(test),
700
556
                   self._error_summary(err)))
701
557
 
702
558
    def report_failure(self, test, err):
703
 
        self.stream.write(' FAIL %s\n%s\n'
 
559
        self.stream.writeln(' FAIL %s\n%s'
704
560
                % (self._testTimeString(test),
705
561
                   self._error_summary(err)))
706
562
 
707
563
    def report_known_failure(self, test, err):
708
 
        self.stream.write('XFAIL %s\n%s\n'
 
564
        self.stream.writeln('XFAIL %s\n%s'
709
565
                % (self._testTimeString(test),
710
566
                   self._error_summary(err)))
711
567
 
712
 
    def report_unexpected_success(self, test, reason):
713
 
        self.stream.write(' FAIL %s\n%s: %s\n'
714
 
                % (self._testTimeString(test),
715
 
                   "Unexpected success. Should have failed",
716
 
                   reason))
717
 
 
718
568
    def report_success(self, test):
719
 
        self.stream.write('   OK %s\n' % self._testTimeString(test))
 
569
        self.stream.writeln('   OK %s' % self._testTimeString(test))
720
570
        for bench_called, stats in getattr(test, '_benchcalls', []):
721
 
            self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
 
571
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
722
572
            stats.pprint(file=self.stream)
723
573
        # flush the stream so that we get smooth output. This verbose mode is
724
574
        # used to show the output in PQM.
725
575
        self.stream.flush()
726
576
 
727
577
    def report_skip(self, test, reason):
728
 
        self.stream.write(' SKIP %s\n%s\n'
 
578
        self.stream.writeln(' SKIP %s\n%s'
729
579
                % (self._testTimeString(test), reason))
730
580
 
731
581
    def report_not_applicable(self, test, reason):
732
 
        self.stream.write('  N/A %s\n    %s\n'
 
582
        self.stream.writeln('  N/A %s\n    %s'
733
583
                % (self._testTimeString(test), reason))
734
584
 
735
585
    def report_unsupported(self, test, feature):
736
586
        """test cannot be run because feature is missing."""
737
 
        self.stream.write("NODEP %s\n    The feature '%s' is not available.\n"
 
587
        self.stream.writeln("NODEP %s\n    The feature '%s' is not available."
738
588
                %(self._testTimeString(test), feature))
739
589
 
740
590
 
767
617
            encode = codec[0]
768
618
        else:
769
619
            encode = codec.encode
770
 
        # GZ 2010-09-08: Really we don't want to be writing arbitrary bytes,
771
 
        #                so should swap to the plain codecs.StreamWriter
772
 
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream,
773
 
            "backslashreplace")
 
620
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
774
621
        stream.encoding = new_encoding
775
 
        self.stream = stream
 
622
        self.stream = unittest._WritelnDecorator(stream)
776
623
        self.descriptions = descriptions
777
624
        self.verbosity = verbosity
778
625
        self._bench_history = bench_history
902
749
    # XXX: Should probably unify more with CannedInputUIFactory or a
903
750
    # particular configuration of TextUIFactory, or otherwise have a clearer
904
751
    # idea of how they're supposed to be different.
905
 
    # See https://bugs.launchpad.net/bzr/+bug/408213
 
752
    # See https://bugs.edge.launchpad.net/bzr/+bug/408213
906
753
 
907
754
    def __init__(self, stdout=None, stderr=None, stdin=None):
908
755
        if stdin is not None:
926
773
        return NullProgressView()
927
774
 
928
775
 
929
 
def isolated_doctest_setUp(test):
930
 
    override_os_environ(test)
931
 
 
932
 
 
933
 
def isolated_doctest_tearDown(test):
934
 
    restore_os_environ(test)
935
 
 
936
 
 
937
 
def IsolatedDocTestSuite(*args, **kwargs):
938
 
    """Overrides doctest.DocTestSuite to handle isolation.
939
 
 
940
 
    The method is really a factory and users are expected to use it as such.
941
 
    """
942
 
 
943
 
    kwargs['setUp'] = isolated_doctest_setUp
944
 
    kwargs['tearDown'] = isolated_doctest_tearDown
945
 
    return doctest.DocTestSuite(*args, **kwargs)
946
 
 
947
 
 
948
776
class TestCase(testtools.TestCase):
949
777
    """Base class for bzr unit tests.
950
778
 
961
789
    routine, and to build and check bzr trees.
962
790
 
963
791
    In addition to the usual method of overriding tearDown(), this class also
964
 
    allows subclasses to register cleanup functions via addCleanup, which are
 
792
    allows subclasses to register functions into the _cleanups list, which is
965
793
    run in order as the object is torn down.  It's less likely this will be
966
794
    accidentally overlooked.
967
795
    """
968
796
 
969
 
    _log_file = None
 
797
    _active_threads = None
 
798
    _leaking_threads_tests = 0
 
799
    _first_thread_leaker_id = None
 
800
    _log_file_name = None
970
801
    # record lsprof data when performing benchmark calls.
971
802
    _gather_lsprof_in_benchmarks = False
972
803
 
973
804
    def __init__(self, methodName='testMethod'):
974
805
        super(TestCase, self).__init__(methodName)
 
806
        self._cleanups = []
975
807
        self._directory_isolation = True
976
808
        self.exception_handlers.insert(0,
977
809
            (UnavailableFeature, self._do_unsupported_or_skip))
982
814
        super(TestCase, self).setUp()
983
815
        for feature in getattr(self, '_test_needs_features', []):
984
816
            self.requireFeature(feature)
 
817
        self._log_contents = None
 
818
        self.addDetail("log", content.Content(content.ContentType("text",
 
819
            "plain", {"charset": "utf8"}),
 
820
            lambda:[self._get_log(keep_log_file=True)]))
985
821
        self._cleanEnvironment()
986
822
        self._silenceUI()
987
823
        self._startLogFile()
991
827
        self._track_transports()
992
828
        self._track_locks()
993
829
        self._clear_debug_flags()
994
 
        # Isolate global verbosity level, to make sure it's reproducible
995
 
        # between tests.  We should get rid of this altogether: bug 656694. --
996
 
        # mbp 20101008
997
 
        self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
998
 
        # Isolate config option expansion until its default value for bzrlib is
999
 
        # settled on or a the FIXME associated with _get_expand_default_value
1000
 
        # is addressed -- vila 20110219
1001
 
        self.overrideAttr(config, '_expand_default_value', None)
1002
 
        self._log_files = set()
1003
 
        # Each key in the ``_counters`` dict holds a value for a different
1004
 
        # counter. When the test ends, addDetail() should be used to output the
1005
 
        # counter values. This happens in install_counter_hook().
1006
 
        self._counters = {}
1007
 
        if 'config_stats' in selftest_debug_flags:
1008
 
            self._install_config_stats_hooks()
1009
 
        # Do not use i18n for tests (unless the test reverses this)
1010
 
        i18n.disable_i18n()
 
830
        TestCase._active_threads = threading.activeCount()
 
831
        self.addCleanup(self._check_leaked_threads)
1011
832
 
1012
833
    def debug(self):
1013
834
        # debug a frame up.
1014
835
        import pdb
1015
 
        # The sys preserved stdin/stdout should allow blackbox tests debugging
1016
 
        pdb.Pdb(stdin=sys.__stdin__, stdout=sys.__stdout__
1017
 
                ).set_trace(sys._getframe().f_back)
1018
 
 
1019
 
    def discardDetail(self, name):
1020
 
        """Extend the addDetail, getDetails api so we can remove a detail.
1021
 
 
1022
 
        eg. bzr always adds the 'log' detail at startup, but we don't want to
1023
 
        include it for skipped, xfail, etc tests.
1024
 
 
1025
 
        It is safe to call this for a detail that doesn't exist, in case this
1026
 
        gets called multiple times.
1027
 
        """
1028
 
        # We cheat. details is stored in __details which means we shouldn't
1029
 
        # touch it. but getDetails() returns the dict directly, so we can
1030
 
        # mutate it.
1031
 
        details = self.getDetails()
1032
 
        if name in details:
1033
 
            del details[name]
1034
 
 
1035
 
    def install_counter_hook(self, hooks, name, counter_name=None):
1036
 
        """Install a counting hook.
1037
 
 
1038
 
        Any hook can be counted as long as it doesn't need to return a value.
1039
 
 
1040
 
        :param hooks: Where the hook should be installed.
1041
 
 
1042
 
        :param name: The hook name that will be counted.
1043
 
 
1044
 
        :param counter_name: The counter identifier in ``_counters``, defaults
1045
 
            to ``name``.
1046
 
        """
1047
 
        _counters = self._counters # Avoid closing over self
1048
 
        if counter_name is None:
1049
 
            counter_name = name
1050
 
        if _counters.has_key(counter_name):
1051
 
            raise AssertionError('%s is already used as a counter name'
1052
 
                                  % (counter_name,))
1053
 
        _counters[counter_name] = 0
1054
 
        self.addDetail(counter_name, content.Content(content.UTF8_TEXT,
1055
 
            lambda: ['%d' % (_counters[counter_name],)]))
1056
 
        def increment_counter(*args, **kwargs):
1057
 
            _counters[counter_name] += 1
1058
 
        label = 'count %s calls' % (counter_name,)
1059
 
        hooks.install_named_hook(name, increment_counter, label)
1060
 
        self.addCleanup(hooks.uninstall_named_hook, name, label)
1061
 
 
1062
 
    def _install_config_stats_hooks(self):
1063
 
        """Install config hooks to count hook calls.
1064
 
 
1065
 
        """
1066
 
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1067
 
            self.install_counter_hook(config.ConfigHooks, hook_name,
1068
 
                                       'config.%s' % (hook_name,))
1069
 
 
1070
 
        # The OldConfigHooks are private and need special handling to protect
1071
 
        # against recursive tests (tests that run other tests), so we just do
1072
 
        # manually what registering them into _builtin_known_hooks will provide
1073
 
        # us.
1074
 
        self.overrideAttr(config, 'OldConfigHooks', config._OldConfigHooks())
1075
 
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1076
 
            self.install_counter_hook(config.OldConfigHooks, hook_name,
1077
 
                                      'old_config.%s' % (hook_name,))
 
836
        pdb.Pdb().set_trace(sys._getframe().f_back)
 
837
 
 
838
    def _check_leaked_threads(self):
 
839
        active = threading.activeCount()
 
840
        leaked_threads = active - TestCase._active_threads
 
841
        TestCase._active_threads = active
 
842
        # If some tests make the number of threads *decrease*, we'll consider
 
843
        # that they are just observing old threads dieing, not agressively kill
 
844
        # random threads. So we don't report these tests as leaking. The risk
 
845
        # is that we have false positives that way (the test see 2 threads
 
846
        # going away but leak one) but it seems less likely than the actual
 
847
        # false positives (the test see threads going away and does not leak).
 
848
        if leaked_threads > 0:
 
849
            TestCase._leaking_threads_tests += 1
 
850
            if TestCase._first_thread_leaker_id is None:
 
851
                TestCase._first_thread_leaker_id = self.id()
1078
852
 
1079
853
    def _clear_debug_flags(self):
1080
854
        """Prevent externally set debug flags affecting tests.
1091
865
 
1092
866
    def _clear_hooks(self):
1093
867
        # prevent hooks affecting tests
1094
 
        known_hooks = hooks.known_hooks
1095
868
        self._preserved_hooks = {}
1096
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1097
 
            current_hooks = getattr(parent, name)
 
869
        for key, factory in hooks.known_hooks.items():
 
870
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
871
            current_hooks = hooks.known_hooks_key_to_object(key)
1098
872
            self._preserved_hooks[parent] = (name, current_hooks)
1099
 
        self._preserved_lazy_hooks = hooks._lazy_hooks
1100
 
        hooks._lazy_hooks = {}
1101
873
        self.addCleanup(self._restoreHooks)
1102
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1103
 
            factory = known_hooks.get(key)
 
874
        for key, factory in hooks.known_hooks.items():
 
875
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
1104
876
            setattr(parent, name, factory())
1105
877
        # this hook should always be installed
1106
878
        request._install_hook()
1135
907
        # break some locks on purpose and should be taken into account by
1136
908
        # considering that breaking a lock is just a dirty way of releasing it.
1137
909
        if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
1138
 
            message = (
1139
 
                'Different number of acquired and '
1140
 
                'released or broken locks.\n'
1141
 
                'acquired=%s\n'
1142
 
                'released=%s\n'
1143
 
                'broken=%s\n' %
1144
 
                (acquired_locks, released_locks, broken_locks))
 
910
            message = ('Different number of acquired and '
 
911
                       'released or broken locks. (%s, %s + %s)' %
 
912
                       (acquired_locks, released_locks, broken_locks))
1145
913
            if not self._lock_check_thorough:
1146
914
                # Rather than fail, just warn
1147
915
                print "Broken test %s: %s" % (self, message)
1175
943
 
1176
944
    def permit_dir(self, name):
1177
945
        """Permit a directory to be used by this test. See permit_url."""
1178
 
        name_transport = _mod_transport.get_transport_from_path(name)
 
946
        name_transport = get_transport(name)
1179
947
        self.permit_url(name)
1180
948
        self.permit_url(name_transport.base)
1181
949
 
1204
972
            try:
1205
973
                workingtree.WorkingTree.open(path)
1206
974
            except (errors.NotBranchError, errors.NoWorkingTree):
1207
 
                raise TestSkipped('Needs a working tree of bzr sources')
 
975
                return
1208
976
        finally:
1209
977
            self.enable_directory_isolation()
1210
978
 
1260
1028
        self.addCleanup(transport_server.stop_server)
1261
1029
        # Obtain a real transport because if the server supplies a password, it
1262
1030
        # will be hidden from the base on the client side.
1263
 
        t = _mod_transport.get_transport_from_url(transport_server.get_url())
 
1031
        t = get_transport(transport_server.get_url())
1264
1032
        # Some transport servers effectively chroot the backing transport;
1265
1033
        # others like SFTPServer don't - users of the transport can walk up the
1266
1034
        # transport to read the entire backing transport. This wouldn't matter
1322
1090
        except UnicodeError, e:
1323
1091
            # If we can't compare without getting a UnicodeError, then
1324
1092
            # obviously they are different
1325
 
            trace.mutter('UnicodeError: %s', e)
 
1093
            mutter('UnicodeError: %s', e)
1326
1094
        if message:
1327
1095
            message += '\n'
1328
1096
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1329
1097
            % (message,
1330
 
               pprint.pformat(a), pprint.pformat(b)))
 
1098
               pformat(a), pformat(b)))
1331
1099
 
1332
1100
    assertEquals = assertEqual
1333
1101
 
1367
1135
                         'st_mtime did not match')
1368
1136
        self.assertEqual(expected.st_ctime, actual.st_ctime,
1369
1137
                         'st_ctime did not match')
1370
 
        if sys.platform == 'win32':
 
1138
        if sys.platform != 'win32':
1371
1139
            # On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1372
1140
            # is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
1373
 
            # odd. We just force it to always be 0 to avoid any problems.
1374
 
            self.assertEqual(0, expected.st_dev)
1375
 
            self.assertEqual(0, actual.st_dev)
1376
 
            self.assertEqual(0, expected.st_ino)
1377
 
            self.assertEqual(0, actual.st_ino)
1378
 
        else:
 
1141
            # odd. Regardless we shouldn't actually try to assert anything
 
1142
            # about their values
1379
1143
            self.assertEqual(expected.st_dev, actual.st_dev,
1380
1144
                             'st_dev did not match')
1381
1145
            self.assertEqual(expected.st_ino, actual.st_ino,
1390
1154
                length, len(obj_with_len), obj_with_len))
1391
1155
 
1392
1156
    def assertLogsError(self, exception_class, func, *args, **kwargs):
1393
 
        """Assert that `func(*args, **kwargs)` quietly logs a specific error.
 
1157
        """Assert that func(*args, **kwargs) quietly logs a specific exception.
1394
1158
        """
 
1159
        from bzrlib import trace
1395
1160
        captured = []
1396
1161
        orig_log_exception_quietly = trace.log_exception_quietly
1397
1162
        try:
1398
1163
            def capture():
1399
1164
                orig_log_exception_quietly()
1400
 
                captured.append(sys.exc_info()[1])
 
1165
                captured.append(sys.exc_info())
1401
1166
            trace.log_exception_quietly = capture
1402
1167
            func(*args, **kwargs)
1403
1168
        finally:
1404
1169
            trace.log_exception_quietly = orig_log_exception_quietly
1405
1170
        self.assertLength(1, captured)
1406
 
        err = captured[0]
 
1171
        err = captured[0][1]
1407
1172
        self.assertIsInstance(err, exception_class)
1408
1173
        return err
1409
1174
 
1446
1211
        if haystack.find(needle) == -1:
1447
1212
            self.fail("string %r not found in '''%s'''" % (needle, haystack))
1448
1213
 
1449
 
    def assertNotContainsString(self, haystack, needle):
1450
 
        if haystack.find(needle) != -1:
1451
 
            self.fail("string %r found in '''%s'''" % (needle, haystack))
1452
 
 
1453
1214
    def assertSubset(self, sublist, superlist):
1454
1215
        """Assert that every entry in sublist is present in superlist."""
1455
1216
        missing = set(sublist) - set(superlist)
1544
1305
 
1545
1306
    def assertFileEqual(self, content, path):
1546
1307
        """Fail if path does not contain 'content'."""
1547
 
        self.assertPathExists(path)
 
1308
        self.failUnlessExists(path)
1548
1309
        f = file(path, 'rb')
1549
1310
        try:
1550
1311
            s = f.read()
1560
1321
        else:
1561
1322
            self.assertEqual(expected_docstring, obj.__doc__)
1562
1323
 
1563
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1564
1324
    def failUnlessExists(self, path):
1565
 
        return self.assertPathExists(path)
1566
 
 
1567
 
    def assertPathExists(self, path):
1568
1325
        """Fail unless path or paths, which may be abs or relative, exist."""
1569
1326
        if not isinstance(path, basestring):
1570
1327
            for p in path:
1571
 
                self.assertPathExists(p)
 
1328
                self.failUnlessExists(p)
1572
1329
        else:
1573
 
            self.assertTrue(osutils.lexists(path),
1574
 
                path + " does not exist")
 
1330
            self.failUnless(osutils.lexists(path),path+" does not exist")
1575
1331
 
1576
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1577
1332
    def failIfExists(self, path):
1578
 
        return self.assertPathDoesNotExist(path)
1579
 
 
1580
 
    def assertPathDoesNotExist(self, path):
1581
1333
        """Fail if path or paths, which may be abs or relative, exist."""
1582
1334
        if not isinstance(path, basestring):
1583
1335
            for p in path:
1584
 
                self.assertPathDoesNotExist(p)
 
1336
                self.failIfExists(p)
1585
1337
        else:
1586
 
            self.assertFalse(osutils.lexists(path),
1587
 
                path + " exists")
 
1338
            self.failIf(osutils.lexists(path),path+" exists")
1588
1339
 
1589
1340
    def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
1590
1341
        """A helper for callDeprecated and applyDeprecated.
1616
1367
        not other callers that go direct to the warning module.
1617
1368
 
1618
1369
        To test that a deprecated method raises an error, do something like
1619
 
        this (remember that both assertRaises and applyDeprecated delays *args
1620
 
        and **kwargs passing)::
 
1370
        this::
1621
1371
 
1622
1372
            self.assertRaises(errors.ReservedId,
1623
1373
                self.applyDeprecated,
1705
1455
 
1706
1456
        The file is removed as the test is torn down.
1707
1457
        """
1708
 
        pseudo_log_file = StringIO()
1709
 
        def _get_log_contents_for_weird_testtools_api():
1710
 
            return [pseudo_log_file.getvalue().decode(
1711
 
                "utf-8", "replace").encode("utf-8")]
1712
 
        self.addDetail("log", content.Content(content.ContentType("text",
1713
 
            "plain", {"charset": "utf8"}),
1714
 
            _get_log_contents_for_weird_testtools_api))
1715
 
        self._log_file = pseudo_log_file
1716
 
        self._log_memento = trace.push_log_file(self._log_file)
 
1458
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
 
1459
        self._log_file = os.fdopen(fileno, 'w+')
 
1460
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
 
1461
        self._log_file_name = name
1717
1462
        self.addCleanup(self._finishLogFile)
1718
1463
 
1719
1464
    def _finishLogFile(self):
1720
1465
        """Finished with the log file.
1721
1466
 
1722
 
        Close the file and delete it.
 
1467
        Close the file and delete it, unless setKeepLogfile was called.
1723
1468
        """
1724
 
        if trace._trace_file:
 
1469
        if bzrlib.trace._trace_file:
1725
1470
            # flush the log file, to get all content
1726
 
            trace._trace_file.flush()
1727
 
        trace.pop_log_file(self._log_memento)
 
1471
            bzrlib.trace._trace_file.flush()
 
1472
        bzrlib.trace.pop_log_file(self._log_memento)
 
1473
        # Cache the log result and delete the file on disk
 
1474
        self._get_log(False)
1728
1475
 
1729
1476
    def thisFailsStrictLockCheck(self):
1730
1477
        """It is known that this test would fail with -Dstrict_locks.
1739
1486
        """
1740
1487
        debug.debug_flags.discard('strict_locks')
1741
1488
 
 
1489
    def addCleanup(self, callable, *args, **kwargs):
 
1490
        """Arrange to run a callable when this case is torn down.
 
1491
 
 
1492
        Callables are run in the reverse of the order they are registered,
 
1493
        ie last-in first-out.
 
1494
        """
 
1495
        self._cleanups.append((callable, args, kwargs))
 
1496
 
1742
1497
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1743
1498
        """Overrides an object attribute restoring it after the test.
1744
1499
 
1745
 
        :note: This should be used with discretion; you should think about
1746
 
        whether it's better to make the code testable without monkey-patching.
1747
 
 
1748
1500
        :param obj: The object that will be mutated.
1749
1501
 
1750
1502
        :param attr_name: The attribute name we want to preserve/override in
1761
1513
            setattr(obj, attr_name, new)
1762
1514
        return value
1763
1515
 
1764
 
    def overrideEnv(self, name, new):
1765
 
        """Set an environment variable, and reset it after the test.
1766
 
 
1767
 
        :param name: The environment variable name.
1768
 
 
1769
 
        :param new: The value to set the variable to. If None, the 
1770
 
            variable is deleted from the environment.
1771
 
 
1772
 
        :returns: The actual variable value.
1773
 
        """
1774
 
        value = osutils.set_or_unset_env(name, new)
1775
 
        self.addCleanup(osutils.set_or_unset_env, name, value)
1776
 
        return value
1777
 
 
1778
 
    def recordCalls(self, obj, attr_name):
1779
 
        """Monkeypatch in a wrapper that will record calls.
1780
 
 
1781
 
        The monkeypatch is automatically removed when the test concludes.
1782
 
 
1783
 
        :param obj: The namespace holding the reference to be replaced;
1784
 
            typically a module, class, or object.
1785
 
        :param attr_name: A string for the name of the attribute to 
1786
 
            patch.
1787
 
        :returns: A list that will be extended with one item every time the
1788
 
            function is called, with a tuple of (args, kwargs).
1789
 
        """
1790
 
        calls = []
1791
 
 
1792
 
        def decorator(*args, **kwargs):
1793
 
            calls.append((args, kwargs))
1794
 
            return orig(*args, **kwargs)
1795
 
        orig = self.overrideAttr(obj, attr_name, decorator)
1796
 
        return calls
1797
 
 
1798
1516
    def _cleanEnvironment(self):
1799
 
        for name, value in isolated_environ.iteritems():
1800
 
            self.overrideEnv(name, value)
 
1517
        new_env = {
 
1518
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
 
1519
            'HOME': os.getcwd(),
 
1520
            # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
 
1521
            # tests do check our impls match APPDATA
 
1522
            'BZR_EDITOR': None, # test_msgeditor manipulates this variable
 
1523
            'VISUAL': None,
 
1524
            'EDITOR': None,
 
1525
            'BZR_EMAIL': None,
 
1526
            'BZREMAIL': None, # may still be present in the environment
 
1527
            'EMAIL': None,
 
1528
            'BZR_PROGRESS_BAR': None,
 
1529
            'BZR_LOG': None,
 
1530
            'BZR_PLUGIN_PATH': None,
 
1531
            'BZR_DISABLE_PLUGINS': None,
 
1532
            'BZR_PLUGINS_AT': None,
 
1533
            'BZR_CONCURRENCY': None,
 
1534
            # Make sure that any text ui tests are consistent regardless of
 
1535
            # the environment the test case is run in; you may want tests that
 
1536
            # test other combinations.  'dumb' is a reasonable guess for tests
 
1537
            # going to a pipe or a StringIO.
 
1538
            'TERM': 'dumb',
 
1539
            'LINES': '25',
 
1540
            'COLUMNS': '80',
 
1541
            'BZR_COLUMNS': '80',
 
1542
            # SSH Agent
 
1543
            'SSH_AUTH_SOCK': None,
 
1544
            # Proxies
 
1545
            'http_proxy': None,
 
1546
            'HTTP_PROXY': None,
 
1547
            'https_proxy': None,
 
1548
            'HTTPS_PROXY': None,
 
1549
            'no_proxy': None,
 
1550
            'NO_PROXY': None,
 
1551
            'all_proxy': None,
 
1552
            'ALL_PROXY': None,
 
1553
            # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
 
1554
            # least. If you do (care), please update this comment
 
1555
            # -- vila 20080401
 
1556
            'ftp_proxy': None,
 
1557
            'FTP_PROXY': None,
 
1558
            'BZR_REMOTE_PATH': None,
 
1559
            # Generally speaking, we don't want apport reporting on crashes in
 
1560
            # the test envirnoment unless we're specifically testing apport,
 
1561
            # so that it doesn't leak into the real system environment.  We
 
1562
            # use an env var so it propagates to subprocesses.
 
1563
            'APPORT_DISABLE': '1',
 
1564
        }
 
1565
        self._old_env = {}
 
1566
        self.addCleanup(self._restoreEnvironment)
 
1567
        for name, value in new_env.iteritems():
 
1568
            self._captureVar(name, value)
 
1569
 
 
1570
    def _captureVar(self, name, newvalue):
 
1571
        """Set an environment variable, and reset it when finished."""
 
1572
        self._old_env[name] = osutils.set_or_unset_env(name, newvalue)
 
1573
 
 
1574
    def _restoreEnvironment(self):
 
1575
        for name, value in self._old_env.iteritems():
 
1576
            osutils.set_or_unset_env(name, value)
1801
1577
 
1802
1578
    def _restoreHooks(self):
1803
1579
        for klass, (name, hooks) in self._preserved_hooks.items():
1804
1580
            setattr(klass, name, hooks)
1805
 
        self._preserved_hooks.clear()
1806
 
        bzrlib.hooks._lazy_hooks = self._preserved_lazy_hooks
1807
 
        self._preserved_lazy_hooks.clear()
1808
1581
 
1809
1582
    def knownFailure(self, reason):
1810
 
        """Declare that this test fails for a known reason
1811
 
 
1812
 
        Tests that are known to fail should generally be using expectedFailure
1813
 
        with an appropriate reverse assertion if a change could cause the test
1814
 
        to start passing. Conversely if the test has no immediate prospect of
1815
 
        succeeding then using skip is more suitable.
1816
 
 
1817
 
        When this method is called while an exception is being handled, that
1818
 
        traceback will be used, otherwise a new exception will be thrown to
1819
 
        provide one but won't be reported.
1820
 
        """
1821
 
        self._add_reason(reason)
1822
 
        try:
1823
 
            exc_info = sys.exc_info()
1824
 
            if exc_info != (None, None, None):
1825
 
                self._report_traceback(exc_info)
1826
 
            else:
1827
 
                try:
1828
 
                    raise self.failureException(reason)
1829
 
                except self.failureException:
1830
 
                    exc_info = sys.exc_info()
1831
 
            # GZ 02-08-2011: Maybe cleanup this err.exc_info attribute too?
1832
 
            raise testtools.testcase._ExpectedFailure(exc_info)
1833
 
        finally:
1834
 
            del exc_info
1835
 
 
1836
 
    def _suppress_log(self):
1837
 
        """Remove the log info from details."""
1838
 
        self.discardDetail('log')
 
1583
        """This test has failed for some known reason."""
 
1584
        raise KnownFailure(reason)
1839
1585
 
1840
1586
    def _do_skip(self, result, reason):
1841
 
        self._suppress_log()
1842
1587
        addSkip = getattr(result, 'addSkip', None)
1843
1588
        if not callable(addSkip):
1844
1589
            result.addSuccess(result)
1847
1592
 
1848
1593
    @staticmethod
1849
1594
    def _do_known_failure(self, result, e):
1850
 
        self._suppress_log()
1851
1595
        err = sys.exc_info()
1852
1596
        addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1853
1597
        if addExpectedFailure is not None:
1861
1605
            reason = 'No reason given'
1862
1606
        else:
1863
1607
            reason = e.args[0]
1864
 
        self._suppress_log ()
1865
1608
        addNotApplicable = getattr(result, 'addNotApplicable', None)
1866
1609
        if addNotApplicable is not None:
1867
1610
            result.addNotApplicable(self, reason)
1869
1612
            self._do_skip(result, reason)
1870
1613
 
1871
1614
    @staticmethod
1872
 
    def _report_skip(self, result, err):
1873
 
        """Override the default _report_skip.
1874
 
 
1875
 
        We want to strip the 'log' detail. If we waint until _do_skip, it has
1876
 
        already been formatted into the 'reason' string, and we can't pull it
1877
 
        out again.
1878
 
        """
1879
 
        self._suppress_log()
1880
 
        super(TestCase, self)._report_skip(self, result, err)
1881
 
 
1882
 
    @staticmethod
1883
 
    def _report_expected_failure(self, result, err):
1884
 
        """Strip the log.
1885
 
 
1886
 
        See _report_skip for motivation.
1887
 
        """
1888
 
        self._suppress_log()
1889
 
        super(TestCase, self)._report_expected_failure(self, result, err)
1890
 
 
1891
 
    @staticmethod
1892
1615
    def _do_unsupported_or_skip(self, result, e):
1893
1616
        reason = e.args[0]
1894
 
        self._suppress_log()
1895
1617
        addNotSupported = getattr(result, 'addNotSupported', None)
1896
1618
        if addNotSupported is not None:
1897
1619
            result.addNotSupported(self, reason)
1923
1645
            self._benchtime += time.time() - start
1924
1646
 
1925
1647
    def log(self, *args):
1926
 
        trace.mutter(*args)
 
1648
        mutter(*args)
 
1649
 
 
1650
    def _get_log(self, keep_log_file=False):
 
1651
        """Internal helper to get the log from bzrlib.trace for this test.
 
1652
 
 
1653
        Please use self.getDetails, or self.get_log to access this in test case
 
1654
        code.
 
1655
 
 
1656
        :param keep_log_file: When True, if the log is still a file on disk
 
1657
            leave it as a file on disk. When False, if the log is still a file
 
1658
            on disk, the log file is deleted and the log preserved as
 
1659
            self._log_contents.
 
1660
        :return: A string containing the log.
 
1661
        """
 
1662
        if self._log_contents is not None:
 
1663
            try:
 
1664
                self._log_contents.decode('utf8')
 
1665
            except UnicodeDecodeError:
 
1666
                unicodestr = self._log_contents.decode('utf8', 'replace')
 
1667
                self._log_contents = unicodestr.encode('utf8')
 
1668
            return self._log_contents
 
1669
        import bzrlib.trace
 
1670
        if bzrlib.trace._trace_file:
 
1671
            # flush the log file, to get all content
 
1672
            bzrlib.trace._trace_file.flush()
 
1673
        if self._log_file_name is not None:
 
1674
            logfile = open(self._log_file_name)
 
1675
            try:
 
1676
                log_contents = logfile.read()
 
1677
            finally:
 
1678
                logfile.close()
 
1679
            try:
 
1680
                log_contents.decode('utf8')
 
1681
            except UnicodeDecodeError:
 
1682
                unicodestr = log_contents.decode('utf8', 'replace')
 
1683
                log_contents = unicodestr.encode('utf8')
 
1684
            if not keep_log_file:
 
1685
                close_attempts = 0
 
1686
                max_close_attempts = 100
 
1687
                first_close_error = None
 
1688
                while close_attempts < max_close_attempts:
 
1689
                    close_attempts += 1
 
1690
                    try:
 
1691
                        self._log_file.close()
 
1692
                    except IOError, ioe:
 
1693
                        if ioe.errno is None:
 
1694
                            # No errno implies 'close() called during
 
1695
                            # concurrent operation on the same file object', so
 
1696
                            # retry.  Probably a thread is trying to write to
 
1697
                            # the log file.
 
1698
                            if first_close_error is None:
 
1699
                                first_close_error = ioe
 
1700
                            continue
 
1701
                        raise
 
1702
                    else:
 
1703
                        break
 
1704
                if close_attempts > 1:
 
1705
                    sys.stderr.write(
 
1706
                        'Unable to close log file on first attempt, '
 
1707
                        'will retry: %s\n' % (first_close_error,))
 
1708
                    if close_attempts == max_close_attempts:
 
1709
                        sys.stderr.write(
 
1710
                            'Unable to close log file after %d attempts.\n'
 
1711
                            % (max_close_attempts,))
 
1712
                self._log_file = None
 
1713
                # Permit multiple calls to get_log until we clean it up in
 
1714
                # finishLogFile
 
1715
                self._log_contents = log_contents
 
1716
                try:
 
1717
                    os.remove(self._log_file_name)
 
1718
                except OSError, e:
 
1719
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
 
1720
                        sys.stderr.write(('Unable to delete log file '
 
1721
                                             ' %r\n' % self._log_file_name))
 
1722
                    else:
 
1723
                        raise
 
1724
                self._log_file_name = None
 
1725
            return log_contents
 
1726
        else:
 
1727
            return "No log file content and no log file name."
1927
1728
 
1928
1729
    def get_log(self):
1929
1730
        """Get a unicode string containing the log from bzrlib.trace.
1979
1780
 
1980
1781
        try:
1981
1782
            try:
1982
 
                result = self.apply_redirected(
1983
 
                    ui.ui_factory.stdin,
 
1783
                result = self.apply_redirected(ui.ui_factory.stdin,
1984
1784
                    stdout, stderr,
1985
 
                    _mod_commands.run_bzr_catch_user_errors,
 
1785
                    bzrlib.commands.run_bzr_catch_user_errors,
1986
1786
                    args)
1987
1787
            except KeyboardInterrupt:
1988
1788
                # Reraise KeyboardInterrupt with contents of redirected stdout
2130
1930
    def start_bzr_subprocess(self, process_args, env_changes=None,
2131
1931
                             skip_if_plan_to_signal=False,
2132
1932
                             working_dir=None,
2133
 
                             allow_plugins=False, stderr=subprocess.PIPE):
 
1933
                             allow_plugins=False):
2134
1934
        """Start bzr in a subprocess for testing.
2135
1935
 
2136
1936
        This starts a new Python interpreter and runs bzr in there.
2145
1945
            variables. A value of None will unset the env variable.
2146
1946
            The values must be strings. The change will only occur in the
2147
1947
            child, so you don't need to fix the environment after running.
2148
 
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
2149
 
            doesn't support signalling subprocesses.
 
1948
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
 
1949
            is not available.
2150
1950
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
2151
 
        :param stderr: file to use for the subprocess's stderr.  Valid values
2152
 
            are those valid for the stderr argument of `subprocess.Popen`.
2153
 
            Default value is ``subprocess.PIPE``.
2154
1951
 
2155
1952
        :returns: Popen object for the started process.
2156
1953
        """
2157
1954
        if skip_if_plan_to_signal:
2158
 
            if os.name != "posix":
2159
 
                raise TestSkipped("Sending signals not supported")
 
1955
            if not getattr(os, 'kill', None):
 
1956
                raise TestSkipped("os.kill not available.")
2160
1957
 
2161
1958
        if env_changes is None:
2162
1959
            env_changes = {}
2182
1979
            # so we will avoid using it on all platforms, just to
2183
1980
            # make sure the code path is used, and we don't break on win32
2184
1981
            cleanup_environment()
2185
 
            # Include the subprocess's log file in the test details, in case
2186
 
            # the test fails due to an error in the subprocess.
2187
 
            self._add_subprocess_log(trace._get_bzr_log_filename())
2188
1982
            command = [sys.executable]
2189
1983
            # frozen executables don't need the path to bzr
2190
1984
            if getattr(sys, "frozen", None) is None:
2192
1986
            if not allow_plugins:
2193
1987
                command.append('--no-plugins')
2194
1988
            command.extend(process_args)
2195
 
            process = self._popen(command, stdin=subprocess.PIPE,
2196
 
                                  stdout=subprocess.PIPE,
2197
 
                                  stderr=stderr)
 
1989
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
2198
1990
        finally:
2199
1991
            restore_environment()
2200
1992
            if cwd is not None:
2202
1994
 
2203
1995
        return process
2204
1996
 
2205
 
    def _add_subprocess_log(self, log_file_path):
2206
 
        if len(self._log_files) == 0:
2207
 
            # Register an addCleanup func.  We do this on the first call to
2208
 
            # _add_subprocess_log rather than in TestCase.setUp so that this
2209
 
            # addCleanup is registered after any cleanups for tempdirs that
2210
 
            # subclasses might create, which will probably remove the log file
2211
 
            # we want to read.
2212
 
            self.addCleanup(self._subprocess_log_cleanup)
2213
 
        # self._log_files is a set, so if a log file is reused we won't grab it
2214
 
        # twice.
2215
 
        self._log_files.add(log_file_path)
2216
 
 
2217
 
    def _subprocess_log_cleanup(self):
2218
 
        for count, log_file_path in enumerate(self._log_files):
2219
 
            # We use buffer_now=True to avoid holding the file open beyond
2220
 
            # the life of this function, which might interfere with e.g.
2221
 
            # cleaning tempdirs on Windows.
2222
 
            # XXX: Testtools 0.9.5 doesn't have the content_from_file helper
2223
 
            #detail_content = content.content_from_file(
2224
 
            #    log_file_path, buffer_now=True)
2225
 
            with open(log_file_path, 'rb') as log_file:
2226
 
                log_file_bytes = log_file.read()
2227
 
            detail_content = content.Content(content.ContentType("text",
2228
 
                "plain", {"charset": "utf8"}), lambda: [log_file_bytes])
2229
 
            self.addDetail("start_bzr_subprocess-log-%d" % (count,),
2230
 
                detail_content)
2231
 
 
2232
1997
    def _popen(self, *args, **kwargs):
2233
1998
        """Place a call to Popen.
2234
1999
 
2235
2000
        Allows tests to override this method to intercept the calls made to
2236
2001
        Popen for introspection.
2237
2002
        """
2238
 
        return subprocess.Popen(*args, **kwargs)
 
2003
        return Popen(*args, **kwargs)
2239
2004
 
2240
2005
    def get_source_path(self):
2241
2006
        """Return the path of the directory containing bzrlib."""
2243
2008
 
2244
2009
    def get_bzr_path(self):
2245
2010
        """Return the path of the 'bzr' executable for this test suite."""
2246
 
        bzr_path = os.path.join(self.get_source_path(), "bzr")
 
2011
        bzr_path = self.get_source_path()+'/bzr'
2247
2012
        if not os.path.isfile(bzr_path):
2248
2013
            # We are probably installed. Assume sys.argv is the right file
2249
2014
            bzr_path = sys.argv[0]
2271
2036
        if retcode is not None and retcode != process.returncode:
2272
2037
            if process_args is None:
2273
2038
                process_args = "(unknown args)"
2274
 
            trace.mutter('Output of bzr %s:\n%s', process_args, out)
2275
 
            trace.mutter('Error for bzr %s:\n%s', process_args, err)
 
2039
            mutter('Output of bzr %s:\n%s', process_args, out)
 
2040
            mutter('Error for bzr %s:\n%s', process_args, err)
2276
2041
            self.fail('Command bzr %s failed with retcode %s != %s'
2277
2042
                      % (process_args, retcode, process.returncode))
2278
2043
        return [out, err]
2279
2044
 
2280
 
    def check_tree_shape(self, tree, shape):
2281
 
        """Compare a tree to a list of expected names.
 
2045
    def check_inventory_shape(self, inv, shape):
 
2046
        """Compare an inventory to a list of expected names.
2282
2047
 
2283
2048
        Fail if they are not precisely equal.
2284
2049
        """
2285
2050
        extras = []
2286
2051
        shape = list(shape)             # copy
2287
 
        for path, ie in tree.iter_entries_by_dir():
 
2052
        for path, ie in inv.entries():
2288
2053
            name = path.replace('\\', '/')
2289
2054
            if ie.kind == 'directory':
2290
2055
                name = name + '/'
2291
 
            if name == "/":
2292
 
                pass # ignore root entry
2293
 
            elif name in shape:
 
2056
            if name in shape:
2294
2057
                shape.remove(name)
2295
2058
            else:
2296
2059
                extras.append(name)
2337
2100
 
2338
2101
        Tests that expect to provoke LockContention errors should call this.
2339
2102
        """
2340
 
        self.overrideAttr(lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
 
2103
        self.overrideAttr(bzrlib.lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
2341
2104
 
2342
2105
    def make_utf8_encoded_stringio(self, encoding_type=None):
2343
2106
        """Return a StringIOWrapper instance, that will encode Unicode
2386
2149
class TestCaseWithMemoryTransport(TestCase):
2387
2150
    """Common test class for tests that do not need disk resources.
2388
2151
 
2389
 
    Tests that need disk resources should derive from TestCaseInTempDir
2390
 
    orTestCaseWithTransport.
 
2152
    Tests that need disk resources should derive from TestCaseWithTransport.
2391
2153
 
2392
2154
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2393
2155
 
2394
 
    For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
 
2156
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
2395
2157
    a directory which does not exist. This serves to help ensure test isolation
2396
 
    is preserved. ``test_dir`` is set to the TEST_ROOT, as is cwd, because they
2397
 
    must exist. However, TestCaseWithMemoryTransport does not offer local file
2398
 
    defaults for the transport in tests, nor does it obey the command line
 
2158
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
 
2159
    must exist. However, TestCaseWithMemoryTransport does not offer local
 
2160
    file defaults for the transport in tests, nor does it obey the command line
2399
2161
    override, so tests that accidentally write to the common directory should
2400
2162
    be rare.
2401
2163
 
2402
 
    :cvar TEST_ROOT: Directory containing all temporary directories, plus a
2403
 
        ``.bzr`` directory that stops us ascending higher into the filesystem.
 
2164
    :cvar TEST_ROOT: Directory containing all temporary directories, plus
 
2165
    a .bzr directory that stops us ascending higher into the filesystem.
2404
2166
    """
2405
2167
 
2406
2168
    TEST_ROOT = None
2424
2186
 
2425
2187
        :param relpath: a path relative to the base url.
2426
2188
        """
2427
 
        t = _mod_transport.get_transport_from_url(self.get_url(relpath))
 
2189
        t = get_transport(self.get_url(relpath))
2428
2190
        self.assertFalse(t.is_readonly())
2429
2191
        return t
2430
2192
 
2436
2198
 
2437
2199
        :param relpath: a path relative to the base url.
2438
2200
        """
2439
 
        t = _mod_transport.get_transport_from_url(
2440
 
            self.get_readonly_url(relpath))
 
2201
        t = get_transport(self.get_readonly_url(relpath))
2441
2202
        self.assertTrue(t.is_readonly())
2442
2203
        return t
2443
2204
 
2564
2325
        real branch.
2565
2326
        """
2566
2327
        root = TestCaseWithMemoryTransport.TEST_ROOT
2567
 
        try:
2568
 
            # Make sure we get a readable and accessible home for .bzr.log
2569
 
            # and/or config files, and not fallback to weird defaults (see
2570
 
            # http://pad.lv/825027).
2571
 
            self.assertIs(None, os.environ.get('BZR_HOME', None))
2572
 
            os.environ['BZR_HOME'] = root
2573
 
            wt = bzrdir.BzrDir.create_standalone_workingtree(root)
2574
 
            del os.environ['BZR_HOME']
2575
 
        except Exception, e:
2576
 
            self.fail("Fail to initialize the safety net: %r\nExiting\n" % (e,))
2577
 
        # Hack for speed: remember the raw bytes of the dirstate file so that
2578
 
        # we don't need to re-open the wt to check it hasn't changed.
2579
 
        TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE = (
2580
 
            wt.control_transport.get_bytes('dirstate'))
 
2328
        bzrdir.BzrDir.create_standalone_workingtree(root)
2581
2329
 
2582
2330
    def _check_safety_net(self):
2583
2331
        """Check that the safety .bzr directory have not been touched.
2586
2334
        propagating. This method ensures than a test did not leaked.
2587
2335
        """
2588
2336
        root = TestCaseWithMemoryTransport.TEST_ROOT
2589
 
        t = _mod_transport.get_transport_from_path(root)
2590
 
        self.permit_url(t.base)
2591
 
        if (t.get_bytes('.bzr/checkout/dirstate') != 
2592
 
                TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE):
 
2337
        self.permit_url(get_transport(root).base)
 
2338
        wt = workingtree.WorkingTree.open(root)
 
2339
        last_rev = wt.last_revision()
 
2340
        if last_rev != 'null:':
2593
2341
            # The current test have modified the /bzr directory, we need to
2594
2342
            # recreate a new one or all the followng tests will fail.
2595
2343
            # If you need to inspect its content uncomment the following line
2630
2378
    def make_branch(self, relpath, format=None):
2631
2379
        """Create a branch on the transport at relpath."""
2632
2380
        repo = self.make_repository(relpath, format=format)
2633
 
        return repo.bzrdir.create_branch(append_revisions_only=False)
2634
 
 
2635
 
    def resolve_format(self, format):
2636
 
        """Resolve an object to a ControlDir format object.
2637
 
 
2638
 
        The initial format object can either already be
2639
 
        a ControlDirFormat, None (for the default format),
2640
 
        or a string with the name of the control dir format.
2641
 
 
2642
 
        :param format: Object to resolve
2643
 
        :return A ControlDirFormat instance
2644
 
        """
2645
 
        if format is None:
2646
 
            format = 'default'
2647
 
        if isinstance(format, basestring):
2648
 
            format = bzrdir.format_registry.make_bzrdir(format)
2649
 
        return format
2650
 
 
2651
 
    def resolve_format(self, format):
2652
 
        """Resolve an object to a ControlDir format object.
2653
 
 
2654
 
        The initial format object can either already be
2655
 
        a ControlDirFormat, None (for the default format),
2656
 
        or a string with the name of the control dir format.
2657
 
 
2658
 
        :param format: Object to resolve
2659
 
        :return A ControlDirFormat instance
2660
 
        """
2661
 
        if format is None:
2662
 
            format = 'default'
2663
 
        if isinstance(format, basestring):
2664
 
            format = bzrdir.format_registry.make_bzrdir(format)
2665
 
        return format
 
2381
        return repo.bzrdir.create_branch()
2666
2382
 
2667
2383
    def make_bzrdir(self, relpath, format=None):
2668
2384
        try:
2669
2385
            # might be a relative or absolute path
2670
2386
            maybe_a_url = self.get_url(relpath)
2671
2387
            segments = maybe_a_url.rsplit('/', 1)
2672
 
            t = _mod_transport.get_transport(maybe_a_url)
 
2388
            t = get_transport(maybe_a_url)
2673
2389
            if len(segments) > 1 and segments[-1] not in ('', '.'):
2674
2390
                t.ensure_base()
2675
 
            format = self.resolve_format(format)
 
2391
            if format is None:
 
2392
                format = 'default'
 
2393
            if isinstance(format, basestring):
 
2394
                format = bzrdir.format_registry.make_bzrdir(format)
2676
2395
            return format.initialize_on_transport(t)
2677
2396
        except errors.UninitializableFormat:
2678
2397
            raise TestSkipped("Format %s is not initializable." % format)
2679
2398
 
2680
 
    def make_repository(self, relpath, shared=None, format=None):
 
2399
    def make_repository(self, relpath, shared=False, format=None):
2681
2400
        """Create a repository on our default transport at relpath.
2682
2401
 
2683
2402
        Note that relpath must be a relative path, not a full url.
2689
2408
        made_control = self.make_bzrdir(relpath, format=format)
2690
2409
        return made_control.create_repository(shared=shared)
2691
2410
 
2692
 
    def make_smart_server(self, path, backing_server=None):
2693
 
        if backing_server is None:
2694
 
            backing_server = self.get_server()
 
2411
    def make_smart_server(self, path):
2695
2412
        smart_server = test_server.SmartTCPServer_for_testing()
2696
 
        self.start_server(smart_server, backing_server)
2697
 
        remote_transport = _mod_transport.get_transport_from_url(smart_server.get_url()
2698
 
                                                   ).clone(path)
 
2413
        self.start_server(smart_server, self.get_server())
 
2414
        remote_transport = get_transport(smart_server.get_url()).clone(path)
2699
2415
        return remote_transport
2700
2416
 
2701
2417
    def make_branch_and_memory_tree(self, relpath, format=None):
2711
2427
        test_home_dir = self.test_home_dir
2712
2428
        if isinstance(test_home_dir, unicode):
2713
2429
            test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
2714
 
        self.overrideEnv('HOME', test_home_dir)
2715
 
        self.overrideEnv('BZR_HOME', test_home_dir)
 
2430
        os.environ['HOME'] = test_home_dir
 
2431
        os.environ['BZR_HOME'] = test_home_dir
2716
2432
 
2717
2433
    def setUp(self):
2718
2434
        super(TestCaseWithMemoryTransport, self).setUp()
2719
 
        # Ensure that ConnectedTransport doesn't leak sockets
2720
 
        def get_transport_from_url_with_cleanup(*args, **kwargs):
2721
 
            t = orig_get_transport_from_url(*args, **kwargs)
2722
 
            if isinstance(t, _mod_transport.ConnectedTransport):
2723
 
                self.addCleanup(t.disconnect)
2724
 
            return t
2725
 
 
2726
 
        orig_get_transport_from_url = self.overrideAttr(
2727
 
            _mod_transport, 'get_transport_from_url',
2728
 
            get_transport_from_url_with_cleanup)
2729
2435
        self._make_test_root()
2730
2436
        self.addCleanup(os.chdir, os.getcwdu())
2731
2437
        self.makeAndChdirToTestDir()
2774
2480
 
2775
2481
    OVERRIDE_PYTHON = 'python'
2776
2482
 
2777
 
    def setUp(self):
2778
 
        super(TestCaseInTempDir, self).setUp()
2779
 
        # Remove the protection set in isolated_environ, we have a proper
2780
 
        # access to disk resources now.
2781
 
        self.overrideEnv('BZR_LOG', None)
2782
 
 
2783
2483
    def check_file_contents(self, filename, expect):
2784
2484
        self.log("check contents of file %s" % filename)
2785
 
        f = file(filename)
2786
 
        try:
2787
 
            contents = f.read()
2788
 
        finally:
2789
 
            f.close()
 
2485
        contents = file(filename, 'r').read()
2790
2486
        if contents != expect:
2791
2487
            self.log("expected: %r" % expect)
2792
2488
            self.log("actually: %r" % contents)
2866
2562
                "a list or a tuple. Got %r instead" % (shape,))
2867
2563
        # It's OK to just create them using forward slashes on windows.
2868
2564
        if transport is None or transport.is_readonly():
2869
 
            transport = _mod_transport.get_transport_from_path(".")
 
2565
            transport = get_transport(".")
2870
2566
        for name in shape:
2871
2567
            self.assertIsInstance(name, basestring)
2872
2568
            if name[-1] == '/':
2882
2578
                content = "contents of %s%s" % (name.encode('utf-8'), end)
2883
2579
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
2884
2580
 
2885
 
    build_tree_contents = staticmethod(treeshape.build_tree_contents)
 
2581
    def build_tree_contents(self, shape):
 
2582
        build_tree_contents(shape)
2886
2583
 
2887
2584
    def assertInWorkingTree(self, path, root_path='.', tree=None):
2888
2585
        """Assert whether path or paths are in the WorkingTree"""
3029
2726
    """
3030
2727
 
3031
2728
    def setUp(self):
3032
 
        from bzrlib.tests import http_server
3033
2729
        super(ChrootedTestCase, self).setUp()
3034
2730
        if not self.vfs_transport_factory == memory.MemoryServer:
3035
 
            self.transport_readonly_server = http_server.HttpServer
 
2731
            self.transport_readonly_server = HttpServer
3036
2732
 
3037
2733
 
3038
2734
def condition_id_re(pattern):
3041
2737
    :param pattern: A regular expression string.
3042
2738
    :return: A callable that returns True if the re matches.
3043
2739
    """
3044
 
    filter_re = re.compile(pattern, 0)
 
2740
    filter_re = osutils.re_compile_checked(pattern, 0,
 
2741
        'test filter')
3045
2742
    def condition(test):
3046
2743
        test_id = test.id()
3047
2744
        return filter_re.search(test_id)
3299
2996
 
3300
2997
 
3301
2998
def fork_decorator(suite):
3302
 
    if getattr(os, "fork", None) is None:
3303
 
        raise errors.BzrCommandError("platform does not support fork,"
3304
 
            " try --parallel=subprocess instead.")
3305
2999
    concurrency = osutils.local_concurrency()
3306
3000
    if concurrency == 1:
3307
3001
        return suite
3362
3056
    return suite
3363
3057
 
3364
3058
 
3365
 
class TestDecorator(TestUtil.TestSuite):
 
3059
class TestDecorator(TestSuite):
3366
3060
    """A decorator for TestCase/TestSuite objects.
3367
3061
    
3368
3062
    Usually, subclasses should override __iter__(used when flattening test
3371
3065
    """
3372
3066
 
3373
3067
    def __init__(self, suite):
3374
 
        TestUtil.TestSuite.__init__(self)
 
3068
        TestSuite.__init__(self)
3375
3069
        self.addTest(suite)
3376
3070
 
3377
3071
    def countTestCases(self):
3496
3190
 
3497
3191
def partition_tests(suite, count):
3498
3192
    """Partition suite into count lists of tests."""
3499
 
    # This just assigns tests in a round-robin fashion.  On one hand this
3500
 
    # splits up blocks of related tests that might run faster if they shared
3501
 
    # resources, but on the other it avoids assigning blocks of slow tests to
3502
 
    # just one partition.  So the slowest partition shouldn't be much slower
3503
 
    # than the fastest.
3504
 
    partitions = [list() for i in range(count)]
3505
 
    tests = iter_suite_tests(suite)
3506
 
    for partition, test in itertools.izip(itertools.cycle(partitions), tests):
3507
 
        partition.append(test)
3508
 
    return partitions
 
3193
    result = []
 
3194
    tests = list(iter_suite_tests(suite))
 
3195
    tests_per_process = int(math.ceil(float(len(tests)) / count))
 
3196
    for block in range(count):
 
3197
        low_test = block * tests_per_process
 
3198
        high_test = low_test + tests_per_process
 
3199
        process_tests = tests[low_test:high_test]
 
3200
        result.append(process_tests)
 
3201
    return result
3509
3202
 
3510
3203
 
3511
3204
def workaround_zealous_crypto_random():
3545
3238
 
3546
3239
    test_blocks = partition_tests(suite, concurrency)
3547
3240
    for process_tests in test_blocks:
3548
 
        process_suite = TestUtil.TestSuite()
 
3241
        process_suite = TestSuite()
3549
3242
        process_suite.addTests(process_tests)
3550
3243
        c2pread, c2pwrite = os.pipe()
3551
3244
        pid = os.fork()
3617
3310
                '--subunit']
3618
3311
            if '--no-plugins' in sys.argv:
3619
3312
                argv.append('--no-plugins')
3620
 
            # stderr=subprocess.STDOUT would be ideal, but until we prevent
3621
 
            # noise on stderr it can interrupt the subunit protocol.
3622
 
            process = subprocess.Popen(argv, stdin=subprocess.PIPE,
3623
 
                                      stdout=subprocess.PIPE,
3624
 
                                      stderr=subprocess.PIPE,
3625
 
                                      bufsize=1)
 
3313
            # stderr=STDOUT would be ideal, but until we prevent noise on
 
3314
            # stderr it can interrupt the subunit protocol.
 
3315
            process = Popen(argv, stdin=PIPE, stdout=PIPE, stderr=PIPE,
 
3316
                bufsize=1)
3626
3317
            test = TestInSubprocess(process, test_list_file_name)
3627
3318
            result.append(test)
3628
3319
        except:
3631
3322
    return result
3632
3323
 
3633
3324
 
3634
 
class ProfileResult(testtools.ExtendedToOriginalDecorator):
 
3325
class ForwardingResult(unittest.TestResult):
 
3326
 
 
3327
    def __init__(self, target):
 
3328
        unittest.TestResult.__init__(self)
 
3329
        self.result = target
 
3330
 
 
3331
    def startTest(self, test):
 
3332
        self.result.startTest(test)
 
3333
 
 
3334
    def stopTest(self, test):
 
3335
        self.result.stopTest(test)
 
3336
 
 
3337
    def startTestRun(self):
 
3338
        self.result.startTestRun()
 
3339
 
 
3340
    def stopTestRun(self):
 
3341
        self.result.stopTestRun()
 
3342
 
 
3343
    def addSkip(self, test, reason):
 
3344
        self.result.addSkip(test, reason)
 
3345
 
 
3346
    def addSuccess(self, test):
 
3347
        self.result.addSuccess(test)
 
3348
 
 
3349
    def addError(self, test, err):
 
3350
        self.result.addError(test, err)
 
3351
 
 
3352
    def addFailure(self, test, err):
 
3353
        self.result.addFailure(test, err)
 
3354
ForwardingResult = testtools.ExtendedToOriginalDecorator
 
3355
 
 
3356
 
 
3357
class ProfileResult(ForwardingResult):
3635
3358
    """Generate profiling data for all activity between start and success.
3636
3359
    
3637
3360
    The profile data is appended to the test's _benchcalls attribute and can
3645
3368
 
3646
3369
    def startTest(self, test):
3647
3370
        self.profiler = bzrlib.lsprof.BzrProfiler()
3648
 
        # Prevent deadlocks in tests that use lsprof: those tests will
3649
 
        # unavoidably fail.
3650
 
        bzrlib.lsprof.BzrProfiler.profiler_block = 0
3651
3371
        self.profiler.start()
3652
 
        testtools.ExtendedToOriginalDecorator.startTest(self, test)
 
3372
        ForwardingResult.startTest(self, test)
3653
3373
 
3654
3374
    def addSuccess(self, test):
3655
3375
        stats = self.profiler.stop()
3659
3379
            test._benchcalls = []
3660
3380
            calls = test._benchcalls
3661
3381
        calls.append(((test.id(), "", ""), stats))
3662
 
        testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
 
3382
        ForwardingResult.addSuccess(self, test)
3663
3383
 
3664
3384
    def stopTest(self, test):
3665
 
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
 
3385
        ForwardingResult.stopTest(self, test)
3666
3386
        self.profiler = None
3667
3387
 
3668
3388
 
3674
3394
#                           rather than failing tests. And no longer raise
3675
3395
#                           LockContention when fctnl locks are not being used
3676
3396
#                           with proper exclusion rules.
3677
 
#   -Ethreads               Will display thread ident at creation/join time to
3678
 
#                           help track thread leaks
3679
 
 
3680
 
#   -Econfig_stats          Will collect statistics using addDetail
3681
3397
selftest_debug_flags = set()
3682
3398
 
3683
3399
 
3877
3593
                key, obj, help=help, info=info, override_existing=False)
3878
3594
        except KeyError:
3879
3595
            actual = self.get(key)
3880
 
            trace.note(
3881
 
                'Test prefix alias %s is already used for %s, ignoring %s'
3882
 
                % (key, actual, obj))
 
3596
            note('Test prefix alias %s is already used for %s, ignoring %s'
 
3597
                 % (key, actual, obj))
3883
3598
 
3884
3599
    def resolve_alias(self, id_start):
3885
3600
        """Replace the alias by the prefix in the given string.
3917
3632
        'bzrlib.doc',
3918
3633
        'bzrlib.tests.blackbox',
3919
3634
        'bzrlib.tests.commands',
3920
 
        'bzrlib.tests.doc_generate',
3921
3635
        'bzrlib.tests.per_branch',
3922
3636
        'bzrlib.tests.per_bzrdir',
3923
 
        'bzrlib.tests.per_controldir',
3924
 
        'bzrlib.tests.per_controldir_colo',
 
3637
        'bzrlib.tests.per_bzrdir_colo',
3925
3638
        'bzrlib.tests.per_foreign_vcs',
3926
3639
        'bzrlib.tests.per_interrepository',
3927
3640
        'bzrlib.tests.per_intertree',
3935
3648
        'bzrlib.tests.per_repository',
3936
3649
        'bzrlib.tests.per_repository_chk',
3937
3650
        'bzrlib.tests.per_repository_reference',
3938
 
        'bzrlib.tests.per_repository_vf',
3939
3651
        'bzrlib.tests.per_uifactory',
3940
3652
        'bzrlib.tests.per_versionedfile',
3941
3653
        'bzrlib.tests.per_workingtree',
3942
3654
        'bzrlib.tests.test__annotator',
3943
3655
        'bzrlib.tests.test__bencode',
3944
 
        'bzrlib.tests.test__btree_serializer',
3945
3656
        'bzrlib.tests.test__chk_map',
3946
3657
        'bzrlib.tests.test__dirstate_helpers',
3947
3658
        'bzrlib.tests.test__groupcompress',
3975
3686
        'bzrlib.tests.test_commit_merge',
3976
3687
        'bzrlib.tests.test_config',
3977
3688
        'bzrlib.tests.test_conflicts',
3978
 
        'bzrlib.tests.test_controldir',
3979
3689
        'bzrlib.tests.test_counted_lock',
3980
3690
        'bzrlib.tests.test_crash',
3981
3691
        'bzrlib.tests.test_decorators',
3982
3692
        'bzrlib.tests.test_delta',
3983
3693
        'bzrlib.tests.test_debug',
 
3694
        'bzrlib.tests.test_deprecated_graph',
3984
3695
        'bzrlib.tests.test_diff',
3985
3696
        'bzrlib.tests.test_directory_service',
3986
3697
        'bzrlib.tests.test_dirstate',
3987
3698
        'bzrlib.tests.test_email_message',
3988
3699
        'bzrlib.tests.test_eol_filters',
3989
3700
        'bzrlib.tests.test_errors',
3990
 
        'bzrlib.tests.test_estimate_compressed_size',
3991
3701
        'bzrlib.tests.test_export',
3992
 
        'bzrlib.tests.test_export_pot',
3993
3702
        'bzrlib.tests.test_extract',
3994
 
        'bzrlib.tests.test_features',
3995
3703
        'bzrlib.tests.test_fetch',
3996
 
        'bzrlib.tests.test_fixtures',
3997
3704
        'bzrlib.tests.test_fifo_cache',
3998
3705
        'bzrlib.tests.test_filters',
3999
 
        'bzrlib.tests.test_filter_tree',
4000
3706
        'bzrlib.tests.test_ftp_transport',
4001
3707
        'bzrlib.tests.test_foreign',
4002
3708
        'bzrlib.tests.test_generate_docs',
4011
3717
        'bzrlib.tests.test_http',
4012
3718
        'bzrlib.tests.test_http_response',
4013
3719
        'bzrlib.tests.test_https_ca_bundle',
4014
 
        'bzrlib.tests.test_i18n',
4015
3720
        'bzrlib.tests.test_identitymap',
4016
3721
        'bzrlib.tests.test_ignores',
4017
3722
        'bzrlib.tests.test_index',
4022
3727
        'bzrlib.tests.test_knit',
4023
3728
        'bzrlib.tests.test_lazy_import',
4024
3729
        'bzrlib.tests.test_lazy_regex',
4025
 
        'bzrlib.tests.test_library_state',
4026
3730
        'bzrlib.tests.test_lock',
4027
3731
        'bzrlib.tests.test_lockable_files',
4028
3732
        'bzrlib.tests.test_lockdir',
4030
3734
        'bzrlib.tests.test_lru_cache',
4031
3735
        'bzrlib.tests.test_lsprof',
4032
3736
        'bzrlib.tests.test_mail_client',
4033
 
        'bzrlib.tests.test_matchers',
4034
3737
        'bzrlib.tests.test_memorytree',
4035
3738
        'bzrlib.tests.test_merge',
4036
3739
        'bzrlib.tests.test_merge3',
4037
3740
        'bzrlib.tests.test_merge_core',
4038
3741
        'bzrlib.tests.test_merge_directive',
4039
 
        'bzrlib.tests.test_mergetools',
4040
3742
        'bzrlib.tests.test_missing',
4041
3743
        'bzrlib.tests.test_msgeditor',
4042
3744
        'bzrlib.tests.test_multiparent',
4051
3753
        'bzrlib.tests.test_permissions',
4052
3754
        'bzrlib.tests.test_plugins',
4053
3755
        'bzrlib.tests.test_progress',
4054
 
        'bzrlib.tests.test_pyutils',
4055
3756
        'bzrlib.tests.test_read_bundle',
4056
3757
        'bzrlib.tests.test_reconcile',
4057
3758
        'bzrlib.tests.test_reconfigure',
4066
3767
        'bzrlib.tests.test_rio',
4067
3768
        'bzrlib.tests.test_rules',
4068
3769
        'bzrlib.tests.test_sampler',
4069
 
        'bzrlib.tests.test_scenarios',
4070
3770
        'bzrlib.tests.test_script',
4071
3771
        'bzrlib.tests.test_selftest',
4072
3772
        'bzrlib.tests.test_serializer',
4077
3777
        'bzrlib.tests.test_smart',
4078
3778
        'bzrlib.tests.test_smart_add',
4079
3779
        'bzrlib.tests.test_smart_request',
4080
 
        'bzrlib.tests.test_smart_signals',
4081
3780
        'bzrlib.tests.test_smart_transport',
4082
3781
        'bzrlib.tests.test_smtp_connection',
4083
3782
        'bzrlib.tests.test_source',
4089
3788
        'bzrlib.tests.test_switch',
4090
3789
        'bzrlib.tests.test_symbol_versioning',
4091
3790
        'bzrlib.tests.test_tag',
4092
 
        'bzrlib.tests.test_test_server',
4093
3791
        'bzrlib.tests.test_testament',
4094
3792
        'bzrlib.tests.test_textfile',
4095
3793
        'bzrlib.tests.test_textmerge',
4096
 
        'bzrlib.tests.test_cethread',
4097
3794
        'bzrlib.tests.test_timestamp',
4098
3795
        'bzrlib.tests.test_trace',
4099
3796
        'bzrlib.tests.test_transactions',
4102
3799
        'bzrlib.tests.test_transport_log',
4103
3800
        'bzrlib.tests.test_tree',
4104
3801
        'bzrlib.tests.test_treebuilder',
4105
 
        'bzrlib.tests.test_treeshape',
4106
3802
        'bzrlib.tests.test_tsort',
4107
3803
        'bzrlib.tests.test_tuned_gzip',
4108
3804
        'bzrlib.tests.test_ui',
4110
3806
        'bzrlib.tests.test_upgrade',
4111
3807
        'bzrlib.tests.test_upgrade_stacked',
4112
3808
        'bzrlib.tests.test_urlutils',
4113
 
        'bzrlib.tests.test_utextwrap',
4114
3809
        'bzrlib.tests.test_version',
4115
3810
        'bzrlib.tests.test_version_info',
4116
 
        'bzrlib.tests.test_versionedfile',
4117
3811
        'bzrlib.tests.test_weave',
4118
3812
        'bzrlib.tests.test_whitebox',
4119
3813
        'bzrlib.tests.test_win32utils',
4133
3827
        'bzrlib',
4134
3828
        'bzrlib.branchbuilder',
4135
3829
        'bzrlib.decorators',
 
3830
        'bzrlib.export',
4136
3831
        'bzrlib.inventory',
4137
3832
        'bzrlib.iterablefile',
4138
3833
        'bzrlib.lockdir',
4139
3834
        'bzrlib.merge3',
4140
3835
        'bzrlib.option',
4141
 
        'bzrlib.pyutils',
4142
3836
        'bzrlib.symbol_versioning',
4143
3837
        'bzrlib.tests',
4144
 
        'bzrlib.tests.fixtures',
4145
3838
        'bzrlib.timestamp',
4146
 
        'bzrlib.transport.http',
4147
3839
        'bzrlib.version_info_formats.format_custom',
4148
3840
        ]
4149
3841
 
4202
3894
        try:
4203
3895
            # note that this really does mean "report only" -- doctest
4204
3896
            # still runs the rest of the examples
4205
 
            doc_suite = IsolatedDocTestSuite(
4206
 
                mod, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
 
3897
            doc_suite = doctest.DocTestSuite(mod,
 
3898
                optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
4207
3899
        except ValueError, e:
4208
3900
            print '**failed to get doctest for: %s\n%s' % (mod, e)
4209
3901
            raise
4212
3904
        suite.addTest(doc_suite)
4213
3905
 
4214
3906
    default_encoding = sys.getdefaultencoding()
4215
 
    for name, plugin in _mod_plugin.plugins().items():
 
3907
    for name, plugin in bzrlib.plugin.plugins().items():
4216
3908
        if not interesting_module(plugin.module.__name__):
4217
3909
            continue
4218
3910
        plugin_suite = plugin.test_suite()
4224
3916
        if plugin_suite is not None:
4225
3917
            suite.addTest(plugin_suite)
4226
3918
        if default_encoding != sys.getdefaultencoding():
4227
 
            trace.warning(
 
3919
            bzrlib.trace.warning(
4228
3920
                'Plugin "%s" tried to reset default encoding to: %s', name,
4229
3921
                sys.getdefaultencoding())
4230
3922
            reload(sys)
4245
3937
            # Some tests mentioned in the list are not in the test suite. The
4246
3938
            # list may be out of date, report to the tester.
4247
3939
            for id in not_found:
4248
 
                trace.warning('"%s" not found in the test suite', id)
 
3940
                bzrlib.trace.warning('"%s" not found in the test suite', id)
4249
3941
        for id in duplicates:
4250
 
            trace.warning('"%s" is used as an id by several tests', id)
 
3942
            bzrlib.trace.warning('"%s" is used as an id by several tests', id)
4251
3943
 
4252
3944
    return suite
4253
3945
 
4254
3946
 
4255
 
def multiply_scenarios(*scenarios):
4256
 
    """Multiply two or more iterables of scenarios.
4257
 
 
4258
 
    It is safe to pass scenario generators or iterators.
4259
 
 
4260
 
    :returns: A list of compound scenarios: the cross-product of all 
4261
 
        scenarios, with the names concatenated and the parameters
4262
 
        merged together.
4263
 
    """
4264
 
    return reduce(_multiply_two_scenarios, map(list, scenarios))
4265
 
 
4266
 
 
4267
 
def _multiply_two_scenarios(scenarios_left, scenarios_right):
 
3947
def multiply_scenarios(scenarios_left, scenarios_right):
4268
3948
    """Multiply two sets of scenarios.
4269
3949
 
4270
3950
    :returns: the cartesian product of the two sets of scenarios, that is
4301
3981
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
4302
3982
    ...     [('one', dict(param=1)),
4303
3983
    ...      ('two', dict(param=2))],
4304
 
    ...     TestUtil.TestSuite())
 
3984
    ...     TestSuite())
4305
3985
    >>> tests = list(iter_suite_tests(r))
4306
3986
    >>> len(tests)
4307
3987
    2
4354
4034
    :param new_id: The id to assign to it.
4355
4035
    :return: The new test.
4356
4036
    """
4357
 
    new_test = copy.copy(test)
 
4037
    new_test = copy(test)
4358
4038
    new_test.id = lambda: new_id
4359
 
    # XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
4360
 
    # causes cloned tests to share the 'details' dict.  This makes it hard to
4361
 
    # read the test output for parameterized tests, because tracebacks will be
4362
 
    # associated with irrelevant tests.
4363
 
    try:
4364
 
        details = new_test._TestCase__details
4365
 
    except AttributeError:
4366
 
        # must be a different version of testtools than expected.  Do nothing.
4367
 
        pass
4368
 
    else:
4369
 
        # Reset the '__details' dict.
4370
 
        new_test._TestCase__details = {}
4371
4039
    return new_test
4372
4040
 
4373
4041
 
4394
4062
        the module is available.
4395
4063
    """
4396
4064
 
4397
 
    from bzrlib.tests.features import ModuleAvailableFeature
4398
 
    py_module = pyutils.get_named_object(py_module_name)
 
4065
    py_module = __import__(py_module_name, {}, {}, ['NO_SUCH_ATTRIB'])
4399
4066
    scenarios = [
4400
4067
        ('python', {'module': py_module}),
4401
4068
    ]
4434
4101
        if test_id != None:
4435
4102
            ui.ui_factory.clear_term()
4436
4103
            sys.stderr.write('\nWhile running: %s\n' % (test_id,))
4437
 
        # Ugly, but the last thing we want here is fail, so bear with it.
4438
 
        printable_e = str(e).decode(osutils.get_user_encoding(), 'replace'
4439
 
                                    ).encode('ascii', 'replace')
4440
4104
        sys.stderr.write('Unable to remove testing dir %s\n%s'
4441
 
                         % (os.path.basename(dirname), printable_e))
 
4105
                         % (os.path.basename(dirname), e))
 
4106
 
 
4107
 
 
4108
class Feature(object):
 
4109
    """An operating system Feature."""
 
4110
 
 
4111
    def __init__(self):
 
4112
        self._available = None
 
4113
 
 
4114
    def available(self):
 
4115
        """Is the feature available?
 
4116
 
 
4117
        :return: True if the feature is available.
 
4118
        """
 
4119
        if self._available is None:
 
4120
            self._available = self._probe()
 
4121
        return self._available
 
4122
 
 
4123
    def _probe(self):
 
4124
        """Implement this method in concrete features.
 
4125
 
 
4126
        :return: True if the feature is available.
 
4127
        """
 
4128
        raise NotImplementedError
 
4129
 
 
4130
    def __str__(self):
 
4131
        if getattr(self, 'feature_name', None):
 
4132
            return self.feature_name()
 
4133
        return self.__class__.__name__
 
4134
 
 
4135
 
 
4136
class _SymlinkFeature(Feature):
 
4137
 
 
4138
    def _probe(self):
 
4139
        return osutils.has_symlinks()
 
4140
 
 
4141
    def feature_name(self):
 
4142
        return 'symlinks'
 
4143
 
 
4144
SymlinkFeature = _SymlinkFeature()
 
4145
 
 
4146
 
 
4147
class _HardlinkFeature(Feature):
 
4148
 
 
4149
    def _probe(self):
 
4150
        return osutils.has_hardlinks()
 
4151
 
 
4152
    def feature_name(self):
 
4153
        return 'hardlinks'
 
4154
 
 
4155
HardlinkFeature = _HardlinkFeature()
 
4156
 
 
4157
 
 
4158
class _OsFifoFeature(Feature):
 
4159
 
 
4160
    def _probe(self):
 
4161
        return getattr(os, 'mkfifo', None)
 
4162
 
 
4163
    def feature_name(self):
 
4164
        return 'filesystem fifos'
 
4165
 
 
4166
OsFifoFeature = _OsFifoFeature()
 
4167
 
 
4168
 
 
4169
class _UnicodeFilenameFeature(Feature):
 
4170
    """Does the filesystem support Unicode filenames?"""
 
4171
 
 
4172
    def _probe(self):
 
4173
        try:
 
4174
            # Check for character combinations unlikely to be covered by any
 
4175
            # single non-unicode encoding. We use the characters
 
4176
            # - greek small letter alpha (U+03B1) and
 
4177
            # - braille pattern dots-123456 (U+283F).
 
4178
            os.stat(u'\u03b1\u283f')
 
4179
        except UnicodeEncodeError:
 
4180
            return False
 
4181
        except (IOError, OSError):
 
4182
            # The filesystem allows the Unicode filename but the file doesn't
 
4183
            # exist.
 
4184
            return True
 
4185
        else:
 
4186
            # The filesystem allows the Unicode filename and the file exists,
 
4187
            # for some reason.
 
4188
            return True
 
4189
 
 
4190
UnicodeFilenameFeature = _UnicodeFilenameFeature()
 
4191
 
 
4192
 
 
4193
class _CompatabilityThunkFeature(Feature):
 
4194
    """This feature is just a thunk to another feature.
 
4195
 
 
4196
    It issues a deprecation warning if it is accessed, to let you know that you
 
4197
    should really use a different feature.
 
4198
    """
 
4199
 
 
4200
    def __init__(self, dep_version, module, name,
 
4201
                 replacement_name, replacement_module=None):
 
4202
        super(_CompatabilityThunkFeature, self).__init__()
 
4203
        self._module = module
 
4204
        if replacement_module is None:
 
4205
            replacement_module = module
 
4206
        self._replacement_module = replacement_module
 
4207
        self._name = name
 
4208
        self._replacement_name = replacement_name
 
4209
        self._dep_version = dep_version
 
4210
        self._feature = None
 
4211
 
 
4212
    def _ensure(self):
 
4213
        if self._feature is None:
 
4214
            depr_msg = self._dep_version % ('%s.%s'
 
4215
                                            % (self._module, self._name))
 
4216
            use_msg = ' Use %s.%s instead.' % (self._replacement_module,
 
4217
                                               self._replacement_name)
 
4218
            symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
 
4219
            # Import the new feature and use it as a replacement for the
 
4220
            # deprecated one.
 
4221
            mod = __import__(self._replacement_module, {}, {},
 
4222
                             [self._replacement_name])
 
4223
            self._feature = getattr(mod, self._replacement_name)
 
4224
 
 
4225
    def _probe(self):
 
4226
        self._ensure()
 
4227
        return self._feature._probe()
 
4228
 
 
4229
 
 
4230
class ModuleAvailableFeature(Feature):
 
4231
    """This is a feature than describes a module we want to be available.
 
4232
 
 
4233
    Declare the name of the module in __init__(), and then after probing, the
 
4234
    module will be available as 'self.module'.
 
4235
 
 
4236
    :ivar module: The module if it is available, else None.
 
4237
    """
 
4238
 
 
4239
    def __init__(self, module_name):
 
4240
        super(ModuleAvailableFeature, self).__init__()
 
4241
        self.module_name = module_name
 
4242
 
 
4243
    def _probe(self):
 
4244
        try:
 
4245
            self._module = __import__(self.module_name, {}, {}, [''])
 
4246
            return True
 
4247
        except ImportError:
 
4248
            return False
 
4249
 
 
4250
    @property
 
4251
    def module(self):
 
4252
        if self.available(): # Make sure the probe has been done
 
4253
            return self._module
 
4254
        return None
 
4255
 
 
4256
    def feature_name(self):
 
4257
        return self.module_name
 
4258
 
 
4259
 
 
4260
# This is kept here for compatibility, it is recommended to use
 
4261
# 'bzrlib.tests.feature.paramiko' instead
 
4262
ParamikoFeature = _CompatabilityThunkFeature(
 
4263
    deprecated_in((2,1,0)),
 
4264
    'bzrlib.tests.features', 'ParamikoFeature', 'paramiko')
4442
4265
 
4443
4266
 
4444
4267
def probe_unicode_in_user_encoding():
4474
4297
    return None
4475
4298
 
4476
4299
 
 
4300
class _HTTPSServerFeature(Feature):
 
4301
    """Some tests want an https Server, check if one is available.
 
4302
 
 
4303
    Right now, the only way this is available is under python2.6 which provides
 
4304
    an ssl module.
 
4305
    """
 
4306
 
 
4307
    def _probe(self):
 
4308
        try:
 
4309
            import ssl
 
4310
            return True
 
4311
        except ImportError:
 
4312
            return False
 
4313
 
 
4314
    def feature_name(self):
 
4315
        return 'HTTPSServer'
 
4316
 
 
4317
 
 
4318
HTTPSServerFeature = _HTTPSServerFeature()
 
4319
 
 
4320
 
 
4321
class _UnicodeFilename(Feature):
 
4322
    """Does the filesystem support Unicode filenames?"""
 
4323
 
 
4324
    def _probe(self):
 
4325
        try:
 
4326
            os.stat(u'\u03b1')
 
4327
        except UnicodeEncodeError:
 
4328
            return False
 
4329
        except (IOError, OSError):
 
4330
            # The filesystem allows the Unicode filename but the file doesn't
 
4331
            # exist.
 
4332
            return True
 
4333
        else:
 
4334
            # The filesystem allows the Unicode filename and the file exists,
 
4335
            # for some reason.
 
4336
            return True
 
4337
 
 
4338
UnicodeFilename = _UnicodeFilename()
 
4339
 
 
4340
 
 
4341
class _UTF8Filesystem(Feature):
 
4342
    """Is the filesystem UTF-8?"""
 
4343
 
 
4344
    def _probe(self):
 
4345
        if osutils._fs_enc.upper() in ('UTF-8', 'UTF8'):
 
4346
            return True
 
4347
        return False
 
4348
 
 
4349
UTF8Filesystem = _UTF8Filesystem()
 
4350
 
 
4351
 
 
4352
class _BreakinFeature(Feature):
 
4353
    """Does this platform support the breakin feature?"""
 
4354
 
 
4355
    def _probe(self):
 
4356
        from bzrlib import breakin
 
4357
        if breakin.determine_signal() is None:
 
4358
            return False
 
4359
        if sys.platform == 'win32':
 
4360
            # Windows doesn't have os.kill, and we catch the SIGBREAK signal.
 
4361
            # We trigger SIGBREAK via a Console api so we need ctypes to
 
4362
            # access the function
 
4363
            try:
 
4364
                import ctypes
 
4365
            except OSError:
 
4366
                return False
 
4367
        return True
 
4368
 
 
4369
    def feature_name(self):
 
4370
        return "SIGQUIT or SIGBREAK w/ctypes on win32"
 
4371
 
 
4372
 
 
4373
BreakinFeature = _BreakinFeature()
 
4374
 
 
4375
 
 
4376
class _CaseInsCasePresFilenameFeature(Feature):
 
4377
    """Is the file-system case insensitive, but case-preserving?"""
 
4378
 
 
4379
    def _probe(self):
 
4380
        fileno, name = tempfile.mkstemp(prefix='MixedCase')
 
4381
        try:
 
4382
            # first check truly case-preserving for created files, then check
 
4383
            # case insensitive when opening existing files.
 
4384
            name = osutils.normpath(name)
 
4385
            base, rel = osutils.split(name)
 
4386
            found_rel = osutils.canonical_relpath(base, name)
 
4387
            return (found_rel == rel
 
4388
                    and os.path.isfile(name.upper())
 
4389
                    and os.path.isfile(name.lower()))
 
4390
        finally:
 
4391
            os.close(fileno)
 
4392
            os.remove(name)
 
4393
 
 
4394
    def feature_name(self):
 
4395
        return "case-insensitive case-preserving filesystem"
 
4396
 
 
4397
CaseInsCasePresFilenameFeature = _CaseInsCasePresFilenameFeature()
 
4398
 
 
4399
 
 
4400
class _CaseInsensitiveFilesystemFeature(Feature):
 
4401
    """Check if underlying filesystem is case-insensitive but *not* case
 
4402
    preserving.
 
4403
    """
 
4404
    # Note that on Windows, Cygwin, MacOS etc, the file-systems are far
 
4405
    # more likely to be case preserving, so this case is rare.
 
4406
 
 
4407
    def _probe(self):
 
4408
        if CaseInsCasePresFilenameFeature.available():
 
4409
            return False
 
4410
 
 
4411
        if TestCaseWithMemoryTransport.TEST_ROOT is None:
 
4412
            root = osutils.mkdtemp(prefix='testbzr-', suffix='.tmp')
 
4413
            TestCaseWithMemoryTransport.TEST_ROOT = root
 
4414
        else:
 
4415
            root = TestCaseWithMemoryTransport.TEST_ROOT
 
4416
        tdir = osutils.mkdtemp(prefix='case-sensitive-probe-', suffix='',
 
4417
            dir=root)
 
4418
        name_a = osutils.pathjoin(tdir, 'a')
 
4419
        name_A = osutils.pathjoin(tdir, 'A')
 
4420
        os.mkdir(name_a)
 
4421
        result = osutils.isdir(name_A)
 
4422
        _rmtree_temp_dir(tdir)
 
4423
        return result
 
4424
 
 
4425
    def feature_name(self):
 
4426
        return 'case-insensitive filesystem'
 
4427
 
 
4428
CaseInsensitiveFilesystemFeature = _CaseInsensitiveFilesystemFeature()
 
4429
 
 
4430
 
 
4431
class _CaseSensitiveFilesystemFeature(Feature):
 
4432
 
 
4433
    def _probe(self):
 
4434
        if CaseInsCasePresFilenameFeature.available():
 
4435
            return False
 
4436
        elif CaseInsensitiveFilesystemFeature.available():
 
4437
            return False
 
4438
        else:
 
4439
            return True
 
4440
 
 
4441
    def feature_name(self):
 
4442
        return 'case-sensitive filesystem'
 
4443
 
 
4444
# new coding style is for feature instances to be lowercase
 
4445
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
 
4446
 
 
4447
 
 
4448
# Kept for compatibility, use bzrlib.tests.features.subunit instead
 
4449
SubUnitFeature = _CompatabilityThunkFeature(
 
4450
    deprecated_in((2,1,0)),
 
4451
    'bzrlib.tests.features', 'SubUnitFeature', 'subunit')
4477
4452
# Only define SubUnitBzrRunner if subunit is available.
4478
4453
try:
4479
4454
    from subunit import TestProtocolClient
4480
4455
    from subunit.test_results import AutoTimingTestResultDecorator
4481
 
    class SubUnitBzrProtocolClient(TestProtocolClient):
4482
 
 
4483
 
        def addSuccess(self, test, details=None):
4484
 
            # The subunit client always includes the details in the subunit
4485
 
            # stream, but we don't want to include it in ours.
4486
 
            if details is not None and 'log' in details:
4487
 
                del details['log']
4488
 
            return super(SubUnitBzrProtocolClient, self).addSuccess(
4489
 
                test, details)
4490
 
 
4491
4456
    class SubUnitBzrRunner(TextTestRunner):
4492
4457
        def run(self, test):
4493
4458
            result = AutoTimingTestResultDecorator(
4494
 
                SubUnitBzrProtocolClient(self.stream))
 
4459
                TestProtocolClient(self.stream))
4495
4460
            test.run(result)
4496
4461
            return result
4497
4462
except ImportError:
4498
4463
    pass
4499
4464
 
4500
 
 
4501
 
@deprecated_function(deprecated_in((2, 5, 0)))
4502
 
def ModuleAvailableFeature(name):
4503
 
    from bzrlib.tests import features
4504
 
    return features.ModuleAvailableFeature(name)
4505
 
    
 
4465
class _PosixPermissionsFeature(Feature):
 
4466
 
 
4467
    def _probe(self):
 
4468
        def has_perms():
 
4469
            # create temporary file and check if specified perms are maintained.
 
4470
            import tempfile
 
4471
 
 
4472
            write_perms = stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR
 
4473
            f = tempfile.mkstemp(prefix='bzr_perms_chk_')
 
4474
            fd, name = f
 
4475
            os.close(fd)
 
4476
            os.chmod(name, write_perms)
 
4477
 
 
4478
            read_perms = os.stat(name).st_mode & 0777
 
4479
            os.unlink(name)
 
4480
            return (write_perms == read_perms)
 
4481
 
 
4482
        return (os.name == 'posix') and has_perms()
 
4483
 
 
4484
    def feature_name(self):
 
4485
        return 'POSIX permissions support'
 
4486
 
 
4487
posix_permissions_feature = _PosixPermissionsFeature()