Let adapter plugins provide configured endpoints

This commit is contained in:
Lyncoln
2026-09-20 19:20:26 -04:00
parent 832928159d
commit 16359dc164
6 changed files with 421 additions and 34 deletions
+12
View File
@@ -150,6 +150,15 @@ class ReconcileCliTests(unittest.TestCase):
verizon_endpoint.identity: verizon,
}
def endpoint_loader(name, config):
if name == "npm":
return (npm_endpoint,)
if name == "verizon":
return (verizon_endpoint,)
raise AssertionError(
f"Unexpected adapter plugin: {name}"
)
def loader(name, config, endpoint):
return adapters[endpoint.identity]
@@ -167,6 +176,9 @@ class ReconcileCliTests(unittest.TestCase):
"ENABLED_PLUGINS": "npm,verizon",
},
clear=True,
), patch(
"dns_sync.cli.configured_adapter_endpoints",
side_effect=endpoint_loader,
), patch(
"dns_sync.cli.load_adapter",
side_effect=loader,
+287
View File
@@ -8,6 +8,7 @@ from unittest.mock import patch
from dns_sync.adapters import Endpoint
from dns_sync.registry import (
configured_adapter_endpoints,
enabled_plugins,
load_adapter,
)
@@ -221,5 +222,291 @@ class PluginRegistryTests(unittest.TestCase):
)
def test_builtin_adapter_supplies_configured_endpoints(self):
endpoint = Endpoint(
"npm",
"192.168.1.3:81",
)
config = SimpleNamespace(
npm_endpoints=(endpoint,),
)
with patch.dict(
os.environ,
{
"ENABLED_PLUGINS": "npm",
},
clear=True,
):
endpoints = configured_adapter_endpoints(
"npm",
config,
)
self.assertEqual(
endpoints,
(endpoint,),
)
def test_external_adapter_cache_respects_plugin_root(self):
with tempfile.TemporaryDirectory() as first_directory, \
tempfile.TemporaryDirectory() as second_directory:
first_root = Path(first_directory)
second_root = Path(second_directory)
first_plugin = first_root / "example_cache"
second_plugin = second_root / "example_cache"
first_plugin.mkdir()
second_plugin.mkdir()
first_plugin.joinpath("__init__.py").write_text(
textwrap.dedent(
"""
from dns_sync.adapters import Endpoint
def configured_endpoints(config):
return (
Endpoint(
"example_cache",
"first.example:443",
),
)
class Plugin:
name = "example_cache"
def __init__(
self,
config,
endpoint,
):
self.endpoint = endpoint
"""
)
)
second_plugin.joinpath("__init__.py").write_text(
textwrap.dedent(
"""
from dns_sync.adapters import Endpoint
def configured_endpoints(config):
return (
Endpoint(
"example_cache",
"second.example:443",
),
)
class Plugin:
name = "example_cache"
def __init__(
self,
config,
endpoint,
):
self.endpoint = endpoint
"""
)
)
with patch.dict(
os.environ,
{
"ENABLED_PLUGINS": "example_cache",
"DNS_SYNC_PLUGIN_PATH": first_directory,
},
clear=True,
):
first = configured_adapter_endpoints(
"example_cache",
SimpleNamespace(),
)
with patch.dict(
os.environ,
{
"ENABLED_PLUGINS": "example_cache",
"DNS_SYNC_PLUGIN_PATH": second_directory,
},
clear=True,
):
second = configured_adapter_endpoints(
"example_cache",
SimpleNamespace(),
)
self.assertEqual(
tuple(endpoint.identity for endpoint in first),
("example_cache://first.example:443",),
)
self.assertEqual(
tuple(endpoint.identity for endpoint in second),
("example_cache://second.example:443",),
)
def test_external_adapter_supplies_configured_endpoints(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
plugin = root / "example"
plugin.mkdir()
(plugin / "__init__.py").write_text(
textwrap.dedent(
"""
import os
from dns_sync.adapters import Endpoint
def configured_endpoints(config):
address = os.environ["EXAMPLE_ENDPOINT"]
return (
Endpoint("example", address),
)
class Plugin:
name = "example"
def __init__(
self,
config,
endpoint,
):
self.config = config
self.endpoint = endpoint
"""
)
)
with patch.dict(
os.environ,
{
"ENABLED_PLUGINS": "example",
"DNS_SYNC_PLUGIN_PATH": directory,
"EXAMPLE_ENDPOINT": "example.test:9443",
},
clear=True,
):
endpoints = configured_adapter_endpoints(
"example",
SimpleNamespace(),
)
self.assertEqual(
tuple(
endpoint.identity
for endpoint in endpoints
),
("example://example.test:9443",),
)
def test_adapter_missing_endpoint_hook_fails_closed(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
plugin = root / "example_missing_hook"
plugin.mkdir()
(plugin / "__init__.py").write_text(
textwrap.dedent(
"""
class Plugin:
name = "example_missing_hook"
def __init__(
self,
config,
endpoint,
):
self.config = config
self.endpoint = endpoint
"""
)
)
with patch.dict(
os.environ,
{
"ENABLED_PLUGINS": "example_missing_hook",
"DNS_SYNC_PLUGIN_PATH": directory,
},
clear=True,
):
with self.assertRaisesRegex(
RuntimeError,
"does not export configured_endpoints",
):
configured_adapter_endpoints(
"example_missing_hook",
SimpleNamespace(),
)
def test_adapter_endpoint_hook_cannot_cross_plugin_boundary(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
plugin = root / "example_wrong_endpoint"
plugin.mkdir()
(plugin / "__init__.py").write_text(
textwrap.dedent(
"""
from dns_sync.adapters import Endpoint
def configured_endpoints(config):
return (
Endpoint(
"other",
"example.test:443",
),
)
class Plugin:
name = "example_wrong_endpoint"
def __init__(
self,
config,
endpoint,
):
self.config = config
self.endpoint = endpoint
"""
)
)
with patch.dict(
os.environ,
{
"ENABLED_PLUGINS": "example_wrong_endpoint",
"DNS_SYNC_PLUGIN_PATH": directory,
},
clear=True,
):
with self.assertRaisesRegex(
RuntimeError,
"returned endpoint for plugin",
):
configured_adapter_endpoints(
"example_wrong_endpoint",
SimpleNamespace(),
)
if __name__ == "__main__":
unittest.main()