1
0
mirror of https://github.com/home-assistant/supervisor.git synced 2026-07-04 04:15:07 +01:00
Files
supervisor/tests/dbus/network/setting/test_init.py
T
Stefan Agner ed91b18c4b tests: enable flake8-pytest-style (PT) ruff rules (#6857)
* tests: enable flake8-pytest-style (PT) ruff rules

Enable the `PT` ruff rule set and fix the resulting violations across the
test suite:

- PT006: pass parametrize argument names as tuples instead of a single
  comma-separated string.
- PT022: switch fixtures that have no teardown from `yield` to `return`
  so the lack of cleanup is obvious at a glance.
- PT011: add `match=` to broad `pytest.raises(ValueError)` blocks so the
  expected error is anchored to a specific message.
- PT012: hoist setup (patches, branching) out of `pytest.raises()`
  blocks so only the call that is expected to raise remains inside.
- PT013: replace `from pytest import X` with `import pytest` and access
  attributes via the module.
- PT015: replace `try/except` + `assert False` patterns with
  `pytest.raises(...)`.
- PT017: replace `assert` on exceptions inside `except` blocks with
  `pytest.raises(...) as exc_info` and assert on `exc_info.value`.

No behavioral changes to the tests; the full suite still passes.

* tests: address review feedback on PT ruff rule enablement

- Fix fixture return-type annotations after switching `yield` to `return`
  in tests/conftest.py: drop the `Generator[...]`/`AsyncGenerator[...]`
  wrapper for `dns_manager_service`, `supervisor_internet`, `websession`,
  and `mock_update_data` so the annotation matches what the fixture
  actually returns.
- Correct the return-type annotation of `fixture_ip6config_service` from
  `IP4ConfigService` to `IP6ConfigService`.
- Fix recurring "excepiton" typo in tests/utils/test_exception_helper.py.

* tests: verify backup cleanup on permission error

After `test_new_backup_permission_error` raises `BackupPermissionError`,
assert that no tarfile was left behind and `tmp_path` is empty. The
previous version only checked that the exception was raised, which
missed any regression where a partial tarfile would survive the failed
create.

* tests: rename DNS_GOOD_V6 to DNS_V6_UNSUPPORTED

The constant was named "good" but its tests assert that the URLs are
rejected by the DNS validator. The IPv6 URLs are well-formed but
currently rejected because IPv6 doesn't work with the Docker network
(see `dns_url` in supervisor/validate.py). Rename the constant and the
related test to make the intent obvious.
2026-05-20 22:17:54 +02:00

183 lines
6.7 KiB
Python

"""Test Network Manager Connection object."""
from unittest.mock import MagicMock, PropertyMock
from awesomeversion import AwesomeVersion
from dbus_fast import Variant
from dbus_fast.aio.message_bus import MessageBus
import pytest
from supervisor.dbus.network import NetworkManager
from supervisor.dbus.network.interface import NetworkInterface
from supervisor.dbus.network.setting import NetworkSetting
from supervisor.dbus.network.setting.generate import get_connection_from_interface
from supervisor.host.configuration import Ip6Setting
from supervisor.host.const import InterfaceMethod
from supervisor.host.network import Interface
from tests.dbus_service_mocks.network_connection_settings import (
ConnectionSettings as ConnectionSettingsService,
)
from tests.dbus_service_mocks.network_device import (
ETHERNET_DEVICE_OBJECT_PATH,
WIRELESS_DEVICE_OBJECT_PATH,
)
pytestmark = pytest.mark.usefixtures("connection_settings_service")
@pytest.fixture(name="dbus_interface")
async def fixture_dbus_interface(
dbus_session_bus: MessageBus, device_object_path: str = ETHERNET_DEVICE_OBJECT_PATH
) -> NetworkInterface:
"""Get connected dbus interface."""
dbus_interface = NetworkInterface(device_object_path)
await dbus_interface.connect(dbus_session_bus)
return dbus_interface
@pytest.mark.parametrize(
"dbus_interface",
[ETHERNET_DEVICE_OBJECT_PATH, WIRELESS_DEVICE_OBJECT_PATH],
indirect=True,
)
async def test_ethernet_update(
dbus_interface: NetworkInterface,
connection_settings_service: ConnectionSettingsService,
network_manager: NetworkManager,
):
"""Test network manager update."""
connection_settings_service.Update.calls.clear()
interface = Interface.from_dbus_interface(dbus_interface)
conn = get_connection_from_interface(
interface,
network_manager,
name=dbus_interface.settings.connection.id,
uuid=dbus_interface.settings.connection.uuid,
)
await dbus_interface.settings.update(conn)
assert len(connection_settings_service.Update.calls) == 1
settings = connection_settings_service.Update.calls[0][0]
assert settings["connection"]["id"] == Variant("s", "Supervisor eth0")
assert "interface-name" not in settings["connection"]
assert settings["connection"]["uuid"] == Variant(
"s", "0c23631e-2118-355c-bbb0-8943229cb0d6"
)
assert settings["connection"]["autoconnect"] == Variant("b", True)
assert settings["match"] == {"path": Variant("as", ["platform-ff3f0000.ethernet"])}
assert "ipv4" in settings
assert settings["ipv4"]["method"] == Variant("s", "auto")
assert "gateway" not in settings["ipv4"]
# Only DNS settings need to be preserved with auto
assert settings["ipv4"]["dns"] == Variant("au", [16951488])
assert "dns-data" not in settings["ipv4"]
assert "address-data" not in settings["ipv4"]
assert "addresses" not in settings["ipv4"]
assert len(settings["ipv4"]["route-data"].value) == 1
assert settings["ipv4"]["route-data"].value[0]["dest"] == Variant(
"s", "192.168.122.0"
)
assert settings["ipv4"]["route-data"].value[0]["prefix"] == Variant("u", 24)
assert settings["ipv4"]["route-data"].value[0]["next-hop"] == Variant(
"s", "10.10.10.1"
)
assert settings["ipv4"]["routes"] == Variant("aau", [[8038592, 24, 17435146, 0]])
assert "ipv6" in settings
assert settings["ipv6"]["method"] == Variant("s", "auto")
assert "gateway" not in settings["ipv6"]
# Only DNS settings need to be preserved with auto
assert settings["ipv6"]["dns"] == Variant(
"aay", [bytearray(b" \x01H`H`\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88")]
)
assert "dns-data" not in settings["ipv6"]
assert "address-data" not in settings["ipv6"]
assert "addresses" not in settings["ipv6"]
assert settings["ipv6"]["addr-gen-mode"] == Variant("i", 0)
assert "proxy" in settings
assert "vlan" not in settings
if settings["connection"]["type"] == "802-3-ethernet":
assert "802-3-ethernet" in settings
assert settings["802-3-ethernet"]["auto-negotiate"] == Variant("b", False)
assert "802-11-wireless" not in settings
assert "802-11-wireless-security" not in settings
if settings["connection"]["type"] == "802-11-wireless":
assert "802-11-wireless" in settings
assert settings["802-11-wireless"]["ssid"] == Variant("ay", b"NETT")
assert "mode" not in settings["802-11-wireless"]
assert "powersave" not in settings["802-11-wireless"]
assert "802-11-wireless-security" not in settings
async def test_ipv6_disabled_is_link_local(
dbus_interface: NetworkInterface, network_manager: NetworkManager
):
"""Test disabled equals link local for ipv6."""
interface = Interface.from_dbus_interface(dbus_interface)
interface.ipv4setting.method = InterfaceMethod.DISABLED
interface.ipv6setting.method = InterfaceMethod.DISABLED
conn = get_connection_from_interface(
interface,
network_manager,
name=dbus_interface.settings.connection.id,
uuid=dbus_interface.settings.connection.uuid,
)
assert conn["ipv4"]["method"] == Variant("s", "disabled")
assert conn["ipv6"]["method"] == Variant("s", "link-local")
@pytest.mark.parametrize(
("version", "addr_gen_mode"),
[
("1.38.0", 1),
("1.40.0", 3),
],
)
async def test_ipv6_addr_gen_mode(
dbus_interface: NetworkInterface, version: str, addr_gen_mode: int
):
"""Test addr_gen_mode with various NetworkManager versions."""
interface = Interface.from_dbus_interface(dbus_interface)
interface.ipv6setting = Ip6Setting(InterfaceMethod.AUTO, [], None, None, [])
network_manager = MagicMock()
type(network_manager).version = PropertyMock(return_value=AwesomeVersion(version))
conn = get_connection_from_interface(
interface,
network_manager,
name=dbus_interface.settings.connection.id,
uuid=dbus_interface.settings.connection.uuid,
)
assert conn["ipv6"]["method"] == Variant("s", "auto")
assert conn["ipv6"]["addr-gen-mode"] == Variant("i", addr_gen_mode)
async def test_watching_updated_signal(
connection_settings_service: ConnectionSettingsService, dbus_session_bus: MessageBus
):
"""Test get settings called on update signal."""
connection_settings_service.GetSettings.calls.clear()
settings = NetworkSetting("/org/freedesktop/NetworkManager/Settings/1")
await settings.connect(dbus_session_bus)
assert connection_settings_service.GetSettings.calls == [()]
connection_settings_service.Updated()
await connection_settings_service.ping()
await connection_settings_service.ping()
assert connection_settings_service.GetSettings.calls == [(), ()]