mirror of https://github.com/home-assistant/core
682 lines
24 KiB
Python
682 lines
24 KiB
Python
"""Tests for the Elmax config flow."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
from elmax_api.exceptions import ElmaxBadLoginError, ElmaxBadPinError, ElmaxNetworkError
|
|
|
|
from homeassistant import config_entries
|
|
from homeassistant.components import zeroconf
|
|
from homeassistant.components.elmax.const import (
|
|
CONF_ELMAX_MODE,
|
|
CONF_ELMAX_MODE_CLOUD,
|
|
CONF_ELMAX_MODE_DIRECT,
|
|
CONF_ELMAX_MODE_DIRECT_HOST,
|
|
CONF_ELMAX_MODE_DIRECT_PORT,
|
|
CONF_ELMAX_MODE_DIRECT_SSL,
|
|
CONF_ELMAX_MODE_DIRECT_SSL_CERT,
|
|
CONF_ELMAX_PANEL_ID,
|
|
CONF_ELMAX_PANEL_NAME,
|
|
CONF_ELMAX_PANEL_PIN,
|
|
CONF_ELMAX_PASSWORD,
|
|
CONF_ELMAX_USERNAME,
|
|
DOMAIN,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.data_entry_flow import FlowResultType
|
|
|
|
from . import (
|
|
MOCK_DIRECT_CERT,
|
|
MOCK_DIRECT_HOST,
|
|
MOCK_DIRECT_HOST_CHANGED,
|
|
MOCK_DIRECT_PORT,
|
|
MOCK_DIRECT_SSL,
|
|
MOCK_PANEL_ID,
|
|
MOCK_PANEL_NAME,
|
|
MOCK_PANEL_PIN,
|
|
MOCK_PASSWORD,
|
|
MOCK_USERNAME,
|
|
MOCK_WRONG_PANEL_PIN,
|
|
)
|
|
|
|
from tests.common import MockConfigEntry
|
|
|
|
MOCK_ZEROCONF_DISCOVERY_INFO = zeroconf.ZeroconfServiceInfo(
|
|
ip_address=MOCK_DIRECT_HOST,
|
|
ip_addresses=[MOCK_DIRECT_HOST],
|
|
hostname="VideoBox.local",
|
|
name="VideoBox",
|
|
port=443,
|
|
properties={
|
|
"idl": MOCK_PANEL_ID,
|
|
"idr": MOCK_PANEL_ID,
|
|
"v1": "PHANTOM64PRO_GSM 11.9.844",
|
|
"v2": "4.9.13",
|
|
},
|
|
type="_elmax-ssl._tcp",
|
|
)
|
|
MOCK_ZEROCONF_DISCOVERY_CHANGED_INFO = zeroconf.ZeroconfServiceInfo(
|
|
ip_address=MOCK_DIRECT_HOST_CHANGED,
|
|
ip_addresses=[MOCK_DIRECT_HOST_CHANGED],
|
|
hostname="VideoBox.local",
|
|
name="VideoBox",
|
|
port=443,
|
|
properties={
|
|
"idl": MOCK_PANEL_ID,
|
|
"idr": MOCK_PANEL_ID,
|
|
"v1": "PHANTOM64PRO_GSM 11.9.844",
|
|
"v2": "4.9.13",
|
|
},
|
|
type="_elmax-ssl._tcp",
|
|
)
|
|
MOCK_ZEROCONF_DISCOVERY_INFO_NOT_SUPPORTED = zeroconf.ZeroconfServiceInfo(
|
|
ip_address=MOCK_DIRECT_HOST,
|
|
ip_addresses=[MOCK_DIRECT_HOST],
|
|
hostname="VideoBox.local",
|
|
name="VideoBox",
|
|
port=443,
|
|
properties={
|
|
"idl": MOCK_PANEL_ID,
|
|
"idr": MOCK_PANEL_ID,
|
|
"v1": "PHANTOM64PRO_GSM 11.9.844",
|
|
},
|
|
type="_elmax-ssl._tcp",
|
|
)
|
|
CONF_POLLING = "polling"
|
|
|
|
|
|
async def test_show_menu(hass: HomeAssistant) -> None:
|
|
"""Test that the form is served with no input."""
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
assert result["type"] is FlowResultType.MENU
|
|
assert result["step_id"] == "choose_mode"
|
|
|
|
|
|
async def test_direct_setup(hass: HomeAssistant) -> None:
|
|
"""Test the standard direct setup case."""
|
|
show_form_result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
with patch(
|
|
"homeassistant.components.elmax.async_setup_entry",
|
|
return_value=True,
|
|
):
|
|
set_mode_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{"next_step_id": CONF_ELMAX_MODE_DIRECT},
|
|
)
|
|
result = await hass.config_entries.flow.async_configure(
|
|
set_mode_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_MODE_DIRECT_HOST: MOCK_DIRECT_HOST,
|
|
CONF_ELMAX_MODE_DIRECT_PORT: MOCK_DIRECT_PORT,
|
|
CONF_ELMAX_MODE_DIRECT_SSL: MOCK_DIRECT_SSL,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
|
|
|
|
|
async def test_direct_show_form(hass: HomeAssistant) -> None:
|
|
"""Test the standard direct show form case."""
|
|
show_form_result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
with patch(
|
|
"homeassistant.components.elmax.async_setup_entry",
|
|
return_value=True,
|
|
):
|
|
set_mode_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
)
|
|
result = await hass.config_entries.flow.async_configure(
|
|
set_mode_result["flow_id"], {"next_step_id": CONF_ELMAX_MODE_DIRECT}
|
|
)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == CONF_ELMAX_MODE_DIRECT
|
|
assert result["errors"] is None
|
|
|
|
|
|
async def test_cloud_setup(hass: HomeAssistant) -> None:
|
|
"""Test the standard cloud setup case."""
|
|
# Setup once.
|
|
show_form_result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
with patch(
|
|
"homeassistant.components.elmax.async_setup_entry",
|
|
return_value=True,
|
|
):
|
|
show_form_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{"next_step_id": CONF_ELMAX_MODE_CLOUD},
|
|
)
|
|
login_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
},
|
|
)
|
|
result = await hass.config_entries.flow.async_configure(
|
|
login_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_PANEL_NAME: MOCK_PANEL_NAME,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
|
|
|
|
|
async def test_zeroconf_form_setup_api_not_supported(hass: HomeAssistant) -> None:
|
|
"""Test the zeroconf setup case."""
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN,
|
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
|
data=MOCK_ZEROCONF_DISCOVERY_INFO_NOT_SUPPORTED,
|
|
)
|
|
assert result["type"] is FlowResultType.ABORT
|
|
assert result["reason"] == "not_supported"
|
|
|
|
|
|
async def test_zeroconf_discovery(hass: HomeAssistant) -> None:
|
|
"""Test discovery of Elmax local api panel."""
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN,
|
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
|
data=MOCK_ZEROCONF_DISCOVERY_INFO,
|
|
)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == "zeroconf_setup"
|
|
assert result["errors"] is None
|
|
|
|
|
|
async def test_zeroconf_setup_show_form(hass: HomeAssistant) -> None:
|
|
"""Test discovery shows a form when activated."""
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN,
|
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
|
data=MOCK_ZEROCONF_DISCOVERY_INFO,
|
|
)
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
)
|
|
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == "zeroconf_setup"
|
|
|
|
|
|
async def test_zeroconf_setup(hass: HomeAssistant) -> None:
|
|
"""Test the successful creation of config entry via discovery flow."""
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN,
|
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
|
data=MOCK_ZEROCONF_DISCOVERY_INFO,
|
|
)
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
CONF_ELMAX_MODE_DIRECT_SSL: MOCK_DIRECT_SSL,
|
|
},
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
|
|
|
|
|
async def test_zeroconf_already_configured(hass: HomeAssistant) -> None:
|
|
"""Ensure local discovery aborts when same panel is already added to ha."""
|
|
MockConfigEntry(
|
|
domain=DOMAIN,
|
|
title=f"Elmax Direct ({MOCK_PANEL_ID})",
|
|
data={
|
|
CONF_ELMAX_MODE: CONF_ELMAX_MODE_DIRECT,
|
|
CONF_ELMAX_MODE_DIRECT_HOST: MOCK_DIRECT_HOST,
|
|
CONF_ELMAX_MODE_DIRECT_PORT: MOCK_DIRECT_PORT,
|
|
CONF_ELMAX_MODE_DIRECT_SSL: MOCK_DIRECT_SSL,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
|
|
CONF_ELMAX_MODE_DIRECT_SSL_CERT: MOCK_DIRECT_CERT,
|
|
},
|
|
unique_id=MOCK_PANEL_ID,
|
|
).add_to_hass(hass)
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN,
|
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
|
data=MOCK_ZEROCONF_DISCOVERY_INFO,
|
|
)
|
|
assert result["type"] is FlowResultType.ABORT
|
|
assert result["reason"] == "already_configured"
|
|
|
|
|
|
async def test_zeroconf_panel_changed_ip(hass: HomeAssistant) -> None:
|
|
"""Ensure local discovery updates the panel data when a the panel changes its IP."""
|
|
# Simulate an entry already exists for ip MOCK_DIRECT_HOST.
|
|
config_entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
title=f"Elmax Direct ({MOCK_PANEL_ID})",
|
|
data={
|
|
CONF_ELMAX_MODE: CONF_ELMAX_MODE_DIRECT,
|
|
CONF_ELMAX_MODE_DIRECT_HOST: MOCK_DIRECT_HOST,
|
|
CONF_ELMAX_MODE_DIRECT_PORT: MOCK_DIRECT_PORT,
|
|
CONF_ELMAX_MODE_DIRECT_SSL: MOCK_DIRECT_SSL,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
|
|
CONF_ELMAX_MODE_DIRECT_SSL_CERT: MOCK_DIRECT_CERT,
|
|
},
|
|
unique_id=MOCK_PANEL_ID,
|
|
)
|
|
config_entry.add_to_hass(hass)
|
|
|
|
# Simulate a MDNS discovery finds the same panel with a different IP (MOCK_ZEROCONF_DISCOVERY_CHANGED_INFO).
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN,
|
|
context={"source": config_entries.SOURCE_ZEROCONF},
|
|
data=MOCK_ZEROCONF_DISCOVERY_CHANGED_INFO,
|
|
)
|
|
|
|
# Expect we abort the configuration as "already configured"
|
|
assert result["type"] is FlowResultType.ABORT
|
|
assert result["reason"] == "already_configured"
|
|
|
|
# Expect the panel ip has been updated.
|
|
assert (
|
|
hass.config_entries.async_get_entry(config_entry.entry_id).data[
|
|
CONF_ELMAX_MODE_DIRECT_HOST
|
|
]
|
|
== MOCK_ZEROCONF_DISCOVERY_CHANGED_INFO.host
|
|
)
|
|
|
|
|
|
async def test_one_config_allowed_cloud(hass: HomeAssistant) -> None:
|
|
"""Test that only one Elmax configuration is allowed for each panel."""
|
|
MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
},
|
|
unique_id=MOCK_PANEL_ID,
|
|
).add_to_hass(hass)
|
|
|
|
# Attempt to add another instance of the integration for the very same panel, it must fail.
|
|
show_form_result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
user_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{"next_step_id": CONF_ELMAX_MODE_CLOUD},
|
|
)
|
|
login_result = await hass.config_entries.flow.async_configure(
|
|
user_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
},
|
|
)
|
|
result = await hass.config_entries.flow.async_configure(
|
|
login_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_PANEL_NAME: MOCK_PANEL_NAME,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
},
|
|
)
|
|
assert result["type"] is FlowResultType.ABORT
|
|
assert result["reason"] == "already_configured"
|
|
|
|
|
|
async def test_cloud_invalid_credentials(hass: HomeAssistant) -> None:
|
|
"""Test that invalid credentials throws an error."""
|
|
with patch(
|
|
"elmax_api.http.Elmax.login",
|
|
side_effect=ElmaxBadLoginError(),
|
|
):
|
|
show_form_result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
show_form_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{"next_step_id": CONF_ELMAX_MODE_CLOUD},
|
|
)
|
|
login_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_USERNAME: "wrong_user_name@email.com",
|
|
CONF_ELMAX_PASSWORD: "incorrect_password",
|
|
},
|
|
)
|
|
assert login_result["step_id"] == CONF_ELMAX_MODE_CLOUD
|
|
assert login_result["type"] is FlowResultType.FORM
|
|
assert login_result["errors"] == {"base": "invalid_auth"}
|
|
|
|
|
|
async def test_cloud_connection_error(hass: HomeAssistant) -> None:
|
|
"""Test other than invalid credentials throws an error."""
|
|
with patch(
|
|
"elmax_api.http.Elmax.login",
|
|
side_effect=ElmaxNetworkError(),
|
|
):
|
|
show_form_result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
show_form_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{"next_step_id": CONF_ELMAX_MODE_CLOUD},
|
|
)
|
|
login_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
},
|
|
)
|
|
assert login_result["step_id"] == CONF_ELMAX_MODE_CLOUD
|
|
assert login_result["type"] is FlowResultType.FORM
|
|
assert login_result["errors"] == {"base": "network_error"}
|
|
|
|
|
|
async def test_direct_connection_error(hass: HomeAssistant) -> None:
|
|
"""Test network error while dealing with direct panel APIs."""
|
|
with patch(
|
|
"elmax_api.http.ElmaxLocal.login",
|
|
side_effect=ElmaxNetworkError(),
|
|
):
|
|
show_form_result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
set_mode_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{"next_step_id": CONF_ELMAX_MODE_DIRECT},
|
|
)
|
|
result = await hass.config_entries.flow.async_configure(
|
|
set_mode_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_MODE_DIRECT_HOST: MOCK_DIRECT_HOST,
|
|
CONF_ELMAX_MODE_DIRECT_PORT: MOCK_DIRECT_PORT,
|
|
CONF_ELMAX_MODE_DIRECT_SSL: MOCK_DIRECT_SSL,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
},
|
|
)
|
|
assert result["step_id"] == CONF_ELMAX_MODE_DIRECT
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] == {"base": "network_error"}
|
|
|
|
|
|
async def test_direct_wrong_panel_code(hass: HomeAssistant) -> None:
|
|
"""Test wrong code being specified while dealing with direct panel APIs."""
|
|
with patch(
|
|
"elmax_api.http.ElmaxLocal.login",
|
|
side_effect=ElmaxBadLoginError(),
|
|
):
|
|
show_form_result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
set_mode_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{"next_step_id": CONF_ELMAX_MODE_DIRECT},
|
|
)
|
|
result = await hass.config_entries.flow.async_configure(
|
|
set_mode_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_MODE_DIRECT_HOST: MOCK_DIRECT_HOST,
|
|
CONF_ELMAX_MODE_DIRECT_PORT: MOCK_DIRECT_PORT,
|
|
CONF_ELMAX_MODE_DIRECT_SSL: MOCK_DIRECT_SSL,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_WRONG_PANEL_PIN,
|
|
},
|
|
)
|
|
assert result["step_id"] == CONF_ELMAX_MODE_DIRECT
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] == {"base": "invalid_auth"}
|
|
|
|
|
|
async def test_unhandled_error(hass: HomeAssistant) -> None:
|
|
"""Test unhandled exceptions."""
|
|
with patch(
|
|
"elmax_api.http.Elmax.get_panel_status",
|
|
side_effect=Exception(),
|
|
):
|
|
show_form_result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
show_form_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{"next_step_id": CONF_ELMAX_MODE_CLOUD},
|
|
)
|
|
login_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
},
|
|
)
|
|
result = await hass.config_entries.flow.async_configure(
|
|
login_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_PANEL_NAME: MOCK_PANEL_NAME,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
},
|
|
)
|
|
assert result["step_id"] == "panels"
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] == {"base": "unknown"}
|
|
|
|
|
|
async def test_invalid_pin(hass: HomeAssistant) -> None:
|
|
"""Test error is thrown when a wrong pin is used to pair a panel."""
|
|
# Simulate bad pin response.
|
|
with patch(
|
|
"elmax_api.http.Elmax.get_panel_status",
|
|
side_effect=ElmaxBadPinError(),
|
|
):
|
|
show_form_result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
show_form_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{"next_step_id": CONF_ELMAX_MODE_CLOUD},
|
|
)
|
|
login_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
},
|
|
)
|
|
result = await hass.config_entries.flow.async_configure(
|
|
login_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_PANEL_NAME: MOCK_PANEL_NAME,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
},
|
|
)
|
|
assert result["step_id"] == "panels"
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] == {"base": "invalid_pin"}
|
|
|
|
|
|
async def test_no_online_panel(hass: HomeAssistant) -> None:
|
|
"""Test no-online panel is available."""
|
|
# Simulate low-level api returns no panels.
|
|
with patch(
|
|
"elmax_api.http.Elmax.list_control_panels",
|
|
return_value=[],
|
|
):
|
|
show_form_result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
show_form_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{"next_step_id": CONF_ELMAX_MODE_CLOUD},
|
|
)
|
|
login_result = await hass.config_entries.flow.async_configure(
|
|
show_form_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
},
|
|
)
|
|
assert login_result["step_id"] == CONF_ELMAX_MODE_CLOUD
|
|
assert login_result["type"] is FlowResultType.FORM
|
|
assert login_result["errors"] == {"base": "no_panel_online"}
|
|
|
|
|
|
async def test_show_reauth(hass: HomeAssistant) -> None:
|
|
"""Test that the reauth form shows."""
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
},
|
|
unique_id=MOCK_PANEL_ID,
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
result = await entry.start_reauth_flow(hass)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == "reauth_confirm"
|
|
|
|
|
|
async def test_reauth_flow(hass: HomeAssistant) -> None:
|
|
"""Test that the reauth flow works."""
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
},
|
|
unique_id=MOCK_PANEL_ID,
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
# Trigger reauth
|
|
reauth_result = await entry.start_reauth_flow(hass)
|
|
with patch(
|
|
"homeassistant.components.elmax.async_setup_entry",
|
|
return_value=True,
|
|
):
|
|
result = await hass.config_entries.flow.async_configure(
|
|
reauth_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
},
|
|
)
|
|
assert result["type"] is FlowResultType.ABORT
|
|
await hass.async_block_till_done()
|
|
assert result["reason"] == "reauth_successful"
|
|
|
|
|
|
async def test_reauth_panel_disappeared(hass: HomeAssistant) -> None:
|
|
"""Test that the case where panel is no longer associated with the user."""
|
|
# Simulate a first setup
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
},
|
|
unique_id=MOCK_PANEL_ID,
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
# Trigger reauth
|
|
reauth_result = await entry.start_reauth_flow(hass)
|
|
with patch(
|
|
"elmax_api.http.Elmax.list_control_panels",
|
|
return_value=[],
|
|
):
|
|
result = await hass.config_entries.flow.async_configure(
|
|
reauth_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
},
|
|
)
|
|
assert result["step_id"] == "reauth_confirm"
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] == {"base": "reauth_panel_disappeared"}
|
|
|
|
|
|
async def test_reauth_invalid_pin(hass: HomeAssistant) -> None:
|
|
"""Test that the case where panel is no longer associated with the user."""
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
},
|
|
unique_id=MOCK_PANEL_ID,
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
# Trigger reauth
|
|
reauth_result = await entry.start_reauth_flow(hass)
|
|
with patch(
|
|
"elmax_api.http.Elmax.get_panel_status",
|
|
side_effect=ElmaxBadPinError(),
|
|
):
|
|
result = await hass.config_entries.flow.async_configure(
|
|
reauth_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
},
|
|
)
|
|
assert result["step_id"] == "reauth_confirm"
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] == {"base": "invalid_pin"}
|
|
|
|
|
|
async def test_reauth_bad_login(hass: HomeAssistant) -> None:
|
|
"""Test bad login attempt at reauth time."""
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
},
|
|
unique_id=MOCK_PANEL_ID,
|
|
)
|
|
entry.add_to_hass(hass)
|
|
|
|
# Trigger reauth
|
|
reauth_result = await entry.start_reauth_flow(hass)
|
|
with patch(
|
|
"elmax_api.http.Elmax.login",
|
|
side_effect=ElmaxBadLoginError(),
|
|
):
|
|
result = await hass.config_entries.flow.async_configure(
|
|
reauth_result["flow_id"],
|
|
{
|
|
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
|
|
CONF_ELMAX_USERNAME: MOCK_USERNAME,
|
|
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
|
|
},
|
|
)
|
|
assert result["step_id"] == "reauth_confirm"
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] == {"base": "invalid_auth"}
|