~bzr-pqm/bzr/bzr.dev

2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2005 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
750 by Martin Pool
- stubbed-out tests for python plugins
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
750 by Martin Pool
- stubbed-out tests for python plugins
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
12
#
750 by Martin Pool
- stubbed-out tests for python plugins
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Tests for plugins"""
18
1185.16.83 by mbp at sourcefrog
- notes on testability of plugins
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
import os
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
24
from StringIO import StringIO
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
25
import sys
2215.4.1 by Alexander Belchenko
Bugfix #68124: Allow plugins import from zip archives.
26
import zipfile
750 by Martin Pool
- stubbed-out tests for python plugins
27
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
28
import bzrlib.plugin
29
import bzrlib.plugins
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
30
import bzrlib.commands
31
import bzrlib.help
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
32
from bzrlib.tests import TestCase, TestCaseInTempDir
1185.31.37 by John Arbash Meinel
Switched os.path.abspath and os.path.realpath to osutils.* (still passes on cygwin)
33
from bzrlib.osutils import pathjoin, abspath
1141 by Martin Pool
- rename FunctionalTest to TestCaseInTempDir
34
1185.16.83 by mbp at sourcefrog
- notes on testability of plugins
35
1185.16.84 by mbp at sourcefrog
- fix indents
36
PLUGIN_TEXT = """\
37
import bzrlib.commands
38
class cmd_myplug(bzrlib.commands.Command):
39
    '''Just a simple test plugin.'''
40
    aliases = ['mplg']
41
    def run(self):
42
        print 'Hello from my plugin'
43
"""
1492 by Robert Collins
Support decoration of commands.
44
45
# TODO: Write a test for plugin decoration of commands.
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
46
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
47
class TestLoadingPlugins(TestCaseInTempDir):
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
48
49
    activeattributes = {}
50
51
    def test_plugins_with_the_same_name_are_not_loaded(self):
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
52
        # This test tests that having two plugins in different directories does
53
        # not result in both being loaded when they have the same name.  get a
54
        # file name we can use which is also a valid attribute for accessing in
55
        # activeattributes. - we cannot give import parameters.
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
56
        tempattribute = "0"
57
        self.failIf(tempattribute in self.activeattributes)
58
        # set a place for the plugins to record their loading, and at the same
59
        # time validate that the location the plugins should record to is
60
        # valid and correct.
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
61
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
62
            [tempattribute] = []
63
        self.failUnless(tempattribute in self.activeattributes)
64
        # create two plugin directories
65
        os.mkdir('first')
66
        os.mkdir('second')
67
        # write a plugin that will record when its loaded in the 
68
        # tempattribute list.
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
69
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
70
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
71
        print >> file(os.path.join('first', 'plugin.py'), 'w'), template % (tempattribute, 'first')
72
        print >> file(os.path.join('second', 'plugin.py'), 'w'), template % (tempattribute, 'second')
73
        try:
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
74
            bzrlib.plugin.load_from_path(['first', 'second'])
75
            self.assertEqual(['first'], self.activeattributes[tempattribute])
76
        finally:
77
            # remove the plugin 'plugin'
78
            del self.activeattributes[tempattribute]
79
            if getattr(bzrlib.plugins, 'plugin', None):
80
                del bzrlib.plugins.plugin
81
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
82
83
    def test_plugins_from_different_dirs_can_demand_load(self):
84
        # This test tests that having two plugins in different
85
        # directories with different names allows them both to be loaded, when
86
        # we do a direct import statement.
87
        # Determine a file name we can use which is also a valid attribute
88
        # for accessing in activeattributes. - we cannot give import parameters.
89
        tempattribute = "different-dirs"
90
        self.failIf(tempattribute in self.activeattributes)
91
        # set a place for the plugins to record their loading, and at the same
92
        # time validate that the location the plugins should record to is
93
        # valid and correct.
94
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
95
            [tempattribute] = []
96
        self.failUnless(tempattribute in self.activeattributes)
97
        # create two plugin directories
98
        os.mkdir('first')
99
        os.mkdir('second')
100
        # write plugins that will record when they are loaded in the 
101
        # tempattribute list.
102
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
103
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
104
        print >> file(os.path.join('first', 'pluginone.py'), 'w'), template % (tempattribute, 'first')
105
        print >> file(os.path.join('second', 'plugintwo.py'), 'w'), template % (tempattribute, 'second')
106
        oldpath = bzrlib.plugins.__path__
107
        try:
108
            bzrlib.plugins.__path__ = ['first', 'second']
109
            exec "import bzrlib.plugins.pluginone"
110
            self.assertEqual(['first'], self.activeattributes[tempattribute])
111
            exec "import bzrlib.plugins.plugintwo"
112
            self.assertEqual(['first', 'second'],
113
                self.activeattributes[tempattribute])
1515 by Robert Collins
* Plugins with the same name in different directories in the bzr plugin
114
        finally:
115
            # remove the plugin 'plugin'
116
            del self.activeattributes[tempattribute]
117
            if getattr(bzrlib.plugins, 'plugin', None):
118
                del bzrlib.plugins.plugin
119
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
1516 by Robert Collins
* bzrlib.plugin.all_plugins has been changed from an attribute to a
120
121
122
class TestAllPlugins(TestCaseInTempDir):
123
124
    def test_plugin_appears_in_all_plugins(self):
125
        # This test tests a new plugin appears in bzrlib.plugin.all_plugins().
126
        # check the plugin is not loaded already
127
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
128
        # write a plugin that _cannot_ fail to load.
129
        print >> file('plugin.py', 'w'), ""
130
        try:
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
131
            bzrlib.plugin.load_from_path(['.'])
1516 by Robert Collins
* bzrlib.plugin.all_plugins has been changed from an attribute to a
132
            self.failUnless('plugin' in bzrlib.plugin.all_plugins())
133
            self.failUnless(getattr(bzrlib.plugins, 'plugin', None))
134
            self.assertEqual(bzrlib.plugin.all_plugins()['plugin'],
135
                             bzrlib.plugins.plugin)
136
        finally:
137
            # remove the plugin 'plugin'
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
138
            if 'bzrlib.plugins.plugin' in sys.modules:
139
                del sys.modules['bzrlib.plugins.plugin']
1516 by Robert Collins
* bzrlib.plugin.all_plugins has been changed from an attribute to a
140
            if getattr(bzrlib.plugins, 'plugin', None):
141
                del bzrlib.plugins.plugin
142
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
143
144
145
class TestPluginHelp(TestCaseInTempDir):
146
147
    def split_help_commands(self):
148
        help = {}
149
        current = None
150
        for line in self.capture('help commands').splitlines():
2034.1.2 by Aaron Bentley
Fix testcase
151
            if not line.startswith(' '):
152
                current = line.split()[0]
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
153
            help[current] = help.get(current, '') + line
154
155
        return help
156
157
    def test_plugin_help_builtins_unaffected(self):
158
        # Check we don't get false positives
159
        help_commands = self.split_help_commands()
160
        for cmd_name in bzrlib.commands.builtin_command_names():
161
            if cmd_name in bzrlib.commands.plugin_command_names():
162
                continue
163
            help = StringIO()
164
            try:
165
                bzrlib.help.help_on_command(cmd_name, help)
166
            except NotImplementedError:
167
                # some commands have no help
168
                pass
169
            else:
170
                help.seek(0)
171
                self.assertNotContainsRe(help.read(), 'From plugin "[^"]*"')
172
173
            if help in help_commands.keys():
174
                # some commands are hidden
175
                help = help_commands[cmd_name]
176
                self.assertNotContainsRe(help, 'From plugin "[^"]*"')
177
178
    def test_plugin_help_shows_plugin(self):
179
        # Create a test plugin
180
        os.mkdir('plugin_test')
181
        f = open(pathjoin('plugin_test', 'myplug.py'), 'w')
182
        f.write(PLUGIN_TEXT)
183
        f.close()
184
185
        try:
186
            # Check its help
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
187
            bzrlib.plugin.load_from_path(['plugin_test'])
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
188
            bzrlib.commands.register_command( bzrlib.plugins.myplug.cmd_myplug)
189
            help = self.capture('help myplug')
190
            self.assertContainsRe(help, 'From plugin "myplug"')
191
            help = self.split_help_commands()['myplug']
2034.1.4 by Aaron Bentley
Change angle brackets to square brackets
192
            self.assertContainsRe(help, '\[myplug\]')
1733.2.5 by Michael Ellerman
Show which plugin (if any) provides a command.
193
        finally:
2204.3.2 by Alexander Belchenko
cherrypicking: test_plugin_help_shows_plugin: fix cleanup after test
194
            # unregister command
195
            if bzrlib.commands.plugin_cmds.get('myplug', None):
196
                del bzrlib.commands.plugin_cmds['myplug']
197
            # remove the plugin 'myplug'
198
            if getattr(bzrlib.plugins, 'myplug', None):
199
                delattr(bzrlib.plugins, 'myplug')
2215.4.1 by Alexander Belchenko
Bugfix #68124: Allow plugins import from zip archives.
200
201
202
class TestPluginFromZip(TestCaseInTempDir):
203
204
    def make_zipped_plugin(self, zip_name, filename):
205
        z = zipfile.ZipFile(zip_name, 'w')
206
        z.writestr(filename, PLUGIN_TEXT)
207
        z.close()
208
209
    def check_plugin_load(self, zip_name, plugin_name):
210
        self.assertFalse(plugin_name in dir(bzrlib.plugins),
211
                         'Plugin already loaded')
212
        try:
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
213
            bzrlib.plugin.load_from_zip(zip_name)
2215.4.1 by Alexander Belchenko
Bugfix #68124: Allow plugins import from zip archives.
214
            self.assertTrue(plugin_name in dir(bzrlib.plugins),
215
                            'Plugin is not loaded')
216
        finally:
217
            # unregister plugin
218
            if getattr(bzrlib.plugins, plugin_name, None):
219
                delattr(bzrlib.plugins, plugin_name)
220
221
    def test_load_module(self):
222
        self.make_zipped_plugin('./test.zip', 'ziplug.py')
223
        self.check_plugin_load('./test.zip', 'ziplug')
224
225
    def test_load_package(self):
226
        self.make_zipped_plugin('./test.zip', 'ziplug/__init__.py')
227
        self.check_plugin_load('./test.zip', 'ziplug')
2256.2.2 by Robert Collins
Allow 'import bzrlib.plugins.NAME' to work when the plugin NAME has not
228
229
230
class TestSetPluginsPath(TestCase):
231
    
232
    def test_set_plugins_path(self):
233
        """set_plugins_path should set the module __path__ correctly."""
234
        old_path = bzrlib.plugins.__path__
235
        try:
236
            bzrlib.plugins.__path__ = []
237
            expected_path = bzrlib.plugin.set_plugins_path()
238
            self.assertEqual(expected_path, bzrlib.plugins.__path__)
239
        finally:
240
            bzrlib.plugins.__path__ = old_path