/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: 2018-05-06 11:48:54 UTC
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@jelmer.uk-20180506114854-h4qd9ojaqy8wxjsd
Move .mailmap to root.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012, 2016 Canonical Ltd
2
 
# Copyright (C) 2017-2018 Breezy developers
 
1
# Copyright (C) 2005-2012, 2016 Canonical Ltd, 2017 Breezy developers
3
2
#
4
3
# This program is free software; you can redistribute it and/or modify
5
4
# it under the terms of the GNU General Public License as published by
17
16
 
18
17
"""Tests for plugins"""
19
18
 
 
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
20
23
import importlib
21
24
import logging
22
25
import os
23
26
import sys
24
 
import types
25
27
 
26
28
import breezy
27
29
from .. import (
 
30
    errors,
28
31
    osutils,
29
32
    plugin,
30
33
    tests,
 
34
    trace,
31
35
    )
32
 
from ..tests.features import pkg_resources_feature
33
36
from ..sixish import (
 
37
    PY3,
34
38
    StringIO,
35
39
    viewkeys,
36
40
    )
48
52
        super(BaseTestPlugins, self).setUp()
49
53
        self.module_name = "breezy.testingplugins"
50
54
        self.module_prefix = self.module_name + "."
51
 
        self.module = types.ModuleType(self.module_name)
 
55
        self.module = module_from_spec(self.module_name)
52
56
 
53
57
        self.overrideAttr(plugin, "_MODULE_PREFIX", self.module_prefix)
54
58
        self.overrideAttr(breezy, "testingplugins", self.module)
116
120
                rel = osutils.relpath(self.test_dir, cache_dir)
117
121
                self.log("moving %s in %s to %s", name, rel, magicless_name)
118
122
                os.rename(os.path.join(cache_dir, name),
119
 
                          os.path.join(directory, magicless_name))
 
123
                    os.path.join(directory, magicless_name))
120
124
 
121
125
    def _unregister_finder(self):
122
126
        """Removes any test copies of _PluginsAtFinder from sys.meta_path."""
138
142
    def assertPluginModules(self, plugin_dict):
139
143
        self.assertEqual(
140
144
            dict((k[len(self.module_prefix):], sys.modules[k])
141
 
                 for k in sys.modules if k.startswith(self.module_prefix)),
 
145
                for k in sys.modules if k.startswith(self.module_prefix)),
142
146
            plugin_dict)
143
147
 
144
148
    def assertPluginUnknown(self, name):
164
168
        # set a place for the plugins to record their loading, and at the same
165
169
        # time validate that the location the plugins should record to is
166
170
        # valid and correct.
167
 
        self.__class__.activeattributes[tempattribute] = []
 
171
        self.__class__.activeattributes [tempattribute] = []
168
172
        self.assertTrue(tempattribute in self.activeattributes)
169
173
        # create two plugin directories
170
174
        os.mkdir('first')
201
205
        # set a place for the plugins to record their loading, and at the same
202
206
        # time validate that the location the plugins should record to is
203
207
        # valid and correct.
204
 
        breezy.tests.test_plugins.TestLoadingPlugins.activeattributes[tempattribute] = [
205
 
            ]
 
208
        breezy.tests.test_plugins.TestLoadingPlugins.activeattributes \
 
209
            [tempattribute] = []
206
210
        self.assertTrue(tempattribute in self.activeattributes)
207
211
        # create two plugin directories
208
212
        os.mkdir('first')
228
232
            self.assertEqual(['first'], self.activeattributes[tempattribute])
229
233
            exec("import %splugintwo" % self.module_prefix)
230
234
            self.assertEqual(['first', 'second'],
231
 
                             self.activeattributes[tempattribute])
 
235
                self.activeattributes[tempattribute])
232
236
        finally:
233
237
            del self.activeattributes[tempattribute]
234
238
 
242
246
        # set a place for the plugin to record its loading, and at the same
243
247
        # time validate that the location the plugin should record to is
244
248
        # valid and correct.
245
 
        breezy.tests.test_plugins.TestLoadingPlugins.activeattributes[tempattribute] = [
246
 
            ]
 
249
        breezy.tests.test_plugins.TestLoadingPlugins.activeattributes \
 
250
            [tempattribute] = []
247
251
        self.assertTrue(tempattribute in self.activeattributes)
248
252
        # create a directory for the plugin
249
253
        os.mkdir('plugin_test')
257
261
            outfile.write('\n')
258
262
 
259
263
        try:
260
 
            self.load_with_paths(['plugin_test' + os.sep])
 
264
            self.load_with_paths(['plugin_test'+os.sep])
261
265
            self.assertEqual(['plugin'], self.activeattributes[tempattribute])
262
266
            self.assertPluginKnown('ts_plugin')
263
267
        finally:
296
300
        name = 'wants100.py'
297
301
        with open(name, 'w') as f:
298
302
            f.write("import breezy\n"
299
 
                    "from breezy.errors import IncompatibleVersion\n"
300
 
                    "raise IncompatibleVersion(breezy, [(1, 0, 0)], (0, 0, 5))\n")
 
303
                "from breezy.errors import IncompatibleVersion\n"
 
304
                "raise IncompatibleVersion(breezy, [(1, 0, 0)], (0, 0, 5))\n")
301
305
        log = self.load_and_capture(name)
302
306
        self.assertNotContainsRe(log,
303
 
                                 r"It supports breezy version")
 
307
            r"It supports breezy version")
304
308
        self.assertEqual({'wants100'}, viewkeys(self.plugin_warnings))
305
309
        self.assertContainsRe(
306
310
            self.plugin_warnings['wants100'][0],
312
316
        open(name, 'w').close()
313
317
        log = self.load_and_capture(name)
314
318
        self.assertContainsRe(log,
315
 
                              r"Unable to load 'brz-bad plugin-name\.' in '\.' as a plugin "
316
 
                              "because the file path isn't a valid module name; try renaming "
317
 
                              "it to 'bad_plugin_name_'\\.")
 
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_'\\.")
318
322
 
319
323
 
320
324
class TestPlugins(BaseTestPlugins):
324
328
        # check the plugin is not loaded already
325
329
        self.assertPluginUnknown('plugin')
326
330
        # write a plugin that _cannot_ fail to load.
327
 
        with open('plugin.py', 'w') as f:
328
 
            f.write(source + '\n')
 
331
        with open('plugin.py', 'w') as f: f.write(source + '\n')
329
332
        self.load_with_paths(['.'])
330
333
 
331
334
    def test_plugin_loaded(self):
360
363
        self.setup_plugin()
361
364
        self.promote_cache(self.test_dir)
362
365
        self.reset()
363
 
        self.load_with_paths(['.'])  # import plugin.pyc
 
366
        self.load_with_paths(['.']) # import plugin.pyc
364
367
        p = plugin.plugins()['plugin']
365
368
        plugin_path = self.test_dir + '/plugin.py'
366
369
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
371
374
        os.unlink(self.test_dir + '/plugin.py')
372
375
        self.promote_cache(self.test_dir)
373
376
        self.reset()
374
 
        self.load_with_paths(['.'])  # import plugin.pyc (or .pyo)
 
377
        self.load_with_paths(['.']) # import plugin.pyc (or .pyo)
375
378
        p = plugin.plugins()['plugin']
376
379
        plugin_path = self.test_dir + '/plugin' + plugin.COMPILED_EXT
377
380
        self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
479
482
        self.assertEqual("1.2.3.2", plugin.__version__)
480
483
 
481
484
 
 
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
 
482
542
class TestHelpIndex(tests.TestCase):
483
543
    """Tests for the PluginsHelpIndex class."""
484
544
 
555
615
        mod = FakeModule(None, 'demo')
556
616
        topic = plugin.ModuleHelpTopic(mod)
557
617
        self.assertEqual("Plugin 'demo' has no docstring.\n",
558
 
                         topic.get_help_text())
 
618
            topic.get_help_text())
559
619
 
560
620
    def test_get_help_text_no_carriage_return(self):
561
621
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
562
622
        mod = FakeModule('one line of help', 'demo')
563
623
        topic = plugin.ModuleHelpTopic(mod)
564
624
        self.assertEqual("one line of help\n",
565
 
                         topic.get_help_text())
 
625
            topic.get_help_text())
566
626
 
567
627
    def test_get_help_text_carriage_return(self):
568
628
        """ModuleHelpTopic.get_help_text adds a \n if needed."""
569
629
        mod = FakeModule('two lines of help\nand more\n', 'demo')
570
630
        topic = plugin.ModuleHelpTopic(mod)
571
631
        self.assertEqual("two lines of help\nand more\n",
572
 
                         topic.get_help_text())
 
632
            topic.get_help_text())
573
633
 
574
634
    def test_get_help_text_with_additional_see_also(self):
575
635
        mod = FakeModule('two lines of help\nand more', 'demo')
576
636
        topic = plugin.ModuleHelpTopic(mod)
577
 
        self.assertEqual(
578
 
            "two lines of help\nand more\n\n:See also: bar, foo\n",
579
 
            topic.get_help_text(['foo', 'bar']))
 
637
        self.assertEqual("two lines of help\nand more\n\n:See also: bar, foo\n",
 
638
                         topic.get_help_text(['foo', 'bar']))
580
639
 
581
640
    def test_get_help_topic(self):
582
641
        """The help topic for a plugin is its module name."""
594
653
    user = "USER"
595
654
    core = "CORE"
596
655
    site = "SITE"
597
 
    entrypoints = "ENTRYPOINTS"
598
656
 
599
657
    def check_path(self, expected_dirs, setting_dirs):
600
658
        if setting_dirs is None:
602
660
        else:
603
661
            os.environ['BRZ_PLUGIN_PATH'] = os.pathsep.join(setting_dirs)
604
662
        actual = [(p if t == 'path' else t.upper())
605
 
                  for p, t in plugin._env_plugin_path()]
 
663
            for p, t in plugin._env_plugin_path()]
606
664
        self.assertEqual(expected_dirs, actual)
607
665
 
608
666
    def test_default(self):
609
 
        self.check_path([self.user, self.core, self.site], None)
 
667
        self.check_path([self.user, self.core, self.site],
 
668
                        None)
610
669
 
611
670
    def test_adhoc_policy(self):
612
671
        self.check_path([self.user, self.core, self.site],
620
679
        self.check_path([self.user, self.site, self.core],
621
680
                        ['+user', '+site', '+core'])
622
681
 
623
 
    def test_enable_entrypoints(self):
624
 
        self.check_path([self.user, self.core, self.site, self.entrypoints],
625
 
                        ['+user', '+core', '+site', '+entrypoints'])
626
 
 
627
682
    def test_disable_user(self):
628
683
        self.check_path([self.core, self.site], ['-user'])
629
684
 
665
720
                        ['mycore', '-core'])
666
721
 
667
722
    def test_my_plugin_only(self):
668
 
        self.check_path(
669
 
            ['myplugin'],
670
 
            ['myplugin', '-user', '-core', '-site', '-entrypoints'])
 
723
        self.check_path(['myplugin'], ['myplugin', '-user', '-core', '-site'])
671
724
 
672
725
    def test_my_plugin_first(self):
673
726
        self.check_path(['myplugin', self.core, self.site, self.user],
733
786
    def test_mixed(self):
734
787
        value = os.pathsep.join(['valid', 'in-valid'])
735
788
        self.assertEqual(['valid'], self._get_names(value))
736
 
        self.assertContainsRe(
737
 
            self.get_log(),
 
789
        self.assertContainsRe(self.get_log(),
738
790
            r"Invalid name 'in-valid' in BRZ_DISABLE_PLUGINS=" + repr(value))
739
791
 
740
792
 
769
821
 
770
822
    def test_bad_name(self):
771
823
        self.assertEqual([], self._get_paths('/usr/local/bzr-git'))
772
 
        self.assertContainsRe(
773
 
            self.get_log(),
 
824
        self.assertContainsRe(self.get_log(),
774
825
            r"Invalid name 'bzr-git' in BRZ_PLUGINS_AT='/usr/local/bzr-git'")
775
826
 
776
827
 
833
884
        self.create_plugin_package('test_bar', dir='non-standard-dir/test_bar')
834
885
        self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
835
886
        self.update_module_paths(['standard'])
836
 
        import breezy.testingplugins.test_foo  # noqa: F401
 
887
        import breezy.testingplugins.test_foo
837
888
        self.assertEqual(self.module_prefix + 'test_foo',
838
889
                         self.module.test_foo.__package__)
839
 
        import breezy.testingplugins.test_foo.test_bar  # noqa: F401
 
890
        import breezy.testingplugins.test_foo.test_bar
840
891
        self.assertIsSameRealPath('non-standard-dir/test_bar/__init__.py',
841
892
                                  self.module.test_foo.test_bar.__file__)
842
893
 
848
899
        self.create_plugin_package('test_bar', dir='another-dir/test_bar')
849
900
        self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@another-dir')
850
901
        self.update_module_paths(['standard'])
851
 
        import breezy.testingplugins.test_foo  # noqa: F401
 
902
        import breezy.testingplugins.test_foo
852
903
        self.assertEqual(self.module_prefix + 'test_foo',
853
904
                         self.module.test_foo.__package__)
854
905
        self.assertIsSameRealPath('another-dir/test_bar/__init__.py',
884
935
    def test_describe_plugins(self):
885
936
        class DummyModule(object):
886
937
            __doc__ = 'Hi there'
887
 
 
888
938
        class DummyPlugin(object):
889
939
            __version__ = '0.1.0'
890
940
            module = DummyModule()
898
948
  Hi there
899
949
 
900
950
""", ''.join(plugin.describe_plugins(state=self)))
901
 
 
902
 
 
903
 
class DummyPlugin(object):
904
 
    """Plugin."""
905
 
 
906
 
 
907
 
class TestLoadEnvPlugin(BaseTestPlugins):
908
 
 
909
 
    _test_needs_features = [pkg_resources_feature]
910
 
 
911
 
    def setup_plugin(self, source=""):
912
 
        # This test tests a new plugin appears in breezy.plugin.plugins().
913
 
        # check the plugin is not loaded already
914
 
        self.assertPluginUnknown('plugin')
915
 
        # write a plugin that _cannot_ fail to load.
916
 
        import pkg_resources
917
 
        d = pkg_resources.Distribution(__file__)
918
 
        ep = pkg_resources.EntryPoint.parse(
919
 
            'plugin = ' + __name__ + ':DummyPlugin', dist=d)
920
 
        d._ep_map = {'breezy.plugin': {'plugin': ep}}
921
 
        pkg_resources.working_set.add(d, 'plugin', replace=True)
922
 
        eps = list(pkg_resources.iter_entry_points('breezy.plugin'))
923
 
        self.assertEqual(['plugin'], [ep.name for ep in eps])
924
 
        self.load_with_paths(['.'])
925
 
        self.addCleanup(d._ep_map.clear)
926
 
 
927
 
    def test_plugin_loaded(self):
928
 
        self.assertPluginUnknown('plugin')
929
 
        self.overrideEnv('BRZ_PLUGIN_PATH', '+entrypoints')
930
 
        self.setup_plugin()
931
 
        p = self.plugins['plugin']
932
 
        self.assertIsInstance(p, breezy.plugin.PlugIn)
933
 
        self.assertIs(p.module, sys.modules[self.module_prefix + 'plugin'])
934
 
 
935
 
    def test_plugin_loaded_disabled(self):
936
 
        self.assertPluginUnknown('plugin')
937
 
        self.overrideEnv('BRZ_PLUGIN_PATH', '+entrypoints')
938
 
        self.overrideEnv('BRZ_DISABLE_PLUGINS', 'plugin')
939
 
        self.setup_plugin()
940
 
        self.assertNotIn('plugin', self.plugins)