mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-11-06 09:29:31 +00:00
* 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>
528 lines
17 KiB
Python
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
|