From 1878db34163157f6115f40e76cfa17eb4883587d Mon Sep 17 00:00:00 2001 From: Jakub Warmuz Date: Sun, 3 May 2015 13:21:36 +0000 Subject: [PATCH] More coverage for plugins.disco --- letsencrypt/client/plugins/disco.py | 40 ++++----- letsencrypt/client/plugins/disco_test.py | 100 ++++++++++++++++++----- 2 files changed, 100 insertions(+), 40 deletions(-) diff --git a/letsencrypt/client/plugins/disco.py b/letsencrypt/client/plugins/disco.py index a4557255e..68cb230d0 100644 --- a/letsencrypt/client/plugins/disco.py +++ b/letsencrypt/client/plugins/disco.py @@ -30,6 +30,11 @@ class PluginEntryPoint(object): return entry_point.name return entry_point.dist.key + ":" + entry_point.name + @property + def name_with_description(self): + """Name with description. Handy for UI.""" + return "{0} ({1})".format(self.name, self.plugin_cls.description) + @property def initialized(self): """Has the plugin been initialized already?""" @@ -42,6 +47,20 @@ class PluginEntryPoint(object): self._initialized = self.plugin_cls(config, self.name) return self._initialized + def verify(self, ifaces): + """Verify that the plugin conforms to the specified interfaces.""" + assert self.initialized + for iface in ifaces: # zope.interface.providedBy(plugin) + try: + zope.interface.verify.verifyObject(iface, self.init()) + except zope.interface.exceptions.BrokenImplementation: + if iface.implementedBy(self.plugin_cls): + logging.debug( + "%s implements %s but object does " + "not verify", self.plugin_cls, iface.__name__) + return False + return True + @property def prepared(self): """Has the plugin been prepared already?""" @@ -68,7 +87,8 @@ class PluginEntryPoint(object): @property def misconfigured(self): """Is plugin misconfigured?""" - return isinstance(self._prepared, errors.LetsEncryptMisconfigurationError) + return isinstance( + self._prepared, errors.LetsEncryptMisconfigurationError) @property def available(self): @@ -78,24 +98,6 @@ class PluginEntryPoint(object): def __repr__(self): return "PluginEntryPoint#{0}".format(self.name) - @property - def name_with_description(self): - """Name with description. Handy for UI.""" - return "{0} ({1})".format(self.name, self.plugin_cls.description) - - def verify(self, ifaces): - assert self.initialized - for iface in ifaces: # zope.interface.providedBy(plugin) - try: - zope.interface.verify.verifyObject(iface, self.init()) - except zope.interface.exceptions.BrokenImplementation: - if iface.implementedBy(self.plugin_cls): - logging.debug( - "%s implements %s but object does " - "not verify", self.plugin_cls, iface.__name__) - return False - return True - def __str__(self): lines = [ "* {0}".format(self.name), diff --git a/letsencrypt/client/plugins/disco_test.py b/letsencrypt/client/plugins/disco_test.py index b55faba0c..54f77c941 100644 --- a/letsencrypt/client/plugins/disco_test.py +++ b/letsencrypt/client/plugins/disco_test.py @@ -3,7 +3,9 @@ import pkg_resources import unittest import mock +import zope.interface +from letsencrypt.client import errors from letsencrypt.client.plugins.standalone import authenticator @@ -21,7 +23,8 @@ class PluginEntryPointTest(unittest.TestCase): # project name != top-level package name self.ep3 = pkg_resources.EntryPoint( "ep3", "a.ep3", dist=mock.MagicMock(key="p3")) - # something we can load()/require() + + # something we can load()/require(), TODO: use mock self.ep_sa = pkg_resources.EntryPoint( "sa", "letsencrypt.client.plugins.standalone.authenticator", attrs=('StandaloneAuthenticator',), @@ -30,26 +33,6 @@ class PluginEntryPointTest(unittest.TestCase): from letsencrypt.client.plugins.disco import PluginEntryPoint self.plugin_ep = PluginEntryPoint(self.ep_sa) - def test__init__(self): - self.assertFalse(self.plugin_ep.initialized) - self.assertTrue(self.plugin_ep.entry_point is self.ep_sa) - self.assertEqual("sa", self.plugin_ep.name) - - self.assertTrue( - self.plugin_ep.plugin_cls is authenticator.StandaloneAuthenticator) - - def test_init(self): - config = mock.MagicMock() - plugin = self.plugin_ep.init(config=config) - self.assertTrue(self.plugin_ep.initialized) - self.assertTrue(plugin.config is config) - # memoize! - self.assertTrue(self.plugin_ep.init() is plugin) - self.assertTrue(plugin.config is config) - # try to give different config - self.assertTrue(self.plugin_ep.init(123) is plugin) - self.assertTrue(plugin.config is config) - def test_entry_point_to_plugin_name(self): from letsencrypt.client.plugins.disco import PluginEntryPoint @@ -69,6 +52,81 @@ class PluginEntryPointTest(unittest.TestCase): self.assertTrue( self.plugin_ep.name_with_description.startswith("sa (")) + def test__init__(self): + self.assertFalse(self.plugin_ep.initialized) + self.assertFalse(self.plugin_ep.prepared) + self.assertFalse(self.plugin_ep.misconfigured) + self.assertFalse(self.plugin_ep.available) + self.assertTrue(self.plugin_ep.entry_point is self.ep_sa) + self.assertEqual("sa", self.plugin_ep.name) + + self.assertTrue( + self.plugin_ep.plugin_cls is authenticator.StandaloneAuthenticator) + + def test_init(self): + config = mock.MagicMock() + plugin = self.plugin_ep.init(config=config) + self.assertTrue(self.plugin_ep.initialized) + self.assertTrue(plugin.config is config) + # memoize! + self.assertTrue(self.plugin_ep.init() is plugin) + self.assertTrue(plugin.config is config) + # try to give different config + self.assertTrue(self.plugin_ep.init(123) is plugin) + self.assertTrue(plugin.config is config) + + self.assertFalse(self.plugin_ep.prepared) + self.assertFalse(self.plugin_ep.misconfigured) + self.assertFalse(self.plugin_ep.available) + + def test_verify(self): + i1 = mock.MagicMock(__name__="i1") + i2 = mock.MagicMock(__name__="i2") + i3 = mock.MagicMock(__name__="i3") + self.plugin_ep._initialized = plugin = mock.MagicMock() + + exceptions = zope.interface.exceptions + with mock.patch("letsencrypt.client.plugins.disco.zope.interface") as mock_zope: + mock_zope.exceptions = exceptions + def verify_object(iface, obj): + assert obj is plugin + assert iface is i1 or iface is i2 or iface is i3 + if iface is i3: + raise mock_zope.exceptions.BrokenImplementation(None, None) + mock_zope.verify.verifyObject.side_effect = verify_object + self.assertTrue(self.plugin_ep.verify((i1,))) + self.assertTrue(self.plugin_ep.verify((i1, i2))) + self.assertFalse(self.plugin_ep.verify((i3,))) + self.assertFalse(self.plugin_ep.verify((i1, i3))) + + def test_prepare(self): + config = mock.MagicMock() + self.plugin_ep.init(config=config) + self.plugin_ep.prepare() + self.assertTrue(self.plugin_ep.prepared) + self.assertFalse(self.plugin_ep.misconfigured) + str(self.plugin_ep) # output doesn't matter that much, just jest if it runs + + def test_prepare_misconfigured(self): + plugin = mock.MagicMock() + plugin.prepare.side_effect = errors.LetsEncryptMisconfigurationError + self.plugin_ep._initialized = plugin + self.assertTrue(isinstance(self.plugin_ep.prepare(), + errors.LetsEncryptMisconfigurationError)) + self.assertTrue(self.plugin_ep.prepared) + self.assertTrue(self.plugin_ep.misconfigured) + self.assertTrue(self.plugin_ep.available) + + def test_prepare_no_installation(self): + plugin = mock.MagicMock() + plugin.prepare.side_effect = errors.LetsEncryptNoInstallationError + self.plugin_ep._initialized = plugin + self.assertTrue(isinstance(self.plugin_ep.prepare(), + errors.LetsEncryptNoInstallationError)) + self.assertTrue(self.plugin_ep.prepared) + self.assertFalse(self.plugin_ep.misconfigured) + self.assertFalse(self.plugin_ep.available) + def test_repr(self): self.assertEqual("PluginEntryPoint#sa", repr(self.plugin_ep))