1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-20 02:48:57 +00:00
Files
core/tests/components/template/conftest.py

365 lines
11 KiB
Python

"""template conftest."""
from dataclasses import dataclass
from enum import Enum, StrEnum
import pytest
from homeassistant.components import template
from homeassistant.config_entries import SOURCE_USER
from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.data_entry_flow import FlowResultType
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.typing import ConfigType
from homeassistant.setup import async_setup_component
from tests.common import assert_setup_component, async_mock_service
from tests.conftest import WebSocketGenerator
class ConfigurationStyle(Enum):
"""Configuration Styles for template testing."""
LEGACY = "Legacy"
MODERN = "Modern"
TRIGGER = "Trigger"
class Brewery(StrEnum):
"""Test enum."""
MMMM = "mmmm"
BEER = "beer"
IS = "is"
GOOD = "good"
def make_test_trigger(*entities: str) -> dict:
"""Make a test state trigger."""
return {
"trigger": [
{
"trigger": "state",
"entity_id": list(entities),
},
{"platform": "event", "event_type": "test_event"},
],
"variables": {"triggering_entity": "{{ trigger.entity_id }}"},
"action": [
{"event": "action_event", "event_data": {"what": "{{ triggering_entity }}"}}
],
}
async def async_trigger(
hass: HomeAssistant, entity_id: str, state: str | None = None
) -> None:
"""Trigger a state change."""
hass.states.async_set(entity_id, state)
await hass.async_block_till_done()
async def async_setup_legacy_platforms(
hass: HomeAssistant,
domain: str,
slug: str | None,
count: int,
config: ConfigType | list[ConfigType],
) -> None:
"""Do setup of any legacy platform that supports a keyed dictionary of template entities."""
if slug is None:
# Lock and Weather platforms do not use a slug
if isinstance(config, list):
config = {domain: [{"platform": "template", **item} for item in config]}
else:
config = {domain: {"platform": "template", **config}}
else:
assert isinstance(config, dict)
config = {domain: {"platform": "template", slug: config}}
with assert_setup_component(count, domain):
assert await async_setup_component(
hass,
domain,
config,
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
async def async_setup_modern_state_format(
hass: HomeAssistant,
domain: str,
count: int,
config: ConfigType | list[ConfigType],
extra_section_config: ConfigType | None = None,
) -> None:
"""Do setup of template integration via modern format."""
with assert_setup_component(count, template.DOMAIN):
assert await async_setup_component(
hass,
template.DOMAIN,
{"template": {domain: config, **(extra_section_config or {})}},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
async def async_setup_modern_trigger_format(
hass: HomeAssistant,
domain: str,
trigger: dict,
count: int,
config: ConfigType | list[ConfigType],
extra_section_config: ConfigType | None = None,
) -> None:
"""Do setup of template integration via trigger format."""
config = {"template": {domain: config, **trigger, **(extra_section_config or {})}}
with assert_setup_component(count, template.DOMAIN):
assert await async_setup_component(
hass,
template.DOMAIN,
config,
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
@dataclass(frozen=True)
class TemplatePlatformSetup:
"""Template Platform Setup Information."""
domain: str
legacy_slug: str | None
object_id: str
trigger: ConfigType
@property
def entity_id(self) -> str:
"""Return test entity ID."""
return f"{self.domain}.{self.object_id}"
async def setup_entity(
hass: HomeAssistant,
platform_setup: TemplatePlatformSetup,
style: ConfigurationStyle,
count: int,
config: ConfigType,
state_template: str | None = None,
extra_config: ConfigType | None = None,
attributes: ConfigType | None = None,
extra_section_config: ConfigType | None = None,
) -> None:
"""Do setup of a template entity based on the configuration style."""
if style == ConfigurationStyle.LEGACY:
await async_setup_legacy_platforms(
hass,
platform_setup.domain,
platform_setup.legacy_slug,
count,
{
platform_setup.object_id: {
**({"value_template": state_template} if state_template else {}),
**config,
**(extra_config or {}),
**({"attribute_templates": attributes} if attributes else {}),
}
},
)
return
entity_config = {
"name": platform_setup.object_id,
**({"state": state_template} if state_template else {}),
**config,
**({"attributes": attributes} if attributes else {}),
**(extra_config or {}),
}
if style == ConfigurationStyle.MODERN:
await async_setup_modern_state_format(
hass, platform_setup.domain, count, entity_config, extra_section_config
)
elif style == ConfigurationStyle.TRIGGER:
await async_setup_modern_trigger_format(
hass,
platform_setup.domain,
platform_setup.trigger,
count,
entity_config,
extra_section_config,
)
async def setup_and_test_unique_id(
hass: HomeAssistant,
platform_setup: TemplatePlatformSetup,
style: ConfigurationStyle,
entity_config: ConfigType | None,
) -> None:
"""Setup 2 entities with the same unique_id and verify only 1 entity is created.
The entity_config not provide name or unique_id, those are added automatically.
"""
entity_config = {"unique_id": "not-so_-unique-anymore", **(entity_config or {})}
if style == ConfigurationStyle.LEGACY:
if platform_setup.legacy_slug is None:
config = [
{"name": "template_entity_1", **entity_config},
{"name": "template_entity_2", **entity_config},
]
else:
config = {
"template_entity_1": entity_config,
"template_entity_2": entity_config,
}
await async_setup_legacy_platforms(
hass, platform_setup.domain, platform_setup.legacy_slug, 1, config
)
elif style == ConfigurationStyle.MODERN:
await async_setup_modern_state_format(
hass,
platform_setup.domain,
1,
[
{"name": "template_entity_1", **entity_config},
{"name": "template_entity_2", **entity_config},
],
)
elif style == ConfigurationStyle.TRIGGER:
await async_setup_modern_trigger_format(
hass,
platform_setup.domain,
platform_setup.trigger,
1,
[
{"name": "template_entity_1", **entity_config},
{"name": "template_entity_2", **entity_config},
],
)
assert len(hass.states.async_all(platform_setup.domain)) == 1
async def setup_and_test_nested_unique_id(
hass: HomeAssistant,
platform_setup: TemplatePlatformSetup,
style: ConfigurationStyle,
entity_registry: er.EntityRegistry,
entity_config: ConfigType | None,
) -> None:
"""Setup 2 entities with unique unique_ids in a template section that contains a unique_id.
The test will verify that 2 entities are created where the unique_id appends the
section unique_id to each entity unique_id.
The entity_config should not provide name or unique_id, those are added automatically.
"""
entities = [
{"name": "test_a", "unique_id": "a", **(entity_config or {})},
{"name": "test_b", "unique_id": "b", **(entity_config or {})},
]
extra_section_config = {"unique_id": "x"}
if style == ConfigurationStyle.MODERN:
await async_setup_modern_state_format(
hass, platform_setup.domain, 1, entities, extra_section_config
)
elif style == ConfigurationStyle.TRIGGER:
await async_setup_modern_trigger_format(
hass,
platform_setup.domain,
platform_setup.trigger,
1,
entities,
extra_section_config,
)
assert len(hass.states.async_all(platform_setup.domain)) == 2
entry = entity_registry.async_get(f"{platform_setup.domain}.test_a")
assert entry.unique_id == "x-a"
entry = entity_registry.async_get(f"{platform_setup.domain}.test_b")
assert entry.unique_id == "x-b"
@pytest.fixture
def calls(hass: HomeAssistant) -> list[ServiceCall]:
"""Track calls to a mock service."""
return async_mock_service(hass, "test", "automation")
@pytest.fixture
async def start_ha(
hass: HomeAssistant, count: int, domain: str, config: ConfigType
) -> None:
"""Do setup of integration."""
with assert_setup_component(count, domain):
assert await async_setup_component(
hass,
domain,
config,
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
@pytest.fixture
async def caplog_setup_text(caplog: pytest.LogCaptureFixture) -> str:
"""Return setup log of integration."""
return caplog.text
@pytest.fixture(autouse=True, name="stub_blueprint_populate")
def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None:
"""Stub copying the blueprints to the config folder."""
async def async_get_flow_preview_state(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
domain: str,
user_input: ConfigType,
) -> ConfigType:
"""Test the config flow preview."""
client = await hass_ws_client(hass)
result = await hass.config_entries.flow.async_init(
template.DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] is FlowResultType.MENU
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{"next_step_id": domain},
)
await hass.async_block_till_done()
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == domain
assert result["errors"] is None
assert result["preview"] == "template"
await client.send_json_auto_id(
{
"type": "template/start_preview",
"flow_id": result["flow_id"],
"flow_type": "config_flow",
"user_input": user_input,
}
)
msg = await client.receive_json()
assert msg["success"]
assert msg["result"] is None
msg = await client.receive_json()
return msg["event"]