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
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
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)
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))
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)),
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] = [
208
breezy.tests.test_plugins.TestLoadingPlugins.activeattributes \
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])
233
237
del self.activeattributes[tempattribute]
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] = [
249
breezy.tests.test_plugins.TestLoadingPlugins.activeattributes \
247
251
self.assertTrue(tempattribute in self.activeattributes)
248
252
# create a directory for the plugin
249
253
os.mkdir('plugin_test')
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_'\\.")
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(['.'])
331
334
def test_plugin_loaded(self):
360
363
self.setup_plugin()
361
364
self.promote_cache(self.test_dir)
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)
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__)
485
# GZ 2017-06-02: Move this suite to blackbox, as it's what it actually is.
486
class TestPluginHelp(BaseTestPlugins):
488
def split_help_commands(self):
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
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():
506
help = breezy.commands.get_cmd_object(cmd_name).get_help_text()
507
except NotImplementedError:
508
# some commands have no help
511
self.assertNotContainsRe(help, 'plugin "[^"]*"')
513
if cmd_name in help_commands:
514
# some commands are hidden
515
help = help_commands[cmd_name]
516
self.assertNotContainsRe(help, 'plugin "[^"]*"')
518
def test_plugin_help_shows_plugin(self):
519
# Create a test plugin
520
os.mkdir('plugin_test')
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"
527
" print ('Hello from my plugin')\n"
529
self.create_plugin('myplug', source, 'plugin_test')
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\\]')
482
542
class TestHelpIndex(tests.TestCase):
483
543
"""Tests for the PluginsHelpIndex class."""
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())
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())
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())
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)
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']))
581
640
def test_get_help_topic(self):
582
641
"""The help topic for a plugin is its module name."""
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)
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],
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'])
623
def test_enable_entrypoints(self):
624
self.check_path([self.user, self.core, self.site, self.entrypoints],
625
['+user', '+core', '+site', '+entrypoints'])
627
682
def test_disable_user(self):
628
683
self.check_path([self.core, self.site], ['-user'])
665
720
['mycore', '-core'])
667
722
def test_my_plugin_only(self):
670
['myplugin', '-user', '-core', '-site', '-entrypoints'])
723
self.check_path(['myplugin'], ['myplugin', '-user', '-core', '-site'])
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(
789
self.assertContainsRe(self.get_log(),
738
790
r"Invalid name 'in-valid' in BRZ_DISABLE_PLUGINS=" + repr(value))
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__)
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',
900
950
""", ''.join(plugin.describe_plugins(state=self)))
903
class DummyPlugin(object):
907
class TestLoadEnvPlugin(BaseTestPlugins):
909
_test_needs_features = [pkg_resources_feature]
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.
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)
927
def test_plugin_loaded(self):
928
self.assertPluginUnknown('plugin')
929
self.overrideEnv('BRZ_PLUGIN_PATH', '+entrypoints')
931
p = self.plugins['plugin']
932
self.assertIsInstance(p, breezy.plugin.PlugIn)
933
self.assertIs(p.module, sys.modules[self.module_prefix + 'plugin'])
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')
940
self.assertNotIn('plugin', self.plugins)