159
54
# file name we can use which is also a valid attribute for accessing in
160
55
# activeattributes. - we cannot give import parameters.
161
56
tempattribute = "0"
162
self.assertFalse(tempattribute in self.activeattributes)
57
self.failIf(tempattribute in self.activeattributes)
163
58
# set a place for the plugins to record their loading, and at the same
164
59
# time validate that the location the plugins should record to is
165
60
# valid and correct.
166
self.__class__.activeattributes[tempattribute] = []
167
self.assertTrue(tempattribute in self.activeattributes)
61
bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
63
self.failUnless(tempattribute in self.activeattributes)
168
64
# create two plugin directories
170
66
os.mkdir('second')
171
# write a plugin that will record when its loaded in the
67
# write a plugin that will record when its loaded in the
172
68
# tempattribute list.
173
template = ("from breezy.tests.test_plugins import TestLoadingPlugins\n"
69
template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
174
70
"TestLoadingPlugins.activeattributes[%r].append('%s')\n")
176
with open(os.path.join('first', 'plugin.py'), 'w') as outfile:
177
outfile.write(template % (tempattribute, 'first'))
180
with open(os.path.join('second', 'plugin.py'), 'w') as outfile:
181
outfile.write(template % (tempattribute, 'second'))
71
print >> file(os.path.join('first', 'plugin.py'), 'w'), template % (tempattribute, 'first')
72
print >> file(os.path.join('second', 'plugin.py'), 'w'), template % (tempattribute, 'second')
185
self.load_with_paths(['first', 'second'])
74
bzrlib.plugin.load_from_path(['first', 'second'])
186
75
self.assertEqual(['first'], self.activeattributes[tempattribute])
77
# remove the plugin 'plugin'
188
78
del self.activeattributes[tempattribute]
79
if getattr(bzrlib.plugins, 'plugin', None):
80
del bzrlib.plugins.plugin
81
self.failIf(getattr(bzrlib.plugins, 'plugin', None))
190
83
def test_plugins_from_different_dirs_can_demand_load(self):
191
self.assertFalse('breezy.plugins.pluginone' in sys.modules)
192
self.assertFalse('breezy.plugins.plugintwo' in sys.modules)
193
84
# This test tests that having two plugins in different
194
85
# directories with different names allows them both to be loaded, when
195
86
# we do a direct import statement.
196
87
# Determine a file name we can use which is also a valid attribute
197
88
# for accessing in activeattributes. - we cannot give import parameters.
198
89
tempattribute = "different-dirs"
199
self.assertFalse(tempattribute in self.activeattributes)
90
self.failIf(tempattribute in self.activeattributes)
200
91
# set a place for the plugins to record their loading, and at the same
201
92
# time validate that the location the plugins should record to is
202
93
# valid and correct.
203
breezy.tests.test_plugins.TestLoadingPlugins.activeattributes[tempattribute] = [
205
self.assertTrue(tempattribute in self.activeattributes)
94
bzrlib.tests.test_plugins.TestLoadingPlugins.activeattributes \
96
self.failUnless(tempattribute in self.activeattributes)
206
97
# create two plugin directories
208
99
os.mkdir('second')
209
# write plugins that will record when they are loaded in the
100
# write plugins that will record when they are loaded in the
210
101
# tempattribute list.
211
template = ("from breezy.tests.test_plugins import TestLoadingPlugins\n"
102
template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
212
103
"TestLoadingPlugins.activeattributes[%r].append('%s')\n")
214
with open(os.path.join('first', 'pluginone.py'), 'w') as outfile:
215
outfile.write(template % (tempattribute, 'first'))
218
with open(os.path.join('second', 'plugintwo.py'), 'w') as outfile:
219
outfile.write(template % (tempattribute, 'second'))
104
print >> file(os.path.join('first', 'pluginone.py'), 'w'), template % (tempattribute, 'first')
105
print >> file(os.path.join('second', 'plugintwo.py'), 'w'), template % (tempattribute, 'second')
106
oldpath = bzrlib.plugins.__path__
223
self.assertPluginUnknown('pluginone')
224
self.assertPluginUnknown('plugintwo')
225
self.update_module_paths(['first', 'second'])
226
exec("import %spluginone" % self.module_prefix)
108
bzrlib.plugins.__path__ = ['first', 'second']
109
exec "import bzrlib.plugins.pluginone"
227
110
self.assertEqual(['first'], self.activeattributes[tempattribute])
228
exec("import %splugintwo" % self.module_prefix)
111
exec "import bzrlib.plugins.plugintwo"
229
112
self.assertEqual(['first', 'second'],
230
self.activeattributes[tempattribute])
113
self.activeattributes[tempattribute])
115
# remove the plugin 'plugin'
232
116
del self.activeattributes[tempattribute]
234
def test_plugins_can_load_from_directory_with_trailing_slash(self):
235
# This test tests that a plugin can load from a directory when the
236
# directory in the path has a trailing slash.
117
if getattr(bzrlib.plugins, 'plugin', None):
118
del bzrlib.plugins.plugin
119
self.failIf(getattr(bzrlib.plugins, 'plugin', None))
122
class TestAllPlugins(TestCaseInTempDir):
124
def test_plugin_appears_in_all_plugins(self):
125
# This test tests a new plugin appears in bzrlib.plugin.all_plugins().
237
126
# check the plugin is not loaded already
238
self.assertPluginUnknown('ts_plugin')
239
tempattribute = "trailing-slash"
240
self.assertFalse(tempattribute in self.activeattributes)
241
# set a place for the plugin to record its loading, and at the same
242
# time validate that the location the plugin should record to is
244
breezy.tests.test_plugins.TestLoadingPlugins.activeattributes[tempattribute] = [
246
self.assertTrue(tempattribute in self.activeattributes)
247
# create a directory for the plugin
127
self.failIf(getattr(bzrlib.plugins, 'plugin', None))
128
# write a plugin that _cannot_ fail to load.
129
print >> file('plugin.py', 'w'), ""
131
bzrlib.plugin.load_from_path(['.'])
132
self.failUnless('plugin' in bzrlib.plugin.all_plugins())
133
self.failUnless(getattr(bzrlib.plugins, 'plugin', None))
134
self.assertEqual(bzrlib.plugin.all_plugins()['plugin'],
135
bzrlib.plugins.plugin)
137
# remove the plugin 'plugin'
138
if 'bzrlib.plugins.plugin' in sys.modules:
139
del sys.modules['bzrlib.plugins.plugin']
140
if getattr(bzrlib.plugins, 'plugin', None):
141
del bzrlib.plugins.plugin
142
self.failIf(getattr(bzrlib.plugins, 'plugin', None))
145
class TestPluginHelp(TestCaseInTempDir):
147
def split_help_commands(self):
150
for line in self.capture('help commands').splitlines():
151
if not line.startswith(' '):
152
current = line.split()[0]
153
help[current] = help.get(current, '') + line
157
def test_plugin_help_builtins_unaffected(self):
158
# Check we don't get false positives
159
help_commands = self.split_help_commands()
160
for cmd_name in bzrlib.commands.builtin_command_names():
161
if cmd_name in bzrlib.commands.plugin_command_names():
165
bzrlib.help.help_on_command(cmd_name, help)
166
except NotImplementedError:
167
# some commands have no help
171
self.assertNotContainsRe(help.read(), 'From plugin "[^"]*"')
173
if help in help_commands.keys():
174
# some commands are hidden
175
help = help_commands[cmd_name]
176
self.assertNotContainsRe(help, 'From plugin "[^"]*"')
178
def test_plugin_help_shows_plugin(self):
179
# Create a test plugin
248
180
os.mkdir('plugin_test')
249
# write a plugin that will record when its loaded in the
250
# tempattribute list.
251
template = ("from breezy.tests.test_plugins import TestLoadingPlugins\n"
252
"TestLoadingPlugins.activeattributes[%r].append('%s')\n")
254
with open(os.path.join('plugin_test', 'ts_plugin.py'), 'w') as outfile:
255
outfile.write(template % (tempattribute, 'plugin'))
259
self.load_with_paths(['plugin_test' + os.sep])
260
self.assertEqual(['plugin'], self.activeattributes[tempattribute])
261
self.assertPluginKnown('ts_plugin')
263
del self.activeattributes[tempattribute]
265
def load_and_capture(self, name, warn_load_problems=True):
266
"""Load plugins from '.' capturing the output.
268
:param name: The name of the plugin.
269
:return: A string with the log from the plugin loading call.
274
handler = logging.StreamHandler(stream)
275
log = logging.getLogger('brz')
276
log.addHandler(handler)
278
self.load_with_paths(
279
['.'], warn_load_problems=warn_load_problems)
281
# Stop capturing output
284
log.removeHandler(handler)
285
return stream.getvalue()
289
def test_plugin_with_bad_api_version_reports(self):
290
"""Try loading a plugin that requests an unsupported api.
292
Observe that it records the problem but doesn't complain on stderr
293
when warn_load_problems=False
296
with open(name, 'w') as f:
297
f.write("import breezy\n"
298
"from breezy.errors import IncompatibleVersion\n"
299
"raise IncompatibleVersion(breezy, [(1, 0, 0)], (0, 0, 5))\n")
300
log = self.load_and_capture(name, warn_load_problems=False)
301
self.assertNotContainsRe(log, r"It supports breezy version")
302
self.assertEqual({'wants100'}, self.plugin_warnings.keys())
303
self.assertContainsRe(
304
self.plugin_warnings['wants100'][0],
305
r"It supports breezy version")
307
def test_plugin_with_bad_name_does_not_load(self):
308
# The file name here invalid for a python module.
309
name = 'brz-bad plugin-name..py'
310
open(name, 'w').close()
311
log = self.load_and_capture(name)
312
self.assertContainsRe(log,
313
r"Unable to load 'brz-bad plugin-name\.' in '\.' as a plugin "
314
"because the file path isn't a valid module name; try renaming "
315
"it to 'bad_plugin_name_'\\.")
317
def test_plugin_with_error_suppress(self):
318
# The file name here invalid for a python module.
319
name = 'some_error.py'
320
with open(name, 'w') as f:
321
f.write('raise Exception("bad")\n')
322
log = self.load_and_capture(name, warn_load_problems=False)
323
self.assertEqual('', log)
325
def test_plugin_with_error(self):
326
# The file name here invalid for a python module.
327
name = 'some_error.py'
328
with open(name, 'w') as f:
329
f.write('raise Exception("bad")\n')
330
log = self.load_and_capture(name, warn_load_problems=True)
332
'Unable to load plugin \'some_error\' from \'.\': bad\n', log)
335
class TestPlugins(BaseTestPlugins):
337
def setup_plugin(self, source=""):
338
# This test tests a new plugin appears in breezy.plugin.plugins().
339
# check the plugin is not loaded already
340
self.assertPluginUnknown('plugin')
341
# write a plugin that _cannot_ fail to load.
342
with open('plugin.py', 'w') as f:
343
f.write(source + '\n')
344
self.load_with_paths(['.'])
346
def test_plugin_loaded(self):
347
self.assertPluginUnknown('plugin')
348
self.assertIs(None, breezy.plugin.get_loaded_plugin('plugin'))
350
p = breezy.plugin.get_loaded_plugin('plugin')
351
self.assertIsInstance(p, breezy.plugin.PlugIn)
352
self.assertIs(p.module, sys.modules[self.module_prefix + 'plugin'])
354
def test_plugin_loaded_disabled(self):
355
self.assertPluginUnknown('plugin')
356
self.overrideEnv('BRZ_DISABLE_PLUGINS', 'plugin')
358
self.assertIs(None, breezy.plugin.get_loaded_plugin('plugin'))
360
def test_plugin_appears_in_plugins(self):
362
self.assertPluginKnown('plugin')
363
p = self.plugins['plugin']
364
self.assertIsInstance(p, breezy.plugin.PlugIn)
365
self.assertIs(p.module, sys.modules[self.module_prefix + 'plugin'])
367
def test_trivial_plugin_get_path(self):
369
p = self.plugins['plugin']
370
plugin_path = self.test_dir + '/plugin.py'
371
self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
373
def test_plugin_get_path_py_not_pyc(self):
374
# first import creates plugin.pyc
376
self.promote_cache(self.test_dir)
378
self.load_with_paths(['.']) # import plugin.pyc
379
p = plugin.plugins()['plugin']
380
plugin_path = self.test_dir + '/plugin.py'
381
self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
383
def test_plugin_get_path_pyc_only(self):
384
# first import creates plugin.pyc (or plugin.pyo depending on __debug__)
386
os.unlink(self.test_dir + '/plugin.py')
387
self.promote_cache(self.test_dir)
389
self.load_with_paths(['.']) # import plugin.pyc (or .pyo)
390
p = plugin.plugins()['plugin']
391
plugin_path = self.test_dir + '/plugin' + plugin.COMPILED_EXT
392
self.assertIsSameRealPath(plugin_path, osutils.normpath(p.path()))
394
def test_no_test_suite_gives_None_for_test_suite(self):
396
p = plugin.plugins()['plugin']
397
self.assertEqual(None, p.test_suite())
399
def test_test_suite_gives_test_suite_result(self):
400
source = """def test_suite(): return 'foo'"""
401
self.setup_plugin(source)
402
p = plugin.plugins()['plugin']
403
self.assertEqual('foo', p.test_suite())
405
def test_no_load_plugin_tests_gives_None_for_load_plugin_tests(self):
407
loader = tests.TestUtil.TestLoader()
408
p = plugin.plugins()['plugin']
409
self.assertEqual(None, p.load_plugin_tests(loader))
411
def test_load_plugin_tests_gives_load_plugin_tests_result(self):
413
def load_tests(loader, standard_tests, pattern):
415
self.setup_plugin(source)
416
loader = tests.TestUtil.TestLoader()
417
p = plugin.plugins()['plugin']
418
self.assertEqual('foo', p.load_plugin_tests(loader))
420
def check_version_info(self, expected, source='', name='plugin'):
421
self.setup_plugin(source)
422
self.assertEqual(expected, plugin.plugins()[name].version_info())
424
def test_no_version_info(self):
425
self.check_version_info(None)
427
def test_with_version_info(self):
428
self.check_version_info((1, 2, 3, 'dev', 4),
429
"version_info = (1, 2, 3, 'dev', 4)")
431
def test_short_version_info_gets_padded(self):
432
# the gtk plugin has version_info = (1,2,3) rather than the 5-tuple.
434
self.check_version_info((1, 2, 3, 'final', 0),
435
"version_info = (1, 2, 3)")
437
def check_version(self, expected, source=None, name='plugin'):
438
self.setup_plugin(source)
439
self.assertEqual(expected, plugins[name].__version__)
441
def test_no_version_info___version__(self):
443
plugin = breezy.plugin.plugins()['plugin']
444
self.assertEqual("unknown", plugin.__version__)
446
def test_str__version__with_version_info(self):
447
self.setup_plugin("version_info = '1.2.3'")
448
plugin = breezy.plugin.plugins()['plugin']
449
self.assertEqual("1.2.3", plugin.__version__)
451
def test_noniterable__version__with_version_info(self):
452
self.setup_plugin("version_info = (1)")
453
plugin = breezy.plugin.plugins()['plugin']
454
self.assertEqual("1", plugin.__version__)
456
def test_1__version__with_version_info(self):
457
self.setup_plugin("version_info = (1,)")
458
plugin = breezy.plugin.plugins()['plugin']
459
self.assertEqual("1", plugin.__version__)
461
def test_1_2__version__with_version_info(self):
462
self.setup_plugin("version_info = (1, 2)")
463
plugin = breezy.plugin.plugins()['plugin']
464
self.assertEqual("1.2", plugin.__version__)
466
def test_1_2_3__version__with_version_info(self):
467
self.setup_plugin("version_info = (1, 2, 3)")
468
plugin = breezy.plugin.plugins()['plugin']
469
self.assertEqual("1.2.3", plugin.__version__)
471
def test_candidate__version__with_version_info(self):
472
self.setup_plugin("version_info = (1, 2, 3, 'candidate', 1)")
473
plugin = breezy.plugin.plugins()['plugin']
474
self.assertEqual("1.2.3rc1", plugin.__version__)
476
def test_dev__version__with_version_info(self):
477
self.setup_plugin("version_info = (1, 2, 3, 'dev', 0)")
478
plugin = breezy.plugin.plugins()['plugin']
479
self.assertEqual("1.2.3dev", plugin.__version__)
481
def test_dev_fallback__version__with_version_info(self):
482
self.setup_plugin("version_info = (1, 2, 3, 'dev', 4)")
483
plugin = breezy.plugin.plugins()['plugin']
484
self.assertEqual("1.2.3dev4", plugin.__version__)
486
def test_final__version__with_version_info(self):
487
self.setup_plugin("version_info = (1, 2, 3, 'final', 0)")
488
plugin = breezy.plugin.plugins()['plugin']
489
self.assertEqual("1.2.3", plugin.__version__)
491
def test_final_fallback__version__with_version_info(self):
492
self.setup_plugin("version_info = (1, 2, 3, 'final', 2)")
493
plugin = breezy.plugin.plugins()['plugin']
494
self.assertEqual("1.2.3.2", plugin.__version__)
497
class TestHelpIndex(tests.TestCase):
498
"""Tests for the PluginsHelpIndex class."""
500
def test_default_constructable(self):
501
index = plugin.PluginsHelpIndex()
503
def test_get_topics_None(self):
504
"""Searching for None returns an empty list."""
505
index = plugin.PluginsHelpIndex()
506
self.assertEqual([], index.get_topics(None))
508
def test_get_topics_for_plugin(self):
509
"""Searching for plugin name gets its docstring."""
510
index = plugin.PluginsHelpIndex()
511
# make a new plugin here for this test, even if we're run with
513
self.assertFalse('breezy.plugins.demo_module' in sys.modules)
514
demo_module = FakeModule('', 'breezy.plugins.demo_module')
515
sys.modules['breezy.plugins.demo_module'] = demo_module
517
topics = index.get_topics('demo_module')
518
self.assertEqual(1, len(topics))
519
self.assertIsInstance(topics[0], plugin.ModuleHelpTopic)
520
self.assertEqual(demo_module, topics[0].module)
522
del sys.modules['breezy.plugins.demo_module']
524
def test_get_topics_no_topic(self):
525
"""Searching for something that is not a plugin returns []."""
526
# test this by using a name that cannot be a plugin - its not
527
# a valid python identifier.
528
index = plugin.PluginsHelpIndex()
529
self.assertEqual([], index.get_topics('nothing by this name'))
531
def test_prefix(self):
532
"""PluginsHelpIndex has a prefix of 'plugins/'."""
533
index = plugin.PluginsHelpIndex()
534
self.assertEqual('plugins/', index.prefix)
536
def test_get_plugin_topic_with_prefix(self):
537
"""Searching for plugins/demo_module returns help."""
538
index = plugin.PluginsHelpIndex()
539
self.assertFalse('breezy.plugins.demo_module' in sys.modules)
540
demo_module = FakeModule('', 'breezy.plugins.demo_module')
541
sys.modules['breezy.plugins.demo_module'] = demo_module
543
topics = index.get_topics('plugins/demo_module')
544
self.assertEqual(1, len(topics))
545
self.assertIsInstance(topics[0], plugin.ModuleHelpTopic)
546
self.assertEqual(demo_module, topics[0].module)
548
del sys.modules['breezy.plugins.demo_module']
551
class FakeModule(object):
552
"""A fake module to test with."""
554
def __init__(self, doc, name):
559
class TestModuleHelpTopic(tests.TestCase):
560
"""Tests for the ModuleHelpTopic class."""
562
def test_contruct(self):
563
"""Construction takes the module to document."""
564
mod = FakeModule('foo', 'foo')
565
topic = plugin.ModuleHelpTopic(mod)
566
self.assertEqual(mod, topic.module)
568
def test_get_help_text_None(self):
569
"""A ModuleHelpTopic returns the docstring for get_help_text."""
570
mod = FakeModule(None, 'demo')
571
topic = plugin.ModuleHelpTopic(mod)
572
self.assertEqual("Plugin 'demo' has no docstring.\n",
573
topic.get_help_text())
575
def test_get_help_text_no_carriage_return(self):
576
"""ModuleHelpTopic.get_help_text adds a \n if needed."""
577
mod = FakeModule('one line of help', 'demo')
578
topic = plugin.ModuleHelpTopic(mod)
579
self.assertEqual("one line of help\n",
580
topic.get_help_text())
582
def test_get_help_text_carriage_return(self):
583
"""ModuleHelpTopic.get_help_text adds a \n if needed."""
584
mod = FakeModule('two lines of help\nand more\n', 'demo')
585
topic = plugin.ModuleHelpTopic(mod)
586
self.assertEqual("two lines of help\nand more\n",
587
topic.get_help_text())
589
def test_get_help_text_with_additional_see_also(self):
590
mod = FakeModule('two lines of help\nand more', 'demo')
591
topic = plugin.ModuleHelpTopic(mod)
593
"two lines of help\nand more\n\n:See also: bar, foo\n",
594
topic.get_help_text(['foo', 'bar']))
596
def test_get_help_topic(self):
597
"""The help topic for a plugin is its module name."""
598
mod = FakeModule('two lines of help\nand more', 'breezy.plugins.demo')
599
topic = plugin.ModuleHelpTopic(mod)
600
self.assertEqual('demo', topic.get_help_topic())
601
mod = FakeModule('two lines of help\nand more',
602
'breezy.plugins.foo_bar')
603
topic = plugin.ModuleHelpTopic(mod)
604
self.assertEqual('foo_bar', topic.get_help_topic())
607
class TestEnvPluginPath(tests.TestCase):
612
entrypoints = "ENTRYPOINTS"
614
def check_path(self, expected_dirs, setting_dirs):
615
if setting_dirs is None:
616
del os.environ['BRZ_PLUGIN_PATH']
618
os.environ['BRZ_PLUGIN_PATH'] = os.pathsep.join(setting_dirs)
619
actual = [(p if t == 'path' else t.upper())
620
for p, t in plugin._env_plugin_path()]
621
self.assertEqual(expected_dirs, actual)
623
def test_default(self):
624
self.check_path([self.user, self.core, self.site], None)
626
def test_adhoc_policy(self):
627
self.check_path([self.user, self.core, self.site],
628
['+user', '+core', '+site'])
630
def test_fallback_policy(self):
631
self.check_path([self.core, self.site, self.user],
632
['+core', '+site', '+user'])
634
def test_override_policy(self):
635
self.check_path([self.user, self.site, self.core],
636
['+user', '+site', '+core'])
638
def test_enable_entrypoints(self):
639
self.check_path([self.user, self.core, self.site, self.entrypoints],
640
['+user', '+core', '+site', '+entrypoints'])
642
def test_disable_user(self):
643
self.check_path([self.core, self.site], ['-user'])
645
def test_disable_user_twice(self):
646
# Ensures multiple removals don't left cruft
647
self.check_path([self.core, self.site], ['-user', '-user'])
649
def test_duplicates_are_removed(self):
650
self.check_path([self.user, self.core, self.site],
652
# And only the first reference is kept (since the later references will
653
# only produce '<plugin> already loaded' mutters)
654
self.check_path([self.user, self.core, self.site],
655
['+user', '+user', '+core',
656
'+user', '+site', '+site',
659
def test_disable_overrides_enable(self):
660
self.check_path([self.core, self.site], ['-user', '+user'])
662
def test_disable_core(self):
663
self.check_path([self.site], ['-core'])
664
self.check_path([self.user, self.site], ['+user', '-core'])
666
def test_disable_site(self):
667
self.check_path([self.core], ['-site'])
668
self.check_path([self.user, self.core], ['-site', '+user'])
670
def test_override_site(self):
671
self.check_path(['mysite', self.user, self.core],
672
['mysite', '-site', '+user'])
673
self.check_path(['mysite', self.core],
676
def test_override_core(self):
677
self.check_path(['mycore', self.user, self.site],
678
['mycore', '-core', '+user', '+site'])
679
self.check_path(['mycore', self.site],
682
def test_my_plugin_only(self):
685
['myplugin', '-user', '-core', '-site', '-entrypoints'])
687
def test_my_plugin_first(self):
688
self.check_path(['myplugin', self.core, self.site, self.user],
689
['myplugin', '+core', '+site', '+user'])
691
def test_bogus_references(self):
692
self.check_path(['+foo', '-bar', self.core, self.site],
696
class TestDisablePlugin(BaseTestPlugins):
698
def test_cannot_import(self):
699
self.create_plugin_package('works')
700
self.create_plugin_package('fails')
701
self.overrideEnv('BRZ_DISABLE_PLUGINS', 'fails')
702
self.update_module_paths(["."])
703
import breezy.testingplugins.works as works
705
import breezy.testingplugins.fails as fails
709
self.fail("Loaded blocked plugin: " + repr(fails))
710
self.assertPluginModules({'fails': None, 'works': works})
712
def test_partial_imports(self):
713
self.create_plugin('good')
714
self.create_plugin('bad')
715
self.create_plugin_package('ugly')
716
self.overrideEnv('BRZ_DISABLE_PLUGINS', 'bad:ugly')
717
self.load_with_paths(['.'])
718
self.assertEqual({'good'}, self.plugins.keys())
719
self.assertPluginModules({
720
'good': self.plugins['good'].module,
724
# Ensure there are no warnings about plugins not being imported as
725
# the user has explictly requested they be disabled.
726
self.assertNotContainsRe(self.get_log(), r"Unable to load plugin")
729
class TestEnvDisablePlugins(tests.TestCase):
731
def _get_names(self, env_value):
732
os.environ['BRZ_DISABLE_PLUGINS'] = env_value
733
return plugin._env_disable_plugins()
735
def test_unset(self):
736
self.assertEqual([], plugin._env_disable_plugins())
738
def test_empty(self):
739
self.assertEqual([], self._get_names(''))
741
def test_single(self):
742
self.assertEqual(['single'], self._get_names('single'))
744
def test_multi(self):
745
expected = ['one', 'two']
746
self.assertEqual(expected, self._get_names(os.pathsep.join(expected)))
748
def test_mixed(self):
749
value = os.pathsep.join(['valid', 'in-valid'])
750
self.assertEqual(['valid'], self._get_names(value))
751
self.assertContainsRe(
753
r"Invalid name 'in-valid' in BRZ_DISABLE_PLUGINS=" + repr(value))
756
class TestEnvPluginsAt(tests.TestCase):
758
def _get_paths(self, env_value):
759
os.environ['BRZ_PLUGINS_AT'] = env_value
760
return plugin._env_plugins_at()
762
def test_empty(self):
763
self.assertEqual([], plugin._env_plugins_at())
764
self.assertEqual([], self._get_paths(''))
766
def test_one_path(self):
767
self.assertEqual([('b', 'man')], self._get_paths('b@man'))
769
def test_multiple(self):
771
[('tools', 'bzr-tools'), ('p', 'play.py')],
772
self._get_paths(os.pathsep.join(('tools@bzr-tools', 'p@play.py'))))
774
def test_many_at(self):
776
[('church', 'StMichael@Plea@Norwich')],
777
self._get_paths('church@StMichael@Plea@Norwich'))
779
def test_only_py(self):
780
self.assertEqual([('test', './test.py')], self._get_paths('./test.py'))
782
def test_only_package(self):
783
self.assertEqual([('py', '/opt/b/py')], self._get_paths('/opt/b/py'))
785
def test_bad_name(self):
786
self.assertEqual([], self._get_paths('/usr/local/bzr-git'))
787
self.assertContainsRe(
789
r"Invalid name 'bzr-git' in BRZ_PLUGINS_AT='/usr/local/bzr-git'")
792
class TestLoadPluginAt(BaseTestPlugins):
795
super(TestLoadPluginAt, self).setUp()
796
# Create the same plugin in two directories
797
self.create_plugin_package('test_foo', dir='non-standard-dir')
798
# The "normal" directory, we use 'standard' instead of 'plugins' to
799
# avoid depending on the precise naming.
800
self.create_plugin_package('test_foo', dir='standard/test_foo')
802
def assertTestFooLoadedFrom(self, path):
803
self.assertPluginKnown('test_foo')
804
self.assertDocstring('This is the doc for test_foo',
805
self.module.test_foo)
806
self.assertEqual(path, self.module.test_foo.dir_source)
808
def test_regular_load(self):
809
self.load_with_paths(['standard'])
810
self.assertTestFooLoadedFrom('standard/test_foo')
812
def test_import(self):
813
self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
814
self.update_module_paths(['standard'])
815
import breezy.testingplugins.test_foo
816
self.assertTestFooLoadedFrom('non-standard-dir')
818
def test_loading(self):
819
self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
820
self.load_with_paths(['standard'])
821
self.assertTestFooLoadedFrom('non-standard-dir')
823
def test_loading_other_name(self):
824
self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
825
os.rename('standard/test_foo', 'standard/test_bar')
826
self.load_with_paths(['standard'])
827
self.assertTestFooLoadedFrom('non-standard-dir')
829
def test_compiled_loaded(self):
830
self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
831
self.load_with_paths(['standard'])
832
self.assertTestFooLoadedFrom('non-standard-dir')
833
self.assertIsSameRealPath('non-standard-dir/__init__.py',
834
self.module.test_foo.__file__)
836
# Try importing again now that the source has been compiled
837
os.remove('non-standard-dir/__init__.py')
838
self.promote_cache('non-standard-dir')
840
self.load_with_paths(['standard'])
841
self.assertTestFooLoadedFrom('non-standard-dir')
842
suffix = plugin.COMPILED_EXT
843
self.assertIsSameRealPath('non-standard-dir/__init__' + suffix,
844
self.module.test_foo.__file__)
846
def test_submodule_loading(self):
847
# We create an additional directory under the one for test_foo
848
self.create_plugin_package('test_bar', dir='non-standard-dir/test_bar')
849
self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
850
self.update_module_paths(['standard'])
851
import breezy.testingplugins.test_foo # noqa: F401
852
self.assertEqual(self.module_prefix + 'test_foo',
853
self.module.test_foo.__package__)
854
import breezy.testingplugins.test_foo.test_bar # noqa: F401
855
self.assertIsSameRealPath('non-standard-dir/test_bar/__init__.py',
856
self.module.test_foo.test_bar.__file__)
858
def test_relative_submodule_loading(self):
859
self.create_plugin_package('test_foo', dir='another-dir', source='''
860
from . import test_bar
862
# We create an additional directory under the one for test_foo
863
self.create_plugin_package('test_bar', dir='another-dir/test_bar')
864
self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@another-dir')
865
self.update_module_paths(['standard'])
866
import breezy.testingplugins.test_foo # noqa: F401
867
self.assertEqual(self.module_prefix + 'test_foo',
868
self.module.test_foo.__package__)
869
self.assertIsSameRealPath('another-dir/test_bar/__init__.py',
870
self.module.test_foo.test_bar.__file__)
872
def test_loading_from___init__only(self):
873
# We rename the existing __init__.py file to ensure that we don't load
875
init = 'non-standard-dir/__init__.py'
876
random = 'non-standard-dir/setup.py'
877
os.rename(init, random)
878
self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@non-standard-dir')
879
self.load_with_paths(['standard'])
880
self.assertPluginUnknown('test_foo')
882
def test_loading_from_specific_file(self):
883
plugin_dir = 'non-standard-dir'
884
plugin_file_name = 'iamtestfoo.py'
885
plugin_path = osutils.pathjoin(plugin_dir, plugin_file_name)
887
"""This is the doc for %s"""
889
''' % ('test_foo', plugin_path)
890
self.create_plugin('test_foo', source=source,
891
dir=plugin_dir, file_name=plugin_file_name)
892
self.overrideEnv('BRZ_PLUGINS_AT', 'test_foo@%s' % plugin_path)
893
self.load_with_paths(['standard'])
894
self.assertTestFooLoadedFrom(plugin_path)
897
class TestDescribePlugins(BaseTestPlugins):
899
def test_describe_plugins(self):
900
class DummyModule(object):
903
class DummyPlugin(object):
904
__version__ = '0.1.0'
905
module = DummyModule()
906
self.plugin_warnings = {'bad': ['Failed to load (just testing)']}
907
self.plugins = {'good': DummyPlugin()}
908
self.assertEqual("""\
910
** Failed to load (just testing)
915
""", ''.join(plugin.describe_plugins(state=self)))
918
class DummyPlugin(object):
922
class TestLoadEnvPlugin(BaseTestPlugins):
924
_test_needs_features = [pkg_resources_feature]
926
def setup_plugin(self, source=""):
927
# This test tests a new plugin appears in breezy.plugin.plugins().
928
# check the plugin is not loaded already
929
self.assertPluginUnknown('plugin')
930
# write a plugin that _cannot_ fail to load.
932
d = pkg_resources.Distribution(__file__)
933
ep = pkg_resources.EntryPoint.parse(
934
'plugin = ' + __name__ + ':DummyPlugin', dist=d)
935
d._ep_map = {'breezy.plugin': {'plugin': ep}}
936
pkg_resources.working_set.add(d, 'plugin', replace=True)
937
eps = list(pkg_resources.iter_entry_points('breezy.plugin'))
938
self.assertEqual(['plugin'], [ep.name for ep in eps])
939
self.load_with_paths(['.'])
940
self.addCleanup(d._ep_map.clear)
942
def test_plugin_loaded(self):
943
self.assertPluginUnknown('plugin')
944
self.overrideEnv('BRZ_PLUGIN_PATH', '+entrypoints')
946
p = self.plugins['plugin']
947
self.assertIsInstance(p, breezy.plugin.PlugIn)
948
self.assertIs(p.module, sys.modules[self.module_prefix + 'plugin'])
950
def test_plugin_loaded_disabled(self):
951
self.assertPluginUnknown('plugin')
952
self.overrideEnv('BRZ_PLUGIN_PATH', '+entrypoints')
953
self.overrideEnv('BRZ_DISABLE_PLUGINS', 'plugin')
955
self.assertNotIn('plugin', self.plugins)
181
f = open(pathjoin('plugin_test', 'myplug.py'), 'w')
187
bzrlib.plugin.load_from_path(['plugin_test'])
188
bzrlib.commands.register_command( bzrlib.plugins.myplug.cmd_myplug)
189
help = self.capture('help myplug')
190
self.assertContainsRe(help, 'From plugin "myplug"')
191
help = self.split_help_commands()['myplug']
192
self.assertContainsRe(help, '\[myplug\]')
195
if bzrlib.commands.plugin_cmds.get('myplug', None):
196
del bzrlib.commands.plugin_cmds['myplug']
197
# remove the plugin 'myplug'
198
if getattr(bzrlib.plugins, 'myplug', None):
199
delattr(bzrlib.plugins, 'myplug')
202
class TestPluginFromZip(TestCaseInTempDir):
204
def make_zipped_plugin(self, zip_name, filename):
205
z = zipfile.ZipFile(zip_name, 'w')
206
z.writestr(filename, PLUGIN_TEXT)
209
def check_plugin_load(self, zip_name, plugin_name):
210
self.assertFalse(plugin_name in dir(bzrlib.plugins),
211
'Plugin already loaded')
213
bzrlib.plugin.load_from_zip(zip_name)
214
self.assertTrue(plugin_name in dir(bzrlib.plugins),
215
'Plugin is not loaded')
218
if getattr(bzrlib.plugins, plugin_name, None):
219
delattr(bzrlib.plugins, plugin_name)
221
def test_load_module(self):
222
self.make_zipped_plugin('./test.zip', 'ziplug.py')
223
self.check_plugin_load('./test.zip', 'ziplug')
225
def test_load_package(self):
226
self.make_zipped_plugin('./test.zip', 'ziplug/__init__.py')
227
self.check_plugin_load('./test.zip', 'ziplug')
230
class TestSetPluginsPath(TestCase):
232
def test_set_plugins_path(self):
233
"""set_plugins_path should set the module __path__ correctly."""
234
old_path = bzrlib.plugins.__path__
236
bzrlib.plugins.__path__ = []
237
expected_path = bzrlib.plugin.set_plugins_path()
238
self.assertEqual(expected_path, bzrlib.plugins.__path__)
240
bzrlib.plugins.__path__ = old_path