mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-11-12 20:40:21 +00:00
* Listen for dbus property changes * Avoid remaking dbus proxy objects * proper snake case for pylint * some cleanup and more tests
254 lines
9.0 KiB
Python
254 lines
9.0 KiB
Python
"""Test network manager."""
|
|
import asyncio
|
|
from ipaddress import IPv4Address, IPv6Address
|
|
from unittest.mock import Mock, PropertyMock, patch
|
|
|
|
from dbus_next.aio.proxy_object import ProxyInterface
|
|
import pytest
|
|
|
|
from supervisor.const import CoreState
|
|
from supervisor.coresys import CoreSys
|
|
from supervisor.dbus.const import ConnectionStateFlags, InterfaceMethod
|
|
from supervisor.exceptions import DBusFatalError, HostNotSupportedError
|
|
from supervisor.homeassistant.const import WSEvent, WSType
|
|
from supervisor.host.const import InterfaceType, WifiMode
|
|
from supervisor.host.network import Interface, IpConfig
|
|
from supervisor.utils.dbus import DBus
|
|
|
|
from tests.common import fire_property_change_signal
|
|
|
|
|
|
async def test_load(coresys: CoreSys, dbus: list[str]):
|
|
"""Test network manager load."""
|
|
dbus.clear()
|
|
await coresys.host.network.load()
|
|
|
|
assert coresys.host.network.connectivity is True
|
|
|
|
assert len(coresys.host.network.dns_servers) == 1
|
|
assert str(coresys.host.network.dns_servers[0]) == "192.168.30.1"
|
|
|
|
assert len(coresys.host.network.interfaces) == 2
|
|
assert coresys.host.network.interfaces[0].name == "eth0"
|
|
assert coresys.host.network.interfaces[0].enabled is True
|
|
assert coresys.host.network.interfaces[0].ipv4.method == InterfaceMethod.AUTO
|
|
assert coresys.host.network.interfaces[0].ipv4.gateway == IPv4Address("192.168.2.1")
|
|
assert coresys.host.network.interfaces[0].ipv4.ready is True
|
|
assert coresys.host.network.interfaces[0].ipv6.method == InterfaceMethod.AUTO
|
|
assert coresys.host.network.interfaces[0].ipv6.gateway == IPv6Address(
|
|
"fe80::da58:d7ff:fe00:9c69"
|
|
)
|
|
assert coresys.host.network.interfaces[0].ipv6.ready is True
|
|
assert coresys.host.network.interfaces[1].name == "wlan0"
|
|
assert coresys.host.network.interfaces[1].enabled is False
|
|
|
|
assert (
|
|
"/org/freedesktop/NetworkManager-org.freedesktop.NetworkManager.ActivateConnection"
|
|
in dbus
|
|
)
|
|
assert (
|
|
"/org/freedesktop/NetworkManager-org.freedesktop.NetworkManager.Connectivity"
|
|
in dbus
|
|
)
|
|
assert (
|
|
"/org/freedesktop/NetworkManager-org.freedesktop.NetworkManager.CheckConnectivity"
|
|
not in dbus
|
|
)
|
|
|
|
|
|
async def test_load_with_disabled_methods(coresys: CoreSys):
|
|
"""Test load does not disable methods of interfaces."""
|
|
with patch(
|
|
"supervisor.host.network.Interface.from_dbus_interface",
|
|
return_value=Interface(
|
|
"eth0",
|
|
True,
|
|
False,
|
|
False,
|
|
InterfaceType.ETHERNET,
|
|
IpConfig(InterfaceMethod.DISABLED, [], None, [], False),
|
|
IpConfig(InterfaceMethod.DISABLED, [], None, [], False),
|
|
None,
|
|
None,
|
|
),
|
|
), patch.object(
|
|
coresys.host.sys_dbus.network,
|
|
"activate_connection",
|
|
new=Mock(wraps=coresys.host.sys_dbus.network.activate_connection),
|
|
) as activate_connection:
|
|
await coresys.host.network.load()
|
|
|
|
activate_connection.assert_not_called()
|
|
|
|
|
|
async def test_load_with_network_connection_issues(coresys: CoreSys, dbus: list[str]):
|
|
"""Test load does not update interfaces with network connection issues."""
|
|
with patch(
|
|
"supervisor.dbus.network.connection.NetworkConnection.state_flags",
|
|
new=PropertyMock(return_value={ConnectionStateFlags.IP6_READY}),
|
|
), patch(
|
|
"supervisor.dbus.network.connection.NetworkConnection.ipv4",
|
|
new=PropertyMock(return_value=None),
|
|
):
|
|
dbus.clear()
|
|
await coresys.host.network.load()
|
|
|
|
assert (
|
|
"/org/freedesktop/NetworkManager-org.freedesktop.NetworkManager.ActivateConnection"
|
|
not in dbus
|
|
)
|
|
|
|
assert len(coresys.host.network.interfaces) == 2
|
|
assert coresys.host.network.interfaces[0].name == "eth0"
|
|
assert coresys.host.network.interfaces[0].enabled is True
|
|
assert coresys.host.network.interfaces[0].ipv4.method == InterfaceMethod.AUTO
|
|
assert coresys.host.network.interfaces[0].ipv4.gateway is None
|
|
assert coresys.host.network.interfaces[0].ipv6.method == InterfaceMethod.AUTO
|
|
assert coresys.host.network.interfaces[0].ipv6.gateway == IPv6Address(
|
|
"fe80::da58:d7ff:fe00:9c69"
|
|
)
|
|
|
|
|
|
async def test_scan_wifi(coresys: CoreSys):
|
|
"""Test scanning wifi."""
|
|
with pytest.raises(HostNotSupportedError):
|
|
await coresys.host.network.scan_wifi(coresys.host.network.get("eth0"))
|
|
|
|
with patch("supervisor.host.network.asyncio.sleep"):
|
|
aps = await coresys.host.network.scan_wifi(coresys.host.network.get("wlan0"))
|
|
|
|
assert len(aps) == 2
|
|
assert aps[0].mac == "E4:57:40:A9:D7:DE"
|
|
assert aps[0].mode == WifiMode.INFRASTRUCTURE
|
|
assert aps[1].mac == "18:4B:0D:23:A1:9C"
|
|
assert aps[1].mode == WifiMode.INFRASTRUCTURE
|
|
|
|
|
|
async def test_scan_wifi_with_failures(coresys: CoreSys, caplog):
|
|
"""Test scanning wifi with accesspoint processing failures."""
|
|
# pylint: disable=protected-access
|
|
init_proxy = DBus._init_proxy
|
|
call_dbus = DBus.call_dbus
|
|
|
|
async def mock_init_proxy(self):
|
|
if self.object_path != "/org/freedesktop/NetworkManager/AccessPoint/99999":
|
|
return await init_proxy(self)
|
|
|
|
raise DBusFatalError("Fail")
|
|
|
|
async def mock_call_dbus(
|
|
proxy_interface: ProxyInterface,
|
|
method: str,
|
|
*args,
|
|
remove_signature: bool = True,
|
|
):
|
|
if method == "call_get_all_access_points":
|
|
return [
|
|
"/org/freedesktop/NetworkManager/AccessPoint/43099",
|
|
"/org/freedesktop/NetworkManager/AccessPoint/43100",
|
|
"/org/freedesktop/NetworkManager/AccessPoint/99999",
|
|
]
|
|
|
|
return await call_dbus(
|
|
proxy_interface, method, *args, remove_signature=remove_signature
|
|
)
|
|
|
|
with patch("supervisor.host.network.asyncio.sleep"), patch(
|
|
"supervisor.utils.dbus.DBus.call_dbus", new=mock_call_dbus
|
|
), patch.object(DBus, "_init_proxy", new=mock_init_proxy):
|
|
aps = await coresys.host.network.scan_wifi(coresys.host.network.get("wlan0"))
|
|
assert len(aps) == 2
|
|
|
|
assert "Can't process an AP" in caplog.text
|
|
|
|
|
|
async def test_host_connectivity_changed(coresys: CoreSys):
|
|
"""Test host connectivity changed."""
|
|
# pylint: disable=protected-access
|
|
client = coresys.homeassistant.websocket._client
|
|
await coresys.host.network.load()
|
|
|
|
assert coresys.host.network.connectivity is True
|
|
|
|
fire_property_change_signal(coresys.dbus.network, {"Connectivity": 1})
|
|
await asyncio.sleep(0)
|
|
assert coresys.host.network.connectivity is False
|
|
await asyncio.sleep(0)
|
|
client.async_send_command.assert_called_once_with(
|
|
{
|
|
"type": WSType.SUPERVISOR_EVENT,
|
|
"data": {
|
|
"event": WSEvent.SUPERVISOR_UPDATE,
|
|
"update_key": "network",
|
|
"data": {"host_internet": False},
|
|
},
|
|
}
|
|
)
|
|
|
|
client.async_send_command.reset_mock()
|
|
fire_property_change_signal(coresys.dbus.network, {}, ["Connectivity"])
|
|
await asyncio.sleep(0)
|
|
await asyncio.sleep(0)
|
|
assert coresys.host.network.connectivity is True
|
|
await asyncio.sleep(0)
|
|
client.async_send_command.assert_called_once_with(
|
|
{
|
|
"type": WSType.SUPERVISOR_EVENT,
|
|
"data": {
|
|
"event": WSEvent.SUPERVISOR_UPDATE,
|
|
"update_key": "network",
|
|
"data": {"host_internet": True},
|
|
},
|
|
}
|
|
)
|
|
|
|
|
|
async def test_host_connectivity_disabled(coresys: CoreSys):
|
|
"""Test host connectivity check disabled."""
|
|
# pylint: disable=protected-access
|
|
client = coresys.homeassistant.websocket._client
|
|
await coresys.host.network.load()
|
|
|
|
coresys.core.state = CoreState.RUNNING
|
|
await asyncio.sleep(0)
|
|
client.async_send_command.reset_mock()
|
|
|
|
assert "connectivity_check" not in coresys.resolution.unsupported
|
|
assert coresys.host.network.connectivity is True
|
|
|
|
fire_property_change_signal(
|
|
coresys.dbus.network, {"ConnectivityCheckEnabled": False}
|
|
)
|
|
await asyncio.sleep(0)
|
|
assert coresys.host.network.connectivity is None
|
|
await asyncio.sleep(0)
|
|
client.async_send_command.assert_called_once_with(
|
|
{
|
|
"type": WSType.SUPERVISOR_EVENT,
|
|
"data": {
|
|
"event": WSEvent.SUPERVISOR_UPDATE,
|
|
"update_key": "network",
|
|
"data": {"host_internet": None},
|
|
},
|
|
}
|
|
)
|
|
assert "connectivity_check" in coresys.resolution.unsupported
|
|
|
|
client.async_send_command.reset_mock()
|
|
fire_property_change_signal(coresys.dbus.network, {}, ["ConnectivityCheckEnabled"])
|
|
await asyncio.sleep(0)
|
|
await asyncio.sleep(0)
|
|
assert coresys.host.network.connectivity is True
|
|
await asyncio.sleep(0)
|
|
client.async_send_command.assert_called_once_with(
|
|
{
|
|
"type": WSType.SUPERVISOR_EVENT,
|
|
"data": {
|
|
"event": WSEvent.SUPERVISOR_UPDATE,
|
|
"update_key": "network",
|
|
"data": {"host_internet": True},
|
|
},
|
|
}
|
|
)
|
|
assert "connectivity_check" not in coresys.resolution.unsupported
|