~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Jelmer Vernooij
  • Date: 2010-12-20 11:57:14 UTC
  • mto: This revision was merged to the branch mainline in revision 5577.
  • Revision ID: jelmer@samba.org-20101220115714-2ru3hfappjweeg7q
Don't use no-plugins.

Show diffs side-by-side

added added

removed removed

Lines of Context:
55
55
import testtools
56
56
# nb: check this before importing anything else from within it
57
57
_testtools_version = getattr(testtools, '__version__', ())
58
 
if _testtools_version < (0, 9, 2):
59
 
    raise ImportError("need at least testtools 0.9.2: %s is %r"
 
58
if _testtools_version < (0, 9, 5):
 
59
    raise ImportError("need at least testtools 0.9.5: %s is %r"
60
60
        % (testtools.__file__, _testtools_version))
61
61
from testtools import content
62
62
 
71
71
    lock as _mod_lock,
72
72
    memorytree,
73
73
    osutils,
 
74
    pyutils,
74
75
    ui,
75
76
    urlutils,
76
77
    registry,
89
90
except ImportError:
90
91
    # lsprof not available
91
92
    pass
92
 
from bzrlib.merge import merge_inner
93
93
import bzrlib.merge3
94
94
import bzrlib.plugin
95
 
from bzrlib.smart import client, request, server
 
95
from bzrlib.smart import client, request
96
96
import bzrlib.store
97
97
from bzrlib import symbol_versioning
98
98
from bzrlib.symbol_versioning import (
116
116
from bzrlib.ui import NullProgressView
117
117
from bzrlib.ui.text import TextUIFactory
118
118
import bzrlib.version_info_formats.format_custom
119
 
from bzrlib.workingtree import WorkingTree, WorkingTreeFormat2
120
119
 
121
120
# Mark this python module as being part of the implementation
122
121
# of unittest: this gives us better tracebacks where the last
195
194
        self._strict = strict
196
195
        self._first_thread_leaker_id = None
197
196
        self._tests_leaking_threads_count = 0
 
197
        self._traceback_from_test = None
198
198
 
199
199
    def stopTestRun(self):
200
200
        run = self.testsRun
260
260
 
261
261
    def _elapsedTestTimeString(self):
262
262
        """Return a time string for the overall time the current test has taken."""
263
 
        return self._formatTime(time.time() - self._start_time)
 
263
        return self._formatTime(self._delta_to_float(
 
264
            self._now() - self._start_datetime))
264
265
 
265
266
    def _testTimeString(self, testCase):
266
267
        benchmark_time = self._extractBenchmarkTime(testCase)
280
281
        what = re.sub(r'^bzrlib\.tests\.', '', what)
281
282
        return what
282
283
 
 
284
    # GZ 2010-10-04: Cloned tests may end up harmlessly calling this method
 
285
    #                multiple times in a row, because the handler is added for
 
286
    #                each test but the container list is shared between cases.
 
287
    #                See lp:498869 lp:625574 and lp:637725 for background.
 
288
    def _record_traceback_from_test(self, exc_info):
 
289
        """Store the traceback from passed exc_info tuple till"""
 
290
        self._traceback_from_test = exc_info[2]
 
291
 
283
292
    def startTest(self, test):
284
293
        super(ExtendedTestResult, self).startTest(test)
285
294
        if self.count == 0:
288
297
        self.report_test_start(test)
289
298
        test.number = self.count
290
299
        self._recordTestStartTime()
 
300
        # Make testtools cases give us the real traceback on failure
 
301
        addOnException = getattr(test, "addOnException", None)
 
302
        if addOnException is not None:
 
303
            addOnException(self._record_traceback_from_test)
291
304
        # Only check for thread leaks if the test case supports cleanups
292
305
        addCleanup = getattr(test, "addCleanup", None)
293
306
        if addCleanup is not None:
297
310
        self.report_tests_starting()
298
311
        self._active_threads = threading.enumerate()
299
312
 
 
313
    def stopTest(self, test):
 
314
        self._traceback_from_test = None
 
315
 
300
316
    def _check_leaked_threads(self, test):
301
317
        """See if any threads have leaked since last call
302
318
 
315
331
 
316
332
    def _recordTestStartTime(self):
317
333
        """Record that a test has started."""
318
 
        self._start_time = time.time()
 
334
        self._start_datetime = self._now()
319
335
 
320
336
    def addError(self, test, err):
321
337
        """Tell result that test finished with an error.
323
339
        Called from the TestCase run() method when the test
324
340
        fails with an unexpected error.
325
341
        """
326
 
        self._post_mortem()
 
342
        self._post_mortem(self._traceback_from_test)
327
343
        super(ExtendedTestResult, self).addError(test, err)
328
344
        self.error_count += 1
329
345
        self.report_error(test, err)
336
352
        Called from the TestCase run() method when the test
337
353
        fails because e.g. an assert() method failed.
338
354
        """
339
 
        self._post_mortem()
 
355
        self._post_mortem(self._traceback_from_test)
340
356
        super(ExtendedTestResult, self).addFailure(test, err)
341
357
        self.failure_count += 1
342
358
        self.report_failure(test, err)
384
400
        self.not_applicable_count += 1
385
401
        self.report_not_applicable(test, reason)
386
402
 
387
 
    def _post_mortem(self):
 
403
    def _post_mortem(self, tb=None):
388
404
        """Start a PDB post mortem session."""
389
405
        if os.environ.get('BZR_TEST_PDB', None):
390
 
            import pdb;pdb.post_mortem()
 
406
            import pdb
 
407
            pdb.post_mortem(tb)
391
408
 
392
409
    def progress(self, offset, whence):
393
410
        """The test is adjusting the count of tests to run."""
634
651
            encode = codec[0]
635
652
        else:
636
653
            encode = codec.encode
637
 
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream)
 
654
        # GZ 2010-09-08: Really we don't want to be writing arbitrary bytes,
 
655
        #                so should swap to the plain codecs.StreamWriter
 
656
        stream = osutils.UnicodeOrBytesToBytesWriter(encode, stream,
 
657
            "backslashreplace")
638
658
        stream.encoding = new_encoding
639
659
        self.stream = stream
640
660
        self.descriptions = descriptions
840
860
        self._track_transports()
841
861
        self._track_locks()
842
862
        self._clear_debug_flags()
 
863
        # Isolate global verbosity level, to make sure it's reproducible
 
864
        # between tests.  We should get rid of this altogether: bug 656694. --
 
865
        # mbp 20101008
 
866
        self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
843
867
 
844
868
    def debug(self):
845
869
        # debug a frame up.
877
901
 
878
902
    def _clear_hooks(self):
879
903
        # prevent hooks affecting tests
 
904
        known_hooks = hooks.known_hooks
880
905
        self._preserved_hooks = {}
881
 
        for key, factory in hooks.known_hooks.items():
882
 
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
883
 
            current_hooks = hooks.known_hooks_key_to_object(key)
 
906
        for key, (parent, name) in known_hooks.iter_parent_objects():
 
907
            current_hooks = getattr(parent, name)
884
908
            self._preserved_hooks[parent] = (name, current_hooks)
885
909
        self.addCleanup(self._restoreHooks)
886
 
        for key, factory in hooks.known_hooks.items():
887
 
            parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
 
910
        for key, (parent, name) in known_hooks.iter_parent_objects():
 
911
            factory = known_hooks.get(key)
888
912
            setattr(parent, name, factory())
889
913
        # this hook should always be installed
890
914
        request._install_hook()
2430
2454
                self.addCleanup(t.disconnect)
2431
2455
            return t
2432
2456
 
2433
 
        orig_get_transport = self.overrideAttr(_mod_transport, 'get_transport',
 
2457
        orig_get_transport = self.overrideAttr(_mod_transport, '_get_transport',
2434
2458
                                               get_transport_with_cleanup)
2435
2459
        self._make_test_root()
2436
2460
        self.addCleanup(os.chdir, os.getcwdu())
3331
3355
    return result
3332
3356
 
3333
3357
 
3334
 
class ForwardingResult(unittest.TestResult):
3335
 
 
3336
 
    def __init__(self, target):
3337
 
        unittest.TestResult.__init__(self)
3338
 
        self.result = target
3339
 
 
3340
 
    def startTest(self, test):
3341
 
        self.result.startTest(test)
3342
 
 
3343
 
    def stopTest(self, test):
3344
 
        self.result.stopTest(test)
3345
 
 
3346
 
    def startTestRun(self):
3347
 
        self.result.startTestRun()
3348
 
 
3349
 
    def stopTestRun(self):
3350
 
        self.result.stopTestRun()
3351
 
 
3352
 
    def addSkip(self, test, reason):
3353
 
        self.result.addSkip(test, reason)
3354
 
 
3355
 
    def addSuccess(self, test):
3356
 
        self.result.addSuccess(test)
3357
 
 
3358
 
    def addError(self, test, err):
3359
 
        self.result.addError(test, err)
3360
 
 
3361
 
    def addFailure(self, test, err):
3362
 
        self.result.addFailure(test, err)
3363
 
ForwardingResult = testtools.ExtendedToOriginalDecorator
3364
 
 
3365
 
 
3366
 
class ProfileResult(ForwardingResult):
 
3358
class ProfileResult(testtools.ExtendedToOriginalDecorator):
3367
3359
    """Generate profiling data for all activity between start and success.
3368
3360
    
3369
3361
    The profile data is appended to the test's _benchcalls attribute and can
3381
3373
        # unavoidably fail.
3382
3374
        bzrlib.lsprof.BzrProfiler.profiler_block = 0
3383
3375
        self.profiler.start()
3384
 
        ForwardingResult.startTest(self, test)
 
3376
        testtools.ExtendedToOriginalDecorator.startTest(self, test)
3385
3377
 
3386
3378
    def addSuccess(self, test):
3387
3379
        stats = self.profiler.stop()
3391
3383
            test._benchcalls = []
3392
3384
            calls = test._benchcalls
3393
3385
        calls.append(((test.id(), "", ""), stats))
3394
 
        ForwardingResult.addSuccess(self, test)
 
3386
        testtools.ExtendedToOriginalDecorator.addSuccess(self, test)
3395
3387
 
3396
3388
    def stopTest(self, test):
3397
 
        ForwardingResult.stopTest(self, test)
 
3389
        testtools.ExtendedToOriginalDecorator.stopTest(self, test)
3398
3390
        self.profiler = None
3399
3391
 
3400
3392
 
3773
3765
        'bzrlib.tests.test_permissions',
3774
3766
        'bzrlib.tests.test_plugins',
3775
3767
        'bzrlib.tests.test_progress',
 
3768
        'bzrlib.tests.test_pyutils',
3776
3769
        'bzrlib.tests.test_read_bundle',
3777
3770
        'bzrlib.tests.test_reconcile',
3778
3771
        'bzrlib.tests.test_reconfigure',
3787
3780
        'bzrlib.tests.test_rio',
3788
3781
        'bzrlib.tests.test_rules',
3789
3782
        'bzrlib.tests.test_sampler',
 
3783
        'bzrlib.tests.test_scenarios',
3790
3784
        'bzrlib.tests.test_script',
3791
3785
        'bzrlib.tests.test_selftest',
3792
3786
        'bzrlib.tests.test_serializer',
3848
3842
        return []
3849
3843
    return [
3850
3844
        'bzrlib',
3851
 
        'bzrlib.branchbuilder',
 
3845
        # FIXME: Fixing bug #690563 revealed an isolation problem in the single
 
3846
        # doctest for branchbuilder. Uncomment this when bug #321320 is fixed
 
3847
        # to ensure the issue is addressed (note that to reproduce the bug in
 
3848
        # the doctest below, one should comment the 'email' config var in
 
3849
        # bazaar.conf (or anywhere else). This means an setup where *no* user
 
3850
        # is being set at all in the environment.
 
3851
#       'bzrlib.branchbuilder',
3852
3852
        'bzrlib.decorators',
3853
3853
        'bzrlib.export',
3854
3854
        'bzrlib.inventory',
3856
3856
        'bzrlib.lockdir',
3857
3857
        'bzrlib.merge3',
3858
3858
        'bzrlib.option',
 
3859
        'bzrlib.pyutils',
3859
3860
        'bzrlib.symbol_versioning',
3860
3861
        'bzrlib.tests',
3861
3862
        'bzrlib.tests.fixtures',
3862
3863
        'bzrlib.timestamp',
 
3864
        'bzrlib.transport.http',
3863
3865
        'bzrlib.version_info_formats.format_custom',
3864
3866
        ]
3865
3867
 
3968
3970
    return suite
3969
3971
 
3970
3972
 
3971
 
def multiply_scenarios(scenarios_left, scenarios_right):
 
3973
def multiply_scenarios(*scenarios):
 
3974
    """Multiply two or more iterables of scenarios.
 
3975
 
 
3976
    It is safe to pass scenario generators or iterators.
 
3977
 
 
3978
    :returns: A list of compound scenarios: the cross-product of all 
 
3979
        scenarios, with the names concatenated and the parameters
 
3980
        merged together.
 
3981
    """
 
3982
    return reduce(_multiply_two_scenarios, map(list, scenarios))
 
3983
 
 
3984
 
 
3985
def _multiply_two_scenarios(scenarios_left, scenarios_right):
3972
3986
    """Multiply two sets of scenarios.
3973
3987
 
3974
3988
    :returns: the cartesian product of the two sets of scenarios, that is
4098
4112
        the module is available.
4099
4113
    """
4100
4114
 
4101
 
    py_module = __import__(py_module_name, {}, {}, ['NO_SUCH_ATTRIB'])
 
4115
    py_module = pyutils.get_named_object(py_module_name)
4102
4116
    scenarios = [
4103
4117
        ('python', {'module': py_module}),
4104
4118
    ]
4257
4271
            symbol_versioning.warn(depr_msg + use_msg, DeprecationWarning)
4258
4272
            # Import the new feature and use it as a replacement for the
4259
4273
            # deprecated one.
4260
 
            mod = __import__(self._replacement_module, {}, {},
4261
 
                             [self._replacement_name])
4262
 
            self._feature = getattr(mod, self._replacement_name)
 
4274
            self._feature = pyutils.get_named_object(
 
4275
                self._replacement_module, self._replacement_name)
4263
4276
 
4264
4277
    def _probe(self):
4265
4278
        self._ensure()