2022-12-01 19:44:56 +00:00
|
|
|
"""Test the Matter config flow."""
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
from collections.abc import Generator
|
|
|
|
from typing import Any
|
|
|
|
from unittest.mock import DEFAULT, AsyncMock, MagicMock, call, patch
|
|
|
|
|
|
|
|
from matter_server.client.exceptions import CannotConnect, InvalidServerVersion
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
from homeassistant import config_entries
|
|
|
|
from homeassistant.components.hassio import HassioAPIError, HassioServiceInfo
|
|
|
|
from homeassistant.components.matter.const import ADDON_SLUG, DOMAIN
|
|
|
|
from homeassistant.core import HomeAssistant
|
|
|
|
from homeassistant.data_entry_flow import FlowResultType
|
|
|
|
|
|
|
|
from tests.common import MockConfigEntry
|
|
|
|
|
|
|
|
ADDON_DISCOVERY_INFO = {
|
|
|
|
"addon": "Matter Server",
|
|
|
|
"host": "host1",
|
|
|
|
"port": 5581,
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="setup_entry", autouse=True)
|
|
|
|
def setup_entry_fixture() -> Generator[AsyncMock, None, None]:
|
|
|
|
"""Mock entry setup."""
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.matter.async_setup_entry", return_value=True
|
|
|
|
) as mock_setup_entry:
|
|
|
|
yield mock_setup_entry
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="client_connect", autouse=True)
|
|
|
|
def client_connect_fixture() -> Generator[AsyncMock, None, None]:
|
|
|
|
"""Mock server version."""
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.matter.config_flow.MatterClient.connect"
|
|
|
|
) as client_connect:
|
|
|
|
yield client_connect
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="supervisor")
|
|
|
|
def supervisor_fixture() -> Generator[MagicMock, None, None]:
|
|
|
|
"""Mock Supervisor."""
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.matter.config_flow.is_hassio", return_value=True
|
|
|
|
) as is_hassio:
|
|
|
|
yield is_hassio
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="discovery_info")
|
|
|
|
def discovery_info_fixture() -> Any:
|
|
|
|
"""Return the discovery info from the supervisor."""
|
|
|
|
return DEFAULT
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="get_addon_discovery_info", autouse=True)
|
|
|
|
def get_addon_discovery_info_fixture(
|
|
|
|
discovery_info: Any,
|
|
|
|
) -> Generator[AsyncMock, None, None]:
|
|
|
|
"""Mock get add-on discovery info."""
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.hassio.addon_manager.async_get_addon_discovery_info",
|
|
|
|
return_value=discovery_info,
|
|
|
|
) as get_addon_discovery_info:
|
|
|
|
yield get_addon_discovery_info
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="addon_setup_time", autouse=True)
|
|
|
|
def addon_setup_time_fixture() -> Generator[int, None, None]:
|
|
|
|
"""Mock add-on setup sleep time."""
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.matter.config_flow.ADDON_SETUP_TIMEOUT", new=0
|
|
|
|
) as addon_setup_time:
|
|
|
|
yield addon_setup_time
|
|
|
|
|
|
|
|
|
|
|
|
async def test_manual_create_entry(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
client_connect: AsyncMock,
|
|
|
|
setup_entry: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test user step create entry."""
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
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"] == FlowResultType.CREATE_ENTRY
|
2022-12-22 15:42:37 +00:00
|
|
|
assert result["title"] == "Matter"
|
2022-12-01 19:44:56 +00:00
|
|
|
assert result["data"] == {
|
|
|
|
"url": "ws://localhost:5580/ws",
|
|
|
|
"integration_created_addon": False,
|
|
|
|
"use_addon": False,
|
|
|
|
}
|
|
|
|
assert setup_entry.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"error, side_effect",
|
|
|
|
[
|
|
|
|
("cannot_connect", CannotConnect(Exception("Boom"))),
|
|
|
|
("invalid_server_version", InvalidServerVersion("Invalid version")),
|
|
|
|
("unknown", Exception("Unknown boom")),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
async def test_manual_errors(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
client_connect: AsyncMock,
|
|
|
|
error: str,
|
|
|
|
side_effect: Exception,
|
|
|
|
) -> None:
|
|
|
|
"""Test user step cannot connect error."""
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
|
|
|
|
client_connect.side_effect = side_effect
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"],
|
|
|
|
{
|
|
|
|
"url": "ws://localhost:5580/ws",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
assert client_connect.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["errors"] == {"base": error}
|
|
|
|
|
|
|
|
|
|
|
|
async def test_manual_already_configured(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
client_connect: AsyncMock,
|
|
|
|
setup_entry: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test manual step abort if already configured."""
|
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={"url": "ws://host1:5581/ws"}, title="Matter"
|
|
|
|
)
|
|
|
|
entry.add_to_hass(hass)
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
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"] == FlowResultType.ABORT
|
|
|
|
assert result["reason"] == "reconfiguration_successful"
|
|
|
|
assert entry.data["url"] == "ws://localhost:5580/ws"
|
|
|
|
assert entry.data["use_addon"] is False
|
|
|
|
assert entry.data["integration_created_addon"] is False
|
2022-12-22 15:42:37 +00:00
|
|
|
assert entry.title == "Matter"
|
2022-12-01 19:44:56 +00:00
|
|
|
assert setup_entry.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
|
|
|
async def test_supervisor_discovery(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_running: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
client_connect: AsyncMock,
|
|
|
|
setup_entry: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test flow started from Supervisor discovery."""
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN,
|
|
|
|
context={"source": config_entries.SOURCE_HASSIO},
|
|
|
|
data=HassioServiceInfo(
|
|
|
|
config=ADDON_DISCOVERY_INFO,
|
|
|
|
name="Matter Server",
|
|
|
|
slug=ADDON_SLUG,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert addon_info.call_count == 1
|
|
|
|
assert client_connect.call_count == 0
|
|
|
|
assert result["type"] == FlowResultType.CREATE_ENTRY
|
2022-12-22 15:42:37 +00:00
|
|
|
assert result["title"] == "Matter"
|
2022-12-01 19:44:56 +00:00
|
|
|
assert result["data"] == {
|
|
|
|
"url": "ws://host1:5581/ws",
|
|
|
|
"use_addon": True,
|
|
|
|
"integration_created_addon": False,
|
|
|
|
}
|
|
|
|
assert setup_entry.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"discovery_info, error",
|
|
|
|
[({"config": ADDON_DISCOVERY_INFO}, HassioAPIError())],
|
|
|
|
)
|
|
|
|
async def test_supervisor_discovery_addon_info_failed(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_running: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
error: Exception,
|
|
|
|
) -> None:
|
|
|
|
"""Test Supervisor discovery and addon info failed."""
|
|
|
|
addon_info.side_effect = error
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN,
|
|
|
|
context={"source": config_entries.SOURCE_HASSIO},
|
|
|
|
data=HassioServiceInfo(
|
|
|
|
config=ADDON_DISCOVERY_INFO,
|
|
|
|
name="Matter Server",
|
|
|
|
slug=ADDON_SLUG,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "hassio_confirm"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
|
|
|
|
|
|
|
assert addon_info.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.ABORT
|
|
|
|
assert result["reason"] == "addon_info_failed"
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
|
|
|
async def test_clean_supervisor_discovery_on_user_create(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_running: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
client_connect: AsyncMock,
|
|
|
|
setup_entry: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test discovery flow is cleaned up when a user flow is finished."""
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN,
|
|
|
|
context={"source": config_entries.SOURCE_HASSIO},
|
|
|
|
data=HassioServiceInfo(
|
|
|
|
config=ADDON_DISCOVERY_INFO,
|
|
|
|
name="Matter Server",
|
|
|
|
slug=ADDON_SLUG,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "hassio_confirm"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "on_supervisor"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"], {"use_addon": False}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert addon_info.call_count == 0
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "manual"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"],
|
|
|
|
{
|
|
|
|
"url": "ws://localhost:5580/ws",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert len(hass.config_entries.flow.async_progress()) == 0
|
|
|
|
assert client_connect.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.CREATE_ENTRY
|
2022-12-22 15:42:37 +00:00
|
|
|
assert result["title"] == "Matter"
|
2022-12-01 19:44:56 +00:00
|
|
|
assert result["data"] == {
|
|
|
|
"url": "ws://localhost:5580/ws",
|
|
|
|
"use_addon": False,
|
|
|
|
"integration_created_addon": False,
|
|
|
|
}
|
|
|
|
assert setup_entry.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
async def test_abort_supervisor_discovery_with_existing_entry(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_running: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test discovery flow is aborted if an entry already exists."""
|
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
data={"url": "ws://localhost:5580/ws"},
|
2022-12-22 15:42:37 +00:00
|
|
|
title="Matter",
|
2022-12-01 19:44:56 +00:00
|
|
|
)
|
|
|
|
entry.add_to_hass(hass)
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN,
|
|
|
|
context={"source": config_entries.SOURCE_HASSIO},
|
|
|
|
data=HassioServiceInfo(
|
|
|
|
config=ADDON_DISCOVERY_INFO,
|
|
|
|
name="Matter Server",
|
|
|
|
slug=ADDON_SLUG,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
assert addon_info.call_count == 0
|
|
|
|
assert result["type"] == FlowResultType.ABORT
|
|
|
|
assert result["reason"] == "already_configured"
|
|
|
|
|
|
|
|
|
|
|
|
async def test_abort_supervisor_discovery_with_existing_flow(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_installed: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test hassio discovery flow is aborted when another flow is in progress."""
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN,
|
|
|
|
context={"source": config_entries.SOURCE_USER},
|
|
|
|
)
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "on_supervisor"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN,
|
|
|
|
context={"source": config_entries.SOURCE_HASSIO},
|
|
|
|
data=HassioServiceInfo(
|
|
|
|
config=ADDON_DISCOVERY_INFO,
|
|
|
|
name="Matter Server",
|
|
|
|
slug=ADDON_SLUG,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
assert addon_info.call_count == 0
|
|
|
|
assert result["type"] == FlowResultType.ABORT
|
|
|
|
assert result["reason"] == "already_in_progress"
|
|
|
|
|
|
|
|
|
|
|
|
async def test_abort_supervisor_discovery_for_other_addon(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_installed: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test hassio discovery flow is aborted for a non official add-on discovery."""
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN,
|
|
|
|
context={"source": config_entries.SOURCE_HASSIO},
|
|
|
|
data=HassioServiceInfo(
|
|
|
|
config={
|
|
|
|
"addon": "Other Matter Server",
|
|
|
|
"host": "host1",
|
|
|
|
"port": 3001,
|
|
|
|
},
|
|
|
|
name="Other Matter Server",
|
|
|
|
slug="other_addon",
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
assert addon_info.call_count == 0
|
|
|
|
assert result["type"] == FlowResultType.ABORT
|
|
|
|
assert result["reason"] == "not_matter_addon"
|
|
|
|
|
|
|
|
|
|
|
|
async def test_supervisor_discovery_addon_not_running(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_installed: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
start_addon: AsyncMock,
|
|
|
|
client_connect: AsyncMock,
|
|
|
|
setup_entry: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test discovery with add-on already installed but not running."""
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN,
|
|
|
|
context={"source": config_entries.SOURCE_HASSIO},
|
|
|
|
data=HassioServiceInfo(
|
|
|
|
config=ADDON_DISCOVERY_INFO,
|
|
|
|
name="Matter Server",
|
|
|
|
slug=ADDON_SLUG,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
assert addon_info.call_count == 0
|
|
|
|
assert result["step_id"] == "hassio_confirm"
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
|
|
|
|
|
|
|
assert addon_info.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.SHOW_PROGRESS
|
|
|
|
assert result["step_id"] == "start_addon"
|
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert start_addon.call_args == call(hass, "core_matter_server")
|
|
|
|
assert client_connect.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.CREATE_ENTRY
|
2022-12-22 15:42:37 +00:00
|
|
|
assert result["title"] == "Matter"
|
2022-12-01 19:44:56 +00:00
|
|
|
assert result["data"] == {
|
|
|
|
"url": "ws://host1:5581/ws",
|
|
|
|
"use_addon": True,
|
|
|
|
"integration_created_addon": False,
|
|
|
|
}
|
|
|
|
assert setup_entry.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
async def test_supervisor_discovery_addon_not_installed(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_not_installed: AsyncMock,
|
|
|
|
install_addon: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
addon_store_info: AsyncMock,
|
|
|
|
start_addon: AsyncMock,
|
|
|
|
client_connect: AsyncMock,
|
|
|
|
setup_entry: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test discovery with add-on not installed."""
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN,
|
|
|
|
context={"source": config_entries.SOURCE_HASSIO},
|
|
|
|
data=HassioServiceInfo(
|
|
|
|
config=ADDON_DISCOVERY_INFO,
|
|
|
|
name="Matter Server",
|
|
|
|
slug=ADDON_SLUG,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
assert addon_info.call_count == 0
|
|
|
|
assert addon_store_info.call_count == 0
|
|
|
|
assert result["step_id"] == "hassio_confirm"
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"], {})
|
|
|
|
|
|
|
|
assert addon_info.call_count == 0
|
|
|
|
assert addon_store_info.call_count == 1
|
|
|
|
assert result["step_id"] == "install_addon"
|
|
|
|
assert result["type"] == FlowResultType.SHOW_PROGRESS
|
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
|
|
|
|
|
|
|
assert install_addon.call_args == call(hass, "core_matter_server")
|
|
|
|
assert result["type"] == FlowResultType.SHOW_PROGRESS
|
|
|
|
assert result["step_id"] == "start_addon"
|
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert start_addon.call_args == call(hass, "core_matter_server")
|
|
|
|
assert client_connect.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.CREATE_ENTRY
|
2022-12-22 15:42:37 +00:00
|
|
|
assert result["title"] == "Matter"
|
2022-12-01 19:44:56 +00:00
|
|
|
assert result["data"] == {
|
|
|
|
"url": "ws://host1:5581/ws",
|
|
|
|
"use_addon": True,
|
|
|
|
"integration_created_addon": True,
|
|
|
|
}
|
|
|
|
assert setup_entry.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
async def test_not_addon(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
client_connect: AsyncMock,
|
|
|
|
setup_entry: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test opting out of add-on on Supervisor."""
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "on_supervisor"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"], {"use_addon": False}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "manual"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"],
|
|
|
|
{
|
|
|
|
"url": "ws://localhost:5581/ws",
|
|
|
|
},
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert client_connect.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.CREATE_ENTRY
|
2022-12-22 15:42:37 +00:00
|
|
|
assert result["title"] == "Matter"
|
2022-12-01 19:44:56 +00:00
|
|
|
assert result["data"] == {
|
|
|
|
"url": "ws://localhost:5581/ws",
|
|
|
|
"use_addon": False,
|
|
|
|
"integration_created_addon": False,
|
|
|
|
}
|
|
|
|
assert setup_entry.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
|
|
|
async def test_addon_running(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_running: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
client_connect: AsyncMock,
|
|
|
|
setup_entry: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test add-on already running on Supervisor."""
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "on_supervisor"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"], {"use_addon": True}
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert addon_info.call_count == 1
|
|
|
|
assert client_connect.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.CREATE_ENTRY
|
2022-12-22 15:42:37 +00:00
|
|
|
assert result["title"] == "Matter"
|
2022-12-01 19:44:56 +00:00
|
|
|
assert result["data"] == {
|
|
|
|
"url": "ws://host1:5581/ws",
|
|
|
|
"use_addon": True,
|
|
|
|
"integration_created_addon": False,
|
|
|
|
}
|
|
|
|
assert setup_entry.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
@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(
|
|
|
|
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,
|
|
|
|
) -> None:
|
|
|
|
"""Test all failures when add-on is running."""
|
|
|
|
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_USER}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "on_supervisor"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"], {"use_addon": True}
|
|
|
|
)
|
|
|
|
|
|
|
|
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"] == FlowResultType.ABORT
|
|
|
|
assert result["reason"] == abort_reason
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
|
|
|
async def test_addon_running_already_configured(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_running: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
setup_entry: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test that only one instance is allowed when add-on is running."""
|
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
data={
|
|
|
|
"url": "ws://localhost:5580/ws",
|
|
|
|
},
|
2022-12-22 15:42:37 +00:00
|
|
|
title="Matter",
|
2022-12-01 19:44:56 +00:00
|
|
|
)
|
|
|
|
entry.add_to_hass(hass)
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "on_supervisor"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"], {"use_addon": True}
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert addon_info.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.ABORT
|
|
|
|
assert result["reason"] == "reconfiguration_successful"
|
|
|
|
assert entry.data["url"] == "ws://host1:5581/ws"
|
2022-12-22 15:42:37 +00:00
|
|
|
assert entry.title == "Matter"
|
2022-12-01 19:44:56 +00:00
|
|
|
assert setup_entry.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
|
|
|
async def test_addon_installed(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_installed: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
start_addon: AsyncMock,
|
|
|
|
setup_entry: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test add-on already installed but not running on Supervisor."""
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "on_supervisor"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"], {"use_addon": True}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert addon_info.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.SHOW_PROGRESS
|
|
|
|
assert result["step_id"] == "start_addon"
|
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert start_addon.call_args == call(hass, "core_matter_server")
|
|
|
|
assert result["type"] == FlowResultType.CREATE_ENTRY
|
2022-12-22 15:42:37 +00:00
|
|
|
assert result["title"] == "Matter"
|
2022-12-01 19:44:56 +00:00
|
|
|
assert result["data"] == {
|
|
|
|
"url": "ws://host1:5581/ws",
|
|
|
|
"use_addon": True,
|
|
|
|
"integration_created_addon": False,
|
|
|
|
}
|
|
|
|
assert setup_entry.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
@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(
|
|
|
|
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,
|
|
|
|
) -> None:
|
|
|
|
"""Test add-on start failure when add-on is installed."""
|
|
|
|
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_USER}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "on_supervisor"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"], {"use_addon": True}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert addon_info.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.SHOW_PROGRESS
|
|
|
|
assert result["step_id"] == "start_addon"
|
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
|
|
|
|
|
|
|
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"] == FlowResultType.ABORT
|
|
|
|
assert result["reason"] == "addon_start_failed"
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
|
|
|
async def test_addon_installed_already_configured(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_installed: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
start_addon: AsyncMock,
|
|
|
|
setup_entry: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test that only one instance is allowed when add-on is installed."""
|
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
data={
|
|
|
|
"url": "ws://localhost:5580/ws",
|
|
|
|
},
|
2022-12-22 15:42:37 +00:00
|
|
|
title="Matter",
|
2022-12-01 19:44:56 +00:00
|
|
|
)
|
|
|
|
entry.add_to_hass(hass)
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "on_supervisor"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"], {"use_addon": True}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert addon_info.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.SHOW_PROGRESS
|
|
|
|
assert result["step_id"] == "start_addon"
|
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert start_addon.call_args == call(hass, "core_matter_server")
|
|
|
|
assert result["type"] == FlowResultType.ABORT
|
|
|
|
assert result["reason"] == "reconfiguration_successful"
|
|
|
|
assert entry.data["url"] == "ws://host1:5581/ws"
|
2022-12-22 15:42:37 +00:00
|
|
|
assert entry.title == "Matter"
|
2022-12-01 19:44:56 +00:00
|
|
|
assert setup_entry.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
|
|
|
async def test_addon_not_installed(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_not_installed: AsyncMock,
|
|
|
|
install_addon: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
addon_store_info: AsyncMock,
|
|
|
|
start_addon: AsyncMock,
|
|
|
|
setup_entry: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test add-on not installed."""
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "on_supervisor"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"], {"use_addon": True}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert addon_info.call_count == 0
|
|
|
|
assert addon_store_info.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.SHOW_PROGRESS
|
|
|
|
assert result["step_id"] == "install_addon"
|
|
|
|
|
|
|
|
# Make sure the flow continues when the progress task is done.
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
|
|
|
|
|
|
|
assert install_addon.call_args == call(hass, "core_matter_server")
|
|
|
|
assert result["type"] == FlowResultType.SHOW_PROGRESS
|
|
|
|
assert result["step_id"] == "start_addon"
|
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert start_addon.call_args == call(hass, "core_matter_server")
|
|
|
|
assert result["type"] == FlowResultType.CREATE_ENTRY
|
2022-12-22 15:42:37 +00:00
|
|
|
assert result["title"] == "Matter"
|
2022-12-01 19:44:56 +00:00
|
|
|
assert result["data"] == {
|
|
|
|
"url": "ws://host1:5581/ws",
|
|
|
|
"use_addon": True,
|
|
|
|
"integration_created_addon": True,
|
|
|
|
}
|
|
|
|
assert setup_entry.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
async def test_addon_not_installed_failures(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_not_installed: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
install_addon: AsyncMock,
|
|
|
|
) -> 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_USER}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "on_supervisor"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"], {"use_addon": True}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.SHOW_PROGRESS
|
|
|
|
assert result["step_id"] == "install_addon"
|
|
|
|
|
|
|
|
# Make sure the flow continues when the progress task is done.
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
|
|
|
|
|
|
|
assert install_addon.call_args == call(hass, "core_matter_server")
|
|
|
|
assert addon_info.call_count == 0
|
|
|
|
assert result["type"] == FlowResultType.ABORT
|
|
|
|
assert result["reason"] == "addon_install_failed"
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize("discovery_info", [{"config": ADDON_DISCOVERY_INFO}])
|
|
|
|
async def test_addon_not_installed_already_configured(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
supervisor: MagicMock,
|
|
|
|
addon_not_installed: AsyncMock,
|
|
|
|
addon_info: AsyncMock,
|
|
|
|
addon_store_info: AsyncMock,
|
|
|
|
install_addon: AsyncMock,
|
|
|
|
start_addon: AsyncMock,
|
|
|
|
client_connect: AsyncMock,
|
|
|
|
setup_entry: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test that only one instance is allowed when add-on is not installed."""
|
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
data={
|
|
|
|
"url": "ws://localhost:5580/ws",
|
|
|
|
},
|
2022-12-22 15:42:37 +00:00
|
|
|
title="Matter",
|
2022-12-01 19:44:56 +00:00
|
|
|
)
|
|
|
|
entry.add_to_hass(hass)
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == FlowResultType.FORM
|
|
|
|
assert result["step_id"] == "on_supervisor"
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"], {"use_addon": True}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert addon_info.call_count == 0
|
|
|
|
assert addon_store_info.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.SHOW_PROGRESS
|
|
|
|
assert result["step_id"] == "install_addon"
|
|
|
|
|
|
|
|
# Make sure the flow continues when the progress task is done.
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
|
|
|
|
|
|
|
assert install_addon.call_args == call(hass, "core_matter_server")
|
|
|
|
assert result["type"] == FlowResultType.SHOW_PROGRESS
|
|
|
|
assert result["step_id"] == "start_addon"
|
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
result = await hass.config_entries.flow.async_configure(result["flow_id"])
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert start_addon.call_args == call(hass, "core_matter_server")
|
|
|
|
assert client_connect.call_count == 1
|
|
|
|
assert result["type"] == FlowResultType.ABORT
|
|
|
|
assert result["reason"] == "reconfiguration_successful"
|
|
|
|
assert entry.data["url"] == "ws://host1:5581/ws"
|
2022-12-22 15:42:37 +00:00
|
|
|
assert entry.title == "Matter"
|
2022-12-01 19:44:56 +00:00
|
|
|
assert setup_entry.call_count == 1
|