Files
supervisor/tests/host/test_configuration.py
Copilot a8b7923a42 Add test coverage for _map_nm_wifi method (#6275)
* Initial plan

* Add comprehensive test coverage for _map_nm_wifi method

Co-authored-by: agners <34061+agners@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: agners <34061+agners@users.noreply.github.com>
2025-11-03 10:04:01 +01:00

528 lines
17 KiB
Python

"""Test host configuration interface."""
from unittest.mock import Mock
from dbus_fast import Variant
import pytest
from supervisor.coresys import CoreSys
from supervisor.dbus.const import DeviceType
from supervisor.host.configuration import Interface, VlanConfig, WifiConfig
from supervisor.host.const import AuthMethod, InterfaceType, WifiMode
from tests.dbus_service_mocks.base import DBusServiceMock
from tests.dbus_service_mocks.network_connection_settings import (
ConnectionSettings as ConnectionSettingsService,
)
from tests.dbus_service_mocks.network_device import Device as DeviceService
async def test_equals_dbus_interface_no_settings(coresys: CoreSys):
"""Test returns False when NetworkInterface has no settings."""
await coresys.host.network.load()
# Create test interface
test_interface = Interface(
name="eth0",
enabled=True,
connected=True,
primary=False,
type=InterfaceType.ETHERNET,
ipv4=None,
ipv4setting=None,
ipv6=None,
ipv6setting=None,
wifi=None,
vlan=None,
path="platform-ff3f0000.ethernet",
mac="AA:BB:CC:DD:EE:FF",
mdns=None,
llmnr=None,
)
# Get network interface and remove its connection to simulate no settings
network_interface = coresys.dbus.network.get("eth0")
network_interface._connection = None
assert test_interface.equals_dbus_interface(network_interface) is False
async def test_equals_dbus_interface_connection_name_match(coresys: CoreSys):
"""Test interface comparison returns True when connection interface name matches."""
await coresys.host.network.load()
# Create test interface
test_interface = Interface(
name="eth0",
enabled=True,
connected=True,
primary=False,
type=InterfaceType.ETHERNET,
ipv4=None,
ipv4setting=None,
ipv6=None,
ipv6setting=None,
wifi=None,
vlan=None,
path="platform-ff3f0000.ethernet",
mac="AA:BB:CC:DD:EE:FF",
mdns=None,
llmnr=None,
)
# Get the network interface - this should have connection settings with interface-name = "eth0"
network_interface = coresys.dbus.network.get("eth0")
assert test_interface.equals_dbus_interface(network_interface) is True
def test_equals_dbus_interface_connection_name_no_match():
"""Test interface comparison returns False when connection interface name differs."""
# Create test interface
test_interface = Interface(
name="eth0",
enabled=True,
connected=True,
primary=False,
type=InterfaceType.ETHERNET,
ipv4=None,
ipv4setting=None,
ipv6=None,
ipv6setting=None,
wifi=None,
vlan=None,
path="platform-ff3f0000.ethernet",
mac="AA:BB:CC:DD:EE:FF",
mdns=None,
llmnr=None,
)
# Mock network interface with different connection name
mock_network_interface = Mock()
mock_network_interface.type = DeviceType.ETHERNET
mock_network_interface.settings = Mock()
mock_network_interface.settings.match = None
mock_network_interface.settings.connection = Mock()
mock_network_interface.settings.connection.interface_name = "eth1" # Different name
assert test_interface.equals_dbus_interface(mock_network_interface) is False
async def test_equals_dbus_interface_path_match(
coresys: CoreSys,
connection_settings_service: ConnectionSettingsService,
):
"""Test interface comparison returns True when path matches."""
await coresys.host.network.load()
# Create test interface
test_interface = Interface(
name="eth0",
enabled=True,
connected=True,
primary=False,
type=InterfaceType.ETHERNET,
ipv4=None,
ipv4setting=None,
ipv6=None,
ipv6setting=None,
wifi=None,
vlan=None,
path="platform-ff3f0000.ethernet",
mac="AA:BB:CC:DD:EE:FF",
mdns=None,
llmnr=None,
)
# Add match settings with path and remove interface name to force path matching
connection_settings_service.settings["match"] = {
"path": Variant("as", ["platform-ff3f0000.ethernet"])
}
connection_settings_service.settings["connection"].pop("interface-name", None)
network_interface = coresys.dbus.network.get("eth0")
assert test_interface.equals_dbus_interface(network_interface) is True
def test_equals_dbus_interface_vlan_type_mismatch():
"""Test VLAN interface returns False when NetworkInterface type doesn't match."""
# Create VLAN test interface
test_vlan_interface = Interface(
name="eth0.10",
enabled=True,
connected=True,
primary=False,
type=InterfaceType.VLAN,
ipv4=None,
ipv4setting=None,
ipv6=None,
ipv6setting=None,
wifi=None,
vlan=VlanConfig(id=10, interface="0c23631e-2118-355c-bbb0-8943229cb0d6"),
path="",
mac="52:54:00:2B:36:80",
mdns=None,
llmnr=None,
)
# Mock non-VLAN NetworkInterface - should return False immediately
mock_network_interface = Mock()
mock_network_interface.type = DeviceType.ETHERNET # Not VLAN type
mock_network_interface.settings = Mock()
# Should return False immediately since types don't match
assert test_vlan_interface.equals_dbus_interface(mock_network_interface) is False
def test_equals_dbus_interface_vlan_missing_info():
"""Test VLAN interface raises RuntimeError when VLAN info is missing."""
# Create VLAN test interface without VLAN config
test_vlan_interface = Interface(
name="eth0.10",
enabled=True,
connected=True,
primary=False,
type=InterfaceType.VLAN,
ipv4=None,
ipv4setting=None,
ipv6=None,
ipv6setting=None,
wifi=None,
vlan=None, # Missing VLAN config!
path="",
mac="52:54:00:2B:36:80",
mdns=None,
llmnr=None,
)
# Mock VLAN NetworkInterface
mock_network_interface = Mock()
mock_network_interface.type = DeviceType.VLAN
mock_network_interface.settings = Mock()
# Should raise RuntimeError
try:
test_vlan_interface.equals_dbus_interface(mock_network_interface)
assert False, "Expected RuntimeError"
except RuntimeError as e:
assert str(e) == "VLAN information missing"
def test_equals_dbus_interface_vlan_no_vlan_settings():
"""Test VLAN interface returns False when NetworkInterface has no VLAN settings."""
# Create VLAN test interface
test_vlan_interface = Interface(
name="eth0.10",
enabled=True,
connected=True,
primary=False,
type=InterfaceType.VLAN,
ipv4=None,
ipv4setting=None,
ipv6=None,
ipv6setting=None,
wifi=None,
vlan=VlanConfig(id=10, interface="0c23631e-2118-355c-bbb0-8943229cb0d6"),
path="",
mac="52:54:00:2B:36:80",
mdns=None,
llmnr=None,
)
# Mock VLAN NetworkInterface without VLAN settings
mock_network_interface = Mock()
mock_network_interface.type = DeviceType.VLAN
mock_network_interface.settings = Mock()
mock_network_interface.settings.vlan = None # No VLAN settings
assert test_vlan_interface.equals_dbus_interface(mock_network_interface) is False
@pytest.fixture(name="device_eth0_10_service")
async def fixture_device_eth0_10_service(
network_manager_services: dict[str, DBusServiceMock | dict[str, DBusServiceMock]],
) -> DeviceService:
"""Mock Device eth0.10 service."""
yield network_manager_services["network_device"][
"/org/freedesktop/NetworkManager/Devices/38"
]
async def test_equals_dbus_interface_eth0_10_real(
coresys: CoreSys, device_eth0_10_service: DeviceService
):
"""Test eth0.10 interface with real D-Bus interface."""
await coresys.host.network.load()
# Get the eth0.10 interface
network_interface = coresys.dbus.network.get("eth0.10")
# Check if it has the expected VLAN type
assert network_interface.type == DeviceType.VLAN
assert network_interface.settings is not None
assert network_interface.settings.vlan is not None
# Create matching test interface with correct parent UUID
test_vlan_interface = Interface(
name="eth0.10",
enabled=True,
connected=True,
primary=False,
type=InterfaceType.VLAN,
ipv4=None,
ipv4setting=None,
ipv6=None,
ipv6setting=None,
wifi=None,
vlan=VlanConfig(
id=network_interface.settings.vlan.id,
interface=network_interface.settings.vlan.parent,
),
path="",
mac="52:54:00:2B:36:80",
mdns=None,
llmnr=None,
)
# Test should pass with matching VLAN config
assert test_vlan_interface.equals_dbus_interface(network_interface) is True
def test_map_nm_wifi_non_wireless_interface():
"""Test _map_nm_wifi returns None for non-wireless interface."""
# Mock non-wireless interface
mock_interface = Mock()
mock_interface.type = DeviceType.ETHERNET
mock_interface.settings = Mock()
result = Interface._map_nm_wifi(mock_interface)
assert result is None
def test_map_nm_wifi_no_settings():
"""Test _map_nm_wifi returns None when interface has no settings."""
# Mock wireless interface without settings
mock_interface = Mock()
mock_interface.type = DeviceType.WIRELESS
mock_interface.settings = None
result = Interface._map_nm_wifi(mock_interface)
assert result is None
def test_map_nm_wifi_open_authentication():
"""Test _map_nm_wifi with open authentication (no security)."""
# Mock wireless interface with open authentication
mock_interface = Mock()
mock_interface.type = DeviceType.WIRELESS
mock_interface.settings = Mock()
mock_interface.settings.wireless_security = None
mock_interface.settings.wireless = Mock()
mock_interface.settings.wireless.ssid = "TestSSID"
mock_interface.settings.wireless.mode = "infrastructure"
mock_interface.wireless = None
mock_interface.interface_name = "wlan0"
result = Interface._map_nm_wifi(mock_interface)
assert result is not None
assert isinstance(result, WifiConfig)
assert result.mode == WifiMode.INFRASTRUCTURE
assert result.ssid == "TestSSID"
assert result.auth == AuthMethod.OPEN
assert result.psk is None
assert result.signal is None
def test_map_nm_wifi_wep_authentication():
"""Test _map_nm_wifi with WEP authentication."""
# Mock wireless interface with WEP authentication
mock_interface = Mock()
mock_interface.type = DeviceType.WIRELESS
mock_interface.settings = Mock()
mock_interface.settings.wireless_security = Mock()
mock_interface.settings.wireless_security.key_mgmt = "none"
mock_interface.settings.wireless_security.psk = None
mock_interface.settings.wireless = Mock()
mock_interface.settings.wireless.ssid = "WEPNetwork"
mock_interface.settings.wireless.mode = "infrastructure"
mock_interface.wireless = None
mock_interface.interface_name = "wlan0"
result = Interface._map_nm_wifi(mock_interface)
assert result is not None
assert isinstance(result, WifiConfig)
assert result.auth == AuthMethod.WEP
assert result.ssid == "WEPNetwork"
assert result.psk is None
def test_map_nm_wifi_wpa_psk_authentication():
"""Test _map_nm_wifi with WPA-PSK authentication."""
# Mock wireless interface with WPA-PSK authentication
mock_interface = Mock()
mock_interface.type = DeviceType.WIRELESS
mock_interface.settings = Mock()
mock_interface.settings.wireless_security = Mock()
mock_interface.settings.wireless_security.key_mgmt = "wpa-psk"
mock_interface.settings.wireless_security.psk = "SecretPassword123"
mock_interface.settings.wireless = Mock()
mock_interface.settings.wireless.ssid = "SecureNetwork"
mock_interface.settings.wireless.mode = "infrastructure"
mock_interface.wireless = None
mock_interface.interface_name = "wlan0"
result = Interface._map_nm_wifi(mock_interface)
assert result is not None
assert isinstance(result, WifiConfig)
assert result.auth == AuthMethod.WPA_PSK
assert result.ssid == "SecureNetwork"
assert result.psk == "SecretPassword123"
def test_map_nm_wifi_unsupported_authentication():
"""Test _map_nm_wifi returns None for unsupported authentication method."""
# Mock wireless interface with unsupported authentication
mock_interface = Mock()
mock_interface.type = DeviceType.WIRELESS
mock_interface.settings = Mock()
mock_interface.settings.wireless_security = Mock()
mock_interface.settings.wireless_security.key_mgmt = "wpa-eap" # Unsupported
mock_interface.settings.wireless = Mock()
mock_interface.settings.wireless.ssid = "EnterpriseNetwork"
mock_interface.interface_name = "wlan0"
result = Interface._map_nm_wifi(mock_interface)
assert result is None
def test_map_nm_wifi_different_modes():
"""Test _map_nm_wifi with different wifi modes."""
modes_to_test = [
("infrastructure", WifiMode.INFRASTRUCTURE),
("mesh", WifiMode.MESH),
("adhoc", WifiMode.ADHOC),
("ap", WifiMode.AP),
]
for mode_value, expected_mode in modes_to_test:
mock_interface = Mock()
mock_interface.type = DeviceType.WIRELESS
mock_interface.settings = Mock()
mock_interface.settings.wireless_security = None
mock_interface.settings.wireless = Mock()
mock_interface.settings.wireless.ssid = "TestSSID"
mock_interface.settings.wireless.mode = mode_value
mock_interface.wireless = None
mock_interface.interface_name = "wlan0"
result = Interface._map_nm_wifi(mock_interface)
assert result is not None
assert result.mode == expected_mode
def test_map_nm_wifi_with_signal():
"""Test _map_nm_wifi with wireless signal strength."""
# Mock wireless interface with active connection and signal
mock_interface = Mock()
mock_interface.type = DeviceType.WIRELESS
mock_interface.settings = Mock()
mock_interface.settings.wireless_security = None
mock_interface.settings.wireless = Mock()
mock_interface.settings.wireless.ssid = "TestSSID"
mock_interface.settings.wireless.mode = "infrastructure"
mock_interface.wireless = Mock()
mock_interface.wireless.active = Mock()
mock_interface.wireless.active.strength = 75
mock_interface.interface_name = "wlan0"
result = Interface._map_nm_wifi(mock_interface)
assert result is not None
assert result.signal == 75
def test_map_nm_wifi_without_signal():
"""Test _map_nm_wifi without wireless signal (no active connection)."""
# Mock wireless interface without active connection
mock_interface = Mock()
mock_interface.type = DeviceType.WIRELESS
mock_interface.settings = Mock()
mock_interface.settings.wireless_security = None
mock_interface.settings.wireless = Mock()
mock_interface.settings.wireless.ssid = "TestSSID"
mock_interface.settings.wireless.mode = "infrastructure"
mock_interface.wireless = None
mock_interface.interface_name = "wlan0"
result = Interface._map_nm_wifi(mock_interface)
assert result is not None
assert result.signal is None
def test_map_nm_wifi_wireless_no_active_ap():
"""Test _map_nm_wifi with wireless object but no active access point."""
# Mock wireless interface with wireless object but no active AP
mock_interface = Mock()
mock_interface.type = DeviceType.WIRELESS
mock_interface.settings = Mock()
mock_interface.settings.wireless_security = None
mock_interface.settings.wireless = Mock()
mock_interface.settings.wireless.ssid = "TestSSID"
mock_interface.settings.wireless.mode = "infrastructure"
mock_interface.wireless = Mock()
mock_interface.wireless.active = None
mock_interface.interface_name = "wlan0"
result = Interface._map_nm_wifi(mock_interface)
assert result is not None
assert result.signal is None
def test_map_nm_wifi_no_wireless_settings():
"""Test _map_nm_wifi when wireless settings are missing."""
# Mock wireless interface without wireless settings
mock_interface = Mock()
mock_interface.type = DeviceType.WIRELESS
mock_interface.settings = Mock()
mock_interface.settings.wireless_security = None
mock_interface.settings.wireless = None
mock_interface.wireless = None
mock_interface.interface_name = "wlan0"
result = Interface._map_nm_wifi(mock_interface)
assert result is not None
assert result.ssid == ""
assert result.mode == WifiMode.INFRASTRUCTURE # Default mode
def test_map_nm_wifi_no_wireless_mode():
"""Test _map_nm_wifi when wireless mode is not specified."""
# Mock wireless interface without mode specified
mock_interface = Mock()
mock_interface.type = DeviceType.WIRELESS
mock_interface.settings = Mock()
mock_interface.settings.wireless_security = None
mock_interface.settings.wireless = Mock()
mock_interface.settings.wireless.ssid = "TestSSID"
mock_interface.settings.wireless.mode = None
mock_interface.wireless = None
mock_interface.interface_name = "wlan0"
result = Interface._map_nm_wifi(mock_interface)
assert result is not None
assert result.mode == WifiMode.INFRASTRUCTURE # Default mode