2024-12-31 13:28:24 +00:00
|
|
|
"""Test the Flick Electric config flow."""
|
|
|
|
|
2025-02-09 22:40:34 +00:00
|
|
|
from unittest.mock import AsyncMock, patch
|
2024-12-31 13:28:24 +00:00
|
|
|
|
2025-02-09 22:40:34 +00:00
|
|
|
import jwt
|
|
|
|
from pyflick.types import APIException, AuthException
|
|
|
|
import pytest
|
2024-12-31 13:28:24 +00:00
|
|
|
|
2025-02-09 22:40:34 +00:00
|
|
|
from homeassistant.components.flick_electric import CONF_ID_TOKEN, HassFlickAuth
|
|
|
|
from homeassistant.components.flick_electric.const import (
|
|
|
|
CONF_ACCOUNT_ID,
|
|
|
|
CONF_TOKEN_EXPIRY,
|
|
|
|
)
|
2024-12-31 13:28:24 +00:00
|
|
|
from homeassistant.config_entries import ConfigEntryState
|
2025-02-09 22:40:34 +00:00
|
|
|
from homeassistant.const import CONF_ACCESS_TOKEN
|
2024-12-31 13:28:24 +00:00
|
|
|
from homeassistant.core import HomeAssistant
|
2025-02-09 22:40:34 +00:00
|
|
|
from homeassistant.util import dt as dt_util
|
2024-12-31 13:28:24 +00:00
|
|
|
|
2025-02-09 22:40:34 +00:00
|
|
|
from . import CONF, setup_integration
|
2024-12-31 13:28:24 +00:00
|
|
|
|
|
|
|
from tests.common import MockConfigEntry
|
|
|
|
|
2025-02-09 22:40:34 +00:00
|
|
|
NEW_TOKEN = jwt.encode(
|
|
|
|
{"exp": dt_util.now().timestamp() + 86400}, "secret", algorithm="HS256"
|
|
|
|
)
|
|
|
|
EXISTING_TOKEN = jwt.encode(
|
|
|
|
{"exp": dt_util.now().timestamp() + 3600}, "secret", algorithm="HS256"
|
|
|
|
)
|
|
|
|
EXPIRED_TOKEN = jwt.encode(
|
|
|
|
{"exp": dt_util.now().timestamp() - 3600}, "secret", algorithm="HS256"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
("exception", "config_entry_state"),
|
|
|
|
[
|
|
|
|
(AuthException, ConfigEntryState.SETUP_ERROR),
|
|
|
|
(APIException, ConfigEntryState.SETUP_RETRY),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
async def test_init_auth_failure_triggers_auth(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
mock_flick_client: AsyncMock,
|
|
|
|
mock_config_entry: MockConfigEntry,
|
|
|
|
exception: Exception,
|
|
|
|
config_entry_state: ConfigEntryState,
|
|
|
|
) -> None:
|
|
|
|
"""Test integration handles initialisation errors."""
|
|
|
|
with patch.object(mock_flick_client, "getPricing", side_effect=exception):
|
|
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
|
|
|
|
assert mock_config_entry.state == config_entry_state
|
|
|
|
|
|
|
|
|
|
|
|
async def test_init_migration_single_account(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
mock_old_config_entry: MockConfigEntry,
|
|
|
|
mock_flick_client: AsyncMock,
|
|
|
|
) -> None:
|
2024-12-31 13:28:24 +00:00
|
|
|
"""Test migration with single account."""
|
2025-02-09 22:40:34 +00:00
|
|
|
await setup_integration(hass, mock_old_config_entry)
|
|
|
|
|
|
|
|
assert len(hass.config_entries.flow.async_progress()) == 0
|
|
|
|
assert mock_old_config_entry.state is ConfigEntryState.LOADED
|
|
|
|
assert mock_old_config_entry.version == 2
|
|
|
|
assert mock_old_config_entry.unique_id == CONF[CONF_ACCOUNT_ID]
|
|
|
|
assert mock_old_config_entry.data == CONF
|
|
|
|
|
|
|
|
|
|
|
|
async def test_init_migration_multi_account_reauth(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
mock_old_config_entry: MockConfigEntry,
|
|
|
|
mock_flick_client_multiple: AsyncMock,
|
|
|
|
) -> None:
|
2024-12-31 13:28:24 +00:00
|
|
|
"""Test migration triggers reauth with multiple accounts."""
|
2025-02-09 22:40:34 +00:00
|
|
|
await setup_integration(hass, mock_old_config_entry)
|
|
|
|
|
|
|
|
assert mock_old_config_entry.state is ConfigEntryState.MIGRATION_ERROR
|
|
|
|
|
|
|
|
# Ensure reauth flow is triggered
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
assert len(hass.config_entries.flow.async_progress()) == 1
|
|
|
|
|
|
|
|
|
|
|
|
async def test_fetch_fresh_token(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
mock_config_entry: MockConfigEntry,
|
|
|
|
mock_flick_client: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test fetching a fresh token."""
|
|
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.flick_electric.config_flow.SimpleFlickAuth.get_new_token",
|
|
|
|
return_value={CONF_ID_TOKEN: NEW_TOKEN},
|
|
|
|
) as mock_get_new_token:
|
|
|
|
auth = HassFlickAuth(hass, mock_config_entry)
|
|
|
|
|
|
|
|
assert await auth.async_get_access_token() == NEW_TOKEN
|
|
|
|
assert mock_get_new_token.call_count == 1
|
|
|
|
|
|
|
|
|
|
|
|
async def test_reuse_token(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
mock_config_entry: MockConfigEntry,
|
|
|
|
mock_flick_client: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test reusing entry token."""
|
|
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
|
|
|
|
hass.config_entries.async_update_entry(
|
|
|
|
mock_config_entry,
|
|
|
|
data={
|
|
|
|
**mock_config_entry.data,
|
|
|
|
CONF_ACCESS_TOKEN: {CONF_ID_TOKEN: EXISTING_TOKEN},
|
|
|
|
CONF_TOKEN_EXPIRY: dt_util.now().timestamp() + 3600,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.flick_electric.config_flow.SimpleFlickAuth.get_new_token",
|
|
|
|
return_value={CONF_ID_TOKEN: NEW_TOKEN},
|
|
|
|
) as mock_get_new_token:
|
|
|
|
auth = HassFlickAuth(hass, mock_config_entry)
|
|
|
|
|
|
|
|
assert await auth.async_get_access_token() == EXISTING_TOKEN
|
|
|
|
assert mock_get_new_token.call_count == 0
|
|
|
|
|
|
|
|
|
|
|
|
async def test_fetch_expired_token(
|
|
|
|
hass: HomeAssistant,
|
|
|
|
mock_config_entry: MockConfigEntry,
|
|
|
|
mock_flick_client: AsyncMock,
|
|
|
|
) -> None:
|
|
|
|
"""Test fetching token when existing token is expired."""
|
|
|
|
await setup_integration(hass, mock_config_entry)
|
|
|
|
|
|
|
|
hass.config_entries.async_update_entry(
|
|
|
|
mock_config_entry,
|
|
|
|
data={
|
|
|
|
**mock_config_entry.data,
|
|
|
|
CONF_ACCESS_TOKEN: {CONF_ID_TOKEN: EXPIRED_TOKEN},
|
|
|
|
CONF_TOKEN_EXPIRY: dt_util.now().timestamp() - 3600,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.flick_electric.config_flow.SimpleFlickAuth.get_new_token",
|
|
|
|
return_value={CONF_ID_TOKEN: NEW_TOKEN},
|
|
|
|
) as mock_get_new_token:
|
|
|
|
auth = HassFlickAuth(hass, mock_config_entry)
|
|
|
|
|
|
|
|
assert await auth.async_get_access_token() == NEW_TOKEN
|
|
|
|
assert mock_get_new_token.call_count == 1
|