~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_plugins.py

  • Committer: John Arbash Meinel
  • Date: 2008-08-25 21:50:11 UTC
  • mfrom: (0.11.3 tools)
  • mto: This revision was merged to the branch mainline in revision 3659.
  • Revision ID: john@arbash-meinel.com-20080825215011-de9esmzgkue3e522
Merge in Lukáš's helper scripts.
Update the packaging documents to describe how to do the releases
using bzr-builddeb to package all distro platforms
simultaneously.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
"""Tests for plugins"""
18
18
 
26
26
import sys
27
27
import zipfile
28
28
 
29
 
from bzrlib import (
30
 
    osutils,
31
 
    plugin,
32
 
    tests,
33
 
    )
 
29
from bzrlib import plugin, tests
34
30
import bzrlib.plugin
35
31
import bzrlib.plugins
36
32
import bzrlib.commands
37
33
import bzrlib.help
 
34
from bzrlib.symbol_versioning import one_three
38
35
from bzrlib.tests import (
39
36
    TestCase,
40
37
    TestCaseInTempDir,
74
71
        # create two plugin directories
75
72
        os.mkdir('first')
76
73
        os.mkdir('second')
77
 
        # write a plugin that will record when its loaded in the
 
74
        # write a plugin that will record when its loaded in the 
78
75
        # tempattribute list.
79
76
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
80
77
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
122
119
        # create two plugin directories
123
120
        os.mkdir('first')
124
121
        os.mkdir('second')
125
 
        # write plugins that will record when they are loaded in the
 
122
        # write plugins that will record when they are loaded in the 
126
123
        # tempattribute list.
127
124
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
128
125
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
174
171
        self.failUnless(tempattribute in self.activeattributes)
175
172
        # create a directory for the plugin
176
173
        os.mkdir('plugin_test')
177
 
        # write a plugin that will record when its loaded in the
 
174
        # write a plugin that will record when its loaded in the 
178
175
        # tempattribute list.
179
176
        template = ("from bzrlib.tests.test_plugins import TestLoadingPlugins\n"
180
177
                    "TestLoadingPlugins.activeattributes[%r].append('%s')\n")
196
193
                del bzrlib.plugins.ts_plugin
197
194
        self.failIf(getattr(bzrlib.plugins, 'ts_plugin', None))
198
195
 
199
 
    def load_and_capture(self, name):
200
 
        """Load plugins from '.' capturing the output.
 
196
    def test_plugin_with_bad_name_does_not_load(self):
 
197
        # Create badly-named plugin
 
198
        file('bzr-bad plugin-name..py', 'w').close()
201
199
 
202
 
        :param name: The name of the plugin.
203
 
        :return: A string with the log from the plugin loading call.
204
 
        """
205
200
        # Capture output
206
201
        stream = StringIO()
207
 
        try:
208
 
            handler = logging.StreamHandler(stream)
209
 
            log = logging.getLogger('bzr')
210
 
            log.addHandler(handler)
211
 
            try:
212
 
                try:
213
 
                    bzrlib.plugin.load_from_path(['.'])
214
 
                finally:
215
 
                    if 'bzrlib.plugins.%s' % name in sys.modules:
216
 
                        del sys.modules['bzrlib.plugins.%s' % name]
217
 
                    if getattr(bzrlib.plugins, name, None):
218
 
                        delattr(bzrlib.plugins, name)
219
 
            finally:
220
 
                # Stop capturing output
221
 
                handler.flush()
222
 
                handler.close()
223
 
                log.removeHandler(handler)
224
 
            return stream.getvalue()
225
 
        finally:
226
 
            stream.close()
227
 
 
228
 
    def test_plugin_with_bad_api_version_reports(self):
229
 
        # This plugin asks for bzrlib api version 1.0.0, which is not supported
230
 
        # anymore.
231
 
        name = 'wants100.py'
232
 
        f = file(name, 'w')
233
 
        try:
234
 
            f.write("import bzrlib.api\n"
235
 
                "bzrlib.api.require_any_api(bzrlib, [(1, 0, 0)])\n")
236
 
        finally:
237
 
            f.close()
238
 
 
239
 
        log = self.load_and_capture(name)
240
 
        self.assertContainsRe(log,
241
 
            r"It requested API version")
242
 
 
243
 
    def test_plugin_with_bad_name_does_not_load(self):
244
 
        # The file name here invalid for a python module.
245
 
        name = 'bzr-bad plugin-name..py'
246
 
        file(name, 'w').close()
247
 
        log = self.load_and_capture(name)
248
 
        self.assertContainsRe(log,
 
202
        handler = logging.StreamHandler(stream)
 
203
        log = logging.getLogger('bzr')
 
204
        log.addHandler(handler)
 
205
 
 
206
        bzrlib.plugin.load_from_dir('.')
 
207
 
 
208
        # Stop capturing output
 
209
        handler.flush()
 
210
        handler.close()
 
211
        log.removeHandler(handler)
 
212
 
 
213
        self.assertContainsRe(stream.getvalue(),
249
214
            r"Unable to load 'bzr-bad plugin-name\.' in '\.' as a plugin "
250
215
            "because the file path isn't a valid module name; try renaming "
251
216
            "it to 'bad_plugin_name_'\.")
252
217
 
 
218
        stream.close()
 
219
 
253
220
 
254
221
class TestPlugins(TestCaseInTempDir):
255
222
 
261
228
        file('plugin.py', 'w').write(source + '\n')
262
229
        self.addCleanup(self.teardown_plugin)
263
230
        bzrlib.plugin.load_from_path(['.'])
264
 
 
 
231
    
265
232
    def teardown_plugin(self):
266
233
        # remove the plugin 'plugin'
267
234
        if 'bzrlib.plugins.plugin' in sys.modules:
356
323
        plugin = bzrlib.plugin.plugins()['plugin']
357
324
        self.assertEqual("unknown", plugin.__version__)
358
325
 
359
 
    def test_str__version__with_version_info(self):
360
 
        self.setup_plugin("version_info = '1.2.3'")
361
 
        plugin = bzrlib.plugin.plugins()['plugin']
362
 
        self.assertEqual("1.2.3", plugin.__version__)
363
 
 
364
 
    def test_noniterable__version__with_version_info(self):
365
 
        self.setup_plugin("version_info = (1)")
366
 
        plugin = bzrlib.plugin.plugins()['plugin']
367
 
        self.assertEqual("1", plugin.__version__)
368
 
 
369
 
    def test_1__version__with_version_info(self):
370
 
        self.setup_plugin("version_info = (1,)")
371
 
        plugin = bzrlib.plugin.plugins()['plugin']
372
 
        self.assertEqual("1", plugin.__version__)
373
 
 
374
 
    def test_1_2__version__with_version_info(self):
375
 
        self.setup_plugin("version_info = (1, 2)")
376
 
        plugin = bzrlib.plugin.plugins()['plugin']
377
 
        self.assertEqual("1.2", plugin.__version__)
378
 
 
379
 
    def test_1_2_3__version__with_version_info(self):
380
 
        self.setup_plugin("version_info = (1, 2, 3)")
381
 
        plugin = bzrlib.plugin.plugins()['plugin']
382
 
        self.assertEqual("1.2.3", plugin.__version__)
383
 
 
384
 
    def test_candidate__version__with_version_info(self):
385
 
        self.setup_plugin("version_info = (1, 2, 3, 'candidate', 1)")
386
 
        plugin = bzrlib.plugin.plugins()['plugin']
387
 
        self.assertEqual("1.2.3rc1", plugin.__version__)
388
 
 
389
 
    def test_dev__version__with_version_info(self):
390
 
        self.setup_plugin("version_info = (1, 2, 3, 'dev', 0)")
391
 
        plugin = bzrlib.plugin.plugins()['plugin']
392
 
        self.assertEqual("1.2.3dev", plugin.__version__)
393
 
 
394
 
    def test_dev_fallback__version__with_version_info(self):
 
326
    def test___version__with_version_info(self):
395
327
        self.setup_plugin("version_info = (1, 2, 3, 'dev', 4)")
396
328
        plugin = bzrlib.plugin.plugins()['plugin']
397
329
        self.assertEqual("1.2.3dev4", plugin.__version__)
398
330
 
399
331
    def test_final__version__with_version_info(self):
400
 
        self.setup_plugin("version_info = (1, 2, 3, 'final', 0)")
 
332
        self.setup_plugin("version_info = (1, 2, 3, 'final', 4)")
401
333
        plugin = bzrlib.plugin.plugins()['plugin']
402
334
        self.assertEqual("1.2.3", plugin.__version__)
403
335
 
404
 
    def test_final_fallback__version__with_version_info(self):
405
 
        self.setup_plugin("version_info = (1, 2, 3, 'final', 2)")
406
 
        plugin = bzrlib.plugin.plugins()['plugin']
407
 
        self.assertEqual("1.2.3.final.2", plugin.__version__)
408
 
 
409
336
 
410
337
class TestPluginHelp(TestCaseInTempDir):
411
338
 
412
339
    def split_help_commands(self):
413
340
        help = {}
414
341
        current = None
415
 
        out, err = self.run_bzr('--no-plugins help commands')
416
 
        for line in out.splitlines():
 
342
        for line in self.run_bzr('help commands')[0].splitlines():
417
343
            if not line.startswith(' '):
418
344
                current = line.split()[0]
419
345
            help[current] = help.get(current, '') + line
456
382
            self.assertContainsRe(help, '\[myplug\]')
457
383
        finally:
458
384
            # unregister command
459
 
            if 'myplug' in bzrlib.commands.plugin_cmds:
460
 
                bzrlib.commands.plugin_cmds.remove('myplug')
 
385
            if bzrlib.commands.plugin_cmds.get('myplug', None):
 
386
                del bzrlib.commands.plugin_cmds['myplug']
461
387
            # remove the plugin 'myplug'
462
388
            if getattr(bzrlib.plugins, 'myplug', None):
463
389
                delattr(bzrlib.plugins, 'myplug')
464
390
 
465
391
 
 
392
class TestPluginFromZip(TestCaseInTempDir):
 
393
 
 
394
    def make_zipped_plugin(self, zip_name, filename):
 
395
        z = zipfile.ZipFile(zip_name, 'w')
 
396
        z.writestr(filename, PLUGIN_TEXT)
 
397
        z.close()
 
398
 
 
399
    def check_plugin_load(self, zip_name, plugin_name):
 
400
        self.assertFalse(plugin_name in dir(bzrlib.plugins),
 
401
                         'Plugin already loaded')
 
402
        old_path = bzrlib.plugins.__path__
 
403
        try:
 
404
            # this is normally done by load_plugins -> set_plugins_path
 
405
            bzrlib.plugins.__path__ = [zip_name]
 
406
            self.applyDeprecated(one_three,
 
407
                bzrlib.plugin.load_from_zip, zip_name)
 
408
            self.assertTrue(plugin_name in dir(bzrlib.plugins),
 
409
                            'Plugin is not loaded')
 
410
        finally:
 
411
            # unregister plugin
 
412
            if getattr(bzrlib.plugins, plugin_name, None):
 
413
                delattr(bzrlib.plugins, plugin_name)
 
414
                del sys.modules['bzrlib.plugins.' + plugin_name]
 
415
            bzrlib.plugins.__path__ = old_path
 
416
 
 
417
    def test_load_module(self):
 
418
        self.make_zipped_plugin('./test.zip', 'ziplug.py')
 
419
        self.check_plugin_load('./test.zip', 'ziplug')
 
420
 
 
421
    def test_load_package(self):
 
422
        self.make_zipped_plugin('./test.zip', 'ziplug/__init__.py')
 
423
        self.check_plugin_load('./test.zip', 'ziplug')
 
424
 
 
425
 
 
426
class TestSetPluginsPath(TestCase):
 
427
    
 
428
    def test_set_plugins_path(self):
 
429
        """set_plugins_path should set the module __path__ correctly."""
 
430
        old_path = bzrlib.plugins.__path__
 
431
        try:
 
432
            bzrlib.plugins.__path__ = []
 
433
            expected_path = bzrlib.plugin.set_plugins_path()
 
434
            self.assertEqual(expected_path, bzrlib.plugins.__path__)
 
435
        finally:
 
436
            bzrlib.plugins.__path__ = old_path
 
437
 
 
438
    def test_set_plugins_path_with_trailing_slashes(self):
 
439
        """set_plugins_path should set the module __path__ based on
 
440
        BZR_PLUGIN_PATH after removing all trailing slashes."""
 
441
        old_path = bzrlib.plugins.__path__
 
442
        old_env = os.environ.get('BZR_PLUGIN_PATH')
 
443
        try:
 
444
            bzrlib.plugins.__path__ = []
 
445
            os.environ['BZR_PLUGIN_PATH'] = "first\\//\\" + os.pathsep + \
 
446
                "second/\\/\\/"
 
447
            bzrlib.plugin.set_plugins_path()
 
448
            # We expect our nominated paths to have all path-seps removed,
 
449
            # and this is testing only that.
 
450
            expected_path = ['first', 'second']
 
451
            self.assertEqual(expected_path,
 
452
                bzrlib.plugins.__path__[:len(expected_path)])
 
453
        finally:
 
454
            bzrlib.plugins.__path__ = old_path
 
455
            if old_env is not None:
 
456
                os.environ['BZR_PLUGIN_PATH'] = old_env
 
457
            else:
 
458
                del os.environ['BZR_PLUGIN_PATH']
 
459
 
 
460
 
466
461
class TestHelpIndex(tests.TestCase):
467
462
    """Tests for the PluginsHelpIndex class."""
468
463
 
569
564
        mod = FakeModule('two lines of help\nand more', 'bzrlib.plugins.foo_bar')
570
565
        topic = plugin.ModuleHelpTopic(mod)
571
566
        self.assertEqual('foo_bar', topic.get_help_topic())
572
 
 
573
 
 
574
 
class TestLoadFromPath(tests.TestCaseInTempDir):
575
 
 
576
 
    def setUp(self):
577
 
        super(TestLoadFromPath, self).setUp()
578
 
        # Change bzrlib.plugin to think no plugins have been loaded yet.
579
 
        self.overrideAttr(bzrlib.plugins, '__path__', [])
580
 
        self.overrideAttr(plugin, '_loaded', False)
581
 
 
582
 
        # Monkey-patch load_from_path to stop it from actually loading anything.
583
 
        self.overrideAttr(plugin, 'load_from_path', lambda dirs: None)
584
 
 
585
 
    def test_set_plugins_path_with_args(self):
586
 
        plugin.set_plugins_path(['a', 'b'])
587
 
        self.assertEqual(['a', 'b'], bzrlib.plugins.__path__)
588
 
 
589
 
    def test_set_plugins_path_defaults(self):
590
 
        plugin.set_plugins_path()
591
 
        self.assertEqual(plugin.get_standard_plugins_path(),
592
 
                         bzrlib.plugins.__path__)
593
 
 
594
 
    def test_get_standard_plugins_path(self):
595
 
        path = plugin.get_standard_plugins_path()
596
 
        for directory in path:
597
 
            self.assertNotContainsRe(directory, r'\\/$')
598
 
        try:
599
 
            from distutils.sysconfig import get_python_lib
600
 
        except ImportError:
601
 
            pass
602
 
        else:
603
 
            if sys.platform != 'win32':
604
 
                python_lib = get_python_lib()
605
 
                for directory in path:
606
 
                    if directory.startswith(python_lib):
607
 
                        break
608
 
                else:
609
 
                    self.fail('No path to global plugins')
610
 
 
611
 
    def test_get_standard_plugins_path_env(self):
612
 
        os.environ['BZR_PLUGIN_PATH'] = 'foo/'
613
 
        path = plugin.get_standard_plugins_path()
614
 
        for directory in path:
615
 
            self.assertNotContainsRe(directory, r'\\/$')
616
 
 
617
 
    def test_load_plugins(self):
618
 
        plugin.load_plugins(['.'])
619
 
        self.assertEqual(bzrlib.plugins.__path__, ['.'])
620
 
        # subsequent loads are no-ops
621
 
        plugin.load_plugins(['foo'])
622
 
        self.assertEqual(bzrlib.plugins.__path__, ['.'])
623
 
 
624
 
    def test_load_plugins_default(self):
625
 
        plugin.load_plugins()
626
 
        path = plugin.get_standard_plugins_path()
627
 
        self.assertEqual(path, bzrlib.plugins.__path__)
628
 
 
629
 
 
630
 
class TestEnvPluginPath(tests.TestCaseInTempDir):
631
 
 
632
 
    def setUp(self):
633
 
        super(TestEnvPluginPath, self).setUp()
634
 
        self.overrideAttr(plugin, 'DEFAULT_PLUGIN_PATH', None)
635
 
 
636
 
        self.user = plugin.get_user_plugin_path()
637
 
        self.site = plugin.get_site_plugin_path()
638
 
        self.core = plugin.get_core_plugin_path()
639
 
 
640
 
    def _list2paths(self, *args):
641
 
        paths = []
642
 
        for p in args:
643
 
            plugin._append_new_path(paths, p)
644
 
        return paths
645
 
 
646
 
    def _set_path(self, *args):
647
 
        path = os.pathsep.join(self._list2paths(*args))
648
 
        osutils.set_or_unset_env('BZR_PLUGIN_PATH', path)
649
 
 
650
 
    def check_path(self, expected_dirs, setting_dirs):
651
 
        if setting_dirs:
652
 
            self._set_path(*setting_dirs)
653
 
        actual = plugin.get_standard_plugins_path()
654
 
        self.assertEquals(self._list2paths(*expected_dirs), actual)
655
 
 
656
 
    def test_default(self):
657
 
        self.check_path([self.user, self.core, self.site],
658
 
                        None)
659
 
 
660
 
    def test_adhoc_policy(self):
661
 
        self.check_path([self.user, self.core, self.site],
662
 
                        ['+user', '+core', '+site'])
663
 
 
664
 
    def test_fallback_policy(self):
665
 
        self.check_path([self.core, self.site, self.user],
666
 
                        ['+core', '+site', '+user'])
667
 
 
668
 
    def test_override_policy(self):
669
 
        self.check_path([self.user, self.site, self.core],
670
 
                        ['+user', '+site', '+core'])
671
 
 
672
 
    def test_disable_user(self):
673
 
        self.check_path([self.core, self.site], ['-user'])
674
 
 
675
 
    def test_disable_user_twice(self):
676
 
        # Ensures multiple removals don't left cruft
677
 
        self.check_path([self.core, self.site], ['-user', '-user'])
678
 
 
679
 
    def test_duplicates_are_removed(self):
680
 
        self.check_path([self.user, self.core, self.site],
681
 
                        ['+user', '+user'])
682
 
        # And only the first reference is kept (since the later references will
683
 
        # onnly produce <plugin> already loaded mutters)
684
 
        self.check_path([self.user, self.core, self.site],
685
 
                        ['+user', '+user', '+core',
686
 
                         '+user', '+site', '+site',
687
 
                         '+core'])
688
 
 
689
 
    def test_disable_overrides_disable(self):
690
 
        self.check_path([self.core, self.site], ['-user', '+user'])
691
 
 
692
 
    def test_disable_core(self):
693
 
        self.check_path([self.site], ['-core'])
694
 
        self.check_path([self.user, self.site], ['+user', '-core'])
695
 
 
696
 
    def test_disable_site(self):
697
 
        self.check_path([self.core], ['-site'])
698
 
        self.check_path([self.user, self.core], ['-site', '+user'])
699
 
 
700
 
    def test_override_site(self):
701
 
        self.check_path(['mysite', self.user, self.core],
702
 
                        ['mysite', '-site', '+user'])
703
 
        self.check_path(['mysite', self.core],
704
 
                        ['mysite', '-site'])
705
 
 
706
 
    def test_override_core(self):
707
 
        self.check_path(['mycore', self.user, self.site],
708
 
                        ['mycore', '-core', '+user', '+site'])
709
 
        self.check_path(['mycore', self.site],
710
 
                        ['mycore', '-core'])
711
 
 
712
 
    def test_my_plugin_only(self):
713
 
        self.check_path(['myplugin'], ['myplugin', '-user', '-core', '-site'])
714
 
 
715
 
    def test_my_plugin_first(self):
716
 
        self.check_path(['myplugin', self.core, self.site, self.user],
717
 
                        ['myplugin', '+core', '+site', '+user'])
718
 
 
719
 
    def test_bogus_references(self):
720
 
        self.check_path(['+foo', '-bar', self.core, self.site],
721
 
                        ['+foo', '-bar'])