/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-05-24 00:42:36 UTC
  • mto: This revision was merged to the branch mainline in revision 7505.
  • Revision ID: jelmer@jelmer.uk-20200524004236-jdj6obo4k5lznqw2
Cleanup Windows functions.

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