Fixed formatting, fixed tests for type checker

This commit is contained in:
TheNetworkGuy
2026-02-11 15:30:53 +00:00
parent d53cc5e7d4
commit 3227bb3165
13 changed files with 351 additions and 312 deletions
+11 -10
View File
@@ -771,10 +771,10 @@ class PhysicalDevice:
# Check if proxy or proxy group is defined.
# Check for proxy_hostid for backwards compatibility with Zabbix <= 6
if (
(self.zbxproxy["idtype"] in host
and host[self.zbxproxy["idtype"]] == self.zbxproxy["id"])
or ("proxy_hostid" in host and
host["proxy_hostid"] == self.zbxproxy["id"])
self.zbxproxy["idtype"] in host
and host[self.zbxproxy["idtype"]] == self.zbxproxy["id"]
) or (
"proxy_hostid" in host and host["proxy_hostid"] == self.zbxproxy["id"]
):
self.logger.debug("Host %s: Proxy in-sync.", self.name)
# Proxy does not match, update Zabbix
@@ -890,10 +890,9 @@ class PhysicalDevice:
if isinstance(item, dict) and key == "details":
for k, i in item.items():
# Check if the key is found in Zabbix and if the value matches
if(
k in host["interfaces"][0][key] and
host["interfaces"][0][key][k] != str(i)
):
if k in host["interfaces"][0][key] and host["interfaces"][
0
][key][k] != str(i):
# If dict has not been created, add it
if key not in updates:
updates[key] = {}
@@ -1009,5 +1008,7 @@ class PhysicalDevice:
# all of the NetBox templates have been confirmed as successful
# and the ZBX template list is empty. This means that
# all of the templates match.
return (len(succesfull_templates) == len(self.zbx_templates)
and len(tmpls_from_zabbix) == 0)
return (
len(succesfull_templates) == len(self.zbx_templates)
and len(tmpls_from_zabbix) == 0
)
+3 -3
View File
@@ -118,9 +118,9 @@ class Hostgroup:
# If the string is between quotes, use it as a literal in the hostgroup name
minimum_length = 2
if (
len(hg_item) > minimum_length and
hg_item[0] == hg_item[-1] and
hg_item[0] in ("'", '"')
len(hg_item) > minimum_length
and hg_item[0] == hg_item[-1]
and hg_item[0] in ("'", '"')
):
hg_output.append(hg_item[1:-1])
else:
+1
View File
@@ -1,6 +1,7 @@
"""
All of the Zabbix interface related configuration
"""
from modules.exceptions import InterfaceConfigError
+10 -2
View File
@@ -54,14 +54,22 @@ class ZabbixTags:
Validates tag name
"""
max_tag_name_length = 256
return tag_name and isinstance(tag_name, str) and len(tag_name) <= max_tag_name_length
return (
tag_name
and isinstance(tag_name, str)
and len(tag_name) <= max_tag_name_length
)
def validate_value(self, tag_value):
"""
Validates tag value
"""
max_tag_value_length = 256
return tag_value and isinstance(tag_value, str) and len(tag_value) <= max_tag_value_length
return (
tag_value
and isinstance(tag_value, str)
and len(tag_value) <= max_tag_value_length
)
def render_tag(self, tag_name, tag_value):
"""
+1
View File
@@ -1,5 +1,6 @@
# pylint: disable=duplicate-code
"""Module that hosts all functions for virtual machine processing"""
from modules.config import load_config
from modules.device import PhysicalDevice
from modules.exceptions import InterfaceConfigError, SyncInventoryError, TemplateError
+24 -12
View File
@@ -1,4 +1,5 @@
"""Tests for configuration parsing in the modules.config module."""
import os
from unittest.mock import MagicMock, patch
@@ -12,8 +13,10 @@ from modules.config import (
def test_load_config_defaults():
"""Test that load_config returns default values when no config file or env vars are present"""
with patch('modules.config.load_config_file', return_value=DEFAULT_CONFIG.copy()), \
patch('modules.config.load_env_variable', return_value=None):
with (
patch("modules.config.load_config_file", return_value=DEFAULT_CONFIG.copy()),
patch("modules.config.load_env_variable", return_value=None),
):
config = load_config()
assert config == DEFAULT_CONFIG
assert config["templates_config_context"] is False
@@ -26,8 +29,10 @@ def test_load_config_file():
mock_config["templates_config_context"] = True
mock_config["sync_vms"] = True
with patch('modules.config.load_config_file', return_value=mock_config), \
patch('modules.config.load_env_variable', return_value=None):
with (
patch("modules.config.load_config_file", return_value=mock_config),
patch("modules.config.load_env_variable", return_value=None),
):
config = load_config()
assert config["templates_config_context"] is True
assert config["sync_vms"] is True
@@ -37,6 +42,7 @@ def test_load_config_file():
def test_load_env_variables():
"""Test that load_config properly loads values from environment variables"""
# Mock env variable loading to return values for specific keys
def mock_load_env(key):
if key == "sync_vms":
@@ -45,8 +51,10 @@ def test_load_env_variables():
return True
return None
with patch('modules.config.load_config_file', return_value=DEFAULT_CONFIG.copy()), \
patch('modules.config.load_env_variable', side_effect=mock_load_env):
with (
patch("modules.config.load_config_file", return_value=DEFAULT_CONFIG.copy()),
patch("modules.config.load_env_variable", side_effect=mock_load_env),
):
config = load_config()
assert config["sync_vms"] is True
assert config["create_journal"] is True
@@ -66,8 +74,10 @@ def test_env_vars_override_config_file():
return True
return None
with patch('modules.config.load_config_file', return_value=mock_config), \
patch('modules.config.load_env_variable', side_effect=mock_load_env):
with (
patch("modules.config.load_config_file", return_value=mock_config),
patch("modules.config.load_env_variable", side_effect=mock_load_env),
):
config = load_config()
# This should be overridden by the env var
assert config["sync_vms"] is True
@@ -78,8 +88,10 @@ def test_env_vars_override_config_file():
def test_load_config_file_function():
"""Test the load_config_file function directly"""
# Test when the file exists
with patch('pathlib.Path.exists', return_value=True), \
patch('importlib.util.spec_from_file_location') as mock_spec:
with (
patch("pathlib.Path.exists", return_value=True),
patch("importlib.util.spec_from_file_location") as mock_spec,
):
# Setup the mock module with attributes
mock_module = MagicMock()
mock_module.templates_config_context = True
@@ -91,7 +103,7 @@ def test_load_config_file_function():
mock_spec_instance.loader.exec_module = lambda x: None
# Patch module_from_spec to return our mock module
with patch('importlib.util.module_from_spec', return_value=mock_module):
with patch("importlib.util.module_from_spec", return_value=mock_module):
config = load_config_file(DEFAULT_CONFIG.copy())
assert config["templates_config_context"] is True
assert config["sync_vms"] is True
@@ -99,7 +111,7 @@ def test_load_config_file_function():
def test_load_config_file_not_found():
"""Test load_config_file when the config file doesn't exist"""
with patch('pathlib.Path.exists', return_value=False):
with patch("pathlib.Path.exists", return_value=False):
result = load_config_file(DEFAULT_CONFIG.copy())
# Should return a dict equal to DEFAULT_CONFIG, not a new object
assert result == DEFAULT_CONFIG
+25 -14
View File
@@ -1,4 +1,5 @@
"""Tests for device deletion functionality in the PhysicalDevice class."""
import unittest
from unittest.mock import MagicMock, patch
@@ -40,14 +41,14 @@ class TestDeviceDeletion(unittest.TestCase):
self.mock_logger = MagicMock()
# Create PhysicalDevice instance with mocks
with patch('modules.device.config', {"device_cf": "zabbix_hostid"}):
with patch("modules.device.config", {"device_cf": "zabbix_hostid"}):
self.device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
journal=True,
logger=self.mock_logger
logger=self.mock_logger,
)
def test_cleanup_successful_deletion(self):
@@ -60,12 +61,15 @@ class TestDeviceDeletion(unittest.TestCase):
self.device.cleanup()
# Verify
self.mock_zabbix.host.get.assert_called_once_with(filter={'hostid': '456'}, output=[])
self.mock_zabbix.host.delete.assert_called_once_with('456')
self.mock_zabbix.host.get.assert_called_once_with(
filter={"hostid": "456"}, output=[]
)
self.mock_zabbix.host.delete.assert_called_once_with("456")
self.mock_nb_device.save.assert_called_once()
self.assertIsNone(self.mock_nb_device.custom_fields["zabbix_hostid"])
self.mock_logger.info.assert_called_with(f"Host {self.device.name}: "
"Deleted host from Zabbix.")
self.mock_logger.info.assert_called_with(
f"Host {self.device.name}: Deleted host from Zabbix."
)
def test_cleanup_device_already_deleted(self):
"""Test cleanup when device is already deleted from Zabbix."""
@@ -76,12 +80,15 @@ class TestDeviceDeletion(unittest.TestCase):
self.device.cleanup()
# Verify
self.mock_zabbix.host.get.assert_called_once_with(filter={'hostid': '456'}, output=[])
self.mock_zabbix.host.get.assert_called_once_with(
filter={"hostid": "456"}, output=[]
)
self.mock_zabbix.host.delete.assert_not_called()
self.mock_nb_device.save.assert_called_once()
self.assertIsNone(self.mock_nb_device.custom_fields["zabbix_hostid"])
self.mock_logger.info.assert_called_with(
f"Host {self.device.name}: was already deleted from Zabbix. Removed link in NetBox.")
f"Host {self.device.name}: was already deleted from Zabbix. Removed link in NetBox."
)
def test_cleanup_api_error(self):
"""Test cleanup when Zabbix API returns an error."""
@@ -94,8 +101,10 @@ class TestDeviceDeletion(unittest.TestCase):
self.device.cleanup()
# Verify correct calls were made
self.mock_zabbix.host.get.assert_called_once_with(filter={'hostid': '456'}, output=[])
self.mock_zabbix.host.delete.assert_called_once_with('456')
self.mock_zabbix.host.get.assert_called_once_with(
filter={"hostid": "456"}, output=[]
)
self.mock_zabbix.host.delete.assert_called_once_with("456")
self.mock_nb_device.save.assert_not_called()
self.mock_logger.error.assert_called()
@@ -138,14 +147,14 @@ class TestDeviceDeletion(unittest.TestCase):
def test_create_journal_entry_when_disabled(self):
"""Test create_journal_entry when journaling is disabled."""
# Setup - create device with journal=False
with patch('modules.device.config', {"device_cf": "zabbix_hostid"}):
with patch("modules.device.config", {"device_cf": "zabbix_hostid"}):
device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
journal=False, # Disable journaling
logger=self.mock_logger
logger=self.mock_logger,
)
# Execute
@@ -161,8 +170,10 @@ class TestDeviceDeletion(unittest.TestCase):
self.mock_zabbix.host.get.return_value = [{"hostid": "456"}]
# Execute
with patch.object(self.device, 'create_journal_entry') as mock_journal_entry:
with patch.object(self.device, "create_journal_entry") as mock_journal_entry:
self.device.cleanup()
# Verify
mock_journal_entry.assert_called_once_with("warning", "Deleted host from Zabbix")
mock_journal_entry.assert_called_once_with(
"warning", "Deleted host from Zabbix"
)
+11 -9
View File
@@ -1,4 +1,5 @@
"""Tests for the Hostgroup class in the hostgroups module."""
import unittest
from unittest.mock import MagicMock, patch
@@ -111,12 +112,12 @@ class TestHostgroups(unittest.TestCase):
# Mock data for nesting tests
self.mock_regions_data = [
{"name": "ParentRegion", "parent": None, "_depth": 0},
{"name": "TestRegion", "parent": "ParentRegion", "_depth": 1}
{"name": "TestRegion", "parent": "ParentRegion", "_depth": 1},
]
self.mock_groups_data = [
{"name": "ParentSiteGroup", "parent": None, "_depth": 0},
{"name": "TestSiteGroup", "parent": "ParentSiteGroup", "_depth": 1}
{"name": "TestSiteGroup", "parent": "ParentSiteGroup", "_depth": 1},
]
def test_device_hostgroup_creation(self):
@@ -170,7 +171,9 @@ class TestHostgroups(unittest.TestCase):
# Custom format: site/tenant/platform/location
complex_result = hostgroup.generate("site/tenant/platform/location")
self.assertEqual(complex_result, "TestSite/TestTenant/TestPlatform/TestLocation")
self.assertEqual(
complex_result, "TestSite/TestTenant/TestPlatform/TestLocation"
)
def test_vm_hostgroup_formats(self):
"""Test different hostgroup formats for VMs."""
@@ -259,7 +262,7 @@ class TestHostgroups(unittest.TestCase):
def test_nested_region_hostgroups(self):
"""Test hostgroup generation with nested regions."""
# Mock the build_path function to return a predictable result
with patch('modules.hostgroups.build_path') as mock_build_path:
with patch("modules.hostgroups.build_path") as mock_build_path:
# Configure the mock to return a list of regions in the path
mock_build_path.return_value = ["ParentRegion", "TestRegion"]
@@ -270,7 +273,7 @@ class TestHostgroups(unittest.TestCase):
"4.0",
self.mock_logger,
nested_region_flag=True,
nb_regions=self.mock_regions_data
nb_regions=self.mock_regions_data,
)
# Generate hostgroup with region
@@ -281,7 +284,7 @@ class TestHostgroups(unittest.TestCase):
def test_nested_sitegroup_hostgroups(self):
"""Test hostgroup generation with nested site groups."""
# Mock the build_path function to return a predictable result
with patch('modules.hostgroups.build_path') as mock_build_path:
with patch("modules.hostgroups.build_path") as mock_build_path:
# Configure the mock to return a list of site groups in the path
mock_build_path.return_value = ["ParentSiteGroup", "TestSiteGroup"]
@@ -292,7 +295,7 @@ class TestHostgroups(unittest.TestCase):
"4.0",
self.mock_logger,
nested_sitegroup_flag=True,
nb_groups=self.mock_groups_data
nb_groups=self.mock_groups_data,
)
# Generate hostgroup with site_group
@@ -300,7 +303,6 @@ class TestHostgroups(unittest.TestCase):
# Should include the parent site group
self.assertEqual(result, "TestSite/ParentSiteGroup/TestSiteGroup/TestRole")
def test_vm_list_based_hostgroup_format(self):
"""Test VM hostgroup generation with a list-based format."""
hostgroup = Hostgroup("vm", self.mock_vm, "4.0", self.mock_logger)
@@ -341,7 +343,7 @@ class TestHostgroups(unittest.TestCase):
"site",
"manufacturer/role",
"platform/location",
"tenant_group/tenant"
"tenant_group/tenant",
]
# Generate and check each format
+36 -36
View File
@@ -1,5 +1,7 @@
"""Tests for the ZabbixInterface class in the interface module."""
import unittest
from typing import cast
from modules.exceptions import InterfaceConfigError
from modules.interface import ZabbixInterface
@@ -19,11 +21,7 @@ class TestZabbixInterface(unittest.TestCase):
"zabbix": {
"interface_type": 2,
"interface_port": "161",
"snmp": {
"version": 2,
"community": "public",
"bulk": 1
}
"snmp": {"version": 2, "community": "public", "bulk": 1},
}
}
@@ -38,16 +36,13 @@ class TestZabbixInterface(unittest.TestCase):
"authpassphrase": "authpass123",
"privprotocol": "AES",
"privpassphrase": "privpass123",
"contextname": "context1"
}
"contextname": "context1",
},
}
}
self.agent_context = {
"zabbix": {
"interface_type": 1,
"interface_port": "10050"
}
"zabbix": {"interface_type": 1, "interface_port": "10050"}
}
def test_init(self):
@@ -128,9 +123,10 @@ class TestZabbixInterface(unittest.TestCase):
interface.set_snmp()
# Check SNMP details
self.assertEqual(interface.interface["details"]["version"], "2")
self.assertEqual(interface.interface["details"]["community"], "public")
self.assertEqual(interface.interface["details"]["bulk"], "1")
details = cast(dict[str, str], interface.interface["details"])
self.assertEqual(details["version"], "2")
self.assertEqual(details["community"], "public")
self.assertEqual(details["bulk"], "1")
def test_set_snmp_v3(self):
"""Test set_snmp with SNMPv3 configuration."""
@@ -141,14 +137,19 @@ class TestZabbixInterface(unittest.TestCase):
interface.set_snmp()
# Check SNMP details
self.assertEqual(interface.interface["details"]["version"], "3")
self.assertEqual(interface.interface["details"]["securityname"], "snmpuser")
self.assertEqual(interface.interface["details"]["securitylevel"], "authPriv")
self.assertEqual(interface.interface["details"]["authprotocol"], "SHA")
self.assertEqual(interface.interface["details"]["authpassphrase"], "authpass123")
self.assertEqual(interface.interface["details"]["privprotocol"], "AES")
self.assertEqual(interface.interface["details"]["privpassphrase"], "privpass123")
self.assertEqual(interface.interface["details"]["contextname"], "context1")
details = cast(dict[str, str], interface.interface["details"])
self.assertEqual(details["version"], "3")
self.assertEqual(details["securityname"], "snmpuser")
self.assertEqual(details["securitylevel"], "authPriv")
self.assertEqual(details["authprotocol"], "SHA")
self.assertEqual(
details["authpassphrase"], "authpass123"
)
self.assertEqual(details["privprotocol"], "AES")
self.assertEqual(
details["privpassphrase"], "privpass123"
)
self.assertEqual(details["contextname"], "context1")
def test_set_snmp_no_snmp_config(self):
"""Test set_snmp with missing SNMP configuration."""
@@ -169,7 +170,7 @@ class TestZabbixInterface(unittest.TestCase):
"interface_type": 2,
"snmp": {
"version": 4 # Invalid version
}
},
}
}
interface = ZabbixInterface(context, self.test_ip)
@@ -187,7 +188,7 @@ class TestZabbixInterface(unittest.TestCase):
"interface_type": 2,
"snmp": {
"community": "public" # No version specified
}
},
}
}
interface = ZabbixInterface(context, self.test_ip)
@@ -214,9 +215,12 @@ class TestZabbixInterface(unittest.TestCase):
# Check interface properties
self.assertEqual(interface.interface["type"], "2")
self.assertEqual(interface.interface["port"], "161")
self.assertEqual(interface.interface["details"]["version"], "2")
self.assertEqual(interface.interface["details"]["community"], "{$SNMP_COMMUNITY}")
self.assertEqual(interface.interface["details"]["bulk"], "1")
details = cast(dict[str, str], interface.interface["details"])
self.assertEqual(details["version"], "2")
self.assertEqual(
details["community"], "{$SNMP_COMMUNITY}"
)
self.assertEqual(details["bulk"], "1")
def test_set_default_agent(self):
"""Test set_default_agent method."""
@@ -230,14 +234,7 @@ class TestZabbixInterface(unittest.TestCase):
def test_snmpv2_no_community(self):
"""Test SNMPv2 with no community string specified."""
# Create context with SNMPv2 but no community
context = {
"zabbix": {
"interface_type": 2,
"snmp": {
"version": 2
}
}
}
context = {"zabbix": {"interface_type": 2, "snmp": {"version": 2}}}
interface = ZabbixInterface(context, self.test_ip)
interface.get_context() # Set the interface type
@@ -245,4 +242,7 @@ class TestZabbixInterface(unittest.TestCase):
interface.set_snmp()
# Should use default community string
self.assertEqual(interface.interface["details"]["community"], "{$SNMP_COMMUNITY}")
details = cast(dict[str, str], interface.interface["details"])
self.assertEqual(
details["community"], "{$SNMP_COMMUNITY}"
)
+1
View File
@@ -1,4 +1,5 @@
"""Tests for list-based hostgroup formats in configuration."""
import unittest
from unittest.mock import MagicMock
+65 -70
View File
@@ -1,4 +1,5 @@
"""Tests for the PhysicalDevice class in the device module."""
import unittest
from unittest.mock import MagicMock, patch
@@ -35,8 +36,10 @@ class TestPhysicalDevice(unittest.TestCase):
self.mock_logger = MagicMock()
# Create PhysicalDevice instance with mocks
with patch('modules.device.config',
{"device_cf": "zabbix_hostid",
with patch(
"modules.device.config",
{
"device_cf": "zabbix_hostid",
"template_cf": "zabbix_template",
"templates_config_context": False,
"templates_config_context_overrule": False,
@@ -44,15 +47,16 @@ class TestPhysicalDevice(unittest.TestCase):
"traverse_site_groups": False,
"inventory_mode": "disabled",
"inventory_sync": False,
"device_inventory_map": {}
}):
"device_inventory_map": {},
},
):
self.device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
journal=True,
logger=self.mock_logger
logger=self.mock_logger,
)
def test_init(self):
@@ -71,8 +75,10 @@ class TestPhysicalDevice(unittest.TestCase):
self.mock_nb_device.name = "test-devïce"
# We need to patch the search function to simulate finding special characters
with patch('modules.device.search') as mock_search, \
patch('modules.device.config', {"device_cf": "zabbix_hostid"}):
with (
patch("modules.device.search") as mock_search,
patch("modules.device.config", {"device_cf": "zabbix_hostid"}),
):
# Make the search function return True to simulate special characters
mock_search.return_value = True
@@ -81,7 +87,7 @@ class TestPhysicalDevice(unittest.TestCase):
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# With the mocked search function, the name should be changed to NETBOX_ID format
@@ -95,19 +101,17 @@ class TestPhysicalDevice(unittest.TestCase):
"""Test get_templates_context with valid config."""
# Set up config_context with valid template data
self.mock_nb_device.config_context = {
"zabbix": {
"templates": ["Template1", "Template2"]
}
"zabbix": {"templates": ["Template1", "Template2"]}
}
# Create device with the updated mock
with patch('modules.device.config', {"device_cf": "zabbix_hostid"}):
with patch("modules.device.config", {"device_cf": "zabbix_hostid"}):
device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# Test that templates are returned correctly
@@ -117,20 +121,16 @@ class TestPhysicalDevice(unittest.TestCase):
def test_get_templates_context_with_string(self):
"""Test get_templates_context with a string instead of list."""
# Set up config_context with a string template
self.mock_nb_device.config_context = {
"zabbix": {
"templates": "Template1"
}
}
self.mock_nb_device.config_context = {"zabbix": {"templates": "Template1"}}
# Create device with the updated mock
with patch('modules.device.config', {"device_cf": "zabbix_hostid"}):
with patch("modules.device.config", {"device_cf": "zabbix_hostid"}):
device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# Test that template is wrapped in a list
@@ -143,13 +143,13 @@ class TestPhysicalDevice(unittest.TestCase):
self.mock_nb_device.config_context = {}
# Create device with the updated mock
with patch('modules.device.config', {"device_cf": "zabbix_hostid"}):
with patch("modules.device.config", {"device_cf": "zabbix_hostid"}):
device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# Test that TemplateError is raised
@@ -162,13 +162,13 @@ class TestPhysicalDevice(unittest.TestCase):
self.mock_nb_device.config_context = {"zabbix": {}}
# Create device with the updated mock
with patch('modules.device.config', {"device_cf": "zabbix_hostid"}):
with patch("modules.device.config", {"device_cf": "zabbix_hostid"}):
device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# Test that TemplateError is raised
@@ -178,25 +178,25 @@ class TestPhysicalDevice(unittest.TestCase):
def test_set_template_with_config_context(self):
"""Test set_template with templates_config_context=True."""
# Set up config_context with templates
self.mock_nb_device.config_context = {
"zabbix": {
"templates": ["Template1"]
}
}
self.mock_nb_device.config_context = {"zabbix": {"templates": ["Template1"]}}
# Mock get_templates_context to return expected templates
with patch.object(PhysicalDevice, 'get_templates_context', return_value=["Template1"]):
with patch('modules.device.config', {"device_cf": "zabbix_hostid"}):
with patch.object(
PhysicalDevice, "get_templates_context", return_value=["Template1"]
):
with patch("modules.device.config", {"device_cf": "zabbix_hostid"}):
device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# Call set_template with prefer_config_context=True
result = device.set_template(prefer_config_context=True, overrule_custom=False)
result = device.set_template(
prefer_config_context=True, overrule_custom=False
)
# Check result and template names
self.assertTrue(result)
@@ -208,20 +208,20 @@ class TestPhysicalDevice(unittest.TestCase):
config_patch = {
"device_cf": "zabbix_hostid",
"inventory_mode": "disabled",
"inventory_sync": False
"inventory_sync": False,
}
with patch('modules.device.config', config_patch):
with patch("modules.device.config", config_patch):
device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# Call set_inventory with the config patch still active
with patch('modules.device.config', config_patch):
with patch("modules.device.config", config_patch):
result = device.set_inventory({})
# Check result
@@ -235,20 +235,20 @@ class TestPhysicalDevice(unittest.TestCase):
config_patch = {
"device_cf": "zabbix_hostid",
"inventory_mode": "manual",
"inventory_sync": False
"inventory_sync": False,
}
with patch('modules.device.config', config_patch):
with patch("modules.device.config", config_patch):
device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# Call set_inventory with the config patch still active
with patch('modules.device.config', config_patch):
with patch("modules.device.config", config_patch):
result = device.set_inventory({})
# Check result
@@ -261,20 +261,20 @@ class TestPhysicalDevice(unittest.TestCase):
config_patch = {
"device_cf": "zabbix_hostid",
"inventory_mode": "automatic",
"inventory_sync": False
"inventory_sync": False,
}
with patch('modules.device.config', config_patch):
with patch("modules.device.config", config_patch):
device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# Call set_inventory with the config patch still active
with patch('modules.device.config', config_patch):
with patch("modules.device.config", config_patch):
result = device.set_inventory({})
# Check result
@@ -288,38 +288,31 @@ class TestPhysicalDevice(unittest.TestCase):
"device_cf": "zabbix_hostid",
"inventory_mode": "manual",
"inventory_sync": True,
"device_inventory_map": {
"name": "name",
"serial": "serialno_a"
}
"device_inventory_map": {"name": "name", "serial": "serialno_a"},
}
with patch('modules.device.config', config_patch):
with patch("modules.device.config", config_patch):
device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# Create a mock device with the required attributes
mock_device_data = {
"name": "test-device",
"serial": "ABC123"
}
mock_device_data = {"name": "test-device", "serial": "ABC123"}
# Call set_inventory with the config patch still active
with patch('modules.device.config', config_patch):
with patch("modules.device.config", config_patch):
result = device.set_inventory(mock_device_data)
# Check result
self.assertTrue(result)
self.assertEqual(device.inventory_mode, 0) # Manual mode
self.assertEqual(device.inventory, {
"name": "test-device",
"serialno_a": "ABC123"
})
self.assertEqual(
device.inventory, {"name": "test-device", "serialno_a": "ABC123"}
)
def test_iscluster_true(self):
"""Test isCluster when device is part of a cluster."""
@@ -327,13 +320,13 @@ class TestPhysicalDevice(unittest.TestCase):
self.mock_nb_device.virtual_chassis = MagicMock()
# Create device with the updated mock
with patch('modules.device.config', {"device_cf": "zabbix_hostid"}):
with patch("modules.device.config", {"device_cf": "zabbix_hostid"}):
device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# Check isCluster result
@@ -345,26 +338,27 @@ class TestPhysicalDevice(unittest.TestCase):
self.mock_nb_device.virtual_chassis = None
# Create device with the updated mock
with patch('modules.device.config', {"device_cf": "zabbix_hostid"}):
with patch("modules.device.config", {"device_cf": "zabbix_hostid"}):
device = PhysicalDevice(
self.mock_nb_device,
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# Check isCluster result
self.assertFalse(device.is_cluster())
def test_promote_master_device_primary(self):
"""Test promoteMasterDevice when device is primary in cluster."""
# Set up virtual chassis with master device
mock_vc = MagicMock()
mock_vc.name = "virtual-chassis-1"
mock_master = MagicMock()
mock_master.id = self.mock_nb_device.id # Set master ID to match the current device
mock_master.id = (
self.mock_nb_device.id
) # Set master ID to match the current device
mock_vc.master = mock_master
self.mock_nb_device.virtual_chassis = mock_vc
@@ -374,7 +368,7 @@ class TestPhysicalDevice(unittest.TestCase):
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# Call promoteMasterDevice and check the result
@@ -385,14 +379,15 @@ class TestPhysicalDevice(unittest.TestCase):
# Device name should be updated to virtual chassis name
self.assertEqual(device.name, "virtual-chassis-1")
def test_promote_master_device_secondary(self):
"""Test promoteMasterDevice when device is secondary in cluster."""
# Set up virtual chassis with a different master device
mock_vc = MagicMock()
mock_vc.name = "virtual-chassis-1"
mock_master = MagicMock()
mock_master.id = self.mock_nb_device.id + 1 # Different ID than the current device
mock_master.id = (
self.mock_nb_device.id + 1
) # Different ID than the current device
mock_vc.master = mock_master
self.mock_nb_device.virtual_chassis = mock_vc
@@ -402,7 +397,7 @@ class TestPhysicalDevice(unittest.TestCase):
self.mock_zabbix,
self.mock_nb_journal,
"3.0",
logger=self.mock_logger
logger=self.mock_logger,
)
# Call promoteMasterDevice and check the result
+7 -3
View File
@@ -12,6 +12,7 @@ def test_sanatize_log_output_secrets():
assert sanitized["macros"][0]["value"] == "********"
assert sanitized["macros"][1]["value"] == "notsecret"
def test_sanatize_log_output_interface_secrets():
data = {
"interfaceid": 123,
@@ -20,8 +21,8 @@ def test_sanatize_log_output_interface_secrets():
"privpassphrase": "anothersecret",
"securityname": "sensitiveuser",
"community": "public",
"other": "normalvalue"
}
"other": "normalvalue",
},
}
sanitized = sanatize_log_output(data)
# Sensitive fields should be sanitized
@@ -34,6 +35,7 @@ def test_sanatize_log_output_interface_secrets():
# interfaceid should be removed
assert "interfaceid" not in sanitized
def test_sanatize_log_output_interface_macros():
data = {
"interfaceid": 123,
@@ -42,7 +44,7 @@ def test_sanatize_log_output_interface_macros():
"privpassphrase": "{$SECRET_MACRO}",
"securityname": "{$USER_MACRO}",
"community": "{$SNNMP_COMMUNITY}",
}
},
}
sanitized = sanatize_log_output(data)
# Macro values should not be sanitized
@@ -52,11 +54,13 @@ def test_sanatize_log_output_interface_macros():
assert sanitized["details"]["community"] == "{$SNNMP_COMMUNITY}"
assert "interfaceid" not in sanitized
def test_sanatize_log_output_plain_data():
data = {"foo": "bar", "baz": 123}
sanitized = sanatize_log_output(data)
assert sanitized == data
def test_sanatize_log_output_non_dict():
data = [1, 2, 3]
sanitized = sanatize_log_output(data)
+35 -32
View File
@@ -20,6 +20,7 @@ class DummyNB:
return self.config_context[key]
raise KeyError(key)
class TestUsermacroSync(unittest.TestCase):
def setUp(self):
self.nb = DummyNB(serial="1234")
@@ -44,20 +45,18 @@ class TestUsermacroSync(unittest.TestCase):
zabbix=MagicMock(),
nb_journal_class=MagicMock(),
nb_version="3.0",
logger=self.logger
logger=self.logger,
)
# Override the usermacro map method for testing
device._usermacro_map = MagicMock(return_value=self.usermacro_map)
return device
@patch("modules.device.config", {
"usermacro_sync": False,
"device_cf": "zabbix_hostid",
"tag_sync": False
})
def test_usermacro_sync_false(self):
@patch(
"modules.device.config",
{"usermacro_sync": False, "device_cf": "zabbix_hostid", "tag_sync": False},
)
@patch.object(PhysicalDevice, '_usermacro_map')
def test_usermacro_sync_false(self, mock_usermacro_map):
mock_usermacro_map.return_value = self.usermacro_map
device = self.create_mock_device()
# Call set_usermacros
@@ -66,17 +65,20 @@ class TestUsermacroSync(unittest.TestCase):
self.assertEqual(device.usermacros, [])
self.assertTrue(result is True or result is None)
@patch("modules.device.config", {
"usermacro_sync": True,
"device_cf": "zabbix_hostid",
"tag_sync": False
})
@patch(
"modules.device.config",
{"usermacro_sync": True, "device_cf": "zabbix_hostid", "tag_sync": False},
)
@patch("modules.device.ZabbixUsermacros")
def test_usermacro_sync_true(self, mock_usermacros_class):
@patch.object(PhysicalDevice, '_usermacro_map')
def test_usermacro_sync_true(self, mock_usermacro_map, mock_usermacros_class):
mock_usermacro_map.return_value = self.usermacro_map
# Mock the ZabbixUsermacros class to return some test data
mock_macros_instance = MagicMock()
mock_macros_instance.sync = True # This is important - sync must be True
mock_macros_instance.generate.return_value = [{"macro": "{$HW_SERIAL}", "value": "1234"}]
mock_macros_instance.generate.return_value = [
{"macro": "{$HW_SERIAL}", "value": "1234"}
]
mock_usermacros_class.return_value = mock_macros_instance
device = self.create_mock_device()
@@ -87,17 +89,20 @@ class TestUsermacroSync(unittest.TestCase):
self.assertIsInstance(device.usermacros, list)
self.assertGreater(len(device.usermacros), 0)
@patch("modules.device.config", {
"usermacro_sync": "full",
"device_cf": "zabbix_hostid",
"tag_sync": False
})
@patch(
"modules.device.config",
{"usermacro_sync": "full", "device_cf": "zabbix_hostid", "tag_sync": False},
)
@patch("modules.device.ZabbixUsermacros")
def test_usermacro_sync_full(self, mock_usermacros_class):
@patch.object(PhysicalDevice, '_usermacro_map')
def test_usermacro_sync_full(self, mock_usermacro_map, mock_usermacros_class):
mock_usermacro_map.return_value = self.usermacro_map
# Mock the ZabbixUsermacros class to return some test data
mock_macros_instance = MagicMock()
mock_macros_instance.sync = True # This is important - sync must be True
mock_macros_instance.generate.return_value = [{"macro": "{$HW_SERIAL}", "value": "1234"}]
mock_macros_instance.generate.return_value = [
{"macro": "{$HW_SERIAL}", "value": "1234"}
]
mock_usermacros_class.return_value = mock_macros_instance
device = self.create_mock_device()
@@ -108,6 +113,7 @@ class TestUsermacroSync(unittest.TestCase):
self.assertIsInstance(device.usermacros, list)
self.assertGreater(len(device.usermacros), 0)
class TestZabbixUsermacros(unittest.TestCase):
def setUp(self):
self.nb = DummyNB()
@@ -128,7 +134,9 @@ class TestZabbixUsermacros(unittest.TestCase):
def test_render_macro_dict(self):
macros = ZabbixUsermacros(self.nb, {}, False, logger=self.logger)
macro = macros.render_macro("{$FOO}", {"value": "bar", "type": "secret", "description": "desc"})
macro = macros.render_macro(
"{$FOO}", {"value": "bar", "type": "secret", "description": "desc"}
)
self.assertEqual(macro["macro"], "{$FOO}")
self.assertEqual(macro["value"], "bar")
self.assertEqual(macro["type"], "1")
@@ -164,13 +172,7 @@ class TestZabbixUsermacros(unittest.TestCase):
self.assertEqual(result[1]["macro"], "{$BAR}")
def test_generate_from_config_context(self):
config_context = {
"zabbix": {
"usermacros": {
"{$TEST_MACRO}": "test_value"
}
}
}
config_context = {"zabbix": {"usermacros": {"{$TEST_MACRO}": "test_value"}}}
nb = DummyNB(config_context=config_context)
macros = ZabbixUsermacros(nb, {}, True, logger=self.logger)
result = macros.generate()
@@ -178,5 +180,6 @@ class TestZabbixUsermacros(unittest.TestCase):
self.assertEqual(result[0]["macro"], "{$TEST_MACRO}")
self.assertEqual(result[0]["value"], "test_value")
if __name__ == "__main__":
unittest.main()