Cleanup Plugwise config flow and tests (#65818)

This commit is contained in:
Franck Nijhof 2022-02-05 19:07:02 +01:00 committed by GitHub
parent 5621e20963
commit b0bb2d2453
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 163 additions and 299 deletions

View File

@ -2,13 +2,14 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
from typing import Any
from plugwise.exceptions import InvalidAuthentication, PlugwiseException from plugwise.exceptions import InvalidAuthentication, PlugwiseException
from plugwise.smile import Smile from plugwise.smile import Smile
import voluptuous as vol import voluptuous as vol
from homeassistant import config_entries, core, exceptions from homeassistant.components.zeroconf import ZeroconfServiceInfo
from homeassistant.components import zeroconf from homeassistant.config_entries import ConfigFlow
from homeassistant.const import ( from homeassistant.const import (
CONF_BASE, CONF_BASE,
CONF_HOST, CONF_HOST,
@ -17,6 +18,7 @@ from homeassistant.const import (
CONF_PORT, CONF_PORT,
CONF_USERNAME, CONF_USERNAME,
) )
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResult from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
@ -25,11 +27,8 @@ from .const import (
DEFAULT_PORT, DEFAULT_PORT,
DEFAULT_USERNAME, DEFAULT_USERNAME,
DOMAIN, DOMAIN,
FLOW_NET,
FLOW_SMILE, FLOW_SMILE,
FLOW_STRETCH, FLOW_STRETCH,
FLOW_TYPE,
FLOW_USB,
PW_TYPE, PW_TYPE,
SMILE, SMILE,
STRETCH, STRETCH,
@ -39,14 +38,6 @@ from .const import (
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONF_MANUAL_PATH = "Enter Manually"
CONNECTION_SCHEMA = vol.Schema(
{vol.Required(FLOW_TYPE, default=FLOW_NET): vol.In([FLOW_NET, FLOW_USB])}
)
# PLACEHOLDER USB connection validation
def _base_gw_schema(discovery_info): def _base_gw_schema(discovery_info):
"""Generate base schema for gateways.""" """Generate base schema for gateways."""
@ -64,14 +55,13 @@ def _base_gw_schema(discovery_info):
return vol.Schema(base_gw_schema) return vol.Schema(base_gw_schema)
async def validate_gw_input(hass: core.HomeAssistant, data): async def validate_gw_input(hass: HomeAssistant, data: dict[str, Any]) -> Smile:
""" """
Validate whether the user input allows us to connect to the gateway. Validate whether the user input allows us to connect to the gateway.
Data has the keys from _base_gw_schema() with values provided by the user. Data has the keys from _base_gw_schema() with values provided by the user.
""" """
websession = async_get_clientsession(hass, verify_ssl=False) websession = async_get_clientsession(hass, verify_ssl=False)
api = Smile( api = Smile(
host=data[CONF_HOST], host=data[CONF_HOST],
password=data[CONF_PASSWORD], password=data[CONF_PASSWORD],
@ -80,35 +70,25 @@ async def validate_gw_input(hass: core.HomeAssistant, data):
timeout=30, timeout=30,
websession=websession, websession=websession,
) )
await api.connect()
try:
await api.connect()
except InvalidAuthentication as err:
raise InvalidAuth from err
except PlugwiseException as err:
raise CannotConnect from err
return api return api
class PlugwiseConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): class PlugwiseConfigFlow(ConfigFlow, domain=DOMAIN):
"""Handle a config flow for Plugwise Smile.""" """Handle a config flow for Plugwise Smile."""
VERSION = 1 VERSION = 1
def __init__(self): discovery_info: ZeroconfServiceInfo | None = None
"""Initialize the Plugwise config flow.""" _username: str = DEFAULT_USERNAME
self.discovery_info: zeroconf.ZeroconfServiceInfo | None = None
self._username: str = DEFAULT_USERNAME
async def async_step_zeroconf( async def async_step_zeroconf(
self, discovery_info: zeroconf.ZeroconfServiceInfo self, discovery_info: ZeroconfServiceInfo
) -> FlowResult: ) -> FlowResult:
"""Prepare configuration for a discovered Plugwise Smile.""" """Prepare configuration for a discovered Plugwise Smile."""
self.discovery_info = discovery_info self.discovery_info = discovery_info
_properties = discovery_info.properties _properties = discovery_info.properties
# unique_id is needed here, to be able to determine whether the discovered device is known, or not.
unique_id = discovery_info.hostname.split(".")[0] unique_id = discovery_info.hostname.split(".")[0]
await self.async_set_unique_id(unique_id) await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured({CONF_HOST: discovery_info.host}) self._abort_if_unique_id_configured({CONF_HOST: discovery_info.host})
@ -125,18 +105,15 @@ class PlugwiseConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
CONF_PORT: discovery_info.port, CONF_PORT: discovery_info.port,
CONF_USERNAME: self._username, CONF_USERNAME: self._username,
} }
return await self.async_step_user_gateway() return await self.async_step_user()
# PLACEHOLDER USB step_user async def async_step_user(
self, user_input: dict[str, Any] | None = None
async def async_step_user_gateway(self, user_input=None): ) -> FlowResult:
"""Handle the initial step when using network/gateway setups.""" """Handle the initial step when using network/gateway setups."""
api = None
errors = {} errors = {}
if user_input is not None: if user_input is not None:
user_input.pop(FLOW_TYPE, None)
if self.discovery_info: if self.discovery_info:
user_input[CONF_HOST] = self.discovery_info.host user_input[CONF_HOST] = self.discovery_info.host
user_input[CONF_PORT] = self.discovery_info.port user_input[CONF_PORT] = self.discovery_info.port
@ -144,16 +121,14 @@ class PlugwiseConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
try: try:
api = await validate_gw_input(self.hass, user_input) api = await validate_gw_input(self.hass, user_input)
except InvalidAuthentication:
except CannotConnect:
errors[CONF_BASE] = "cannot_connect"
except InvalidAuth:
errors[CONF_BASE] = "invalid_auth" errors[CONF_BASE] = "invalid_auth"
except PlugwiseException:
errors[CONF_BASE] = "cannot_connect"
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception") _LOGGER.exception("Unexpected exception")
errors[CONF_BASE] = "unknown" errors[CONF_BASE] = "unknown"
else:
if not errors:
await self.async_set_unique_id( await self.async_set_unique_id(
api.smile_hostname or api.gateway_id, raise_on_progress=False api.smile_hostname or api.gateway_id, raise_on_progress=False
) )
@ -163,30 +138,7 @@ class PlugwiseConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_create_entry(title=api.smile_name, data=user_input) return self.async_create_entry(title=api.smile_name, data=user_input)
return self.async_show_form( return self.async_show_form(
step_id="user_gateway", step_id="user",
data_schema=_base_gw_schema(self.discovery_info), data_schema=_base_gw_schema(self.discovery_info),
errors=errors, errors=errors,
) )
async def async_step_user(self, user_input=None):
"""Handle the initial step when using network/gateway setups."""
errors = {}
if user_input is not None:
if user_input[FLOW_TYPE] == FLOW_NET:
return await self.async_step_user_gateway()
# PLACEHOLDER for USB_FLOW
return self.async_show_form(
step_id="user",
data_schema=CONNECTION_SCHEMA,
errors=errors,
)
class CannotConnect(exceptions.HomeAssistantError):
"""Error to indicate we cannot connect."""
class InvalidAuth(exceptions.HomeAssistantError):
"""Error to indicate there is invalid auth."""

View File

@ -8,11 +8,9 @@ ATTR_ILLUMINANCE = "illuminance"
COORDINATOR = "coordinator" COORDINATOR = "coordinator"
DEVICE_STATE = "device_state" DEVICE_STATE = "device_state"
DOMAIN = "plugwise" DOMAIN = "plugwise"
FLOW_NET = "Network: Smile/Stretch"
FLOW_SMILE = "smile (Adam/Anna/P1)" FLOW_SMILE = "smile (Adam/Anna/P1)"
FLOW_STRETCH = "stretch (Stretch)" FLOW_STRETCH = "stretch (Stretch)"
FLOW_TYPE = "flow_type" FLOW_TYPE = "flow_type"
FLOW_USB = "USB: Stick - Coming soon"
GATEWAY = "gateway" GATEWAY = "gateway"
PW_TYPE = "plugwise_type" PW_TYPE = "plugwise_type"
SCHEDULE_OFF = "false" SCHEDULE_OFF = "false"

View File

@ -1,9 +1,11 @@
"""Setup mocks for the Plugwise integration tests.""" """Setup mocks for the Plugwise integration tests."""
from __future__ import annotations
from collections.abc import Generator
from functools import partial from functools import partial
from http import HTTPStatus from http import HTTPStatus
import re import re
from unittest.mock import AsyncMock, Mock, patch from unittest.mock import AsyncMock, MagicMock, Mock, patch
import jsonpickle import jsonpickle
from plugwise.exceptions import ( from plugwise.exceptions import (
@ -24,16 +26,27 @@ def _read_json(environment, call):
return jsonpickle.decode(fixture) return jsonpickle.decode(fixture)
@pytest.fixture(name="mock_smile") @pytest.fixture
def mock_smile(): def mock_setup_entry() -> Generator[AsyncMock, None, None]:
"""Create a Mock Smile for testing exceptions.""" """Mock setting up a config entry."""
with patch(
"homeassistant.components.plugwise.async_setup_entry", return_value=True
) as mock_setup:
yield mock_setup
@pytest.fixture()
def mock_smile_config_flow() -> Generator[None, MagicMock, None]:
"""Return a mocked Smile client."""
with patch( with patch(
"homeassistant.components.plugwise.config_flow.Smile", "homeassistant.components.plugwise.config_flow.Smile",
autospec=True,
) as smile_mock: ) as smile_mock:
smile_mock.InvalidAuthentication = InvalidAuthentication smile = smile_mock.return_value
smile_mock.ConnectionFailedError = ConnectionFailedError smile.smile_hostname = "smile12345"
smile_mock.return_value.connect.return_value = True smile.smile_name = "Test Smile Name"
yield smile_mock.return_value smile.connect.return_value = True
yield smile
@pytest.fixture(name="mock_smile_unauth") @pytest.fixture(name="mock_smile_unauth")

View File

@ -1,5 +1,5 @@
"""Test the Plugwise config flow.""" """Test the Plugwise config flow."""
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, MagicMock, patch
from plugwise.exceptions import ( from plugwise.exceptions import (
ConnectionFailedError, ConnectionFailedError,
@ -8,15 +8,8 @@ from plugwise.exceptions import (
) )
import pytest import pytest
from homeassistant.components import zeroconf from homeassistant.components.plugwise.const import API, DEFAULT_PORT, DOMAIN, PW_TYPE
from homeassistant.components.plugwise.const import ( from homeassistant.components.zeroconf import ZeroconfServiceInfo
API,
DEFAULT_PORT,
DOMAIN,
FLOW_NET,
FLOW_TYPE,
PW_TYPE,
)
from homeassistant.config_entries import SOURCE_USER, SOURCE_ZEROCONF from homeassistant.config_entries import SOURCE_USER, SOURCE_ZEROCONF
from homeassistant.const import ( from homeassistant.const import (
CONF_HOST, CONF_HOST,
@ -26,7 +19,12 @@ from homeassistant.const import (
CONF_SOURCE, CONF_SOURCE,
CONF_USERNAME, CONF_USERNAME,
) )
from homeassistant.data_entry_flow import RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_FORM from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import (
RESULT_TYPE_ABORT,
RESULT_TYPE_CREATE_ENTRY,
RESULT_TYPE_FORM,
)
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
@ -38,7 +36,7 @@ TEST_PORT = 81
TEST_USERNAME = "smile" TEST_USERNAME = "smile"
TEST_USERNAME2 = "stretch" TEST_USERNAME2 = "stretch"
TEST_DISCOVERY = zeroconf.ZeroconfServiceInfo( TEST_DISCOVERY = ZeroconfServiceInfo(
host=TEST_HOST, host=TEST_HOST,
hostname=f"{TEST_HOSTNAME}.local.", hostname=f"{TEST_HOSTNAME}.local.",
name="mock_name", name="mock_name",
@ -50,7 +48,8 @@ TEST_DISCOVERY = zeroconf.ZeroconfServiceInfo(
}, },
type="mock_type", type="mock_type",
) )
TEST_DISCOVERY2 = zeroconf.ZeroconfServiceInfo(
TEST_DISCOVERY2 = ZeroconfServiceInfo(
host=TEST_HOST, host=TEST_HOST,
hostname=f"{TEST_HOSTNAME2}.local.", hostname=f"{TEST_HOSTNAME2}.local.",
name="mock_name", name="mock_name",
@ -77,49 +76,32 @@ def mock_smile():
yield smile_mock.return_value yield smile_mock.return_value
async def test_form_flow_gateway(hass): async def test_form(
"""Test we get the form for Plugwise Gateway product type.""" hass: HomeAssistant,
mock_setup_entry: AsyncMock,
mock_smile_config_flow: MagicMock,
) -> None:
"""Test the full user configuration flow."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER} DOMAIN, context={CONF_SOURCE: SOURCE_USER}
) )
assert result["type"] == RESULT_TYPE_FORM assert result.get("type") == RESULT_TYPE_FORM
assert result["errors"] == {} assert result.get("errors") == {}
assert result["step_id"] == "user" assert result.get("step_id") == "user"
assert "flow_id" in result
result = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={FLOW_TYPE: FLOW_NET} result["flow_id"],
user_input={
CONF_HOST: TEST_HOST,
CONF_PASSWORD: TEST_PASSWORD,
},
) )
assert result["type"] == RESULT_TYPE_FORM
assert result["errors"] == {}
assert result["step_id"] == "user_gateway"
async def test_form(hass):
"""Test we get the form."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data={FLOW_TYPE: FLOW_NET}
)
assert result["type"] == RESULT_TYPE_FORM
assert result["errors"] == {}
with patch(
"homeassistant.components.plugwise.config_flow.Smile.connect",
return_value=True,
), patch(
"homeassistant.components.plugwise.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD},
)
await hass.async_block_till_done() await hass.async_block_till_done()
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY assert result2.get("type") == RESULT_TYPE_CREATE_ENTRY
assert result2["data"] == { assert result2.get("title") == "Test Smile Name"
assert result2.get("data") == {
CONF_HOST: TEST_HOST, CONF_HOST: TEST_HOST,
CONF_PASSWORD: TEST_PASSWORD, CONF_PASSWORD: TEST_PASSWORD,
CONF_PORT: DEFAULT_PORT, CONF_PORT: DEFAULT_PORT,
@ -128,72 +110,79 @@ async def test_form(hass):
} }
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_smile_config_flow.connect.mock_calls) == 1
async def test_zeroconf_form(hass): @pytest.mark.parametrize(
"""Test we get the form.""" "discovery,username",
[
(TEST_DISCOVERY, TEST_USERNAME),
(TEST_DISCOVERY2, TEST_USERNAME2),
],
)
async def test_zeroconf_flow(
hass: HomeAssistant,
mock_setup_entry: AsyncMock,
mock_smile_config_flow: MagicMock,
discovery: ZeroconfServiceInfo,
username: str,
) -> None:
"""Test config flow for smile devices."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
context={CONF_SOURCE: SOURCE_ZEROCONF}, context={CONF_SOURCE: SOURCE_ZEROCONF},
data=TEST_DISCOVERY, data=discovery,
) )
assert result["type"] == RESULT_TYPE_FORM assert result.get("type") == RESULT_TYPE_FORM
assert result["errors"] == {} assert result.get("errors") == {}
assert result.get("step_id") == "user"
with patch( assert "flow_id" in result
"homeassistant.components.plugwise.config_flow.Smile.connect",
return_value=True,
), patch(
"homeassistant.components.plugwise.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_PASSWORD: TEST_PASSWORD},
)
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_PASSWORD: TEST_PASSWORD},
)
await hass.async_block_till_done() await hass.async_block_till_done()
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY assert result2.get("type") == RESULT_TYPE_CREATE_ENTRY
assert result2["data"] == { assert result2.get("title") == "Test Smile Name"
assert result2.get("data") == {
CONF_HOST: TEST_HOST, CONF_HOST: TEST_HOST,
CONF_PASSWORD: TEST_PASSWORD, CONF_PASSWORD: TEST_PASSWORD,
CONF_PORT: DEFAULT_PORT, CONF_PORT: DEFAULT_PORT,
CONF_USERNAME: TEST_USERNAME, CONF_USERNAME: username,
PW_TYPE: API, PW_TYPE: API,
} }
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_smile_config_flow.connect.mock_calls) == 1
async def test_zeroconf_stretch_form(hass): async def test_zeroconf_flow_stretch(
"""Test we get the form.""" hass: HomeAssistant,
mock_setup_entry: AsyncMock,
mock_smile_config_flow: MagicMock,
) -> None:
"""Test config flow for stretch devices."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, DOMAIN,
context={CONF_SOURCE: SOURCE_ZEROCONF}, context={CONF_SOURCE: SOURCE_ZEROCONF},
data=TEST_DISCOVERY2, data=TEST_DISCOVERY2,
) )
assert result["type"] == RESULT_TYPE_FORM assert result.get("type") == RESULT_TYPE_FORM
assert result["errors"] == {} assert result.get("errors") == {}
assert result.get("step_id") == "user"
with patch( assert "flow_id" in result
"homeassistant.components.plugwise.config_flow.Smile.connect",
return_value=True,
), patch(
"homeassistant.components.plugwise.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_PASSWORD: TEST_PASSWORD},
)
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_PASSWORD: TEST_PASSWORD},
)
await hass.async_block_till_done() await hass.async_block_till_done()
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY assert result2.get("type") == RESULT_TYPE_CREATE_ENTRY
assert result2["data"] == { assert result2.get("title") == "Test Smile Name"
assert result2.get("data") == {
CONF_HOST: TEST_HOST, CONF_HOST: TEST_HOST,
CONF_PASSWORD: TEST_PASSWORD, CONF_PASSWORD: TEST_PASSWORD,
CONF_PORT: DEFAULT_PORT, CONF_PORT: DEFAULT_PORT,
@ -202,9 +191,10 @@ async def test_zeroconf_stretch_form(hass):
} }
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
assert len(mock_smile_config_flow.connect.mock_calls) == 1
async def test_zercoconf_discovery_update_configuration(hass): async def test_zercoconf_discovery_update_configuration(hass: HomeAssistant) -> None:
"""Test if a discovered device is configured and updated with new host.""" """Test if a discovered device is configured and updated with new host."""
entry = MockConfigEntry( entry = MockConfigEntry(
domain=DOMAIN, domain=DOMAIN,
@ -222,154 +212,65 @@ async def test_zercoconf_discovery_update_configuration(hass):
data=TEST_DISCOVERY, data=TEST_DISCOVERY,
) )
assert result["type"] == "abort" assert result.get("type") == RESULT_TYPE_ABORT
assert result["reason"] == "already_configured" assert result.get("reason") == "already_configured"
assert entry.data[CONF_HOST] == "1.1.1.1" assert entry.data[CONF_HOST] == "1.1.1.1"
async def test_form_username(hass): @pytest.mark.parametrize(
"""Test we get the username data back.""" "side_effect,reason",
[
result = await hass.config_entries.flow.async_init( (InvalidAuthentication, "invalid_auth"),
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data={FLOW_TYPE: FLOW_NET} (ConnectionFailedError, "cannot_connect"),
) (PlugwiseException, "cannot_connect"),
assert result["type"] == RESULT_TYPE_FORM (RuntimeError, "unknown"),
assert result["errors"] == {} ],
)
with patch( async def test_flow_errors(
"homeassistant.components.plugwise.config_flow.Smile", hass: HomeAssistant,
) as smile_mock, patch( mock_setup_entry: AsyncMock,
"homeassistant.components.plugwise.async_setup_entry", mock_smile_config_flow: MagicMock,
return_value=True, side_effect: Exception,
) as mock_setup_entry: reason: str,
smile_mock.return_value.connect.side_effect = AsyncMock(return_value=True) ) -> None:
smile_mock.return_value.gateway_id = "abcdefgh12345678"
smile_mock.return_value.smile_hostname = TEST_HOST
smile_mock.return_value.smile_name = "Adam"
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_HOST: TEST_HOST,
CONF_PASSWORD: TEST_PASSWORD,
CONF_USERNAME: TEST_USERNAME2,
},
)
await hass.async_block_till_done()
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
assert result2["data"] == {
CONF_HOST: TEST_HOST,
CONF_PASSWORD: TEST_PASSWORD,
CONF_PORT: DEFAULT_PORT,
CONF_USERNAME: TEST_USERNAME2,
PW_TYPE: API,
}
assert len(mock_setup_entry.mock_calls) == 1
result3 = await hass.config_entries.flow.async_init(
DOMAIN,
context={CONF_SOURCE: SOURCE_ZEROCONF},
data=TEST_DISCOVERY,
)
assert result3["type"] == RESULT_TYPE_FORM
with patch(
"homeassistant.components.plugwise.config_flow.Smile",
) as smile_mock, patch(
"homeassistant.components.plugwise.async_setup_entry",
return_value=True,
) as mock_setup_entry:
smile_mock.return_value.side_effect = AsyncMock(return_value=True)
smile_mock.return_value.connect.side_effect = AsyncMock(return_value=True)
smile_mock.return_value.gateway_id = "abcdefgh12345678"
smile_mock.return_value.smile_hostname = TEST_HOST
smile_mock.return_value.smile_name = "Adam"
result4 = await hass.config_entries.flow.async_configure(
result3["flow_id"],
user_input={CONF_PASSWORD: TEST_PASSWORD},
)
await hass.async_block_till_done()
assert result4["type"] == "abort"
assert result4["reason"] == "already_configured"
async def test_form_invalid_auth(hass, mock_smile):
"""Test we handle invalid auth.""" """Test we handle invalid auth."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data={FLOW_TYPE: FLOW_NET} DOMAIN,
context={CONF_SOURCE: SOURCE_USER},
) )
assert result.get("type") == RESULT_TYPE_FORM
assert result.get("errors") == {}
assert result.get("step_id") == "user"
assert "flow_id" in result
mock_smile.connect.side_effect = InvalidAuthentication mock_smile_config_flow.connect.side_effect = side_effect
mock_smile.gateway_id = "0a636a4fc1704ab4a24e4f7e37fb187a"
result2 = await hass.config_entries.flow.async_configure( result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
user_input={CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD}, user_input={CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD},
) )
assert result2["type"] == RESULT_TYPE_FORM assert result2.get("type") == RESULT_TYPE_FORM
assert result2["errors"] == {"base": "invalid_auth"} assert result2.get("errors") == {"base": reason}
assert result2.get("step_id") == "user"
assert len(mock_setup_entry.mock_calls) == 0
assert len(mock_smile_config_flow.connect.mock_calls) == 1
async def test_form_cannot_connect(hass, mock_smile): mock_smile_config_flow.connect.side_effect = None
"""Test we handle cannot connect error.""" result3 = await hass.config_entries.flow.async_configure(
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data={FLOW_TYPE: FLOW_NET}
)
mock_smile.connect.side_effect = ConnectionFailedError
mock_smile.gateway_id = "0a636a4fc1704ab4a24e4f7e37fb187a"
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], result["flow_id"],
user_input={CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD}, user_input={CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD},
) )
assert result2["type"] == RESULT_TYPE_FORM assert result3.get("type") == RESULT_TYPE_CREATE_ENTRY
assert result2["errors"] == {"base": "cannot_connect"} assert result3.get("title") == "Test Smile Name"
assert result3.get("data") == {
CONF_HOST: TEST_HOST,
CONF_PASSWORD: TEST_PASSWORD,
CONF_PORT: DEFAULT_PORT,
CONF_USERNAME: TEST_USERNAME,
PW_TYPE: API,
}
assert len(mock_setup_entry.mock_calls) == 1
async def test_form_cannot_connect_port(hass, mock_smile): assert len(mock_smile_config_flow.connect.mock_calls) == 2
"""Test we handle cannot connect to port error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data={FLOW_TYPE: FLOW_NET}
)
mock_smile.connect.side_effect = ConnectionFailedError
mock_smile.gateway_id = "0a636a4fc1704ab4a24e4f7e37fb187a"
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={
CONF_HOST: TEST_HOST,
CONF_PASSWORD: TEST_PASSWORD,
CONF_PORT: TEST_PORT,
},
)
assert result2["type"] == RESULT_TYPE_FORM
assert result2["errors"] == {"base": "cannot_connect"}
async def test_form_other_problem(hass, mock_smile):
"""Test we handle cannot connect error."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data={FLOW_TYPE: FLOW_NET}
)
mock_smile.connect.side_effect = TimeoutError
mock_smile.gateway_id = "0a636a4fc1704ab4a24e4f7e37fb187a"
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input={CONF_HOST: TEST_HOST, CONF_PASSWORD: TEST_PASSWORD},
)
assert result2["type"] == RESULT_TYPE_FORM
assert result2["errors"] == {"base": "unknown"}