1
0
mirror of https://github.com/home-assistant/core.git synced 2026-02-15 07:36:16 +00:00
Files
core/tests/components/splunk/test_config_flow.py
Brett Adams 877ad391f0 Add config flow to Splunk (#160478)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Erwin Douna <e.douna@gmail.com>
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
2026-02-12 23:27:49 +01:00

279 lines
8.2 KiB
Python

"""Test the Splunk config flow."""
from unittest.mock import AsyncMock
import pytest
from homeassistant.components.splunk.const import DEFAULT_HOST, DEFAULT_PORT, DOMAIN
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_USER
from homeassistant.const import (
CONF_HOST,
CONF_NAME,
CONF_PORT,
CONF_SSL,
CONF_TOKEN,
CONF_VERIFY_SSL,
)
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
pytestmark = pytest.mark.usefixtures("mock_setup_entry")
async def test_user_flow_success(
hass: HomeAssistant, mock_hass_splunk: AsyncMock
) -> None:
"""Test successful user flow."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
assert result["errors"] == {}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_TOKEN: "test-token-123",
CONF_HOST: "splunk.example.com",
CONF_PORT: 8088,
CONF_SSL: True,
CONF_NAME: "Test Splunk",
},
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "splunk.example.com:8088"
assert result["data"] == {
CONF_TOKEN: "test-token-123",
CONF_HOST: "splunk.example.com",
CONF_PORT: 8088,
CONF_SSL: True,
CONF_VERIFY_SSL: True,
CONF_NAME: "Test Splunk",
}
# Verify that check was called twice (connectivity and token)
assert mock_hass_splunk.check.call_count == 2
@pytest.mark.parametrize(
("side_effect", "error"),
[
([False, True], "cannot_connect"),
([True, False], "invalid_auth"),
(Exception("Unexpected error"), "unknown"),
],
)
async def test_user_flow_error_and_recovery(
hass: HomeAssistant,
mock_hass_splunk: AsyncMock,
side_effect: list[bool] | Exception,
error: str,
) -> None:
"""Test user flow errors and recovery."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
mock_hass_splunk.check.side_effect = side_effect
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_TOKEN: "test-token-123",
CONF_HOST: "splunk.example.com",
CONF_PORT: 8088,
CONF_SSL: False,
},
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
assert result["errors"] == {"base": error}
# Test recovery by resetting mock and completing successfully
mock_hass_splunk.check.side_effect = None
mock_hass_splunk.check.return_value = True
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
CONF_TOKEN: "test-token-123",
CONF_HOST: "splunk.example.com",
CONF_PORT: 8088,
CONF_SSL: False,
},
)
assert result["type"] is FlowResultType.CREATE_ENTRY
async def test_user_flow_already_configured(
hass: HomeAssistant, mock_hass_splunk: AsyncMock, mock_config_entry: MockConfigEntry
) -> None:
"""Test user flow when entry is already configured (single instance)."""
mock_config_entry.add_to_hass(hass)
# With single_config_entry in manifest, flow should abort immediately
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "single_instance_allowed"
async def test_import_flow_success(
hass: HomeAssistant, mock_hass_splunk: AsyncMock
) -> None:
"""Test successful import flow."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data={
CONF_TOKEN: "test-token-123",
CONF_HOST: "splunk.example.com",
CONF_PORT: 8088,
CONF_SSL: False,
CONF_NAME: "Imported Splunk",
},
)
assert result["type"] is FlowResultType.CREATE_ENTRY
assert result["title"] == "splunk.example.com:8088"
assert result["data"] == {
CONF_TOKEN: "test-token-123",
CONF_HOST: "splunk.example.com",
CONF_PORT: 8088,
CONF_SSL: False,
CONF_NAME: "Imported Splunk",
}
@pytest.mark.parametrize(
("side_effect", "reason"),
[
([False, True], "cannot_connect"),
([True, False], "invalid_auth"),
(Exception("Unexpected error"), "unknown"),
],
)
async def test_import_flow_error_and_recovery(
hass: HomeAssistant,
mock_hass_splunk: AsyncMock,
side_effect: list[bool] | Exception,
reason: str,
) -> None:
"""Test import flow errors and recovery."""
mock_hass_splunk.check.side_effect = side_effect
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data={
CONF_TOKEN: "test-token-123",
CONF_HOST: "splunk.example.com",
CONF_PORT: 8088,
CONF_SSL: False,
},
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == reason
# Test recovery by resetting mock and importing again
mock_hass_splunk.check.side_effect = None
mock_hass_splunk.check.return_value = True
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data={
CONF_TOKEN: "test-token-123",
CONF_HOST: "splunk.example.com",
CONF_PORT: 8088,
CONF_SSL: False,
},
)
assert result["type"] is FlowResultType.CREATE_ENTRY
async def test_import_flow_already_configured(
hass: HomeAssistant, mock_hass_splunk: AsyncMock, mock_config_entry: MockConfigEntry
) -> None:
"""Test import flow when entry is already configured (single instance)."""
mock_config_entry.add_to_hass(hass)
# With single_config_entry in manifest, import should abort immediately
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data={
CONF_TOKEN: "test-token-123",
CONF_HOST: DEFAULT_HOST,
CONF_PORT: DEFAULT_PORT,
CONF_SSL: False,
},
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "single_instance_allowed"
async def test_reauth_flow_success(
hass: HomeAssistant, mock_hass_splunk: AsyncMock, mock_config_entry: MockConfigEntry
) -> None:
"""Test successful 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"],
{CONF_TOKEN: "new-token-456"},
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "reauth_successful"
assert mock_config_entry.data[CONF_TOKEN] == "new-token-456"
async def test_reauth_flow_invalid_auth(
hass: HomeAssistant, mock_hass_splunk: AsyncMock, mock_config_entry: MockConfigEntry
) -> None:
"""Test reauth flow with invalid token and recovery."""
mock_config_entry.add_to_hass(hass)
result = await mock_config_entry.start_reauth_flow(hass)
# Mock token check failure
mock_hass_splunk.check.side_effect = [True, False]
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_TOKEN: "invalid-token"},
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "reauth_confirm"
assert result["errors"] == {"base": "invalid_auth"}
# Now test that we can recover from the error
mock_hass_splunk.check.side_effect = None
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_TOKEN: "new-valid-token"},
)
assert result["type"] is FlowResultType.ABORT
assert result["reason"] == "reauth_successful"
assert mock_config_entry.data[CONF_TOKEN] == "new-valid-token"