Files
NetAlertX/test/plugins/test___template.py
T
2026-09-02 07:58:31 +10:00

110 lines
4.0 KiB
Python

"""
Tests for the __template plugin scaffold (server/plugins/__template/rename_me.py).
This is the copy-paste starting point for every new plugin, so keeping it
covered by a passing test (and demonstrating the expected test shape) gives
new plugin authors something to copy alongside the script itself.
Run from inside the NetAlertX container, or locally - NetAlertX-specific
modules are stubbed out automatically before the script is imported.
pytest "test/plugins/test___template.py" -v
"""
import base64
import json
import os
import sys
import tempfile
import types
from unittest.mock import MagicMock, patch
_tmp_log = tempfile.mkdtemp()
_tmp_db = tempfile.mkdtemp()
def _decode_settings_base64(encoded_str, convert_types=True):
"""Mirrors plugin_helper.decode_settings_base64 - reimplemented here
(rather than importing the real plugin_helper.py) since that module's
other top-level imports need the full container environment."""
settings_list = json.loads(base64.b64decode(encoded_str).decode("utf-8"))
result = {}
for _, key, _type, value in settings_list:
result[key] = value.lower() == "true" if convert_types and _type.lower() == "boolean" else value
return result
def _encode_instance(name, url, enabled):
payload = [
["group", "TMP_instance_name", "string", name],
["group", "TMP_instance_url", "string", url],
["group", "TMP_instance_enabled", "boolean", str(enabled)],
]
return base64.b64encode(json.dumps(payload).encode("utf-8")).decode("ascii")
_stubbed_module_names = []
def _stub(name: str, **attrs):
if name not in sys.modules:
mod = types.ModuleType(name)
for k, v in attrs.items():
setattr(mod, k, v)
sys.modules[name] = mod
_stubbed_module_names.append(name)
_stub("pytz", timezone=lambda tz: tz)
_stub("conf")
_stub("const", dataPath=_tmp_db, dbFolderPath=_tmp_db, configPath=_tmp_db, logPath=_tmp_log)
_stub("plugin_helper", Plugin_Objects=MagicMock, decode_settings_base64=_decode_settings_base64)
_stub("logger", mylog=lambda *a: None, Logger=MagicMock)
_stub("helper", get_setting_value=lambda k: "")
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "server", "plugins", "__template"))
import rename_me # noqa: E402
# Stops these fake entries from shadowing the real modules for other test
# files collected later in the same pytest session (rename_me's own
# module-level `from x import y` bindings are already resolved by now).
for _name in _stubbed_module_names:
sys.modules.pop(_name, None)
class TestGetDeviceData:
def test_returns_the_sample_devices(self):
data = rename_me.get_device_data(some_setting="anything")
assert len(data) == 2
assert {d["mac_address"] for d in data} == {"00:11:22:33:44:55", "00:11:22:33:44:66"}
for device in data:
for key in ("mac_address", "ip_address", "hostname", "vendor", "device_type", "last_seen"):
assert key in device
class TestGetConfiguredInstances:
def test_decodes_and_returns_enabled_instances(self):
raw = [
_encode_instance("Site A", "https://a.example", True),
_encode_instance("Site B", "https://b.example", False),
]
with patch("rename_me.get_setting_value", side_effect=lambda k: raw if k == "TMP_nested_form_example" else ""):
instances = rename_me.get_configured_instances()
assert instances == [{"name": "Site A", "url": "https://a.example", "enabled": True}]
def test_empty_setting_returns_no_instances(self):
with patch("rename_me.get_setting_value", return_value=""):
assert rename_me.get_configured_instances() == []
class TestMain:
def test_writes_one_object_per_device_and_result_file_once(self):
rename_me.plugin_objects = MagicMock()
rename_me.plugin_objects.__len__ = lambda self: 2
rename_me.main()
assert rename_me.plugin_objects.add_object.call_count == 2
rename_me.plugin_objects.write_result_file.assert_called_once()