Add already exists config flow tests for Ecovacs (#133572)
Co-authored-by: Michael <35783820+mib1185@users.noreply.github.com> Co-authored-by: Franck Nijhof <git@frenck.dev>pull/133826/head
parent
07322c6992
commit
0ad9af0feb
|
@ -1,6 +1,7 @@
|
||||||
"""Test Ecovacs config flow."""
|
"""Test Ecovacs config flow."""
|
||||||
|
|
||||||
from collections.abc import Awaitable, Callable
|
from collections.abc import Awaitable, Callable
|
||||||
|
from dataclasses import dataclass, field
|
||||||
import ssl
|
import ssl
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import AsyncMock, Mock, patch
|
from unittest.mock import AsyncMock, Mock, patch
|
||||||
|
@ -28,15 +29,20 @@ from .const import (
|
||||||
VALID_ENTRY_DATA_SELF_HOSTED_WITH_VALIDATE_CERT,
|
VALID_ENTRY_DATA_SELF_HOSTED_WITH_VALIDATE_CERT,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
_USER_STEP_SELF_HOSTED = {CONF_MODE: InstanceMode.SELF_HOSTED}
|
_USER_STEP_SELF_HOSTED = {CONF_MODE: InstanceMode.SELF_HOSTED}
|
||||||
|
|
||||||
_TEST_FN_AUTH_ARG = "user_input_auth"
|
|
||||||
_TEST_FN_USER_ARG = "user_input_user"
|
@dataclass
|
||||||
|
class _TestFnUserInput:
|
||||||
|
auth: dict[str, Any]
|
||||||
|
user: dict[str, Any] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
async def _test_user_flow(
|
async def _test_user_flow(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
user_input_auth: dict[str, Any],
|
user_input: _TestFnUserInput,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Test config flow."""
|
"""Test config flow."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
@ -50,15 +56,13 @@ async def _test_user_flow(
|
||||||
|
|
||||||
return await hass.config_entries.flow.async_configure(
|
return await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input=user_input_auth,
|
user_input=user_input.auth,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _test_user_flow_show_advanced_options(
|
async def _test_user_flow_show_advanced_options(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
*,
|
user_input: _TestFnUserInput,
|
||||||
user_input_auth: dict[str, Any],
|
|
||||||
user_input_user: dict[str, Any] | None = None,
|
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Test config flow."""
|
"""Test config flow."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
@ -72,7 +76,7 @@ async def _test_user_flow_show_advanced_options(
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input=user_input_user or {},
|
user_input=user_input.user,
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.FORM
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
@ -81,29 +85,26 @@ async def _test_user_flow_show_advanced_options(
|
||||||
|
|
||||||
return await hass.config_entries.flow.async_configure(
|
return await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input=user_input_auth,
|
user_input=user_input.auth,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("test_fn", "test_fn_args", "entry_data"),
|
("test_fn", "test_fn_user_input", "entry_data"),
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
_test_user_flow_show_advanced_options,
|
_test_user_flow_show_advanced_options,
|
||||||
{_TEST_FN_AUTH_ARG: VALID_ENTRY_DATA_CLOUD},
|
_TestFnUserInput(VALID_ENTRY_DATA_CLOUD),
|
||||||
VALID_ENTRY_DATA_CLOUD,
|
VALID_ENTRY_DATA_CLOUD,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
_test_user_flow_show_advanced_options,
|
_test_user_flow_show_advanced_options,
|
||||||
{
|
_TestFnUserInput(VALID_ENTRY_DATA_SELF_HOSTED, _USER_STEP_SELF_HOSTED),
|
||||||
_TEST_FN_AUTH_ARG: VALID_ENTRY_DATA_SELF_HOSTED,
|
|
||||||
_TEST_FN_USER_ARG: _USER_STEP_SELF_HOSTED,
|
|
||||||
},
|
|
||||||
VALID_ENTRY_DATA_SELF_HOSTED,
|
VALID_ENTRY_DATA_SELF_HOSTED,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
_test_user_flow,
|
_test_user_flow,
|
||||||
{_TEST_FN_AUTH_ARG: VALID_ENTRY_DATA_CLOUD},
|
_TestFnUserInput(VALID_ENTRY_DATA_CLOUD),
|
||||||
VALID_ENTRY_DATA_CLOUD,
|
VALID_ENTRY_DATA_CLOUD,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -114,18 +115,12 @@ async def test_user_flow(
|
||||||
mock_setup_entry: AsyncMock,
|
mock_setup_entry: AsyncMock,
|
||||||
mock_authenticator_authenticate: AsyncMock,
|
mock_authenticator_authenticate: AsyncMock,
|
||||||
mock_mqtt_client: Mock,
|
mock_mqtt_client: Mock,
|
||||||
test_fn: Callable[[HomeAssistant, dict[str, Any]], Awaitable[dict[str, Any]]]
|
test_fn: Callable[[HomeAssistant, _TestFnUserInput], Awaitable[dict[str, Any]]],
|
||||||
| Callable[
|
test_fn_user_input: _TestFnUserInput,
|
||||||
[HomeAssistant, dict[str, Any], dict[str, Any]], Awaitable[dict[str, Any]]
|
|
||||||
],
|
|
||||||
test_fn_args: dict[str, Any],
|
|
||||||
entry_data: dict[str, Any],
|
entry_data: dict[str, Any],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the user config flow."""
|
"""Test the user config flow."""
|
||||||
result = await test_fn(
|
result = await test_fn(hass, test_fn_user_input)
|
||||||
hass,
|
|
||||||
**test_fn_args,
|
|
||||||
)
|
|
||||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
assert result["title"] == entry_data[CONF_USERNAME]
|
assert result["title"] == entry_data[CONF_USERNAME]
|
||||||
assert result["data"] == entry_data
|
assert result["data"] == entry_data
|
||||||
|
@ -161,24 +156,21 @@ def _cannot_connect_error(user_input: dict[str, Any]) -> str:
|
||||||
ids=["cannot_connect", "invalid_auth", "unknown"],
|
ids=["cannot_connect", "invalid_auth", "unknown"],
|
||||||
)
|
)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("test_fn", "test_fn_args", "entry_data"),
|
("test_fn", "test_fn_user_input", "entry_data"),
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
_test_user_flow_show_advanced_options,
|
_test_user_flow_show_advanced_options,
|
||||||
{_TEST_FN_AUTH_ARG: VALID_ENTRY_DATA_CLOUD},
|
_TestFnUserInput(VALID_ENTRY_DATA_CLOUD),
|
||||||
VALID_ENTRY_DATA_CLOUD,
|
VALID_ENTRY_DATA_CLOUD,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
_test_user_flow_show_advanced_options,
|
_test_user_flow_show_advanced_options,
|
||||||
{
|
_TestFnUserInput(VALID_ENTRY_DATA_SELF_HOSTED, _USER_STEP_SELF_HOSTED),
|
||||||
_TEST_FN_AUTH_ARG: VALID_ENTRY_DATA_SELF_HOSTED,
|
|
||||||
_TEST_FN_USER_ARG: _USER_STEP_SELF_HOSTED,
|
|
||||||
},
|
|
||||||
VALID_ENTRY_DATA_SELF_HOSTED_WITH_VALIDATE_CERT,
|
VALID_ENTRY_DATA_SELF_HOSTED_WITH_VALIDATE_CERT,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
_test_user_flow,
|
_test_user_flow,
|
||||||
{_TEST_FN_AUTH_ARG: VALID_ENTRY_DATA_CLOUD},
|
_TestFnUserInput(VALID_ENTRY_DATA_CLOUD),
|
||||||
VALID_ENTRY_DATA_CLOUD,
|
VALID_ENTRY_DATA_CLOUD,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -193,22 +185,16 @@ async def test_user_flow_raise_error(
|
||||||
reason_rest: str,
|
reason_rest: str,
|
||||||
side_effect_mqtt: Exception,
|
side_effect_mqtt: Exception,
|
||||||
errors_mqtt: Callable[[dict[str, Any]], str],
|
errors_mqtt: Callable[[dict[str, Any]], str],
|
||||||
test_fn: Callable[[HomeAssistant, dict[str, Any]], Awaitable[dict[str, Any]]]
|
test_fn: Callable[[HomeAssistant, _TestFnUserInput], Awaitable[dict[str, Any]]],
|
||||||
| Callable[
|
test_fn_user_input: _TestFnUserInput,
|
||||||
[HomeAssistant, dict[str, Any], dict[str, Any]], Awaitable[dict[str, Any]]
|
|
||||||
],
|
|
||||||
test_fn_args: dict[str, Any],
|
|
||||||
entry_data: dict[str, Any],
|
entry_data: dict[str, Any],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test handling error on library calls."""
|
"""Test handling error on library calls."""
|
||||||
user_input_auth = test_fn_args[_TEST_FN_AUTH_ARG]
|
user_input_auth = test_fn_user_input.auth
|
||||||
|
|
||||||
# Authenticator raises error
|
# Authenticator raises error
|
||||||
mock_authenticator_authenticate.side_effect = side_effect_rest
|
mock_authenticator_authenticate.side_effect = side_effect_rest
|
||||||
result = await test_fn(
|
result = await test_fn(hass, test_fn_user_input)
|
||||||
hass,
|
|
||||||
**test_fn_args,
|
|
||||||
)
|
|
||||||
assert result["type"] is FlowResultType.FORM
|
assert result["type"] is FlowResultType.FORM
|
||||||
assert result["step_id"] == "auth"
|
assert result["step_id"] == "auth"
|
||||||
assert result["errors"] == {"base": reason_rest}
|
assert result["errors"] == {"base": reason_rest}
|
||||||
|
@ -256,12 +242,14 @@ async def test_user_flow_self_hosted_error(
|
||||||
|
|
||||||
result = await _test_user_flow_show_advanced_options(
|
result = await _test_user_flow_show_advanced_options(
|
||||||
hass,
|
hass,
|
||||||
user_input_auth=VALID_ENTRY_DATA_SELF_HOSTED
|
_TestFnUserInput(
|
||||||
|
VALID_ENTRY_DATA_SELF_HOSTED
|
||||||
| {
|
| {
|
||||||
CONF_OVERRIDE_REST_URL: "bla://localhost:8000",
|
CONF_OVERRIDE_REST_URL: "bla://localhost:8000",
|
||||||
CONF_OVERRIDE_MQTT_URL: "mqtt://",
|
CONF_OVERRIDE_MQTT_URL: "mqtt://",
|
||||||
},
|
},
|
||||||
user_input_user=_USER_STEP_SELF_HOSTED,
|
_USER_STEP_SELF_HOSTED,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] is FlowResultType.FORM
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
@ -298,3 +286,39 @@ async def test_user_flow_self_hosted_error(
|
||||||
mock_setup_entry.assert_called()
|
mock_setup_entry.assert_called()
|
||||||
mock_authenticator_authenticate.assert_called()
|
mock_authenticator_authenticate.assert_called()
|
||||||
mock_mqtt_client.verify_config.assert_called()
|
mock_mqtt_client.verify_config.assert_called()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("test_fn", "test_fn_user_input"),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
_test_user_flow_show_advanced_options,
|
||||||
|
_TestFnUserInput(VALID_ENTRY_DATA_CLOUD),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
_test_user_flow_show_advanced_options,
|
||||||
|
_TestFnUserInput(VALID_ENTRY_DATA_SELF_HOSTED, _USER_STEP_SELF_HOSTED),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
_test_user_flow,
|
||||||
|
_TestFnUserInput(VALID_ENTRY_DATA_CLOUD),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
ids=["advanced_cloud", "advanced_self_hosted", "cloud"],
|
||||||
|
)
|
||||||
|
async def test_already_exists(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
test_fn: Callable[[HomeAssistant, _TestFnUserInput], Awaitable[dict[str, Any]]],
|
||||||
|
test_fn_user_input: _TestFnUserInput,
|
||||||
|
) -> None:
|
||||||
|
"""Test we don't allow duplicated config entries."""
|
||||||
|
MockConfigEntry(domain=DOMAIN, data=test_fn_user_input.auth).add_to_hass(hass)
|
||||||
|
|
||||||
|
result = await test_fn(
|
||||||
|
hass,
|
||||||
|
test_fn_user_input,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result
|
||||||
|
assert result["type"] is FlowResultType.ABORT
|
||||||
|
assert result["reason"] == "already_configured"
|
||||||
|
|
Loading…
Reference in New Issue