Skip to content

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 mock device and call capability methods:

import pytest
from neops_workflow_engine_client import DeviceTypeDto

from my_package.plugins.frr_plugin import FRRPlugin  # see examples/device-connections/frr_plugin.py


@pytest.fixture
def frr_device() -> DeviceTypeDto:
    return DeviceTypeDto(
        id=1,
        hostname="frr-rtr-01",
        ip="10.0.1.1",
        platform="frr",
        username="admin",
        password="admin",
    )


def test_plugin_identity(frr_device):
    plugin = FRRPlugin(device=frr_device)
    assert plugin.platform == "frr"
    assert plugin.connection_type == "ssh"
    assert plugin.connection_library == "netmiko"

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. Use clear_registry() and get_registry_snapshot() to isolate:

from neops_worker_sdk.connection.registry import (
    clear_registry,
    get_registry_snapshot,
    register_connection_plugin,
)


@pytest.fixture(autouse=True)
def clean_registry():
    clear_registry()
    yield
    clear_registry()


def test_plugin_registers():
    @register_connection_plugin()
    class TestPlugin(ConnectionPlugin):
        platform = "test"
        connection_type = "ssh"
        connection_library = "mock"
        ...

    snapshot = get_registry_snapshot()
    assert "test" in snapshot["plugins"]
    assert "ssh" in snapshot["plugins"]["test"]

Warning

Without clear_registry(), plugins registered in one test will be visible in all subsequent tests. This 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 only implements DeviceInfoCapability
    proxy = FullProxy.get_connection(
        frr_device, "ssh", "netmiko"
    )
    try:
        with pytest.raises(NotImplementedForThisPlatform) as exc_info:
            proxy.get_inventory()  # not implemented

        assert exc_info.value.context.method_name == "get_inventory"
        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:
        version = proxy.get_version()
        assert version["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:

snapshot = get_registry_snapshot()
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.