269 lines
8.4 KiB
Python
269 lines
8.4 KiB
Python
"""Tests for the Abode 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 homeassistant.data_entry_flow import FlowResult
|
|
|
|
from tests.components.elmax import (
|
|
MOCK_PANEL_ID,
|
|
MOCK_PANEL_NAME,
|
|
MOCK_PANEL_PIN,
|
|
MOCK_PASSWORD,
|
|
MOCK_USERNAME,
|
|
)
|
|
|
|
CONF_POLLING = "polling"
|
|
|
|
|
|
def _has_error(errors):
|
|
return errors is not None and len(errors.keys()) > 0
|
|
|
|
|
|
async def _bootstrap(
|
|
hass,
|
|
source=config_entries.SOURCE_USER,
|
|
username=MOCK_USERNAME,
|
|
password=MOCK_PASSWORD,
|
|
panel_name=MOCK_PANEL_NAME,
|
|
panel_pin=MOCK_PANEL_PIN,
|
|
) -> FlowResult:
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": source}
|
|
)
|
|
if result["type"] != data_entry_flow.RESULT_TYPE_FORM or _has_error(
|
|
result["errors"]
|
|
):
|
|
return result
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{
|
|
CONF_ELMAX_USERNAME: username,
|
|
CONF_ELMAX_PASSWORD: password,
|
|
},
|
|
)
|
|
if result2["type"] != data_entry_flow.RESULT_TYPE_FORM or _has_error(
|
|
result2["errors"]
|
|
):
|
|
return result2
|
|
result3 = await hass.config_entries.flow.async_configure(
|
|
result2["flow_id"],
|
|
{
|
|
CONF_ELMAX_PANEL_NAME: panel_name,
|
|
CONF_ELMAX_PANEL_PIN: panel_pin,
|
|
},
|
|
)
|
|
return result3
|
|
|
|
|
|
async def _reauth(hass):
|
|
|
|
# Trigger reauth
|
|
result2 = 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,
|
|
},
|
|
)
|
|
if result2["type"] != data_entry_flow.RESULT_TYPE_FORM or _has_error(
|
|
result2["errors"]
|
|
):
|
|
return result2
|
|
|
|
# Perform reauth confirm step
|
|
result3 = await hass.config_entries.flow.async_configure(
|
|
result2["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,
|
|
},
|
|
)
|
|
return result3
|
|
|
|
|
|
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_one_config_allowed(hass):
|
|
"""Test that only one Elmax configuration is allowed for each panel."""
|
|
# Setup once.
|
|
attempt1 = await _bootstrap(hass)
|
|
assert attempt1["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
|
|
|
# Attempt to add another instance of the integration for the very same panel, it must fail.
|
|
attempt2 = await _bootstrap(hass)
|
|
assert attempt2["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
|
assert attempt2["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(),
|
|
):
|
|
result = await _bootstrap(
|
|
hass, username="wrong_user_name@email.com", password="incorrect_password"
|
|
)
|
|
assert result["step_id"] == "user"
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
assert result["errors"] == {"base": "bad_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(),
|
|
):
|
|
result = await _bootstrap(
|
|
hass, username="wrong_user_name@email.com", password="incorrect_password"
|
|
)
|
|
assert result["step_id"] == "user"
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
assert 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(),
|
|
):
|
|
result = await _bootstrap(hass)
|
|
assert result["step_id"] == "panels"
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
assert result["errors"] == {"base": "unknown_error"}
|
|
|
|
|
|
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(),
|
|
):
|
|
result = await _bootstrap(hass)
|
|
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=[],
|
|
):
|
|
result = await _bootstrap(hass)
|
|
assert result["step_id"] == "user"
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
assert result["errors"] == {"base": "no_panel_online"}
|
|
|
|
|
|
async def test_step_user(hass):
|
|
"""Test that the user step works."""
|
|
result = await _bootstrap(hass)
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
|
assert result["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,
|
|
}
|
|
|
|
|
|
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."""
|
|
# Simulate a first setup
|
|
await _bootstrap(hass)
|
|
# Trigger reauth
|
|
result = await _reauth(hass)
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
|
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
|
|
await _bootstrap(hass)
|
|
# Trigger reauth
|
|
with patch(
|
|
"elmax_api.http.Elmax.list_control_panels",
|
|
return_value=[],
|
|
):
|
|
result = await _reauth(hass)
|
|
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."""
|
|
# Simulate a first setup
|
|
await _bootstrap(hass)
|
|
# Trigger reauth
|
|
with patch(
|
|
"elmax_api.http.Elmax.get_panel_status",
|
|
side_effect=ElmaxBadPinError(),
|
|
):
|
|
result = await _reauth(hass)
|
|
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."""
|
|
# Simulate a first setup
|
|
await _bootstrap(hass)
|
|
# Trigger reauth
|
|
with patch(
|
|
"elmax_api.http.Elmax.login",
|
|
side_effect=ElmaxBadLoginError(),
|
|
):
|
|
result = await _reauth(hass)
|
|
assert result["step_id"] == "reauth_confirm"
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
assert result["errors"] == {"base": "bad_auth"}
|