"""Shared pytest fixtures for NetBox LibreNMS Plugin tests.""" from unittest.mock import MagicMock, patch import pytest # ============================================================================= # Configuration Fixtures # ============================================================================= @pytest.fixture def mock_multi_server_config(): """Multi-server configuration dict.""" return { "default": { "librenms_url": "https://librenms-default.example.com", "api_token": "default-token-12345", "cache_timeout": 300, "verify_ssl": True, }, "secondary": { "librenms_url": "https://librenms-secondary.example.com", "api_token": "secondary-token-67890", "cache_timeout": 600, "verify_ssl": False, }, } @pytest.fixture def mock_legacy_config(): """Legacy single-server configuration dict (flat structure).""" return { "librenms_url": "https://librenms.example.com", "api_token": "legacy-token-abcdef", "cache_timeout": 300, "verify_ssl": True, } # ============================================================================= # API Instance Fixtures # ============================================================================= @pytest.fixture def mock_librenms_api(mock_multi_server_config): """Pre-configured LibreNMSAPI instance with mocked dependencies.""" with patch("netbox_librenms_plugin.librenms_api.get_plugin_config") as mock_config: mock_config.return_value = mock_multi_server_config from netbox_librenms_plugin.librenms_api import LibreNMSAPI api = LibreNMSAPI(server_key="default") yield api # ============================================================================= # NetBox Object Mocks (Avoid Database) # ============================================================================= @pytest.fixture def mock_netbox_device(): """Mock NetBox Device object without database.""" device = MagicMock() device.name = "test-device" device.cf = {} # Custom fields device.primary_ip4 = MagicMock() device.primary_ip4.address = MagicMock() device.primary_ip4.address.ip = "192.168.1.1" device.primary_ip4.__str__ = lambda self: "192.168.1.1/24" device.primary_ip6 = None device._meta.model_name = "device" return device @pytest.fixture def mock_netbox_vm(): """Mock NetBox VirtualMachine object without database.""" vm = MagicMock() vm.name = "test-vm" vm.cf = {} vm.primary_ip4 = MagicMock() vm.primary_ip4.address = MagicMock() vm.primary_ip4.address.ip = "10.0.0.1" vm.primary_ip6 = None vm._meta.model_name = "virtualmachine" return vm # ============================================================================= # HTTP Response Fixtures # ============================================================================= @pytest.fixture def mock_response_factory(): """Factory for creating mock HTTP responses.""" def _create_response(status_code=200, json_data=None, raise_for_status=None): response = MagicMock() response.status_code = status_code response.json.return_value = json_data or {} response.ok = 200 <= status_code < 300 if raise_for_status: response.raise_for_status.side_effect = raise_for_status return response return _create_response @pytest.fixture def mock_success_response(mock_response_factory): """Standard successful API response.""" return mock_response_factory(status_code=200, json_data={"status": "ok", "message": "Success"}) @pytest.fixture def mock_device_response(mock_response_factory): """Mock response for device info endpoint.""" return mock_response_factory( status_code=200, json_data={ "status": "ok", "devices": [ { "device_id": 42, "hostname": "test-device.example.com", "sysName": "test-device", "ip": "192.168.1.1", "status": 1, "location": "Data Center 1", } ], }, ) @pytest.fixture def mock_error_response(mock_response_factory): """Standard error API response.""" return mock_response_factory( status_code=500, json_data={"status": "error", "message": "Internal server error"}, ) @pytest.fixture def mock_auth_error_response(mock_response_factory): """Authentication error response (401).""" return mock_response_factory(status_code=401, json_data={"status": "error", "message": "Unauthorized"}) # ============================================================================= # Phase 2: Import Utilities Fixtures # ============================================================================= @pytest.fixture def sample_librenms_device(): """Sample LibreNMS device data for import tests.""" return { "device_id": 1, "hostname": "switch-01.example.com", "sysName": "switch-01", "ip": "192.168.1.1", "location": "DC1", "os": "ios", "hardware": "C9300-48P", "version": "17.3.1", "status": 1, } @pytest.fixture def sample_librenms_device_minimal(): """Minimal LibreNMS device data with missing fields.""" return { "device_id": 2, "hostname": "10.0.0.1", "status": 1, } @pytest.fixture def sample_validation_state(): """Sample validation state for testing updates.""" return { "device_id": 1, "hostname": "switch-01", "is_ready": False, "can_import": False, "import_as_vm": False, "existing_device": None, "issues": ["Device role must be manually selected before import"], "warnings": [], "site": { "found": True, "site": MagicMock(id=1, name="DC1"), "match_type": "exact", }, "device_type": { "found": True, "device_type": MagicMock(id=1, model="C9300-48P"), "match_type": "exact", }, "device_role": {"found": False, "role": None, "available_roles": []}, "cluster": {"found": False, "cluster": None, "available_clusters": []}, "platform": { "found": True, "platform": MagicMock(id=1, name="ios"), "match_type": "exact", }, } @pytest.fixture def sample_validation_state_vm(): """Sample validation state for VM import testing.""" return { "device_id": 1, "hostname": "vm-01", "is_ready": False, "can_import": False, "import_as_vm": True, "existing_device": None, "issues": ["Cluster must be manually selected before import"], "warnings": [], "cluster": {"found": False, "cluster": None, "available_clusters": []}, "device_role": {"found": False, "role": None, "available_roles": []}, } @pytest.fixture def mock_netbox_site(): """Mock NetBox Site object.""" site = MagicMock() site.id = 1 site.name = "DC1" site.slug = "dc1" return site @pytest.fixture def mock_netbox_platform(): """Mock NetBox Platform object.""" platform = MagicMock() platform.id = 1 platform.name = "Cisco IOS" platform.slug = "cisco_ios" return platform @pytest.fixture def mock_netbox_device_type(): """Mock NetBox DeviceType object.""" dt = MagicMock() dt.id = 1 dt.model = "C9300-48P" dt.manufacturer = MagicMock(name="Cisco") return dt @pytest.fixture def mock_netbox_device_role(): """Mock NetBox DeviceRole object.""" role = MagicMock() role.id = 1 role.name = "Access Switch" role.slug = "access-switch" return role @pytest.fixture def mock_netbox_cluster(): """Mock NetBox Cluster object.""" cluster = MagicMock() cluster.id = 1 cluster.name = "VMware Cluster 1" return cluster @pytest.fixture def mock_netbox_rack(): """Mock NetBox Rack object.""" rack = MagicMock() rack.id = 1 rack.name = "Rack A1" rack.site = MagicMock(id=1, name="DC1") return rack # ============================================================================= # Server Mapping Fixtures (used by test_sync_view_mismatch.py) # ============================================================================= @pytest.fixture def mock_plugins_config_single_server(): """PLUGINS_CONFIG with a single 'production' server (for _build_all_server_mappings tests).""" return { "netbox_librenms_plugin": { "servers": { "production": { "display_name": "Production LibreNMS", "librenms_url": "https://librenms.example.com", }, } } } @pytest.fixture def mock_plugins_config_empty_servers(): """PLUGINS_CONFIG with no configured servers (simulates all orphaned).""" return {"netbox_librenms_plugin": {"servers": {}}} @pytest.fixture def mock_plugins_config_multi_server_mapping(): """PLUGINS_CONFIG with 'production' and 'mock-dev' servers (for multi-server mapping tests).""" return { "netbox_librenms_plugin": { "servers": { "production": { "display_name": "Production LibreNMS", "librenms_url": "https://librenms.example.com", }, "mock-dev": { "display_name": "Mock", "librenms_url": "http://mock.example.com", }, } } }