/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-06 02:13:25 UTC
  • mfrom: (7490.7.21 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200506021325-awbmmqu1zyorz7sj
Merge 3.1 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012, 2016 Canonical Ltd, 2017 Breezy developers
 
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
 
try:
20
 
    from importlib.util import module_from_spec
21
 
except ImportError:  # python < 3
22
 
    from imp import new_module as module_from_spec
23
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
27
import breezy
29
28
from .. import (
30
 
    errors,
31
29
    osutils,
32
30
    plugin,
33
31
    tests,
34
 
    trace,
35
 
    )
36
 
from ..sixish import (
37
 
    PY3,
38
 
    StringIO,
39
 
    viewkeys,
40
 
    )
 
32
    )
 
33
from ..tests.features import pkg_resources_feature
41
34
 
42
35
 
43
36
# TODO: Write a test for plugin decoration of commands.
52
45
        super(BaseTestPlugins, self).setUp()
53
46
        self.module_name = "breezy.testingplugins"
54
47
        self.module_prefix = self.module_name + "."
55
 
        self.module = module_from_spec(self.module_name)
 
48
        self.module = types.ModuleType(self.module_name)
56
49
 
57
50
        self.overrideAttr(plugin, "_MODULE_PREFIX", self.module_prefix)
58
51
        self.overrideAttr(breezy, "testingplugins", self.module)
120
113
                rel = osutils.relpath(self.test_dir, cache_dir)
121
114
                self.log("moving %s in %s to %s", name, rel, magicless_name)
122
115
                os.rename(os.path.join(cache_dir, name),
123
 
                    os.path.join(directory, magicless_name))
 
116
                          os.path.join(directory, magicless_name))
124
117
 
125
118
    def _unregister_finder(self):
126
119
        """Removes any test copies of _PluginsAtFinder from sys.meta_path."""
142
135
    def assertPluginModules(self, plugin_dict):
143
136
        self.assertEqual(
144
137
            dict((k[len(self.module_prefix):], sys.modules[k])
145
 
                for k in sys.modules if k.startswith(self.module_prefix)),
 
138
                 for k in sys.modules if k.startswith(self.module_prefix)),
146
139
            plugin_dict)
147
140
 
148
141
    def assertPluginUnknown(self, name):
168
161
        # set a place for the plugins to record their loading, and at the same
169
162
        # time validate that the location the plugins should record to is
170
163
        # valid and correct.
171
 
        self.__class__.activeattributes [tempattribute] = []
 
164
        self.__class__.activeattributes[tempattribute] = []
172
165
        self.assertTrue(tempattribute in self.activeattributes)
173
166
        # create two plugin directories
174
167
        os.mkdir('first')
205
198
        # set a place for the plugins to record their loading, and at the same
206
199
        # time validate that the location the plugins should record to is
207
200
        # valid and correct.
208
 
        breezy.tests.test_plugins.TestLoadingPlugins.activeattributes \
209
 
            [tempattribute] = []
 
201
        breezy.tests.test_plugins.TestLoadingPlugins.activeattributes[tempattribute] = [
 
202
            ]
210
203
        self.assertTrue(tempattribute in self.activeattributes)
211
204
        # create two plugin directories
212
205
        os.mkdir('first')
232
225
            self.assertEqual(['first'], self.activeattributes[tempattribute])
233
226
            exec("import %splugintwo" % self.module_prefix)
234
227
            self.assertEqual(['first', 'second'],
235
 
                self.activeattributes[tempattribute])
 
228
                             self.activeattributes[tempattribute])
236
229
        finally:
237
230
            del self.activeattributes[tempattribute]
238
231
 
246
239
        # set a place for the plugin to record its loading, and at the same
247
240
        # time validate that the location the plugin should record to is
248
241
        # valid and correct.
249
 
        breezy.tests.test_plugins.TestLoadingPlugins.activeattributes \
250
 
            [tempattribute] = []
 
242
        breezy.tests.test_plugins.TestLoadingPlugins.activeattributes[tempattribute] = [
 
243
            ]
251
244
        self.assertTrue(tempattribute in self.activeattributes)
252
245
        # create a directory for the plugin
253
246
        os.mkdir('plugin_test')
261
254
            outfile.write('\n')
262
255
 
263
256
        try:
264
 
            self.load_with_paths(['plugin_test'+os.sep])
 
257
            self.load_with_paths(['plugin_test' + os.sep])
265
258
            self.assertEqual(['plugin'], self.activeattributes[tempattribute])
266
259
            self.assertPluginKnown('ts_plugin')
267
260
        finally:
300
293
        name = 'wants100.py'
301
294
        with open(name, 'w') as f:
302
295
            f.write("import breezy\n"
303
 
                "from breezy.errors import IncompatibleVersion\n"
304
 
                "raise IncompatibleVersion(breezy, [(1, 0, 0)], (0, 0, 5))\n")
 
296
                    "from breezy.errors import IncompatibleVersion\n"
 
297
                    "raise IncompatibleVersion(breezy, [(1, 0, 0)], (0, 0, 5))\n")
305
298
        log = self.load_and_capture(name)
306
299
        self.assertNotContainsRe(log,
307
 
            r"It supports breezy version")
308
 
        self.assertEqual({'wants100'}, viewkeys(self.plugin_warnings))
 
300
                                 r"It supports breezy version")
 
301
        self.assertEqual({'wants100'}, self.plugin_warnings.keys())
309
302
        self.assertContainsRe(
310
303
            self.plugin_warnings['wants100'][0],
311
304
            r"It supports breezy version")
316
309
        open(name, 'w').close()
317
310
        log = self.load_and_capture(name)
318
311
        self.assertContainsRe(log,
319
 
            r"Unable to load 'brz-bad plugin-name\.' in '\.' as a plugin "
320
 
            "because the file path isn't a valid module name; try renaming "
321
 
            "it to 'bad_plugin_name_'\\.")
 
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_'\\.")
322
315
 
323
316
 
324
317
class TestPlugins(BaseTestPlugins):
328
321
        # check the plugin is not loaded already
329
322
        self.assertPluginUnknown('plugin')
330
323
        # write a plugin that _cannot_ fail to load.
331
 
        with open('plugin.py', 'w') as f: f.write(source + '\n')
 
324
        with open('plugin.py', 'w') as f:
 
325
            f.write(source + '\n')
332
326
        self.load_with_paths(['.'])
333
327
 
334
328
    def test_plugin_loaded(self):
363
357
        self.setup_plugin()
364
358
        self.promote_cache(self.test_dir)
365
359
        self.reset()
366
 
        self.load_with_paths(['.']) # import plugin.pyc
 
360
        self.load_with_paths(['.'])  # import plugin.pyc
367
361
        p = plugin.plugins()['plugin']
368
362
        plugin_path = self.test_dir + '/plugin.py'
369
363
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
374
368
        os.unlink(self.test_dir + '/plugin.py')
375
369
        self.promote_cache(self.test_dir)
376
370
        self.reset()
377
 
        self.load_with_paths(['.']) # import plugin.pyc (or .pyo)
 
371
        self.load_with_paths(['.'])  # import plugin.pyc (or .pyo)
378
372
        p = plugin.plugins()['plugin']
379
373
        plugin_path = self.test_dir + '/plugin' + plugin.COMPILED_EXT
380
374
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
482
476
        self.assertEqual("1.2.3.2", plugin.__version__)
483
477
 
484
478
 
485
 
# GZ 2017-06-02: Move this suite to blackbox, as it's what it actually is.
486
 
class TestPluginHelp(BaseTestPlugins):
487
 
 
488
 
    def split_help_commands(self):
489
 
        help = {}
490
 
        current = None
491
 
        out, err = self.run_bzr('--no-plugins help commands')
492
 
        for line in out.splitlines():
493
 
            if not line.startswith(' '):
494
 
                current = line.split()[0]
495
 
            help[current] = help.get(current, '') + line
496
 
 
497
 
        return help
498
 
 
499
 
    def test_plugin_help_builtins_unaffected(self):
500
 
        # Check we don't get false positives
501
 
        help_commands = self.split_help_commands()
502
 
        for cmd_name in breezy.commands.builtin_command_names():
503
 
            if cmd_name in breezy.commands.plugin_command_names():
504
 
                continue
505
 
            try:
506
 
                help = breezy.commands.get_cmd_object(cmd_name).get_help_text()
507
 
            except NotImplementedError:
508
 
                # some commands have no help
509
 
                pass
510
 
            else:
511
 
                self.assertNotContainsRe(help, 'plugin "[^"]*"')
512
 
 
513
 
            if cmd_name in help_commands:
514
 
                # some commands are hidden
515
 
                help = help_commands[cmd_name]
516
 
                self.assertNotContainsRe(help, 'plugin "[^"]*"')
517
 
 
518
 
    def test_plugin_help_shows_plugin(self):
519
 
        # Create a test plugin
520
 
        os.mkdir('plugin_test')
521
 
        source = (
522
 
            "from breezy import commands\n"
523
 
            "class cmd_myplug(commands.Command):\n"
524
 
            "    __doc__ = '''Just a simple test plugin.'''\n"
525
 
            "    aliases = ['mplg']\n"
526
 
            "    def run(self):\n"
527
 
            "        print ('Hello from my plugin')\n"
528
 
        )
529
 
        self.create_plugin('myplug', source, 'plugin_test')
530
 
 
531
 
        # Check its help
532
 
        self.load_with_paths(['plugin_test'])
533
 
        myplug = self.plugins['myplug'].module
534
 
        breezy.commands.register_command(myplug.cmd_myplug)
535
 
        self.addCleanup(breezy.commands.plugin_cmds.remove, 'myplug')
536
 
        help = self.run_bzr('help myplug')[0]
537
 
        self.assertContainsRe(help, 'plugin "myplug"')
538
 
        help = self.split_help_commands()['myplug']
539
 
        self.assertContainsRe(help, '\\[myplug\\]')
540
 
 
541
 
 
542
479
class TestHelpIndex(tests.TestCase):
543
480
    """Tests for the PluginsHelpIndex class."""
544
481
 
615
552
        mod = FakeModule(None, 'demo')
616
553
        topic = plugin.ModuleHelpTopic(mod)
617
554
        self.assertEqual("Plugin 'demo' has no docstring.\n",
618
 
            topic.get_help_text())
 
555
                         topic.get_help_text())
619
556
 
620
557
    def test_get_help_text_no_carriage_return(self):
621
558
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
622
559
        mod = FakeModule('one line of help', 'demo')
623
560
        topic = plugin.ModuleHelpTopic(mod)
624
561
        self.assertEqual("one line of help\n",
625
 
            topic.get_help_text())
 
562
                         topic.get_help_text())
626
563
 
627
564
    def test_get_help_text_carriage_return(self):
628
565
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
629
566
        mod = FakeModule('two lines of help\nand more\n', 'demo')
630
567
        topic = plugin.ModuleHelpTopic(mod)
631
568
        self.assertEqual("two lines of help\nand more\n",
632
 
            topic.get_help_text())
 
569
                         topic.get_help_text())
633
570
 
634
571
    def test_get_help_text_with_additional_see_also(self):
635
572
        mod = FakeModule('two lines of help\nand more', 'demo')
636
573
        topic = plugin.ModuleHelpTopic(mod)
637
 
        self.assertEqual("two lines of help\nand more\n\n:See also: bar, foo\n",
638
 
                         topic.get_help_text(['foo', 'bar']))
 
574
        self.assertEqual(
 
575
            "two lines of help\nand more\n\n:See also: bar, foo\n",
 
576
            topic.get_help_text(['foo', 'bar']))
639
577
 
640
578
    def test_get_help_topic(self):
641
579
        """The help topic for a plugin is its module name."""
653
591
    user = "USER"
654
592
    core = "CORE"
655
593
    site = "SITE"
 
594
    entrypoints = "ENTRYPOINTS"
656
595
 
657
596
    def check_path(self, expected_dirs, setting_dirs):
658
597
        if setting_dirs is None:
660
599
        else:
661
600
            os.environ['BRZ_PLUGIN_PATH'] = os.pathsep.join(setting_dirs)
662
601
        actual = [(p if t == 'path' else t.upper())
663
 
            for p, t in plugin._env_plugin_path()]
 
602
                  for p, t in plugin._env_plugin_path()]
664
603
        self.assertEqual(expected_dirs, actual)
665
604
 
666
605
    def test_default(self):
667
 
        self.check_path([self.user, self.core, self.site],
668
 
                        None)
 
606
        self.check_path([self.user, self.core, self.site], None)
669
607
 
670
608
    def test_adhoc_policy(self):
671
609
        self.check_path([self.user, self.core, self.site],
679
617
        self.check_path([self.user, self.site, self.core],
680
618
                        ['+user', '+site', '+core'])
681
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
 
682
624
    def test_disable_user(self):
683
625
        self.check_path([self.core, self.site], ['-user'])
684
626
 
720
662
                        ['mycore', '-core'])
721
663
 
722
664
    def test_my_plugin_only(self):
723
 
        self.check_path(['myplugin'], ['myplugin', '-user', '-core', '-site'])
 
665
        self.check_path(
 
666
            ['myplugin'],
 
667
            ['myplugin', '-user', '-core', '-site', '-entrypoints'])
724
668
 
725
669
    def test_my_plugin_first(self):
726
670
        self.check_path(['myplugin', self.core, self.site, self.user],
753
697
        self.create_plugin_package('ugly')
754
698
        self.overrideEnv('BRZ_DISABLE_PLUGINS', 'bad:ugly')
755
699
        self.load_with_paths(['.'])
756
 
        self.assertEqual({'good'}, viewkeys(self.plugins))
 
700
        self.assertEqual({'good'}, self.plugins.keys())
757
701
        self.assertPluginModules({
758
702
            'good': self.plugins['good'].module,
759
703
            'bad': None,
786
730
    def test_mixed(self):
787
731
        value = os.pathsep.join(['valid', 'in-valid'])
788
732
        self.assertEqual(['valid'], self._get_names(value))
789
 
        self.assertContainsRe(self.get_log(),
 
733
        self.assertContainsRe(
 
734
            self.get_log(),
790
735
            r"Invalid name 'in-valid' in BRZ_DISABLE_PLUGINS=" + repr(value))
791
736
 
792
737
 
821
766
 
822
767
    def test_bad_name(self):
823
768
        self.assertEqual([], self._get_paths('/usr/local/bzr-git'))
824
 
        self.assertContainsRe(self.get_log(),
 
769
        self.assertContainsRe(
 
770
            self.get_log(),
825
771
            r"Invalid name 'bzr-git' in BRZ_PLUGINS_AT='/usr/local/bzr-git'")
826
772
 
827
773
 
884
830
        self.create_plugin_package('test_bar', dir='non-standard-dir/test_bar')
885
831
        self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
886
832
        self.update_module_paths(['standard'])
887
 
        import breezy.testingplugins.test_foo
 
833
        import breezy.testingplugins.test_foo  # noqa: F401
888
834
        self.assertEqual(self.module_prefix + 'test_foo',
889
835
                         self.module.test_foo.__package__)
890
 
        import breezy.testingplugins.test_foo.test_bar
 
836
        import breezy.testingplugins.test_foo.test_bar  # noqa: F401
891
837
        self.assertIsSameRealPath('non-standard-dir/test_bar/__init__.py',
892
838
                                  self.module.test_foo.test_bar.__file__)
893
839
 
899
845
        self.create_plugin_package('test_bar', dir='another-dir/test_bar')
900
846
        self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@another-dir')
901
847
        self.update_module_paths(['standard'])
902
 
        import breezy.testingplugins.test_foo
 
848
        import breezy.testingplugins.test_foo  # noqa: F401
903
849
        self.assertEqual(self.module_prefix + 'test_foo',
904
850
                         self.module.test_foo.__package__)
905
851
        self.assertIsSameRealPath('another-dir/test_bar/__init__.py',
935
881
    def test_describe_plugins(self):
936
882
        class DummyModule(object):
937
883
            __doc__ = 'Hi there'
 
884
 
938
885
        class DummyPlugin(object):
939
886
            __version__ = '0.1.0'
940
887
            module = DummyModule()
948
895
  Hi there
949
896
 
950
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)