Testing Plugins and Proxies
This page covers testing patterns for custom connection plugins, proxies, and capability interfaces.
Testing a Plugin Directly
Instantiate the plugin with a DeviceTypeDto and check its identity. To test a
capability method without a device, replace require_raw_connection with a fake
that answers the commands the plugin sends. These tests run against the SDK’s
own FRR plugin (neops_worker_sdk/connection/plugins/frr/netmiko_plugin.py):
import copy
import pytest
from neops_workflow_engine_client import DeviceTypeDto, PlatformTypeDto
from neops_worker_sdk.connection.plugins.frr import FRRNetmikoPlugin
@pytest.fixture
def frr_device() -> DeviceTypeDto:
return DeviceTypeDto(
id=1,
hostname="frr-rtr-01",
ip="10.0.1.1",
platform=PlatformTypeDto(short_name="frr"),
username="admin",
password="admin",
)
def test_plugin_identity(frr_device: DeviceTypeDto) -> None:
plugin = FRRNetmikoPlugin(frr_device)
assert plugin.platform == "frr"
assert plugin.connection_type == "ssh"
assert plugin.connection_library == "netmiko"
FRR_OUTPUTS = {
"/usr/bin/vtysh -c 'show running-config'": "hostname frr-rtr-01\n!",
"cat /etc/frr/frr.conf": "hostname frr-rtr-01",
}
class FakeNetmiko:
"""Answers the commands the plugin sends, so no SSH happens."""
def send_command(self, command: str) -> str:
return FRR_OUTPUTS[command]
def test_plugin_reads_the_config(frr_device: DeviceTypeDto, monkeypatch: pytest.MonkeyPatch) -> None:
plugin = FRRNetmikoPlugin(frr_device)
monkeypatch.setattr(plugin, "require_raw_connection", FakeNetmiko)
config = plugin.get_config()
assert config.running == "hostname frr-rtr-01\n!"
assert config.startup == "hostname frr-rtr-01"
For integration tests that actually connect, use a remote lab fixture to provide a real device.
Registry Isolation
Plugin tests must not leak registrations into other tests. Snapshot the registry, clear it for the test, and put the snapshot back afterwards:
from neops_worker_sdk.connection.registry import ( # noqa: E402
_connection_type_defaults,
_platform_defaults,
_plugin_registry,
clear_registry,
get_registry_snapshot,
register_connection_plugin,
)
from neops_worker_sdk.connection.types import BaseConnection, ConnectionPlugin # noqa: E402
@pytest.fixture
def isolated_registry():
"""Start from an empty registry and put the previous one back afterwards."""
snapshot = copy.deepcopy(get_registry_snapshot())
clear_registry()
try:
yield
finally:
clear_registry()
_plugin_registry.update(snapshot["plugins"])
_platform_defaults.update(snapshot["platform_defaults"])
_connection_type_defaults.update(snapshot["connection_type_defaults"])
@pytest.mark.usefixtures("isolated_registry")
def test_plugin_registers() -> None:
@register_connection_plugin()
class TestPlugin(ConnectionPlugin):
platform = "test"
connection_type = "ssh"
connection_library = "mock"
def _create_connection(self) -> BaseConnection:
raise NotImplementedError
snapshot = get_registry_snapshot()
assert snapshot["plugins"]["test"]["ssh"]["mock"] is TestPlugin
Warning
Clearing without restoring is a leak too: every later test then runs
without the SDK’s bundled plugins. Registering without clearing leaves the
test plugin visible in all subsequent tests, which causes flaky
AmbiguousPluginError failures that are hard to debug.
Testing Custom Capabilities
Verify that a proxy correctly raises NotImplementedForThisPlatform when
the resolved plugin does not implement a method:
from neops_worker_sdk.connection.exceptions import NotImplementedForThisPlatform
def test_unimplemented_capability_raises(frr_device):
# Assume MinimalPlugin implements NetworkDeviceLifecycleCapability but not cancel_reload()
proxy = FullProxy.get_connection(
frr_device, "ssh", "netmiko"
)
try:
with pytest.raises(NotImplementedForThisPlatform) as exc_info:
proxy.cancel_reload() # not implemented
assert exc_info.value.context.method_name == "cancel_reload"
assert exc_info.value.context.platform == "frr"
finally:
proxy.close()
Integration: Proxy + Plugin Together
Test the full stack — plugin resolution, connection, and capability calls — against a mock or real device:
@pytest.mark.asyncio
async def test_proxy_resolves_correct_plugin(frr_device):
with FRRProxy.connect(
frr_device, "ssh", "netmiko"
) as proxy:
information = proxy.get_information()
assert information.vendor is not None
For real-device tests, use @fb_test_case_with_lab with a topology that
includes the target platform.
Asserting Registration State
get_registry_snapshot() returns the full registry for inspection:
| Key | Type | Content |
|---|---|---|
plugins |
dict[platform, dict[type, dict[library, class]]] |
All registered plugins |
platform_defaults |
dict[platform, class] |
Platform-level defaults |
connection_type_defaults |
dict[(platform, type), class] |
Type-level defaults |
Use this to verify that your plugin package registers exactly the plugins you expect, and no more.

