hass-core/tests/components/conversation/test_default_agent.py
Michael Hansen 325674ec44
Only expose default cloud domains in Assist default agent ()
* Only expose default cloud domains in default agent

* Copy exposed domain list to conversation

* Implement requested changes

* Add test for exposed devices/areas
2023-02-17 16:19:22 -05:00

122 lines
4.6 KiB
Python

"""Test for the default agent."""
from unittest.mock import patch
import pytest
from homeassistant.components import conversation
from homeassistant.const import ATTR_FRIENDLY_NAME
from homeassistant.core import DOMAIN as HASS_DOMAIN, Context, HomeAssistant
from homeassistant.helpers import (
area_registry,
device_registry,
entity,
entity_registry,
intent,
)
from homeassistant.setup import async_setup_component
from tests.common import async_mock_service
@pytest.fixture
async def init_components(hass):
"""Initialize relevant components with empty configs."""
assert await async_setup_component(hass, "homeassistant", {})
assert await async_setup_component(hass, "conversation", {})
assert await async_setup_component(hass, "intent", {})
@pytest.mark.parametrize(
"er_kwargs",
[
{"hidden_by": entity_registry.RegistryEntryHider.USER},
{"hidden_by": entity_registry.RegistryEntryHider.INTEGRATION},
{"entity_category": entity.EntityCategory.CONFIG},
{"entity_category": entity.EntityCategory.DIAGNOSTIC},
],
)
async def test_hidden_entities_skipped(
hass: HomeAssistant, init_components, er_kwargs
) -> None:
"""Test we skip hidden entities."""
er = entity_registry.async_get(hass)
er.async_get_or_create(
"light", "demo", "1234", suggested_object_id="Test light", **er_kwargs
)
hass.states.async_set("light.test_light", "off")
calls = async_mock_service(hass, HASS_DOMAIN, "turn_on")
result = await conversation.async_converse(
hass, "turn on test light", None, Context(), None
)
assert len(calls) == 0
assert result.response.response_type == intent.IntentResponseType.ERROR
assert result.response.error_code == intent.IntentResponseErrorCode.NO_INTENT_MATCH
async def test_exposed_domains(hass: HomeAssistant, init_components) -> None:
"""Test that we can't interact with entities that aren't exposed."""
hass.states.async_set(
"media_player.test", "off", attributes={ATTR_FRIENDLY_NAME: "Test Media Player"}
)
result = await conversation.async_converse(
hass, "turn on test media player", None, Context(), None
)
# This is an intent match failure instead of a handle failure because the
# media player domain is not exposed.
assert result.response.response_type == intent.IntentResponseType.ERROR
assert result.response.error_code == intent.IntentResponseErrorCode.NO_INTENT_MATCH
async def test_exposed_areas(hass: HomeAssistant, init_components) -> None:
"""Test that only expose areas with an exposed entity/device."""
areas = area_registry.async_get(hass)
area_kitchen = areas.async_get_or_create("kitchen")
area_bedroom = areas.async_get_or_create("bedroom")
devices = device_registry.async_get(hass)
kitchen_device = devices.async_get_or_create(
config_entry_id="1234", connections=set(), identifiers={("demo", "id-1234")}
)
devices.async_update_device(kitchen_device.id, area_id=area_kitchen.id)
entities = entity_registry.async_get(hass)
kitchen_light = entities.async_get_or_create("light", "demo", "1234")
entities.async_update_entity(kitchen_light.entity_id, device_id=kitchen_device.id)
hass.states.async_set(
kitchen_light.entity_id, "on", attributes={ATTR_FRIENDLY_NAME: "kitchen light"}
)
bedroom_light = entities.async_get_or_create("light", "demo", "5678")
entities.async_update_entity(bedroom_light.entity_id, area_id=area_bedroom.id)
hass.states.async_set(
bedroom_light.entity_id, "on", attributes={ATTR_FRIENDLY_NAME: "bedroom light"}
)
def is_entity_exposed(state):
return state.entity_id != bedroom_light.entity_id
with patch(
"homeassistant.components.conversation.default_agent.is_entity_exposed",
is_entity_exposed,
):
result = await conversation.async_converse(
hass, "turn on lights in the kitchen", None, Context(), None
)
# All is well for the exposed kitchen light
assert result.response.response_type == intent.IntentResponseType.ACTION_DONE
# Bedroom is not exposed because it has no exposed entities
result = await conversation.async_converse(
hass, "turn on lights in the bedroom", None, Context(), None
)
# This should be an intent match failure because the area isn't in the slot list
assert result.response.response_type == intent.IntentResponseType.ERROR
assert (
result.response.error_code == intent.IntentResponseErrorCode.NO_INTENT_MATCH
)