~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Patch Queue Manager
  • Date: 2015-12-17 18:39:00 UTC
  • mfrom: (6606.1.2 fix-float)
  • Revision ID: pqm@pqm.ubuntu.com-20151217183900-0719du2uv1kwu3lc
(vila) Inline testtools private method to fix an issue in xenial (the
 private implementation has changed in an backward incompatible way).
 (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Testing framework extensions"""
18
18
 
 
19
from __future__ import absolute_import
 
20
 
19
21
# NOTE: Some classes in here use camelCaseNaming() rather than
20
22
# underscore_naming().  That's for consistency with unittest; it's not the
21
23
# general style of bzrlib.  Please continue that consistency when adding e.g.
30
32
import errno
31
33
import itertools
32
34
import logging
 
35
import math
33
36
import os
34
37
import platform
35
38
import pprint
36
39
import random
37
40
import re
38
41
import shlex
 
42
import site
39
43
import stat
40
44
import subprocess
41
45
import sys
57
61
import bzrlib
58
62
from bzrlib import (
59
63
    branchbuilder,
60
 
    bzrdir,
 
64
    controldir,
61
65
    chk_map,
62
66
    commands as _mod_commands,
63
67
    config,
94
98
    deprecated_in,
95
99
    )
96
100
from bzrlib.tests import (
 
101
    fixtures,
97
102
    test_server,
98
103
    TestUtil,
99
104
    treeshape,
100
105
    )
101
106
from bzrlib.ui import NullProgressView
102
107
from bzrlib.ui.text import TextUIFactory
 
108
from bzrlib.tests.features import _CompatabilityThunkFeature
103
109
 
104
110
# Mark this python module as being part of the implementation
105
111
# of unittest: this gives us better tracebacks where the last
132
138
isolated_environ = {
133
139
    'BZR_HOME': None,
134
140
    'HOME': None,
 
141
    'XDG_CONFIG_HOME': None,
135
142
    # bzr now uses the Win32 API and doesn't rely on APPDATA, but the
136
143
    # tests do check our impls match APPDATA
137
144
    'BZR_EDITOR': None, # test_msgeditor manipulates this variable
212
219
        osutils.set_or_unset_env(var, value)
213
220
 
214
221
 
 
222
def _clear__type_equality_funcs(test):
 
223
    """Cleanup bound methods stored on TestCase instances
 
224
 
 
225
    Clear the dict breaking a few (mostly) harmless cycles in the affected
 
226
    unittests released with Python 2.6 and initial Python 2.7 versions.
 
227
 
 
228
    For a few revisions between Python 2.7.1 and Python 2.7.2 that annoyingly
 
229
    shipped in Oneiric, an object with no clear method was used, hence the
 
230
    extra complications, see bug 809048 for details.
 
231
    """
 
232
    type_equality_funcs = getattr(test, "_type_equality_funcs", None)
 
233
    if type_equality_funcs is not None:
 
234
        tef_clear = getattr(type_equality_funcs, "clear", None)
 
235
        if tef_clear is None:
 
236
            tef_instance_dict = getattr(type_equality_funcs, "__dict__", None)
 
237
            if tef_instance_dict is not None:
 
238
                tef_clear = tef_instance_dict.clear
 
239
        if tef_clear is not None:
 
240
            tef_clear()
 
241
 
 
242
 
215
243
class ExtendedTestResult(testtools.TextTestResult):
216
244
    """Accepts, reports and accumulates the results of running tests.
217
245
 
221
249
    different types of display.
222
250
 
223
251
    When a test finishes, in whatever way, it calls one of the addSuccess,
224
 
    addFailure or addError classes.  These in turn may redirect to a more
 
252
    addFailure or addError methods.  These in turn may redirect to a more
225
253
    specific case for the special test results supported by our extended
226
254
    tests.
227
255
 
332
360
            return float(''.join(details['benchtime'].iter_bytes()))
333
361
        return getattr(testCase, "_benchtime", None)
334
362
 
 
363
    def _delta_to_float(self, a_timedelta, precision):
 
364
        # This calls ceiling to ensure that the most pessimistic view of time
 
365
        # taken is shown (rather than leaving it to the Python %f operator
 
366
        # to decide whether to round/floor/ceiling. This was added when we
 
367
        # had pyp3 test failures that suggest a floor was happening.
 
368
        shift = 10 ** precision
 
369
        return math.ceil((a_timedelta.days * 86400.0 + a_timedelta.seconds +
 
370
            a_timedelta.microseconds / 1000000.0) * shift) / shift
 
371
 
335
372
    def _elapsedTestTimeString(self):
336
373
        """Return a time string for the overall time the current test has taken."""
337
374
        return self._formatTime(self._delta_to_float(
338
 
            self._now() - self._start_datetime))
 
375
            self._now() - self._start_datetime, 3))
339
376
 
340
377
    def _testTimeString(self, testCase):
341
378
        benchmark_time = self._extractBenchmarkTime(testCase)
385
422
        getDetails = getattr(test, "getDetails", None)
386
423
        if getDetails is not None:
387
424
            getDetails().clear()
388
 
        # Clear _type_equality_funcs to try to stop TestCase instances
389
 
        # from wasting memory. 'clear' is not available in all Python
390
 
        # versions (bug 809048)
391
 
        type_equality_funcs = getattr(test, "_type_equality_funcs", None)
392
 
        if type_equality_funcs is not None:
393
 
            tef_clear = getattr(type_equality_funcs, "clear", None)
394
 
            if tef_clear is None:
395
 
                tef_instance_dict = getattr(type_equality_funcs, "__dict__", None)
396
 
                if tef_instance_dict is not None:
397
 
                    tef_clear = tef_instance_dict.clear
398
 
            if tef_clear is not None:
399
 
                tef_clear()
 
425
        _clear__type_equality_funcs(test)
400
426
        self._traceback_from_test = None
401
427
 
402
428
    def startTests(self):
503
529
        self.not_applicable_count += 1
504
530
        self.report_not_applicable(test, reason)
505
531
 
 
532
    def _count_stored_tests(self):
 
533
        """Count of tests instances kept alive due to not succeeding"""
 
534
        return self.error_count + self.failure_count + self.known_failure_count
 
535
 
506
536
    def _post_mortem(self, tb=None):
507
537
        """Start a PDB post mortem session."""
508
538
        if os.environ.get('BZR_TEST_PDB', None):
980
1010
 
981
1011
    def setUp(self):
982
1012
        super(TestCase, self).setUp()
 
1013
 
 
1014
        # At this point we're still accessing the config files in $BZR_HOME (as
 
1015
        # set by the user running selftest).
 
1016
        timeout = config.GlobalStack().get('selftest.timeout')
 
1017
        if timeout:
 
1018
            timeout_fixture = fixtures.TimeoutFixture(timeout)
 
1019
            timeout_fixture.setUp()
 
1020
            self.addCleanup(timeout_fixture.cleanUp)
 
1021
 
983
1022
        for feature in getattr(self, '_test_needs_features', []):
984
1023
            self.requireFeature(feature)
985
1024
        self._cleanEnvironment()
 
1025
 
 
1026
        if bzrlib.global_state is not None:
 
1027
            self.overrideAttr(bzrlib.global_state, 'cmdline_overrides',
 
1028
                              config.CommandLineStore())
 
1029
 
986
1030
        self._silenceUI()
987
1031
        self._startLogFile()
988
1032
        self._benchcalls = []
995
1039
        # between tests.  We should get rid of this altogether: bug 656694. --
996
1040
        # mbp 20101008
997
1041
        self.overrideAttr(bzrlib.trace, '_verbosity_level', 0)
998
 
        # Isolate config option expansion until its default value for bzrlib is
999
 
        # settled on or a the FIXME associated with _get_expand_default_value
1000
 
        # is addressed -- vila 20110219
1001
 
        self.overrideAttr(config, '_expand_default_value', None)
1002
1042
        self._log_files = set()
1003
1043
        # Each key in the ``_counters`` dict holds a value for a different
1004
1044
        # counter. When the test ends, addDetail() should be used to output the
1297
1337
        # hook into bzr dir opening. This leaves a small window of error for
1298
1338
        # transport tests, but they are well known, and we can improve on this
1299
1339
        # step.
1300
 
        bzrdir.BzrDir.hooks.install_named_hook("pre_open",
 
1340
        controldir.ControlDir.hooks.install_named_hook("pre_open",
1301
1341
            self._preopen_isolate_transport, "Check bzr directories are safe.")
1302
1342
 
1303
1343
    def _ndiff_strings(self, a, b):
1701
1741
        return result
1702
1742
 
1703
1743
    def _startLogFile(self):
1704
 
        """Send bzr and test log messages to a temporary file.
1705
 
 
1706
 
        The file is removed as the test is torn down.
1707
 
        """
 
1744
        """Setup a in-memory target for bzr and testcase log messages"""
1708
1745
        pseudo_log_file = StringIO()
1709
1746
        def _get_log_contents_for_weird_testtools_api():
1710
1747
            return [pseudo_log_file.getvalue().decode(
1717
1754
        self.addCleanup(self._finishLogFile)
1718
1755
 
1719
1756
    def _finishLogFile(self):
1720
 
        """Finished with the log file.
1721
 
 
1722
 
        Close the file and delete it.
1723
 
        """
 
1757
        """Flush and dereference the in-memory log for this testcase"""
1724
1758
        if trace._trace_file:
1725
1759
            # flush the log file, to get all content
1726
1760
            trace._trace_file.flush()
1727
1761
        trace.pop_log_file(self._log_memento)
 
1762
        # The logging module now tracks references for cleanup so discard ours
 
1763
        del self._log_memento
1728
1764
 
1729
1765
    def thisFailsStrictLockCheck(self):
1730
1766
        """It is known that this test would fail with -Dstrict_locks.
1754
1790
 
1755
1791
        :returns: The actual attr value.
1756
1792
        """
1757
 
        value = getattr(obj, attr_name)
1758
1793
        # The actual value is captured by the call below
1759
 
        self.addCleanup(setattr, obj, attr_name, value)
 
1794
        value = getattr(obj, attr_name, _unitialized_attr)
 
1795
        if value is _unitialized_attr:
 
1796
            # When the test completes, the attribute should not exist, but if
 
1797
            # we aren't setting a value, we don't need to do anything.
 
1798
            if new is not _unitialized_attr:
 
1799
                self.addCleanup(delattr, obj, attr_name)
 
1800
        else:
 
1801
            self.addCleanup(setattr, obj, attr_name, value)
1760
1802
        if new is not _unitialized_attr:
1761
1803
            setattr(obj, attr_name, new)
1762
1804
        return value
1965
2007
 
1966
2008
        self.log('run bzr: %r', args)
1967
2009
        # FIXME: don't call into logging here
1968
 
        handler = logging.StreamHandler(stderr)
1969
 
        handler.setLevel(logging.INFO)
 
2010
        handler = trace.EncodedStreamHandler(stderr, errors="replace",
 
2011
            level=logging.INFO)
1970
2012
        logger = logging.getLogger('')
1971
2013
        logger.addHandler(handler)
1972
2014
        old_ui_factory = ui.ui_factory
2160
2202
 
2161
2203
        if env_changes is None:
2162
2204
            env_changes = {}
 
2205
        # Because $HOME is set to a tempdir for the context of a test, modules
 
2206
        # installed in the user dir will not be found unless $PYTHONUSERBASE
 
2207
        # gets set to the computed directory of this parent process.
 
2208
        if site.USER_BASE is not None:
 
2209
            env_changes["PYTHONUSERBASE"] = site.USER_BASE
2163
2210
        old_env = {}
2164
2211
 
2165
2212
        def cleanup_environment():
2356
2403
        from bzrlib.smart import request
2357
2404
        request_handlers = request.request_handlers
2358
2405
        orig_method = request_handlers.get(verb)
 
2406
        orig_info = request_handlers.get_info(verb)
2359
2407
        request_handlers.remove(verb)
2360
 
        self.addCleanup(request_handlers.register, verb, orig_method)
 
2408
        self.addCleanup(request_handlers.register, verb, orig_method,
 
2409
            info=orig_info)
2361
2410
 
2362
2411
 
2363
2412
class CapturedCall(object):
2416
2465
        self.transport_readonly_server = None
2417
2466
        self.__vfs_server = None
2418
2467
 
 
2468
    def setUp(self):
 
2469
        super(TestCaseWithMemoryTransport, self).setUp()
 
2470
 
 
2471
        def _add_disconnect_cleanup(transport):
 
2472
            """Schedule disconnection of given transport at test cleanup
 
2473
 
 
2474
            This needs to happen for all connected transports or leaks occur.
 
2475
 
 
2476
            Note reconnections may mean we call disconnect multiple times per
 
2477
            transport which is suboptimal but seems harmless.
 
2478
            """
 
2479
            self.addCleanup(transport.disconnect)
 
2480
 
 
2481
        _mod_transport.Transport.hooks.install_named_hook('post_connect',
 
2482
            _add_disconnect_cleanup, None)
 
2483
 
 
2484
        self._make_test_root()
 
2485
        self.addCleanup(os.chdir, os.getcwdu())
 
2486
        self.makeAndChdirToTestDir()
 
2487
        self.overrideEnvironmentForTesting()
 
2488
        self.__readonly_server = None
 
2489
        self.__server = None
 
2490
        self.reduceLockdirTimeout()
 
2491
        # Each test may use its own config files even if the local config files
 
2492
        # don't actually exist. They'll rightly fail if they try to create them
 
2493
        # though.
 
2494
        self.overrideAttr(config, '_shared_stores', {})
 
2495
 
2419
2496
    def get_transport(self, relpath=None):
2420
2497
        """Return a writeable transport.
2421
2498
 
2570
2647
            # http://pad.lv/825027).
2571
2648
            self.assertIs(None, os.environ.get('BZR_HOME', None))
2572
2649
            os.environ['BZR_HOME'] = root
2573
 
            wt = bzrdir.BzrDir.create_standalone_workingtree(root)
 
2650
            wt = controldir.ControlDir.create_standalone_workingtree(root)
2574
2651
            del os.environ['BZR_HOME']
2575
2652
        except Exception, e:
2576
 
            self.fail("Fail to initialize the safety net: %r\nExiting\n" % (e,))
 
2653
            self.fail("Fail to initialize the safety net: %r\n" % (e,))
2577
2654
        # Hack for speed: remember the raw bytes of the dirstate file so that
2578
2655
        # we don't need to re-open the wt to check it hasn't changed.
2579
2656
        TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE = (
2627
2704
        self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
2628
2705
        self.permit_dir(self.test_dir)
2629
2706
 
2630
 
    def make_branch(self, relpath, format=None):
 
2707
    def make_branch(self, relpath, format=None, name=None):
2631
2708
        """Create a branch on the transport at relpath."""
2632
2709
        repo = self.make_repository(relpath, format=format)
2633
 
        return repo.bzrdir.create_branch(append_revisions_only=False)
2634
 
 
2635
 
    def resolve_format(self, format):
2636
 
        """Resolve an object to a ControlDir format object.
2637
 
 
2638
 
        The initial format object can either already be
2639
 
        a ControlDirFormat, None (for the default format),
2640
 
        or a string with the name of the control dir format.
2641
 
 
2642
 
        :param format: Object to resolve
2643
 
        :return A ControlDirFormat instance
2644
 
        """
2645
 
        if format is None:
2646
 
            format = 'default'
2647
 
        if isinstance(format, basestring):
2648
 
            format = bzrdir.format_registry.make_bzrdir(format)
2649
 
        return format
2650
 
 
2651
 
    def resolve_format(self, format):
2652
 
        """Resolve an object to a ControlDir format object.
2653
 
 
2654
 
        The initial format object can either already be
2655
 
        a ControlDirFormat, None (for the default format),
2656
 
        or a string with the name of the control dir format.
2657
 
 
2658
 
        :param format: Object to resolve
2659
 
        :return A ControlDirFormat instance
2660
 
        """
2661
 
        if format is None:
2662
 
            format = 'default'
2663
 
        if isinstance(format, basestring):
2664
 
            format = bzrdir.format_registry.make_bzrdir(format)
 
2710
        return repo.bzrdir.create_branch(append_revisions_only=False,
 
2711
                                         name=name)
 
2712
 
 
2713
    def get_default_format(self):
 
2714
        return 'default'
 
2715
 
 
2716
    def resolve_format(self, format):
 
2717
        """Resolve an object to a ControlDir format object.
 
2718
 
 
2719
        The initial format object can either already be
 
2720
        a ControlDirFormat, None (for the default format),
 
2721
        or a string with the name of the control dir format.
 
2722
 
 
2723
        :param format: Object to resolve
 
2724
        :return A ControlDirFormat instance
 
2725
        """
 
2726
        if format is None:
 
2727
            format = self.get_default_format()
 
2728
        if isinstance(format, basestring):
 
2729
            format = controldir.format_registry.make_bzrdir(format)
2665
2730
        return format
2666
2731
 
2667
2732
    def make_bzrdir(self, relpath, format=None):
2714
2779
        self.overrideEnv('HOME', test_home_dir)
2715
2780
        self.overrideEnv('BZR_HOME', test_home_dir)
2716
2781
 
2717
 
    def setUp(self):
2718
 
        super(TestCaseWithMemoryTransport, self).setUp()
2719
 
        # Ensure that ConnectedTransport doesn't leak sockets
2720
 
        def get_transport_from_url_with_cleanup(*args, **kwargs):
2721
 
            t = orig_get_transport_from_url(*args, **kwargs)
2722
 
            if isinstance(t, _mod_transport.ConnectedTransport):
2723
 
                self.addCleanup(t.disconnect)
2724
 
            return t
2725
 
 
2726
 
        orig_get_transport_from_url = self.overrideAttr(
2727
 
            _mod_transport, 'get_transport_from_url',
2728
 
            get_transport_from_url_with_cleanup)
2729
 
        self._make_test_root()
2730
 
        self.addCleanup(os.chdir, os.getcwdu())
2731
 
        self.makeAndChdirToTestDir()
2732
 
        self.overrideEnvironmentForTesting()
2733
 
        self.__readonly_server = None
2734
 
        self.__server = None
2735
 
        self.reduceLockdirTimeout()
2736
 
 
2737
2782
    def setup_smart_server_with_call_log(self):
2738
2783
        """Sets up a smart server as the transport server with a call log."""
2739
2784
        self.transport_server = test_server.SmartTCPServer_for_testing
 
2785
        self.hpss_connections = []
2740
2786
        self.hpss_calls = []
2741
2787
        import traceback
2742
2788
        # Skip the current stack down to the caller of
2745
2791
        def capture_hpss_call(params):
2746
2792
            self.hpss_calls.append(
2747
2793
                CapturedCall(params, prefix_length))
 
2794
        def capture_connect(transport):
 
2795
            self.hpss_connections.append(transport)
2748
2796
        client._SmartClient.hooks.install_named_hook(
2749
2797
            'call', capture_hpss_call, None)
 
2798
        _mod_transport.Transport.hooks.install_named_hook(
 
2799
            'post_connect', capture_connect, None)
2750
2800
 
2751
2801
    def reset_smart_call_log(self):
2752
2802
        self.hpss_calls = []
 
2803
        self.hpss_connections = []
2753
2804
 
2754
2805
 
2755
2806
class TestCaseInTempDir(TestCaseWithMemoryTransport):
2825
2876
        # stacking policy to honour; create a bzr dir with an unshared
2826
2877
        # repository (but not a branch - our code would be trying to escape
2827
2878
        # then!) to stop them, and permit it to be read.
2828
 
        # control = bzrdir.BzrDir.create(self.test_base_dir)
 
2879
        # control = controldir.ControlDir.create(self.test_base_dir)
2829
2880
        # control.create_repository()
2830
2881
        self.test_home_dir = self.test_base_dir + '/home'
2831
2882
        os.mkdir(self.test_home_dir)
2920
2971
    readwrite one must both define get_url() as resolving to os.getcwd().
2921
2972
    """
2922
2973
 
 
2974
    def setUp(self):
 
2975
        super(TestCaseWithTransport, self).setUp()
 
2976
        self.__vfs_server = None
 
2977
 
2923
2978
    def get_vfs_only_server(self):
2924
2979
        """See TestCaseWithMemoryTransport.
2925
2980
 
2957
3012
        # this obviously requires a format that supports branch references
2958
3013
        # so check for that by checking bzrdir.BzrDirFormat.get_default_format()
2959
3014
        # RBC 20060208
 
3015
        format = self.resolve_format(format=format)
 
3016
        if not format.supports_workingtrees:
 
3017
            b = self.make_branch(relpath+'.branch', format=format)
 
3018
            return b.create_checkout(relpath, lightweight=True)
2960
3019
        b = self.make_branch(relpath, format=format)
2961
3020
        try:
2962
3021
            return b.bzrdir.create_workingtree()
2967
3026
            if self.vfs_transport_factory is test_server.LocalURLServer:
2968
3027
                # the branch is colocated on disk, we cannot create a checkout.
2969
3028
                # hopefully callers will expect this.
2970
 
                local_controldir= bzrdir.BzrDir.open(self.get_vfs_only_url(relpath))
 
3029
                local_controldir = controldir.ControlDir.open(
 
3030
                    self.get_vfs_only_url(relpath))
2971
3031
                wt = local_controldir.create_workingtree()
2972
3032
                if wt.branch._format != b._format:
2973
3033
                    wt._branch = b
3003
3063
        self.assertFalse(differences.has_changed(),
3004
3064
            "Trees %r and %r are different: %r" % (left, right, differences))
3005
3065
 
3006
 
    def setUp(self):
3007
 
        super(TestCaseWithTransport, self).setUp()
3008
 
        self.__vfs_server = None
3009
 
 
3010
3066
    def disable_missing_extensions_warning(self):
3011
3067
        """Some tests expect a precise stderr content.
3012
3068
 
3013
3069
        There is no point in forcing them to duplicate the extension related
3014
3070
        warning.
3015
3071
        """
3016
 
        config.GlobalConfig().set_user_option('ignore_missing_extensions', True)
 
3072
        config.GlobalStack().set('ignore_missing_extensions', True)
3017
3073
 
3018
3074
 
3019
3075
class ChrootedTestCase(TestCaseWithTransport):
3261
3317
                            result_decorators=result_decorators,
3262
3318
                            )
3263
3319
    runner.stop_on_failure=stop_on_failure
 
3320
    if isinstance(suite, unittest.TestSuite):
 
3321
        # Empty out _tests list of passed suite and populate new TestSuite
 
3322
        suite._tests[:], suite = [], TestSuite(suite)
3264
3323
    # built in decorator factories:
3265
3324
    decorators = [
3266
3325
        random_order(random_seed, runner),
3364
3423
 
3365
3424
class TestDecorator(TestUtil.TestSuite):
3366
3425
    """A decorator for TestCase/TestSuite objects.
3367
 
    
3368
 
    Usually, subclasses should override __iter__(used when flattening test
3369
 
    suites), which we do to filter, reorder, parallelise and so on, run() and
3370
 
    debug().
 
3426
 
 
3427
    Contains rather than flattening suite passed on construction
3371
3428
    """
3372
3429
 
3373
 
    def __init__(self, suite):
3374
 
        TestUtil.TestSuite.__init__(self)
3375
 
        self.addTest(suite)
3376
 
 
3377
 
    def countTestCases(self):
3378
 
        cases = 0
3379
 
        for test in self:
3380
 
            cases += test.countTestCases()
3381
 
        return cases
3382
 
 
3383
 
    def debug(self):
3384
 
        for test in self:
3385
 
            test.debug()
3386
 
 
3387
 
    def run(self, result):
3388
 
        # Use iteration on self, not self._tests, to allow subclasses to hook
3389
 
        # into __iter__.
3390
 
        for test in self:
3391
 
            if result.shouldStop:
3392
 
                break
3393
 
            test.run(result)
3394
 
        return result
 
3430
    def __init__(self, suite=None):
 
3431
        super(TestDecorator, self).__init__()
 
3432
        if suite is not None:
 
3433
            self.addTest(suite)
 
3434
 
 
3435
    # Don't need subclass run method with suite emptying
 
3436
    run = unittest.TestSuite.run
3395
3437
 
3396
3438
 
3397
3439
class CountingDecorator(TestDecorator):
3408
3450
    """A decorator which excludes test matching an exclude pattern."""
3409
3451
 
3410
3452
    def __init__(self, suite, exclude_pattern):
3411
 
        TestDecorator.__init__(self, suite)
3412
 
        self.exclude_pattern = exclude_pattern
3413
 
        self.excluded = False
3414
 
 
3415
 
    def __iter__(self):
3416
 
        if self.excluded:
3417
 
            return iter(self._tests)
3418
 
        self.excluded = True
3419
 
        suite = exclude_tests_by_re(self, self.exclude_pattern)
3420
 
        del self._tests[:]
3421
 
        self.addTests(suite)
3422
 
        return iter(self._tests)
 
3453
        super(ExcludeDecorator, self).__init__(
 
3454
            exclude_tests_by_re(suite, exclude_pattern))
3423
3455
 
3424
3456
 
3425
3457
class FilterTestsDecorator(TestDecorator):
3426
3458
    """A decorator which filters tests to those matching a pattern."""
3427
3459
 
3428
3460
    def __init__(self, suite, pattern):
3429
 
        TestDecorator.__init__(self, suite)
3430
 
        self.pattern = pattern
3431
 
        self.filtered = False
3432
 
 
3433
 
    def __iter__(self):
3434
 
        if self.filtered:
3435
 
            return iter(self._tests)
3436
 
        self.filtered = True
3437
 
        suite = filter_suite_by_re(self, self.pattern)
3438
 
        del self._tests[:]
3439
 
        self.addTests(suite)
3440
 
        return iter(self._tests)
 
3461
        super(FilterTestsDecorator, self).__init__(
 
3462
            filter_suite_by_re(suite, pattern))
3441
3463
 
3442
3464
 
3443
3465
class RandomDecorator(TestDecorator):
3444
3466
    """A decorator which randomises the order of its tests."""
3445
3467
 
3446
3468
    def __init__(self, suite, random_seed, stream):
3447
 
        TestDecorator.__init__(self, suite)
3448
 
        self.random_seed = random_seed
3449
 
        self.randomised = False
3450
 
        self.stream = stream
3451
 
 
3452
 
    def __iter__(self):
3453
 
        if self.randomised:
3454
 
            return iter(self._tests)
3455
 
        self.randomised = True
3456
 
        self.stream.write("Randomizing test order using seed %s\n\n" %
3457
 
            (self.actual_seed()))
 
3469
        random_seed = self.actual_seed(random_seed)
 
3470
        stream.write("Randomizing test order using seed %s\n\n" %
 
3471
            (random_seed,))
3458
3472
        # Initialise the random number generator.
3459
 
        random.seed(self.actual_seed())
3460
 
        suite = randomize_suite(self)
3461
 
        del self._tests[:]
3462
 
        self.addTests(suite)
3463
 
        return iter(self._tests)
 
3473
        random.seed(random_seed)
 
3474
        super(RandomDecorator, self).__init__(randomize_suite(suite))
3464
3475
 
3465
 
    def actual_seed(self):
3466
 
        if self.random_seed == "now":
 
3476
    @staticmethod
 
3477
    def actual_seed(seed):
 
3478
        if seed == "now":
3467
3479
            # We convert the seed to a long to make it reuseable across
3468
3480
            # invocations (because the user can reenter it).
3469
 
            self.random_seed = long(time.time())
 
3481
            return long(time.time())
3470
3482
        else:
3471
3483
            # Convert the seed to a long if we can
3472
3484
            try:
3473
 
                self.random_seed = long(self.random_seed)
3474
 
            except:
 
3485
                return long(seed)
 
3486
            except (TypeError, ValueError):
3475
3487
                pass
3476
 
        return self.random_seed
 
3488
        return seed
3477
3489
 
3478
3490
 
3479
3491
class TestFirstDecorator(TestDecorator):
3480
3492
    """A decorator which moves named tests to the front."""
3481
3493
 
3482
3494
    def __init__(self, suite, pattern):
3483
 
        TestDecorator.__init__(self, suite)
3484
 
        self.pattern = pattern
3485
 
        self.filtered = False
3486
 
 
3487
 
    def __iter__(self):
3488
 
        if self.filtered:
3489
 
            return iter(self._tests)
3490
 
        self.filtered = True
3491
 
        suites = split_suite_by_re(self, self.pattern)
3492
 
        del self._tests[:]
3493
 
        self.addTests(suites)
3494
 
        return iter(self._tests)
 
3495
        super(TestFirstDecorator, self).__init__()
 
3496
        self.addTests(split_suite_by_re(suite, pattern))
3495
3497
 
3496
3498
 
3497
3499
def partition_tests(suite, count):
3529
3531
    """
3530
3532
    concurrency = osutils.local_concurrency()
3531
3533
    result = []
3532
 
    from subunit import TestProtocolClient, ProtocolTestCase
 
3534
    from subunit import ProtocolTestCase
3533
3535
    from subunit.test_results import AutoTimingTestResultDecorator
3534
3536
    class TestInOtherProcess(ProtocolTestCase):
3535
3537
        # Should be in subunit, I think. RBC.
3541
3543
            try:
3542
3544
                ProtocolTestCase.run(self, result)
3543
3545
            finally:
3544
 
                os.waitpid(self.pid, 0)
 
3546
                pid, status = os.waitpid(self.pid, 0)
 
3547
            # GZ 2011-10-18: If status is nonzero, should report to the result
 
3548
            #                that something went wrong.
3545
3549
 
3546
3550
    test_blocks = partition_tests(suite, concurrency)
 
3551
    # Clear the tests from the original suite so it doesn't keep them alive
 
3552
    suite._tests[:] = []
3547
3553
    for process_tests in test_blocks:
3548
 
        process_suite = TestUtil.TestSuite()
3549
 
        process_suite.addTests(process_tests)
 
3554
        process_suite = TestUtil.TestSuite(process_tests)
 
3555
        # Also clear each split list so new suite has only reference
 
3556
        process_tests[:] = []
3550
3557
        c2pread, c2pwrite = os.pipe()
3551
3558
        pid = os.fork()
3552
3559
        if pid == 0:
3553
 
            workaround_zealous_crypto_random()
3554
3560
            try:
 
3561
                stream = os.fdopen(c2pwrite, 'wb', 1)
 
3562
                workaround_zealous_crypto_random()
3555
3563
                os.close(c2pread)
3556
3564
                # Leave stderr and stdout open so we can see test noise
3557
3565
                # Close stdin so that the child goes away if it decides to
3558
3566
                # read from stdin (otherwise its a roulette to see what
3559
3567
                # child actually gets keystrokes for pdb etc).
3560
3568
                sys.stdin.close()
3561
 
                sys.stdin = None
3562
 
                stream = os.fdopen(c2pwrite, 'wb', 1)
3563
3569
                subunit_result = AutoTimingTestResultDecorator(
3564
 
                    TestProtocolClient(stream))
 
3570
                    SubUnitBzrProtocolClient(stream))
3565
3571
                process_suite.run(subunit_result)
3566
 
            finally:
3567
 
                os._exit(0)
 
3572
            except:
 
3573
                # Try and report traceback on stream, but exit with error even
 
3574
                # if stream couldn't be created or something else goes wrong.
 
3575
                # The traceback is formatted to a string and written in one go
 
3576
                # to avoid interleaving lines from multiple failing children.
 
3577
                try:
 
3578
                    stream.write(traceback.format_exc())
 
3579
                finally:
 
3580
                    os._exit(1)
 
3581
            os._exit(0)
3568
3582
        else:
3569
3583
            os.close(c2pwrite)
3570
3584
            stream = os.fdopen(c2pread, 'rb', 1)
3676
3690
#                           with proper exclusion rules.
3677
3691
#   -Ethreads               Will display thread ident at creation/join time to
3678
3692
#                           help track thread leaks
3679
 
 
 
3693
#   -Euncollected_cases     Display the identity of any test cases that weren't
 
3694
#                           deallocated after being completed.
3680
3695
#   -Econfig_stats          Will collect statistics using addDetail
3681
3696
selftest_debug_flags = set()
3682
3697
 
3787
3802
 
3788
3803
    :return: (absents, duplicates) absents is a list containing the test found
3789
3804
        in id_list but not in test_suite, duplicates is a list containing the
3790
 
        test found multiple times in test_suite.
 
3805
        tests found multiple times in test_suite.
3791
3806
 
3792
3807
    When using a prefined test id list, it may occurs that some tests do not
3793
3808
    exist anymore or that some tests use the same id. This function warns the
3917
3932
        'bzrlib.doc',
3918
3933
        'bzrlib.tests.blackbox',
3919
3934
        'bzrlib.tests.commands',
3920
 
        'bzrlib.tests.doc_generate',
3921
3935
        'bzrlib.tests.per_branch',
3922
3936
        'bzrlib.tests.per_bzrdir',
3923
3937
        'bzrlib.tests.per_controldir',
4011
4025
        'bzrlib.tests.test_http',
4012
4026
        'bzrlib.tests.test_http_response',
4013
4027
        'bzrlib.tests.test_https_ca_bundle',
 
4028
        'bzrlib.tests.test_https_urllib',
4014
4029
        'bzrlib.tests.test_i18n',
4015
4030
        'bzrlib.tests.test_identitymap',
4016
4031
        'bzrlib.tests.test_ignores',
4065
4080
        'bzrlib.tests.test_revisiontree',
4066
4081
        'bzrlib.tests.test_rio',
4067
4082
        'bzrlib.tests.test_rules',
 
4083
        'bzrlib.tests.test_url_policy_open',
4068
4084
        'bzrlib.tests.test_sampler',
4069
4085
        'bzrlib.tests.test_scenarios',
4070
4086
        'bzrlib.tests.test_script',
4114
4130
        'bzrlib.tests.test_version',
4115
4131
        'bzrlib.tests.test_version_info',
4116
4132
        'bzrlib.tests.test_versionedfile',
 
4133
        'bzrlib.tests.test_vf_search',
4117
4134
        'bzrlib.tests.test_weave',
4118
4135
        'bzrlib.tests.test_whitebox',
4119
4136
        'bzrlib.tests.test_win32utils',
4334
4351
    """Copy test and apply scenario to it.
4335
4352
 
4336
4353
    :param test: A test to adapt.
4337
 
    :param scenario: A tuple describing the scenarion.
 
4354
    :param scenario: A tuple describing the scenario.
4338
4355
        The first element of the tuple is the new test id.
4339
4356
        The second element is a dict containing attributes to set on the
4340
4357
        test.
4480
4497
    from subunit.test_results import AutoTimingTestResultDecorator
4481
4498
    class SubUnitBzrProtocolClient(TestProtocolClient):
4482
4499
 
 
4500
        def stopTest(self, test):
 
4501
            super(SubUnitBzrProtocolClient, self).stopTest(test)
 
4502
            _clear__type_equality_funcs(test)
 
4503
 
4483
4504
        def addSuccess(self, test, details=None):
4484
4505
            # The subunit client always includes the details in the subunit
4485
4506
            # stream, but we don't want to include it in ours.
4498
4519
    pass
4499
4520
 
4500
4521
 
4501
 
@deprecated_function(deprecated_in((2, 5, 0)))
4502
 
def ModuleAvailableFeature(name):
4503
 
    from bzrlib.tests import features
4504
 
    return features.ModuleAvailableFeature(name)
4505
 
    
 
4522
# API compatibility for old plugins; see bug 892622.
 
4523
for name in [
 
4524
    'Feature',
 
4525
    'HTTPServerFeature', 
 
4526
    'ModuleAvailableFeature',
 
4527
    'HTTPSServerFeature', 'SymlinkFeature', 'HardlinkFeature',
 
4528
    'OsFifoFeature', 'UnicodeFilenameFeature',
 
4529
    'ByteStringNamedFilesystem', 'UTF8Filesystem',
 
4530
    'BreakinFeature', 'CaseInsCasePresFilenameFeature',
 
4531
    'CaseInsensitiveFilesystemFeature', 'case_sensitive_filesystem_feature',
 
4532
    'posix_permissions_feature',
 
4533
    ]:
 
4534
    globals()[name] = _CompatabilityThunkFeature(
 
4535
        symbol_versioning.deprecated_in((2, 5, 0)),
 
4536
        'bzrlib.tests', name,
 
4537
        name, 'bzrlib.tests.features')
 
4538
 
 
4539
 
 
4540
for (old_name, new_name) in [
 
4541
    ('UnicodeFilename', 'UnicodeFilenameFeature'),
 
4542
    ]:
 
4543
    globals()[name] = _CompatabilityThunkFeature(
 
4544
        symbol_versioning.deprecated_in((2, 5, 0)),
 
4545
        'bzrlib.tests', old_name,
 
4546
        new_name, 'bzrlib.tests.features')