mirror of
https://github.com/home-assistant/core.git
synced 2026-08-28 02:24:46 -05:00
359 lines
12 KiB
Python
359 lines
12 KiB
Python
"""Test the Gatus Config flow."""
|
|
|
|
from unittest.mock import AsyncMock
|
|
|
|
from gatus_api import GatusAuthError, GatusClientError
|
|
import pytest
|
|
|
|
from homeassistant import config_entries
|
|
from homeassistant.components.gatus.const import DOMAIN
|
|
from homeassistant.const import CONF_URL
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.data_entry_flow import FlowResultType
|
|
|
|
from tests.common import MockConfigEntry
|
|
|
|
|
|
@pytest.mark.usefixtures("mock_gatus_client")
|
|
async def test_form_success(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None:
|
|
"""Test we get the form, validate the client, and create a successful entry."""
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] == {}
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_URL: "http://gatus.example.com:8080"},
|
|
)
|
|
|
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
|
assert result["title"] == "Gatus"
|
|
assert result["data"] == {
|
|
CONF_URL: "http://gatus.example.com:8080",
|
|
}
|
|
assert len(mock_setup_entry.mock_calls) == 1
|
|
|
|
|
|
@pytest.mark.usefixtures("mock_gatus_client")
|
|
async def test_form_success_with_path(
|
|
hass: HomeAssistant, mock_setup_entry: AsyncMock
|
|
) -> None:
|
|
"""Test we get the form, validate the client, and create a successful entry with a sub-path."""
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] == {}
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_URL: "http://gatus.example.com:8080/gatus-instance/"},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
|
assert result["title"] == "Gatus"
|
|
assert result["data"] == {
|
|
CONF_URL: "http://gatus.example.com:8080/gatus-instance",
|
|
}
|
|
assert len(mock_setup_entry.mock_calls) == 1
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("side_effect", "error_key"),
|
|
[
|
|
(GatusClientError("Cannot connect"), "cannot_connect"),
|
|
(GatusAuthError("401 Unauthorized"), "invalid_auth"),
|
|
(Exception("Unexpected backend explosion"), "unknown"),
|
|
],
|
|
)
|
|
async def test_form_failures_and_recovery(
|
|
hass: HomeAssistant,
|
|
mock_setup_entry: AsyncMock,
|
|
mock_gatus_client: AsyncMock,
|
|
side_effect: Exception,
|
|
error_key: str,
|
|
) -> None:
|
|
"""Test handling validation failures and ensuring the flow can completely recover."""
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
|
|
mock_gatus_client.get_endpoints_statuses.side_effect = side_effect
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_URL: "http://gatus.example.com:8080"},
|
|
)
|
|
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] == {"base": error_key}
|
|
|
|
mock_gatus_client.get_endpoints_statuses.side_effect = None
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_URL: "http://gatus.example.com:8080"},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
|
assert len(mock_setup_entry.mock_calls) == 1
|
|
|
|
|
|
async def test_form_already_configured(
|
|
hass: HomeAssistant, mock_config_entry: MockConfigEntry
|
|
) -> None:
|
|
"""Test that duplicate configurations for the same base URL abort early."""
|
|
mock_config_entry.add_to_hass(hass)
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_URL: "http://gatus.example.com:8080"},
|
|
)
|
|
|
|
assert result["type"] is FlowResultType.ABORT
|
|
assert result["reason"] == "already_configured"
|
|
|
|
|
|
@pytest.mark.usefixtures("mock_gatus_client")
|
|
async def test_flow_reconfigure(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
) -> None:
|
|
"""Test reconfigure flow."""
|
|
mock_config_entry.add_to_hass(hass)
|
|
result = await mock_config_entry.start_reconfigure_flow(hass)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == "reconfigure"
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_URL: "http://gatus.example2.com:8080/"},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result["type"] is FlowResultType.ABORT
|
|
assert result["reason"] == "reconfigure_successful"
|
|
assert mock_config_entry.data == {
|
|
CONF_URL: "http://gatus.example2.com:8080",
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("side_effect", "error_key"),
|
|
[
|
|
(GatusClientError("Cannot connect"), "cannot_connect"),
|
|
(GatusAuthError("401 Unauthorized"), "invalid_auth"),
|
|
(Exception("Unexpected backend explosion"), "unknown"),
|
|
],
|
|
)
|
|
async def test_flow_reconfigure_errors(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_gatus_client: AsyncMock,
|
|
side_effect: Exception,
|
|
error_key: str,
|
|
) -> None:
|
|
"""Test reconfigure flow errors and recover."""
|
|
mock_config_entry.add_to_hass(hass)
|
|
result = await mock_config_entry.start_reconfigure_flow(hass)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == "reconfigure"
|
|
|
|
mock_gatus_client.get_endpoints_statuses.side_effect = side_effect
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_URL: "http://gatus.example2.com:8080"},
|
|
)
|
|
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] == {"base": error_key}
|
|
|
|
mock_gatus_client.get_endpoints_statuses.side_effect = None
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_URL: "http://gatus.example2.com:8080"},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result["type"] is FlowResultType.ABORT
|
|
assert result["reason"] == "reconfigure_successful"
|
|
assert mock_config_entry.data == {
|
|
CONF_URL: "http://gatus.example2.com:8080",
|
|
}
|
|
|
|
|
|
@pytest.mark.usefixtures("mock_gatus_client")
|
|
async def test_flow_reconfigure_already_configured(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
) -> None:
|
|
"""Test reconfigure flow aborts if the new URL is already configured."""
|
|
mock_config_entry.add_to_hass(hass)
|
|
|
|
other_entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
data={CONF_URL: "http://gatus.example3.com:8080"},
|
|
entry_id="other_id",
|
|
)
|
|
other_entry.add_to_hass(hass)
|
|
|
|
result = await mock_config_entry.start_reconfigure_flow(hass)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == "reconfigure"
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{CONF_URL: "http://gatus.example3.com:8080"},
|
|
)
|
|
|
|
assert result["type"] is FlowResultType.ABORT
|
|
assert result["reason"] == "already_configured"
|
|
|
|
|
|
@pytest.mark.usefixtures("mock_gatus_client")
|
|
async def test_form_success_with_credentials(
|
|
hass: HomeAssistant, mock_setup_entry: AsyncMock
|
|
) -> None:
|
|
"""Test setup with username, password, and token credentials."""
|
|
result = await hass.config_entries.flow.async_init(
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
)
|
|
assert result["type"] is FlowResultType.FORM
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{
|
|
CONF_URL: "http://gatus.example.com:8080",
|
|
"username": "user",
|
|
"password": "pass",
|
|
"token": "secret_token",
|
|
},
|
|
)
|
|
|
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
|
assert result["data"] == {
|
|
CONF_URL: "http://gatus.example.com:8080",
|
|
"username": "user",
|
|
"password": "pass",
|
|
"token": "secret_token",
|
|
}
|
|
assert len(mock_setup_entry.mock_calls) == 1
|
|
|
|
|
|
@pytest.mark.usefixtures("mock_gatus_client")
|
|
async def test_flow_reconfigure_credentials(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
) -> None:
|
|
"""Test reconfigure flow updating stored credentials."""
|
|
mock_config_entry.add_to_hass(hass)
|
|
result = await mock_config_entry.start_reconfigure_flow(hass)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == "reconfigure"
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{
|
|
CONF_URL: "http://gatus.example.com:8080",
|
|
"username": "new_user",
|
|
"password": "new_password",
|
|
"token": "new_token",
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result["type"] is FlowResultType.ABORT
|
|
assert result["reason"] == "reconfigure_successful"
|
|
assert mock_config_entry.data == {
|
|
CONF_URL: "http://gatus.example.com:8080",
|
|
"username": "new_user",
|
|
"password": "new_password",
|
|
"token": "new_token",
|
|
}
|
|
|
|
|
|
@pytest.mark.usefixtures("mock_gatus_client")
|
|
async def test_flow_reauth(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
) -> None:
|
|
"""Test reauth flow."""
|
|
mock_config_entry.add_to_hass(hass)
|
|
result = await mock_config_entry.start_reauth_flow(hass)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == "reauth_confirm"
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{
|
|
"username": "reauth_user",
|
|
"password": "reauth_password",
|
|
},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result["type"] is FlowResultType.ABORT
|
|
assert result["reason"] == "reauth_successful"
|
|
assert mock_config_entry.data == {
|
|
CONF_URL: "http://gatus.example.com:8080",
|
|
"username": "reauth_user",
|
|
"password": "reauth_password",
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("side_effect", "error_key"),
|
|
[
|
|
(GatusClientError("Cannot connect"), "cannot_connect"),
|
|
(GatusAuthError("401 Unauthorized"), "invalid_auth"),
|
|
(Exception("Unexpected backend explosion"), "unknown"),
|
|
],
|
|
)
|
|
async def test_flow_reauth_errors(
|
|
hass: HomeAssistant,
|
|
mock_config_entry: MockConfigEntry,
|
|
mock_gatus_client: AsyncMock,
|
|
side_effect: Exception,
|
|
error_key: str,
|
|
) -> None:
|
|
"""Test reauth flow errors and recovery."""
|
|
mock_config_entry.add_to_hass(hass)
|
|
result = await mock_config_entry.start_reauth_flow(hass)
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["step_id"] == "reauth_confirm"
|
|
|
|
mock_gatus_client.get_endpoints_statuses.side_effect = side_effect
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{"username": "user", "password": "wrong_password"},
|
|
)
|
|
|
|
assert result["type"] is FlowResultType.FORM
|
|
assert result["errors"] == {"base": error_key}
|
|
|
|
mock_gatus_client.get_endpoints_statuses.side_effect = None
|
|
|
|
result = await hass.config_entries.flow.async_configure(
|
|
result["flow_id"],
|
|
{"username": "user", "password": "correct_password"},
|
|
)
|
|
await hass.async_block_till_done()
|
|
|
|
assert result["type"] is FlowResultType.ABORT
|
|
assert result["reason"] == "reauth_successful"
|
|
assert mock_config_entry.data == {
|
|
CONF_URL: "http://gatus.example.com:8080",
|
|
"username": "user",
|
|
"password": "correct_password",
|
|
}
|