/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_plugins.py

  • Committer: Jelmer Vernooij
  • Date: 2020-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2012, 2016 Canonical Ltd
 
2
# Copyright (C) 2017-2018 Breezy developers
2
3
#
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
16
17
 
17
18
"""Tests for plugins"""
18
19
 
19
 
# XXX: There are no plugin tests at the moment because the plugin module
20
 
# affects the global state of the process.  See bzrlib/plugins.py for more
21
 
# comments.
22
 
 
23
 
from cStringIO import StringIO
 
20
import importlib
24
21
import logging
25
22
import os
26
23
import sys
 
24
import types
27
25
 
28
 
import bzrlib
29
 
from bzrlib import (
 
26
import breezy
 
27
from .. import (
30
28
    osutils,
31
29
    plugin,
32
 
    plugins,
33
30
    tests,
34
 
    trace,
 
31
    )
 
32
from ..tests.features import pkg_resources_feature
 
33
from ..sixish import (
 
34
    StringIO,
 
35
    viewkeys,
35
36
    )
36
37
 
37
38
 
38
39
# TODO: Write a test for plugin decoration of commands.
39
40
 
40
 
class TestPluginMixin(object):
 
41
invalidate_caches = getattr(importlib, "invalidate_caches", lambda: None)
 
42
 
 
43
 
 
44
class BaseTestPlugins(tests.TestCaseInTempDir):
 
45
    """TestCase that isolates plugin imports and cleans up on completion."""
 
46
 
 
47
    def setUp(self):
 
48
        super(BaseTestPlugins, self).setUp()
 
49
        self.module_name = "breezy.testingplugins"
 
50
        self.module_prefix = self.module_name + "."
 
51
        self.module = types.ModuleType(self.module_name)
 
52
 
 
53
        self.overrideAttr(plugin, "_MODULE_PREFIX", self.module_prefix)
 
54
        self.overrideAttr(breezy, "testingplugins", self.module)
 
55
 
 
56
        sys.modules[self.module_name] = self.module
 
57
        self.addCleanup(self._unregister_all)
 
58
        self.addCleanup(self._unregister_finder)
 
59
 
 
60
        invalidate_caches()
 
61
 
 
62
    def reset(self):
 
63
        """Remove all global testing state and clean up module."""
 
64
        # GZ 2017-06-02: Ideally don't do this, write new test or generate
 
65
        # bytecode by other mechanism.
 
66
        self.log("resetting plugin testing context")
 
67
        self._unregister_all()
 
68
        self._unregister_finder()
 
69
        sys.modules[self.module_name] = self.module
 
70
        for name in list(self.module.__dict__):
 
71
            if name[:2] != '__':
 
72
                delattr(self.module, name)
 
73
        invalidate_caches()
 
74
        self.plugins = None
 
75
 
 
76
    def update_module_paths(self, paths):
 
77
        paths = plugin.extend_path(paths, self.module_name)
 
78
        self.module.__path__ = paths
 
79
        self.log("using %r", paths)
 
80
        return paths
 
81
 
 
82
    def load_with_paths(self, paths):
 
83
        self.log("loading plugins!")
 
84
        plugin.load_plugins(self.update_module_paths(paths), state=self)
41
85
 
42
86
    def create_plugin(self, name, source=None, dir='.', file_name=None):
43
87
        if source is None:
48
92
            file_name = name + '.py'
49
93
        # 'source' must not fail to load
50
94
        path = osutils.pathjoin(dir, file_name)
51
 
        f = open(path, 'w')
52
 
        self.addCleanup(os.unlink, path)
53
 
        try:
 
95
        with open(path, 'w') as f:
54
96
            f.write(source + '\n')
55
 
        finally:
56
 
            f.close()
57
97
 
58
98
    def create_plugin_package(self, name, dir=None, source=None):
59
99
        if dir is None:
64
104
dir_source = '%s'
65
105
''' % (name, dir)
66
106
        os.makedirs(dir)
67
 
        def cleanup():
68
 
            # Workaround lazy import random? madness
69
 
            osutils.rmtree(dir)
70
 
        self.addCleanup(cleanup)
71
107
        self.create_plugin(name, source, dir,
72
108
                           file_name='__init__.py')
73
109
 
74
 
    def _unregister_plugin(self, name):
75
 
        """Remove the plugin from sys.modules and the bzrlib namespace."""
76
 
        py_name = 'bzrlib.plugins.%s' % name
77
 
        if py_name in sys.modules:
78
 
            del sys.modules[py_name]
79
 
        if getattr(bzrlib.plugins, name, None) is not None:
80
 
            delattr(bzrlib.plugins, name)
 
110
    def promote_cache(self, directory):
 
111
        """Move bytecode files out of __pycache__ in given directory."""
 
112
        cache_dir = os.path.join(directory, '__pycache__')
 
113
        if os.path.isdir(cache_dir):
 
114
            for name in os.listdir(cache_dir):
 
115
                magicless_name = '.'.join(name.split('.')[0::name.count('.')])
 
116
                rel = osutils.relpath(self.test_dir, cache_dir)
 
117
                self.log("moving %s in %s to %s", name, rel, magicless_name)
 
118
                os.rename(os.path.join(cache_dir, name),
 
119
                          os.path.join(directory, magicless_name))
 
120
 
 
121
    def _unregister_finder(self):
 
122
        """Removes any test copies of _PluginsAtFinder from sys.meta_path."""
 
123
        idx = len(sys.meta_path)
 
124
        while idx:
 
125
            idx -= 1
 
126
            finder = sys.meta_path[idx]
 
127
            if getattr(finder, "prefix", "") == self.module_prefix:
 
128
                self.log("removed %r from sys.meta_path", finder)
 
129
                sys.meta_path.pop(idx)
 
130
 
 
131
    def _unregister_all(self):
 
132
        """Remove all plugins in the test namespace from sys.modules."""
 
133
        for name in list(sys.modules):
 
134
            if name.startswith(self.module_prefix) or name == self.module_name:
 
135
                self.log("removed %s from sys.modules", name)
 
136
                del sys.modules[name]
 
137
 
 
138
    def assertPluginModules(self, plugin_dict):
 
139
        self.assertEqual(
 
140
            dict((k[len(self.module_prefix):], sys.modules[k])
 
141
                 for k in sys.modules if k.startswith(self.module_prefix)),
 
142
            plugin_dict)
81
143
 
82
144
    def assertPluginUnknown(self, name):
83
 
        self.failIf(getattr(bzrlib.plugins, name, None) is not None)
84
 
        self.failIf('bzrlib.plugins.%s' % name in sys.modules)
 
145
        self.assertTrue(getattr(self.module, name, None) is None)
 
146
        self.assertFalse(self.module_prefix + name in sys.modules)
85
147
 
86
148
    def assertPluginKnown(self, name):
87
 
        self.failUnless(getattr(bzrlib.plugins, name, None) is not None)
88
 
        self.failUnless('bzrlib.plugins.%s' % name in sys.modules)
89
 
 
90
 
 
91
 
class TestLoadingPlugins(tests.TestCaseInTempDir, TestPluginMixin):
 
149
        self.assertTrue(getattr(self.module, name, None) is not None)
 
150
        self.assertTrue(self.module_prefix + name in sys.modules)
 
151
 
 
152
 
 
153
class TestLoadingPlugins(BaseTestPlugins):
92
154
 
93
155
    activeattributes = {}
94
156
 
98
160
        # file name we can use which is also a valid attribute for accessing in
99
161
        # activeattributes. - we cannot give import parameters.
100
162
        tempattribute = "0"
101
 
        self.failIf(tempattribute in self.activeattributes)
 
163
        self.assertFalse(tempattribute in self.activeattributes)
102
164
        # set a place for the plugins to record their loading, and at the same
103
165
        # time validate that the location the plugins should record to is
104
166
        # valid and correct.
105
 
        self.__class__.activeattributes [tempattribute] = []
106
 
        self.failUnless(tempattribute in self.activeattributes)
 
167
        self.__class__.activeattributes[tempattribute] = []
 
168
        self.assertTrue(tempattribute in self.activeattributes)
107
169
        # create two plugin directories
108
170
        os.mkdir('first')
109
171
        os.mkdir('second')
110
172
        # write a plugin that will record when its loaded in the
111
173
        # tempattribute list.
112
 
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
 
174
        template = ("from breezy.tests.test_plugins import TestLoadingPlugins\n"
113
175
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
114
176
 
115
 
        outfile = open(os.path.join('first', 'plugin.py'), 'w')
116
 
        try:
 
177
        with open(os.path.join('first', 'plugin.py'), 'w') as outfile:
117
178
            outfile.write(template % (tempattribute, 'first'))
118
179
            outfile.write('\n')
119
 
        finally:
120
 
            outfile.close()
121
180
 
122
 
        outfile = open(os.path.join('second', 'plugin.py'), 'w')
123
 
        try:
 
181
        with open(os.path.join('second', 'plugin.py'), 'w') as outfile:
124
182
            outfile.write(template % (tempattribute, 'second'))
125
183
            outfile.write('\n')
126
 
        finally:
127
 
            outfile.close()
128
184
 
129
185
        try:
130
 
            bzrlib.plugin.load_from_path(['first', 'second'])
 
186
            self.load_with_paths(['first', 'second'])
131
187
            self.assertEqual(['first'], self.activeattributes[tempattribute])
132
188
        finally:
133
 
            # remove the plugin 'plugin'
134
189
            del self.activeattributes[tempattribute]
135
 
            self._unregister_plugin('plugin')
136
 
        self.assertPluginUnknown('plugin')
137
190
 
138
191
    def test_plugins_from_different_dirs_can_demand_load(self):
139
 
        self.failIf('bzrlib.plugins.pluginone' in sys.modules)
140
 
        self.failIf('bzrlib.plugins.plugintwo' in sys.modules)
 
192
        self.assertFalse('breezy.plugins.pluginone' in sys.modules)
 
193
        self.assertFalse('breezy.plugins.plugintwo' in sys.modules)
141
194
        # This test tests that having two plugins in different
142
195
        # directories with different names allows them both to be loaded, when
143
196
        # we do a direct import statement.
144
197
        # Determine a file name we can use which is also a valid attribute
145
198
        # for accessing in activeattributes. - we cannot give import parameters.
146
199
        tempattribute = "different-dirs"
147
 
        self.failIf(tempattribute in self.activeattributes)
 
200
        self.assertFalse(tempattribute in self.activeattributes)
148
201
        # set a place for the plugins to record their loading, and at the same
149
202
        # time validate that the location the plugins should record to is
150
203
        # valid and correct.
151
 
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
152
 
            [tempattribute] = []
153
 
        self.failUnless(tempattribute in self.activeattributes)
 
204
        breezy.tests.test_plugins.TestLoadingPlugins.activeattributes[tempattribute] = [
 
205
            ]
 
206
        self.assertTrue(tempattribute in self.activeattributes)
154
207
        # create two plugin directories
155
208
        os.mkdir('first')
156
209
        os.mkdir('second')
157
210
        # write plugins that will record when they are loaded in the
158
211
        # tempattribute list.
159
 
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
 
212
        template = ("from breezy.tests.test_plugins import TestLoadingPlugins\n"
160
213
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
161
214
 
162
 
        outfile = open(os.path.join('first', 'pluginone.py'), 'w')
163
 
        try:
 
215
        with open(os.path.join('first', 'pluginone.py'), 'w') as outfile:
164
216
            outfile.write(template % (tempattribute, 'first'))
165
217
            outfile.write('\n')
166
 
        finally:
167
 
            outfile.close()
168
218
 
169
 
        outfile = open(os.path.join('second', 'plugintwo.py'), 'w')
170
 
        try:
 
219
        with open(os.path.join('second', 'plugintwo.py'), 'w') as outfile:
171
220
            outfile.write(template % (tempattribute, 'second'))
172
221
            outfile.write('\n')
173
 
        finally:
174
 
            outfile.close()
175
222
 
176
 
        oldpath = bzrlib.plugins.__path__
177
223
        try:
178
 
            self.failIf('bzrlib.plugins.pluginone' in sys.modules)
179
 
            self.failIf('bzrlib.plugins.plugintwo' in sys.modules)
180
 
            bzrlib.plugins.__path__ = ['first', 'second']
181
 
            exec "import bzrlib.plugins.pluginone"
 
224
            self.assertPluginUnknown('pluginone')
 
225
            self.assertPluginUnknown('plugintwo')
 
226
            self.update_module_paths(['first', 'second'])
 
227
            exec("import %spluginone" % self.module_prefix)
182
228
            self.assertEqual(['first'], self.activeattributes[tempattribute])
183
 
            exec "import bzrlib.plugins.plugintwo"
 
229
            exec("import %splugintwo" % self.module_prefix)
184
230
            self.assertEqual(['first', 'second'],
185
 
                self.activeattributes[tempattribute])
 
231
                             self.activeattributes[tempattribute])
186
232
        finally:
187
 
            # remove the plugin 'plugin'
188
233
            del self.activeattributes[tempattribute]
189
 
            self._unregister_plugin('pluginone')
190
 
            self._unregister_plugin('plugintwo')
191
 
        self.assertPluginUnknown('pluginone')
192
 
        self.assertPluginUnknown('plugintwo')
193
234
 
194
235
    def test_plugins_can_load_from_directory_with_trailing_slash(self):
195
236
        # This test tests that a plugin can load from a directory when the
197
238
        # check the plugin is not loaded already
198
239
        self.assertPluginUnknown('ts_plugin')
199
240
        tempattribute = "trailing-slash"
200
 
        self.failIf(tempattribute in self.activeattributes)
 
241
        self.assertFalse(tempattribute in self.activeattributes)
201
242
        # set a place for the plugin to record its loading, and at the same
202
243
        # time validate that the location the plugin should record to is
203
244
        # valid and correct.
204
 
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
205
 
            [tempattribute] = []
206
 
        self.failUnless(tempattribute in self.activeattributes)
 
245
        breezy.tests.test_plugins.TestLoadingPlugins.activeattributes[tempattribute] = [
 
246
            ]
 
247
        self.assertTrue(tempattribute in self.activeattributes)
207
248
        # create a directory for the plugin
208
249
        os.mkdir('plugin_test')
209
250
        # write a plugin that will record when its loaded in the
210
251
        # tempattribute list.
211
 
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
 
252
        template = ("from breezy.tests.test_plugins import TestLoadingPlugins\n"
212
253
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
213
254
 
214
 
        outfile = open(os.path.join('plugin_test', 'ts_plugin.py'), 'w')
215
 
        try:
 
255
        with open(os.path.join('plugin_test', 'ts_plugin.py'), 'w') as outfile:
216
256
            outfile.write(template % (tempattribute, 'plugin'))
217
257
            outfile.write('\n')
218
 
        finally:
219
 
            outfile.close()
220
258
 
221
259
        try:
222
 
            bzrlib.plugin.load_from_path(['plugin_test'+os.sep])
 
260
            self.load_with_paths(['plugin_test' + os.sep])
223
261
            self.assertEqual(['plugin'], self.activeattributes[tempattribute])
 
262
            self.assertPluginKnown('ts_plugin')
224
263
        finally:
225
264
            del self.activeattributes[tempattribute]
226
 
            self._unregister_plugin('ts_plugin')
227
 
        self.assertPluginUnknown('ts_plugin')
228
265
 
229
266
    def load_and_capture(self, name):
230
267
        """Load plugins from '.' capturing the output.
236
273
        stream = StringIO()
237
274
        try:
238
275
            handler = logging.StreamHandler(stream)
239
 
            log = logging.getLogger('bzr')
 
276
            log = logging.getLogger('brz')
240
277
            log.addHandler(handler)
241
278
            try:
242
 
                try:
243
 
                    bzrlib.plugin.load_from_path(['.'])
244
 
                finally:
245
 
                    if 'bzrlib.plugins.%s' % name in sys.modules:
246
 
                        del sys.modules['bzrlib.plugins.%s' % name]
247
 
                    if getattr(bzrlib.plugins, name, None):
248
 
                        delattr(bzrlib.plugins, name)
 
279
                self.load_with_paths(['.'])
249
280
            finally:
250
281
                # Stop capturing output
251
282
                handler.flush()
256
287
            stream.close()
257
288
 
258
289
    def test_plugin_with_bad_api_version_reports(self):
259
 
        # This plugin asks for bzrlib api version 1.0.0, which is not supported
260
 
        # anymore.
 
290
        """Try loading a plugin that requests an unsupported api.
 
291
 
 
292
        Observe that it records the problem but doesn't complain on stderr.
 
293
 
 
294
        See https://bugs.launchpad.net/bzr/+bug/704195
 
295
        """
261
296
        name = 'wants100.py'
262
 
        f = file(name, 'w')
263
 
        try:
264
 
            f.write("import bzrlib.api\n"
265
 
                "bzrlib.api.require_any_api(bzrlib, [(1, 0, 0)])\n")
266
 
        finally:
267
 
            f.close()
268
 
 
 
297
        with open(name, 'w') as f:
 
298
            f.write("import breezy\n"
 
299
                    "from breezy.errors import IncompatibleVersion\n"
 
300
                    "raise IncompatibleVersion(breezy, [(1, 0, 0)], (0, 0, 5))\n")
269
301
        log = self.load_and_capture(name)
270
 
        self.assertContainsRe(log,
271
 
            r"It requested API version")
 
302
        self.assertNotContainsRe(log,
 
303
                                 r"It supports breezy version")
 
304
        self.assertEqual({'wants100'}, viewkeys(self.plugin_warnings))
 
305
        self.assertContainsRe(
 
306
            self.plugin_warnings['wants100'][0],
 
307
            r"It supports breezy version")
272
308
 
273
309
    def test_plugin_with_bad_name_does_not_load(self):
274
310
        # The file name here invalid for a python module.
275
 
        name = 'bzr-bad plugin-name..py'
276
 
        file(name, 'w').close()
 
311
        name = 'brz-bad plugin-name..py'
 
312
        open(name, 'w').close()
277
313
        log = self.load_and_capture(name)
278
314
        self.assertContainsRe(log,
279
 
            r"Unable to load 'bzr-bad plugin-name\.' in '\.' as a plugin "
280
 
            "because the file path isn't a valid module name; try renaming "
281
 
            "it to 'bad_plugin_name_'\.")
282
 
 
283
 
 
284
 
class TestPlugins(tests.TestCaseInTempDir, TestPluginMixin):
 
315
                              r"Unable to load 'brz-bad plugin-name\.' in '\.' as a plugin "
 
316
                              "because the file path isn't a valid module name; try renaming "
 
317
                              "it to 'bad_plugin_name_'\\.")
 
318
 
 
319
 
 
320
class TestPlugins(BaseTestPlugins):
285
321
 
286
322
    def setup_plugin(self, source=""):
287
 
        # This test tests a new plugin appears in bzrlib.plugin.plugins().
 
323
        # This test tests a new plugin appears in breezy.plugin.plugins().
288
324
        # check the plugin is not loaded already
289
325
        self.assertPluginUnknown('plugin')
290
326
        # write a plugin that _cannot_ fail to load.
291
 
        file('plugin.py', 'w').write(source + '\n')
292
 
        self.addCleanup(self.teardown_plugin)
293
 
        plugin.load_from_path(['.'])
294
 
 
295
 
    def teardown_plugin(self):
296
 
        self._unregister_plugin('plugin')
297
 
        self.assertPluginUnknown('plugin')
 
327
        with open('plugin.py', 'w') as f:
 
328
            f.write(source + '\n')
 
329
        self.load_with_paths(['.'])
 
330
 
 
331
    def test_plugin_loaded(self):
 
332
        self.assertPluginUnknown('plugin')
 
333
        self.assertIs(None, breezy.plugin.get_loaded_plugin('plugin'))
 
334
        self.setup_plugin()
 
335
        p = breezy.plugin.get_loaded_plugin('plugin')
 
336
        self.assertIsInstance(p, breezy.plugin.PlugIn)
 
337
        self.assertIs(p.module, sys.modules[self.module_prefix + 'plugin'])
 
338
 
 
339
    def test_plugin_loaded_disabled(self):
 
340
        self.assertPluginUnknown('plugin')
 
341
        self.overrideEnv('BRZ_DISABLE_PLUGINS', 'plugin')
 
342
        self.setup_plugin()
 
343
        self.assertIs(None, breezy.plugin.get_loaded_plugin('plugin'))
298
344
 
299
345
    def test_plugin_appears_in_plugins(self):
300
346
        self.setup_plugin()
301
347
        self.assertPluginKnown('plugin')
302
 
        p = plugin.plugins()['plugin']
303
 
        self.assertIsInstance(p, bzrlib.plugin.PlugIn)
304
 
        self.assertEqual(p.module, plugins.plugin)
 
348
        p = self.plugins['plugin']
 
349
        self.assertIsInstance(p, breezy.plugin.PlugIn)
 
350
        self.assertIs(p.module, sys.modules[self.module_prefix + 'plugin'])
305
351
 
306
352
    def test_trivial_plugin_get_path(self):
307
353
        self.setup_plugin()
308
 
        p = plugin.plugins()['plugin']
 
354
        p = self.plugins['plugin']
309
355
        plugin_path = self.test_dir + '/plugin.py'
310
356
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
311
357
 
312
358
    def test_plugin_get_path_py_not_pyc(self):
313
359
        # first import creates plugin.pyc
314
360
        self.setup_plugin()
315
 
        self.teardown_plugin()
316
 
        plugin.load_from_path(['.']) # import plugin.pyc
 
361
        self.promote_cache(self.test_dir)
 
362
        self.reset()
 
363
        self.load_with_paths(['.'])  # import plugin.pyc
317
364
        p = plugin.plugins()['plugin']
318
365
        plugin_path = self.test_dir + '/plugin.py'
319
366
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
321
368
    def test_plugin_get_path_pyc_only(self):
322
369
        # first import creates plugin.pyc (or plugin.pyo depending on __debug__)
323
370
        self.setup_plugin()
324
 
        self.teardown_plugin()
325
371
        os.unlink(self.test_dir + '/plugin.py')
326
 
        plugin.load_from_path(['.']) # import plugin.pyc (or .pyo)
 
372
        self.promote_cache(self.test_dir)
 
373
        self.reset()
 
374
        self.load_with_paths(['.'])  # import plugin.pyc (or .pyo)
327
375
        p = plugin.plugins()['plugin']
328
 
        if __debug__:
329
 
            plugin_path = self.test_dir + '/plugin.pyc'
330
 
        else:
331
 
            plugin_path = self.test_dir + '/plugin.pyo'
 
376
        plugin_path = self.test_dir + '/plugin' + plugin.COMPILED_EXT
332
377
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
333
378
 
334
379
    def test_no_test_suite_gives_None_for_test_suite(self):
350
395
 
351
396
    def test_load_plugin_tests_gives_load_plugin_tests_result(self):
352
397
        source = """
353
 
def load_tests(standard_tests, module, loader):
 
398
def load_tests(loader, standard_tests, pattern):
354
399
    return 'foo'"""
355
400
        self.setup_plugin(source)
356
401
        loader = tests.TestUtil.TestLoader()
380
425
 
381
426
    def test_no_version_info___version__(self):
382
427
        self.setup_plugin()
383
 
        plugin = bzrlib.plugin.plugins()['plugin']
 
428
        plugin = breezy.plugin.plugins()['plugin']
384
429
        self.assertEqual("unknown", plugin.__version__)
385
430
 
386
431
    def test_str__version__with_version_info(self):
387
432
        self.setup_plugin("version_info = '1.2.3'")
388
 
        plugin = bzrlib.plugin.plugins()['plugin']
 
433
        plugin = breezy.plugin.plugins()['plugin']
389
434
        self.assertEqual("1.2.3", plugin.__version__)
390
435
 
391
436
    def test_noniterable__version__with_version_info(self):
392
437
        self.setup_plugin("version_info = (1)")
393
 
        plugin = bzrlib.plugin.plugins()['plugin']
 
438
        plugin = breezy.plugin.plugins()['plugin']
394
439
        self.assertEqual("1", plugin.__version__)
395
440
 
396
441
    def test_1__version__with_version_info(self):
397
442
        self.setup_plugin("version_info = (1,)")
398
 
        plugin = bzrlib.plugin.plugins()['plugin']
 
443
        plugin = breezy.plugin.plugins()['plugin']
399
444
        self.assertEqual("1", plugin.__version__)
400
445
 
401
446
    def test_1_2__version__with_version_info(self):
402
447
        self.setup_plugin("version_info = (1, 2)")
403
 
        plugin = bzrlib.plugin.plugins()['plugin']
 
448
        plugin = breezy.plugin.plugins()['plugin']
404
449
        self.assertEqual("1.2", plugin.__version__)
405
450
 
406
451
    def test_1_2_3__version__with_version_info(self):
407
452
        self.setup_plugin("version_info = (1, 2, 3)")
408
 
        plugin = bzrlib.plugin.plugins()['plugin']
 
453
        plugin = breezy.plugin.plugins()['plugin']
409
454
        self.assertEqual("1.2.3", plugin.__version__)
410
455
 
411
456
    def test_candidate__version__with_version_info(self):
412
457
        self.setup_plugin("version_info = (1, 2, 3, 'candidate', 1)")
413
 
        plugin = bzrlib.plugin.plugins()['plugin']
 
458
        plugin = breezy.plugin.plugins()['plugin']
414
459
        self.assertEqual("1.2.3rc1", plugin.__version__)
415
460
 
416
461
    def test_dev__version__with_version_info(self):
417
462
        self.setup_plugin("version_info = (1, 2, 3, 'dev', 0)")
418
 
        plugin = bzrlib.plugin.plugins()['plugin']
 
463
        plugin = breezy.plugin.plugins()['plugin']
419
464
        self.assertEqual("1.2.3dev", plugin.__version__)
420
465
 
421
466
    def test_dev_fallback__version__with_version_info(self):
422
467
        self.setup_plugin("version_info = (1, 2, 3, 'dev', 4)")
423
 
        plugin = bzrlib.plugin.plugins()['plugin']
 
468
        plugin = breezy.plugin.plugins()['plugin']
424
469
        self.assertEqual("1.2.3dev4", plugin.__version__)
425
470
 
426
471
    def test_final__version__with_version_info(self):
427
472
        self.setup_plugin("version_info = (1, 2, 3, 'final', 0)")
428
 
        plugin = bzrlib.plugin.plugins()['plugin']
 
473
        plugin = breezy.plugin.plugins()['plugin']
429
474
        self.assertEqual("1.2.3", plugin.__version__)
430
475
 
431
476
    def test_final_fallback__version__with_version_info(self):
432
477
        self.setup_plugin("version_info = (1, 2, 3, 'final', 2)")
433
 
        plugin = bzrlib.plugin.plugins()['plugin']
434
 
        self.assertEqual("1.2.3.final.2", plugin.__version__)
435
 
 
436
 
 
437
 
class TestPluginHelp(tests.TestCaseInTempDir):
438
 
 
439
 
    def split_help_commands(self):
440
 
        help = {}
441
 
        current = None
442
 
        out, err = self.run_bzr('--no-plugins help commands')
443
 
        for line in out.splitlines():
444
 
            if not line.startswith(' '):
445
 
                current = line.split()[0]
446
 
            help[current] = help.get(current, '') + line
447
 
 
448
 
        return help
449
 
 
450
 
    def test_plugin_help_builtins_unaffected(self):
451
 
        # Check we don't get false positives
452
 
        help_commands = self.split_help_commands()
453
 
        for cmd_name in bzrlib.commands.builtin_command_names():
454
 
            if cmd_name in bzrlib.commands.plugin_command_names():
455
 
                continue
456
 
            try:
457
 
                help = bzrlib.commands.get_cmd_object(cmd_name).get_help_text()
458
 
            except NotImplementedError:
459
 
                # some commands have no help
460
 
                pass
461
 
            else:
462
 
                self.assertNotContainsRe(help, 'plugin "[^"]*"')
463
 
 
464
 
            if cmd_name in help_commands.keys():
465
 
                # some commands are hidden
466
 
                help = help_commands[cmd_name]
467
 
                self.assertNotContainsRe(help, 'plugin "[^"]*"')
468
 
 
469
 
    def test_plugin_help_shows_plugin(self):
470
 
        # Create a test plugin
471
 
        os.mkdir('plugin_test')
472
 
        f = open(osutils.pathjoin('plugin_test', 'myplug.py'), 'w')
473
 
        f.write("""\
474
 
from bzrlib import commands
475
 
class cmd_myplug(commands.Command):
476
 
    __doc__ = '''Just a simple test plugin.'''
477
 
    aliases = ['mplg']
478
 
    def run(self):
479
 
        print 'Hello from my plugin'
480
 
 
481
 
"""
482
 
)
483
 
        f.close()
484
 
 
485
 
        try:
486
 
            # Check its help
487
 
            bzrlib.plugin.load_from_path(['plugin_test'])
488
 
            bzrlib.commands.register_command( bzrlib.plugins.myplug.cmd_myplug)
489
 
            help = self.run_bzr('help myplug')[0]
490
 
            self.assertContainsRe(help, 'plugin "myplug"')
491
 
            help = self.split_help_commands()['myplug']
492
 
            self.assertContainsRe(help, '\[myplug\]')
493
 
        finally:
494
 
            # unregister command
495
 
            if 'myplug' in bzrlib.commands.plugin_cmds:
496
 
                bzrlib.commands.plugin_cmds.remove('myplug')
497
 
            # remove the plugin 'myplug'
498
 
            if getattr(bzrlib.plugins, 'myplug', None):
499
 
                delattr(bzrlib.plugins, 'myplug')
 
478
        plugin = breezy.plugin.plugins()['plugin']
 
479
        self.assertEqual("1.2.3.2", plugin.__version__)
500
480
 
501
481
 
502
482
class TestHelpIndex(tests.TestCase):
515
495
        index = plugin.PluginsHelpIndex()
516
496
        # make a new plugin here for this test, even if we're run with
517
497
        # --no-plugins
518
 
        self.assertFalse(sys.modules.has_key('bzrlib.plugins.demo_module'))
519
 
        demo_module = FakeModule('', 'bzrlib.plugins.demo_module')
520
 
        sys.modules['bzrlib.plugins.demo_module'] = demo_module
 
498
        self.assertFalse('breezy.plugins.demo_module' in sys.modules)
 
499
        demo_module = FakeModule('', 'breezy.plugins.demo_module')
 
500
        sys.modules['breezy.plugins.demo_module'] = demo_module
521
501
        try:
522
502
            topics = index.get_topics('demo_module')
523
503
            self.assertEqual(1, len(topics))
524
504
            self.assertIsInstance(topics[0], plugin.ModuleHelpTopic)
525
505
            self.assertEqual(demo_module, topics[0].module)
526
506
        finally:
527
 
            del sys.modules['bzrlib.plugins.demo_module']
 
507
            del sys.modules['breezy.plugins.demo_module']
528
508
 
529
509
    def test_get_topics_no_topic(self):
530
510
        """Searching for something that is not a plugin returns []."""
541
521
    def test_get_plugin_topic_with_prefix(self):
542
522
        """Searching for plugins/demo_module returns help."""
543
523
        index = plugin.PluginsHelpIndex()
544
 
        self.assertFalse(sys.modules.has_key('bzrlib.plugins.demo_module'))
545
 
        demo_module = FakeModule('', 'bzrlib.plugins.demo_module')
546
 
        sys.modules['bzrlib.plugins.demo_module'] = demo_module
 
524
        self.assertFalse('breezy.plugins.demo_module' in sys.modules)
 
525
        demo_module = FakeModule('', 'breezy.plugins.demo_module')
 
526
        sys.modules['breezy.plugins.demo_module'] = demo_module
547
527
        try:
548
528
            topics = index.get_topics('plugins/demo_module')
549
529
            self.assertEqual(1, len(topics))
550
530
            self.assertIsInstance(topics[0], plugin.ModuleHelpTopic)
551
531
            self.assertEqual(demo_module, topics[0].module)
552
532
        finally:
553
 
            del sys.modules['bzrlib.plugins.demo_module']
 
533
            del sys.modules['breezy.plugins.demo_module']
554
534
 
555
535
 
556
536
class FakeModule(object):
575
555
        mod = FakeModule(None, 'demo')
576
556
        topic = plugin.ModuleHelpTopic(mod)
577
557
        self.assertEqual("Plugin 'demo' has no docstring.\n",
578
 
            topic.get_help_text())
 
558
                         topic.get_help_text())
579
559
 
580
560
    def test_get_help_text_no_carriage_return(self):
581
561
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
582
562
        mod = FakeModule('one line of help', 'demo')
583
563
        topic = plugin.ModuleHelpTopic(mod)
584
564
        self.assertEqual("one line of help\n",
585
 
            topic.get_help_text())
 
565
                         topic.get_help_text())
586
566
 
587
567
    def test_get_help_text_carriage_return(self):
588
568
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
589
569
        mod = FakeModule('two lines of help\nand more\n', 'demo')
590
570
        topic = plugin.ModuleHelpTopic(mod)
591
571
        self.assertEqual("two lines of help\nand more\n",
592
 
            topic.get_help_text())
 
572
                         topic.get_help_text())
593
573
 
594
574
    def test_get_help_text_with_additional_see_also(self):
595
575
        mod = FakeModule('two lines of help\nand more', 'demo')
596
576
        topic = plugin.ModuleHelpTopic(mod)
597
 
        self.assertEqual("two lines of help\nand more\nSee also: bar, foo\n",
 
577
        self.assertEqual(
 
578
            "two lines of help\nand more\n\n:See also: bar, foo\n",
598
579
            topic.get_help_text(['foo', 'bar']))
599
580
 
600
581
    def test_get_help_topic(self):
601
582
        """The help topic for a plugin is its module name."""
602
 
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.demo')
 
583
        mod = FakeModule('two lines of help\nand more', 'breezy.plugins.demo')
603
584
        topic = plugin.ModuleHelpTopic(mod)
604
585
        self.assertEqual('demo', topic.get_help_topic())
605
 
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.foo_bar')
 
586
        mod = FakeModule('two lines of help\nand more',
 
587
                         'breezy.plugins.foo_bar')
606
588
        topic = plugin.ModuleHelpTopic(mod)
607
589
        self.assertEqual('foo_bar', topic.get_help_topic())
608
590
 
609
591
 
610
 
class TestLoadFromPath(tests.TestCaseInTempDir):
611
 
 
612
 
    def setUp(self):
613
 
        super(TestLoadFromPath, self).setUp()
614
 
        # Change bzrlib.plugin to think no plugins have been loaded yet.
615
 
        self.overrideAttr(bzrlib.plugins, '__path__', [])
616
 
        self.overrideAttr(plugin, '_loaded', False)
617
 
 
618
 
        # Monkey-patch load_from_path to stop it from actually loading anything.
619
 
        self.overrideAttr(plugin, 'load_from_path', lambda dirs: None)
620
 
 
621
 
    def test_set_plugins_path_with_args(self):
622
 
        plugin.set_plugins_path(['a', 'b'])
623
 
        self.assertEqual(['a', 'b'], bzrlib.plugins.__path__)
624
 
 
625
 
    def test_set_plugins_path_defaults(self):
626
 
        plugin.set_plugins_path()
627
 
        self.assertEqual(plugin.get_standard_plugins_path(),
628
 
                         bzrlib.plugins.__path__)
629
 
 
630
 
    def test_get_standard_plugins_path(self):
631
 
        path = plugin.get_standard_plugins_path()
632
 
        for directory in path:
633
 
            self.assertNotContainsRe(directory, r'\\/$')
634
 
        try:
635
 
            from distutils.sysconfig import get_python_lib
636
 
        except ImportError:
637
 
            pass
638
 
        else:
639
 
            if sys.platform != 'win32':
640
 
                python_lib = get_python_lib()
641
 
                for directory in path:
642
 
                    if directory.startswith(python_lib):
643
 
                        break
644
 
                else:
645
 
                    self.fail('No path to global plugins')
646
 
 
647
 
    def test_get_standard_plugins_path_env(self):
648
 
        os.environ['BZR_PLUGIN_PATH'] = 'foo/'
649
 
        path = plugin.get_standard_plugins_path()
650
 
        for directory in path:
651
 
            self.assertNotContainsRe(directory, r'\\/$')
652
 
 
653
 
    def test_load_plugins(self):
654
 
        plugin.load_plugins(['.'])
655
 
        self.assertEqual(bzrlib.plugins.__path__, ['.'])
656
 
        # subsequent loads are no-ops
657
 
        plugin.load_plugins(['foo'])
658
 
        self.assertEqual(bzrlib.plugins.__path__, ['.'])
659
 
 
660
 
    def test_load_plugins_default(self):
661
 
        plugin.load_plugins()
662
 
        path = plugin.get_standard_plugins_path()
663
 
        self.assertEqual(path, bzrlib.plugins.__path__)
664
 
 
665
 
 
666
592
class TestEnvPluginPath(tests.TestCase):
667
593
 
668
 
    def setUp(self):
669
 
        super(TestEnvPluginPath, self).setUp()
670
 
        self.overrideAttr(plugin, 'DEFAULT_PLUGIN_PATH', None)
671
 
 
672
 
        self.user = plugin.get_user_plugin_path()
673
 
        self.site = plugin.get_site_plugin_path()
674
 
        self.core = plugin.get_core_plugin_path()
675
 
 
676
 
    def _list2paths(self, *args):
677
 
        paths = []
678
 
        for p in args:
679
 
            plugin._append_new_path(paths, p)
680
 
        return paths
681
 
 
682
 
    def _set_path(self, *args):
683
 
        path = os.pathsep.join(self._list2paths(*args))
684
 
        osutils.set_or_unset_env('BZR_PLUGIN_PATH', path)
 
594
    user = "USER"
 
595
    core = "CORE"
 
596
    site = "SITE"
 
597
    entrypoints = "ENTRYPOINTS"
685
598
 
686
599
    def check_path(self, expected_dirs, setting_dirs):
687
 
        if setting_dirs:
688
 
            self._set_path(*setting_dirs)
689
 
        actual = plugin.get_standard_plugins_path()
690
 
        self.assertEquals(self._list2paths(*expected_dirs), actual)
 
600
        if setting_dirs is None:
 
601
            del os.environ['BRZ_PLUGIN_PATH']
 
602
        else:
 
603
            os.environ['BRZ_PLUGIN_PATH'] = os.pathsep.join(setting_dirs)
 
604
        actual = [(p if t == 'path' else t.upper())
 
605
                  for p, t in plugin._env_plugin_path()]
 
606
        self.assertEqual(expected_dirs, actual)
691
607
 
692
608
    def test_default(self):
693
 
        self.check_path([self.user, self.core, self.site],
694
 
                        None)
 
609
        self.check_path([self.user, self.core, self.site], None)
695
610
 
696
611
    def test_adhoc_policy(self):
697
612
        self.check_path([self.user, self.core, self.site],
705
620
        self.check_path([self.user, self.site, self.core],
706
621
                        ['+user', '+site', '+core'])
707
622
 
 
623
    def test_enable_entrypoints(self):
 
624
        self.check_path([self.user, self.core, self.site, self.entrypoints],
 
625
                        ['+user', '+core', '+site', '+entrypoints'])
 
626
 
708
627
    def test_disable_user(self):
709
628
        self.check_path([self.core, self.site], ['-user'])
710
629
 
746
665
                        ['mycore', '-core'])
747
666
 
748
667
    def test_my_plugin_only(self):
749
 
        self.check_path(['myplugin'], ['myplugin', '-user', '-core', '-site'])
 
668
        self.check_path(
 
669
            ['myplugin'],
 
670
            ['myplugin', '-user', '-core', '-site', '-entrypoints'])
750
671
 
751
672
    def test_my_plugin_first(self):
752
673
        self.check_path(['myplugin', self.core, self.site, self.user],
757
678
                        ['+foo', '-bar'])
758
679
 
759
680
 
760
 
class TestDisablePlugin(tests.TestCaseInTempDir, TestPluginMixin):
761
 
 
762
 
    def setUp(self):
763
 
        super(TestDisablePlugin, self).setUp()
764
 
        self.create_plugin_package('test_foo')
765
 
        # Make sure we don't pollute the plugins namespace
766
 
        self.overrideAttr(plugins, '__path__')
767
 
        # Be paranoid in case a test fail
768
 
        self.addCleanup(self._unregister_plugin, 'test_foo')
 
681
class TestDisablePlugin(BaseTestPlugins):
769
682
 
770
683
    def test_cannot_import(self):
771
 
        osutils.set_or_unset_env('BZR_DISABLE_PLUGINS', 'test_foo')
772
 
        plugin.set_plugins_path(['.'])
 
684
        self.create_plugin_package('works')
 
685
        self.create_plugin_package('fails')
 
686
        self.overrideEnv('BRZ_DISABLE_PLUGINS', 'fails')
 
687
        self.update_module_paths(["."])
 
688
        import breezy.testingplugins.works as works
773
689
        try:
774
 
            import bzrlib.plugins.test_foo
 
690
            import breezy.testingplugins.fails as fails
775
691
        except ImportError:
776
692
            pass
777
 
        self.assertPluginUnknown('test_foo')
778
 
 
779
 
    def test_regular_load(self):
780
 
        self.overrideAttr(plugin, '_loaded', False)
781
 
        plugin.load_plugins(['.'])
782
 
        self.assertPluginKnown('test_foo')
783
 
        self.assertDocstring("This is the doc for test_foo",
784
 
                             bzrlib.plugins.test_foo)
785
 
 
786
 
    def test_not_loaded(self):
787
 
        self.warnings = []
788
 
        def captured_warning(*args, **kwargs):
789
 
            self.warnings.append((args, kwargs))
790
 
        self.overrideAttr(trace, 'warning', captured_warning)
791
 
        # Reset the flag that protect against double loading
792
 
        self.overrideAttr(plugin, '_loaded', False)
793
 
        osutils.set_or_unset_env('BZR_DISABLE_PLUGINS', 'test_foo')
794
 
        plugin.load_plugins(['.'])
795
 
        self.assertPluginUnknown('test_foo')
796
 
        # Make sure we don't warn about the plugin ImportError since this has
797
 
        # been *requested* by the user.
798
 
        self.assertLength(0, self.warnings)
799
 
 
800
 
 
801
 
class TestLoadPluginAt(tests.TestCaseInTempDir, TestPluginMixin):
 
693
        else:
 
694
            self.fail("Loaded blocked plugin: " + repr(fails))
 
695
        self.assertPluginModules({'fails': None, 'works': works})
 
696
 
 
697
    def test_partial_imports(self):
 
698
        self.create_plugin('good')
 
699
        self.create_plugin('bad')
 
700
        self.create_plugin_package('ugly')
 
701
        self.overrideEnv('BRZ_DISABLE_PLUGINS', 'bad:ugly')
 
702
        self.load_with_paths(['.'])
 
703
        self.assertEqual({'good'}, viewkeys(self.plugins))
 
704
        self.assertPluginModules({
 
705
            'good': self.plugins['good'].module,
 
706
            'bad': None,
 
707
            'ugly': None,
 
708
        })
 
709
        # Ensure there are no warnings about plugins not being imported as
 
710
        # the user has explictly requested they be disabled.
 
711
        self.assertNotContainsRe(self.get_log(), r"Unable to load plugin")
 
712
 
 
713
 
 
714
class TestEnvDisablePlugins(tests.TestCase):
 
715
 
 
716
    def _get_names(self, env_value):
 
717
        os.environ['BRZ_DISABLE_PLUGINS'] = env_value
 
718
        return plugin._env_disable_plugins()
 
719
 
 
720
    def test_unset(self):
 
721
        self.assertEqual([], plugin._env_disable_plugins())
 
722
 
 
723
    def test_empty(self):
 
724
        self.assertEqual([], self._get_names(''))
 
725
 
 
726
    def test_single(self):
 
727
        self.assertEqual(['single'], self._get_names('single'))
 
728
 
 
729
    def test_multi(self):
 
730
        expected = ['one', 'two']
 
731
        self.assertEqual(expected, self._get_names(os.pathsep.join(expected)))
 
732
 
 
733
    def test_mixed(self):
 
734
        value = os.pathsep.join(['valid', 'in-valid'])
 
735
        self.assertEqual(['valid'], self._get_names(value))
 
736
        self.assertContainsRe(
 
737
            self.get_log(),
 
738
            r"Invalid name 'in-valid' in BRZ_DISABLE_PLUGINS=" + repr(value))
 
739
 
 
740
 
 
741
class TestEnvPluginsAt(tests.TestCase):
 
742
 
 
743
    def _get_paths(self, env_value):
 
744
        os.environ['BRZ_PLUGINS_AT'] = env_value
 
745
        return plugin._env_plugins_at()
 
746
 
 
747
    def test_empty(self):
 
748
        self.assertEqual([], plugin._env_plugins_at())
 
749
        self.assertEqual([], self._get_paths(''))
 
750
 
 
751
    def test_one_path(self):
 
752
        self.assertEqual([('b', 'man')], self._get_paths('b@man'))
 
753
 
 
754
    def test_multiple(self):
 
755
        self.assertEqual(
 
756
            [('tools', 'bzr-tools'), ('p', 'play.py')],
 
757
            self._get_paths(os.pathsep.join(('tools@bzr-tools', 'p@play.py'))))
 
758
 
 
759
    def test_many_at(self):
 
760
        self.assertEqual(
 
761
            [('church', 'StMichael@Plea@Norwich')],
 
762
            self._get_paths('church@StMichael@Plea@Norwich'))
 
763
 
 
764
    def test_only_py(self):
 
765
        self.assertEqual([('test', './test.py')], self._get_paths('./test.py'))
 
766
 
 
767
    def test_only_package(self):
 
768
        self.assertEqual([('py', '/opt/b/py')], self._get_paths('/opt/b/py'))
 
769
 
 
770
    def test_bad_name(self):
 
771
        self.assertEqual([], self._get_paths('/usr/local/bzr-git'))
 
772
        self.assertContainsRe(
 
773
            self.get_log(),
 
774
            r"Invalid name 'bzr-git' in BRZ_PLUGINS_AT='/usr/local/bzr-git'")
 
775
 
 
776
 
 
777
class TestLoadPluginAt(BaseTestPlugins):
802
778
 
803
779
    def setUp(self):
804
780
        super(TestLoadPluginAt, self).setUp()
805
 
        # Make sure we don't pollute the plugins namespace
806
 
        self.overrideAttr(plugins, '__path__')
807
 
        # Be paranoid in case a test fail
808
 
        self.addCleanup(self._unregister_plugin, 'test_foo')
809
 
        # Reset the flag that protect against double loading
810
 
        self.overrideAttr(plugin, '_loaded', False)
811
781
        # Create the same plugin in two directories
812
782
        self.create_plugin_package('test_foo', dir='non-standard-dir')
813
783
        # The "normal" directory, we use 'standard' instead of 'plugins' to
817
787
    def assertTestFooLoadedFrom(self, path):
818
788
        self.assertPluginKnown('test_foo')
819
789
        self.assertDocstring('This is the doc for test_foo',
820
 
                             bzrlib.plugins.test_foo)
821
 
        self.assertEqual(path, bzrlib.plugins.test_foo.dir_source)
 
790
                             self.module.test_foo)
 
791
        self.assertEqual(path, self.module.test_foo.dir_source)
822
792
 
823
793
    def test_regular_load(self):
824
 
        plugin.load_plugins(['standard'])
 
794
        self.load_with_paths(['standard'])
825
795
        self.assertTestFooLoadedFrom('standard/test_foo')
826
796
 
827
797
    def test_import(self):
828
 
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
829
 
        plugin.set_plugins_path(['standard'])
830
 
        try:
831
 
            import bzrlib.plugins.test_foo
832
 
        except ImportError:
833
 
            pass
 
798
        self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
 
799
        self.update_module_paths(['standard'])
 
800
        import breezy.testingplugins.test_foo
834
801
        self.assertTestFooLoadedFrom('non-standard-dir')
835
802
 
836
803
    def test_loading(self):
837
 
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
838
 
        plugin.load_plugins(['standard'])
 
804
        self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
 
805
        self.load_with_paths(['standard'])
 
806
        self.assertTestFooLoadedFrom('non-standard-dir')
 
807
 
 
808
    def test_loading_other_name(self):
 
809
        self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
 
810
        os.rename('standard/test_foo', 'standard/test_bar')
 
811
        self.load_with_paths(['standard'])
839
812
        self.assertTestFooLoadedFrom('non-standard-dir')
840
813
 
841
814
    def test_compiled_loaded(self):
842
 
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
843
 
        plugin.load_plugins(['standard'])
 
815
        self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
 
816
        self.load_with_paths(['standard'])
844
817
        self.assertTestFooLoadedFrom('non-standard-dir')
845
 
        self.assertEqual('non-standard-dir/__init__.py',
846
 
                         bzrlib.plugins.test_foo.__file__)
 
818
        self.assertIsSameRealPath('non-standard-dir/__init__.py',
 
819
                                  self.module.test_foo.__file__)
847
820
 
848
821
        # Try importing again now that the source has been compiled
849
 
        self._unregister_plugin('test_foo')
850
 
        plugin._loaded = False
851
 
        plugin.load_plugins(['standard'])
 
822
        os.remove('non-standard-dir/__init__.py')
 
823
        self.promote_cache('non-standard-dir')
 
824
        self.reset()
 
825
        self.load_with_paths(['standard'])
852
826
        self.assertTestFooLoadedFrom('non-standard-dir')
853
 
        if __debug__:
854
 
            suffix = 'pyc'
855
 
        else:
856
 
            suffix = 'pyo'
857
 
        self.assertEqual('non-standard-dir/__init__.%s' % suffix,
858
 
                         bzrlib.plugins.test_foo.__file__)
 
827
        suffix = plugin.COMPILED_EXT
 
828
        self.assertIsSameRealPath('non-standard-dir/__init__' + suffix,
 
829
                                  self.module.test_foo.__file__)
859
830
 
860
831
    def test_submodule_loading(self):
861
832
        # We create an additional directory under the one for test_foo
862
833
        self.create_plugin_package('test_bar', dir='non-standard-dir/test_bar')
863
 
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
864
 
        plugin.set_plugins_path(['standard'])
865
 
        import bzrlib.plugins.test_foo
866
 
        self.assertEqual('bzrlib.plugins.test_foo',
867
 
                         bzrlib.plugins.test_foo.__package__)
868
 
        import bzrlib.plugins.test_foo.test_bar
869
 
        self.assertEqual('non-standard-dir/test_bar/__init__.py',
870
 
                         bzrlib.plugins.test_foo.test_bar.__file__)
 
834
        self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
 
835
        self.update_module_paths(['standard'])
 
836
        import breezy.testingplugins.test_foo  # noqa: F401
 
837
        self.assertEqual(self.module_prefix + 'test_foo',
 
838
                         self.module.test_foo.__package__)
 
839
        import breezy.testingplugins.test_foo.test_bar  # noqa: F401
 
840
        self.assertIsSameRealPath('non-standard-dir/test_bar/__init__.py',
 
841
                                  self.module.test_foo.test_bar.__file__)
 
842
 
 
843
    def test_relative_submodule_loading(self):
 
844
        self.create_plugin_package('test_foo', dir='another-dir', source='''
 
845
from . import test_bar
 
846
''')
 
847
        # We create an additional directory under the one for test_foo
 
848
        self.create_plugin_package('test_bar', dir='another-dir/test_bar')
 
849
        self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@another-dir')
 
850
        self.update_module_paths(['standard'])
 
851
        import breezy.testingplugins.test_foo  # noqa: F401
 
852
        self.assertEqual(self.module_prefix + 'test_foo',
 
853
                         self.module.test_foo.__package__)
 
854
        self.assertIsSameRealPath('another-dir/test_bar/__init__.py',
 
855
                                  self.module.test_foo.test_bar.__file__)
871
856
 
872
857
    def test_loading_from___init__only(self):
873
858
        # We rename the existing __init__.py file to ensure that we don't load
875
860
        init = 'non-standard-dir/__init__.py'
876
861
        random = 'non-standard-dir/setup.py'
877
862
        os.rename(init, random)
878
 
        self.addCleanup(os.rename, random, init)
879
 
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
880
 
        plugin.load_plugins(['standard'])
 
863
        self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
 
864
        self.load_with_paths(['standard'])
881
865
        self.assertPluginUnknown('test_foo')
882
866
 
883
867
    def test_loading_from_specific_file(self):
890
874
''' % ('test_foo', plugin_path)
891
875
        self.create_plugin('test_foo', source=source,
892
876
                           dir=plugin_dir, file_name=plugin_file_name)
893
 
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@%s' % plugin_path)
894
 
        plugin.load_plugins(['standard'])
 
877
        self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@%s' % plugin_path)
 
878
        self.load_with_paths(['standard'])
895
879
        self.assertTestFooLoadedFrom(plugin_path)
 
880
 
 
881
 
 
882
class TestDescribePlugins(BaseTestPlugins):
 
883
 
 
884
    def test_describe_plugins(self):
 
885
        class DummyModule(object):
 
886
            __doc__ = 'Hi there'
 
887
 
 
888
        class DummyPlugin(object):
 
889
            __version__ = '0.1.0'
 
890
            module = DummyModule()
 
891
        self.plugin_warnings = {'bad': ['Failed to load (just testing)']}
 
892
        self.plugins = {'good': DummyPlugin()}
 
893
        self.assertEqual("""\
 
894
bad (failed to load)
 
895
  ** Failed to load (just testing)
 
896
 
 
897
good 0.1.0
 
898
  Hi there
 
899
 
 
900
""", ''.join(plugin.describe_plugins(state=self)))
 
901
 
 
902
 
 
903
class DummyPlugin(object):
 
904
    """Plugin."""
 
905
 
 
906
 
 
907
class TestLoadEnvPlugin(BaseTestPlugins):
 
908
 
 
909
    _test_needs_features = [pkg_resources_feature]
 
910
 
 
911
    def setup_plugin(self, source=""):
 
912
        # This test tests a new plugin appears in breezy.plugin.plugins().
 
913
        # check the plugin is not loaded already
 
914
        self.assertPluginUnknown('plugin')
 
915
        # write a plugin that _cannot_ fail to load.
 
916
        import pkg_resources
 
917
        d = pkg_resources.Distribution(__file__)
 
918
        ep = pkg_resources.EntryPoint.parse(
 
919
            'plugin = ' + __name__ + ':DummyPlugin', dist=d)
 
920
        d._ep_map = {'breezy.plugin': {'plugin': ep}}
 
921
        pkg_resources.working_set.add(d, 'plugin', replace=True)
 
922
        eps = list(pkg_resources.iter_entry_points('breezy.plugin'))
 
923
        self.assertEqual(['plugin'], [ep.name for ep in eps])
 
924
        self.load_with_paths(['.'])
 
925
        self.addCleanup(d._ep_map.clear)
 
926
 
 
927
    def test_plugin_loaded(self):
 
928
        self.assertPluginUnknown('plugin')
 
929
        self.overrideEnv('BRZ_PLUGIN_PATH', '+entrypoints')
 
930
        self.setup_plugin()
 
931
        p = self.plugins['plugin']
 
932
        self.assertIsInstance(p, breezy.plugin.PlugIn)
 
933
        self.assertIs(p.module, sys.modules[self.module_prefix + 'plugin'])
 
934
 
 
935
    def test_plugin_loaded_disabled(self):
 
936
        self.assertPluginUnknown('plugin')
 
937
        self.overrideEnv('BRZ_PLUGIN_PATH', '+entrypoints')
 
938
        self.overrideEnv('BRZ_DISABLE_PLUGINS', 'plugin')
 
939
        self.setup_plugin()
 
940
        self.assertNotIn('plugin', self.plugins)