~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_import_tariff.py

  • Committer: John Arbash Meinel
  • Author(s): Mark Hammond
  • Date: 2008-09-09 17:02:21 UTC
  • mto: This revision was merged to the branch mainline in revision 3697.
  • Revision ID: john@arbash-meinel.com-20080909170221-svim3jw2mrz0amp3
An updated transparent icon for bzr.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2010, 2011 Canonical Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
14
 
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
 
18
 
"""Tests for how many modules are loaded in executing various commands."""
19
 
 
20
 
import os
21
 
 
22
 
from testtools import content
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
 
 
32
 
from bzrlib.plugin import (
33
 
    are_plugins_disabled,
34
 
    )
35
 
 
36
 
from bzrlib.tests import (
37
 
    TestCaseWithTransport,
38
 
    )
39
 
 
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):
57
 
    """Check how many modules are loaded for some representative scenarios.
58
 
 
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.
68
 
    """
69
 
 
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.
79
 
 
80
 
        This is fairly expensive because we start a subprocess, so we aim to
81
 
        cover representative rather than exhaustive cases.
82
 
        """
83
 
        # We use PYTHON_VERBOSE rather than --profile-imports because in
84
 
        # experimentation the profile-imports output seems to not always show
85
 
        # the modules you'd expect; this can be debugged but python -v seems
86
 
        # more likely to always show everything.  And we use the environment
87
 
        # variable rather than 'python -v' in the hope it will work even if
88
 
        # 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
 
        """
105
 
        self.addDetail('subprocess_stderr',
106
 
            content.Content(content.ContentType("text", "plain"),
107
 
                lambda:[err]))
108
 
 
109
 
        bad_modules = []
110
 
        for module_name in forbidden_imports:
111
 
            if err.find("\nimport %s " % module_name) != -1:
112
 
                bad_modules.append(module_name)
113
 
 
114
 
        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)
129
 
        return out, err
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
 
 
148
 
    def test_import_tariffs_working(self):
149
 
        # check some guaranteed-true and false imports to be sure we're
150
 
        # measuring correctly
151
 
        self.make_branch_and_tree('.')
152
 
        self.run_command_check_imports(['st'],
153
 
            ['nonexistentmodulename', 'anothernonexistentmodule'])
154
 
        self.assertRaises(AssertionError,
155
 
            self.run_command_check_imports,
156
 
            ['st'],
157
 
            ['bzrlib.tree'])
158
 
 
159
 
    def test_simple_local(self):
160
 
        # 'st' in a default format working tree shouldn't need many modules
161
 
        self.make_branch_and_tree('.')
162
 
        self.run_command_check_imports(['st'], [
163
 
            'bzrlib.annotate',
164
 
            'bzrlib.atomicfile',
165
 
            'bzrlib.bugtracker',
166
 
            'bzrlib.bundle.commands',
167
 
            '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',
176
 
            'bzrlib.merge3',
177
 
            'bzrlib.merge_directive',
178
 
            'bzrlib.msgeditor',
179
 
            'bzrlib.patiencediff',
180
 
            'bzrlib.remote',
181
 
            'bzrlib.rules',
182
 
            'bzrlib.sign_my_commits',
183
 
            'bzrlib.smart',
184
 
            'bzrlib.smart.client',
185
 
            'bzrlib.smart.medium',
186
 
            'bzrlib.smart.server',
187
 
            'bzrlib.transform',
188
 
            'bzrlib.version_info_formats.format_rio',
189
 
            'bzrlib.xml_serializer',
190
 
            'bzrlib.xml8',
191
 
            'getpass',
192
 
            'kerberos',
193
 
            'ssl',
194
 
            'socket',
195
 
            'smtplib',
196
 
            'tarfile',
197
 
            'tempfile',
198
 
            'termios',
199
 
            'tty',
200
 
            'urllib',
201
 
            ] + old_format_modules)
202
 
        # TODO: similar test for repository-only operations, checking we avoid
203
 
        # loading wt-specific stuff
204
 
        #
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)