~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/__init__.py

  • Committer: Vincent Ladeuil
  • Date: 2011-06-27 15:42:09 UTC
  • mfrom: (5993 +trunk)
  • mto: (5993.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 5994.
  • Revision ID: v.ladeuil+lp@free.fr-20110627154209-azubuhbuxsz109hq
Merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
142
142
    'BZREMAIL': None, # may still be present in the environment
143
143
    'EMAIL': 'jrandom@example.com', # set EMAIL as bzr does not guess
144
144
    'BZR_PROGRESS_BAR': None,
145
 
    'BZR_LOG': 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',
146
149
    'BZR_PLUGIN_PATH': None,
147
150
    'BZR_DISABLE_PLUGINS': None,
148
151
    'BZR_PLUGINS_AT': None,
928
931
 
929
932
    The method is really a factory and users are expected to use it as such.
930
933
    """
931
 
    
 
934
 
932
935
    kwargs['setUp'] = isolated_doctest_setUp
933
936
    kwargs['tearDown'] = isolated_doctest_tearDown
934
937
    return doctest.DocTestSuite(*args, **kwargs)
988
991
        # settled on or a the FIXME associated with _get_expand_default_value
989
992
        # is addressed -- vila 20110219
990
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()
991
1001
 
992
1002
    def debug(self):
993
1003
        # debug a frame up.
1010
1020
        if name in details:
1011
1021
            del details[name]
1012
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,))
 
1066
 
1013
1067
    def _clear_debug_flags(self):
1014
1068
        """Prevent externally set debug flags affecting tests.
1015
1069
 
1069
1123
        # break some locks on purpose and should be taken into account by
1070
1124
        # considering that breaking a lock is just a dirty way of releasing it.
1071
1125
        if len(acquired_locks) != (len(released_locks) + len(broken_locks)):
1072
 
            message = ('Different number of acquired and '
1073
 
                       'released or broken locks. (%s, %s + %s)' %
1074
 
                       (acquired_locks, released_locks, 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))
1075
1133
            if not self._lock_check_thorough:
1076
1134
                # Rather than fail, just warn
1077
1135
                print "Broken test %s: %s" % (self, message)
1546
1604
        not other callers that go direct to the warning module.
1547
1605
 
1548
1606
        To test that a deprecated method raises an error, do something like
1549
 
        this::
 
1607
        this (remember that both assertRaises and applyDeprecated delays *args
 
1608
        and **kwargs passing)::
1550
1609
 
1551
1610
            self.assertRaises(errors.ReservedId,
1552
1611
                self.applyDeprecated,
1637
1696
        pseudo_log_file = StringIO()
1638
1697
        def _get_log_contents_for_weird_testtools_api():
1639
1698
            return [pseudo_log_file.getvalue().decode(
1640
 
                "utf-8", "replace").encode("utf-8")]          
 
1699
                "utf-8", "replace").encode("utf-8")]
1641
1700
        self.addDetail("log", content.Content(content.ContentType("text",
1642
1701
            "plain", {"charset": "utf8"}),
1643
1702
            _get_log_contents_for_weird_testtools_api))
1648
1707
    def _finishLogFile(self):
1649
1708
        """Finished with the log file.
1650
1709
 
1651
 
        Close the file and delete it, unless setKeepLogfile was called.
 
1710
        Close the file and delete it.
1652
1711
        """
1653
1712
        if trace._trace_file:
1654
1713
            # flush the log file, to get all content
2065
2124
            # so we will avoid using it on all platforms, just to
2066
2125
            # make sure the code path is used, and we don't break on win32
2067
2126
            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())
2068
2130
            command = [sys.executable]
2069
2131
            # frozen executables don't need the path to bzr
2070
2132
            if getattr(sys, "frozen", None) is None:
2082
2144
 
2083
2145
        return process
2084
2146
 
 
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
 
2085
2174
    def _popen(self, *args, **kwargs):
2086
2175
        """Place a call to Popen.
2087
2176
 
2239
2328
class TestCaseWithMemoryTransport(TestCase):
2240
2329
    """Common test class for tests that do not need disk resources.
2241
2330
 
2242
 
    Tests that need disk resources should derive from TestCaseWithTransport.
 
2331
    Tests that need disk resources should derive from TestCaseInTempDir
 
2332
    orTestCaseWithTransport.
2243
2333
 
2244
2334
    TestCaseWithMemoryTransport sets the TEST_ROOT variable for all bzr tests.
2245
2335
 
2246
 
    For TestCaseWithMemoryTransport the test_home_dir is set to the name of
 
2336
    For TestCaseWithMemoryTransport the ``test_home_dir`` is set to the name of
2247
2337
    a directory which does not exist. This serves to help ensure test isolation
2248
 
    is preserved. test_dir is set to the TEST_ROOT, as is cwd, because they
2249
 
    must exist. However, TestCaseWithMemoryTransport does not offer local
2250
 
    file defaults for the transport in tests, nor does it obey the command line
 
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
2251
2341
    override, so tests that accidentally write to the common directory should
2252
2342
    be rare.
2253
2343
 
2254
 
    :cvar TEST_ROOT: Directory containing all temporary directories, plus
2255
 
    a .bzr directory that stops us ascending higher into the filesystem.
 
2344
    :cvar TEST_ROOT: Directory containing all temporary directories, plus a
 
2345
        ``.bzr`` directory that stops us ascending higher into the filesystem.
2256
2346
    """
2257
2347
 
2258
2348
    TEST_ROOT = None
2582
2672
 
2583
2673
    OVERRIDE_PYTHON = 'python'
2584
2674
 
 
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
 
2585
2681
    def check_file_contents(self, filename, expect):
2586
2682
        self.log("check contents of file %s" % filename)
2587
2683
        f = file(filename)
3478
3574
#                           with proper exclusion rules.
3479
3575
#   -Ethreads               Will display thread ident at creation/join time to
3480
3576
#                           help track thread leaks
 
3577
 
 
3578
#   -Econfig_stats          Will collect statistics using addDetail
3481
3579
selftest_debug_flags = set()
3482
3580
 
3483
3581