~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Tarmac
  • Author(s): Vincent Ladeuil
  • Date: 2017-01-30 14:42:05 UTC
  • mfrom: (6620.1.1 trunk)
  • Revision ID: tarmac-20170130144205-r8fh2xpmiuxyozpv
Merge  2.7 into trunk including fix for bug #1657238 [r=vila]

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 Canonical Ltd
 
1
# Copyright (C) 2005-2013, 2015, 2016 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
16
16
 
17
17
"""Testing framework extensions"""
18
18
 
 
19
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):
1329
1369
            % (message,
1330
1370
               pprint.pformat(a), pprint.pformat(b)))
1331
1371
 
 
1372
    # FIXME: This is deprecated in unittest2 but plugins may still use it so we
 
1373
    # need a deprecation period for them -- vila 2016-02-01
1332
1374
    assertEquals = assertEqual
1333
1375
 
1334
1376
    def assertEqualDiff(self, a, b, message=None):
1337
1379
        This is intended for use with multi-line strings where it can
1338
1380
        be hard to find the differences by eye.
1339
1381
        """
1340
 
        # TODO: perhaps override assertEquals to call this for strings?
 
1382
        # TODO: perhaps override assertEqual to call this for strings?
1341
1383
        if a == b:
1342
1384
            return
1343
1385
        if message is None:
1701
1743
        return result
1702
1744
 
1703
1745
    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
 
        """
 
1746
        """Setup a in-memory target for bzr and testcase log messages"""
1708
1747
        pseudo_log_file = StringIO()
1709
1748
        def _get_log_contents_for_weird_testtools_api():
1710
1749
            return [pseudo_log_file.getvalue().decode(
1717
1756
        self.addCleanup(self._finishLogFile)
1718
1757
 
1719
1758
    def _finishLogFile(self):
1720
 
        """Finished with the log file.
1721
 
 
1722
 
        Close the file and delete it.
1723
 
        """
 
1759
        """Flush and dereference the in-memory log for this testcase"""
1724
1760
        if trace._trace_file:
1725
1761
            # flush the log file, to get all content
1726
1762
            trace._trace_file.flush()
1727
1763
        trace.pop_log_file(self._log_memento)
 
1764
        # The logging module now tracks references for cleanup so discard ours
 
1765
        del self._log_memento
1728
1766
 
1729
1767
    def thisFailsStrictLockCheck(self):
1730
1768
        """It is known that this test would fail with -Dstrict_locks.
1754
1792
 
1755
1793
        :returns: The actual attr value.
1756
1794
        """
1757
 
        value = getattr(obj, attr_name)
1758
1795
        # The actual value is captured by the call below
1759
 
        self.addCleanup(setattr, obj, attr_name, value)
 
1796
        value = getattr(obj, attr_name, _unitialized_attr)
 
1797
        if value is _unitialized_attr:
 
1798
            # When the test completes, the attribute should not exist, but if
 
1799
            # we aren't setting a value, we don't need to do anything.
 
1800
            if new is not _unitialized_attr:
 
1801
                self.addCleanup(delattr, obj, attr_name)
 
1802
        else:
 
1803
            self.addCleanup(setattr, obj, attr_name, value)
1760
1804
        if new is not _unitialized_attr:
1761
1805
            setattr(obj, attr_name, new)
1762
1806
        return value
1965
2009
 
1966
2010
        self.log('run bzr: %r', args)
1967
2011
        # FIXME: don't call into logging here
1968
 
        handler = logging.StreamHandler(stderr)
1969
 
        handler.setLevel(logging.INFO)
 
2012
        handler = trace.EncodedStreamHandler(stderr, errors="replace",
 
2013
            level=logging.INFO)
1970
2014
        logger = logging.getLogger('')
1971
2015
        logger.addHandler(handler)
1972
2016
        old_ui_factory = ui.ui_factory
2008
2052
        if err:
2009
2053
            self.log('errors:\n%r', err)
2010
2054
        if retcode is not None:
2011
 
            self.assertEquals(retcode, result,
 
2055
            self.assertEqual(retcode, result,
2012
2056
                              message='Unexpected return code')
2013
2057
        return result, out, err
2014
2058
 
2160
2204
 
2161
2205
        if env_changes is None:
2162
2206
            env_changes = {}
 
2207
        # Because $HOME is set to a tempdir for the context of a test, modules
 
2208
        # installed in the user dir will not be found unless $PYTHONUSERBASE
 
2209
        # gets set to the computed directory of this parent process.
 
2210
        if site.USER_BASE is not None:
 
2211
            env_changes["PYTHONUSERBASE"] = site.USER_BASE
2163
2212
        old_env = {}
2164
2213
 
2165
2214
        def cleanup_environment():
2356
2405
        from bzrlib.smart import request
2357
2406
        request_handlers = request.request_handlers
2358
2407
        orig_method = request_handlers.get(verb)
 
2408
        orig_info = request_handlers.get_info(verb)
2359
2409
        request_handlers.remove(verb)
2360
 
        self.addCleanup(request_handlers.register, verb, orig_method)
 
2410
        self.addCleanup(request_handlers.register, verb, orig_method,
 
2411
            info=orig_info)
2361
2412
 
2362
2413
 
2363
2414
class CapturedCall(object):
2416
2467
        self.transport_readonly_server = None
2417
2468
        self.__vfs_server = None
2418
2469
 
 
2470
    def setUp(self):
 
2471
        super(TestCaseWithMemoryTransport, self).setUp()
 
2472
 
 
2473
        def _add_disconnect_cleanup(transport):
 
2474
            """Schedule disconnection of given transport at test cleanup
 
2475
 
 
2476
            This needs to happen for all connected transports or leaks occur.
 
2477
 
 
2478
            Note reconnections may mean we call disconnect multiple times per
 
2479
            transport which is suboptimal but seems harmless.
 
2480
            """
 
2481
            self.addCleanup(transport.disconnect)
 
2482
 
 
2483
        _mod_transport.Transport.hooks.install_named_hook('post_connect',
 
2484
            _add_disconnect_cleanup, None)
 
2485
 
 
2486
        self._make_test_root()
 
2487
        self.addCleanup(os.chdir, os.getcwdu())
 
2488
        self.makeAndChdirToTestDir()
 
2489
        self.overrideEnvironmentForTesting()
 
2490
        self.__readonly_server = None
 
2491
        self.__server = None
 
2492
        self.reduceLockdirTimeout()
 
2493
        # Each test may use its own config files even if the local config files
 
2494
        # don't actually exist. They'll rightly fail if they try to create them
 
2495
        # though.
 
2496
        self.overrideAttr(config, '_shared_stores', {})
 
2497
 
2419
2498
    def get_transport(self, relpath=None):
2420
2499
        """Return a writeable transport.
2421
2500
 
2570
2649
            # http://pad.lv/825027).
2571
2650
            self.assertIs(None, os.environ.get('BZR_HOME', None))
2572
2651
            os.environ['BZR_HOME'] = root
2573
 
            wt = bzrdir.BzrDir.create_standalone_workingtree(root)
 
2652
            wt = controldir.ControlDir.create_standalone_workingtree(root)
2574
2653
            del os.environ['BZR_HOME']
2575
2654
        except Exception, e:
2576
 
            self.fail("Fail to initialize the safety net: %r\nExiting\n" % (e,))
 
2655
            self.fail("Fail to initialize the safety net: %r\n" % (e,))
2577
2656
        # Hack for speed: remember the raw bytes of the dirstate file so that
2578
2657
        # we don't need to re-open the wt to check it hasn't changed.
2579
2658
        TestCaseWithMemoryTransport._SAFETY_NET_PRISTINE_DIRSTATE = (
2627
2706
        self.test_home_dir = self.test_dir + "/MemoryTransportMissingHomeDir"
2628
2707
        self.permit_dir(self.test_dir)
2629
2708
 
2630
 
    def make_branch(self, relpath, format=None):
 
2709
    def make_branch(self, relpath, format=None, name=None):
2631
2710
        """Create a branch on the transport at relpath."""
2632
2711
        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)
 
2712
        return repo.bzrdir.create_branch(append_revisions_only=False,
 
2713
                                         name=name)
 
2714
 
 
2715
    def get_default_format(self):
 
2716
        return 'default'
 
2717
 
 
2718
    def resolve_format(self, format):
 
2719
        """Resolve an object to a ControlDir format object.
 
2720
 
 
2721
        The initial format object can either already be
 
2722
        a ControlDirFormat, None (for the default format),
 
2723
        or a string with the name of the control dir format.
 
2724
 
 
2725
        :param format: Object to resolve
 
2726
        :return A ControlDirFormat instance
 
2727
        """
 
2728
        if format is None:
 
2729
            format = self.get_default_format()
 
2730
        if isinstance(format, basestring):
 
2731
            format = controldir.format_registry.make_bzrdir(format)
2665
2732
        return format
2666
2733
 
2667
2734
    def make_bzrdir(self, relpath, format=None):
2714
2781
        self.overrideEnv('HOME', test_home_dir)
2715
2782
        self.overrideEnv('BZR_HOME', test_home_dir)
2716
2783
 
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
2784
    def setup_smart_server_with_call_log(self):
2738
2785
        """Sets up a smart server as the transport server with a call log."""
2739
2786
        self.transport_server = test_server.SmartTCPServer_for_testing
 
2787
        self.hpss_connections = []
2740
2788
        self.hpss_calls = []
2741
2789
        import traceback
2742
2790
        # Skip the current stack down to the caller of
2745
2793
        def capture_hpss_call(params):
2746
2794
            self.hpss_calls.append(
2747
2795
                CapturedCall(params, prefix_length))
 
2796
        def capture_connect(transport):
 
2797
            self.hpss_connections.append(transport)
2748
2798
        client._SmartClient.hooks.install_named_hook(
2749
2799
            'call', capture_hpss_call, None)
 
2800
        _mod_transport.Transport.hooks.install_named_hook(
 
2801
            'post_connect', capture_connect, None)
2750
2802
 
2751
2803
    def reset_smart_call_log(self):
2752
2804
        self.hpss_calls = []
 
2805
        self.hpss_connections = []
2753
2806
 
2754
2807
 
2755
2808
class TestCaseInTempDir(TestCaseWithMemoryTransport):
2825
2878
        # stacking policy to honour; create a bzr dir with an unshared
2826
2879
        # repository (but not a branch - our code would be trying to escape
2827
2880
        # then!) to stop them, and permit it to be read.
2828
 
        # control = bzrdir.BzrDir.create(self.test_base_dir)
 
2881
        # control = controldir.ControlDir.create(self.test_base_dir)
2829
2882
        # control.create_repository()
2830
2883
        self.test_home_dir = self.test_base_dir + '/home'
2831
2884
        os.mkdir(self.test_home_dir)
2920
2973
    readwrite one must both define get_url() as resolving to os.getcwd().
2921
2974
    """
2922
2975
 
 
2976
    def setUp(self):
 
2977
        super(TestCaseWithTransport, self).setUp()
 
2978
        self.__vfs_server = None
 
2979
 
2923
2980
    def get_vfs_only_server(self):
2924
2981
        """See TestCaseWithMemoryTransport.
2925
2982
 
2957
3014
        # this obviously requires a format that supports branch references
2958
3015
        # so check for that by checking bzrdir.BzrDirFormat.get_default_format()
2959
3016
        # RBC 20060208
 
3017
        format = self.resolve_format(format=format)
 
3018
        if not format.supports_workingtrees:
 
3019
            b = self.make_branch(relpath+'.branch', format=format)
 
3020
            return b.create_checkout(relpath, lightweight=True)
2960
3021
        b = self.make_branch(relpath, format=format)
2961
3022
        try:
2962
3023
            return b.bzrdir.create_workingtree()
2967
3028
            if self.vfs_transport_factory is test_server.LocalURLServer:
2968
3029
                # the branch is colocated on disk, we cannot create a checkout.
2969
3030
                # hopefully callers will expect this.
2970
 
                local_controldir= bzrdir.BzrDir.open(self.get_vfs_only_url(relpath))
 
3031
                local_controldir = controldir.ControlDir.open(
 
3032
                    self.get_vfs_only_url(relpath))
2971
3033
                wt = local_controldir.create_workingtree()
2972
3034
                if wt.branch._format != b._format:
2973
3035
                    wt._branch = b
3003
3065
        self.assertFalse(differences.has_changed(),
3004
3066
            "Trees %r and %r are different: %r" % (left, right, differences))
3005
3067
 
3006
 
    def setUp(self):
3007
 
        super(TestCaseWithTransport, self).setUp()
3008
 
        self.__vfs_server = None
3009
 
 
3010
3068
    def disable_missing_extensions_warning(self):
3011
3069
        """Some tests expect a precise stderr content.
3012
3070
 
3013
3071
        There is no point in forcing them to duplicate the extension related
3014
3072
        warning.
3015
3073
        """
3016
 
        config.GlobalConfig().set_user_option('ignore_missing_extensions', True)
 
3074
        config.GlobalStack().set('ignore_missing_extensions', True)
3017
3075
 
3018
3076
 
3019
3077
class ChrootedTestCase(TestCaseWithTransport):
3261
3319
                            result_decorators=result_decorators,
3262
3320
                            )
3263
3321
    runner.stop_on_failure=stop_on_failure
 
3322
    if isinstance(suite, unittest.TestSuite):
 
3323
        # Empty out _tests list of passed suite and populate new TestSuite
 
3324
        suite._tests[:], suite = [], TestSuite(suite)
3264
3325
    # built in decorator factories:
3265
3326
    decorators = [
3266
3327
        random_order(random_seed, runner),
3364
3425
 
3365
3426
class TestDecorator(TestUtil.TestSuite):
3366
3427
    """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().
 
3428
 
 
3429
    Contains rather than flattening suite passed on construction
3371
3430
    """
3372
3431
 
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
 
3432
    def __init__(self, suite=None):
 
3433
        super(TestDecorator, self).__init__()
 
3434
        if suite is not None:
 
3435
            self.addTest(suite)
 
3436
 
 
3437
    # Don't need subclass run method with suite emptying
 
3438
    run = unittest.TestSuite.run
3395
3439
 
3396
3440
 
3397
3441
class CountingDecorator(TestDecorator):
3408
3452
    """A decorator which excludes test matching an exclude pattern."""
3409
3453
 
3410
3454
    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)
 
3455
        super(ExcludeDecorator, self).__init__(
 
3456
            exclude_tests_by_re(suite, exclude_pattern))
3423
3457
 
3424
3458
 
3425
3459
class FilterTestsDecorator(TestDecorator):
3426
3460
    """A decorator which filters tests to those matching a pattern."""
3427
3461
 
3428
3462
    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)
 
3463
        super(FilterTestsDecorator, self).__init__(
 
3464
            filter_suite_by_re(suite, pattern))
3441
3465
 
3442
3466
 
3443
3467
class RandomDecorator(TestDecorator):
3444
3468
    """A decorator which randomises the order of its tests."""
3445
3469
 
3446
3470
    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()))
 
3471
        random_seed = self.actual_seed(random_seed)
 
3472
        stream.write("Randomizing test order using seed %s\n\n" %
 
3473
            (random_seed,))
3458
3474
        # 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)
 
3475
        random.seed(random_seed)
 
3476
        super(RandomDecorator, self).__init__(randomize_suite(suite))
3464
3477
 
3465
 
    def actual_seed(self):
3466
 
        if self.random_seed == "now":
 
3478
    @staticmethod
 
3479
    def actual_seed(seed):
 
3480
        if seed == "now":
3467
3481
            # We convert the seed to a long to make it reuseable across
3468
3482
            # invocations (because the user can reenter it).
3469
 
            self.random_seed = long(time.time())
 
3483
            return long(time.time())
3470
3484
        else:
3471
3485
            # Convert the seed to a long if we can
3472
3486
            try:
3473
 
                self.random_seed = long(self.random_seed)
3474
 
            except:
 
3487
                return long(seed)
 
3488
            except (TypeError, ValueError):
3475
3489
                pass
3476
 
        return self.random_seed
 
3490
        return seed
3477
3491
 
3478
3492
 
3479
3493
class TestFirstDecorator(TestDecorator):
3480
3494
    """A decorator which moves named tests to the front."""
3481
3495
 
3482
3496
    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)
 
3497
        super(TestFirstDecorator, self).__init__()
 
3498
        self.addTests(split_suite_by_re(suite, pattern))
3495
3499
 
3496
3500
 
3497
3501
def partition_tests(suite, count):
3529
3533
    """
3530
3534
    concurrency = osutils.local_concurrency()
3531
3535
    result = []
3532
 
    from subunit import TestProtocolClient, ProtocolTestCase
 
3536
    from subunit import ProtocolTestCase
3533
3537
    from subunit.test_results import AutoTimingTestResultDecorator
3534
3538
    class TestInOtherProcess(ProtocolTestCase):
3535
3539
        # Should be in subunit, I think. RBC.
3541
3545
            try:
3542
3546
                ProtocolTestCase.run(self, result)
3543
3547
            finally:
3544
 
                os.waitpid(self.pid, 0)
 
3548
                pid, status = os.waitpid(self.pid, 0)
 
3549
            # GZ 2011-10-18: If status is nonzero, should report to the result
 
3550
            #                that something went wrong.
3545
3551
 
3546
3552
    test_blocks = partition_tests(suite, concurrency)
 
3553
    # Clear the tests from the original suite so it doesn't keep them alive
 
3554
    suite._tests[:] = []
3547
3555
    for process_tests in test_blocks:
3548
 
        process_suite = TestUtil.TestSuite()
3549
 
        process_suite.addTests(process_tests)
 
3556
        process_suite = TestUtil.TestSuite(process_tests)
 
3557
        # Also clear each split list so new suite has only reference
 
3558
        process_tests[:] = []
3550
3559
        c2pread, c2pwrite = os.pipe()
3551
3560
        pid = os.fork()
3552
3561
        if pid == 0:
3553
 
            workaround_zealous_crypto_random()
3554
3562
            try:
 
3563
                stream = os.fdopen(c2pwrite, 'wb', 1)
 
3564
                workaround_zealous_crypto_random()
3555
3565
                os.close(c2pread)
3556
3566
                # Leave stderr and stdout open so we can see test noise
3557
3567
                # Close stdin so that the child goes away if it decides to
3558
3568
                # read from stdin (otherwise its a roulette to see what
3559
3569
                # child actually gets keystrokes for pdb etc).
3560
3570
                sys.stdin.close()
3561
 
                sys.stdin = None
3562
 
                stream = os.fdopen(c2pwrite, 'wb', 1)
3563
3571
                subunit_result = AutoTimingTestResultDecorator(
3564
 
                    TestProtocolClient(stream))
 
3572
                    SubUnitBzrProtocolClient(stream))
3565
3573
                process_suite.run(subunit_result)
3566
 
            finally:
3567
 
                os._exit(0)
 
3574
            except:
 
3575
                # Try and report traceback on stream, but exit with error even
 
3576
                # if stream couldn't be created or something else goes wrong.
 
3577
                # The traceback is formatted to a string and written in one go
 
3578
                # to avoid interleaving lines from multiple failing children.
 
3579
                try:
 
3580
                    stream.write(traceback.format_exc())
 
3581
                finally:
 
3582
                    os._exit(1)
 
3583
            os._exit(0)
3568
3584
        else:
3569
3585
            os.close(c2pwrite)
3570
3586
            stream = os.fdopen(c2pread, 'rb', 1)
3676
3692
#                           with proper exclusion rules.
3677
3693
#   -Ethreads               Will display thread ident at creation/join time to
3678
3694
#                           help track thread leaks
3679
 
 
 
3695
#   -Euncollected_cases     Display the identity of any test cases that weren't
 
3696
#                           deallocated after being completed.
3680
3697
#   -Econfig_stats          Will collect statistics using addDetail
3681
3698
selftest_debug_flags = set()
3682
3699
 
3787
3804
 
3788
3805
    :return: (absents, duplicates) absents is a list containing the test found
3789
3806
        in id_list but not in test_suite, duplicates is a list containing the
3790
 
        test found multiple times in test_suite.
 
3807
        tests found multiple times in test_suite.
3791
3808
 
3792
3809
    When using a prefined test id list, it may occurs that some tests do not
3793
3810
    exist anymore or that some tests use the same id. This function warns the
3917
3934
        'bzrlib.doc',
3918
3935
        'bzrlib.tests.blackbox',
3919
3936
        'bzrlib.tests.commands',
3920
 
        'bzrlib.tests.doc_generate',
3921
3937
        'bzrlib.tests.per_branch',
3922
3938
        'bzrlib.tests.per_bzrdir',
3923
3939
        'bzrlib.tests.per_controldir',
4011
4027
        'bzrlib.tests.test_http',
4012
4028
        'bzrlib.tests.test_http_response',
4013
4029
        'bzrlib.tests.test_https_ca_bundle',
 
4030
        'bzrlib.tests.test_https_urllib',
4014
4031
        'bzrlib.tests.test_i18n',
4015
4032
        'bzrlib.tests.test_identitymap',
4016
4033
        'bzrlib.tests.test_ignores',
4065
4082
        'bzrlib.tests.test_revisiontree',
4066
4083
        'bzrlib.tests.test_rio',
4067
4084
        'bzrlib.tests.test_rules',
 
4085
        'bzrlib.tests.test_url_policy_open',
4068
4086
        'bzrlib.tests.test_sampler',
4069
4087
        'bzrlib.tests.test_scenarios',
4070
4088
        'bzrlib.tests.test_script',
4114
4132
        'bzrlib.tests.test_version',
4115
4133
        'bzrlib.tests.test_version_info',
4116
4134
        'bzrlib.tests.test_versionedfile',
 
4135
        'bzrlib.tests.test_vf_search',
4117
4136
        'bzrlib.tests.test_weave',
4118
4137
        'bzrlib.tests.test_whitebox',
4119
4138
        'bzrlib.tests.test_win32utils',
4334
4353
    """Copy test and apply scenario to it.
4335
4354
 
4336
4355
    :param test: A test to adapt.
4337
 
    :param scenario: A tuple describing the scenarion.
 
4356
    :param scenario: A tuple describing the scenario.
4338
4357
        The first element of the tuple is the new test id.
4339
4358
        The second element is a dict containing attributes to set on the
4340
4359
        test.
4480
4499
    from subunit.test_results import AutoTimingTestResultDecorator
4481
4500
    class SubUnitBzrProtocolClient(TestProtocolClient):
4482
4501
 
 
4502
        def stopTest(self, test):
 
4503
            super(SubUnitBzrProtocolClient, self).stopTest(test)
 
4504
            _clear__type_equality_funcs(test)
 
4505
 
4483
4506
        def addSuccess(self, test, details=None):
4484
4507
            # The subunit client always includes the details in the subunit
4485
4508
            # stream, but we don't want to include it in ours.
4498
4521
    pass
4499
4522
 
4500
4523
 
4501
 
@deprecated_function(deprecated_in((2, 5, 0)))
4502
 
def ModuleAvailableFeature(name):
4503
 
    from bzrlib.tests import features
4504
 
    return features.ModuleAvailableFeature(name)
4505
 
    
 
4524
# API compatibility for old plugins; see bug 892622.
 
4525
for name in [
 
4526
    'Feature',
 
4527
    'HTTPServerFeature', 
 
4528
    'ModuleAvailableFeature',
 
4529
    'HTTPSServerFeature', 'SymlinkFeature', 'HardlinkFeature',
 
4530
    'OsFifoFeature', 'UnicodeFilenameFeature',
 
4531
    'ByteStringNamedFilesystem', 'UTF8Filesystem',
 
4532
    'BreakinFeature', 'CaseInsCasePresFilenameFeature',
 
4533
    'CaseInsensitiveFilesystemFeature', 'case_sensitive_filesystem_feature',
 
4534
    'posix_permissions_feature',
 
4535
    ]:
 
4536
    globals()[name] = _CompatabilityThunkFeature(
 
4537
        symbol_versioning.deprecated_in((2, 5, 0)),
 
4538
        'bzrlib.tests', name,
 
4539
        name, 'bzrlib.tests.features')
 
4540
 
 
4541
 
 
4542
for (old_name, new_name) in [
 
4543
    ('UnicodeFilename', 'UnicodeFilenameFeature'),
 
4544
    ]:
 
4545
    globals()[name] = _CompatabilityThunkFeature(
 
4546
        symbol_versioning.deprecated_in((2, 5, 0)),
 
4547
        'bzrlib.tests', old_name,
 
4548
        new_name, 'bzrlib.tests.features')