Add repair when IPv6 is disabled for Matter (#174653)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Stefan Agner
2026-06-24 17:11:54 +02:00
committed by GitHub
co-authored by Claude Opus 4.8 Copilot Autofix powered by AI
parent f0ed257f47
commit 0808e30e37
3 changed files with 254 additions and 2 deletions
+192 -1
View File
@@ -5,7 +5,7 @@ from collections.abc import Generator
from unittest.mock import AsyncMock, MagicMock, call, patch
from aiohasupervisor import SupervisorError
from aiohasupervisor.models import PartialBackupOptions
from aiohasupervisor.models import InterfaceMethod, PartialBackupOptions
from matter_server.client.exceptions import (
CannotConnect,
NotConnected,
@@ -550,6 +550,197 @@ async def test_issue_registry_invalid_version(
assert not issue_registry.async_get_issue(DOMAIN, issue_raised)
def _mock_network_interface(
*, enabled: bool, connected: bool, ipv6_method: InterfaceMethod | None
) -> MagicMock:
"""Build a mock Supervisor network interface."""
interface = MagicMock()
interface.enabled = enabled
interface.connected = connected
interface.ipv6 = None if ipv6_method is None else MagicMock(method=ipv6_method)
return interface
@pytest.mark.parametrize(
("interfaces", "issue_expected"),
[
pytest.param(
[
_mock_network_interface(
enabled=True, connected=True, ipv6_method=InterfaceMethod.DISABLED
)
],
True,
id="ipv6_disabled",
),
pytest.param(
[_mock_network_interface(enabled=True, connected=True, ipv6_method=None)],
True,
id="no_ipv6_config",
),
pytest.param(
[
_mock_network_interface(
enabled=True, connected=True, ipv6_method=InterfaceMethod.AUTO
)
],
False,
id="ipv6_auto",
),
pytest.param(
[
_mock_network_interface(
enabled=True, connected=True, ipv6_method=InterfaceMethod.STATIC
)
],
False,
id="ipv6_static",
),
pytest.param(
[
_mock_network_interface(
enabled=True, connected=True, ipv6_method=InterfaceMethod.DISABLED
),
_mock_network_interface(
enabled=True, connected=True, ipv6_method=InterfaceMethod.AUTO
),
],
False,
id="ipv6_enabled_on_secondary_interface",
),
pytest.param(
[
_mock_network_interface(
enabled=True, connected=False, ipv6_method=InterfaceMethod.DISABLED
)
],
False,
id="no_connected_interface",
),
],
)
async def test_ipv6_disabled_repair(
hass: HomeAssistant,
matter_client: MagicMock,
issue_registry: ir.IssueRegistry,
interfaces: list[MagicMock],
issue_expected: bool,
) -> None:
"""Test repair issue when IPv6 is disabled in Supervisor network settings."""
supervisor_client = MagicMock()
supervisor_client.network.info = AsyncMock(
return_value=MagicMock(interfaces=interfaces)
)
entry = MockConfigEntry(domain=DOMAIN, data={"url": "ws://localhost:5580/ws"})
entry.add_to_hass(hass)
with (
patch("homeassistant.components.matter.is_hassio", return_value=True),
patch(
"homeassistant.components.matter.get_supervisor_client",
return_value=supervisor_client,
),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.state is ConfigEntryState.LOADED
issue = issue_registry.async_get_issue(DOMAIN, "ipv6_disabled")
assert (issue is not None) is issue_expected
async def test_ipv6_repair_not_raised_without_supervisor(
hass: HomeAssistant,
matter_client: MagicMock,
issue_registry: ir.IssueRegistry,
) -> None:
"""Test the IPv6 repair is skipped when not running on Supervisor."""
with patch(
"homeassistant.components.matter.get_supervisor_client"
) as get_supervisor_client:
entry = MockConfigEntry(domain=DOMAIN, data={"url": "ws://localhost:5580/ws"})
entry.add_to_hass(hass)
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.state is ConfigEntryState.LOADED
get_supervisor_client.assert_not_called()
assert not issue_registry.async_get_issue(DOMAIN, "ipv6_disabled")
async def test_ipv6_repair_supervisor_error(
hass: HomeAssistant,
matter_client: MagicMock,
issue_registry: ir.IssueRegistry,
) -> None:
"""Test the IPv6 repair handles Supervisor errors gracefully."""
supervisor_client = MagicMock()
supervisor_client.network.info = AsyncMock(side_effect=SupervisorError("boom"))
entry = MockConfigEntry(domain=DOMAIN, data={"url": "ws://localhost:5580/ws"})
entry.add_to_hass(hass)
with (
patch("homeassistant.components.matter.is_hassio", return_value=True),
patch(
"homeassistant.components.matter.get_supervisor_client",
return_value=supervisor_client,
),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert entry.state is ConfigEntryState.LOADED
assert not issue_registry.async_get_issue(DOMAIN, "ipv6_disabled")
async def test_ipv6_repair_resolves_on_reload(
hass: HomeAssistant,
matter_client: MagicMock,
issue_registry: ir.IssueRegistry,
) -> None:
"""Test the IPv6 repair is removed once IPv6 is enabled again."""
supervisor_client = MagicMock()
supervisor_client.network.info = AsyncMock(
return_value=MagicMock(
interfaces=[
_mock_network_interface(
enabled=True, connected=True, ipv6_method=InterfaceMethod.DISABLED
)
]
)
)
entry = MockConfigEntry(domain=DOMAIN, data={"url": "ws://localhost:5580/ws"})
entry.add_to_hass(hass)
with (
patch("homeassistant.components.matter.is_hassio", return_value=True),
patch(
"homeassistant.components.matter.get_supervisor_client",
return_value=supervisor_client,
),
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
assert issue_registry.async_get_issue(DOMAIN, "ipv6_disabled")
supervisor_client.network.info.return_value = MagicMock(
interfaces=[
_mock_network_interface(
enabled=True, connected=True, ipv6_method=InterfaceMethod.AUTO
)
]
)
await hass.config_entries.async_reload(entry.entry_id)
await hass.async_block_till_done()
assert entry.state is ConfigEntryState.LOADED
assert not issue_registry.async_get_issue(DOMAIN, "ipv6_disabled")
@pytest.mark.parametrize(
("stop_addon_side_effect", "entry_state"),
[