/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 bzrlib/tests/test_plugins.py

  • Committer: Jelmer Vernooij
  • Date: 2010-03-21 21:39:33 UTC
  • mfrom: (5102 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5143.
  • Revision ID: jelmer@samba.org-20100321213933-fexeh9zcoz8oaju2
merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2007 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
20
20
# affects the global state of the process.  See bzrlib/plugins.py for more
21
21
# comments.
22
22
 
 
23
from cStringIO import StringIO
23
24
import logging
24
25
import os
25
 
from StringIO import StringIO
26
26
import sys
27
 
import zipfile
28
27
 
 
28
import bzrlib
29
29
from bzrlib import (
30
30
    osutils,
31
31
    plugin,
 
32
    plugins,
32
33
    tests,
33
 
    )
34
 
import bzrlib.plugin
35
 
import bzrlib.plugins
36
 
import bzrlib.commands
37
 
import bzrlib.help
38
 
from bzrlib.tests import (
39
 
    TestCase,
40
 
    TestCaseInTempDir,
41
 
    TestUtil,
42
 
    )
43
 
from bzrlib.osutils import pathjoin, abspath, normpath
44
 
 
45
 
 
46
 
PLUGIN_TEXT = """\
47
 
import bzrlib.commands
48
 
class cmd_myplug(bzrlib.commands.Command):
49
 
    '''Just a simple test plugin.'''
50
 
    aliases = ['mplg']
51
 
    def run(self):
52
 
        print 'Hello from my plugin'
53
 
"""
 
34
    trace,
 
35
    )
 
36
 
54
37
 
55
38
# TODO: Write a test for plugin decoration of commands.
56
39
 
57
 
class TestLoadingPlugins(TestCaseInTempDir):
 
40
class TestPluginMixin(object):
 
41
 
 
42
    def create_plugin(self, name, source='', dir='.', file_name=None):
 
43
        if file_name is None:
 
44
            file_name = name + '.py'
 
45
        # 'source' must not fail to load
 
46
        path = osutils.pathjoin(dir, file_name)
 
47
        f = open(path, 'w')
 
48
        self.addCleanup(os.unlink, path)
 
49
        try:
 
50
            f.write(source + '\n')
 
51
        finally:
 
52
            f.close()
 
53
 
 
54
    def create_plugin_package(self, name, source='', dir='.'):
 
55
        plugin_dir = osutils.pathjoin(dir, name)
 
56
        os.mkdir(plugin_dir)
 
57
        self.addCleanup(osutils.rmtree, plugin_dir)
 
58
        self.create_plugin(name, source, dir=plugin_dir,
 
59
                           file_name='__init__.py')
 
60
 
 
61
    def _unregister_plugin(self, name):
 
62
        """Remove the plugin from sys.modules and the bzrlib namespace."""
 
63
        py_name = 'bzrlib.plugins.%s' % name
 
64
        if py_name in sys.modules:
 
65
            del sys.modules[py_name]
 
66
        if getattr(bzrlib.plugins, name, None) is not None:
 
67
            delattr(bzrlib.plugins, name)
 
68
 
 
69
    def assertPluginUnknown(self, name):
 
70
        self.failIf(getattr(bzrlib.plugins, name, None) is not None)
 
71
        self.failIf('bzrlib.plugins.%s' % name in sys.modules)
 
72
 
 
73
    def assertPluginKnown(self, name):
 
74
        self.failUnless(getattr(bzrlib.plugins, name, None) is not None)
 
75
        self.failUnless('bzrlib.plugins.%s' % name in sys.modules)
 
76
 
 
77
 
 
78
class TestLoadingPlugins(tests.TestCaseInTempDir, TestPluginMixin):
58
79
 
59
80
    activeattributes = {}
60
81
 
68
89
        # set a place for the plugins to record their loading, and at the same
69
90
        # time validate that the location the plugins should record to is
70
91
        # valid and correct.
71
 
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
72
 
            [tempattribute] = []
 
92
        self.__class__.activeattributes [tempattribute] = []
73
93
        self.failUnless(tempattribute in self.activeattributes)
74
94
        # create two plugin directories
75
95
        os.mkdir('first')
99
119
        finally:
100
120
            # remove the plugin 'plugin'
101
121
            del self.activeattributes[tempattribute]
102
 
            if 'bzrlib.plugins.plugin' in sys.modules:
103
 
                del sys.modules['bzrlib.plugins.plugin']
104
 
            if getattr(bzrlib.plugins, 'plugin', None):
105
 
                del bzrlib.plugins.plugin
106
 
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
 
122
            self._unregister_plugin('plugin')
 
123
        self.assertPluginUnknown('plugin')
107
124
 
108
125
    def test_plugins_from_different_dirs_can_demand_load(self):
 
126
        self.failIf('bzrlib.plugins.pluginone' in sys.modules)
 
127
        self.failIf('bzrlib.plugins.plugintwo' in sys.modules)
109
128
        # This test tests that having two plugins in different
110
129
        # directories with different names allows them both to be loaded, when
111
130
        # we do a direct import statement.
143
162
 
144
163
        oldpath = bzrlib.plugins.__path__
145
164
        try:
 
165
            self.failIf('bzrlib.plugins.pluginone' in sys.modules)
 
166
            self.failIf('bzrlib.plugins.plugintwo' in sys.modules)
146
167
            bzrlib.plugins.__path__ = ['first', 'second']
147
168
            exec "import bzrlib.plugins.pluginone"
148
169
            self.assertEqual(['first'], self.activeattributes[tempattribute])
152
173
        finally:
153
174
            # remove the plugin 'plugin'
154
175
            del self.activeattributes[tempattribute]
155
 
            if getattr(bzrlib.plugins, 'pluginone', None):
156
 
                del bzrlib.plugins.pluginone
157
 
            if getattr(bzrlib.plugins, 'plugintwo', None):
158
 
                del bzrlib.plugins.plugintwo
159
 
        self.failIf(getattr(bzrlib.plugins, 'pluginone', None))
160
 
        self.failIf(getattr(bzrlib.plugins, 'plugintwo', None))
 
176
            self._unregister_plugin('pluginone')
 
177
            self._unregister_plugin('plugintwo')
 
178
        self.assertPluginUnknown('pluginone')
 
179
        self.assertPluginUnknown('plugintwo')
161
180
 
162
181
    def test_plugins_can_load_from_directory_with_trailing_slash(self):
163
182
        # This test tests that a plugin can load from a directory when the
164
183
        # directory in the path has a trailing slash.
165
184
        # check the plugin is not loaded already
166
 
        self.failIf(getattr(bzrlib.plugins, 'ts_plugin', None))
 
185
        self.assertPluginUnknown('ts_plugin')
167
186
        tempattribute = "trailing-slash"
168
187
        self.failIf(tempattribute in self.activeattributes)
169
188
        # set a place for the plugin to record its loading, and at the same
190
209
            bzrlib.plugin.load_from_path(['plugin_test'+os.sep])
191
210
            self.assertEqual(['plugin'], self.activeattributes[tempattribute])
192
211
        finally:
193
 
            # remove the plugin 'plugin'
194
212
            del self.activeattributes[tempattribute]
195
 
            if getattr(bzrlib.plugins, 'ts_plugin', None):
196
 
                del bzrlib.plugins.ts_plugin
197
 
        self.failIf(getattr(bzrlib.plugins, 'ts_plugin', None))
 
213
            self._unregister_plugin('ts_plugin')
 
214
        self.assertPluginUnknown('ts_plugin')
198
215
 
199
216
    def load_and_capture(self, name):
200
217
        """Load plugins from '.' capturing the output.
251
268
            "it to 'bad_plugin_name_'\.")
252
269
 
253
270
 
254
 
class TestPlugins(TestCaseInTempDir):
 
271
class TestPlugins(tests.TestCaseInTempDir, TestPluginMixin):
255
272
 
256
273
    def setup_plugin(self, source=""):
257
274
        # This test tests a new plugin appears in bzrlib.plugin.plugins().
258
275
        # check the plugin is not loaded already
259
 
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
 
276
        self.assertPluginUnknown('plugin')
260
277
        # write a plugin that _cannot_ fail to load.
261
278
        file('plugin.py', 'w').write(source + '\n')
262
279
        self.addCleanup(self.teardown_plugin)
263
 
        bzrlib.plugin.load_from_path(['.'])
 
280
        plugin.load_from_path(['.'])
264
281
 
265
282
    def teardown_plugin(self):
266
 
        # remove the plugin 'plugin'
267
 
        if 'bzrlib.plugins.plugin' in sys.modules:
268
 
            del sys.modules['bzrlib.plugins.plugin']
269
 
        if getattr(bzrlib.plugins, 'plugin', None):
270
 
            del bzrlib.plugins.plugin
271
 
        self.failIf(getattr(bzrlib.plugins, 'plugin', None))
 
283
        self._unregister_plugin('plugin')
 
284
        self.assertPluginUnknown('plugin')
272
285
 
273
286
    def test_plugin_appears_in_plugins(self):
274
287
        self.setup_plugin()
275
 
        self.failUnless('plugin' in bzrlib.plugin.plugins())
276
 
        self.failUnless(getattr(bzrlib.plugins, 'plugin', None))
277
 
        plugins = bzrlib.plugin.plugins()
278
 
        plugin = plugins['plugin']
279
 
        self.assertIsInstance(plugin, bzrlib.plugin.PlugIn)
280
 
        self.assertEqual(bzrlib.plugins.plugin, plugin.module)
 
288
        self.assertPluginKnown('plugin')
 
289
        p = plugin.plugins()['plugin']
 
290
        self.assertIsInstance(p, bzrlib.plugin.PlugIn)
 
291
        self.assertEqual(p.module, plugins.plugin)
281
292
 
282
293
    def test_trivial_plugin_get_path(self):
283
294
        self.setup_plugin()
284
 
        plugins = bzrlib.plugin.plugins()
285
 
        plugin = plugins['plugin']
 
295
        p = plugin.plugins()['plugin']
286
296
        plugin_path = self.test_dir + '/plugin.py'
287
 
        self.assertIsSameRealPath(plugin_path, normpath(plugin.path()))
 
297
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
288
298
 
289
299
    def test_plugin_get_path_py_not_pyc(self):
290
 
        self.setup_plugin()         # after first import there will be plugin.pyc
 
300
        # first import creates plugin.pyc
 
301
        self.setup_plugin()
291
302
        self.teardown_plugin()
292
 
        bzrlib.plugin.load_from_path(['.']) # import plugin.pyc
293
 
        plugins = bzrlib.plugin.plugins()
294
 
        plugin = plugins['plugin']
 
303
        plugin.load_from_path(['.']) # import plugin.pyc
 
304
        p = plugin.plugins()['plugin']
295
305
        plugin_path = self.test_dir + '/plugin.py'
296
 
        self.assertIsSameRealPath(plugin_path, normpath(plugin.path()))
 
306
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
297
307
 
298
308
    def test_plugin_get_path_pyc_only(self):
299
 
        self.setup_plugin()         # after first import there will be plugin.pyc
 
309
        # first import creates plugin.pyc (or plugin.pyo depending on __debug__)
 
310
        self.setup_plugin()
300
311
        self.teardown_plugin()
301
312
        os.unlink(self.test_dir + '/plugin.py')
302
 
        bzrlib.plugin.load_from_path(['.']) # import plugin.pyc
303
 
        plugins = bzrlib.plugin.plugins()
304
 
        plugin = plugins['plugin']
 
313
        plugin.load_from_path(['.']) # import plugin.pyc (or .pyo)
 
314
        p = plugin.plugins()['plugin']
305
315
        if __debug__:
306
316
            plugin_path = self.test_dir + '/plugin.pyc'
307
317
        else:
308
318
            plugin_path = self.test_dir + '/plugin.pyo'
309
 
        self.assertIsSameRealPath(plugin_path, normpath(plugin.path()))
 
319
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
310
320
 
311
321
    def test_no_test_suite_gives_None_for_test_suite(self):
312
322
        self.setup_plugin()
313
 
        plugin = bzrlib.plugin.plugins()['plugin']
314
 
        self.assertEqual(None, plugin.test_suite())
 
323
        p = plugin.plugins()['plugin']
 
324
        self.assertEqual(None, p.test_suite())
315
325
 
316
326
    def test_test_suite_gives_test_suite_result(self):
317
327
        source = """def test_suite(): return 'foo'"""
318
328
        self.setup_plugin(source)
319
 
        plugin = bzrlib.plugin.plugins()['plugin']
320
 
        self.assertEqual('foo', plugin.test_suite())
 
329
        p = plugin.plugins()['plugin']
 
330
        self.assertEqual('foo', p.test_suite())
321
331
 
322
332
    def test_no_load_plugin_tests_gives_None_for_load_plugin_tests(self):
323
333
        self.setup_plugin()
324
 
        loader = TestUtil.TestLoader()
325
 
        plugin = bzrlib.plugin.plugins()['plugin']
326
 
        self.assertEqual(None, plugin.load_plugin_tests(loader))
 
334
        loader = tests.TestUtil.TestLoader()
 
335
        p = plugin.plugins()['plugin']
 
336
        self.assertEqual(None, p.load_plugin_tests(loader))
327
337
 
328
338
    def test_load_plugin_tests_gives_load_plugin_tests_result(self):
329
339
        source = """
330
340
def load_tests(standard_tests, module, loader):
331
341
    return 'foo'"""
332
342
        self.setup_plugin(source)
333
 
        loader = TestUtil.TestLoader()
334
 
        plugin = bzrlib.plugin.plugins()['plugin']
335
 
        self.assertEqual('foo', plugin.load_plugin_tests(loader))
 
343
        loader = tests.TestUtil.TestLoader()
 
344
        p = plugin.plugins()['plugin']
 
345
        self.assertEqual('foo', p.load_plugin_tests(loader))
 
346
 
 
347
    def check_version_info(self, expected, source='', name='plugin'):
 
348
        self.setup_plugin(source)
 
349
        self.assertEqual(expected, plugin.plugins()[name].version_info())
336
350
 
337
351
    def test_no_version_info(self):
338
 
        self.setup_plugin()
339
 
        plugin = bzrlib.plugin.plugins()['plugin']
340
 
        self.assertEqual(None, plugin.version_info())
 
352
        self.check_version_info(None)
341
353
 
342
354
    def test_with_version_info(self):
343
 
        self.setup_plugin("version_info = (1, 2, 3, 'dev', 4)")
344
 
        plugin = bzrlib.plugin.plugins()['plugin']
345
 
        self.assertEqual((1, 2, 3, 'dev', 4), plugin.version_info())
 
355
        self.check_version_info((1, 2, 3, 'dev', 4),
 
356
                                "version_info = (1, 2, 3, 'dev', 4)")
346
357
 
347
358
    def test_short_version_info_gets_padded(self):
348
359
        # the gtk plugin has version_info = (1,2,3) rather than the 5-tuple.
349
360
        # so we adapt it
350
 
        self.setup_plugin("version_info = (1, 2, 3)")
351
 
        plugin = bzrlib.plugin.plugins()['plugin']
352
 
        self.assertEqual((1, 2, 3, 'final', 0), plugin.version_info())
 
361
        self.check_version_info((1, 2, 3, 'final', 0),
 
362
                                "version_info = (1, 2, 3)")
 
363
 
 
364
    def check_version(self, expected, source=None, name='plugin'):
 
365
        self.setup_plugin(source)
 
366
        self.assertEqual(expected, plugins[name].__version__)
353
367
 
354
368
    def test_no_version_info___version__(self):
355
369
        self.setup_plugin()
407
421
        self.assertEqual("1.2.3.final.2", plugin.__version__)
408
422
 
409
423
 
410
 
class TestPluginHelp(TestCaseInTempDir):
 
424
class TestPluginHelp(tests.TestCaseInTempDir):
411
425
 
412
426
    def split_help_commands(self):
413
427
        help = {}
442
456
    def test_plugin_help_shows_plugin(self):
443
457
        # Create a test plugin
444
458
        os.mkdir('plugin_test')
445
 
        f = open(pathjoin('plugin_test', 'myplug.py'), 'w')
446
 
        f.write(PLUGIN_TEXT)
 
459
        f = open(osutils.pathjoin('plugin_test', 'myplug.py'), 'w')
 
460
        f.write("""\
 
461
from bzrlib import commands
 
462
class cmd_myplug(commands.Command):
 
463
    '''Just a simple test plugin.'''
 
464
    aliases = ['mplg']
 
465
    def run(self):
 
466
        print 'Hello from my plugin'
 
467
 
 
468
"""
 
469
)
447
470
        f.close()
448
471
 
449
472
        try:
575
598
 
576
599
    def setUp(self):
577
600
        super(TestLoadFromPath, self).setUp()
578
 
        # Save the attributes that we're about to monkey-patch.
579
 
        old_plugins_path = bzrlib.plugins.__path__
580
 
        old_loaded = plugin._loaded
581
 
        old_load_from_path = plugin.load_from_path
582
 
 
583
 
        def restore():
584
 
            bzrlib.plugins.__path__ = old_plugins_path
585
 
            plugin._loaded = old_loaded
586
 
            plugin.load_from_path = old_load_from_path
587
 
 
588
 
        self.addCleanup(restore)
589
 
 
590
601
        # Change bzrlib.plugin to think no plugins have been loaded yet.
591
 
        bzrlib.plugins.__path__ = []
592
 
        plugin._loaded = False
 
602
        self.overrideAttr(bzrlib.plugins, '__path__', [])
 
603
        self.overrideAttr(plugin, '_loaded', False)
593
604
 
594
605
        # Monkey-patch load_from_path to stop it from actually loading anything.
595
 
        def load_from_path(dirs):
596
 
            pass
597
 
        plugin.load_from_path = load_from_path
 
606
        self.overrideAttr(plugin, 'load_from_path', lambda dirs: None)
598
607
 
599
608
    def test_set_plugins_path_with_args(self):
600
609
        plugin.set_plugins_path(['a', 'b'])
641
650
        self.assertEqual(path, bzrlib.plugins.__path__)
642
651
 
643
652
 
644
 
class TestEnvPluginPath(tests.TestCaseInTempDir):
 
653
class TestEnvPluginPath(tests.TestCase):
645
654
 
646
655
    def setUp(self):
647
656
        super(TestEnvPluginPath, self).setUp()
648
 
        old_default = plugin.DEFAULT_PLUGIN_PATH
649
 
 
650
 
        def restore():
651
 
            plugin.DEFAULT_PLUGIN_PATH = old_default
652
 
 
653
 
        self.addCleanup(restore)
654
 
 
655
 
        plugin.DEFAULT_PLUGIN_PATH = None
 
657
        self.overrideAttr(plugin, 'DEFAULT_PLUGIN_PATH', None)
656
658
 
657
659
        self.user = plugin.get_user_plugin_path()
658
660
        self.site = plugin.get_site_plugin_path()
701
703
        self.check_path([self.user, self.core, self.site],
702
704
                        ['+user', '+user'])
703
705
        # And only the first reference is kept (since the later references will
704
 
        # onnly produce <plugin> already loaded mutters)
 
706
        # only produce '<plugin> already loaded' mutters)
705
707
        self.check_path([self.user, self.core, self.site],
706
708
                        ['+user', '+user', '+core',
707
709
                         '+user', '+site', '+site',
708
710
                         '+core'])
709
711
 
710
 
    def test_disable_overrides_disable(self):
 
712
    def test_disable_overrides_enable(self):
711
713
        self.check_path([self.core, self.site], ['-user', '+user'])
712
714
 
713
715
    def test_disable_core(self):
740
742
    def test_bogus_references(self):
741
743
        self.check_path(['+foo', '-bar', self.core, self.site],
742
744
                        ['+foo', '-bar'])
 
745
 
 
746
 
 
747
class TestDisablePlugin(tests.TestCaseInTempDir, TestPluginMixin):
 
748
 
 
749
    def setUp(self):
 
750
        super(TestDisablePlugin, self).setUp()
 
751
        self.create_plugin_package('test_foo')
 
752
        # Make sure we don't pollute the plugins namespace
 
753
        self.overrideAttr(plugins, '__path__')
 
754
        # Be paranoid in case a test fail
 
755
        self.addCleanup(self._unregister_plugin, 'test_foo')
 
756
 
 
757
    def test_cannot_import(self):
 
758
        osutils.set_or_unset_env('BZR_DISABLE_PLUGINS', 'test_foo')
 
759
        plugin.set_plugins_path(['.'])
 
760
        try:
 
761
            import bzrlib.plugins.test_foo
 
762
        except ImportError:
 
763
            pass
 
764
        self.assertPluginUnknown('test_foo')
 
765
 
 
766
    def test_regular_load(self):
 
767
        self.overrideAttr(plugin, '_loaded', False)
 
768
        plugin.load_plugins(['.'])
 
769
        self.assertPluginKnown('test_foo')
 
770
 
 
771
    def test_not_loaded(self):
 
772
        self.warnings = []
 
773
        def captured_warning(*args, **kwargs):
 
774
            self.warnings.append((args, kwargs))
 
775
        self.overrideAttr(trace, 'warning', captured_warning)
 
776
        self.overrideAttr(plugin, '_loaded', False)
 
777
        osutils.set_or_unset_env('BZR_DISABLE_PLUGINS', 'test_foo')
 
778
        plugin.load_plugins(plugin.set_plugins_path(['.']))
 
779
        self.assertPluginUnknown('test_foo')
 
780
        # Make sure we don't warn about the plugin ImportError since this has
 
781
        # been *requested* by the user.
 
782
        self.assertLength(0, self.warnings)