~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_plugins.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-05-11 11:47:36 UTC
  • mfrom: (5200.3.8 lock_return)
  • Revision ID: pqm@pqm.ubuntu.com-20100511114736-mc1sq9zyo3vufec7
(lifeless) Provide a consistent interface to Tree, Branch,
 Repository where lock methods return an object with an unlock method to
 unlock the lock. This breaks the API for Branch,
 Repository on their lock_write methods. (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2011 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
27
27
 
28
28
import bzrlib
29
29
from bzrlib import (
30
 
    errors,
31
30
    osutils,
32
31
    plugin,
33
32
    plugins,
38
37
 
39
38
# TODO: Write a test for plugin decoration of commands.
40
39
 
41
 
class BaseTestPlugins(tests.TestCaseInTempDir):
 
40
class TestPluginMixin(object):
42
41
 
43
42
    def create_plugin(self, name, source=None, dir='.', file_name=None):
44
43
        if source is None:
80
79
        if getattr(bzrlib.plugins, name, None) is not None:
81
80
            delattr(bzrlib.plugins, name)
82
81
 
83
 
    def _unregister_plugin_submodule(self, plugin_name, submodule_name):
84
 
        """Remove the submodule from sys.modules and the bzrlib namespace."""
85
 
        py_name = 'bzrlib.plugins.%s.%s' % (plugin_name, submodule_name)
86
 
        if py_name in sys.modules:
87
 
            del sys.modules[py_name]
88
 
        plugin = getattr(bzrlib.plugins, plugin_name, None)
89
 
        if plugin is not None:
90
 
            if getattr(plugin, submodule_name, None) is not None:
91
 
                delattr(plugin, submodule_name)
92
 
 
93
82
    def assertPluginUnknown(self, name):
94
 
        self.assertFalse(getattr(bzrlib.plugins, name, None) is not None)
95
 
        self.assertFalse('bzrlib.plugins.%s' % name in sys.modules)
 
83
        self.failIf(getattr(bzrlib.plugins, name, None) is not None)
 
84
        self.failIf('bzrlib.plugins.%s' % name in sys.modules)
96
85
 
97
86
    def assertPluginKnown(self, name):
98
 
        self.assertTrue(getattr(bzrlib.plugins, name, None) is not None)
99
 
        self.assertTrue('bzrlib.plugins.%s' % name in sys.modules)
100
 
 
101
 
 
102
 
class TestLoadingPlugins(BaseTestPlugins):
 
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):
103
92
 
104
93
    activeattributes = {}
105
94
 
109
98
        # file name we can use which is also a valid attribute for accessing in
110
99
        # activeattributes. - we cannot give import parameters.
111
100
        tempattribute = "0"
112
 
        self.assertFalse(tempattribute in self.activeattributes)
 
101
        self.failIf(tempattribute in self.activeattributes)
113
102
        # set a place for the plugins to record their loading, and at the same
114
103
        # time validate that the location the plugins should record to is
115
104
        # valid and correct.
116
105
        self.__class__.activeattributes [tempattribute] = []
117
 
        self.assertTrue(tempattribute in self.activeattributes)
 
106
        self.failUnless(tempattribute in self.activeattributes)
118
107
        # create two plugin directories
119
108
        os.mkdir('first')
120
109
        os.mkdir('second')
147
136
        self.assertPluginUnknown('plugin')
148
137
 
149
138
    def test_plugins_from_different_dirs_can_demand_load(self):
150
 
        self.assertFalse('bzrlib.plugins.pluginone' in sys.modules)
151
 
        self.assertFalse('bzrlib.plugins.plugintwo' in sys.modules)
 
139
        self.failIf('bzrlib.plugins.pluginone' in sys.modules)
 
140
        self.failIf('bzrlib.plugins.plugintwo' in sys.modules)
152
141
        # This test tests that having two plugins in different
153
142
        # directories with different names allows them both to be loaded, when
154
143
        # we do a direct import statement.
155
144
        # Determine a file name we can use which is also a valid attribute
156
145
        # for accessing in activeattributes. - we cannot give import parameters.
157
146
        tempattribute = "different-dirs"
158
 
        self.assertFalse(tempattribute in self.activeattributes)
 
147
        self.failIf(tempattribute in self.activeattributes)
159
148
        # set a place for the plugins to record their loading, and at the same
160
149
        # time validate that the location the plugins should record to is
161
150
        # valid and correct.
162
151
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
163
152
            [tempattribute] = []
164
 
        self.assertTrue(tempattribute in self.activeattributes)
 
153
        self.failUnless(tempattribute in self.activeattributes)
165
154
        # create two plugin directories
166
155
        os.mkdir('first')
167
156
        os.mkdir('second')
186
175
 
187
176
        oldpath = bzrlib.plugins.__path__
188
177
        try:
189
 
            self.assertFalse('bzrlib.plugins.pluginone' in sys.modules)
190
 
            self.assertFalse('bzrlib.plugins.plugintwo' in sys.modules)
 
178
            self.failIf('bzrlib.plugins.pluginone' in sys.modules)
 
179
            self.failIf('bzrlib.plugins.plugintwo' in sys.modules)
191
180
            bzrlib.plugins.__path__ = ['first', 'second']
192
181
            exec "import bzrlib.plugins.pluginone"
193
182
            self.assertEqual(['first'], self.activeattributes[tempattribute])
208
197
        # check the plugin is not loaded already
209
198
        self.assertPluginUnknown('ts_plugin')
210
199
        tempattribute = "trailing-slash"
211
 
        self.assertFalse(tempattribute in self.activeattributes)
 
200
        self.failIf(tempattribute in self.activeattributes)
212
201
        # set a place for the plugin to record its loading, and at the same
213
202
        # time validate that the location the plugin should record to is
214
203
        # valid and correct.
215
204
        bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
216
205
            [tempattribute] = []
217
 
        self.assertTrue(tempattribute in self.activeattributes)
 
206
        self.failUnless(tempattribute in self.activeattributes)
218
207
        # create a directory for the plugin
219
208
        os.mkdir('plugin_test')
220
209
        # write a plugin that will record when its loaded in the
267
256
            stream.close()
268
257
 
269
258
    def test_plugin_with_bad_api_version_reports(self):
270
 
        """Try loading a plugin that requests an unsupported api.
271
 
        
272
 
        Observe that it records the problem but doesn't complain on stderr.
273
 
 
274
 
        See https://bugs.launchpad.net/bzr/+bug/704195
275
 
        """
276
 
        self.overrideAttr(plugin, 'plugin_warnings', {})
 
259
        # This plugin asks for bzrlib api version 1.0.0, which is not supported
 
260
        # anymore.
277
261
        name = 'wants100.py'
278
262
        f = file(name, 'w')
279
263
        try:
281
265
                "bzrlib.api.require_any_api(bzrlib, [(1, 0, 0)])\n")
282
266
        finally:
283
267
            f.close()
 
268
 
284
269
        log = self.load_and_capture(name)
285
 
        self.assertNotContainsRe(log,
286
 
            r"It requested API version")
287
 
        self.assertEquals(
288
 
            ['wants100'],
289
 
            plugin.plugin_warnings.keys())
290
 
        self.assertContainsRe(
291
 
            plugin.plugin_warnings['wants100'][0],
 
270
        self.assertContainsRe(log,
292
271
            r"It requested API version")
293
272
 
294
273
    def test_plugin_with_bad_name_does_not_load(self):
302
281
            "it to 'bad_plugin_name_'\.")
303
282
 
304
283
 
305
 
class TestPlugins(BaseTestPlugins):
 
284
class TestPlugins(tests.TestCaseInTempDir, TestPluginMixin):
306
285
 
307
286
    def setup_plugin(self, source=""):
308
287
        # This test tests a new plugin appears in bzrlib.plugin.plugins().
452
431
    def test_final_fallback__version__with_version_info(self):
453
432
        self.setup_plugin("version_info = (1, 2, 3, 'final', 2)")
454
433
        plugin = bzrlib.plugin.plugins()['plugin']
455
 
        self.assertEqual("1.2.3.2", plugin.__version__)
 
434
        self.assertEqual("1.2.3.final.2", plugin.__version__)
456
435
 
457
436
 
458
437
class TestPluginHelp(tests.TestCaseInTempDir):
615
594
    def test_get_help_text_with_additional_see_also(self):
616
595
        mod = FakeModule('two lines of help\nand more', 'demo')
617
596
        topic = plugin.ModuleHelpTopic(mod)
618
 
        self.assertEqual("two lines of help\nand more\n\n:See also: bar, foo\n",
619
 
                         topic.get_help_text(['foo', 'bar']))
 
597
        self.assertEqual("two lines of help\nand more\nSee also: bar, foo\n",
 
598
            topic.get_help_text(['foo', 'bar']))
620
599
 
621
600
    def test_get_help_topic(self):
622
601
        """The help topic for a plugin is its module name."""
623
602
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.demo')
624
603
        topic = plugin.ModuleHelpTopic(mod)
625
604
        self.assertEqual('demo', topic.get_help_topic())
626
 
        mod = FakeModule('two lines of help\nand more',
627
 
                         'bzrlib.plugins.foo_bar')
 
605
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.foo_bar')
628
606
        topic = plugin.ModuleHelpTopic(mod)
629
607
        self.assertEqual('foo_bar', topic.get_help_topic())
630
608
 
667
645
                    self.fail('No path to global plugins')
668
646
 
669
647
    def test_get_standard_plugins_path_env(self):
670
 
        self.overrideEnv('BZR_PLUGIN_PATH', 'foo/')
 
648
        os.environ['BZR_PLUGIN_PATH'] = 'foo/'
671
649
        path = plugin.get_standard_plugins_path()
672
650
        for directory in path:
673
651
            self.assertNotContainsRe(directory, r'\\/$')
703
681
 
704
682
    def _set_path(self, *args):
705
683
        path = os.pathsep.join(self._list2paths(*args))
706
 
        self.overrideEnv('BZR_PLUGIN_PATH', path)
 
684
        osutils.set_or_unset_env('BZR_PLUGIN_PATH', path)
707
685
 
708
686
    def check_path(self, expected_dirs, setting_dirs):
709
687
        if setting_dirs:
779
757
                        ['+foo', '-bar'])
780
758
 
781
759
 
782
 
class TestDisablePlugin(BaseTestPlugins):
 
760
class TestDisablePlugin(tests.TestCaseInTempDir, TestPluginMixin):
783
761
 
784
762
    def setUp(self):
785
763
        super(TestDisablePlugin, self).setUp()
790
768
        self.addCleanup(self._unregister_plugin, 'test_foo')
791
769
 
792
770
    def test_cannot_import(self):
793
 
        self.overrideEnv('BZR_DISABLE_PLUGINS', 'test_foo')
 
771
        osutils.set_or_unset_env('BZR_DISABLE_PLUGINS', 'test_foo')
794
772
        plugin.set_plugins_path(['.'])
795
773
        try:
796
774
            import bzrlib.plugins.test_foo
812
790
        self.overrideAttr(trace, 'warning', captured_warning)
813
791
        # Reset the flag that protect against double loading
814
792
        self.overrideAttr(plugin, '_loaded', False)
815
 
        self.overrideEnv('BZR_DISABLE_PLUGINS', 'test_foo')
 
793
        osutils.set_or_unset_env('BZR_DISABLE_PLUGINS', 'test_foo')
816
794
        plugin.load_plugins(['.'])
817
795
        self.assertPluginUnknown('test_foo')
818
796
        # Make sure we don't warn about the plugin ImportError since this has
820
798
        self.assertLength(0, self.warnings)
821
799
 
822
800
 
823
 
 
824
 
class TestLoadPluginAtSyntax(tests.TestCase):
825
 
 
826
 
    def _get_paths(self, paths):
827
 
        return plugin._get_specific_plugin_paths(paths)
828
 
 
829
 
    def test_empty(self):
830
 
        self.assertEquals([], self._get_paths(None))
831
 
        self.assertEquals([], self._get_paths(''))
832
 
 
833
 
    def test_one_path(self):
834
 
        self.assertEquals([('b', 'man')], self._get_paths('b@man'))
835
 
 
836
 
    def test_bogus_path(self):
837
 
        # We need a '@'
838
 
        self.assertRaises(errors.BzrCommandError, self._get_paths, 'batman')
839
 
        # Too much '@' isn't good either
840
 
        self.assertRaises(errors.BzrCommandError, self._get_paths,
841
 
                          'batman@mobile@cave')
842
 
        # An empty description probably indicates a problem
843
 
        self.assertRaises(errors.BzrCommandError, self._get_paths,
844
 
                          os.pathsep.join(['batman@cave', '', 'robin@mobile']))
845
 
 
846
 
 
847
 
class TestLoadPluginAt(BaseTestPlugins):
 
801
class TestLoadPluginAt(tests.TestCaseInTempDir, TestPluginMixin):
848
802
 
849
803
    def setUp(self):
850
804
        super(TestLoadPluginAt, self).setUp()
851
805
        # Make sure we don't pollute the plugins namespace
852
806
        self.overrideAttr(plugins, '__path__')
 
807
        # Be paranoid in case a test fail
 
808
        self.addCleanup(self._unregister_plugin, 'test_foo')
853
809
        # Reset the flag that protect against double loading
854
810
        self.overrideAttr(plugin, '_loaded', False)
855
811
        # Create the same plugin in two directories
857
813
        # The "normal" directory, we use 'standard' instead of 'plugins' to
858
814
        # avoid depending on the precise naming.
859
815
        self.create_plugin_package('test_foo', dir='standard/test_foo')
860
 
        # All the tests will load the 'test_foo' plugin from various locations
861
 
        self.addCleanup(self._unregister_plugin, 'test_foo')
862
 
        # Unfortunately there's global cached state for the specific
863
 
        # registered paths.
864
 
        self.addCleanup(plugin.PluginImporter.reset)
865
816
 
866
817
    def assertTestFooLoadedFrom(self, path):
867
818
        self.assertPluginKnown('test_foo')
874
825
        self.assertTestFooLoadedFrom('standard/test_foo')
875
826
 
876
827
    def test_import(self):
877
 
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
 
828
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
878
829
        plugin.set_plugins_path(['standard'])
879
830
        try:
880
831
            import bzrlib.plugins.test_foo
883
834
        self.assertTestFooLoadedFrom('non-standard-dir')
884
835
 
885
836
    def test_loading(self):
886
 
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
 
837
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
887
838
        plugin.load_plugins(['standard'])
888
839
        self.assertTestFooLoadedFrom('non-standard-dir')
889
840
 
890
841
    def test_compiled_loaded(self):
891
 
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
 
842
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
892
843
        plugin.load_plugins(['standard'])
893
844
        self.assertTestFooLoadedFrom('non-standard-dir')
894
 
        self.assertIsSameRealPath('non-standard-dir/__init__.py',
895
 
                                  bzrlib.plugins.test_foo.__file__)
 
845
        self.assertEqual('non-standard-dir/__init__.py',
 
846
                         bzrlib.plugins.test_foo.__file__)
896
847
 
897
848
        # Try importing again now that the source has been compiled
898
849
        self._unregister_plugin('test_foo')
903
854
            suffix = 'pyc'
904
855
        else:
905
856
            suffix = 'pyo'
906
 
        self.assertIsSameRealPath('non-standard-dir/__init__.%s' % suffix,
907
 
                                  bzrlib.plugins.test_foo.__file__)
 
857
        self.assertEqual('non-standard-dir/__init__.%s' % suffix,
 
858
                         bzrlib.plugins.test_foo.__file__)
908
859
 
909
860
    def test_submodule_loading(self):
910
861
        # We create an additional directory under the one for test_foo
911
862
        self.create_plugin_package('test_bar', dir='non-standard-dir/test_bar')
912
 
        self.addCleanup(self._unregister_plugin_submodule,
913
 
                        'test_foo', 'test_bar')
914
 
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
 
863
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
915
864
        plugin.set_plugins_path(['standard'])
916
865
        import bzrlib.plugins.test_foo
917
866
        self.assertEqual('bzrlib.plugins.test_foo',
918
867
                         bzrlib.plugins.test_foo.__package__)
919
868
        import bzrlib.plugins.test_foo.test_bar
920
 
        self.assertIsSameRealPath('non-standard-dir/test_bar/__init__.py',
921
 
                                  bzrlib.plugins.test_foo.test_bar.__file__)
922
 
 
923
 
    def test_relative_submodule_loading(self):
924
 
        self.create_plugin_package('test_foo', dir='another-dir', source='''
925
 
import test_bar
926
 
''')
927
 
        # We create an additional directory under the one for test_foo
928
 
        self.create_plugin_package('test_bar', dir='another-dir/test_bar')
929
 
        self.addCleanup(self._unregister_plugin_submodule,
930
 
                        'test_foo', 'test_bar')
931
 
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@another-dir')
932
 
        plugin.set_plugins_path(['standard'])
933
 
        import bzrlib.plugins.test_foo
934
 
        self.assertEqual('bzrlib.plugins.test_foo',
935
 
                         bzrlib.plugins.test_foo.__package__)
936
 
        self.assertIsSameRealPath('another-dir/test_bar/__init__.py',
937
 
                                  bzrlib.plugins.test_foo.test_bar.__file__)
 
869
        self.assertEqual('non-standard-dir/test_bar/__init__.py',
 
870
                         bzrlib.plugins.test_foo.test_bar.__file__)
938
871
 
939
872
    def test_loading_from___init__only(self):
940
873
        # We rename the existing __init__.py file to ensure that we don't load
943
876
        random = 'non-standard-dir/setup.py'
944
877
        os.rename(init, random)
945
878
        self.addCleanup(os.rename, random, init)
946
 
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
 
879
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@non-standard-dir')
947
880
        plugin.load_plugins(['standard'])
948
881
        self.assertPluginUnknown('test_foo')
949
882
 
957
890
''' % ('test_foo', plugin_path)
958
891
        self.create_plugin('test_foo', source=source,
959
892
                           dir=plugin_dir, file_name=plugin_file_name)
960
 
        self.overrideEnv('BZR_PLUGINS_AT', 'test_foo@%s' % plugin_path)
 
893
        osutils.set_or_unset_env('BZR_PLUGINS_AT', 'test_foo@%s' % plugin_path)
961
894
        plugin.load_plugins(['standard'])
962
895
        self.assertTestFooLoadedFrom(plugin_path)
963
 
 
964
 
 
965
 
class TestDescribePlugins(BaseTestPlugins):
966
 
 
967
 
    def test_describe_plugins(self):
968
 
        class DummyModule(object):
969
 
            __doc__ = 'Hi there'
970
 
        class DummyPlugin(object):
971
 
            __version__ = '0.1.0'
972
 
            module = DummyModule()
973
 
        def dummy_plugins():
974
 
            return { 'good': DummyPlugin() }
975
 
        self.overrideAttr(plugin, 'plugin_warnings',
976
 
            {'bad': ['Failed to load (just testing)']})
977
 
        self.overrideAttr(plugin, 'plugins', dummy_plugins)
978
 
        self.assertEquals("""\
979
 
bad (failed to load)
980
 
  ** Failed to load (just testing)
981
 
 
982
 
good 0.1.0
983
 
  Hi there
984
 
 
985
 
""", ''.join(plugin.describe_plugins()))