core/tests/components/elmax/test_config_flow.py

405 lines
14 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, data_entry_flow
from homeassistant.components.elmax.const import (
CONF_ELMAX_PANEL_ID,
CONF_ELMAX_PANEL_NAME,
CONF_ELMAX_PANEL_PIN,
CONF_ELMAX_PASSWORD,
CONF_ELMAX_USERNAME,
DOMAIN,
)
from homeassistant.config_entries import SOURCE_REAUTH
from tests.common import MockConfigEntry
from tests.components.elmax import (
MOCK_PANEL_ID,
MOCK_PANEL_NAME,
MOCK_PANEL_PIN,
MOCK_PASSWORD,
MOCK_USERNAME,
)
CONF_POLLING = "polling"
async def test_show_form(hass):
"""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"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"
async def test_standard_setup(hass):
"""Test the standard 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,
):
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"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
async def test_one_config_allowed(hass):
"""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}
)
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["type"] == data_entry_flow.RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"
async def test_invalid_credentials(hass):
"""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}
)
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"] == "user"
assert login_result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert login_result["errors"] == {"base": "invalid_auth"}
async def test_connection_error(hass):
"""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}
)
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"] == "user"
assert login_result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert login_result["errors"] == {"base": "network_error"}
async def test_unhandled_error(hass):
"""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}
)
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"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "unknown"}
async def test_invalid_pin(hass):
"""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}
)
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"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "invalid_pin"}
async def test_no_online_panel(hass):
"""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}
)
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"] == "user"
assert login_result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert login_result["errors"] == {"base": "no_panel_online"}
async def test_show_reauth(hass):
"""Test that the reauth form shows."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_REAUTH},
data={
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
CONF_ELMAX_USERNAME: MOCK_USERNAME,
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
},
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "reauth_confirm"
async def test_reauth_flow(hass):
"""Test that the reauth flow works."""
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)
# Trigger reauth
with patch(
"homeassistant.components.elmax.async_setup_entry",
return_value=True,
):
reauth_result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_REAUTH},
data={
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
CONF_ELMAX_USERNAME: MOCK_USERNAME,
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
},
)
result = await hass.config_entries.flow.async_configure(
reauth_result["flow_id"],
{
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
CONF_ELMAX_USERNAME: MOCK_USERNAME,
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
},
)
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
await hass.async_block_till_done()
assert result["reason"] == "reauth_successful"
async def test_reauth_panel_disappeared(hass):
"""Test that the case where panel is no longer associated with the user."""
# Simulate a first setup
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)
# Trigger reauth
with patch(
"elmax_api.http.Elmax.list_control_panels",
return_value=[],
):
reauth_result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_REAUTH},
data={
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
CONF_ELMAX_USERNAME: MOCK_USERNAME,
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
},
)
result = await hass.config_entries.flow.async_configure(
reauth_result["flow_id"],
{
CONF_ELMAX_PANEL_ID: MOCK_PANEL_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"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "reauth_panel_disappeared"}
async def test_reauth_invalid_pin(hass):
"""Test that the case where panel is no longer associated with the user."""
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)
# Trigger reauth
with patch(
"elmax_api.http.Elmax.get_panel_status",
side_effect=ElmaxBadPinError(),
):
reauth_result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_REAUTH},
data={
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
CONF_ELMAX_USERNAME: MOCK_USERNAME,
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
},
)
result = await hass.config_entries.flow.async_configure(
reauth_result["flow_id"],
{
CONF_ELMAX_PANEL_ID: MOCK_PANEL_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"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "invalid_pin"}
async def test_reauth_bad_login(hass):
"""Test bad login attempt at reauth time."""
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)
# Trigger reauth
with patch(
"elmax_api.http.Elmax.login",
side_effect=ElmaxBadLoginError(),
):
reauth_result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_REAUTH},
data={
CONF_ELMAX_PANEL_ID: MOCK_PANEL_ID,
CONF_ELMAX_PANEL_PIN: MOCK_PANEL_PIN,
CONF_ELMAX_USERNAME: MOCK_USERNAME,
CONF_ELMAX_PASSWORD: MOCK_PASSWORD,
},
)
result = await hass.config_entries.flow.async_configure(
reauth_result["flow_id"],
{
CONF_ELMAX_PANEL_ID: MOCK_PANEL_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"] == data_entry_flow.RESULT_TYPE_FORM
assert result["errors"] == {"base": "invalid_auth"}