~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Parth Malwankar
  • Date: 2010-05-03 08:33:32 UTC
  • mto: This revision was merged to the branch mainline in revision 5210.
  • Revision ID: parth.malwankar@gmail.com-20100503083332-233xyz4wwef6x3ey
removedĀ unusedĀ import.

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
29
29
 
30
30
import atexit
31
31
import codecs
32
 
import copy
 
32
from copy import copy
33
33
from cStringIO import StringIO
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
 
import pprint
 
40
from pprint import pformat
42
41
import random
43
42
import re
44
43
import shlex
45
44
import stat
46
 
import subprocess
 
45
from subprocess import Popen, PIPE, STDOUT
47
46
import sys
48
47
import tempfile
49
48
import threading
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
 
    transport as _mod_transport,
85
77
    workingtree,
86
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
87
86
try:
88
87
    import bzrlib.lsprof
89
88
except ImportError:
90
89
    # lsprof not available
91
90
    pass
92
 
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
93
105
from bzrlib.transport import (
 
106
    get_transport,
94
107
    memory,
95
108
    pathfilter,
96
109
    )
 
110
import bzrlib.transport
 
111
from bzrlib.trace import mutter, note
97
112
from bzrlib.tests import (
98
113
    test_server,
99
114
    TestUtil,
100
 
    treeshape,
101
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
102
122
from bzrlib.ui import NullProgressView
103
123
from bzrlib.ui.text import TextUIFactory
 
124
import bzrlib.version_info_formats.format_custom
 
125
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
104
126
 
105
127
# Mark this python module as being part of the implementation
106
128
# of unittest: this gives us better tracebacks where the last
118
140
SUBUNIT_SEEK_SET = 0
119
141
SUBUNIT_SEEK_CUR = 1
120
142
 
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):
 
143
 
 
144
class ExtendedTestResult(unittest._TextTestResult):
217
145
    """Accepts, reports and accumulates the results of running tests.
218
146
 
219
147
    Compared to the unittest version this class adds support for
240
168
        :param bench_history: Optionally, a writable file object to accumulate
241
169
            benchmark results.
242
170
        """
243
 
        testtools.TextTestResult.__init__(self, stream)
 
171
        unittest._TextTestResult.__init__(self, stream, descriptions, verbosity)
244
172
        if bench_history is not None:
245
173
            from bzrlib.version import _get_bzr_source_tree
246
174
            src_tree = _get_bzr_source_tree()
267
195
        self.count = 0
268
196
        self._overall_start_time = time.time()
269
197
        self._strict = strict
270
 
        self._first_thread_leaker_id = None
271
 
        self._tests_leaking_threads_count = 0
272
 
        self._traceback_from_test = None
273
198
 
274
199
    def stopTestRun(self):
275
200
        run = self.testsRun
276
201
        actionTaken = "Ran"
277
202
        stopTime = time.time()
278
203
        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,
 
204
        self.printErrors()
 
205
        self.stream.writeln(self.separator2)
 
206
        self.stream.writeln("%s %d test%s in %.3fs" % (actionTaken,
285
207
                            run, run != 1 and "s" or "", timeTaken))
 
208
        self.stream.writeln()
286
209
        if not self.wasSuccessful():
287
210
            self.stream.write("FAILED (")
288
211
            failed, errored = map(len, (self.failures, self.errors))
295
218
                if failed or errored: self.stream.write(", ")
296
219
                self.stream.write("known_failure_count=%d" %
297
220
                    self.known_failure_count)
298
 
            self.stream.write(")\n")
 
221
            self.stream.writeln(")")
299
222
        else:
300
223
            if self.known_failure_count:
301
 
                self.stream.write("OK (known_failures=%d)\n" %
 
224
                self.stream.writeln("OK (known_failures=%d)" %
302
225
                    self.known_failure_count)
303
226
            else:
304
 
                self.stream.write("OK\n")
 
227
                self.stream.writeln("OK")
305
228
        if self.skip_count > 0:
306
229
            skipped = self.skip_count
307
 
            self.stream.write('%d test%s skipped\n' %
 
230
            self.stream.writeln('%d test%s skipped' %
308
231
                                (skipped, skipped != 1 and "s" or ""))
309
232
        if self.unsupported:
310
233
            for feature, count in sorted(self.unsupported.items()):
311
 
                self.stream.write("Missing feature '%s' skipped %d tests.\n" %
 
234
                self.stream.writeln("Missing feature '%s' skipped %d tests." %
312
235
                    (feature, count))
313
236
        if self._strict:
314
237
            ok = self.wasStrictlySuccessful()
315
238
        else:
316
239
            ok = self.wasSuccessful()
317
 
        if self._first_thread_leaker_id:
 
240
        if TestCase._first_thread_leaker_id:
318
241
            self.stream.write(
319
242
                '%s is leaking threads among %d leaking tests.\n' % (
320
 
                self._first_thread_leaker_id,
321
 
                self._tests_leaking_threads_count))
 
243
                TestCase._first_thread_leaker_id,
 
244
                TestCase._leaking_threads_tests))
322
245
            # We don't report the main thread as an active one.
323
246
            self.stream.write(
324
247
                '%d non-main threads were left active in the end.\n'
325
 
                % (len(self._active_threads) - 1))
 
248
                % (TestCase._active_threads - 1))
326
249
 
327
250
    def getDescription(self, test):
328
251
        return test.id()
335
258
 
336
259
    def _elapsedTestTimeString(self):
337
260
        """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))
 
261
        return self._formatTime(time.time() - self._start_time)
340
262
 
341
263
    def _testTimeString(self, testCase):
342
264
        benchmark_time = self._extractBenchmarkTime(testCase)
353
275
 
354
276
    def _shortened_test_description(self, test):
355
277
        what = test.id()
356
 
        what = re.sub(r'^bzrlib\.tests\.', '', what)
 
278
        what = re.sub(r'^bzrlib\.(tests|benchmarks)\.', '', what)
357
279
        return what
358
280
 
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
281
    def startTest(self, test):
368
 
        super(ExtendedTestResult, self).startTest(test)
 
282
        unittest.TestResult.startTest(self, test)
369
283
        if self.count == 0:
370
284
            self.startTests()
371
 
        self.count += 1
372
285
        self.report_test_start(test)
373
286
        test.number = self.count
374
287
        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
288
 
394
289
    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
 
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')
413
307
 
414
308
    def _recordTestStartTime(self):
415
309
        """Record that a test has started."""
416
 
        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()
417
318
 
418
319
    def addError(self, test, err):
419
320
        """Tell result that test finished with an error.
421
322
        Called from the TestCase run() method when the test
422
323
        fails with an unexpected error.
423
324
        """
424
 
        self._post_mortem(self._traceback_from_test)
425
 
        super(ExtendedTestResult, self).addError(test, err)
 
325
        self._post_mortem()
 
326
        unittest.TestResult.addError(self, test, err)
426
327
        self.error_count += 1
427
328
        self.report_error(test, err)
428
329
        if self.stop_early:
429
330
            self.stop()
 
331
        self._cleanupLogFile(test)
430
332
 
431
333
    def addFailure(self, test, err):
432
334
        """Tell result that test failed.
434
336
        Called from the TestCase run() method when the test
435
337
        fails because e.g. an assert() method failed.
436
338
        """
437
 
        self._post_mortem(self._traceback_from_test)
438
 
        super(ExtendedTestResult, self).addFailure(test, err)
 
339
        self._post_mortem()
 
340
        unittest.TestResult.addFailure(self, test, err)
439
341
        self.failure_count += 1
440
342
        self.report_failure(test, err)
441
343
        if self.stop_early:
442
344
            self.stop()
 
345
        self._cleanupLogFile(test)
443
346
 
444
347
    def addSuccess(self, test, details=None):
445
348
        """Tell result that test completed successfully.
453
356
                    self._formatTime(benchmark_time),
454
357
                    test.id()))
455
358
        self.report_success(test)
456
 
        super(ExtendedTestResult, self).addSuccess(test)
 
359
        self._cleanupLogFile(test)
 
360
        unittest.TestResult.addSuccess(self, test)
457
361
        test._log_contents = ''
458
362
 
459
363
    def addExpectedFailure(self, test, err):
460
364
        self.known_failure_count += 1
461
365
        self.report_known_failure(test, err)
462
366
 
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
367
    def addNotSupported(self, test, feature):
477
368
        """The test will not be run because of a missing feature.
478
369
        """
495
386
        self.not_applicable_count += 1
496
387
        self.report_not_applicable(test, reason)
497
388
 
498
 
    def _post_mortem(self, tb=None):
 
389
    def _post_mortem(self):
499
390
        """Start a PDB post mortem session."""
500
391
        if os.environ.get('BZR_TEST_PDB', None):
501
 
            import pdb
502
 
            pdb.post_mortem(tb)
 
392
            import pdb;pdb.post_mortem()
503
393
 
504
394
    def progress(self, offset, whence):
505
395
        """The test is adjusting the count of tests to run."""
510
400
        else:
511
401
            raise errors.BzrError("Unknown whence %r" % whence)
512
402
 
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)))
 
403
    def report_cleaning_up(self):
 
404
        pass
544
405
 
545
406
    def startTestRun(self):
546
407
        self.startTime = time.time()
583
444
        self.pb.finished()
584
445
        super(TextTestResult, self).stopTestRun()
585
446
 
586
 
    def report_tests_starting(self):
587
 
        super(TextTestResult, self).report_tests_starting()
 
447
    def startTestRun(self):
 
448
        super(TextTestResult, self).startTestRun()
588
449
        self.pb.update('[test 0/%d] Starting' % (self.num_tests))
589
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
 
590
456
    def _progress_prefix_text(self):
591
457
        # the longer this text, the less space we have to show the test
592
458
        # name...
614
480
        return a
615
481
 
616
482
    def report_test_start(self, test):
 
483
        self.count += 1
617
484
        self.pb.update(
618
485
                self._progress_prefix_text()
619
486
                + ' '
637
504
    def report_known_failure(self, test, err):
638
505
        pass
639
506
 
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
507
    def report_skip(self, test, reason):
648
508
        pass
649
509
 
653
513
    def report_unsupported(self, test, feature):
654
514
        """test cannot be run because feature is missing."""
655
515
 
 
516
    def report_cleaning_up(self):
 
517
        self.pb.update('Cleaning up')
 
518
 
656
519
 
657
520
class VerboseTestResult(ExtendedTestResult):
658
521
    """Produce long output, with one line per test run plus times"""
665
528
            result = a_string
666
529
        return result.ljust(final_width)
667
530
 
668
 
    def report_tests_starting(self):
 
531
    def startTestRun(self):
 
532
        super(VerboseTestResult, self).startTestRun()
669
533
        self.stream.write('running %d tests...\n' % self.num_tests)
670
 
        super(VerboseTestResult, self).report_tests_starting()
671
534
 
672
535
    def report_test_start(self, test):
 
536
        self.count += 1
673
537
        name = self._shortened_test_description(test)
674
538
        width = osutils.terminal_width()
675
539
        if width is not None:
687
551
        return '%s%s' % (indent, err[1])
688
552
 
689
553
    def report_error(self, test, err):
690
 
        self.stream.write('ERROR %s\n%s\n'
 
554
        self.stream.writeln('ERROR %s\n%s'
691
555
                % (self._testTimeString(test),
692
556
                   self._error_summary(err)))
693
557
 
694
558
    def report_failure(self, test, err):
695
 
        self.stream.write(' FAIL %s\n%s\n'
 
559
        self.stream.writeln(' FAIL %s\n%s'
696
560
                % (self._testTimeString(test),
697
561
                   self._error_summary(err)))
698
562
 
699
563
    def report_known_failure(self, test, err):
700
 
        self.stream.write('XFAIL %s\n%s\n'
 
564
        self.stream.writeln('XFAIL %s\n%s'
701
565
                % (self._testTimeString(test),
702
566
                   self._error_summary(err)))
703
567
 
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
568
    def report_success(self, test):
711
 
        self.stream.write('   OK %s\n' % self._testTimeString(test))
 
569
        self.stream.writeln('   OK %s' % self._testTimeString(test))
712
570
        for bench_called, stats in getattr(test, '_benchcalls', []):
713
 
            self.stream.write('LSProf output for %s(%s, %s)\n' % bench_called)
 
571
            self.stream.writeln('LSProf output for %s(%s, %s)' % bench_called)
714
572
            stats.pprint(file=self.stream)
715
573
        # flush the stream so that we get smooth output. This verbose mode is
716
574
        # used to show the output in PQM.
717
575
        self.stream.flush()
718
576
 
719
577
    def report_skip(self, test, reason):
720
 
        self.stream.write(' SKIP %s\n%s\n'
 
578
        self.stream.writeln(' SKIP %s\n%s'
721
579
                % (self._testTimeString(test), reason))
722
580
 
723
581
    def report_not_applicable(self, test, reason):
724
 
        self.stream.write('  N/A %s\n    %s\n'
 
582
        self.stream.writeln('  N/A %s\n    %s'
725
583
                % (self._testTimeString(test), reason))
726
584
 
727
585
    def report_unsupported(self, test, feature):
728
586
        """test cannot be run because feature is missing."""
729
 
        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."
730
588
                %(self._testTimeString(test), feature))
731
589
 
732
590
 
759
617
            encode = codec[0]
760
618
        else:
761
619
            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")
 
620
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
766
621
        stream.encoding = new_encoding
767
 
        self.stream = stream
 
622
        self.stream = unittest._WritelnDecorator(stream)
768
623
        self.descriptions = descriptions
769
624
        self.verbosity = verbosity
770
625
        self._bench_history = bench_history
894
749
    # XXX: Should probably unify more with CannedInputUIFactory or a
895
750
    # particular configuration of TextUIFactory, or otherwise have a clearer
896
751
    # idea of how they're supposed to be different.
897
 
    # See https://bugs.launchpad.net/bzr/+bug/408213
 
752
    # See https://bugs.edge.launchpad.net/bzr/+bug/408213
898
753
 
899
754
    def __init__(self, stdout=None, stderr=None, stdin=None):
900
755
        if stdin is not None:
918
773
        return NullProgressView()
919
774
 
920
775
 
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
776
class TestCase(testtools.TestCase):
941
777
    """Base class for bzr unit tests.
942
778
 
953
789
    routine, and to build and check bzr trees.
954
790
 
955
791
    In addition to the usual method of overriding tearDown(), this class also
956
 
    allows subclasses to register cleanup functions via addCleanup, which are
 
792
    allows subclasses to register functions into the _cleanups list, which is
957
793
    run in order as the object is torn down.  It's less likely this will be
958
794
    accidentally overlooked.
959
795
    """
960
796
 
961
 
    _log_file = None
 
797
    _active_threads = None
 
798
    _leaking_threads_tests = 0
 
799
    _first_thread_leaker_id = None
 
800
    _log_file_name = None
962
801
    # record lsprof data when performing benchmark calls.
963
802
    _gather_lsprof_in_benchmarks = False
964
803
 
965
804
    def __init__(self, methodName='testMethod'):
966
805
        super(TestCase, self).__init__(methodName)
 
806
        self._cleanups = []
967
807
        self._directory_isolation = True
968
808
        self.exception_handlers.insert(0,
969
809
            (UnavailableFeature, self._do_unsupported_or_skip))
974
814
        super(TestCase, self).setUp()
975
815
        for feature in getattr(self, '_test_needs_features', []):
976
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)]))
977
821
        self._cleanEnvironment()
978
822
        self._silenceUI()
979
823
        self._startLogFile()
983
827
        self._track_transports()
984
828
        self._track_locks()
985
829
        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()
 
830
        TestCase._active_threads = threading.activeCount()
 
831
        self.addCleanup(self._check_leaked_threads)
1001
832
 
1002
833
    def debug(self):
1003
834
        # debug a frame up.
1004
835
        import pdb
1005
836
        pdb.Pdb().set_trace(sys._getframe().f_back)
1006
837
 
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,))
 
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()
1066
852
 
1067
853
    def _clear_debug_flags(self):
1068
854
        """Prevent externally set debug flags affecting tests.
1079
865
 
1080
866
    def _clear_hooks(self):
1081
867
        # prevent hooks affecting tests
1082
 
        known_hooks = hooks.known_hooks
1083
868
        self._preserved_hooks = {}
1084
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1085
 
            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)
1086
872
            self._preserved_hooks[parent] = (name, current_hooks)
1087
 
        self._preserved_lazy_hooks = hooks._lazy_hooks
1088
 
        hooks._lazy_hooks = {}
1089
873
        self.addCleanup(self._restoreHooks)
1090
 
        for key, (parent, name) in known_hooks.iter_parent_objects():
1091
 
            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)
1092
876
            setattr(parent, name, factory())
1093
877
        # this hook should always be installed
1094
878
        request._install_hook()
1123
907
        # break some locks on purpose and should be taken into account by
1124
908
        # considering that breaking a lock is just a dirty way of releasing it.
1125
909
        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))
 
910
            message = ('Different number of acquired and '
 
911
                       'released or broken locks. (%s, %s + %s)' %
 
912
                       (acquired_locks, released_locks, broken_locks))
1133
913
            if not self._lock_check_thorough:
1134
914
                # Rather than fail, just warn
1135
915
                print "Broken test %s: %s" % (self, message)
1163
943
 
1164
944
    def permit_dir(self, name):
1165
945
        """Permit a directory to be used by this test. See permit_url."""
1166
 
        name_transport = _mod_transport.get_transport(name)
 
946
        name_transport = get_transport(name)
1167
947
        self.permit_url(name)
1168
948
        self.permit_url(name_transport.base)
1169
949
 
1192
972
            try:
1193
973
                workingtree.WorkingTree.open(path)
1194
974
            except (errors.NotBranchError, errors.NoWorkingTree):
1195
 
                raise TestSkipped('Needs a working tree of bzr sources')
 
975
                return
1196
976
        finally:
1197
977
            self.enable_directory_isolation()
1198
978
 
1248
1028
        self.addCleanup(transport_server.stop_server)
1249
1029
        # Obtain a real transport because if the server supplies a password, it
1250
1030
        # will be hidden from the base on the client side.
1251
 
        t = _mod_transport.get_transport(transport_server.get_url())
 
1031
        t = get_transport(transport_server.get_url())
1252
1032
        # Some transport servers effectively chroot the backing transport;
1253
1033
        # others like SFTPServer don't - users of the transport can walk up the
1254
1034
        # transport to read the entire backing transport. This wouldn't matter
1310
1090
        except UnicodeError, e:
1311
1091
            # If we can't compare without getting a UnicodeError, then
1312
1092
            # obviously they are different
1313
 
            trace.mutter('UnicodeError: %s', e)
 
1093
            mutter('UnicodeError: %s', e)
1314
1094
        if message:
1315
1095
            message += '\n'
1316
1096
        raise AssertionError("%snot equal:\na = %s\nb = %s\n"
1317
1097
            % (message,
1318
 
               pprint.pformat(a), pprint.pformat(b)))
 
1098
               pformat(a), pformat(b)))
1319
1099
 
1320
1100
    assertEquals = assertEqual
1321
1101
 
1355
1135
                         'st_mtime did not match')
1356
1136
        self.assertEqual(expected.st_ctime, actual.st_ctime,
1357
1137
                         'st_ctime did not match')
1358
 
        if sys.platform == 'win32':
 
1138
        if sys.platform != 'win32':
1359
1139
            # On Win32 both 'dev' and 'ino' cannot be trusted. In python2.4 it
1360
1140
            # 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:
 
1141
            # odd. Regardless we shouldn't actually try to assert anything
 
1142
            # about their values
1367
1143
            self.assertEqual(expected.st_dev, actual.st_dev,
1368
1144
                             'st_dev did not match')
1369
1145
            self.assertEqual(expected.st_ino, actual.st_ino,
1378
1154
                length, len(obj_with_len), obj_with_len))
1379
1155
 
1380
1156
    def assertLogsError(self, exception_class, func, *args, **kwargs):
1381
 
        """Assert that `func(*args, **kwargs)` quietly logs a specific error.
 
1157
        """Assert that func(*args, **kwargs) quietly logs a specific exception.
1382
1158
        """
 
1159
        from bzrlib import trace
1383
1160
        captured = []
1384
1161
        orig_log_exception_quietly = trace.log_exception_quietly
1385
1162
        try:
1386
1163
            def capture():
1387
1164
                orig_log_exception_quietly()
1388
 
                captured.append(sys.exc_info()[1])
 
1165
                captured.append(sys.exc_info())
1389
1166
            trace.log_exception_quietly = capture
1390
1167
            func(*args, **kwargs)
1391
1168
        finally:
1392
1169
            trace.log_exception_quietly = orig_log_exception_quietly
1393
1170
        self.assertLength(1, captured)
1394
 
        err = captured[0]
 
1171
        err = captured[0][1]
1395
1172
        self.assertIsInstance(err, exception_class)
1396
1173
        return err
1397
1174
 
1434
1211
        if haystack.find(needle) == -1:
1435
1212
            self.fail("string %r not found in '''%s'''" % (needle, haystack))
1436
1213
 
1437
 
    def assertNotContainsString(self, haystack, needle):
1438
 
        if haystack.find(needle) != -1:
1439
 
            self.fail("string %r found in '''%s'''" % (needle, haystack))
1440
 
 
1441
1214
    def assertSubset(self, sublist, superlist):
1442
1215
        """Assert that every entry in sublist is present in superlist."""
1443
1216
        missing = set(sublist) - set(superlist)
1532
1305
 
1533
1306
    def assertFileEqual(self, content, path):
1534
1307
        """Fail if path does not contain 'content'."""
1535
 
        self.assertPathExists(path)
 
1308
        self.failUnlessExists(path)
1536
1309
        f = file(path, 'rb')
1537
1310
        try:
1538
1311
            s = f.read()
1548
1321
        else:
1549
1322
            self.assertEqual(expected_docstring, obj.__doc__)
1550
1323
 
1551
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1552
1324
    def failUnlessExists(self, path):
1553
 
        return self.assertPathExists(path)
1554
 
 
1555
 
    def assertPathExists(self, path):
1556
1325
        """Fail unless path or paths, which may be abs or relative, exist."""
1557
1326
        if not isinstance(path, basestring):
1558
1327
            for p in path:
1559
 
                self.assertPathExists(p)
 
1328
                self.failUnlessExists(p)
1560
1329
        else:
1561
 
            self.assertTrue(osutils.lexists(path),
1562
 
                path + " does not exist")
 
1330
            self.failUnless(osutils.lexists(path),path+" does not exist")
1563
1331
 
1564
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4)))
1565
1332
    def failIfExists(self, path):
1566
 
        return self.assertPathDoesNotExist(path)
1567
 
 
1568
 
    def assertPathDoesNotExist(self, path):
1569
1333
        """Fail if path or paths, which may be abs or relative, exist."""
1570
1334
        if not isinstance(path, basestring):
1571
1335
            for p in path:
1572
 
                self.assertPathDoesNotExist(p)
 
1336
                self.failIfExists(p)
1573
1337
        else:
1574
 
            self.assertFalse(osutils.lexists(path),
1575
 
                path + " exists")
 
1338
            self.failIf(osutils.lexists(path),path+" exists")
1576
1339
 
1577
1340
    def _capture_deprecation_warnings(self, a_callable, *args, **kwargs):
1578
1341
        """A helper for callDeprecated and applyDeprecated.
1604
1367
        not other callers that go direct to the warning module.
1605
1368
 
1606
1369
        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)::
 
1370
        this::
1609
1371
 
1610
1372
            self.assertRaises(errors.ReservedId,
1611
1373
                self.applyDeprecated,
1693
1455
 
1694
1456
        The file is removed as the test is torn down.
1695
1457
        """
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)
 
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
1705
1462
        self.addCleanup(self._finishLogFile)
1706
1463
 
1707
1464
    def _finishLogFile(self):
1708
1465
        """Finished with the log file.
1709
1466
 
1710
 
        Close the file and delete it.
 
1467
        Close the file and delete it, unless setKeepLogfile was called.
1711
1468
        """
1712
 
        if trace._trace_file:
 
1469
        if bzrlib.trace._trace_file:
1713
1470
            # flush the log file, to get all content
1714
 
            trace._trace_file.flush()
1715
 
        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)
1716
1475
 
1717
1476
    def thisFailsStrictLockCheck(self):
1718
1477
        """It is known that this test would fail with -Dstrict_locks.
1727
1486
        """
1728
1487
        debug.debug_flags.discard('strict_locks')
1729
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
 
1730
1497
    def overrideAttr(self, obj, attr_name, new=_unitialized_attr):
1731
1498
        """Overrides an object attribute restoring it after the test.
1732
1499
 
1746
1513
            setattr(obj, attr_name, new)
1747
1514
        return value
1748
1515
 
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
1516
    def _cleanEnvironment(self):
1764
 
        for name, value in isolated_environ.iteritems():
1765
 
            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)
1766
1577
 
1767
1578
    def _restoreHooks(self):
1768
1579
        for klass, (name, hooks) in self._preserved_hooks.items():
1769
1580
            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
1581
 
1774
1582
    def knownFailure(self, reason):
1775
1583
        """This test has failed for some known reason."""
1776
1584
        raise KnownFailure(reason)
1777
1585
 
1778
 
    def _suppress_log(self):
1779
 
        """Remove the log info from details."""
1780
 
        self.discardDetail('log')
1781
 
 
1782
1586
    def _do_skip(self, result, reason):
1783
 
        self._suppress_log()
1784
1587
        addSkip = getattr(result, 'addSkip', None)
1785
1588
        if not callable(addSkip):
1786
1589
            result.addSuccess(result)
1789
1592
 
1790
1593
    @staticmethod
1791
1594
    def _do_known_failure(self, result, e):
1792
 
        self._suppress_log()
1793
1595
        err = sys.exc_info()
1794
1596
        addExpectedFailure = getattr(result, 'addExpectedFailure', None)
1795
1597
        if addExpectedFailure is not None:
1803
1605
            reason = 'No reason given'
1804
1606
        else:
1805
1607
            reason = e.args[0]
1806
 
        self._suppress_log ()
1807
1608
        addNotApplicable = getattr(result, 'addNotApplicable', None)
1808
1609
        if addNotApplicable is not None:
1809
1610
            result.addNotApplicable(self, reason)
1811
1612
            self._do_skip(result, reason)
1812
1613
 
1813
1614
    @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
1615
    def _do_unsupported_or_skip(self, result, e):
1835
1616
        reason = e.args[0]
1836
 
        self._suppress_log()
1837
1617
        addNotSupported = getattr(result, 'addNotSupported', None)
1838
1618
        if addNotSupported is not None:
1839
1619
            result.addNotSupported(self, reason)
1865
1645
            self._benchtime += time.time() - start
1866
1646
 
1867
1647
    def log(self, *args):
1868
 
        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."
1869
1728
 
1870
1729
    def get_log(self):
1871
1730
        """Get a unicode string containing the log from bzrlib.trace.
1921
1780
 
1922
1781
        try:
1923
1782
            try:
1924
 
                result = self.apply_redirected(
1925
 
                    ui.ui_factory.stdin,
 
1783
                result = self.apply_redirected(ui.ui_factory.stdin,
1926
1784
                    stdout, stderr,
1927
 
                    _mod_commands.run_bzr_catch_user_errors,
 
1785
                    bzrlib.commands.run_bzr_catch_user_errors,
1928
1786
                    args)
1929
1787
            except KeyboardInterrupt:
1930
1788
                # Reraise KeyboardInterrupt with contents of redirected stdout
2072
1930
    def start_bzr_subprocess(self, process_args, env_changes=None,
2073
1931
                             skip_if_plan_to_signal=False,
2074
1932
                             working_dir=None,
2075
 
                             allow_plugins=False, stderr=subprocess.PIPE):
 
1933
                             allow_plugins=False):
2076
1934
        """Start bzr in a subprocess for testing.
2077
1935
 
2078
1936
        This starts a new Python interpreter and runs bzr in there.
2087
1945
            variables. A value of None will unset the env variable.
2088
1946
            The values must be strings. The change will only occur in the
2089
1947
            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.
 
1948
        :param skip_if_plan_to_signal: raise TestSkipped when true and os.kill
 
1949
            is not available.
2092
1950
        :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
1951
 
2097
1952
        :returns: Popen object for the started process.
2098
1953
        """
2099
1954
        if skip_if_plan_to_signal:
2100
 
            if os.name != "posix":
2101
 
                raise TestSkipped("Sending signals not supported")
 
1955
            if not getattr(os, 'kill', None):
 
1956
                raise TestSkipped("os.kill not available.")
2102
1957
 
2103
1958
        if env_changes is None:
2104
1959
            env_changes = {}
2124
1979
            # so we will avoid using it on all platforms, just to
2125
1980
            # make sure the code path is used, and we don't break on win32
2126
1981
            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
1982
            command = [sys.executable]
2131
1983
            # frozen executables don't need the path to bzr
2132
1984
            if getattr(sys, "frozen", None) is None:
2134
1986
            if not allow_plugins:
2135
1987
                command.append('--no-plugins')
2136
1988
            command.extend(process_args)
2137
 
            process = self._popen(command, stdin=subprocess.PIPE,
2138
 
                                  stdout=subprocess.PIPE,
2139
 
                                  stderr=stderr)
 
1989
            process = self._popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE)
2140
1990
        finally:
2141
1991
            restore_environment()
2142
1992
            if cwd is not None:
2144
1994
 
2145
1995
        return process
2146
1996
 
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
1997
    def _popen(self, *args, **kwargs):
2175
1998
        """Place a call to Popen.
2176
1999
 
2177
2000
        Allows tests to override this method to intercept the calls made to
2178
2001
        Popen for introspection.
2179
2002
        """
2180
 
        return subprocess.Popen(*args, **kwargs)
 
2003
        return Popen(*args, **kwargs)
2181
2004
 
2182
2005
    def get_source_path(self):
2183
2006
        """Return the path of the directory containing bzrlib."""
2185
2008
 
2186
2009
    def get_bzr_path(self):
2187
2010
        """Return the path of the 'bzr' executable for this test suite."""
2188
 
        bzr_path = os.path.join(self.get_source_path(), "bzr")
 
2011
        bzr_path = self.get_source_path()+'/bzr'
2189
2012
        if not os.path.isfile(bzr_path):
2190
2013
            # We are probably installed. Assume sys.argv is the right file
2191
2014
            bzr_path = sys.argv[0]
2213
2036
        if retcode is not None and retcode != process.returncode:
2214
2037
            if process_args is None:
2215
2038
                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)
 
2039
            mutter('Output of bzr %s:\n%s', process_args, out)
 
2040
            mutter('Error for bzr %s:\n%s', process_args, err)
2218
2041
            self.fail('Command bzr %s failed with retcode %s != %s'
2219
2042
                      % (process_args, retcode, process.returncode))
2220
2043
        return [out, err]
2221
2044
 
2222
 
    def check_tree_shape(self, tree, shape):
2223
 
        """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.
2224
2047
 
2225
2048
        Fail if they are not precisely equal.
2226
2049
        """
2227
2050
        extras = []
2228
2051
        shape = list(shape)             # copy
2229
 
        for path, ie in tree.iter_entries_by_dir():
 
2052
        for path, ie in inv.entries():
2230
2053
            name = path.replace('\\', '/')
2231
2054
            if ie.kind == 'directory':
2232
2055
                name = name + '/'
2233
 
            if name == "/":
2234
 
                pass # ignore root entry
2235
 
            elif name in shape:
 
2056
            if name in shape:
2236
2057
                shape.remove(name)
2237
2058
            else:
2238
2059
                extras.append(name)
2279
2100
 
2280
2101
        Tests that expect to provoke LockContention errors should call this.
2281
2102
        """
2282
 
        self.overrideAttr(lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
 
2103
        self.overrideAttr(bzrlib.lockdir, '_DEFAULT_TIMEOUT_SECONDS', 0)
2283
2104
 
2284
2105
    def make_utf8_encoded_stringio(self, encoding_type=None):
2285
2106
        """Return a StringIOWrapper instance, that will encode Unicode
2328
2149
class TestCaseWithMemoryTransport(TestCase):
2329
2150
    """Common test class for tests that do not need disk resources.
2330
2151
 
2331
 
    Tests that need disk resources should derive from TestCaseInTempDir
2332
 
    orTestCaseWithTransport.
 
2152
    Tests that need disk resources should derive from TestCaseWithTransport.
2333
2153
 
2334
2154
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2335
2155
 
2336
 
    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
2337
2157
    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
 
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
2341
2161
    override, so tests that accidentally write to the common directory should
2342
2162
    be rare.
2343
2163
 
2344
 
    :cvar TEST_ROOT: Directory containing all temporary directories, plus a
2345
 
        ``.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.
2346
2166
    """
2347
2167
 
2348
2168
    TEST_ROOT = None
2366
2186
 
2367
2187
        :param relpath: a path relative to the base url.
2368
2188
        """
2369
 
        t = _mod_transport.get_transport(self.get_url(relpath))
 
2189
        t = get_transport(self.get_url(relpath))
2370
2190
        self.assertFalse(t.is_readonly())
2371
2191
        return t
2372
2192
 
2378
2198
 
2379
2199
        :param relpath: a path relative to the base url.
2380
2200
        """
2381
 
        t = _mod_transport.get_transport(self.get_readonly_url(relpath))
 
2201
        t = get_transport(self.get_readonly_url(relpath))
2382
2202
        self.assertTrue(t.is_readonly())
2383
2203
        return t
2384
2204
 
2514
2334
        propagating. This method ensures than a test did not leaked.
2515
2335
        """
2516
2336
        root = TestCaseWithMemoryTransport.TEST_ROOT
2517
 
        self.permit_url(_mod_transport.get_transport(root).base)
 
2337
        self.permit_url(get_transport(root).base)
2518
2338
        wt = workingtree.WorkingTree.open(root)
2519
2339
        last_rev = wt.last_revision()
2520
2340
        if last_rev != 'null:':
2565
2385
            # might be a relative or absolute path
2566
2386
            maybe_a_url = self.get_url(relpath)
2567
2387
            segments = maybe_a_url.rsplit('/', 1)
2568
 
            t = _mod_transport.get_transport(maybe_a_url)
 
2388
            t = get_transport(maybe_a_url)
2569
2389
            if len(segments) > 1 and segments[-1] not in ('', '.'):
2570
2390
                t.ensure_base()
2571
2391
            if format is None:
2588
2408
        made_control = self.make_bzrdir(relpath, format=format)
2589
2409
        return made_control.create_repository(shared=shared)
2590
2410
 
2591
 
    def make_smart_server(self, path, backing_server=None):
2592
 
        if backing_server is None:
2593
 
            backing_server = self.get_server()
 
2411
    def make_smart_server(self, path):
2594
2412
        smart_server = test_server.SmartTCPServer_for_testing()
2595
 
        self.start_server(smart_server, backing_server)
2596
 
        remote_transport = _mod_transport.get_transport(smart_server.get_url()
2597
 
                                                   ).clone(path)
 
2413
        self.start_server(smart_server, self.get_server())
 
2414
        remote_transport = get_transport(smart_server.get_url()).clone(path)
2598
2415
        return remote_transport
2599
2416
 
2600
2417
    def make_branch_and_memory_tree(self, relpath, format=None):
2610
2427
        test_home_dir = self.test_home_dir
2611
2428
        if isinstance(test_home_dir, unicode):
2612
2429
            test_home_dir = test_home_dir.encode(sys.getfilesystemencoding())
2613
 
        self.overrideEnv('HOME', test_home_dir)
2614
 
        self.overrideEnv('BZR_HOME', test_home_dir)
 
2430
        os.environ['HOME'] = test_home_dir
 
2431
        os.environ['BZR_HOME'] = test_home_dir
2615
2432
 
2616
2433
    def setUp(self):
2617
2434
        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
2435
        self._make_test_root()
2628
2436
        self.addCleanup(os.chdir, os.getcwdu())
2629
2437
        self.makeAndChdirToTestDir()
2672
2480
 
2673
2481
    OVERRIDE_PYTHON = 'python'
2674
2482
 
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
2483
    def check_file_contents(self, filename, expect):
2682
2484
        self.log("check contents of file %s" % filename)
2683
 
        f = file(filename)
2684
 
        try:
2685
 
            contents = f.read()
2686
 
        finally:
2687
 
            f.close()
 
2485
        contents = file(filename, 'r').read()
2688
2486
        if contents != expect:
2689
2487
            self.log("expected: %r" % expect)
2690
2488
            self.log("actually: %r" % contents)
2764
2562
                "a list or a tuple. Got %r instead" % (shape,))
2765
2563
        # It's OK to just create them using forward slashes on windows.
2766
2564
        if transport is None or transport.is_readonly():
2767
 
            transport = _mod_transport.get_transport(".")
 
2565
            transport = get_transport(".")
2768
2566
        for name in shape:
2769
2567
            self.assertIsInstance(name, basestring)
2770
2568
            if name[-1] == '/':
2780
2578
                content = "contents of %s%s" % (name.encode('utf-8'), end)
2781
2579
                transport.put_bytes_non_atomic(urlutils.escape(name), content)
2782
2580
 
2783
 
    build_tree_contents = staticmethod(treeshape.build_tree_contents)
 
2581
    def build_tree_contents(self, shape):
 
2582
        build_tree_contents(shape)
2784
2583
 
2785
2584
    def assertInWorkingTree(self, path, root_path='.', tree=None):
2786
2585
        """Assert whether path or paths are in the WorkingTree"""
2927
2726
    """
2928
2727
 
2929
2728
    def setUp(self):
2930
 
        from bzrlib.tests import http_server
2931
2729
        super(ChrootedTestCase, self).setUp()
2932
2730
        if not self.vfs_transport_factory == memory.MemoryServer:
2933
 
            self.transport_readonly_server = http_server.HttpServer
 
2731
            self.transport_readonly_server = HttpServer
2934
2732
 
2935
2733
 
2936
2734
def condition_id_re(pattern):
2939
2737
    :param pattern: A regular expression string.
2940
2738
    :return: A callable that returns True if the re matches.
2941
2739
    """
2942
 
    filter_re = re.compile(pattern, 0)
 
2740
    filter_re = osutils.re_compile_checked(pattern, 0,
 
2741
        'test filter')
2943
2742
    def condition(test):
2944
2743
        test_id = test.id()
2945
2744
        return filter_re.search(test_id)
3197
2996
 
3198
2997
 
3199
2998
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
2999
    concurrency = osutils.local_concurrency()
3204
3000
    if concurrency == 1:
3205
3001
        return suite
3260
3056
    return suite
3261
3057
 
3262
3058
 
3263
 
class TestDecorator(TestUtil.TestSuite):
 
3059
class TestDecorator(TestSuite):
3264
3060
    """A decorator for TestCase/TestSuite objects.
3265
3061
    
3266
3062
    Usually, subclasses should override __iter__(used when flattening test
3269
3065
    """
3270
3066
 
3271
3067
    def __init__(self, suite):
3272
 
        TestUtil.TestSuite.__init__(self)
 
3068
        TestSuite.__init__(self)
3273
3069
        self.addTest(suite)
3274
3070
 
3275
3071
    def countTestCases(self):
3394
3190
 
3395
3191
def partition_tests(suite, count):
3396
3192
    """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
 
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
3407
3202
 
3408
3203
 
3409
3204
def workaround_zealous_crypto_random():
3443
3238
 
3444
3239
    test_blocks = partition_tests(suite, concurrency)
3445
3240
    for process_tests in test_blocks:
3446
 
        process_suite = TestUtil.TestSuite()
 
3241
        process_suite = TestSuite()
3447
3242
        process_suite.addTests(process_tests)
3448
3243
        c2pread, c2pwrite = os.pipe()
3449
3244
        pid = os.fork()
3515
3310
                '--subunit']
3516
3311
            if '--no-plugins' in sys.argv:
3517
3312
                argv.append('--no-plugins')
3518
 
            # stderr=subprocess.STDOUT would be ideal, but until we prevent
3519
 
            # noise on stderr it can interrupt the subunit protocol.
3520
 
            process = subprocess.Popen(argv, stdin=subprocess.PIPE,
3521
 
                                      stdout=subprocess.PIPE,
3522
 
                                      stderr=subprocess.PIPE,
3523
 
                                      bufsize=1)
 
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)
3524
3317
            test = TestInSubprocess(process, test_list_file_name)
3525
3318
            result.append(test)
3526
3319
        except:
3529
3322
    return result
3530
3323
 
3531
3324
 
3532
 
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):
3533
3358
    """Generate profiling data for all activity between start and success.
3534
3359
    
3535
3360
    The profile data is appended to the test's _benchcalls attribute and can
3543
3368
 
3544
3369
    def startTest(self, test):
3545
3370
        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
3371
        self.profiler.start()
3550
 
        testtools.ExtendedToOriginalDecorator.startTest(self, test)
 
3372
        ForwardingResult.startTest(self, test)
3551
3373
 
3552
3374
    def addSuccess(self, test):
3553
3375
        stats = self.profiler.stop()
3557
3379
            test._benchcalls = []
3558
3380
            calls = test._benchcalls
3559
3381
        calls.append(((test.id(), "", ""), stats))
3560
 
        testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
 
3382
        ForwardingResult.addSuccess(self, test)
3561
3383
 
3562
3384
    def stopTest(self, test):
3563
 
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
 
3385
        ForwardingResult.stopTest(self, test)
3564
3386
        self.profiler = None
3565
3387
 
3566
3388
 
3572
3394
#                           rather than failing tests. And no longer raise
3573
3395
#                           LockContention when fctnl locks are not being used
3574
3396
#                           with proper exclusion rules.
3575
 
#   -Ethreads               Will display thread ident at creation/join time to
3576
 
#                           help track thread leaks
3577
 
 
3578
 
#   -Econfig_stats          Will collect statistics using addDetail
3579
3397
selftest_debug_flags = set()
3580
3398
 
3581
3399
 
3775
3593
                key, obj, help=help, info=info, override_existing=False)
3776
3594
        except KeyError:
3777
3595
            actual = self.get(key)
3778
 
            trace.note(
3779
 
                'Test prefix alias %s is already used for %s, ignoring %s'
3780
 
                % (key, actual, obj))
 
3596
            note('Test prefix alias %s is already used for %s, ignoring %s'
 
3597
                 % (key, actual, obj))
3781
3598
 
3782
3599
    def resolve_alias(self, id_start):
3783
3600
        """Replace the alias by the prefix in the given string.
3815
3632
        'bzrlib.doc',
3816
3633
        'bzrlib.tests.blackbox',
3817
3634
        'bzrlib.tests.commands',
3818
 
        'bzrlib.tests.doc_generate',
3819
3635
        'bzrlib.tests.per_branch',
3820
3636
        'bzrlib.tests.per_bzrdir',
3821
 
        'bzrlib.tests.per_controldir',
3822
 
        'bzrlib.tests.per_controldir_colo',
 
3637
        'bzrlib.tests.per_bzrdir_colo',
3823
3638
        'bzrlib.tests.per_foreign_vcs',
3824
3639
        'bzrlib.tests.per_interrepository',
3825
3640
        'bzrlib.tests.per_intertree',
3833
3648
        'bzrlib.tests.per_repository',
3834
3649
        'bzrlib.tests.per_repository_chk',
3835
3650
        'bzrlib.tests.per_repository_reference',
3836
 
        'bzrlib.tests.per_repository_vf',
3837
3651
        'bzrlib.tests.per_uifactory',
3838
3652
        'bzrlib.tests.per_versionedfile',
3839
3653
        'bzrlib.tests.per_workingtree',
3840
3654
        'bzrlib.tests.test__annotator',
3841
3655
        'bzrlib.tests.test__bencode',
3842
 
        'bzrlib.tests.test__btree_serializer',
3843
3656
        'bzrlib.tests.test__chk_map',
3844
3657
        'bzrlib.tests.test__dirstate_helpers',
3845
3658
        'bzrlib.tests.test__groupcompress',
3873
3686
        'bzrlib.tests.test_commit_merge',
3874
3687
        'bzrlib.tests.test_config',
3875
3688
        'bzrlib.tests.test_conflicts',
3876
 
        'bzrlib.tests.test_controldir',
3877
3689
        'bzrlib.tests.test_counted_lock',
3878
3690
        'bzrlib.tests.test_crash',
3879
3691
        'bzrlib.tests.test_decorators',
3880
3692
        'bzrlib.tests.test_delta',
3881
3693
        'bzrlib.tests.test_debug',
 
3694
        'bzrlib.tests.test_deprecated_graph',
3882
3695
        'bzrlib.tests.test_diff',
3883
3696
        'bzrlib.tests.test_directory_service',
3884
3697
        'bzrlib.tests.test_dirstate',
3886
3699
        'bzrlib.tests.test_eol_filters',
3887
3700
        'bzrlib.tests.test_errors',
3888
3701
        'bzrlib.tests.test_export',
3889
 
        'bzrlib.tests.test_export_pot',
3890
3702
        'bzrlib.tests.test_extract',
3891
3703
        'bzrlib.tests.test_fetch',
3892
 
        'bzrlib.tests.test_fixtures',
3893
3704
        'bzrlib.tests.test_fifo_cache',
3894
3705
        'bzrlib.tests.test_filters',
3895
3706
        'bzrlib.tests.test_ftp_transport',
3906
3717
        'bzrlib.tests.test_http',
3907
3718
        'bzrlib.tests.test_http_response',
3908
3719
        'bzrlib.tests.test_https_ca_bundle',
3909
 
        'bzrlib.tests.test_i18n',
3910
3720
        'bzrlib.tests.test_identitymap',
3911
3721
        'bzrlib.tests.test_ignores',
3912
3722
        'bzrlib.tests.test_index',
3917
3727
        'bzrlib.tests.test_knit',
3918
3728
        'bzrlib.tests.test_lazy_import',
3919
3729
        'bzrlib.tests.test_lazy_regex',
3920
 
        'bzrlib.tests.test_library_state',
3921
3730
        'bzrlib.tests.test_lock',
3922
3731
        'bzrlib.tests.test_lockable_files',
3923
3732
        'bzrlib.tests.test_lockdir',
3925
3734
        'bzrlib.tests.test_lru_cache',
3926
3735
        'bzrlib.tests.test_lsprof',
3927
3736
        'bzrlib.tests.test_mail_client',
3928
 
        'bzrlib.tests.test_matchers',
3929
3737
        'bzrlib.tests.test_memorytree',
3930
3738
        'bzrlib.tests.test_merge',
3931
3739
        'bzrlib.tests.test_merge3',
3932
3740
        'bzrlib.tests.test_merge_core',
3933
3741
        'bzrlib.tests.test_merge_directive',
3934
 
        'bzrlib.tests.test_mergetools',
3935
3742
        'bzrlib.tests.test_missing',
3936
3743
        'bzrlib.tests.test_msgeditor',
3937
3744
        'bzrlib.tests.test_multiparent',
3946
3753
        'bzrlib.tests.test_permissions',
3947
3754
        'bzrlib.tests.test_plugins',
3948
3755
        'bzrlib.tests.test_progress',
3949
 
        'bzrlib.tests.test_pyutils',
3950
3756
        'bzrlib.tests.test_read_bundle',
3951
3757
        'bzrlib.tests.test_reconcile',
3952
3758
        'bzrlib.tests.test_reconfigure',
3961
3767
        'bzrlib.tests.test_rio',
3962
3768
        'bzrlib.tests.test_rules',
3963
3769
        'bzrlib.tests.test_sampler',
3964
 
        'bzrlib.tests.test_scenarios',
3965
3770
        'bzrlib.tests.test_script',
3966
3771
        'bzrlib.tests.test_selftest',
3967
3772
        'bzrlib.tests.test_serializer',
3983
3788
        'bzrlib.tests.test_switch',
3984
3789
        'bzrlib.tests.test_symbol_versioning',
3985
3790
        'bzrlib.tests.test_tag',
3986
 
        'bzrlib.tests.test_test_server',
3987
3791
        'bzrlib.tests.test_testament',
3988
3792
        'bzrlib.tests.test_textfile',
3989
3793
        'bzrlib.tests.test_textmerge',
3990
 
        'bzrlib.tests.test_cethread',
3991
3794
        'bzrlib.tests.test_timestamp',
3992
3795
        'bzrlib.tests.test_trace',
3993
3796
        'bzrlib.tests.test_transactions',
3996
3799
        'bzrlib.tests.test_transport_log',
3997
3800
        'bzrlib.tests.test_tree',
3998
3801
        'bzrlib.tests.test_treebuilder',
3999
 
        'bzrlib.tests.test_treeshape',
4000
3802
        'bzrlib.tests.test_tsort',
4001
3803
        'bzrlib.tests.test_tuned_gzip',
4002
3804
        'bzrlib.tests.test_ui',
4004
3806
        'bzrlib.tests.test_upgrade',
4005
3807
        'bzrlib.tests.test_upgrade_stacked',
4006
3808
        'bzrlib.tests.test_urlutils',
4007
 
        'bzrlib.tests.test_utextwrap',
4008
3809
        'bzrlib.tests.test_version',
4009
3810
        'bzrlib.tests.test_version_info',
4010
 
        'bzrlib.tests.test_versionedfile',
4011
3811
        'bzrlib.tests.test_weave',
4012
3812
        'bzrlib.tests.test_whitebox',
4013
3813
        'bzrlib.tests.test_win32utils',
4027
3827
        'bzrlib',
4028
3828
        'bzrlib.branchbuilder',
4029
3829
        'bzrlib.decorators',
 
3830
        'bzrlib.export',
4030
3831
        'bzrlib.inventory',
4031
3832
        'bzrlib.iterablefile',
4032
3833
        'bzrlib.lockdir',
4033
3834
        'bzrlib.merge3',
4034
3835
        'bzrlib.option',
4035
 
        'bzrlib.pyutils',
4036
3836
        'bzrlib.symbol_versioning',
4037
3837
        'bzrlib.tests',
4038
 
        'bzrlib.tests.fixtures',
4039
3838
        'bzrlib.timestamp',
4040
 
        'bzrlib.transport.http',
4041
3839
        'bzrlib.version_info_formats.format_custom',
4042
3840
        ]
4043
3841
 
4096
3894
        try:
4097
3895
            # note that this really does mean "report only" -- doctest
4098
3896
            # still runs the rest of the examples
4099
 
            doc_suite = IsolatedDocTestSuite(
4100
 
                mod, optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
 
3897
            doc_suite = doctest.DocTestSuite(mod,
 
3898
                optionflags=doctest.REPORT_ONLY_FIRST_FAILURE)
4101
3899
        except ValueError, e:
4102
3900
            print '**failed to get doctest for: %s\n%s' % (mod, e)
4103
3901
            raise
4106
3904
        suite.addTest(doc_suite)
4107
3905
 
4108
3906
    default_encoding = sys.getdefaultencoding()
4109
 
    for name, plugin in _mod_plugin.plugins().items():
 
3907
    for name, plugin in bzrlib.plugin.plugins().items():
4110
3908
        if not interesting_module(plugin.module.__name__):
4111
3909
            continue
4112
3910
        plugin_suite = plugin.test_suite()
4118
3916
        if plugin_suite is not None:
4119
3917
            suite.addTest(plugin_suite)
4120
3918
        if default_encoding != sys.getdefaultencoding():
4121
 
            trace.warning(
 
3919
            bzrlib.trace.warning(
4122
3920
                'Plugin "%s" tried to reset default encoding to: %s', name,
4123
3921
                sys.getdefaultencoding())
4124
3922
            reload(sys)
4139
3937
            # Some tests mentioned in the list are not in the test suite. The
4140
3938
            # list may be out of date, report to the tester.
4141
3939
            for id in not_found:
4142
 
                trace.warning('"%s" not found in the test suite', id)
 
3940
                bzrlib.trace.warning('"%s" not found in the test suite', id)
4143
3941
        for id in duplicates:
4144
 
            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)
4145
3943
 
4146
3944
    return suite
4147
3945
 
4148
3946
 
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):
 
3947
def multiply_scenarios(scenarios_left, scenarios_right):
4162
3948
    """Multiply two sets of scenarios.
4163
3949
 
4164
3950
    :returns: the cartesian product of the two sets of scenarios, that is
4195
3981
    ...     bzrlib.tests.test_sampler.DemoTest('test_nothing'),
4196
3982
    ...     [('one', dict(param=1)),
4197
3983
    ...      ('two', dict(param=2))],
4198
 
    ...     TestUtil.TestSuite())
 
3984
    ...     TestSuite())
4199
3985
    >>> tests = list(iter_suite_tests(r))
4200
3986
    >>> len(tests)
4201
3987
    2
4248
4034
    :param new_id: The id to assign to it.
4249
4035
    :return: The new test.
4250
4036
    """
4251
 
    new_test = copy.copy(test)
 
4037
    new_test = copy(test)
4252
4038
    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
4039
    return new_test
4266
4040
 
4267
4041
 
4288
4062
        the module is available.
4289
4063
    """
4290
4064
 
4291
 
    py_module = pyutils.get_named_object(py_module_name)
 
4065
    py_module = __import__(py_module_name, {}, {}, ['NO_SUCH_ATTRIB'])
4292
4066
    scenarios = [
4293
4067
        ('python', {'module': py_module}),
4294
4068
    ]
4327
4101
        if test_id != None:
4328
4102
            ui.ui_factory.clear_term()
4329
4103
            sys.stderr.write('\nWhile running: %s\n' % (test_id,))
4330
 
        # Ugly, but the last thing we want here is fail, so bear with it.
4331
 
        printable_e = str(e).decode(osutils.get_user_encoding(), 'replace'
4332
 
                                    ).encode('ascii', 'replace')
4333
4104
        sys.stderr.write('Unable to remove testing dir %s\n%s'
4334
 
                         % (os.path.basename(dirname), printable_e))
 
4105
                         % (os.path.basename(dirname), e))
4335
4106
 
4336
4107
 
4337
4108
class Feature(object):
4447
4218
            symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4448
4219
            # Import the new feature and use it as a replacement for the
4449
4220
            # deprecated one.
4450
 
            self._feature = pyutils.get_named_object(
4451
 
                self._replacement_module, self._replacement_name)
 
4221
            mod = __import__(self._replacement_module, {}, {},
 
4222
                             [self._replacement_name])
 
4223
            self._feature = getattr(mod, self._replacement_name)
4452
4224
 
4453
4225
    def _probe(self):
4454
4226
        self._ensure()
4485
4257
        return self.module_name
4486
4258
 
4487
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')
 
4265
 
 
4266
 
4488
4267
def probe_unicode_in_user_encoding():
4489
4268
    """Try to encode several unicode strings to use in unicode-aware tests.
4490
4269
    Return first successfull match.
4559
4338
UnicodeFilename = _UnicodeFilename()
4560
4339
 
4561
4340
 
4562
 
class _ByteStringNamedFilesystem(Feature):
4563
 
    """Is the filesystem based on bytes?"""
4564
 
 
4565
 
    def _probe(self):
4566
 
        if os.name == "posix":
4567
 
            return True
4568
 
        return False
4569
 
 
4570
 
ByteStringNamedFilesystem = _ByteStringNamedFilesystem()
4571
 
 
4572
 
 
4573
4341
class _UTF8Filesystem(Feature):
4574
4342
    """Is the filesystem UTF-8?"""
4575
4343
 
4677
4445
case_sensitive_filesystem_feature = _CaseSensitiveFilesystemFeature()
4678
4446
 
4679
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')
4680
4452
# Only define SubUnitBzrRunner if subunit is available.
4681
4453
try:
4682
4454
    from subunit import TestProtocolClient
4683
4455
    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
4456
    class SubUnitBzrRunner(TextTestRunner):
4695
4457
        def run(self, test):
4696
4458
            result = AutoTimingTestResultDecorator(
4697
 
                SubUnitBzrProtocolClient(self.stream))
 
4459
                TestProtocolClient(self.stream))
4698
4460
            test.run(result)
4699
4461
            return result
4700
4462
except ImportError: