Add reauth step to Hyperion config flow (#43797)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
d0ebc00684
commit
aaae452d58
8 changed files with 275 additions and 46 deletions
|
@ -8,8 +8,8 @@ from hyperion import client, const as hyperion_const
|
|||
from pkg_resources import parse_version
|
||||
|
||||
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_TOKEN
|
||||
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntry
|
||||
from homeassistant.const import CONF_HOST, CONF_PORT, CONF_SOURCE, CONF_TOKEN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_send
|
||||
|
@ -85,6 +85,17 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||
return True
|
||||
|
||||
|
||||
async def _create_reauth_flow(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
) -> None:
|
||||
hass.async_create_task(
|
||||
hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={CONF_SOURCE: SOURCE_REAUTH}, data=config_entry.data
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
|
||||
"""Set up Hyperion from a config entry."""
|
||||
host = config_entry.data[CONF_HOST]
|
||||
|
@ -92,8 +103,10 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
|||
token = config_entry.data.get(CONF_TOKEN)
|
||||
|
||||
hyperion_client = await async_create_connect_hyperion_client(
|
||||
host, port, token=token
|
||||
host, port, token=token, raw_connection=True
|
||||
)
|
||||
|
||||
# Client won't connect? => Not ready.
|
||||
if not hyperion_client:
|
||||
raise ConfigEntryNotReady
|
||||
version = await hyperion_client.async_sysinfo_version()
|
||||
|
@ -110,6 +123,31 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
|||
except ValueError:
|
||||
pass
|
||||
|
||||
# Client needs authentication, but no token provided? => Reauth.
|
||||
auth_resp = await hyperion_client.async_is_auth_required()
|
||||
if (
|
||||
auth_resp is not None
|
||||
and client.ResponseOK(auth_resp)
|
||||
and auth_resp.get(hyperion_const.KEY_INFO, {}).get(
|
||||
hyperion_const.KEY_REQUIRED, False
|
||||
)
|
||||
and token is None
|
||||
):
|
||||
await _create_reauth_flow(hass, config_entry)
|
||||
return False
|
||||
|
||||
# Client login doesn't work? => Reauth.
|
||||
if not await hyperion_client.async_client_login():
|
||||
await _create_reauth_flow(hass, config_entry)
|
||||
return False
|
||||
|
||||
# Cannot switch instance or cannot load state? => Not ready.
|
||||
if (
|
||||
not await hyperion_client.async_client_switch_instance()
|
||||
or not client.ServerInfoResponseOK(await hyperion_client.async_get_serverinfo())
|
||||
):
|
||||
raise ConfigEntryNotReady
|
||||
|
||||
hyperion_client.set_callbacks(
|
||||
{
|
||||
f"{hyperion_const.KEY_INSTANCE}-{hyperion_const.KEY_UPDATE}": lambda json: (
|
||||
|
@ -139,17 +177,17 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
|||
]
|
||||
)
|
||||
hass.data[DOMAIN][config_entry.entry_id][CONF_ON_UNLOAD].append(
|
||||
config_entry.add_update_listener(_async_options_updated)
|
||||
config_entry.add_update_listener(_async_entry_updated)
|
||||
)
|
||||
|
||||
hass.async_create_task(setup_then_listen())
|
||||
return True
|
||||
|
||||
|
||||
async def _async_options_updated(
|
||||
async def _async_entry_updated(
|
||||
hass: HomeAssistantType, config_entry: ConfigEntry
|
||||
) -> None:
|
||||
"""Handle options update."""
|
||||
"""Handle entry updates."""
|
||||
await hass.config_entries.async_reload(config_entry.entry_id)
|
||||
|
||||
|
||||
|
|
|
@ -12,11 +12,19 @@ import voluptuous as vol
|
|||
from homeassistant.components.ssdp import ATTR_SSDP_LOCATION, ATTR_UPNP_SERIAL
|
||||
from homeassistant.config_entries import (
|
||||
CONN_CLASS_LOCAL_PUSH,
|
||||
SOURCE_REAUTH,
|
||||
ConfigEntry,
|
||||
ConfigFlow,
|
||||
OptionsFlow,
|
||||
)
|
||||
from homeassistant.const import CONF_BASE, CONF_HOST, CONF_ID, CONF_PORT, CONF_TOKEN
|
||||
from homeassistant.const import (
|
||||
CONF_BASE,
|
||||
CONF_HOST,
|
||||
CONF_ID,
|
||||
CONF_PORT,
|
||||
CONF_SOURCE,
|
||||
CONF_TOKEN,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
|
@ -35,13 +43,13 @@ from .const import (
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
_LOGGER.setLevel(logging.DEBUG)
|
||||
|
||||
# +------------------+ +------------------+ +--------------------+
|
||||
# |Step: SSDP | |Step: user | |Step: import |
|
||||
# | | | | | |
|
||||
# |Input: <discovery>| |Input: <host/port>| |Input: <import data>|
|
||||
# +------------------+ +------------------+ +--------------------+
|
||||
# v v v
|
||||
# +----------------------+-----------------------+
|
||||
# +------------------+ +------------------+ +--------------------+ +--------------------+
|
||||
# |Step: SSDP | |Step: user | |Step: import | |Step: reauth |
|
||||
# | | | | | | | |
|
||||
# |Input: <discovery>| |Input: <host/port>| |Input: <import data>| |Input: <entry_data> |
|
||||
# +------------------+ +------------------+ +--------------------+ +--------------------+
|
||||
# v v v v
|
||||
# +-------------------+-----------------------+--------------------+
|
||||
# Auth not | Auth |
|
||||
# required? | required? |
|
||||
# | v
|
||||
|
@ -82,7 +90,7 @@ _LOGGER.setLevel(logging.DEBUG)
|
|||
# |
|
||||
# v
|
||||
# +----------------+
|
||||
# | Create! |
|
||||
# | Create/Update! |
|
||||
# +----------------+
|
||||
|
||||
# A note on choice of discovery mechanisms: Hyperion supports both Zeroconf and SSDP out
|
||||
|
@ -140,6 +148,17 @@ class HyperionConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
return self.async_abort(reason="cannot_connect")
|
||||
return await self._advance_to_auth_step_if_necessary(hyperion_client)
|
||||
|
||||
async def async_step_reauth(
|
||||
self,
|
||||
config_data: ConfigType,
|
||||
) -> Dict[str, Any]:
|
||||
"""Handle a reauthentication flow."""
|
||||
self._data = dict(config_data)
|
||||
async with self._create_client(raw_connection=True) as hyperion_client:
|
||||
if not hyperion_client:
|
||||
return self.async_abort(reason="cannot_connect")
|
||||
return await self._advance_to_auth_step_if_necessary(hyperion_client)
|
||||
|
||||
async def async_step_ssdp( # type: ignore[override]
|
||||
self, discovery_info: Dict[str, Any]
|
||||
) -> Dict[str, Any]:
|
||||
|
@ -401,7 +420,18 @@ class HyperionConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
if not hyperion_id:
|
||||
return self.async_abort(reason="no_id")
|
||||
|
||||
await self.async_set_unique_id(hyperion_id, raise_on_progress=False)
|
||||
entry = await self.async_set_unique_id(hyperion_id, raise_on_progress=False)
|
||||
|
||||
# pylint: disable=no-member
|
||||
if self.context.get(CONF_SOURCE) == SOURCE_REAUTH and entry is not None:
|
||||
assert self.hass
|
||||
self.hass.config_entries.async_update_entry(entry, data=self._data)
|
||||
# Need to manually reload, as the listener won't have been installed because
|
||||
# the initial load did not succeed (the reauth flow will not be initiated if
|
||||
# the load succeeds)
|
||||
await self.hass.config_entries.async_reload(entry.entry_id)
|
||||
return self.async_abort(reason="reauth_successful")
|
||||
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
|
||||
|
|
|
@ -16,8 +16,6 @@ CONF_ON_UNLOAD = "ON_UNLOAD"
|
|||
SIGNAL_INSTANCES_UPDATED = f"{DOMAIN}_instances_updated_signal." "{}"
|
||||
SIGNAL_INSTANCE_REMOVED = f"{DOMAIN}_instance_removed_signal." "{}"
|
||||
|
||||
SOURCE_IMPORT = "import"
|
||||
|
||||
HYPERION_VERSION_WARN_CUTOFF = "2.0.0-alpha.9"
|
||||
HYPERION_RELEASES_URL = "https://github.com/hyperion-project/hyperion.ng/releases"
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ from homeassistant.components.light import (
|
|||
SUPPORT_EFFECT,
|
||||
LightEntity,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT, CONF_TOKEN
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
|
@ -47,7 +47,6 @@ from .const import (
|
|||
DOMAIN,
|
||||
SIGNAL_INSTANCE_REMOVED,
|
||||
SIGNAL_INSTANCES_UPDATED,
|
||||
SOURCE_IMPORT,
|
||||
TYPE_HYPERION_LIGHT,
|
||||
)
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"auth_new_token_not_granted_error": "Newly created token was not approved on Hyperion UI",
|
||||
"auth_new_token_not_work_error": "Failed to authenticate using newly created token",
|
||||
"no_id": "The Hyperion Ambilight instance did not report its id"
|
||||
"no_id": "The Hyperion Ambilight instance did not report its id",
|
||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
|
|
|
@ -50,6 +50,20 @@ TEST_INSTANCE_3: Dict[str, Any] = {
|
|||
"running": True,
|
||||
}
|
||||
|
||||
TEST_AUTH_REQUIRED_RESP: Dict[str, Any] = {
|
||||
"command": "authorize-tokenRequired",
|
||||
"info": {
|
||||
"required": True,
|
||||
},
|
||||
"success": True,
|
||||
"tan": 1,
|
||||
}
|
||||
|
||||
TEST_AUTH_NOT_REQUIRED_RESP = {
|
||||
**TEST_AUTH_REQUIRED_RESP,
|
||||
"info": {"required": False},
|
||||
}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
@ -78,12 +92,7 @@ def create_mock_client() -> Mock:
|
|||
mock_client.async_client_connect = AsyncMock(return_value=True)
|
||||
mock_client.async_client_disconnect = AsyncMock(return_value=True)
|
||||
mock_client.async_is_auth_required = AsyncMock(
|
||||
return_value={
|
||||
"command": "authorize-tokenRequired",
|
||||
"info": {"required": False},
|
||||
"success": True,
|
||||
"tan": 1,
|
||||
}
|
||||
return_value=TEST_AUTH_NOT_REQUIRED_RESP
|
||||
)
|
||||
mock_client.async_login = AsyncMock(
|
||||
return_value={"command": "authorize-login", "success": True, "tan": 0}
|
||||
|
@ -91,6 +100,17 @@ def create_mock_client() -> Mock:
|
|||
|
||||
mock_client.async_sysinfo_id = AsyncMock(return_value=TEST_SYSINFO_ID)
|
||||
mock_client.async_sysinfo_version = AsyncMock(return_value=TEST_SYSINFO_ID)
|
||||
mock_client.async_client_switch_instance = AsyncMock(return_value=True)
|
||||
mock_client.async_client_login = AsyncMock(return_value=True)
|
||||
mock_client.async_get_serverinfo = AsyncMock(
|
||||
return_value={
|
||||
"command": "serverinfo",
|
||||
"success": True,
|
||||
"tan": 0,
|
||||
"info": {"fake": "data"},
|
||||
}
|
||||
)
|
||||
|
||||
mock_client.adjustment = None
|
||||
mock_client.effects = None
|
||||
mock_client.instances = [
|
||||
|
@ -100,12 +120,15 @@ def create_mock_client() -> Mock:
|
|||
return mock_client
|
||||
|
||||
|
||||
def add_test_config_entry(hass: HomeAssistantType) -> ConfigEntry:
|
||||
def add_test_config_entry(
|
||||
hass: HomeAssistantType, data: Optional[Dict[str, Any]] = None
|
||||
) -> ConfigEntry:
|
||||
"""Add a test config entry."""
|
||||
config_entry: MockConfigEntry = MockConfigEntry( # type: ignore[no-untyped-call]
|
||||
entry_id=TEST_CONFIG_ENTRY_ID,
|
||||
domain=DOMAIN,
|
||||
data={
|
||||
data=data
|
||||
or {
|
||||
CONF_HOST: TEST_HOST,
|
||||
CONF_PORT: TEST_PORT,
|
||||
},
|
||||
|
@ -118,10 +141,12 @@ def add_test_config_entry(hass: HomeAssistantType) -> ConfigEntry:
|
|||
|
||||
|
||||
async def setup_test_config_entry(
|
||||
hass: HomeAssistantType, hyperion_client: Optional[Mock] = None
|
||||
hass: HomeAssistantType,
|
||||
config_entry: Optional[ConfigEntry] = None,
|
||||
hyperion_client: Optional[Mock] = None,
|
||||
) -> ConfigEntry:
|
||||
"""Add a test Hyperion entity to hass."""
|
||||
config_entry = add_test_config_entry(hass)
|
||||
config_entry = config_entry or add_test_config_entry(hass)
|
||||
|
||||
hyperion_client = hyperion_client or create_mock_client()
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
|
|
|
@ -11,10 +11,14 @@ from homeassistant.components.hyperion.const import (
|
|||
CONF_CREATE_TOKEN,
|
||||
CONF_PRIORITY,
|
||||
DOMAIN,
|
||||
SOURCE_IMPORT,
|
||||
)
|
||||
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_SSDP, SOURCE_USER
|
||||
from homeassistant.config_entries import (
|
||||
SOURCE_IMPORT,
|
||||
SOURCE_REAUTH,
|
||||
SOURCE_SSDP,
|
||||
SOURCE_USER,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
CONF_HOST,
|
||||
|
@ -25,6 +29,7 @@ from homeassistant.const import (
|
|||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from . import (
|
||||
TEST_AUTH_REQUIRED_RESP,
|
||||
TEST_CONFIG_ENTRY_ID,
|
||||
TEST_ENTITY_ID_1,
|
||||
TEST_HOST,
|
||||
|
@ -49,15 +54,6 @@ TEST_HOST_PORT: Dict[str, Any] = {
|
|||
CONF_PORT: TEST_PORT,
|
||||
}
|
||||
|
||||
TEST_AUTH_REQUIRED_RESP = {
|
||||
"command": "authorize-tokenRequired",
|
||||
"info": {
|
||||
"required": True,
|
||||
},
|
||||
"success": True,
|
||||
"tan": 1,
|
||||
}
|
||||
|
||||
TEST_AUTH_ID = "ABCDE"
|
||||
TEST_REQUEST_TOKEN_SUCCESS = {
|
||||
"command": "authorize-requestToken",
|
||||
|
@ -694,3 +690,62 @@ async def test_options(hass: HomeAssistantType) -> None:
|
|||
blocking=True,
|
||||
)
|
||||
assert client.async_send_set_color.call_args[1][CONF_PRIORITY] == new_priority
|
||||
|
||||
|
||||
async def test_reauth_success(hass: HomeAssistantType) -> None:
|
||||
"""Check a reauth flow that succeeds."""
|
||||
|
||||
config_data = {
|
||||
CONF_HOST: TEST_HOST,
|
||||
CONF_PORT: TEST_PORT,
|
||||
}
|
||||
|
||||
config_entry = add_test_config_entry(hass, data=config_data)
|
||||
client = create_mock_client()
|
||||
client.async_is_auth_required = AsyncMock(return_value=TEST_AUTH_REQUIRED_RESP)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.hyperion.client.HyperionClient", return_value=client
|
||||
), patch("homeassistant.components.hyperion.async_setup", return_value=True), patch(
|
||||
"homeassistant.components.hyperion.async_setup_entry", return_value=True
|
||||
):
|
||||
result = await _init_flow(
|
||||
hass,
|
||||
source=SOURCE_REAUTH,
|
||||
data=config_data,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
|
||||
result = await _configure_flow(
|
||||
hass, result, user_input={CONF_CREATE_TOKEN: False, CONF_TOKEN: TEST_TOKEN}
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "reauth_successful"
|
||||
assert CONF_TOKEN in config_entry.data
|
||||
|
||||
|
||||
async def test_reauth_cannot_connect(hass: HomeAssistantType) -> None:
|
||||
"""Check a reauth flow that fails to connect."""
|
||||
|
||||
config_data = {
|
||||
CONF_HOST: TEST_HOST,
|
||||
CONF_PORT: TEST_PORT,
|
||||
}
|
||||
|
||||
add_test_config_entry(hass, data=config_data)
|
||||
client = create_mock_client()
|
||||
client.async_client_connect = AsyncMock(return_value=False)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.hyperion.client.HyperionClient", return_value=client
|
||||
):
|
||||
result = await _init_flow(
|
||||
hass,
|
||||
source=SOURCE_REAUTH,
|
||||
data=config_data,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "cannot_connect"
|
||||
|
|
|
@ -17,12 +17,26 @@ from homeassistant.components.light import (
|
|||
ATTR_HS_COLOR,
|
||||
DOMAIN as LIGHT_DOMAIN,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON
|
||||
from homeassistant.config_entries import (
|
||||
ENTRY_STATE_SETUP_ERROR,
|
||||
SOURCE_REAUTH,
|
||||
ConfigEntry,
|
||||
)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID,
|
||||
CONF_HOST,
|
||||
CONF_PORT,
|
||||
CONF_SOURCE,
|
||||
CONF_TOKEN,
|
||||
SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON,
|
||||
)
|
||||
from homeassistant.helpers.entity_registry import async_get_registry
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
|
||||
from . import (
|
||||
TEST_AUTH_NOT_REQUIRED_RESP,
|
||||
TEST_AUTH_REQUIRED_RESP,
|
||||
TEST_CONFIG_ENTRY_OPTIONS,
|
||||
TEST_ENTITY_ID_1,
|
||||
TEST_ENTITY_ID_2,
|
||||
|
@ -206,7 +220,9 @@ async def test_setup_config_entry(hass: HomeAssistantType) -> None:
|
|||
assert hass.states.get(TEST_ENTITY_ID_1) is not None
|
||||
|
||||
|
||||
async def test_setup_config_entry_not_ready(hass: HomeAssistantType) -> None:
|
||||
async def test_setup_config_entry_not_ready_connect_fail(
|
||||
hass: HomeAssistantType,
|
||||
) -> None:
|
||||
"""Test the component not being ready."""
|
||||
client = create_mock_client()
|
||||
client.async_client_connect = AsyncMock(return_value=False)
|
||||
|
@ -214,6 +230,32 @@ async def test_setup_config_entry_not_ready(hass: HomeAssistantType) -> None:
|
|||
assert hass.states.get(TEST_ENTITY_ID_1) is None
|
||||
|
||||
|
||||
async def test_setup_config_entry_not_ready_switch_instance_fail(
|
||||
hass: HomeAssistantType,
|
||||
) -> None:
|
||||
"""Test the component not being ready."""
|
||||
client = create_mock_client()
|
||||
client.async_client_switch_instance = AsyncMock(return_value=False)
|
||||
await setup_test_config_entry(hass, hyperion_client=client)
|
||||
assert hass.states.get(TEST_ENTITY_ID_1) is None
|
||||
|
||||
|
||||
async def test_setup_config_entry_not_ready_load_state_fail(
|
||||
hass: HomeAssistantType,
|
||||
) -> None:
|
||||
"""Test the component not being ready."""
|
||||
client = create_mock_client()
|
||||
client.async_get_serverinfo = AsyncMock(
|
||||
return_value={
|
||||
"command": "serverinfo",
|
||||
"success": False,
|
||||
}
|
||||
)
|
||||
|
||||
await setup_test_config_entry(hass, hyperion_client=client)
|
||||
assert hass.states.get(TEST_ENTITY_ID_1) is None
|
||||
|
||||
|
||||
async def test_setup_config_entry_dynamic_instances(hass: HomeAssistantType) -> None:
|
||||
"""Test dynamic changes in the omstamce configuration."""
|
||||
config_entry = add_test_config_entry(hass)
|
||||
|
@ -724,7 +766,7 @@ async def test_unload_entry(hass: HomeAssistantType) -> None:
|
|||
client = create_mock_client()
|
||||
await setup_test_config_entry(hass, hyperion_client=client)
|
||||
assert hass.states.get(TEST_ENTITY_ID_1) is not None
|
||||
assert client.async_client_connect.called
|
||||
assert client.async_client_connect.call_count == 2
|
||||
assert not client.async_client_disconnect.called
|
||||
entry = _get_config_entry_from_unique_id(hass, TEST_SYSINFO_ID)
|
||||
assert entry
|
||||
|
@ -749,3 +791,44 @@ async def test_version_no_log_warning(caplog, hass: HomeAssistantType) -> None:
|
|||
await setup_test_config_entry(hass, hyperion_client=client)
|
||||
assert hass.states.get(TEST_ENTITY_ID_1) is not None
|
||||
assert "Please consider upgrading" not in caplog.text
|
||||
|
||||
|
||||
async def test_setup_entry_no_token_reauth(hass: HomeAssistantType) -> None:
|
||||
"""Verify a reauth flow when auth is required but no token provided."""
|
||||
client = create_mock_client()
|
||||
config_entry = add_test_config_entry(hass)
|
||||
client.async_is_auth_required = AsyncMock(return_value=TEST_AUTH_REQUIRED_RESP)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.hyperion.client.HyperionClient", return_value=client
|
||||
), patch.object(hass.config_entries.flow, "async_init") as mock_flow_init:
|
||||
assert not await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
mock_flow_init.assert_called_once_with(
|
||||
DOMAIN,
|
||||
context={CONF_SOURCE: SOURCE_REAUTH},
|
||||
data=config_entry.data,
|
||||
)
|
||||
assert config_entry.state == ENTRY_STATE_SETUP_ERROR
|
||||
|
||||
|
||||
async def test_setup_entry_bad_token_reauth(hass: HomeAssistantType) -> None:
|
||||
"""Verify a reauth flow when a bad token is provided."""
|
||||
client = create_mock_client()
|
||||
config_entry = add_test_config_entry(
|
||||
hass,
|
||||
data={CONF_HOST: TEST_HOST, CONF_PORT: TEST_PORT, CONF_TOKEN: "expired_token"},
|
||||
)
|
||||
client.async_is_auth_required = AsyncMock(return_value=TEST_AUTH_NOT_REQUIRED_RESP)
|
||||
|
||||
# Fail to log in.
|
||||
client.async_client_login = AsyncMock(return_value=False)
|
||||
with patch(
|
||||
"homeassistant.components.hyperion.client.HyperionClient", return_value=client
|
||||
), patch.object(hass.config_entries.flow, "async_init") as mock_flow_init:
|
||||
assert not await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
mock_flow_init.assert_called_once_with(
|
||||
DOMAIN,
|
||||
context={CONF_SOURCE: SOURCE_REAUTH},
|
||||
data=config_entry.data,
|
||||
)
|
||||
assert config_entry.state == ENTRY_STATE_SETUP_ERROR
|
||||
|
|
Loading…
Add table
Reference in a new issue