Files

251 lines
8.1 KiB
Python

"""Tests for component initialisation."""
from datetime import timedelta
from unittest.mock import AsyncMock, patch
from freezegun.api import FrozenDateTimeFactory
from monzopy import AuthorisationExpiredError
import pytest
from homeassistant.components.monzo.const import DOMAIN
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntryState
from homeassistant.const import CONF_WEBHOOK_ID
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.config_entry_oauth2_flow import (
ImplementationUnavailableError,
)
from . import setup_integration
from .conftest import TEST_ACCOUNTS, TITLE, USER_ID
from tests.common import MockConfigEntry, async_fire_time_changed
async def test_config_entry_title_uses_authenticated_owner(
hass: HomeAssistant,
polling_config_entry: MockConfigEntry,
monzo: AsyncMock,
) -> None:
"""Test the config entry is named after the authenticated owner."""
monzo.user_account.accounts.return_value = [
{
**TEST_ACCOUNTS[0],
"owners": [
{
"user_id": "another-user",
"preferred_name": "Jane Martin",
},
{
"user_id": str(USER_ID),
"preferred_name": "Jake Martin",
"preferred_first_name": "Jake",
},
],
},
TEST_ACCOUNTS[1],
]
polling_config_entry.add_to_hass(hass)
hass.config_entries.async_update_entry(polling_config_entry, title=DOMAIN)
assert await hass.config_entries.async_setup(polling_config_entry.entry_id)
assert polling_config_entry.title == "Jake Martin"
async def test_config_entry_title_falls_back_without_owner(
hass: HomeAssistant,
polling_config_entry: MockConfigEntry,
monzo: AsyncMock,
) -> None:
"""Test the existing title is retained without matching owner metadata."""
monzo.user_account.accounts.return_value = [
{key: value for key, value in account.items() if key != "owners"}
for account in TEST_ACCOUNTS
]
polling_config_entry.add_to_hass(hass)
hass.config_entries.async_update_entry(polling_config_entry, title=DOMAIN)
assert await hass.config_entries.async_setup(polling_config_entry.entry_id)
assert polling_config_entry.title == DOMAIN
async def test_config_entry_title_preserves_custom_name(
hass: HomeAssistant,
polling_config_entry: MockConfigEntry,
monzo: AsyncMock,
) -> None:
"""Test a user-defined config entry title is retained."""
await setup_integration(hass, polling_config_entry)
assert polling_config_entry.title == TITLE
async def test_device_names(
hass: HomeAssistant,
polling_config_entry: MockConfigEntry,
monzo: AsyncMock,
device_registry: dr.DeviceRegistry,
) -> None:
"""Test devices use descriptive resource names."""
joint_account = {
**TEST_ACCOUNTS[0],
"id": "acc_joint",
"name": "Joint Account",
"owners": [
TEST_ACCOUNTS[0]["owners"][0],
{
"user_id": "another-user",
"preferred_name": "Jane Martin",
"preferred_first_name": "Jane",
},
],
}
monzo.user_account.accounts.return_value = [TEST_ACCOUNTS[0], joint_account]
monzo.user_account.pots.return_value = [
{
"id": "pot_joint",
"name": "Holiday",
"balance": 12345,
"currency": "GBP",
}
]
await setup_integration(hass, polling_config_entry)
current_account_device = device_registry.async_get_device_by_identifier(
(DOMAIN, "acc_curr"), polling_config_entry.entry_id
)
joint_account_device = device_registry.async_get_device_by_identifier(
(DOMAIN, "acc_joint"), polling_config_entry.entry_id
)
pot_device = device_registry.async_get_device_by_identifier(
(DOMAIN, "pot_joint"), polling_config_entry.entry_id
)
assert current_account_device is not None
assert current_account_device.name == "Current Account"
assert joint_account_device is not None
assert joint_account_device.name == "Joint Account — Jake Martin & Jane Martin"
assert pot_device is not None
assert pot_device.name == "Holiday"
async def test_joint_account_owners_with_same_name(
hass: HomeAssistant,
polling_config_entry: MockConfigEntry,
monzo: AsyncMock,
device_registry: dr.DeviceRegistry,
) -> None:
"""Test distinct joint owners can have the same preferred name."""
monzo.user_account.accounts.return_value = [
{
**TEST_ACCOUNTS[0],
"id": "acc_joint",
"name": "Joint Account",
"owners": [
{
"user_id": str(USER_ID),
"preferred_name": "Alex Smith",
},
{
"user_id": "another-user",
"preferred_name": "Alex Smith",
},
],
}
]
await setup_integration(hass, polling_config_entry)
account_device = device_registry.async_get_device_by_identifier(
(DOMAIN, "acc_joint"), polling_config_entry.entry_id
)
assert account_device is not None
assert account_device.name == "Joint Account — Alex Smith & Alex Smith"
async def test_api_can_trigger_reauth(
hass: HomeAssistant,
polling_config_entry: MockConfigEntry,
monzo: AsyncMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test reauth an existing profile reauthenticates the config entry."""
await setup_integration(hass, polling_config_entry)
monzo.user_account.accounts.side_effect = AuthorisationExpiredError()
freezer.tick(timedelta(minutes=10))
async_fire_time_changed(hass)
await hass.async_block_till_done(wait_background_tasks=True)
flows = hass.config_entries.flow.async_progress()
assert len(flows) == 1
flow = flows[0]
assert flow["step_id"] == "reauth_confirm"
assert flow["handler"] == DOMAIN
assert flow["context"]["source"] == SOURCE_REAUTH
@pytest.mark.parametrize(
("minor_version", "unique_id"),
[
pytest.param(1, 600, id="minor-version-1"),
pytest.param(2, "600", id="minor-version-2"),
],
)
async def test_migrate_entry(
hass: HomeAssistant, minor_version: int, unique_id: int | str
) -> None:
"""Test migrating an older config entry to 1.3."""
entry = MockConfigEntry(
domain=DOMAIN,
data={
"auth_implementation": DOMAIN,
"token": {
"refresh_token": "mock-refresh-token",
"access_token": "mock-access-token",
"type": "Bearer",
"expires_in": 60,
"user_id": "600",
},
},
version=1,
minor_version=minor_version,
unique_id=unique_id,
)
entry.add_to_hass(hass)
with (
patch(
"homeassistant.components.monzo.async_generate_id",
return_value="generated-webhook-id",
),
patch("homeassistant.components.monzo.async_setup_entry", return_value=True),
patch("homeassistant.components.monzo.async_unload_entry", return_value=True),
):
assert await hass.config_entries.async_setup(entry.entry_id)
assert entry.version == 1
assert entry.minor_version == 3
assert entry.unique_id == "600"
assert entry.data[CONF_WEBHOOK_ID] == "generated-webhook-id"
assert await hass.config_entries.async_unload(entry.entry_id)
async def test_oauth_implementation_not_available(
hass: HomeAssistant,
polling_config_entry: MockConfigEntry,
) -> None:
"""Test that unavailable OAuth implementation raises ConfigEntryNotReady."""
polling_config_entry.add_to_hass(hass)
with patch(
"homeassistant.components.monzo.async_get_config_entry_implementation",
side_effect=ImplementationUnavailableError,
):
await hass.config_entries.async_setup(polling_config_entry.entry_id)
await hass.async_block_till_done()
assert polling_config_entry.state is ConfigEntryState.SETUP_RETRY