from __future__ import annotations
import importlib.util
import os
import pathlib
import sys
import pytest
_HERE = pathlib.Path(__file__).resolve()
_PLUGIN_DIR = _HERE.parents[1] _SDK_PY_SRC = _PLUGIN_DIR.parents[1] / "sdk-py" / "src"
if _SDK_PY_SRC.is_dir() and str(_SDK_PY_SRC) not in sys.path:
sys.path.insert(0, str(_SDK_PY_SRC))
_PKG = "net_hermes_plugin"
@pytest.fixture(scope="session")
def plugin():
if _PKG in sys.modules:
return sys.modules[_PKG]
spec = importlib.util.spec_from_file_location(
_PKG,
_PLUGIN_DIR / "__init__.py",
submodule_search_locations=[str(_PLUGIN_DIR)],
)
assert spec is not None and spec.loader is not None
mod = importlib.util.module_from_spec(spec)
sys.modules[_PKG] = mod
spec.loader.exec_module(mod)
return mod
class FakeCtx:
def __init__(self) -> None:
self.tools: dict = {}
self.hooks: dict = {}
def register_tool(
self,
*,
name,
toolset,
schema,
handler,
check_fn=None,
requires_env=None,
is_async=False,
description="",
emoji="",
override=False,
) -> None:
self.tools[name] = {
"toolset": toolset,
"schema": schema,
"handler": handler,
"check_fn": check_fn,
"is_async": is_async,
"emoji": emoji,
}
def register_hook(self, event, fn) -> None:
self.hooks.setdefault(event, []).append(fn)
@pytest.fixture()
def ctx() -> FakeCtx:
return FakeCtx()
@pytest.fixture(scope="session")
def node_ready(plugin, tmp_path_factory):
store = tmp_path_factory.mktemp("net-plugin") / "pins.json"
_keys = ("NET_MESH_PIN_STORE", "NET_MESH_PSK", "NET_MESH_PEERS")
_saved = {k: os.environ.get(k) for k in _keys}
os.environ["NET_MESH_PIN_STORE"] = str(store)
os.environ.pop("NET_MESH_PSK", None)
os.environ.pop("NET_MESH_PEERS", None)
node = plugin.node
try:
assert node.check_net_available(), "isolated node should be healthy/available"
yield node
finally:
node.shutdown()
for k, v in _saved.items():
if v is None:
os.environ.pop(k, None)
else:
os.environ[k] = v