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
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
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)
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))
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)),
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 \
201
breezy.tests.test_plugins.TestLoadingPlugins.activeattributes[tempattribute] = [
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])
237
230
del self.activeattributes[tempattribute]
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 \
242
breezy.tests.test_plugins.TestLoadingPlugins.activeattributes[tempattribute] = [
251
244
self.assertTrue(tempattribute in self.activeattributes)
252
245
# create a directory for the plugin
253
246
os.mkdir('plugin_test')
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_'\\.")
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(['.'])
334
328
def test_plugin_loaded(self):
363
357
self.setup_plugin()
364
358
self.promote_cache(self.test_dir)
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)
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__)
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\\]')
542
479
class TestHelpIndex(tests.TestCase):
543
480
"""Tests for the PluginsHelpIndex class."""
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())
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())
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())
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']))
575
"two lines of help\nand more\n\n:See also: bar, foo\n",
576
topic.get_help_text(['foo', 'bar']))
640
578
def test_get_help_topic(self):
641
579
"""The help topic for a plugin is its module name."""
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)
666
605
def test_default(self):
667
self.check_path([self.user, self.core, self.site],
606
self.check_path([self.user, self.core, self.site], None)
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'])
620
def test_enable_entrypoints(self):
621
self.check_path([self.user, self.core, self.site, self.entrypoints],
622
['+user', '+core', '+site', '+entrypoints'])
682
624
def test_disable_user(self):
683
625
self.check_path([self.core, self.site], ['-user'])
720
662
['mycore', '-core'])
722
664
def test_my_plugin_only(self):
723
self.check_path(['myplugin'], ['myplugin', '-user', '-core', '-site'])
667
['myplugin', '-user', '-core', '-site', '-entrypoints'])
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,
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(
790
735
r"Invalid name 'in-valid' in BRZ_DISABLE_PLUGINS=" + repr(value))
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__)
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',
950
897
""", ''.join(plugin.describe_plugins(state=self)))
900
class DummyPlugin(object):
904
class TestLoadEnvPlugin(BaseTestPlugins):
906
_test_needs_features = [pkg_resources_feature]
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.
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)
924
def test_plugin_loaded(self):
925
self.assertPluginUnknown('plugin')
926
self.overrideEnv('BRZ_PLUGIN_PATH', '+entrypoints')
928
p = self.plugins['plugin']
929
self.assertIsInstance(p, breezy.plugin.PlugIn)
930
self.assertIs(p.module, sys.modules[self.module_prefix + 'plugin'])
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')
937
self.assertNotIn('plugin', self.plugins)