mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Add matter during onboarding (#116163)
* Add matter during onboarding * test_zeroconf_not_onboarded_running * test_zeroconf_not_onboarded_installed * test_zeroconf_not_onboarded_not_installed * test_zeroconf_discovery_not_onboarded_not_supervisor * Clean up * Add udp address * Test zeroconf udp info too * test_addon_installed_failures_zeroconf * test_addon_running_failures_zeroconf * test_addon_not_installed_failures_zeroconf * Clean up stale changes * Set unique id for discovery step * Fix tests for background flow * Fix flow running in background * Test already discovered zeroconf * Mock unload entry
This commit is contained in:
parent
8153ff78bf
commit
0e0ea0017e
@ -17,6 +17,8 @@ from homeassistant.components.hassio import (
|
|||||||
HassioServiceInfo,
|
HassioServiceInfo,
|
||||||
is_hassio,
|
is_hassio,
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.onboarding import async_is_onboarded
|
||||||
|
from homeassistant.components.zeroconf import ZeroconfServiceInfo
|
||||||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||||
from homeassistant.const import CONF_URL
|
from homeassistant.const import CONF_URL
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
@ -64,6 +66,7 @@ class MatterConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
"""Set up flow instance."""
|
"""Set up flow instance."""
|
||||||
|
self._running_in_background = False
|
||||||
self.ws_address: str | None = None
|
self.ws_address: str | None = None
|
||||||
# If we install the add-on we should uninstall it on entry remove.
|
# If we install the add-on we should uninstall it on entry remove.
|
||||||
self.integration_created_addon = False
|
self.integration_created_addon = False
|
||||||
@ -78,7 +81,7 @@ class MatterConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
if not self.install_task:
|
if not self.install_task:
|
||||||
self.install_task = self.hass.async_create_task(self._async_install_addon())
|
self.install_task = self.hass.async_create_task(self._async_install_addon())
|
||||||
|
|
||||||
if not self.install_task.done():
|
if not self._running_in_background and not self.install_task.done():
|
||||||
return self.async_show_progress(
|
return self.async_show_progress(
|
||||||
step_id="install_addon",
|
step_id="install_addon",
|
||||||
progress_action="install_addon",
|
progress_action="install_addon",
|
||||||
@ -89,12 +92,16 @@ class MatterConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
await self.install_task
|
await self.install_task
|
||||||
except AddonError as err:
|
except AddonError as err:
|
||||||
LOGGER.error(err)
|
LOGGER.error(err)
|
||||||
|
if self._running_in_background:
|
||||||
|
return await self.async_step_install_failed()
|
||||||
return self.async_show_progress_done(next_step_id="install_failed")
|
return self.async_show_progress_done(next_step_id="install_failed")
|
||||||
finally:
|
finally:
|
||||||
self.install_task = None
|
self.install_task = None
|
||||||
|
|
||||||
self.integration_created_addon = True
|
self.integration_created_addon = True
|
||||||
|
|
||||||
|
if self._running_in_background:
|
||||||
|
return await self.async_step_start_addon()
|
||||||
return self.async_show_progress_done(next_step_id="start_addon")
|
return self.async_show_progress_done(next_step_id="start_addon")
|
||||||
|
|
||||||
async def async_step_install_failed(
|
async def async_step_install_failed(
|
||||||
@ -125,7 +132,7 @@ class MatterConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
"""Start Matter Server add-on."""
|
"""Start Matter Server add-on."""
|
||||||
if not self.start_task:
|
if not self.start_task:
|
||||||
self.start_task = self.hass.async_create_task(self._async_start_addon())
|
self.start_task = self.hass.async_create_task(self._async_start_addon())
|
||||||
if not self.start_task.done():
|
if not self._running_in_background and not self.start_task.done():
|
||||||
return self.async_show_progress(
|
return self.async_show_progress(
|
||||||
step_id="start_addon",
|
step_id="start_addon",
|
||||||
progress_action="start_addon",
|
progress_action="start_addon",
|
||||||
@ -136,10 +143,14 @@ class MatterConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
await self.start_task
|
await self.start_task
|
||||||
except (FailedConnect, AddonError, AbortFlow) as err:
|
except (FailedConnect, AddonError, AbortFlow) as err:
|
||||||
LOGGER.error(err)
|
LOGGER.error(err)
|
||||||
|
if self._running_in_background:
|
||||||
|
return await self.async_step_start_failed()
|
||||||
return self.async_show_progress_done(next_step_id="start_failed")
|
return self.async_show_progress_done(next_step_id="start_failed")
|
||||||
finally:
|
finally:
|
||||||
self.start_task = None
|
self.start_task = None
|
||||||
|
|
||||||
|
if self._running_in_background:
|
||||||
|
return await self.async_step_finish_addon_setup()
|
||||||
return self.async_show_progress_done(next_step_id="finish_addon_setup")
|
return self.async_show_progress_done(next_step_id="finish_addon_setup")
|
||||||
|
|
||||||
async def async_step_start_failed(
|
async def async_step_start_failed(
|
||||||
@ -223,6 +234,18 @@ class MatterConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
step_id="manual", data_schema=get_manual_schema(user_input), errors=errors
|
step_id="manual", data_schema=get_manual_schema(user_input), errors=errors
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async def async_step_zeroconf(
|
||||||
|
self, discovery_info: ZeroconfServiceInfo
|
||||||
|
) -> ConfigFlowResult:
|
||||||
|
"""Handle zeroconf discovery."""
|
||||||
|
if not async_is_onboarded(self.hass) and is_hassio(self.hass):
|
||||||
|
await self._async_handle_discovery_without_unique_id()
|
||||||
|
self._running_in_background = True
|
||||||
|
return await self.async_step_on_supervisor(
|
||||||
|
user_input={CONF_USE_ADDON: True}
|
||||||
|
)
|
||||||
|
return await self._async_step_discovery_without_unique_id()
|
||||||
|
|
||||||
async def async_step_hassio(
|
async def async_step_hassio(
|
||||||
self, discovery_info: HassioServiceInfo
|
self, discovery_info: HassioServiceInfo
|
||||||
) -> ConfigFlowResult:
|
) -> ConfigFlowResult:
|
||||||
|
@ -7,5 +7,5 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/matter",
|
"documentation": "https://www.home-assistant.io/integrations/matter",
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"requirements": ["python-matter-server==5.7.0"],
|
"requirements": ["python-matter-server==5.7.0"],
|
||||||
"zeroconf": ["_matter._tcp.local."]
|
"zeroconf": ["_matter._tcp.local.", "_matterc._udp.local."]
|
||||||
}
|
}
|
||||||
|
@ -608,6 +608,11 @@ ZEROCONF = {
|
|||||||
"domain": "matter",
|
"domain": "matter",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
"_matterc._udp.local.": [
|
||||||
|
{
|
||||||
|
"domain": "matter",
|
||||||
|
},
|
||||||
|
],
|
||||||
"_mediaremotetv._tcp.local.": [
|
"_mediaremotetv._tcp.local.": [
|
||||||
{
|
{
|
||||||
"domain": "apple_tv",
|
"domain": "apple_tv",
|
||||||
|
@ -24,6 +24,37 @@ ADDON_DISCOVERY_INFO = {
|
|||||||
"host": "host1",
|
"host": "host1",
|
||||||
"port": 5581,
|
"port": 5581,
|
||||||
}
|
}
|
||||||
|
ZEROCONF_INFO_TCP = ZeroconfServiceInfo(
|
||||||
|
ip_address=ip_address("fd11:be53:8d46:0:729e:5a4f:539d:1ee6"),
|
||||||
|
ip_addresses=[ip_address("fd11:be53:8d46:0:729e:5a4f:539d:1ee6")],
|
||||||
|
port=5540,
|
||||||
|
hostname="CDEFGHIJ12345678.local.",
|
||||||
|
type="_matter._tcp.local.",
|
||||||
|
name="ABCDEFGH123456789-0000000012345678._matter._tcp.local.",
|
||||||
|
properties={"SII": "3300", "SAI": "1100", "T": "0"},
|
||||||
|
)
|
||||||
|
|
||||||
|
ZEROCONF_INFO_UDP = ZeroconfServiceInfo(
|
||||||
|
ip_address=ip_address("fd11:be53:8d46:0:729e:5a4f:539d:1ee6"),
|
||||||
|
ip_addresses=[ip_address("fd11:be53:8d46:0:729e:5a4f:539d:1ee6")],
|
||||||
|
port=5540,
|
||||||
|
hostname="CDEFGHIJ12345678.local.",
|
||||||
|
type="_matterc._udp.local.",
|
||||||
|
name="ABCDEFGH123456789._matterc._udp.local.",
|
||||||
|
properties={
|
||||||
|
"VP": "4874+77",
|
||||||
|
"DT": "21",
|
||||||
|
"DN": "Eve Door",
|
||||||
|
"SII": "3300",
|
||||||
|
"SAI": "1100",
|
||||||
|
"T": "0",
|
||||||
|
"D": "183",
|
||||||
|
"CM": "2",
|
||||||
|
"RI": "0400530980B950D59BF473CFE42BD7DDBF2D",
|
||||||
|
"PH": "36",
|
||||||
|
"PI": None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="setup_entry", autouse=True)
|
@pytest.fixture(name="setup_entry", autouse=True)
|
||||||
@ -35,6 +66,15 @@ def setup_entry_fixture() -> Generator[AsyncMock, None, None]:
|
|||||||
yield mock_setup_entry
|
yield mock_setup_entry
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="unload_entry", autouse=True)
|
||||||
|
def unload_entry_fixture() -> Generator[AsyncMock, None, None]:
|
||||||
|
"""Mock entry unload."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.matter.async_unload_entry", return_value=True
|
||||||
|
) as mock_unload_entry:
|
||||||
|
yield mock_unload_entry
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="client_connect", autouse=True)
|
@pytest.fixture(name="client_connect", autouse=True)
|
||||||
def client_connect_fixture() -> Generator[AsyncMock, None, None]:
|
def client_connect_fixture() -> Generator[AsyncMock, None, None]:
|
||||||
"""Mock server version."""
|
"""Mock server version."""
|
||||||
@ -80,6 +120,16 @@ def addon_setup_time_fixture() -> Generator[int, None, None]:
|
|||||||
yield addon_setup_time
|
yield addon_setup_time
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="not_onboarded")
|
||||||
|
def mock_onboarded_fixture() -> Generator[MagicMock, None, None]:
|
||||||
|
"""Mock that Home Assistant is not yet onboarded."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.matter.config_flow.async_is_onboarded",
|
||||||
|
return_value=False,
|
||||||
|
) as mock_onboarded:
|
||||||
|
yield mock_onboarded
|
||||||
|
|
||||||
|
|
||||||
async def test_manual_create_entry(
|
async def test_manual_create_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
client_connect: AsyncMock,
|
client_connect: AsyncMock,
|
||||||
@ -179,24 +229,18 @@ async def test_manual_already_configured(
|
|||||||
assert setup_entry.call_count == 1
|
assert setup_entry.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("zeroconf_info", [ZEROCONF_INFO_TCP, ZEROCONF_INFO_UDP])
|
||||||
async def test_zeroconf_discovery(
|
async def test_zeroconf_discovery(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
client_connect: AsyncMock,
|
client_connect: AsyncMock,
|
||||||
setup_entry: AsyncMock,
|
setup_entry: AsyncMock,
|
||||||
|
zeroconf_info: ZeroconfServiceInfo,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test flow started from Zeroconf discovery."""
|
"""Test flow started from Zeroconf discovery."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
context={"source": config_entries.SOURCE_ZEROCONF},
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||||
data=ZeroconfServiceInfo(
|
data=zeroconf_info,
|
||||||
ip_address=ip_address("fd11:be53:8d46:0:729e:5a4f:539d:1ee6"),
|
|
||||||
ip_addresses=[ip_address("fd11:be53:8d46:0:729e:5a4f:539d:1ee6")],
|
|
||||||
port=5540,
|
|
||||||
hostname="CDEFGHIJ12345678.local.",
|
|
||||||
type="_matter._tcp.local.",
|
|
||||||
name="ABCDEFGH123456789-0000000012345678._matter._tcp.local.",
|
|
||||||
properties={"SII": "3300", "SAI": "1100", "T": "0"},
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
assert result["type"] is FlowResultType.FORM
|
assert result["type"] is FlowResultType.FORM
|
||||||
assert result["step_id"] == "manual"
|
assert result["step_id"] == "manual"
|
||||||
@ -221,6 +265,185 @@ async def test_zeroconf_discovery(
|
|||||||
assert setup_entry.call_count == 1
|
assert setup_entry.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("zeroconf_info", [ZEROCONF_INFO_TCP, ZEROCONF_INFO_UDP])
|
||||||
|
async def test_zeroconf_discovery_not_onboarded_not_supervisor(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
client_connect: AsyncMock,
|
||||||
|
setup_entry: AsyncMock,
|
||||||
|
not_onboarded: MagicMock,
|
||||||
|
zeroconf_info: ZeroconfServiceInfo,
|
||||||
|
) -> None:
|
||||||
|
"""Test flow started from Zeroconf discovery when not onboarded."""
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||||
|
data=zeroconf_info,
|
||||||
|
)
|
||||||
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "manual"
|
||||||
|
assert result["errors"] is None
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{
|
||||||
|
"url": "ws://localhost:5580/ws",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert client_connect.call_count == 1
|
||||||
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
|
assert result["title"] == "Matter"
|
||||||
|
assert result["data"] == {
|
||||||
|
"url": "ws://localhost:5580/ws",
|
||||||
|
"integration_created_addon": False,
|
||||||
|
"use_addon": False,
|
||||||
|
}
|
||||||
|
assert setup_entry.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("zeroconf_info", [ZEROCONF_INFO_TCP, ZEROCONF_INFO_UDP])
|
||||||
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
||||||
|
async def test_zeroconf_not_onboarded_already_discovered(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
supervisor: MagicMock,
|
||||||
|
addon_info: AsyncMock,
|
||||||
|
addon_running: AsyncMock,
|
||||||
|
client_connect: AsyncMock,
|
||||||
|
setup_entry: AsyncMock,
|
||||||
|
not_onboarded: MagicMock,
|
||||||
|
zeroconf_info: ZeroconfServiceInfo,
|
||||||
|
) -> None:
|
||||||
|
"""Test flow Zeroconf discovery when not onboarded and already discovered."""
|
||||||
|
result_flow_1 = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||||
|
data=zeroconf_info,
|
||||||
|
)
|
||||||
|
result_flow_2 = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||||
|
data=zeroconf_info,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert result_flow_2["type"] is FlowResultType.ABORT
|
||||||
|
assert result_flow_2["reason"] == "already_configured"
|
||||||
|
assert addon_info.call_count == 1
|
||||||
|
assert client_connect.call_count == 1
|
||||||
|
assert result_flow_1["type"] is FlowResultType.CREATE_ENTRY
|
||||||
|
assert result_flow_1["title"] == "Matter"
|
||||||
|
assert result_flow_1["data"] == {
|
||||||
|
"url": "ws://host1:5581/ws",
|
||||||
|
"use_addon": True,
|
||||||
|
"integration_created_addon": False,
|
||||||
|
}
|
||||||
|
assert setup_entry.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("zeroconf_info", [ZEROCONF_INFO_TCP, ZEROCONF_INFO_UDP])
|
||||||
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
||||||
|
async def test_zeroconf_not_onboarded_running(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
supervisor: MagicMock,
|
||||||
|
addon_info: AsyncMock,
|
||||||
|
addon_running: AsyncMock,
|
||||||
|
client_connect: AsyncMock,
|
||||||
|
setup_entry: AsyncMock,
|
||||||
|
not_onboarded: MagicMock,
|
||||||
|
zeroconf_info: ZeroconfServiceInfo,
|
||||||
|
) -> None:
|
||||||
|
"""Test flow Zeroconf discovery when not onboarded and add-on running."""
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||||
|
data=zeroconf_info,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert addon_info.call_count == 1
|
||||||
|
assert client_connect.call_count == 1
|
||||||
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
|
assert result["title"] == "Matter"
|
||||||
|
assert result["data"] == {
|
||||||
|
"url": "ws://host1:5581/ws",
|
||||||
|
"use_addon": True,
|
||||||
|
"integration_created_addon": False,
|
||||||
|
}
|
||||||
|
assert setup_entry.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("zeroconf_info", [ZEROCONF_INFO_TCP, ZEROCONF_INFO_UDP])
|
||||||
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
||||||
|
async def test_zeroconf_not_onboarded_installed(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
supervisor: MagicMock,
|
||||||
|
addon_info: AsyncMock,
|
||||||
|
addon_installed: AsyncMock,
|
||||||
|
start_addon: AsyncMock,
|
||||||
|
client_connect: AsyncMock,
|
||||||
|
setup_entry: AsyncMock,
|
||||||
|
not_onboarded: MagicMock,
|
||||||
|
zeroconf_info: ZeroconfServiceInfo,
|
||||||
|
) -> None:
|
||||||
|
"""Test flow Zeroconf discovery when not onboarded and add-on installed."""
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||||
|
data=zeroconf_info,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert addon_info.call_count == 1
|
||||||
|
assert start_addon.call_args == call(hass, "core_matter_server")
|
||||||
|
assert client_connect.call_count == 1
|
||||||
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
|
assert result["title"] == "Matter"
|
||||||
|
assert result["data"] == {
|
||||||
|
"url": "ws://host1:5581/ws",
|
||||||
|
"use_addon": True,
|
||||||
|
"integration_created_addon": False,
|
||||||
|
}
|
||||||
|
assert setup_entry.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("zeroconf_info", [ZEROCONF_INFO_TCP, ZEROCONF_INFO_UDP])
|
||||||
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
||||||
|
async def test_zeroconf_not_onboarded_not_installed(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
supervisor: MagicMock,
|
||||||
|
addon_info: AsyncMock,
|
||||||
|
addon_store_info: AsyncMock,
|
||||||
|
addon_not_installed: AsyncMock,
|
||||||
|
install_addon: AsyncMock,
|
||||||
|
start_addon: AsyncMock,
|
||||||
|
client_connect: AsyncMock,
|
||||||
|
setup_entry: AsyncMock,
|
||||||
|
not_onboarded: MagicMock,
|
||||||
|
zeroconf_info: ZeroconfServiceInfo,
|
||||||
|
) -> None:
|
||||||
|
"""Test flow Zeroconf discovery when not onboarded and add-on not installed."""
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||||
|
data=zeroconf_info,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert addon_info.call_count == 0
|
||||||
|
assert addon_store_info.call_count == 2
|
||||||
|
assert install_addon.call_args == call(hass, "core_matter_server")
|
||||||
|
assert start_addon.call_args == call(hass, "core_matter_server")
|
||||||
|
assert client_connect.call_count == 1
|
||||||
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
|
assert result["title"] == "Matter"
|
||||||
|
assert result["data"] == {
|
||||||
|
"url": "ws://host1:5581/ws",
|
||||||
|
"use_addon": True,
|
||||||
|
"integration_created_addon": True,
|
||||||
|
}
|
||||||
|
assert setup_entry.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
||||||
async def test_supervisor_discovery(
|
async def test_supervisor_discovery(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -702,6 +925,90 @@ async def test_addon_running_failures(
|
|||||||
assert result["reason"] == abort_reason
|
assert result["reason"] == abort_reason
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("zeroconf_info", [ZEROCONF_INFO_TCP, ZEROCONF_INFO_UDP])
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
(
|
||||||
|
"discovery_info",
|
||||||
|
"discovery_info_error",
|
||||||
|
"client_connect_error",
|
||||||
|
"addon_info_error",
|
||||||
|
"abort_reason",
|
||||||
|
"discovery_info_called",
|
||||||
|
"client_connect_called",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
{"config": ADDON_DISCOVERY_INFO},
|
||||||
|
HassioAPIError(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
"addon_get_discovery_info_failed",
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{"config": ADDON_DISCOVERY_INFO},
|
||||||
|
None,
|
||||||
|
CannotConnect(Exception("Boom")),
|
||||||
|
None,
|
||||||
|
"cannot_connect",
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
"addon_get_discovery_info_failed",
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{"config": ADDON_DISCOVERY_INFO},
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
HassioAPIError(),
|
||||||
|
"addon_info_failed",
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_addon_running_failures_zeroconf(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
supervisor: MagicMock,
|
||||||
|
addon_running: AsyncMock,
|
||||||
|
addon_info: AsyncMock,
|
||||||
|
get_addon_discovery_info: AsyncMock,
|
||||||
|
client_connect: AsyncMock,
|
||||||
|
discovery_info_error: Exception | None,
|
||||||
|
client_connect_error: Exception | None,
|
||||||
|
addon_info_error: Exception | None,
|
||||||
|
abort_reason: str,
|
||||||
|
discovery_info_called: bool,
|
||||||
|
client_connect_called: bool,
|
||||||
|
not_onboarded: MagicMock,
|
||||||
|
zeroconf_info: ZeroconfServiceInfo,
|
||||||
|
) -> None:
|
||||||
|
"""Test all failures when add-on is running and not onboarded."""
|
||||||
|
get_addon_discovery_info.side_effect = discovery_info_error
|
||||||
|
client_connect.side_effect = client_connect_error
|
||||||
|
addon_info.side_effect = addon_info_error
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
||||||
|
data=zeroconf_info,
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert addon_info.call_count == 1
|
||||||
|
assert get_addon_discovery_info.called is discovery_info_called
|
||||||
|
assert client_connect.called is client_connect_called
|
||||||
|
assert result["type"] is FlowResultType.ABORT
|
||||||
|
assert result["reason"] == abort_reason
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
||||||
async def test_addon_running_already_configured(
|
async def test_addon_running_already_configured(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -854,6 +1161,71 @@ async def test_addon_installed_failures(
|
|||||||
assert result["reason"] == "addon_start_failed"
|
assert result["reason"] == "addon_start_failed"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("zeroconf_info", [ZEROCONF_INFO_TCP, ZEROCONF_INFO_UDP])
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
(
|
||||||
|
"discovery_info",
|
||||||
|
"start_addon_error",
|
||||||
|
"client_connect_error",
|
||||||
|
"discovery_info_called",
|
||||||
|
"client_connect_called",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
{"config": ADDON_DISCOVERY_INFO},
|
||||||
|
HassioAPIError(),
|
||||||
|
None,
|
||||||
|
False,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
{"config": ADDON_DISCOVERY_INFO},
|
||||||
|
None,
|
||||||
|
CannotConnect(Exception("Boom")),
|
||||||
|
True,
|
||||||
|
True,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_addon_installed_failures_zeroconf(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
supervisor: MagicMock,
|
||||||
|
addon_installed: AsyncMock,
|
||||||
|
addon_info: AsyncMock,
|
||||||
|
start_addon: AsyncMock,
|
||||||
|
get_addon_discovery_info: AsyncMock,
|
||||||
|
client_connect: AsyncMock,
|
||||||
|
start_addon_error: Exception | None,
|
||||||
|
client_connect_error: Exception | None,
|
||||||
|
discovery_info_called: bool,
|
||||||
|
client_connect_called: bool,
|
||||||
|
not_onboarded: MagicMock,
|
||||||
|
zeroconf_info: ZeroconfServiceInfo,
|
||||||
|
) -> None:
|
||||||
|
"""Test add-on start failure when add-on is installed and not onboarded."""
|
||||||
|
start_addon.side_effect = start_addon_error
|
||||||
|
client_connect.side_effect = client_connect_error
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_ZEROCONF}, data=zeroconf_info
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert addon_info.call_count == 1
|
||||||
|
assert start_addon.call_args == call(hass, "core_matter_server")
|
||||||
|
assert get_addon_discovery_info.called is discovery_info_called
|
||||||
|
assert client_connect.called is client_connect_called
|
||||||
|
assert result["type"] is FlowResultType.ABORT
|
||||||
|
assert result["reason"] == "addon_start_failed"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
||||||
async def test_addon_installed_already_configured(
|
async def test_addon_installed_already_configured(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
@ -985,6 +1357,30 @@ async def test_addon_not_installed_failures(
|
|||||||
assert result["reason"] == "addon_install_failed"
|
assert result["reason"] == "addon_install_failed"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("zeroconf_info", [ZEROCONF_INFO_TCP, ZEROCONF_INFO_UDP])
|
||||||
|
async def test_addon_not_installed_failures_zeroconf(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
supervisor: MagicMock,
|
||||||
|
addon_not_installed: AsyncMock,
|
||||||
|
addon_info: AsyncMock,
|
||||||
|
install_addon: AsyncMock,
|
||||||
|
not_onboarded: MagicMock,
|
||||||
|
zeroconf_info: ZeroconfServiceInfo,
|
||||||
|
) -> None:
|
||||||
|
"""Test add-on install failure."""
|
||||||
|
install_addon.side_effect = HassioAPIError()
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": config_entries.SOURCE_ZEROCONF}, data=zeroconf_info
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert install_addon.call_args == call(hass, "core_matter_server")
|
||||||
|
assert addon_info.call_count == 0
|
||||||
|
assert result["type"] is FlowResultType.ABORT
|
||||||
|
assert result["reason"] == "addon_install_failed"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
||||||
async def test_addon_not_installed_already_configured(
|
async def test_addon_not_installed_already_configured(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user