disco_test.py
1 """Tests for letsencrypt.plugins.disco.""" 2 import pkg_resources 3 import unittest 4 5 import mock 6 import zope.interface 7 8 from letsencrypt import errors 9 from letsencrypt import interfaces 10 11 from letsencrypt.plugins import standalone 12 13 EP_SA = pkg_resources.EntryPoint( 14 "sa", "letsencrypt.plugins.standalone", 15 attrs=("Authenticator",), 16 dist=mock.MagicMock(key="letsencrypt")) 17 18 19 class PluginEntryPointTest(unittest.TestCase): 20 """Tests for letsencrypt.plugins.disco.PluginEntryPoint.""" 21 22 def setUp(self): 23 self.ep1 = pkg_resources.EntryPoint( 24 "ep1", "p1.ep1", dist=mock.MagicMock(key="p1")) 25 self.ep1prim = pkg_resources.EntryPoint( 26 "ep1", "p2.ep2", dist=mock.MagicMock(key="p2")) 27 # nested 28 self.ep2 = pkg_resources.EntryPoint( 29 "ep2", "p2.foo.ep2", dist=mock.MagicMock(key="p2")) 30 # project name != top-level package name 31 self.ep3 = pkg_resources.EntryPoint( 32 "ep3", "a.ep3", dist=mock.MagicMock(key="p3")) 33 34 from letsencrypt.plugins.disco import PluginEntryPoint 35 self.plugin_ep = PluginEntryPoint(EP_SA) 36 37 def test_entry_point_to_plugin_name(self): 38 from letsencrypt.plugins.disco import PluginEntryPoint 39 40 names = { 41 self.ep1: "p1:ep1", 42 self.ep1prim: "p2:ep1", 43 self.ep2: "p2:ep2", 44 self.ep3: "p3:ep3", 45 EP_SA: "sa", 46 } 47 48 for entry_point, name in names.iteritems(): 49 self.assertEqual( 50 name, PluginEntryPoint.entry_point_to_plugin_name(entry_point)) 51 52 def test_description(self): 53 self.assertEqual("Standalone Authenticator", self.plugin_ep.description) 54 55 def test_description_with_name(self): 56 self.plugin_ep.plugin_cls = mock.MagicMock(description="Desc") 57 self.assertEqual( 58 "Desc (sa)", self.plugin_ep.description_with_name) 59 60 def test_ifaces(self): 61 self.assertTrue(self.plugin_ep.ifaces((interfaces.IAuthenticator,))) 62 self.assertFalse(self.plugin_ep.ifaces((interfaces.IInstaller,))) 63 self.assertFalse(self.plugin_ep.ifaces(( 64 interfaces.IInstaller, interfaces.IAuthenticator))) 65 66 def test__init__(self): 67 self.assertFalse(self.plugin_ep.initialized) 68 self.assertFalse(self.plugin_ep.prepared) 69 self.assertFalse(self.plugin_ep.misconfigured) 70 self.assertFalse(self.plugin_ep.available) 71 self.assertTrue(self.plugin_ep.problem is None) 72 self.assertTrue(self.plugin_ep.entry_point is EP_SA) 73 self.assertEqual("sa", self.plugin_ep.name) 74 75 self.assertTrue(self.plugin_ep.plugin_cls is standalone.Authenticator) 76 77 def test_init(self): 78 config = mock.MagicMock() 79 plugin = self.plugin_ep.init(config=config) 80 self.assertTrue(self.plugin_ep.initialized) 81 self.assertTrue(plugin.config is config) 82 # memoize! 83 self.assertTrue(self.plugin_ep.init() is plugin) 84 self.assertTrue(plugin.config is config) 85 # try to give different config 86 self.assertTrue(self.plugin_ep.init(123) is plugin) 87 self.assertTrue(plugin.config is config) 88 89 self.assertFalse(self.plugin_ep.prepared) 90 self.assertFalse(self.plugin_ep.misconfigured) 91 self.assertFalse(self.plugin_ep.available) 92 93 def test_verify(self): 94 iface1 = mock.MagicMock(__name__="iface1") 95 iface2 = mock.MagicMock(__name__="iface2") 96 iface3 = mock.MagicMock(__name__="iface3") 97 # pylint: disable=protected-access 98 self.plugin_ep._initialized = plugin = mock.MagicMock() 99 100 exceptions = zope.interface.exceptions 101 with mock.patch("letsencrypt.plugins." 102 "disco.zope.interface") as mock_zope: 103 mock_zope.exceptions = exceptions 104 105 def verify_object(iface, obj): # pylint: disable=missing-docstring 106 assert obj is plugin 107 assert iface is iface1 or iface is iface2 or iface is iface3 108 if iface is iface3: 109 raise mock_zope.exceptions.BrokenImplementation(None, None) 110 mock_zope.verify.verifyObject.side_effect = verify_object 111 self.assertTrue(self.plugin_ep.verify((iface1,))) 112 self.assertTrue(self.plugin_ep.verify((iface1, iface2))) 113 self.assertFalse(self.plugin_ep.verify((iface3,))) 114 self.assertFalse(self.plugin_ep.verify((iface1, iface3))) 115 116 def test_prepare(self): 117 config = mock.MagicMock() 118 self.plugin_ep.init(config=config) 119 self.plugin_ep.prepare() 120 self.assertTrue(self.plugin_ep.prepared) 121 self.assertFalse(self.plugin_ep.misconfigured) 122 123 # output doesn't matter that much, just test if it runs 124 str(self.plugin_ep) 125 126 def test_prepare_misconfigured(self): 127 plugin = mock.MagicMock() 128 plugin.prepare.side_effect = errors.MisconfigurationError 129 # pylint: disable=protected-access 130 self.plugin_ep._initialized = plugin 131 self.assertTrue(isinstance(self.plugin_ep.prepare(), 132 errors.MisconfigurationError)) 133 self.assertTrue(self.plugin_ep.prepared) 134 self.assertTrue(self.plugin_ep.misconfigured) 135 self.assertTrue(isinstance(self.plugin_ep.problem, 136 errors.MisconfigurationError)) 137 self.assertTrue(self.plugin_ep.available) 138 139 def test_prepare_no_installation(self): 140 plugin = mock.MagicMock() 141 plugin.prepare.side_effect = errors.NoInstallationError 142 # pylint: disable=protected-access 143 self.plugin_ep._initialized = plugin 144 self.assertTrue(isinstance(self.plugin_ep.prepare(), 145 errors.NoInstallationError)) 146 self.assertTrue(self.plugin_ep.prepared) 147 self.assertFalse(self.plugin_ep.misconfigured) 148 self.assertFalse(self.plugin_ep.available) 149 150 def test_prepare_generic_plugin_error(self): 151 plugin = mock.MagicMock() 152 plugin.prepare.side_effect = errors.PluginError 153 # pylint: disable=protected-access 154 self.plugin_ep._initialized = plugin 155 self.assertTrue(isinstance(self.plugin_ep.prepare(), errors.PluginError)) 156 self.assertTrue(self.plugin_ep.prepared) 157 self.assertFalse(self.plugin_ep.misconfigured) 158 self.assertFalse(self.plugin_ep.available) 159 160 def test_repr(self): 161 self.assertEqual("PluginEntryPoint#sa", repr(self.plugin_ep)) 162 163 164 class PluginsRegistryTest(unittest.TestCase): 165 """Tests for letsencrypt.plugins.disco.PluginsRegistry.""" 166 167 def setUp(self): 168 from letsencrypt.plugins.disco import PluginsRegistry 169 self.plugin_ep = mock.MagicMock(name="mock") 170 self.plugin_ep.__hash__.side_effect = TypeError 171 self.plugins = {"mock": self.plugin_ep} 172 self.reg = PluginsRegistry(self.plugins) 173 174 def test_find_all(self): 175 from letsencrypt.plugins.disco import PluginsRegistry 176 with mock.patch("letsencrypt.plugins.disco.pkg_resources") as mock_pkg: 177 mock_pkg.iter_entry_points.return_value = iter([EP_SA]) 178 plugins = PluginsRegistry.find_all() 179 self.assertTrue(plugins["sa"].plugin_cls is standalone.Authenticator) 180 self.assertTrue(plugins["sa"].entry_point is EP_SA) 181 182 def test_getitem(self): 183 self.assertEqual(self.plugin_ep, self.reg["mock"]) 184 185 def test_iter(self): 186 self.assertEqual(["mock"], list(self.reg)) 187 188 def test_len(self): 189 self.assertEqual(1, len(self.reg)) 190 self.plugins.clear() 191 self.assertEqual(0, len(self.reg)) 192 193 def test_init(self): 194 self.plugin_ep.init.return_value = "baz" 195 self.assertEqual(["baz"], self.reg.init("bar")) 196 self.plugin_ep.init.assert_called_once_with("bar") 197 198 def test_filter(self): 199 self.plugins.update({ 200 "foo": "bar", 201 "bar": "foo", 202 "baz": "boo", 203 }) 204 self.assertEqual( 205 {"foo": "bar", "baz": "boo"}, 206 self.reg.filter(lambda p_ep: str(p_ep).startswith("b"))) 207 208 def test_ifaces(self): 209 self.plugin_ep.ifaces.return_value = True 210 # pylint: disable=protected-access 211 self.assertEqual(self.plugins, self.reg.ifaces()._plugins) 212 self.plugin_ep.ifaces.return_value = False 213 self.assertEqual({}, self.reg.ifaces()._plugins) 214 215 def test_verify(self): 216 self.plugin_ep.verify.return_value = True 217 # pylint: disable=protected-access 218 self.assertEqual( 219 self.plugins, self.reg.verify(mock.MagicMock())._plugins) 220 self.plugin_ep.verify.return_value = False 221 self.assertEqual({}, self.reg.verify(mock.MagicMock())._plugins) 222 223 def test_prepare(self): 224 self.plugin_ep.prepare.return_value = "baz" 225 self.assertEqual(["baz"], self.reg.prepare()) 226 self.plugin_ep.prepare.assert_called_once_with() 227 228 def test_available(self): 229 self.plugin_ep.available = True 230 # pylint: disable=protected-access 231 self.assertEqual(self.plugins, self.reg.available()._plugins) 232 self.plugin_ep.available = False 233 self.assertEqual({}, self.reg.available()._plugins) 234 235 def test_find_init(self): 236 self.assertTrue(self.reg.find_init(mock.Mock()) is None) 237 self.plugin_ep.initalized = True 238 self.assertTrue( 239 self.reg.find_init(self.plugin_ep.init()) is self.plugin_ep) 240 241 def test_repr(self): 242 self.plugin_ep.__repr__ = lambda _: "PluginEntryPoint#mock" 243 self.assertEqual("PluginsRegistry(PluginEntryPoint#mock)", 244 repr(self.reg)) 245 246 def test_str(self): 247 self.plugin_ep.__str__ = lambda _: "Mock" 248 self.plugins["foo"] = "Mock" 249 self.assertEqual("Mock\n\nMock", str(self.reg)) 250 self.plugins.clear() 251 self.assertEqual("No plugins", str(self.reg)) 252 253 254 if __name__ == "__main__": 255 unittest.main() # pragma: no cover