~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Vincent Ladeuil
  • Date: 2010-07-01 06:40:14 UTC
  • mto: (5247.3.46 smart-server-leaks)
  • mto: This revision was merged to the branch mainline in revision 5396.
  • Revision ID: v.ladeuil+lp@free.fr-20100701064014-p3zyz3eevfrkl8i4
Fix vicious spurious spaces.

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
34
34
import difflib
35
35
import doctest
36
36
import errno
37
 
import itertools
38
37
import logging
 
38
import math
39
39
import os
40
 
import platform
41
40
import pprint
42
41
import random
43
42
import re
55
54
import testtools
56
55
# nb: check this before importing anything else from within it
57
56
_testtools_version = getattr(testtools, '__version__', ())
58
 
if _testtools_version < (0, 9, 5):
59
 
    raise ImportError("need at least testtools 0.9.5: %s is %r"
 
57
if _testtools_version < (0, 9, 2):
 
58
    raise ImportError("need at least testtools 0.9.2: %s is %r"
60
59
        % (testtools.__file__, _testtools_version))
61
60
from testtools import content
62
61
 
63
 
import bzrlib
64
62
from bzrlib import (
65
63
    branchbuilder,
66
64
    bzrdir,
67
65
    chk_map,
68
 
    commands as _mod_commands,
69
66
    config,
70
67
    debug,
71
68
    errors,
72
69
    hooks,
73
70
    lock as _mod_lock,
74
 
    lockdir,
75
71
    memorytree,
76
72
    osutils,
77
 
    plugin as _mod_plugin,
78
 
    pyutils,
 
73
    progress,
79
74
    ui,
80
75
    urlutils,
81
76
    registry,
82
 
    symbol_versioning,
83
 
    trace,
84
77
    transport as _mod_transport,
85
78
    workingtree,
86
79
    )
 
80
import bzrlib.branch
 
81
import bzrlib.commands
 
82
import bzrlib.timestamp
 
83
import bzrlib.export
 
84
import bzrlib.inventory
 
85
import bzrlib.iterablefile
 
86
import bzrlib.lockdir
87
87
try:
88
88
    import bzrlib.lsprof
89
89
except ImportError:
90
90
    # lsprof not available
91
91
    pass
92
 
from bzrlib.smart import client, request
 
92
from bzrlib.merge import merge_inner
 
93
import bzrlib.merge3
 
94
import bzrlib.plugin
 
95
from bzrlib.smart import client, request, server
 
96
import bzrlib.store
 
97
from bzrlib import symbol_versioning
 
98
from bzrlib.symbol_versioning import (
 
99
    DEPRECATED_PARAMETER,
 
100
    deprecated_function,
 
101
    deprecated_in,
 
102
    deprecated_method,
 
103
    deprecated_passed,
 
104
    )
 
105
import bzrlib.trace
93
106
from bzrlib.transport import (
94
107
    memory,
95
108
    pathfilter,
96
109
    )
 
110
from bzrlib.trace import mutter, note
97
111
from bzrlib.tests import (
98
112
    test_server,
99
113
    TestUtil,
101
115
    )
102
116
from bzrlib.ui import NullProgressView
103
117
from bzrlib.ui.text import TextUIFactory
 
118
import bzrlib.version_info_formats.format_custom
 
119
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
104
120
 
105
121
# Mark this python module as being part of the implementation
106
122
# of unittest: this gives us better tracebacks where the last
118
134
SUBUNIT_SEEK_SET = 0
119
135
SUBUNIT_SEEK_CUR = 1
120
136
 
121
 
# These are intentionally brought into this namespace. That way plugins, etc
122
 
# can just "from bzrlib.tests import TestCase, TestLoader, etc"
123
 
TestSuite = TestUtil.TestSuite
124
 
TestLoader = TestUtil.TestLoader
125
 
 
126
 
# Tests should run in a clean and clearly defined environment. The goal is to
127
 
# keep them isolated from the running environment as mush as possible. The test
128
 
# framework ensures the variables defined below are set (or deleted if the
129
 
# value is None) before a test is run and reset to their original value after
130
 
# the test is run. Generally if some code depends on an environment variable,
131
 
# the tests should start without this variable in the environment. There are a
132
 
# few exceptions but you shouldn't violate this rule lightly.
133
 
isolated_environ = {
134
 
    'BZR_HOME': None,
135
 
    'HOME': None,
136
 
    # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
137
 
    # tests do check our impls match APPDATA
138
 
    'BZR_EDITOR': None, # test_msgeditor manipulates this variable
139
 
    'VISUAL': None,
140
 
    'EDITOR': None,
141
 
    'BZR_EMAIL': None,
142
 
    'BZREMAIL': None, # may still be present in the environment
143
 
    'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
144
 
    'BZR_PROGRESS_BAR': None,
145
 
    # This should trap leaks to ~/.bzr.log. This occurs when tests use TestCase
146
 
    # as a base class instead of TestCaseInTempDir. Tests inheriting from
147
 
    # TestCase should not use disk resources, BZR_LOG is one.
148
 
    'BZR_LOG': '/you-should-use-TestCaseInTempDir-if-you-need-a-log-file',
149
 
    'BZR_PLUGIN_PATH': None,
150
 
    'BZR_DISABLE_PLUGINS': None,
151
 
    'BZR_PLUGINS_AT': None,
152
 
    'BZR_CONCURRENCY': None,
153
 
    # Make sure that any text ui tests are consistent regardless of
154
 
    # the environment the test case is run in; you may want tests that
155
 
    # test other combinations.  'dumb' is a reasonable guess for tests
156
 
    # going to a pipe or a StringIO.
157
 
    'TERM': 'dumb',
158
 
    'LINES': '25',
159
 
    'COLUMNS': '80',
160
 
    'BZR_COLUMNS': '80',
161
 
    # Disable SSH Agent
162
 
    'SSH_AUTH_SOCK': None,
163
 
    # Proxies
164
 
    'http_proxy': None,
165
 
    'HTTP_PROXY': None,
166
 
    'https_proxy': None,
167
 
    'HTTPS_PROXY': None,
168
 
    'no_proxy': None,
169
 
    'NO_PROXY': None,
170
 
    'all_proxy': None,
171
 
    'ALL_PROXY': None,
172
 
    # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
173
 
    # least. If you do (care), please update this comment
174
 
    # -- vila 20080401
175
 
    'ftp_proxy': None,
176
 
    'FTP_PROXY': None,
177
 
    'BZR_REMOTE_PATH': None,
178
 
    # Generally speaking, we don't want apport reporting on crashes in
179
 
    # the test envirnoment unless we're specifically testing apport,
180
 
    # so that it doesn't leak into the real system environment.  We
181
 
    # use an env var so it propagates to subprocesses.
182
 
    'APPORT_DISABLE': '1',
183
 
    }
184
 
 
185
 
 
186
 
def override_os_environ(test, env=None):
187
 
    """Modify os.environ keeping a copy.
188
 
    
189
 
    :param test: A test instance
190
 
 
191
 
    :param env: A dict containing variable definitions to be installed
192
 
    """
193
 
    if env is None:
194
 
        env = isolated_environ
195
 
    test._original_os_environ = dict([(var, value)
196
 
                                      for var, value in os.environ.iteritems()])
197
 
    for var, value in env.iteritems():
198
 
        osutils.set_or_unset_env(var, value)
199
 
        if var not in test._original_os_environ:
200
 
            # The var is new, add it with a value of None, so
201
 
            # restore_os_environ will delete it
202
 
            test._original_os_environ[var] = None
203
 
 
204
 
 
205
 
def restore_os_environ(test):
206
 
    """Restore os.environ to its original state.
207
 
 
208
 
    :param test: A test instance previously passed to override_os_environ.
209
 
    """
210
 
    for var, value in test._original_os_environ.iteritems():
211
 
        # Restore the original value (or delete it if the value has been set to
212
 
        # None in override_os_environ).
213
 
        osutils.set_or_unset_env(var, value)
214
 
 
215
 
 
216
 
class ExtendedTestResult(testtools.TextTestResult):
 
137
 
 
138
class ExtendedTestResult(unittest._TextTestResult):
217
139
    """Accepts, reports and accumulates the results of running tests.
218
140
 
219
141
    Compared to the unittest version this class adds support for
240
162
        :param bench_history: Optionally, a writable file object to accumulate
241
163
            benchmark results.
242
164
        """
243
 
        testtools.TextTestResult.__init__(self, stream)
 
165
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
244
166
        if bench_history is not None:
245
167
            from bzrlib.version import _get_bzr_source_tree
246
168
            src_tree = _get_bzr_source_tree()
267
189
        self.count = 0
268
190
        self._overall_start_time = time.time()
269
191
        self._strict = strict
270
 
        self._first_thread_leaker_id = None
271
 
        self._tests_leaking_threads_count = 0
272
 
        self._traceback_from_test = None
273
192
 
274
193
    def stopTestRun(self):
275
194
        run = self.testsRun
276
195
        actionTaken = "Ran"
277
196
        stopTime = time.time()
278
197
        timeTaken = stopTime - self.startTime
279
 
        # GZ 2010-07-19: Seems testtools has no printErrors method, and though
280
 
        #                the parent class method is similar have to duplicate
281
 
        self._show_list('ERROR', self.errors)
282
 
        self._show_list('FAIL', self.failures)
283
 
        self.stream.write(self.sep2)
284
 
        self.stream.write("%s %d test%s in %.3fs\n\n" % (actionTaken,
 
198
        self.printErrors()
 
199
        self.stream.writeln(self.separator2)
 
200
        self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
285
201
                            run, run != 1 and "s" or "", timeTaken))
 
202
        self.stream.writeln()
286
203
        if not self.wasSuccessful():
287
204
            self.stream.write("FAILED (")
288
205
            failed, errored = map(len, (self.failures, self.errors))
295
212
                if failed or errored: self.stream.write(", ")
296
213
                self.stream.write("known_failure_count=%d" %
297
214
                    self.known_failure_count)
298
 
            self.stream.write(")\n")
 
215
            self.stream.writeln(")")
299
216
        else:
300
217
            if self.known_failure_count:
301
 
                self.stream.write("OK (known_failures=%d)\n" %
 
218
                self.stream.writeln("OK (known_failures=%d)" %
302
219
                    self.known_failure_count)
303
220
            else:
304
 
                self.stream.write("OK\n")
 
221
                self.stream.writeln("OK")
305
222
        if self.skip_count > 0:
306
223
            skipped = self.skip_count
307
 
            self.stream.write('%d test%s skipped\n' %
 
224
            self.stream.writeln('%d test%s skipped' %
308
225
                                (skipped, skipped != 1 and "s" or ""))
309
226
        if self.unsupported:
310
227
            for feature, count in sorted(self.unsupported.items()):
311
 
                self.stream.write("Missing feature '%s' skipped %d tests.\n" %
 
228
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
312
229
                    (feature, count))
313
230
        if self._strict:
314
231
            ok = self.wasStrictlySuccessful()
315
232
        else:
316
233
            ok = self.wasSuccessful()
317
 
        if self._first_thread_leaker_id:
 
234
        if TestCase._first_thread_leaker_id:
318
235
            self.stream.write(
319
236
                '%s is leaking threads among %d leaking tests.\n' % (
320
 
                self._first_thread_leaker_id,
321
 
                self._tests_leaking_threads_count))
 
237
                TestCase._first_thread_leaker_id,
 
238
                TestCase._leaking_threads_tests))
322
239
            # We don't report the main thread as an active one.
323
240
            self.stream.write(
324
241
                '%d non-main threads were left active in the end.\n'
325
 
                % (len(self._active_threads) - 1))
 
242
                % (TestCase._active_threads - 1))
326
243
 
327
244
    def getDescription(self, test):
328
245
        return test.id()
335
252
 
336
253
    def _elapsedTestTimeString(self):
337
254
        """Return a time string for the overall time the current test has taken."""
338
 
        return self._formatTime(self._delta_to_float(
339
 
            self._now() - self._start_datetime))
 
255
        return self._formatTime(time.time() - self._start_time)
340
256
 
341
257
    def _testTimeString(self, testCase):
342
258
        benchmark_time = self._extractBenchmarkTime(testCase)
353
269
 
354
270
    def _shortened_test_description(self, test):
355
271
        what = test.id()
356
 
        what = re.sub(r'^bzrlib\.tests\.', '', what)
 
272
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
357
273
        return what
358
274
 
359
 
    # GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
360
 
    #                multiple times in a row, because the handler is added for
361
 
    #                each test but the container list is shared between cases.
362
 
    #                See lp:498869 lp:625574 and lp:637725 for background.
363
 
    def _record_traceback_from_test(self, exc_info):
364
 
        """Store the traceback from passed exc_info tuple till"""
365
 
        self._traceback_from_test = exc_info[2]
366
 
 
367
275
    def startTest(self, test):
368
 
        super(ExtendedTestResult, self).startTest(test)
 
276
        unittest.TestResult.startTest(self, test)
369
277
        if self.count == 0:
370
278
            self.startTests()
371
 
        self.count += 1
372
279
        self.report_test_start(test)
373
280
        test.number = self.count
374
281
        self._recordTestStartTime()
375
 
        # Make testtools cases give us the real traceback on failure
376
 
        addOnException = getattr(test, "addOnException", None)
377
 
        if addOnException is not None:
378
 
            addOnException(self._record_traceback_from_test)
379
 
        # Only check for thread leaks on bzrlib derived test cases
380
 
        if isinstance(test, TestCase):
381
 
            test.addCleanup(self._check_leaked_threads, test)
382
 
 
383
 
    def stopTest(self, test):
384
 
        super(ExtendedTestResult, self).stopTest(test)
385
 
        # Manually break cycles, means touching various private things but hey
386
 
        getDetails = getattr(test, "getDetails", None)
387
 
        if getDetails is not None:
388
 
            getDetails().clear()
389
 
        type_equality_funcs = getattr(test, "_type_equality_funcs", None)
390
 
        if type_equality_funcs is not None:
391
 
            type_equality_funcs.clear()
392
 
        self._traceback_from_test = None
393
282
 
394
283
    def startTests(self):
395
 
        self.report_tests_starting()
396
 
        self._active_threads = threading.enumerate()
397
 
 
398
 
    def _check_leaked_threads(self, test):
399
 
        """See if any threads have leaked since last call
400
 
 
401
 
        A sample of live threads is stored in the _active_threads attribute,
402
 
        when this method runs it compares the current live threads and any not
403
 
        in the previous sample are treated as having leaked.
404
 
        """
405
 
        now_active_threads = set(threading.enumerate())
406
 
        threads_leaked = now_active_threads.difference(self._active_threads)
407
 
        if threads_leaked:
408
 
            self._report_thread_leak(test, threads_leaked, now_active_threads)
409
 
            self._tests_leaking_threads_count += 1
410
 
            if self._first_thread_leaker_id is None:
411
 
                self._first_thread_leaker_id = test.id()
412
 
            self._active_threads = now_active_threads
 
284
        import platform
 
285
        if getattr(sys, 'frozen', None) is None:
 
286
            bzr_path = osutils.realpath(sys.argv[0])
 
287
        else:
 
288
            bzr_path = sys.executable
 
289
        self.stream.write(
 
290
            'bzr selftest: %s\n' % (bzr_path,))
 
291
        self.stream.write(
 
292
            '   %s\n' % (
 
293
                    bzrlib.__path__[0],))
 
294
        self.stream.write(
 
295
            '   bzr-%s python-%s %s\n' % (
 
296
                    bzrlib.version_string,
 
297
                    bzrlib._format_version_tuple(sys.version_info),
 
298
                    platform.platform(aliased=1),
 
299
                    ))
 
300
        self.stream.write('\n')
413
301
 
414
302
    def _recordTestStartTime(self):
415
303
        """Record that a test has started."""
416
 
        self._start_datetime = self._now()
 
304
        self._start_time = time.time()
 
305
 
 
306
    def _cleanupLogFile(self, test):
 
307
        # We can only do this if we have one of our TestCases, not if
 
308
        # we have a doctest.
 
309
        setKeepLogfile = getattr(test, 'setKeepLogfile', None)
 
310
        if setKeepLogfile is not None:
 
311
            setKeepLogfile()
417
312
 
418
313
    def addError(self, test, err):
419
314
        """Tell result that test finished with an error.
421
316
        Called from the TestCase run() method when the test
422
317
        fails with an unexpected error.
423
318
        """
424
 
        self._post_mortem(self._traceback_from_test)
425
 
        super(ExtendedTestResult, self).addError(test, err)
 
319
        self._post_mortem()
 
320
        unittest.TestResult.addError(self, test, err)
426
321
        self.error_count += 1
427
322
        self.report_error(test, err)
428
323
        if self.stop_early:
429
324
            self.stop()
 
325
        self._cleanupLogFile(test)
430
326
 
431
327
    def addFailure(self, test, err):
432
328
        """Tell result that test failed.
434
330
        Called from the TestCase run() method when the test
435
331
        fails because e.g. an assert() method failed.
436
332
        """
437
 
        self._post_mortem(self._traceback_from_test)
438
 
        super(ExtendedTestResult, self).addFailure(test, err)
 
333
        self._post_mortem()
 
334
        unittest.TestResult.addFailure(self, test, err)
439
335
        self.failure_count += 1
440
336
        self.report_failure(test, err)
441
337
        if self.stop_early:
442
338
            self.stop()
 
339
        self._cleanupLogFile(test)
443
340
 
444
341
    def addSuccess(self, test, details=None):
445
342
        """Tell result that test completed successfully.
453
350
                    self._formatTime(benchmark_time),
454
351
                    test.id()))
455
352
        self.report_success(test)
456
 
        super(ExtendedTestResult, self).addSuccess(test)
 
353
        self._cleanupLogFile(test)
 
354
        unittest.TestResult.addSuccess(self, test)
457
355
        test._log_contents = ''
458
356
 
459
357
    def addExpectedFailure(self, test, err):
460
358
        self.known_failure_count += 1
461
359
        self.report_known_failure(test, err)
462
360
 
463
 
    def addUnexpectedSuccess(self, test, details=None):
464
 
        """Tell result the test unexpectedly passed, counting as a failure
465
 
 
466
 
        When the minimum version of testtools required becomes 0.9.8 this
467
 
        can be updated to use the new handling there.
468
 
        """
469
 
        super(ExtendedTestResult, self).addFailure(test, details=details)
470
 
        self.failure_count += 1
471
 
        self.report_unexpected_success(test,
472
 
            "".join(details["reason"].iter_text()))
473
 
        if self.stop_early:
474
 
            self.stop()
475
 
 
476
361
    def addNotSupported(self, test, feature):
477
362
        """The test will not be run because of a missing feature.
478
363
        """
495
380
        self.not_applicable_count += 1
496
381
        self.report_not_applicable(test, reason)
497
382
 
498
 
    def _post_mortem(self, tb=None):
 
383
    def _post_mortem(self):
499
384
        """Start a PDB post mortem session."""
500
385
        if os.environ.get('BZR_TEST_PDB', None):
501
 
            import pdb
502
 
            pdb.post_mortem(tb)
 
386
            import pdb;pdb.post_mortem()
503
387
 
504
388
    def progress(self, offset, whence):
505
389
        """The test is adjusting the count of tests to run."""
510
394
        else:
511
395
            raise errors.BzrError("Unknown whence %r" % whence)
512
396
 
513
 
    def report_tests_starting(self):
514
 
        """Display information before the test run begins"""
515
 
        if getattr(sys, 'frozen', None) is None:
516
 
            bzr_path = osutils.realpath(sys.argv[0])
517
 
        else:
518
 
            bzr_path = sys.executable
519
 
        self.stream.write(
520
 
            'bzr selftest: %s\n' % (bzr_path,))
521
 
        self.stream.write(
522
 
            '   %s\n' % (
523
 
                    bzrlib.__path__[0],))
524
 
        self.stream.write(
525
 
            '   bzr-%s python-%s %s\n' % (
526
 
                    bzrlib.version_string,
527
 
                    bzrlib._format_version_tuple(sys.version_info),
528
 
                    platform.platform(aliased=1),
529
 
                    ))
530
 
        self.stream.write('\n')
531
 
 
532
 
    def report_test_start(self, test):
533
 
        """Display information on the test just about to be run"""
534
 
 
535
 
    def _report_thread_leak(self, test, leaked_threads, active_threads):
536
 
        """Display information on a test that leaked one or more threads"""
537
 
        # GZ 2010-09-09: A leak summary reported separately from the general
538
 
        #                thread debugging would be nice. Tests under subunit
539
 
        #                need something not using stream, perhaps adding a
540
 
        #                testtools details object would be fitting.
541
 
        if 'threads' in selftest_debug_flags:
542
 
            self.stream.write('%s is leaking, active is now %d\n' %
543
 
                (test.id(), len(active_threads)))
 
397
    def report_cleaning_up(self):
 
398
        pass
544
399
 
545
400
    def startTestRun(self):
546
401
        self.startTime = time.time()
583
438
        self.pb.finished()
584
439
        super(TextTestResult, self).stopTestRun()
585
440
 
586
 
    def report_tests_starting(self):
587
 
        super(TextTestResult, self).report_tests_starting()
 
441
    def startTestRun(self):
 
442
        super(TextTestResult, self).startTestRun()
588
443
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
589
444
 
 
445
    def printErrors(self):
 
446
        # clear the pb to make room for the error listing
 
447
        self.pb.clear()
 
448
        super(TextTestResult, self).printErrors()
 
449
 
590
450
    def _progress_prefix_text(self):
591
451
        # the longer this text, the less space we have to show the test
592
452
        # name...
614
474
        return a
615
475
 
616
476
    def report_test_start(self, test):
 
477
        self.count += 1
617
478
        self.pb.update(
618
479
                self._progress_prefix_text()
619
480
                + ' '
637
498
    def report_known_failure(self, test, err):
638
499
        pass
639
500
 
640
 
    def report_unexpected_success(self, test, reason):
641
 
        self.stream.write('FAIL: %s\n    %s: %s\n' % (
642
 
            self._test_description(test),
643
 
            "Unexpected success. Should have failed",
644
 
            reason,
645
 
            ))
646
 
 
647
501
    def report_skip(self, test, reason):
648
502
        pass
649
503
 
653
507
    def report_unsupported(self, test, feature):
654
508
        """test cannot be run because feature is missing."""
655
509
 
 
510
    def report_cleaning_up(self):
 
511
        self.pb.update('Cleaning up')
 
512
 
656
513
 
657
514
class VerboseTestResult(ExtendedTestResult):
658
515
    """Produce long output, with one line per test run plus times"""
665
522
            result = a_string
666
523
        return result.ljust(final_width)
667
524
 
668
 
    def report_tests_starting(self):
 
525
    def startTestRun(self):
 
526
        super(VerboseTestResult, self).startTestRun()
669
527
        self.stream.write('running %d tests...\n' % self.num_tests)
670
 
        super(VerboseTestResult, self).report_tests_starting()
671
528
 
672
529
    def report_test_start(self, test):
 
530
        self.count += 1
673
531
        name = self._shortened_test_description(test)
674
532
        width = osutils.terminal_width()
675
533
        if width is not None:
687
545
        return '%s%s' % (indent, err[1])
688
546
 
689
547
    def report_error(self, test, err):
690
 
        self.stream.write('ERROR %s\n%s\n'
 
548
        self.stream.writeln('ERROR %s\n%s'
691
549
                % (self._testTimeString(test),
692
550
                   self._error_summary(err)))
693
551
 
694
552
    def report_failure(self, test, err):
695
 
        self.stream.write(' FAIL %s\n%s\n'
 
553
        self.stream.writeln(' FAIL %s\n%s'
696
554
                % (self._testTimeString(test),
697
555
                   self._error_summary(err)))
698
556
 
699
557
    def report_known_failure(self, test, err):
700
 
        self.stream.write('XFAIL %s\n%s\n'
 
558
        self.stream.writeln('XFAIL %s\n%s'
701
559
                % (self._testTimeString(test),
702
560
                   self._error_summary(err)))
703
561
 
704
 
    def report_unexpected_success(self, test, reason):
705
 
        self.stream.write(' FAIL %s\n%s: %s\n'
706
 
                % (self._testTimeString(test),
707
 
                   "Unexpected success. Should have failed",
708
 
                   reason))
709
 
 
710
562
    def report_success(self, test):
711
 
        self.stream.write('   OK %s\n' % self._testTimeString(test))
 
563
        self.stream.writeln('   OK %s' % self._testTimeString(test))
712
564
        for bench_called, stats in getattr(test, '_benchcalls', []):
713
 
            self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
 
565
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
714
566
            stats.pprint(file=self.stream)
715
567
        # flush the stream so that we get smooth output. This verbose mode is
716
568
        # used to show the output in PQM.
717
569
        self.stream.flush()
718
570
 
719
571
    def report_skip(self, test, reason):
720
 
        self.stream.write(' SKIP %s\n%s\n'
 
572
        self.stream.writeln(' SKIP %s\n%s'
721
573
                % (self._testTimeString(test), reason))
722
574
 
723
575
    def report_not_applicable(self, test, reason):
724
 
        self.stream.write('  N/A %s\n    %s\n'
 
576
        self.stream.writeln('  N/A %s\n    %s'
725
577
                % (self._testTimeString(test), reason))
726
578
 
727
579
    def report_unsupported(self, test, feature):
728
580
        """test cannot be run because feature is missing."""
729
 
        self.stream.write("NODEP %s\n    The feature '%s' is not available.\n"
 
581
        self.stream.writeln("NODEP %s\n    The feature '%s' is not available."
730
582
                %(self._testTimeString(test), feature))
731
583
 
732
584
 
759
611
            encode = codec[0]
760
612
        else:
761
613
            encode = codec.encode
762
 
        # GZ 2010-09-08: Really we don't want to be writing arbitrary bytes,
763
 
        #                so should swap to the plain codecs.StreamWriter
764
 
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream,
765
 
            "backslashreplace")
 
614
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
766
615
        stream.encoding = new_encoding
767
 
        self.stream = stream
 
616
        self.stream = unittest._WritelnDecorator(stream)
768
617
        self.descriptions = descriptions
769
618
        self.verbosity = verbosity
770
619
        self._bench_history = bench_history
918
767
        return NullProgressView()
919
768
 
920
769
 
921
 
def isolated_doctest_setUp(test):
922
 
    override_os_environ(test)
923
 
 
924
 
 
925
 
def isolated_doctest_tearDown(test):
926
 
    restore_os_environ(test)
927
 
 
928
 
 
929
 
def IsolatedDocTestSuite(*args, **kwargs):
930
 
    """Overrides doctest.DocTestSuite to handle isolation.
931
 
 
932
 
    The method is really a factory and users are expected to use it as such.
933
 
    """
934
 
 
935
 
    kwargs['setUp'] = isolated_doctest_setUp
936
 
    kwargs['tearDown'] = isolated_doctest_tearDown
937
 
    return doctest.DocTestSuite(*args, **kwargs)
938
 
 
939
 
 
940
770
class TestCase(testtools.TestCase):
941
771
    """Base class for bzr unit tests.
942
772
 
953
783
    routine, and to build and check bzr trees.
954
784
 
955
785
    In addition to the usual method of overriding tearDown(), this class also
956
 
    allows subclasses to register cleanup functions via addCleanup, which are
 
786
    allows subclasses to register functions into the _cleanups list, which is
957
787
    run in order as the object is torn down.  It's less likely this will be
958
788
    accidentally overlooked.
959
789
    """
960
790
 
961
 
    _log_file = None
 
791
    _active_threads = None
 
792
    _leaking_threads_tests = 0
 
793
    _first_thread_leaker_id = None
 
794
    _log_file_name = None
962
795
    # record lsprof data when performing benchmark calls.
963
796
    _gather_lsprof_in_benchmarks = False
964
797
 
965
798
    def __init__(self, methodName='testMethod'):
966
799
        super(TestCase, self).__init__(methodName)
 
800
        self._cleanups = []
967
801
        self._directory_isolation = True
968
802
        self.exception_handlers.insert(0,
969
803
            (UnavailableFeature, self._do_unsupported_or_skip))
974
808
        super(TestCase, self).setUp()
975
809
        for feature in getattr(self, '_test_needs_features', []):
976
810
            self.requireFeature(feature)
 
811
        self._log_contents = None
 
812
        self.addDetail("log", content.Content(content.ContentType("text",
 
813
            "plain", {"charset": "utf8"}),
 
814
            lambda:[self._get_log(keep_log_file=True)]))
977
815
        self._cleanEnvironment()
978
816
        self._silenceUI()
979
817
        self._startLogFile()
983
821
        self._track_transports()
984
822
        self._track_locks()
985
823
        self._clear_debug_flags()
986
 
        # Isolate global verbosity level, to make sure it's reproducible
987
 
        # between tests.  We should get rid of this altogether: bug 656694. --
988
 
        # mbp 20101008
989
 
        self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
990
 
        # Isolate config option expansion until its default value for bzrlib is
991
 
        # settled on or a the FIXME associated with _get_expand_default_value
992
 
        # is addressed -- vila 20110219
993
 
        self.overrideAttr(config, '_expand_default_value', None)
994
 
        self._log_files = set()
995
 
        # Each key in the ``_counters`` dict holds a value for a different
996
 
        # counter. When the test ends, addDetail() should be used to output the
997
 
        # counter values. This happens in install_counter_hook().
998
 
        self._counters = {}
999
 
        if 'config_stats' in selftest_debug_flags:
1000
 
            self._install_config_stats_hooks()
 
824
        TestCase._active_threads = threading.activeCount()
 
825
        self.addCleanup(self._check_leaked_threads)
1001
826
 
1002
827
    def debug(self):
1003
828
        # debug a frame up.
1004
829
        import pdb
1005
830
        pdb.Pdb().set_trace(sys._getframe().f_back)
1006
831
 
1007
 
    def discardDetail(self, name):
1008
 
        """Extend the addDetail, getDetails api so we can remove a detail.
1009
 
 
1010
 
        eg. bzr always adds the 'log' detail at startup, but we don't want to
1011
 
        include it for skipped, xfail, etc tests.
1012
 
 
1013
 
        It is safe to call this for a detail that doesn't exist, in case this
1014
 
        gets called multiple times.
1015
 
        """
1016
 
        # We cheat. details is stored in __details which means we shouldn't
1017
 
        # touch it. but getDetails() returns the dict directly, so we can
1018
 
        # mutate it.
1019
 
        details = self.getDetails()
1020
 
        if name in details:
1021
 
            del details[name]
1022
 
 
1023
 
    def install_counter_hook(self, hooks, name, counter_name=None):
1024
 
        """Install a counting hook.
1025
 
 
1026
 
        Any hook can be counted as long as it doesn't need to return a value.
1027
 
 
1028
 
        :param hooks: Where the hook should be installed.
1029
 
 
1030
 
        :param name: The hook name that will be counted.
1031
 
 
1032
 
        :param counter_name: The counter identifier in ``_counters``, defaults
1033
 
            to ``name``.
1034
 
        """
1035
 
        _counters = self._counters # Avoid closing over self
1036
 
        if counter_name is None:
1037
 
            counter_name = name
1038
 
        if _counters.has_key(counter_name):
1039
 
            raise AssertionError('%s is already used as a counter name'
1040
 
                                  % (counter_name,))
1041
 
        _counters[counter_name] = 0
1042
 
        self.addDetail(counter_name, content.Content(content.UTF8_TEXT,
1043
 
            lambda: ['%d' % (_counters[counter_name],)]))
1044
 
        def increment_counter(*args, **kwargs):
1045
 
            _counters[counter_name] += 1
1046
 
        label = 'count %s calls' % (counter_name,)
1047
 
        hooks.install_named_hook(name, increment_counter, label)
1048
 
        self.addCleanup(hooks.uninstall_named_hook, name, label)
1049
 
 
1050
 
    def _install_config_stats_hooks(self):
1051
 
        """Install config hooks to count hook calls.
1052
 
 
1053
 
        """
1054
 
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1055
 
            self.install_counter_hook(config.ConfigHooks, hook_name,
1056
 
                                       'config.%s' % (hook_name,))
1057
 
 
1058
 
        # The OldConfigHooks are private and need special handling to protect
1059
 
        # against recursive tests (tests that run other tests), so we just do
1060
 
        # manually what registering them into _builtin_known_hooks will provide
1061
 
        # us.
1062
 
        self.overrideAttr(config, 'OldConfigHooks', config._OldConfigHooks())
1063
 
        for hook_name in ('get', 'set', 'remove', 'load', 'save'):
1064
 
            self.install_counter_hook(config.OldConfigHooks, hook_name,
1065
 
                                      'old_config.%s' % (hook_name,))
 
832
    def _check_leaked_threads(self):
 
833
        active = threading.activeCount()
 
834
        leaked_threads = active - TestCase._active_threads
 
835
        TestCase._active_threads = active
 
836
        # If some tests make the number of threads *decrease*, we'll consider
 
837
        # that they are just observing old threads dieing, not agressively kill
 
838
        # random threads. So we don't report these tests as leaking. The risk
 
839
        # is that we have false positives that way (the test see 2 threads
 
840
        # going away but leak one) but it seems less likely than the actual
 
841
        # false positives (the test see threads going away and does not leak).
 
842
        if leaked_threads > 0:
 
843
            if 'threads' in selftest_debug_flags:
 
844
                print '%s is leaking, active is now %d' % (self.id(), active)
 
845
            TestCase._leaking_threads_tests += 1
 
846
            if TestCase._first_thread_leaker_id is None:
 
847
                TestCase._first_thread_leaker_id = self.id()
1066
848
 
1067
849
    def _clear_debug_flags(self):
1068
850
        """Prevent externally set debug flags affecting tests.
1079
861
 
1080
862
    def _clear_hooks(self):
1081
863
        # prevent hooks affecting tests
1082
 
        known_hooks = hooks.known_hooks
1083
864
        self._preserved_hooks = {}
1084
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1085
 
            current_hooks = getattr(parent, name)
 
865
        for key, factory in hooks.known_hooks.items():
 
866
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
867
            current_hooks = hooks.known_hooks_key_to_object(key)
1086
868
            self._preserved_hooks[parent] = (name, current_hooks)
1087
 
        self._preserved_lazy_hooks = hooks._lazy_hooks
1088
 
        hooks._lazy_hooks = {}
1089
869
        self.addCleanup(self._restoreHooks)
1090
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1091
 
            factory = known_hooks.get(key)
 
870
        for key, factory in hooks.known_hooks.items():
 
871
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
1092
872
            setattr(parent, name, factory())
1093
873
        # this hook should always be installed
1094
874
        request._install_hook()
1123
903
        # break some locks on purpose and should be taken into account by
1124
904
        # considering that breaking a lock is just a dirty way of releasing it.
1125
905
        if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
1126
 
            message = (
1127
 
                'Different number of acquired and '
1128
 
                'released or broken locks.\n'
1129
 
                'acquired=%s\n'
1130
 
                'released=%s\n'
1131
 
                'broken=%s\n' %
1132
 
                (acquired_locks, released_locks, broken_locks))
 
906
            message = ('Different number of acquired and '
 
907
                       'released or broken locks. (%s, %s + %s)' %
 
908
                       (acquired_locks, released_locks, broken_locks))
1133
909
            if not self._lock_check_thorough:
1134
910
                # Rather than fail, just warn
1135
911
                print "Broken test %s: %s" % (self, message)
1192
968
            try:
1193
969
                workingtree.WorkingTree.open(path)
1194
970
            except (errors.NotBranchError, errors.NoWorkingTree):
1195
 
                raise TestSkipped('Needs a working tree of bzr sources')
 
971
                return
1196
972
        finally:
1197
973
            self.enable_directory_isolation()
1198
974
 
1310
1086
        except UnicodeError, e:
1311
1087
            # If we can't compare without getting a UnicodeError, then
1312
1088
            # obviously they are different
1313
 
            trace.mutter('UnicodeError: %s', e)
 
1089
            mutter('UnicodeError: %s', e)
1314
1090
        if message:
1315
1091
            message += '\n'
1316
1092
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1355
1131
                         'st_mtime did not match')
1356
1132
        self.assertEqual(expected.st_ctime, actual.st_ctime,
1357
1133
                         'st_ctime did not match')
1358
 
        if sys.platform == 'win32':
 
1134
        if sys.platform != 'win32':
1359
1135
            # On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1360
1136
            # is 'dev' that varies, in python 2.5 (6?) it is st_ino that is
1361
 
            # odd. We just force it to always be 0 to avoid any problems.
1362
 
            self.assertEqual(0, expected.st_dev)
1363
 
            self.assertEqual(0, actual.st_dev)
1364
 
            self.assertEqual(0, expected.st_ino)
1365
 
            self.assertEqual(0, actual.st_ino)
1366
 
        else:
 
1137
            # odd. Regardless we shouldn't actually try to assert anything
 
1138
            # about their values
1367
1139
            self.assertEqual(expected.st_dev, actual.st_dev,
1368
1140
                             'st_dev did not match')
1369
1141
            self.assertEqual(expected.st_ino, actual.st_ino,
1378
1150
                length, len(obj_with_len), obj_with_len))
1379
1151
 
1380
1152
    def assertLogsError(self, exception_class, func, *args, **kwargs):
1381
 
        """Assert that `func(*args, **kwargs)` quietly logs a specific error.
 
1153
        """Assert that func(*args, **kwargs) quietly logs a specific exception.
1382
1154
        """
 
1155
        from bzrlib import trace
1383
1156
        captured = []
1384
1157
        orig_log_exception_quietly = trace.log_exception_quietly
1385
1158
        try:
1386
1159
            def capture():
1387
1160
                orig_log_exception_quietly()
1388
 
                captured.append(sys.exc_info()[1])
 
1161
                captured.append(sys.exc_info())
1389
1162
            trace.log_exception_quietly = capture
1390
1163
            func(*args, **kwargs)
1391
1164
        finally:
1392
1165
            trace.log_exception_quietly = orig_log_exception_quietly
1393
1166
        self.assertLength(1, captured)
1394
 
        err = captured[0]
 
1167
        err = captured[0][1]
1395
1168
        self.assertIsInstance(err, exception_class)
1396
1169
        return err
1397
1170
 
1434
1207
        if haystack.find(needle) == -1:
1435
1208
            self.fail("string %r not found in '''%s'''" % (needle, haystack))
1436
1209
 
1437
 
    def assertNotContainsString(self, haystack, needle):
1438
 
        if haystack.find(needle) != -1:
1439
 
            self.fail("string %r found in '''%s'''" % (needle, haystack))
1440
 
 
1441
1210
    def assertSubset(self, sublist, superlist):
1442
1211
        """Assert that every entry in sublist is present in superlist."""
1443
1212
        missing = set(sublist) - set(superlist)
1532
1301
 
1533
1302
    def assertFileEqual(self, content, path):
1534
1303
        """Fail if path does not contain 'content'."""
1535
 
        self.assertPathExists(path)
 
1304
        self.failUnlessExists(path)
1536
1305
        f = file(path, 'rb')
1537
1306
        try:
1538
1307
            s = f.read()
1548
1317
        else:
1549
1318
            self.assertEqual(expected_docstring, obj.__doc__)
1550
1319
 
1551
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1552
1320
    def failUnlessExists(self, path):
1553
 
        return self.assertPathExists(path)
1554
 
 
1555
 
    def assertPathExists(self, path):
1556
1321
        """Fail unless path or paths, which may be abs or relative, exist."""
1557
1322
        if not isinstance(path, basestring):
1558
1323
            for p in path:
1559
 
                self.assertPathExists(p)
 
1324
                self.failUnlessExists(p)
1560
1325
        else:
1561
 
            self.assertTrue(osutils.lexists(path),
1562
 
                path + " does not exist")
 
1326
            self.failUnless(osutils.lexists(path),path+" does not exist")
1563
1327
 
1564
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1565
1328
    def failIfExists(self, path):
1566
 
        return self.assertPathDoesNotExist(path)
1567
 
 
1568
 
    def assertPathDoesNotExist(self, path):
1569
1329
        """Fail if path or paths, which may be abs or relative, exist."""
1570
1330
        if not isinstance(path, basestring):
1571
1331
            for p in path:
1572
 
                self.assertPathDoesNotExist(p)
 
1332
                self.failIfExists(p)
1573
1333
        else:
1574
 
            self.assertFalse(osutils.lexists(path),
1575
 
                path + " exists")
 
1334
            self.failIf(osutils.lexists(path),path+" exists")
1576
1335
 
1577
1336
    def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
1578
1337
        """A helper for callDeprecated and applyDeprecated.
1604
1363
        not other callers that go direct to the warning module.
1605
1364
 
1606
1365
        To test that a deprecated method raises an error, do something like
1607
 
        this (remember that both assertRaises and applyDeprecated delays *args
1608
 
        and **kwargs passing)::
 
1366
        this::
1609
1367
 
1610
1368
            self.assertRaises(errors.ReservedId,
1611
1369
                self.applyDeprecated,
1693
1451
 
1694
1452
        The file is removed as the test is torn down.
1695
1453
        """
1696
 
        pseudo_log_file = StringIO()
1697
 
        def _get_log_contents_for_weird_testtools_api():
1698
 
            return [pseudo_log_file.getvalue().decode(
1699
 
                "utf-8", "replace").encode("utf-8")]
1700
 
        self.addDetail("log", content.Content(content.ContentType("text",
1701
 
            "plain", {"charset": "utf8"}),
1702
 
            _get_log_contents_for_weird_testtools_api))
1703
 
        self._log_file = pseudo_log_file
1704
 
        self._log_memento = trace.push_log_file(self._log_file)
 
1454
        fileno, name = tempfile.mkstemp(suffix='.log', prefix='testbzr')
 
1455
        self._log_file = os.fdopen(fileno, 'w+')
 
1456
        self._log_memento = bzrlib.trace.push_log_file(self._log_file)
 
1457
        self._log_file_name = name
1705
1458
        self.addCleanup(self._finishLogFile)
1706
1459
 
1707
1460
    def _finishLogFile(self):
1708
1461
        """Finished with the log file.
1709
1462
 
1710
 
        Close the file and delete it.
 
1463
        Close the file and delete it, unless setKeepLogfile was called.
1711
1464
        """
1712
 
        if trace._trace_file:
 
1465
        if bzrlib.trace._trace_file:
1713
1466
            # flush the log file, to get all content
1714
 
            trace._trace_file.flush()
1715
 
        trace.pop_log_file(self._log_memento)
 
1467
            bzrlib.trace._trace_file.flush()
 
1468
        bzrlib.trace.pop_log_file(self._log_memento)
 
1469
        # Cache the log result and delete the file on disk
 
1470
        self._get_log(False)
1716
1471
 
1717
1472
    def thisFailsStrictLockCheck(self):
1718
1473
        """It is known that this test would fail with -Dstrict_locks.
1727
1482
        """
1728
1483
        debug.debug_flags.discard('strict_locks')
1729
1484
 
 
1485
    def addCleanup(self, callable, *args, **kwargs):
 
1486
        """Arrange to run a callable when this case is torn down.
 
1487
 
 
1488
        Callables are run in the reverse of the order they are registered,
 
1489
        ie last-in first-out.
 
1490
        """
 
1491
        self._cleanups.append((callable, args, kwargs))
 
1492
 
1730
1493
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1731
1494
        """Overrides an object attribute restoring it after the test.
1732
1495
 
1746
1509
            setattr(obj, attr_name, new)
1747
1510
        return value
1748
1511
 
1749
 
    def overrideEnv(self, name, new):
1750
 
        """Set an environment variable, and reset it after the test.
1751
 
 
1752
 
        :param name: The environment variable name.
1753
 
 
1754
 
        :param new: The value to set the variable to. If None, the 
1755
 
            variable is deleted from the environment.
1756
 
 
1757
 
        :returns: The actual variable value.
1758
 
        """
1759
 
        value = osutils.set_or_unset_env(name, new)
1760
 
        self.addCleanup(osutils.set_or_unset_env, name, value)
1761
 
        return value
1762
 
 
1763
1512
    def _cleanEnvironment(self):
1764
 
        for name, value in isolated_environ.iteritems():
1765
 
            self.overrideEnv(name, value)
 
1513
        new_env = {
 
1514
            'BZR_HOME': None, # Don't inherit BZR_HOME to all the tests.
 
1515
            'HOME': os.getcwd(),
 
1516
            # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
 
1517
            # tests do check our impls match APPDATA
 
1518
            'BZR_EDITOR': None, # test_msgeditor manipulates this variable
 
1519
            'VISUAL': None,
 
1520
            'EDITOR': None,
 
1521
            'BZR_EMAIL': None,
 
1522
            'BZREMAIL': None, # may still be present in the environment
 
1523
            'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
 
1524
            'BZR_PROGRESS_BAR': None,
 
1525
            'BZR_LOG': None,
 
1526
            'BZR_PLUGIN_PATH': None,
 
1527
            'BZR_DISABLE_PLUGINS': None,
 
1528
            'BZR_PLUGINS_AT': None,
 
1529
            'BZR_CONCURRENCY': None,
 
1530
            # Make sure that any text ui tests are consistent regardless of
 
1531
            # the environment the test case is run in; you may want tests that
 
1532
            # test other combinations.  'dumb' is a reasonable guess for tests
 
1533
            # going to a pipe or a StringIO.
 
1534
            'TERM': 'dumb',
 
1535
            'LINES': '25',
 
1536
            'COLUMNS': '80',
 
1537
            'BZR_COLUMNS': '80',
 
1538
            # SSH Agent
 
1539
            'SSH_AUTH_SOCK': None,
 
1540
            # Proxies
 
1541
            'http_proxy': None,
 
1542
            'HTTP_PROXY': None,
 
1543
            'https_proxy': None,
 
1544
            'HTTPS_PROXY': None,
 
1545
            'no_proxy': None,
 
1546
            'NO_PROXY': None,
 
1547
            'all_proxy': None,
 
1548
            'ALL_PROXY': None,
 
1549
            # Nobody cares about ftp_proxy, FTP_PROXY AFAIK. So far at
 
1550
            # least. If you do (care), please update this comment
 
1551
            # -- vila 20080401
 
1552
            'ftp_proxy': None,
 
1553
            'FTP_PROXY': None,
 
1554
            'BZR_REMOTE_PATH': None,
 
1555
            # Generally speaking, we don't want apport reporting on crashes in
 
1556
            # the test envirnoment unless we're specifically testing apport,
 
1557
            # so that it doesn't leak into the real system environment.  We
 
1558
            # use an env var so it propagates to subprocesses.
 
1559
            'APPORT_DISABLE': '1',
 
1560
        }
 
1561
        self._old_env = {}
 
1562
        self.addCleanup(self._restoreEnvironment)
 
1563
        for name, value in new_env.iteritems():
 
1564
            self._captureVar(name, value)
 
1565
 
 
1566
    def _captureVar(self, name, newvalue):
 
1567
        """Set an environment variable, and reset it when finished."""
 
1568
        self._old_env[name] = osutils.set_or_unset_env(name, newvalue)
 
1569
 
 
1570
    def _restoreEnvironment(self):
 
1571
        for name, value in self._old_env.iteritems():
 
1572
            osutils.set_or_unset_env(name, value)
1766
1573
 
1767
1574
    def _restoreHooks(self):
1768
1575
        for klass, (name, hooks) in self._preserved_hooks.items():
1769
1576
            setattr(klass, name, hooks)
1770
 
        self._preserved_hooks.clear()
1771
 
        bzrlib.hooks._lazy_hooks = self._preserved_lazy_hooks
1772
 
        self._preserved_lazy_hooks.clear()
1773
1577
 
1774
1578
    def knownFailure(self, reason):
1775
1579
        """This test has failed for some known reason."""
1776
1580
        raise KnownFailure(reason)
1777
1581
 
1778
 
    def _suppress_log(self):
1779
 
        """Remove the log info from details."""
1780
 
        self.discardDetail('log')
1781
 
 
1782
1582
    def _do_skip(self, result, reason):
1783
 
        self._suppress_log()
1784
1583
        addSkip = getattr(result, 'addSkip', None)
1785
1584
        if not callable(addSkip):
1786
1585
            result.addSuccess(result)
1789
1588
 
1790
1589
    @staticmethod
1791
1590
    def _do_known_failure(self, result, e):
1792
 
        self._suppress_log()
1793
1591
        err = sys.exc_info()
1794
1592
        addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1795
1593
        if addExpectedFailure is not None:
1803
1601
            reason = 'No reason given'
1804
1602
        else:
1805
1603
            reason = e.args[0]
1806
 
        self._suppress_log ()
1807
1604
        addNotApplicable = getattr(result, 'addNotApplicable', None)
1808
1605
        if addNotApplicable is not None:
1809
1606
            result.addNotApplicable(self, reason)
1811
1608
            self._do_skip(result, reason)
1812
1609
 
1813
1610
    @staticmethod
1814
 
    def _report_skip(self, result, err):
1815
 
        """Override the default _report_skip.
1816
 
 
1817
 
        We want to strip the 'log' detail. If we waint until _do_skip, it has
1818
 
        already been formatted into the 'reason' string, and we can't pull it
1819
 
        out again.
1820
 
        """
1821
 
        self._suppress_log()
1822
 
        super(TestCase, self)._report_skip(self, result, err)
1823
 
 
1824
 
    @staticmethod
1825
 
    def _report_expected_failure(self, result, err):
1826
 
        """Strip the log.
1827
 
 
1828
 
        See _report_skip for motivation.
1829
 
        """
1830
 
        self._suppress_log()
1831
 
        super(TestCase, self)._report_expected_failure(self, result, err)
1832
 
 
1833
 
    @staticmethod
1834
1611
    def _do_unsupported_or_skip(self, result, e):
1835
1612
        reason = e.args[0]
1836
 
        self._suppress_log()
1837
1613
        addNotSupported = getattr(result, 'addNotSupported', None)
1838
1614
        if addNotSupported is not None:
1839
1615
            result.addNotSupported(self, reason)
1865
1641
            self._benchtime += time.time() - start
1866
1642
 
1867
1643
    def log(self, *args):
1868
 
        trace.mutter(*args)
 
1644
        mutter(*args)
 
1645
 
 
1646
    def _get_log(self, keep_log_file=False):
 
1647
        """Internal helper to get the log from bzrlib.trace for this test.
 
1648
 
 
1649
        Please use self.getDetails, or self.get_log to access this in test case
 
1650
        code.
 
1651
 
 
1652
        :param keep_log_file: When True, if the log is still a file on disk
 
1653
            leave it as a file on disk. When False, if the log is still a file
 
1654
            on disk, the log file is deleted and the log preserved as
 
1655
            self._log_contents.
 
1656
        :return: A string containing the log.
 
1657
        """
 
1658
        if self._log_contents is not None:
 
1659
            try:
 
1660
                self._log_contents.decode('utf8')
 
1661
            except UnicodeDecodeError:
 
1662
                unicodestr = self._log_contents.decode('utf8', 'replace')
 
1663
                self._log_contents = unicodestr.encode('utf8')
 
1664
            return self._log_contents
 
1665
        import bzrlib.trace
 
1666
        if bzrlib.trace._trace_file:
 
1667
            # flush the log file, to get all content
 
1668
            bzrlib.trace._trace_file.flush()
 
1669
        if self._log_file_name is not None:
 
1670
            logfile = open(self._log_file_name)
 
1671
            try:
 
1672
                log_contents = logfile.read()
 
1673
            finally:
 
1674
                logfile.close()
 
1675
            try:
 
1676
                log_contents.decode('utf8')
 
1677
            except UnicodeDecodeError:
 
1678
                unicodestr = log_contents.decode('utf8', 'replace')
 
1679
                log_contents = unicodestr.encode('utf8')
 
1680
            if not keep_log_file:
 
1681
                close_attempts = 0
 
1682
                max_close_attempts = 100
 
1683
                first_close_error = None
 
1684
                while close_attempts < max_close_attempts:
 
1685
                    close_attempts += 1
 
1686
                    try:
 
1687
                        self._log_file.close()
 
1688
                    except IOError, ioe:
 
1689
                        if ioe.errno is None:
 
1690
                            # No errno implies 'close() called during
 
1691
                            # concurrent operation on the same file object', so
 
1692
                            # retry.  Probably a thread is trying to write to
 
1693
                            # the log file.
 
1694
                            if first_close_error is None:
 
1695
                                first_close_error = ioe
 
1696
                            continue
 
1697
                        raise
 
1698
                    else:
 
1699
                        break
 
1700
                if close_attempts > 1:
 
1701
                    sys.stderr.write(
 
1702
                        'Unable to close log file on first attempt, '
 
1703
                        'will retry: %s\n' % (first_close_error,))
 
1704
                    if close_attempts == max_close_attempts:
 
1705
                        sys.stderr.write(
 
1706
                            'Unable to close log file after %d attempts.\n'
 
1707
                            % (max_close_attempts,))
 
1708
                self._log_file = None
 
1709
                # Permit multiple calls to get_log until we clean it up in
 
1710
                # finishLogFile
 
1711
                self._log_contents = log_contents
 
1712
                try:
 
1713
                    os.remove(self._log_file_name)
 
1714
                except OSError, e:
 
1715
                    if sys.platform == 'win32' and e.errno == errno.EACCES:
 
1716
                        sys.stderr.write(('Unable to delete log file '
 
1717
                                             ' %r\n' % self._log_file_name))
 
1718
                    else:
 
1719
                        raise
 
1720
                self._log_file_name = None
 
1721
            return log_contents
 
1722
        else:
 
1723
            return "No log file content and no log file name."
1869
1724
 
1870
1725
    def get_log(self):
1871
1726
        """Get a unicode string containing the log from bzrlib.trace.
1921
1776
 
1922
1777
        try:
1923
1778
            try:
1924
 
                result = self.apply_redirected(
1925
 
                    ui.ui_factory.stdin,
 
1779
                result = self.apply_redirected(ui.ui_factory.stdin,
1926
1780
                    stdout, stderr,
1927
 
                    _mod_commands.run_bzr_catch_user_errors,
 
1781
                    bzrlib.commands.run_bzr_catch_user_errors,
1928
1782
                    args)
1929
1783
            except KeyboardInterrupt:
1930
1784
                # Reraise KeyboardInterrupt with contents of redirected stdout
2072
1926
    def start_bzr_subprocess(self, process_args, env_changes=None,
2073
1927
                             skip_if_plan_to_signal=False,
2074
1928
                             working_dir=None,
2075
 
                             allow_plugins=False, stderr=subprocess.PIPE):
 
1929
                             allow_plugins=False):
2076
1930
        """Start bzr in a subprocess for testing.
2077
1931
 
2078
1932
        This starts a new Python interpreter and runs bzr in there.
2087
1941
            variables. A value of None will unset the env variable.
2088
1942
            The values must be strings. The change will only occur in the
2089
1943
            child, so you don't need to fix the environment after running.
2090
 
        :param skip_if_plan_to_signal: raise TestSkipped when true and system
2091
 
            doesn't support signalling subprocesses.
 
1944
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
 
1945
            is not available.
2092
1946
        :param allow_plugins: If False (default) pass --no-plugins to bzr.
2093
 
        :param stderr: file to use for the subprocess's stderr.  Valid values
2094
 
            are those valid for the stderr argument of `subprocess.Popen`.
2095
 
            Default value is ``subprocess.PIPE``.
2096
1947
 
2097
1948
        :returns: Popen object for the started process.
2098
1949
        """
2099
1950
        if skip_if_plan_to_signal:
2100
 
            if os.name != "posix":
2101
 
                raise TestSkipped("Sending signals not supported")
 
1951
            if not getattr(os, 'kill', None):
 
1952
                raise TestSkipped("os.kill not available.")
2102
1953
 
2103
1954
        if env_changes is None:
2104
1955
            env_changes = {}
2124
1975
            # so we will avoid using it on all platforms, just to
2125
1976
            # make sure the code path is used, and we don't break on win32
2126
1977
            cleanup_environment()
2127
 
            # Include the subprocess's log file in the test details, in case
2128
 
            # the test fails due to an error in the subprocess.
2129
 
            self._add_subprocess_log(trace._get_bzr_log_filename())
2130
1978
            command = [sys.executable]
2131
1979
            # frozen executables don't need the path to bzr
2132
1980
            if getattr(sys, "frozen", None) is None:
2136
1984
            command.extend(process_args)
2137
1985
            process = self._popen(command, stdin=subprocess.PIPE,
2138
1986
                                  stdout=subprocess.PIPE,
2139
 
                                  stderr=stderr)
 
1987
                                  stderr=subprocess.PIPE)
2140
1988
        finally:
2141
1989
            restore_environment()
2142
1990
            if cwd is not None:
2144
1992
 
2145
1993
        return process
2146
1994
 
2147
 
    def _add_subprocess_log(self, log_file_path):
2148
 
        if len(self._log_files) == 0:
2149
 
            # Register an addCleanup func.  We do this on the first call to
2150
 
            # _add_subprocess_log rather than in TestCase.setUp so that this
2151
 
            # addCleanup is registered after any cleanups for tempdirs that
2152
 
            # subclasses might create, which will probably remove the log file
2153
 
            # we want to read.
2154
 
            self.addCleanup(self._subprocess_log_cleanup)
2155
 
        # self._log_files is a set, so if a log file is reused we won't grab it
2156
 
        # twice.
2157
 
        self._log_files.add(log_file_path)
2158
 
 
2159
 
    def _subprocess_log_cleanup(self):
2160
 
        for count, log_file_path in enumerate(self._log_files):
2161
 
            # We use buffer_now=True to avoid holding the file open beyond
2162
 
            # the life of this function, which might interfere with e.g.
2163
 
            # cleaning tempdirs on Windows.
2164
 
            # XXX: Testtools 0.9.5 doesn't have the content_from_file helper
2165
 
            #detail_content = content.content_from_file(
2166
 
            #    log_file_path, buffer_now=True)
2167
 
            with open(log_file_path, 'rb') as log_file:
2168
 
                log_file_bytes = log_file.read()
2169
 
            detail_content = content.Content(content.ContentType("text",
2170
 
                "plain", {"charset": "utf8"}), lambda: [log_file_bytes])
2171
 
            self.addDetail("start_bzr_subprocess-log-%d" % (count,),
2172
 
                detail_content)
2173
 
 
2174
1995
    def _popen(self, *args, **kwargs):
2175
1996
        """Place a call to Popen.
2176
1997
 
2185
2006
 
2186
2007
    def get_bzr_path(self):
2187
2008
        """Return the path of the 'bzr' executable for this test suite."""
2188
 
        bzr_path = os.path.join(self.get_source_path(), "bzr")
 
2009
        bzr_path = self.get_source_path()+'/bzr'
2189
2010
        if not os.path.isfile(bzr_path):
2190
2011
            # We are probably installed. Assume sys.argv is the right file
2191
2012
            bzr_path = sys.argv[0]
2213
2034
        if retcode is not None and retcode != process.returncode:
2214
2035
            if process_args is None:
2215
2036
                process_args = "(unknown args)"
2216
 
            trace.mutter('Output of bzr %s:\n%s', process_args, out)
2217
 
            trace.mutter('Error for bzr %s:\n%s', process_args, err)
 
2037
            mutter('Output of bzr %s:\n%s', process_args, out)
 
2038
            mutter('Error for bzr %s:\n%s', process_args, err)
2218
2039
            self.fail('Command bzr %s failed with retcode %s != %s'
2219
2040
                      % (process_args, retcode, process.returncode))
2220
2041
        return [out, err]
2221
2042
 
2222
 
    def check_tree_shape(self, tree, shape):
2223
 
        """Compare a tree to a list of expected names.
 
2043
    def check_inventory_shape(self, inv, shape):
 
2044
        """Compare an inventory to a list of expected names.
2224
2045
 
2225
2046
        Fail if they are not precisely equal.
2226
2047
        """
2227
2048
        extras = []
2228
2049
        shape = list(shape)             # copy
2229
 
        for path, ie in tree.iter_entries_by_dir():
 
2050
        for path, ie in inv.entries():
2230
2051
            name = path.replace('\\', '/')
2231
2052
            if ie.kind == 'directory':
2232
2053
                name = name + '/'
2233
 
            if name == "/":
2234
 
                pass # ignore root entry
2235
 
            elif name in shape:
 
2054
            if name in shape:
2236
2055
                shape.remove(name)
2237
2056
            else:
2238
2057
                extras.append(name)
2279
2098
 
2280
2099
        Tests that expect to provoke LockContention errors should call this.
2281
2100
        """
2282
 
        self.overrideAttr(lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
 
2101
        self.overrideAttr(bzrlib.lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
2283
2102
 
2284
2103
    def make_utf8_encoded_stringio(self, encoding_type=None):
2285
2104
        """Return a StringIOWrapper instance, that will encode Unicode
2328
2147
class TestCaseWithMemoryTransport(TestCase):
2329
2148
    """Common test class for tests that do not need disk resources.
2330
2149
 
2331
 
    Tests that need disk resources should derive from TestCaseInTempDir
2332
 
    orTestCaseWithTransport.
 
2150
    Tests that need disk resources should derive from TestCaseWithTransport.
2333
2151
 
2334
2152
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2335
2153
 
2336
 
    For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
 
2154
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
2337
2155
    a directory which does not exist. This serves to help ensure test isolation
2338
 
    is preserved. ``test_dir`` is set to the TEST_ROOT, as is cwd, because they
2339
 
    must exist. However, TestCaseWithMemoryTransport does not offer local file
2340
 
    defaults for the transport in tests, nor does it obey the command line
 
2156
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
 
2157
    must exist. However, TestCaseWithMemoryTransport does not offer local
 
2158
    file defaults for the transport in tests, nor does it obey the command line
2341
2159
    override, so tests that accidentally write to the common directory should
2342
2160
    be rare.
2343
2161
 
2344
 
    :cvar TEST_ROOT: Directory containing all temporary directories, plus a
2345
 
        ``.bzr`` directory that stops us ascending higher into the filesystem.
 
2162
    :cvar TEST_ROOT: Directory containing all temporary directories, plus
 
2163
    a .bzr directory that stops us ascending higher into the filesystem.
2346
2164
    """
2347
2165
 
2348
2166
    TEST_ROOT = None
2610
2428
        test_home_dir = self.test_home_dir
2611
2429
        if isinstance(test_home_dir, unicode):
2612
2430
            test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
2613
 
        self.overrideEnv('HOME', test_home_dir)
2614
 
        self.overrideEnv('BZR_HOME', test_home_dir)
 
2431
        os.environ['HOME'] = test_home_dir
 
2432
        os.environ['BZR_HOME'] = test_home_dir
2615
2433
 
2616
2434
    def setUp(self):
2617
2435
        super(TestCaseWithMemoryTransport, self).setUp()
2618
 
        # Ensure that ConnectedTransport doesn't leak sockets
2619
 
        def get_transport_with_cleanup(*args, **kwargs):
2620
 
            t = orig_get_transport(*args, **kwargs)
2621
 
            if isinstance(t, _mod_transport.ConnectedTransport):
2622
 
                self.addCleanup(t.disconnect)
2623
 
            return t
2624
 
 
2625
 
        orig_get_transport = self.overrideAttr(_mod_transport, 'get_transport',
2626
 
                                               get_transport_with_cleanup)
2627
2436
        self._make_test_root()
2628
2437
        self.addCleanup(os.chdir, os.getcwdu())
2629
2438
        self.makeAndChdirToTestDir()
2672
2481
 
2673
2482
    OVERRIDE_PYTHON = 'python'
2674
2483
 
2675
 
    def setUp(self):
2676
 
        super(TestCaseInTempDir, self).setUp()
2677
 
        # Remove the protection set in isolated_environ, we have a proper
2678
 
        # access to disk resources now.
2679
 
        self.overrideEnv('BZR_LOG', None)
2680
 
 
2681
2484
    def check_file_contents(self, filename, expect):
2682
2485
        self.log("check contents of file %s" % filename)
2683
2486
        f = file(filename)
2939
2742
    :param pattern: A regular expression string.
2940
2743
    :return: A callable that returns True if the re matches.
2941
2744
    """
2942
 
    filter_re = re.compile(pattern, 0)
 
2745
    filter_re = osutils.re_compile_checked(pattern, 0,
 
2746
        'test filter')
2943
2747
    def condition(test):
2944
2748
        test_id = test.id()
2945
2749
        return filter_re.search(test_id)
3197
3001
 
3198
3002
 
3199
3003
def fork_decorator(suite):
3200
 
    if getattr(os, "fork", None) is None:
3201
 
        raise errors.BzrCommandError("platform does not support fork,"
3202
 
            " try --parallel=subprocess instead.")
3203
3004
    concurrency = osutils.local_concurrency()
3204
3005
    if concurrency == 1:
3205
3006
        return suite
3394
3195
 
3395
3196
def partition_tests(suite, count):
3396
3197
    """Partition suite into count lists of tests."""
3397
 
    # This just assigns tests in a round-robin fashion.  On one hand this
3398
 
    # splits up blocks of related tests that might run faster if they shared
3399
 
    # resources, but on the other it avoids assigning blocks of slow tests to
3400
 
    # just one partition.  So the slowest partition shouldn't be much slower
3401
 
    # than the fastest.
3402
 
    partitions = [list() for i in range(count)]
3403
 
    tests = iter_suite_tests(suite)
3404
 
    for partition, test in itertools.izip(itertools.cycle(partitions), tests):
3405
 
        partition.append(test)
3406
 
    return partitions
 
3198
    result = []
 
3199
    tests = list(iter_suite_tests(suite))
 
3200
    tests_per_process = int(math.ceil(float(len(tests)) / count))
 
3201
    for block in range(count):
 
3202
        low_test = block * tests_per_process
 
3203
        high_test = low_test + tests_per_process
 
3204
        process_tests = tests[low_test:high_test]
 
3205
        result.append(process_tests)
 
3206
    return result
3407
3207
 
3408
3208
 
3409
3209
def workaround_zealous_crypto_random():
3529
3329
    return result
3530
3330
 
3531
3331
 
3532
 
class ProfileResult(testtools.ExtendedToOriginalDecorator):
 
3332
class ForwardingResult(unittest.TestResult):
 
3333
 
 
3334
    def __init__(self, target):
 
3335
        unittest.TestResult.__init__(self)
 
3336
        self.result = target
 
3337
 
 
3338
    def startTest(self, test):
 
3339
        self.result.startTest(test)
 
3340
 
 
3341
    def stopTest(self, test):
 
3342
        self.result.stopTest(test)
 
3343
 
 
3344
    def startTestRun(self):
 
3345
        self.result.startTestRun()
 
3346
 
 
3347
    def stopTestRun(self):
 
3348
        self.result.stopTestRun()
 
3349
 
 
3350
    def addSkip(self, test, reason):
 
3351
        self.result.addSkip(test, reason)
 
3352
 
 
3353
    def addSuccess(self, test):
 
3354
        self.result.addSuccess(test)
 
3355
 
 
3356
    def addError(self, test, err):
 
3357
        self.result.addError(test, err)
 
3358
 
 
3359
    def addFailure(self, test, err):
 
3360
        self.result.addFailure(test, err)
 
3361
ForwardingResult = testtools.ExtendedToOriginalDecorator
 
3362
 
 
3363
 
 
3364
class ProfileResult(ForwardingResult):
3533
3365
    """Generate profiling data for all activity between start and success.
3534
3366
    
3535
3367
    The profile data is appended to the test's _benchcalls attribute and can
3543
3375
 
3544
3376
    def startTest(self, test):
3545
3377
        self.profiler = bzrlib.lsprof.BzrProfiler()
3546
 
        # Prevent deadlocks in tests that use lsprof: those tests will
3547
 
        # unavoidably fail.
3548
 
        bzrlib.lsprof.BzrProfiler.profiler_block = 0
3549
3378
        self.profiler.start()
3550
 
        testtools.ExtendedToOriginalDecorator.startTest(self, test)
 
3379
        ForwardingResult.startTest(self, test)
3551
3380
 
3552
3381
    def addSuccess(self, test):
3553
3382
        stats = self.profiler.stop()
3557
3386
            test._benchcalls = []
3558
3387
            calls = test._benchcalls
3559
3388
        calls.append(((test.id(), "", ""), stats))
3560
 
        testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
 
3389
        ForwardingResult.addSuccess(self, test)
3561
3390
 
3562
3391
    def stopTest(self, test):
3563
 
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
 
3392
        ForwardingResult.stopTest(self, test)
3564
3393
        self.profiler = None
3565
3394
 
3566
3395
 
3574
3403
#                           with proper exclusion rules.
3575
3404
#   -Ethreads               Will display thread ident at creation/join time to
3576
3405
#                           help track thread leaks
3577
 
 
3578
 
#   -Econfig_stats          Will collect statistics using addDetail
3579
3406
selftest_debug_flags = set()
3580
3407
 
3581
3408
 
3775
3602
                key, obj, help=help, info=info, override_existing=False)
3776
3603
        except KeyError:
3777
3604
            actual = self.get(key)
3778
 
            trace.note(
3779
 
                'Test prefix alias %s is already used for %s, ignoring %s'
3780
 
                % (key, actual, obj))
 
3605
            note('Test prefix alias %s is already used for %s, ignoring %s'
 
3606
                 % (key, actual, obj))
3781
3607
 
3782
3608
    def resolve_alias(self, id_start):
3783
3609
        """Replace the alias by the prefix in the given string.
3815
3641
        'bzrlib.doc',
3816
3642
        'bzrlib.tests.blackbox',
3817
3643
        'bzrlib.tests.commands',
3818
 
        'bzrlib.tests.doc_generate',
3819
3644
        'bzrlib.tests.per_branch',
3820
3645
        'bzrlib.tests.per_bzrdir',
3821
 
        'bzrlib.tests.per_controldir',
3822
 
        'bzrlib.tests.per_controldir_colo',
 
3646
        'bzrlib.tests.per_bzrdir_colo',
3823
3647
        'bzrlib.tests.per_foreign_vcs',
3824
3648
        'bzrlib.tests.per_interrepository',
3825
3649
        'bzrlib.tests.per_intertree',
3833
3657
        'bzrlib.tests.per_repository',
3834
3658
        'bzrlib.tests.per_repository_chk',
3835
3659
        'bzrlib.tests.per_repository_reference',
3836
 
        'bzrlib.tests.per_repository_vf',
3837
3660
        'bzrlib.tests.per_uifactory',
3838
3661
        'bzrlib.tests.per_versionedfile',
3839
3662
        'bzrlib.tests.per_workingtree',
3840
3663
        'bzrlib.tests.test__annotator',
3841
3664
        'bzrlib.tests.test__bencode',
3842
 
        'bzrlib.tests.test__btree_serializer',
3843
3665
        'bzrlib.tests.test__chk_map',
3844
3666
        'bzrlib.tests.test__dirstate_helpers',
3845
3667
        'bzrlib.tests.test__groupcompress',
3873
3695
        'bzrlib.tests.test_commit_merge',
3874
3696
        'bzrlib.tests.test_config',
3875
3697
        'bzrlib.tests.test_conflicts',
3876
 
        'bzrlib.tests.test_controldir',
3877
3698
        'bzrlib.tests.test_counted_lock',
3878
3699
        'bzrlib.tests.test_crash',
3879
3700
        'bzrlib.tests.test_decorators',
3880
3701
        'bzrlib.tests.test_delta',
3881
3702
        'bzrlib.tests.test_debug',
 
3703
        'bzrlib.tests.test_deprecated_graph',
3882
3704
        'bzrlib.tests.test_diff',
3883
3705
        'bzrlib.tests.test_directory_service',
3884
3706
        'bzrlib.tests.test_dirstate',
3886
3708
        'bzrlib.tests.test_eol_filters',
3887
3709
        'bzrlib.tests.test_errors',
3888
3710
        'bzrlib.tests.test_export',
3889
 
        'bzrlib.tests.test_export_pot',
3890
3711
        'bzrlib.tests.test_extract',
3891
3712
        'bzrlib.tests.test_fetch',
3892
3713
        'bzrlib.tests.test_fixtures',
3906
3727
        'bzrlib.tests.test_http',
3907
3728
        'bzrlib.tests.test_http_response',
3908
3729
        'bzrlib.tests.test_https_ca_bundle',
3909
 
        'bzrlib.tests.test_i18n',
3910
3730
        'bzrlib.tests.test_identitymap',
3911
3731
        'bzrlib.tests.test_ignores',
3912
3732
        'bzrlib.tests.test_index',
3931
3751
        'bzrlib.tests.test_merge3',
3932
3752
        'bzrlib.tests.test_merge_core',
3933
3753
        'bzrlib.tests.test_merge_directive',
3934
 
        'bzrlib.tests.test_mergetools',
3935
3754
        'bzrlib.tests.test_missing',
3936
3755
        'bzrlib.tests.test_msgeditor',
3937
3756
        'bzrlib.tests.test_multiparent',
3946
3765
        'bzrlib.tests.test_permissions',
3947
3766
        'bzrlib.tests.test_plugins',
3948
3767
        'bzrlib.tests.test_progress',
3949
 
        'bzrlib.tests.test_pyutils',
3950
3768
        'bzrlib.tests.test_read_bundle',
3951
3769
        'bzrlib.tests.test_reconcile',
3952
3770
        'bzrlib.tests.test_reconfigure',
3961
3779
        'bzrlib.tests.test_rio',
3962
3780
        'bzrlib.tests.test_rules',
3963
3781
        'bzrlib.tests.test_sampler',
3964
 
        'bzrlib.tests.test_scenarios',
3965
3782
        'bzrlib.tests.test_script',
3966
3783
        'bzrlib.tests.test_selftest',
3967
3784
        'bzrlib.tests.test_serializer',
3987
3804
        'bzrlib.tests.test_testament',
3988
3805
        'bzrlib.tests.test_textfile',
3989
3806
        'bzrlib.tests.test_textmerge',
3990
 
        'bzrlib.tests.test_cethread',
3991
3807
        'bzrlib.tests.test_timestamp',
3992
3808
        'bzrlib.tests.test_trace',
3993
3809
        'bzrlib.tests.test_transactions',
3996
3812
        'bzrlib.tests.test_transport_log',
3997
3813
        'bzrlib.tests.test_tree',
3998
3814
        'bzrlib.tests.test_treebuilder',
3999
 
        'bzrlib.tests.test_treeshape',
4000
3815
        'bzrlib.tests.test_tsort',
4001
3816
        'bzrlib.tests.test_tuned_gzip',
4002
3817
        'bzrlib.tests.test_ui',
4004
3819
        'bzrlib.tests.test_upgrade',
4005
3820
        'bzrlib.tests.test_upgrade_stacked',
4006
3821
        'bzrlib.tests.test_urlutils',
4007
 
        'bzrlib.tests.test_utextwrap',
4008
3822
        'bzrlib.tests.test_version',
4009
3823
        'bzrlib.tests.test_version_info',
4010
 
        'bzrlib.tests.test_versionedfile',
4011
3824
        'bzrlib.tests.test_weave',
4012
3825
        'bzrlib.tests.test_whitebox',
4013
3826
        'bzrlib.tests.test_win32utils',
4027
3840
        'bzrlib',
4028
3841
        'bzrlib.branchbuilder',
4029
3842
        'bzrlib.decorators',
 
3843
        'bzrlib.export',
4030
3844
        'bzrlib.inventory',
4031
3845
        'bzrlib.iterablefile',
4032
3846
        'bzrlib.lockdir',
4033
3847
        'bzrlib.merge3',
4034
3848
        'bzrlib.option',
4035
 
        'bzrlib.pyutils',
4036
3849
        'bzrlib.symbol_versioning',
4037
3850
        'bzrlib.tests',
4038
3851
        'bzrlib.tests.fixtures',
4039
3852
        'bzrlib.timestamp',
4040
 
        'bzrlib.transport.http',
4041
3853
        'bzrlib.version_info_formats.format_custom',
4042
3854
        ]
4043
3855
 
4096
3908
        try:
4097
3909
            # note that this really does mean "report only" -- doctest
4098
3910
            # still runs the rest of the examples
4099
 
            doc_suite = IsolatedDocTestSuite(
4100
 
                mod, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
 
3911
            doc_suite = doctest.DocTestSuite(mod,
 
3912
                optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
4101
3913
        except ValueError, e:
4102
3914
            print '**failed to get doctest for: %s\n%s' % (mod, e)
4103
3915
            raise
4106
3918
        suite.addTest(doc_suite)
4107
3919
 
4108
3920
    default_encoding = sys.getdefaultencoding()
4109
 
    for name, plugin in _mod_plugin.plugins().items():
 
3921
    for name, plugin in bzrlib.plugin.plugins().items():
4110
3922
        if not interesting_module(plugin.module.__name__):
4111
3923
            continue
4112
3924
        plugin_suite = plugin.test_suite()
4118
3930
        if plugin_suite is not None:
4119
3931
            suite.addTest(plugin_suite)
4120
3932
        if default_encoding != sys.getdefaultencoding():
4121
 
            trace.warning(
 
3933
            bzrlib.trace.warning(
4122
3934
                'Plugin "%s" tried to reset default encoding to: %s', name,
4123
3935
                sys.getdefaultencoding())
4124
3936
            reload(sys)
4139
3951
            # Some tests mentioned in the list are not in the test suite. The
4140
3952
            # list may be out of date, report to the tester.
4141
3953
            for id in not_found:
4142
 
                trace.warning('"%s" not found in the test suite', id)
 
3954
                bzrlib.trace.warning('"%s" not found in the test suite', id)
4143
3955
        for id in duplicates:
4144
 
            trace.warning('"%s" is used as an id by several tests', id)
 
3956
            bzrlib.trace.warning('"%s" is used as an id by several tests', id)
4145
3957
 
4146
3958
    return suite
4147
3959
 
4148
3960
 
4149
 
def multiply_scenarios(*scenarios):
4150
 
    """Multiply two or more iterables of scenarios.
4151
 
 
4152
 
    It is safe to pass scenario generators or iterators.
4153
 
 
4154
 
    :returns: A list of compound scenarios: the cross-product of all 
4155
 
        scenarios, with the names concatenated and the parameters
4156
 
        merged together.
4157
 
    """
4158
 
    return reduce(_multiply_two_scenarios, map(list, scenarios))
4159
 
 
4160
 
 
4161
 
def _multiply_two_scenarios(scenarios_left, scenarios_right):
 
3961
def multiply_scenarios(scenarios_left, scenarios_right):
4162
3962
    """Multiply two sets of scenarios.
4163
3963
 
4164
3964
    :returns: the cartesian product of the two sets of scenarios, that is
4250
4050
    """
4251
4051
    new_test = copy.copy(test)
4252
4052
    new_test.id = lambda: new_id
4253
 
    # XXX: Workaround <https://bugs.launchpad.net/testtools/+bug/637725>, which
4254
 
    # causes cloned tests to share the 'details' dict.  This makes it hard to
4255
 
    # read the test output for parameterized tests, because tracebacks will be
4256
 
    # associated with irrelevant tests.
4257
 
    try:
4258
 
        details = new_test._TestCase__details
4259
 
    except AttributeError:
4260
 
        # must be a different version of testtools than expected.  Do nothing.
4261
 
        pass
4262
 
    else:
4263
 
        # Reset the '__details' dict.
4264
 
        new_test._TestCase__details = {}
4265
4053
    return new_test
4266
4054
 
4267
4055
 
4288
4076
        the module is available.
4289
4077
    """
4290
4078
 
4291
 
    py_module = pyutils.get_named_object(py_module_name)
 
4079
    py_module = __import__(py_module_name, {}, {}, ['NO_SUCH_ATTRIB'])
4292
4080
    scenarios = [
4293
4081
        ('python', {'module': py_module}),
4294
4082
    ]
4447
4235
            symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4448
4236
            # Import the new feature and use it as a replacement for the
4449
4237
            # deprecated one.
4450
 
            self._feature = pyutils.get_named_object(
4451
 
                self._replacement_module, self._replacement_name)
 
4238
            mod = __import__(self._replacement_module, {}, {},
 
4239
                             [self._replacement_name])
 
4240
            self._feature = getattr(mod, self._replacement_name)
4452
4241
 
4453
4242
    def _probe(self):
4454
4243
        self._ensure()
4485
4274
        return self.module_name
4486
4275
 
4487
4276
 
 
4277
# This is kept here for compatibility, it is recommended to use
 
4278
# 'bzrlib.tests.feature.paramiko' instead
 
4279
ParamikoFeature = _CompatabilityThunkFeature(
 
4280
    deprecated_in((2,1,0)),
 
4281
    'bzrlib.tests.features', 'ParamikoFeature', 'paramiko')
 
4282
 
 
4283
 
4488
4284
def probe_unicode_in_user_encoding():
4489
4285
    """Try to encode several unicode strings to use in unicode-aware tests.
4490
4286
    Return first successfull match.
4677
4473
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
4678
4474
 
4679
4475
 
 
4476
# Kept for compatibility, use bzrlib.tests.features.subunit instead
 
4477
SubUnitFeature = _CompatabilityThunkFeature(
 
4478
    deprecated_in((2,1,0)),
 
4479
    'bzrlib.tests.features', 'SubUnitFeature', 'subunit')
4680
4480
# Only define SubUnitBzrRunner if subunit is available.
4681
4481
try:
4682
4482
    from subunit import TestProtocolClient
4683
4483
    from subunit.test_results import AutoTimingTestResultDecorator
4684
 
    class SubUnitBzrProtocolClient(TestProtocolClient):
4685
 
 
4686
 
        def addSuccess(self, test, details=None):
4687
 
            # The subunit client always includes the details in the subunit
4688
 
            # stream, but we don't want to include it in ours.
4689
 
            if details is not None and 'log' in details:
4690
 
                del details['log']
4691
 
            return super(SubUnitBzrProtocolClient, self).addSuccess(
4692
 
                test, details)
4693
 
 
4694
4484
    class SubUnitBzrRunner(TextTestRunner):
4695
4485
        def run(self, test):
4696
4486
            result = AutoTimingTestResultDecorator(
4697
 
                SubUnitBzrProtocolClient(self.stream))
 
4487
                TestProtocolClient(self.stream))
4698
4488
            test.run(result)
4699
4489
            return result
4700
4490
except ImportError: