mirror of https://github.com/home-assistant/core
225 lines
7.5 KiB
Python
225 lines
7.5 KiB
Python
"""Test conversation."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import patch
|
|
|
|
from syrupy import SnapshotAssertion
|
|
from wyoming.asr import Transcript
|
|
from wyoming.handle import Handled, NotHandled
|
|
from wyoming.intent import Entity, Intent, NotRecognized
|
|
|
|
from homeassistant.components import conversation
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.core import Context, HomeAssistant
|
|
from homeassistant.helpers import intent
|
|
|
|
from . import MockAsyncTcpClient
|
|
|
|
|
|
async def test_intent(hass: HomeAssistant, init_wyoming_intent: ConfigEntry) -> None:
|
|
"""Test when an intent is recognized."""
|
|
agent_id = "conversation.test_intent"
|
|
|
|
conversation_id = "conversation-1234"
|
|
test_intent = Intent(
|
|
name="TestIntent",
|
|
entities=[Entity(name="entity", value="value")],
|
|
text="success",
|
|
)
|
|
|
|
class TestIntentHandler(intent.IntentHandler):
|
|
"""Test Intent Handler."""
|
|
|
|
intent_type = "TestIntent"
|
|
|
|
async def async_handle(self, intent_obj: intent.Intent):
|
|
"""Handle the intent."""
|
|
assert intent_obj.slots.get("entity", {}).get("value") == "value"
|
|
return intent_obj.create_response()
|
|
|
|
intent.async_register(hass, TestIntentHandler())
|
|
|
|
with patch(
|
|
"homeassistant.components.wyoming.conversation.AsyncTcpClient",
|
|
MockAsyncTcpClient([test_intent.event()]),
|
|
):
|
|
result = await conversation.async_converse(
|
|
hass=hass,
|
|
text="test text",
|
|
conversation_id=conversation_id,
|
|
context=Context(),
|
|
language=hass.config.language,
|
|
agent_id=agent_id,
|
|
)
|
|
|
|
assert result.response.response_type == intent.IntentResponseType.ACTION_DONE
|
|
assert result.response.speech, "No speech"
|
|
assert result.response.speech.get("plain", {}).get("speech") == "success"
|
|
assert result.conversation_id == conversation_id
|
|
|
|
|
|
async def test_intent_handle_error(
|
|
hass: HomeAssistant, init_wyoming_intent: ConfigEntry
|
|
) -> None:
|
|
"""Test error during handling when an intent is recognized."""
|
|
agent_id = "conversation.test_intent"
|
|
|
|
test_intent = Intent(name="TestIntent", entities=[], text="success")
|
|
|
|
class TestIntentHandler(intent.IntentHandler):
|
|
"""Test Intent Handler."""
|
|
|
|
intent_type = "TestIntent"
|
|
|
|
async def async_handle(self, intent_obj: intent.Intent):
|
|
"""Handle the intent."""
|
|
raise intent.IntentError
|
|
|
|
intent.async_register(hass, TestIntentHandler())
|
|
|
|
with patch(
|
|
"homeassistant.components.wyoming.conversation.AsyncTcpClient",
|
|
MockAsyncTcpClient([test_intent.event()]),
|
|
):
|
|
result = await conversation.async_converse(
|
|
hass=hass,
|
|
text="test text",
|
|
conversation_id=None,
|
|
context=Context(),
|
|
language=hass.config.language,
|
|
agent_id=agent_id,
|
|
)
|
|
|
|
assert result.response.response_type == intent.IntentResponseType.ERROR
|
|
assert result.response.error_code == intent.IntentResponseErrorCode.FAILED_TO_HANDLE
|
|
|
|
|
|
async def test_not_recognized(
|
|
hass: HomeAssistant, init_wyoming_intent: ConfigEntry
|
|
) -> None:
|
|
"""Test when an intent is not recognized."""
|
|
agent_id = "conversation.test_intent"
|
|
|
|
with patch(
|
|
"homeassistant.components.wyoming.conversation.AsyncTcpClient",
|
|
MockAsyncTcpClient([NotRecognized(text="failure").event()]),
|
|
):
|
|
result = await conversation.async_converse(
|
|
hass=hass,
|
|
text="test text",
|
|
conversation_id=None,
|
|
context=Context(),
|
|
language=hass.config.language,
|
|
agent_id=agent_id,
|
|
)
|
|
|
|
assert result.response.response_type == intent.IntentResponseType.ERROR
|
|
assert result.response.error_code == intent.IntentResponseErrorCode.NO_INTENT_MATCH
|
|
assert result.response.speech, "No speech"
|
|
assert result.response.speech.get("plain", {}).get("speech") == "failure"
|
|
|
|
|
|
async def test_handle(hass: HomeAssistant, init_wyoming_handle: ConfigEntry) -> None:
|
|
"""Test when an intent is handled."""
|
|
agent_id = "conversation.test_handle"
|
|
|
|
conversation_id = "conversation-1234"
|
|
|
|
with patch(
|
|
"homeassistant.components.wyoming.conversation.AsyncTcpClient",
|
|
MockAsyncTcpClient([Handled(text="success").event()]),
|
|
):
|
|
result = await conversation.async_converse(
|
|
hass=hass,
|
|
text="test text",
|
|
conversation_id=conversation_id,
|
|
context=Context(),
|
|
language=hass.config.language,
|
|
agent_id=agent_id,
|
|
)
|
|
|
|
assert result.response.response_type == intent.IntentResponseType.ACTION_DONE
|
|
assert result.response.speech, "No speech"
|
|
assert result.response.speech.get("plain", {}).get("speech") == "success"
|
|
assert result.conversation_id == conversation_id
|
|
|
|
|
|
async def test_not_handled(
|
|
hass: HomeAssistant, init_wyoming_handle: ConfigEntry
|
|
) -> None:
|
|
"""Test when an intent is not handled."""
|
|
agent_id = "conversation.test_handle"
|
|
|
|
with patch(
|
|
"homeassistant.components.wyoming.conversation.AsyncTcpClient",
|
|
MockAsyncTcpClient([NotHandled(text="failure").event()]),
|
|
):
|
|
result = await conversation.async_converse(
|
|
hass=hass,
|
|
text="test text",
|
|
conversation_id=None,
|
|
context=Context(),
|
|
language=hass.config.language,
|
|
agent_id=agent_id,
|
|
)
|
|
|
|
assert result.response.response_type == intent.IntentResponseType.ERROR
|
|
assert result.response.error_code == intent.IntentResponseErrorCode.FAILED_TO_HANDLE
|
|
assert result.response.speech, "No speech"
|
|
assert result.response.speech.get("plain", {}).get("speech") == "failure"
|
|
|
|
|
|
async def test_connection_lost(
|
|
hass: HomeAssistant, init_wyoming_handle: ConfigEntry, snapshot: SnapshotAssertion
|
|
) -> None:
|
|
"""Test connection to client is lost."""
|
|
agent_id = "conversation.test_handle"
|
|
|
|
with patch(
|
|
"homeassistant.components.wyoming.conversation.AsyncTcpClient",
|
|
MockAsyncTcpClient([None]),
|
|
):
|
|
result = await conversation.async_converse(
|
|
hass=hass,
|
|
text="test text",
|
|
conversation_id=None,
|
|
context=Context(),
|
|
language=hass.config.language,
|
|
agent_id=agent_id,
|
|
)
|
|
|
|
assert result.response.response_type == intent.IntentResponseType.ERROR
|
|
assert result.response.error_code == intent.IntentResponseErrorCode.UNKNOWN
|
|
assert result.response.speech, "No speech"
|
|
assert result.response.speech.get("plain", {}).get("speech") == snapshot()
|
|
|
|
|
|
async def test_oserror(
|
|
hass: HomeAssistant, init_wyoming_handle: ConfigEntry, snapshot: SnapshotAssertion
|
|
) -> None:
|
|
"""Test connection error."""
|
|
agent_id = "conversation.test_handle"
|
|
|
|
mock_client = MockAsyncTcpClient([Transcript("success").event()])
|
|
|
|
with (
|
|
patch(
|
|
"homeassistant.components.wyoming.conversation.AsyncTcpClient", mock_client
|
|
),
|
|
patch.object(mock_client, "read_event", side_effect=OSError("Boom!")),
|
|
):
|
|
result = await conversation.async_converse(
|
|
hass=hass,
|
|
text="test text",
|
|
conversation_id=None,
|
|
context=Context(),
|
|
language=hass.config.language,
|
|
agent_id=agent_id,
|
|
)
|
|
|
|
assert result.response.response_type == intent.IntentResponseType.ERROR
|
|
assert result.response.error_code == intent.IntentResponseErrorCode.UNKNOWN
|
|
assert result.response.speech, "No speech"
|
|
assert result.response.speech.get("plain", {}).get("speech") == snapshot()
|