~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_import_tariff.py

  • Committer: Andrew Bennetts
  • Date: 2010-10-08 08:15:14 UTC
  • mto: This revision was merged to the branch mainline in revision 5498.
  • Revision ID: andrew.bennetts@canonical.com-20101008081514-dviqzrdfwyzsqbz2
Split NEWS into per-release doc/en/release-notes/bzr-*.txt

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2010, 2011 Canonical Ltd
 
1
# Copyright (C) 2010 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
 
 
22
20
from testtools import content
23
21
 
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
 
 
32
22
from bzrlib.plugin import (
33
23
    are_plugins_disabled,
34
24
    )
37
27
    TestCaseWithTransport,
38
28
    )
39
29
 
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):
 
30
 
 
31
class TestImportTariffs(TestCaseWithTransport):
 
32
 
57
33
    """Check how many modules are loaded for some representative scenarios.
58
34
 
59
35
    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.
68
36
    """
69
37
 
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.
 
38
    def run_command_check_imports(self, args, forbidden_imports):
 
39
        """Run bzr ARGS in a subprocess and check its imports.
79
40
 
80
41
        This is fairly expensive because we start a subprocess, so we aim to
81
42
        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.
82
46
        """
83
 
        # We use PYTHON_VERBOSE rather than --profile-imports because in
 
47
        # We use PYTHON_VERBOSE rather than --profile-importts because in
84
48
        # experimentation the profile-imports output seems to not always show
85
49
        # the modules you'd expect; this can be debugged but python -v seems
86
50
        # more likely to always show everything.  And we use the environment
87
51
        # variable rather than 'python -v' in the hope it will work even if
88
52
        # bzr is frozen and python is not explicitly specified. -- mbp 20100208
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
 
        """
 
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
 
105
66
        self.addDetail('subprocess_stderr',
106
67
            content.Content(content.ContentType("text", "plain"),
107
68
                lambda:[err]))
112
73
                bad_modules.append(module_name)
113
74
 
114
75
        if 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)
 
76
            self.fail("command %r loaded forbidden modules %r"
 
77
                % (args, bad_modules))
129
78
        return out, err
130
79
 
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
 
 
148
80
    def test_import_tariffs_working(self):
149
81
        # check some guaranteed-true and false imports to be sure we're
150
82
        # measuring correctly
157
89
            ['bzrlib.tree'])
158
90
 
159
91
    def test_simple_local(self):
160
 
        # 'st' in a default format working tree shouldn't need many modules
 
92
        # 'st' in a working tree shouldn't need many modules
161
93
        self.make_branch_and_tree('.')
162
94
        self.run_command_check_imports(['st'], [
163
 
            'bzrlib.annotate',
164
 
            'bzrlib.atomicfile',
165
 
            'bzrlib.bugtracker',
166
95
            'bzrlib.bundle.commands',
167
96
            'bzrlib.cmd_version_info',
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',
 
97
            'bzrlib.foreign',
176
98
            'bzrlib.merge3',
177
 
            'bzrlib.merge_directive',
178
 
            'bzrlib.msgeditor',
179
99
            'bzrlib.patiencediff',
180
100
            'bzrlib.remote',
181
 
            'bzrlib.rules',
182
101
            'bzrlib.sign_my_commits',
183
102
            'bzrlib.smart',
184
 
            'bzrlib.smart.client',
185
 
            'bzrlib.smart.medium',
186
 
            'bzrlib.smart.server',
187
103
            'bzrlib.transform',
188
 
            'bzrlib.version_info_formats.format_rio',
189
 
            'bzrlib.xml_serializer',
190
 
            'bzrlib.xml8',
191
 
            'getpass',
192
104
            'kerberos',
193
 
            'ssl',
194
 
            'socket',
195
105
            'smtplib',
196
106
            'tarfile',
197
 
            'tempfile',
198
 
            'termios',
199
 
            'tty',
200
 
            'urllib',
201
 
            ] + old_format_modules)
 
107
            ])
202
108
        # TODO: similar test for repository-only operations, checking we avoid
203
109
        # loading wt-specific stuff
204
110
        #
205
111
        # 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)