mirror of
https://github.com/home-assistant/core.git
synced 2026-08-06 21:35:13 +01:00
240 lines
8.6 KiB
Python
240 lines
8.6 KiB
Python
"""Init tests for the Telegram Bot integration."""
|
|
|
|
import pytest
|
|
|
|
from homeassistant.components.telegram_bot.const import (
|
|
ATTR_PARSER,
|
|
CONF_ALLOWED_CHAT_IDS,
|
|
CONF_API_ENDPOINT,
|
|
CONF_CHAT_ID,
|
|
DEFAULT_API_ENDPOINT,
|
|
DOMAIN,
|
|
PARSER_MD,
|
|
PLATFORM_BROADCAST,
|
|
)
|
|
from homeassistant.config_entries import ConfigEntryState, ConfigSubentryData
|
|
from homeassistant.const import CONF_API_KEY, CONF_PLATFORM
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
|
|
|
from tests.common import MockConfigEntry
|
|
|
|
|
|
async def test_migration_error(
|
|
hass: HomeAssistant,
|
|
mock_external_calls: None,
|
|
) -> None:
|
|
"""Test migrate config entry from unsupported version."""
|
|
|
|
mock_config_entry = MockConfigEntry(
|
|
unique_id="mock api key",
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_PLATFORM: PLATFORM_BROADCAST,
|
|
CONF_API_KEY: "mock api key",
|
|
},
|
|
options={ATTR_PARSER: PARSER_MD},
|
|
version=99,
|
|
)
|
|
|
|
mock_config_entry.add_to_hass(hass)
|
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert mock_config_entry.state is ConfigEntryState.MIGRATION_ERROR
|
|
|
|
|
|
async def test_migrate_entry_from_1_1(
|
|
hass: HomeAssistant,
|
|
mock_external_calls: None,
|
|
) -> None:
|
|
"""Test migrate config entry from 1.1, chaining through to the latest version."""
|
|
|
|
mock_config_entry = MockConfigEntry(
|
|
unique_id="mock api key",
|
|
domain=DOMAIN,
|
|
data={
|
|
CONF_PLATFORM: PLATFORM_BROADCAST,
|
|
CONF_API_KEY: "mock api key",
|
|
},
|
|
options={ATTR_PARSER: PARSER_MD},
|
|
)
|
|
|
|
mock_config_entry.add_to_hass(hass)
|
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert mock_config_entry.state is ConfigEntryState.LOADED
|
|
assert mock_config_entry.version == 1
|
|
assert mock_config_entry.minor_version == 3
|
|
assert mock_config_entry.data == {
|
|
CONF_PLATFORM: PLATFORM_BROADCAST,
|
|
CONF_API_KEY: "mock api key",
|
|
CONF_API_ENDPOINT: DEFAULT_API_ENDPOINT,
|
|
}
|
|
|
|
|
|
@pytest.mark.parametrize("collapsed_chat_index", [0, 1])
|
|
@pytest.mark.parametrize(
|
|
"chats_without_notify_entity",
|
|
[
|
|
pytest.param((), id="notify entities intact"),
|
|
pytest.param((654321,), id="notify entity deleted"),
|
|
],
|
|
)
|
|
async def test_migrate_entry_to_per_chat_devices(
|
|
hass: HomeAssistant,
|
|
mock_external_calls: None,
|
|
device_registry: dr.DeviceRegistry,
|
|
entity_registry: er.EntityRegistry,
|
|
collapsed_chat_index: int,
|
|
chats_without_notify_entity: tuple[int, ...],
|
|
) -> None:
|
|
"""Test migrating chats sharing one bot device to per-chat devices."""
|
|
bot_id = 123456 # test_user id from mock_external_calls
|
|
chat_ids = (123456, 654321)
|
|
config_entry = MockConfigEntry(
|
|
unique_id="mock api key",
|
|
domain=DOMAIN,
|
|
minor_version=2,
|
|
data={
|
|
CONF_PLATFORM: PLATFORM_BROADCAST,
|
|
CONF_API_KEY: "mock api key",
|
|
CONF_API_ENDPOINT: DEFAULT_API_ENDPOINT,
|
|
},
|
|
options={ATTR_PARSER: PARSER_MD},
|
|
subentries_data=[
|
|
ConfigSubentryData(
|
|
unique_id="123456",
|
|
data={CONF_CHAT_ID: 123456},
|
|
subentry_type=CONF_ALLOWED_CHAT_IDS,
|
|
title="chat 1",
|
|
),
|
|
ConfigSubentryData(
|
|
unique_id="654321",
|
|
data={CONF_CHAT_ID: 654321},
|
|
subentry_type=CONF_ALLOWED_CHAT_IDS,
|
|
title="chat 2",
|
|
),
|
|
],
|
|
)
|
|
config_entry.add_to_hass(hass)
|
|
subentry_ids = list(config_entry.subentries)
|
|
|
|
# Post-store-migration state: one shared bot device collapsed onto an arbitrary chat
|
|
# subentry, holding the event entity and every surviving chat's notify entity.
|
|
bot_device = device_registry.async_get_or_create(
|
|
config_entry_id=config_entry.entry_id,
|
|
config_subentry_id=subentry_ids[collapsed_chat_index],
|
|
identifiers={(DOMAIN, str(bot_id))},
|
|
)
|
|
event_entity = entity_registry.async_get_or_create(
|
|
"event",
|
|
DOMAIN,
|
|
f"{bot_id}_update_event",
|
|
config_entry=config_entry,
|
|
device_id=bot_device.id,
|
|
)
|
|
notify_entities = {
|
|
chat_id: entity_registry.async_get_or_create(
|
|
"notify",
|
|
DOMAIN,
|
|
f"{bot_id}_{chat_id}",
|
|
config_entry=config_entry,
|
|
config_subentry_id=subentry_id,
|
|
device_id=bot_device.id,
|
|
)
|
|
for subentry_id, chat_id in zip(subentry_ids, chat_ids, strict=True)
|
|
if chat_id not in chats_without_notify_entity
|
|
}
|
|
|
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
assert config_entry.state is ConfigEntryState.LOADED
|
|
assert config_entry.minor_version == 3
|
|
|
|
# Every chat has its own device - owned by that subentry and linked to the bot device -
|
|
# even a chat whose notify entity was deleted before the migration ran. A surviving
|
|
# notify entity is moved onto its chat's device.
|
|
for subentry_id, chat_id in zip(subentry_ids, chat_ids, strict=True):
|
|
chat_device = device_registry.async_get_device(
|
|
identifiers={(DOMAIN, f"{bot_id}_{chat_id}")}
|
|
)
|
|
assert chat_device is not None
|
|
assert chat_device.config_subentry_id == subentry_id
|
|
assert chat_device.via_device_id == bot_device.id
|
|
if chat_id in notify_entities:
|
|
assert (
|
|
entity_registry.async_get(notify_entities[chat_id].entity_id).device_id
|
|
== chat_device.id
|
|
)
|
|
|
|
# The bot device was handed back to the config entry, keeping the event entity
|
|
bot_device = device_registry.async_get(bot_device.id)
|
|
assert bot_device is not None
|
|
assert bot_device.config_subentry_id is None
|
|
assert entity_registry.async_get(event_entity.entity_id).device_id == bot_device.id
|
|
|
|
|
|
async def test_per_chat_devices(
|
|
hass: HomeAssistant,
|
|
mock_broadcast_config_entry: MockConfigEntry,
|
|
mock_external_calls: None,
|
|
device_registry: dr.DeviceRegistry,
|
|
entity_registry: er.EntityRegistry,
|
|
) -> None:
|
|
"""Each chat gets its own device linked to the config-entry-level bot device."""
|
|
mock_broadcast_config_entry.add_to_hass(hass)
|
|
await hass.config_entries.async_setup(mock_broadcast_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
# The bot device belongs to the config entry (no subentry) and holds the event entity
|
|
bot_device = device_registry.async_get_device(identifiers={(DOMAIN, "123456")})
|
|
assert bot_device is not None
|
|
assert bot_device.config_subentry_id is None
|
|
|
|
for chat_id in (123456, 654321):
|
|
chat_device = device_registry.async_get_device(
|
|
identifiers={(DOMAIN, f"123456_{chat_id}")}
|
|
)
|
|
assert chat_device is not None
|
|
assert chat_device.config_subentry_id is not None
|
|
assert chat_device.via_device_id == bot_device.id
|
|
notify_entity_id = entity_registry.async_get_entity_id(
|
|
"notify", DOMAIN, f"123456_{chat_id}"
|
|
)
|
|
assert notify_entity_id is not None
|
|
assert entity_registry.async_get(notify_entity_id).device_id == chat_device.id
|
|
|
|
|
|
async def test_remove_chat_subentry_removes_per_chat_device(
|
|
hass: HomeAssistant,
|
|
mock_broadcast_config_entry: MockConfigEntry,
|
|
mock_external_calls: None,
|
|
device_registry: dr.DeviceRegistry,
|
|
entity_registry: er.EntityRegistry,
|
|
) -> None:
|
|
"""Removing a chat subentry removes just its per-chat device and notify entity."""
|
|
mock_broadcast_config_entry.add_to_hass(hass)
|
|
await hass.config_entries.async_setup(mock_broadcast_config_entry.entry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
subentry_id = next(
|
|
sid
|
|
for sid, subentry in mock_broadcast_config_entry.subentries.items()
|
|
if subentry.data[CONF_CHAT_ID] == 123456
|
|
)
|
|
assert device_registry.async_get_device(identifiers={(DOMAIN, "123456_123456")})
|
|
assert entity_registry.async_get_entity_id("notify", DOMAIN, "123456_123456")
|
|
|
|
hass.config_entries.async_remove_subentry(mock_broadcast_config_entry, subentry_id)
|
|
await hass.async_block_till_done()
|
|
|
|
# The removed chat's device and notify entity are gone; the other chat and the bot
|
|
# device remain
|
|
assert not device_registry.async_get_device(identifiers={(DOMAIN, "123456_123456")})
|
|
assert not entity_registry.async_get_entity_id("notify", DOMAIN, "123456_123456")
|
|
assert device_registry.async_get_device(identifiers={(DOMAIN, "123456_654321")})
|
|
assert device_registry.async_get_device(identifiers={(DOMAIN, "123456")})
|