~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_import_tariff.py

  • Committer: Patch Queue Manager
  • Date: 2016-04-21 04:10:52 UTC
  • mfrom: (6616.1.1 fix-en-user-guide)
  • Revision ID: pqm@pqm.ubuntu.com-20160421041052-clcye7ns1qcl2n7w
(richard-wilbur) Ensure build of English use guide always uses English text
 even when user's locale specifies a different language. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2010 Canonical Ltd
 
1
# Copyright (C) 2010, 2011 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
17
17
 
18
18
"""Tests for how many modules are loaded in executing various commands."""
19
19
 
 
20
import os
 
21
 
20
22
from testtools import content
21
23
 
 
24
from bzrlib import (
 
25
    plugins as _mod_plugins,
 
26
    trace,
 
27
    )
 
28
from bzrlib.controldir import ControlDir
 
29
from bzrlib.smart import medium
 
30
from bzrlib.transport import remote
 
31
 
22
32
from bzrlib.plugin import (
23
33
    are_plugins_disabled,
24
34
    )
27
37
    TestCaseWithTransport,
28
38
    )
29
39
 
30
 
 
31
 
class TestImportTariffs(TestCaseWithTransport):
32
 
 
 
40
old_format_modules = [
 
41
    'bzrlib.repofmt.knitrepo',
 
42
    'bzrlib.repofmt.knitpack_repo',
 
43
    'bzrlib.plugins.weave_fmt.branch',
 
44
    'bzrlib.plugins.weave_fmt.bzrdir',
 
45
    'bzrlib.plugins.weave_fmt.repository',
 
46
    'bzrlib.plugins.weave_fmt.workingtree',
 
47
    'bzrlib.weave',
 
48
    'bzrlib.weavefile',
 
49
    'bzrlib.xml4',
 
50
    'bzrlib.xml5',
 
51
    'bzrlib.xml6',
 
52
    'bzrlib.xml7',
 
53
    ]
 
54
 
 
55
 
 
56
class ImportTariffTestCase(TestCaseWithTransport):
33
57
    """Check how many modules are loaded for some representative scenarios.
34
58
 
35
59
    See the Testing Guide in the developer documentation for more explanation.
 
60
 
 
61
 
 
62
    We must respect the setup used by the selftest command regarding
 
63
    plugins. This allows the user to control which plugins are in effect while
 
64
    running these tests and respect the import policies defined here.
 
65
 
 
66
    When failures are encountered for a given plugin, they can generally be
 
67
    addressed by using lazy import or lazy hook registration.
36
68
    """
37
69
 
38
 
    def run_command_check_imports(self, args, forbidden_imports):
39
 
        """Run bzr ARGS in a subprocess and check its imports.
 
70
    def setUp(self):
 
71
        self.preserved_env_vars = {}
 
72
        for name in ('BZR_PLUGIN_PATH', 'BZR_DISABLE_PLUGINS', 'BZR_PLUGINS_AT'
 
73
                     ):
 
74
            self.preserved_env_vars[name] = os.environ.get(name)
 
75
        super(ImportTariffTestCase, self).setUp()
 
76
 
 
77
    def start_bzr_subprocess_with_import_check(self, args, stderr_file=None):
 
78
        """Run a bzr process and capture the imports.
40
79
 
41
80
        This is fairly expensive because we start a subprocess, so we aim to
42
81
        cover representative rather than exhaustive cases.
43
 
 
44
 
        :param forbidden_imports: List of fully-qualified Python module names
45
 
            that should not be loaded while running this command.
46
82
        """
47
 
        # We use PYTHON_VERBOSE rather than --profile-importts because in
 
83
        # We use PYTHON_VERBOSE rather than --profile-imports because in
48
84
        # experimentation the profile-imports output seems to not always show
49
85
        # the modules you'd expect; this can be debugged but python -v seems
50
86
        # more likely to always show everything.  And we use the environment
51
87
        # variable rather than 'python -v' in the hope it will work even if
52
88
        # bzr is frozen and python is not explicitly specified. -- mbp 20100208
53
 
        #
54
 
        # Normally we want test isolation from the real $HOME but here we
55
 
        # explicitly do want to test against things installed there, therefore
56
 
        # we pass it through.
57
 
        env_changes = dict(PYTHONVERBOSE='1')
58
 
        for name in ['BZR_HOME', 'BZR_PLUGIN_PATH',
59
 
                     'BZR_DISABLE_PLUGINS', 'BZR_PLUGINS_AT',
60
 
                     'HOME',]:
61
 
            env_changes[name] = self._old_env.get(name)
62
 
        out, err = self.run_bzr_subprocess(args,
63
 
            allow_plugins=(not are_plugins_disabled()),
64
 
            env_changes=env_changes)
65
 
 
 
89
        env_changes = dict(PYTHONVERBOSE='1', **self.preserved_env_vars)
 
90
        trace.mutter('Setting env for bzr subprocess: %r', env_changes)
 
91
        kwargs = dict(env_changes=env_changes,
 
92
                      allow_plugins=(not are_plugins_disabled()))
 
93
        if stderr_file:
 
94
            # We don't want to update the whole call chain so we insert stderr
 
95
            # *iff* we need to
 
96
            kwargs['stderr'] = stderr_file
 
97
        return self.start_bzr_subprocess(args, **kwargs)
 
98
 
 
99
    def check_forbidden_modules(self, err, forbidden_imports):
 
100
        """Check for forbidden modules in stderr.
 
101
 
 
102
        :param err: Standard error
 
103
        :param forbidden_imports: List of forbidden modules
 
104
        """
66
105
        self.addDetail('subprocess_stderr',
67
106
            content.Content(content.ContentType("text", "plain"),
68
107
                lambda:[err]))
73
112
                bad_modules.append(module_name)
74
113
 
75
114
        if bad_modules:
76
 
            self.fail("command %r loaded forbidden modules %r"
77
 
                % (args, bad_modules))
 
115
            self.fail("command loaded forbidden modules %r"
 
116
                % (bad_modules,))
 
117
 
 
118
    def finish_bzr_subprocess_with_import_check(self, process,
 
119
            args, forbidden_imports):
 
120
        """Finish subprocess and check specific modules have not been
 
121
        imported.
 
122
 
 
123
        :param forbidden_imports: List of fully-qualified Python module names
 
124
            that should not be loaded while running this command.
 
125
        """
 
126
        (out, err) = self.finish_bzr_subprocess(process,
 
127
            universal_newlines=False, process_args=args)
 
128
        self.check_forbidden_modules(err, forbidden_imports)
78
129
        return out, err
79
130
 
 
131
    def run_command_check_imports(self, args, forbidden_imports):
 
132
        """Run bzr ARGS in a subprocess and check its imports.
 
133
 
 
134
        This is fairly expensive because we start a subprocess, so we aim to
 
135
        cover representative rather than exhaustive cases.
 
136
 
 
137
        :param forbidden_imports: List of fully-qualified Python module names
 
138
            that should not be loaded while running this command.
 
139
        """
 
140
        process = self.start_bzr_subprocess_with_import_check(args)
 
141
        self.finish_bzr_subprocess_with_import_check(process, args,
 
142
            forbidden_imports)
 
143
 
 
144
 
 
145
class TestImportTariffs(ImportTariffTestCase):
 
146
    """Basic import tariff tests for some common bzr commands"""
 
147
 
80
148
    def test_import_tariffs_working(self):
81
149
        # check some guaranteed-true and false imports to be sure we're
82
150
        # measuring correctly
89
157
            ['bzrlib.tree'])
90
158
 
91
159
    def test_simple_local(self):
92
 
        # 'st' in a working tree shouldn't need many modules
 
160
        # 'st' in a default format working tree shouldn't need many modules
93
161
        self.make_branch_and_tree('.')
94
162
        self.run_command_check_imports(['st'], [
 
163
            'bzrlib.annotate',
 
164
            'bzrlib.atomicfile',
 
165
            'bzrlib.bugtracker',
95
166
            'bzrlib.bundle.commands',
96
167
            'bzrlib.cmd_version_info',
97
 
            'bzrlib.foreign',
 
168
            'bzrlib.externalcommand',
 
169
            'bzrlib.filters',
 
170
            'bzrlib.hashcache',
 
171
            # foreign branch plugins import the foreign_vcs_registry from 
 
172
            # bzrlib.foreign so it can't be blacklisted
 
173
            'bzrlib.gpg',
 
174
            'bzrlib.info',
 
175
            'bzrlib.knit',
98
176
            'bzrlib.merge3',
 
177
            'bzrlib.merge_directive',
 
178
            'bzrlib.msgeditor',
99
179
            'bzrlib.patiencediff',
100
180
            'bzrlib.remote',
 
181
            'bzrlib.rules',
101
182
            'bzrlib.sign_my_commits',
102
183
            'bzrlib.smart',
 
184
            'bzrlib.smart.client',
 
185
            'bzrlib.smart.medium',
 
186
            'bzrlib.smart.server',
103
187
            'bzrlib.transform',
 
188
            'bzrlib.version_info_formats.format_rio',
 
189
            'bzrlib.xml_serializer',
 
190
            'bzrlib.xml8',
 
191
            'getpass',
104
192
            'kerberos',
 
193
            'ssl',
 
194
            'socket',
105
195
            'smtplib',
106
196
            'tarfile',
107
 
            ])
 
197
            'tempfile',
 
198
            'termios',
 
199
            'tty',
 
200
            'urllib',
 
201
            ] + old_format_modules)
108
202
        # TODO: similar test for repository-only operations, checking we avoid
109
203
        # loading wt-specific stuff
110
204
        #
111
205
        # See https://bugs.launchpad.net/bzr/+bug/553017
 
206
 
 
207
    def test_help_commands(self):
 
208
        # See https://bugs.launchpad.net/bzr/+bug/663773
 
209
        self.run_command_check_imports(['help', 'commands'], [
 
210
            'testtools',
 
211
            ])
 
212
 
 
213
    def test_simple_serve(self):
 
214
        # 'serve' in a default format working tree shouldn't need many modules
 
215
        tree = self.make_branch_and_tree('.')
 
216
        # Capture the bzr serve process' stderr in a file to avoid deadlocks
 
217
        # while the smart client interacts with it.
 
218
        stderr_file = open('bzr-serve.stderr', 'w')
 
219
        process = self.start_bzr_subprocess_with_import_check(['serve',
 
220
            '--inet', '-d', tree.basedir], stderr_file=stderr_file)
 
221
        url = 'bzr://localhost/'
 
222
        self.permit_url(url)
 
223
        client_medium = medium.SmartSimplePipesClientMedium(
 
224
            process.stdout, process.stdin, url)
 
225
        transport = remote.RemoteTransport(url, medium=client_medium)
 
226
        branch = ControlDir.open_from_transport(transport).open_branch()
 
227
        process.stdin.close()
 
228
        # Hide stdin from the subprocess module, so it won't fail to close it.
 
229
        process.stdin = None
 
230
        (out, err) = self.finish_bzr_subprocess(process,
 
231
            universal_newlines=False)
 
232
        stderr_file.close()
 
233
        with open('bzr-serve.stderr', 'r') as stderr_file:
 
234
            err = stderr_file.read()
 
235
        self.check_forbidden_modules(err,
 
236
            ['bzrlib.annotate',
 
237
            'bzrlib.atomicfile',
 
238
            'bzrlib.bugtracker',
 
239
            'bzrlib.bundle.commands',
 
240
            'bzrlib.cmd_version_info',
 
241
            'bzrlib.dirstate',
 
242
            'bzrlib._dirstate_helpers_py',
 
243
            'bzrlib._dirstate_helpers_pyx',
 
244
            'bzrlib.externalcommand',
 
245
            'bzrlib.filters',
 
246
            'bzrlib.hashcache',
 
247
            # foreign branch plugins import the foreign_vcs_registry from 
 
248
            # bzrlib.foreign so it can't be blacklisted
 
249
            'bzrlib.gpg',
 
250
            'bzrlib.info',
 
251
            'bzrlib.knit',
 
252
            'bzrlib.merge3',
 
253
            'bzrlib.merge_directive',
 
254
            'bzrlib.msgeditor',
 
255
            'bzrlib.patiencediff',
 
256
            'bzrlib.remote',
 
257
            'bzrlib.rules',
 
258
            'bzrlib.sign_my_commits',
 
259
            'bzrlib.smart.client',
 
260
            'bzrlib.transform',
 
261
            'bzrlib.version_info_formats.format_rio',
 
262
            'bzrlib.workingtree_4',
 
263
            'bzrlib.xml_serializer',
 
264
            'bzrlib.xml8',
 
265
            'getpass',
 
266
            'kerberos',
 
267
            'smtplib',
 
268
            'tarfile',
 
269
            'tempfile',
 
270
            'termios',
 
271
            'tty',
 
272
            ] + old_format_modules)