mirror of
https://github.com/home-assistant/core.git
synced 2026-03-04 14:57:07 +01:00
Compare commits
3 Commits
dev
...
synesthesi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d47bed74d | ||
|
|
cd4db314cd | ||
|
|
5b2e0e2a4f |
@@ -627,13 +627,17 @@ class IntentHandleView(http.HomeAssistantView):
|
||||
{
|
||||
vol.Required("name"): cv.string,
|
||||
vol.Optional("data"): vol.Schema({cv.string: object}),
|
||||
vol.Optional("language"): cv.string,
|
||||
vol.Optional("assistant"): vol.Any(cv.string, None),
|
||||
vol.Optional("device_id"): vol.Any(cv.string, None),
|
||||
vol.Optional("satellite_id"): vol.Any(cv.string, None),
|
||||
}
|
||||
)
|
||||
)
|
||||
async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response:
|
||||
"""Handle intent with name/data."""
|
||||
hass = request.app[http.KEY_HASS]
|
||||
language = hass.config.language
|
||||
language = data.get("language", hass.config.language)
|
||||
|
||||
try:
|
||||
intent_name = data["name"]
|
||||
@@ -641,14 +645,21 @@ class IntentHandleView(http.HomeAssistantView):
|
||||
key: {"value": value} for key, value in data.get("data", {}).items()
|
||||
}
|
||||
intent_result = await intent.async_handle(
|
||||
hass, DOMAIN, intent_name, slots, "", self.context(request)
|
||||
hass,
|
||||
DOMAIN,
|
||||
intent_name,
|
||||
slots,
|
||||
"",
|
||||
self.context(request),
|
||||
language=language,
|
||||
assistant=data.get("assistant"),
|
||||
device_id=data.get("device_id"),
|
||||
satellite_id=data.get("satellite_id"),
|
||||
)
|
||||
except (intent.IntentHandleError, intent.MatchFailedError) as err:
|
||||
intent_result = intent.IntentResponse(language=language)
|
||||
intent_result.async_set_speech(str(err))
|
||||
|
||||
if intent_result is None:
|
||||
intent_result = intent.IntentResponse(language=language) # type: ignore[unreachable]
|
||||
intent_result.async_set_speech("Sorry, I couldn't handle that")
|
||||
intent_result.async_set_error(
|
||||
intent.IntentResponseErrorCode.FAILED_TO_HANDLE, str(err)
|
||||
)
|
||||
|
||||
return self.json(intent_result)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Iterable
|
||||
import dataclasses
|
||||
from dataclasses import dataclass, field
|
||||
import logging
|
||||
import time
|
||||
@@ -481,7 +482,9 @@ class MediaSetVolumeRelativeHandler(intent.IntentHandler):
|
||||
result=intent.MatchTargetsResult(
|
||||
is_match=False, no_match_reason=intent.MatchFailedReason.STATE
|
||||
),
|
||||
constraints=match_constraints,
|
||||
constraints=dataclasses.replace(
|
||||
match_constraints, states=[MediaPlayerState.PLAYING]
|
||||
),
|
||||
preferences=match_preferences,
|
||||
)
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components import conversation
|
||||
from homeassistant.components.button import SERVICE_PRESS
|
||||
from homeassistant.components.cover import (
|
||||
DOMAIN as COVER_DOMAIN,
|
||||
@@ -12,6 +13,7 @@ from homeassistant.components.cover import (
|
||||
SERVICE_STOP_COVER,
|
||||
CoverState,
|
||||
)
|
||||
from homeassistant.components.homeassistant.exposed_entities import async_expose_entity
|
||||
from homeassistant.components.lock import SERVICE_LOCK, SERVICE_UNLOCK
|
||||
from homeassistant.components.valve import (
|
||||
DOMAIN as VALVE_DOMAIN,
|
||||
@@ -82,6 +84,70 @@ async def test_http_handle_intent(
|
||||
}
|
||||
},
|
||||
"language": hass.config.language,
|
||||
"response_type": intent.IntentResponseType.ACTION_DONE.value,
|
||||
"data": {"targets": [], "success": [], "failed": []},
|
||||
}
|
||||
|
||||
|
||||
async def test_http_language_device_satellite_id(
|
||||
hass: HomeAssistant, hass_client: ClientSessionGenerator, hass_admin_user: MockUser
|
||||
) -> None:
|
||||
"""Test handle intent with language, device id, and satellite id."""
|
||||
device_id = "test-device-id"
|
||||
satellite_id = "test-satellite-id"
|
||||
language = "en-GB"
|
||||
|
||||
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.context.user_id == hass_admin_user.id
|
||||
assert intent_obj.device_id == device_id
|
||||
assert intent_obj.satellite_id == satellite_id
|
||||
assert intent_obj.language == language
|
||||
|
||||
response = intent_obj.create_response()
|
||||
response.async_set_speech("Test response")
|
||||
response.async_set_speech_slots({"slot1": "value 1", "slot2": 2})
|
||||
return response
|
||||
|
||||
intent.async_register(hass, TestIntentHandler())
|
||||
|
||||
result = await async_setup_component(hass, "intent", {})
|
||||
assert result
|
||||
|
||||
client = await hass_client()
|
||||
resp = await client.post(
|
||||
"/api/intent/handle",
|
||||
json={
|
||||
"name": "TestIntent",
|
||||
"language": language,
|
||||
"device_id": device_id,
|
||||
"satellite_id": satellite_id,
|
||||
},
|
||||
)
|
||||
|
||||
assert resp.status == 200
|
||||
data = await resp.json()
|
||||
|
||||
# Verify language, device id, and satellite id were passed through.
|
||||
# Also check speech slots.
|
||||
assert data == {
|
||||
"card": {},
|
||||
"speech": {
|
||||
"plain": {
|
||||
"extra_data": None,
|
||||
"speech": "Test response",
|
||||
}
|
||||
},
|
||||
"speech_slots": {
|
||||
"slot1": "value 1",
|
||||
"slot2": 2,
|
||||
},
|
||||
"language": language,
|
||||
"response_type": "action_done",
|
||||
"data": {"targets": [], "success": [], "failed": []},
|
||||
}
|
||||
@@ -113,6 +179,60 @@ async def test_http_handle_intent_match_failure(
|
||||
assert "DUPLICATE_NAME" in data["speech"]["plain"]["speech"]
|
||||
|
||||
|
||||
async def test_http_assistant(
|
||||
hass: HomeAssistant, hass_client: ClientSessionGenerator, hass_admin_user: MockUser
|
||||
) -> None:
|
||||
"""Test handle intent only targets exposed entities with 'assistant' set."""
|
||||
|
||||
assert await async_setup_component(hass, "homeassistant", {})
|
||||
assert await async_setup_component(hass, "intent", {})
|
||||
|
||||
hass.states.async_set(
|
||||
"cover.garage_door_1", "closed", {ATTR_FRIENDLY_NAME: "Garage Door 1"}
|
||||
)
|
||||
async_mock_service(hass, "cover", SERVICE_OPEN_COVER)
|
||||
|
||||
client = await hass_client()
|
||||
|
||||
# Exposed
|
||||
async_expose_entity(hass, conversation.DOMAIN, "cover.garage_door_1", True)
|
||||
resp = await client.post(
|
||||
"/api/intent/handle",
|
||||
json={
|
||||
"name": "HassTurnOn",
|
||||
"data": {"name": "Garage Door 1"},
|
||||
"assistant": conversation.DOMAIN,
|
||||
},
|
||||
)
|
||||
assert resp.status == 200
|
||||
data = await resp.json()
|
||||
assert data["response_type"] == intent.IntentResponseType.ACTION_DONE.value
|
||||
|
||||
# Not exposed
|
||||
async_expose_entity(hass, conversation.DOMAIN, "cover.garage_door_1", False)
|
||||
resp = await client.post(
|
||||
"/api/intent/handle",
|
||||
json={
|
||||
"name": "HassTurnOn",
|
||||
"data": {"name": "Garage Door 1"},
|
||||
"assistant": conversation.DOMAIN,
|
||||
},
|
||||
)
|
||||
assert resp.status == 200
|
||||
data = await resp.json()
|
||||
assert data["response_type"] == intent.IntentResponseType.ERROR.value
|
||||
assert data["data"]["code"] == intent.IntentResponseErrorCode.FAILED_TO_HANDLE.value
|
||||
|
||||
# No assistant (exposure is irrelevant)
|
||||
resp = await client.post(
|
||||
"/api/intent/handle",
|
||||
json={"name": "HassTurnOn", "data": {"name": "Garage Door 1"}},
|
||||
)
|
||||
assert resp.status == 200
|
||||
data = await resp.json()
|
||||
assert data["response_type"] == intent.IntentResponseType.ACTION_DONE.value
|
||||
|
||||
|
||||
async def test_cover_intents_loading(hass: HomeAssistant) -> None:
|
||||
"""Test Cover Intents Loading."""
|
||||
assert await async_setup_component(hass, "intent", {})
|
||||
|
||||
@@ -78,13 +78,21 @@ async def test_pause_media_player_intent(hass: HomeAssistant) -> None:
|
||||
# Test if not playing
|
||||
hass.states.async_set(entity_id, STATE_IDLE, attributes=attributes)
|
||||
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
response = await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
media_player_intent.INTENT_MEDIA_PAUSE,
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.STATE
|
||||
assert match_failed_error.constraints.states
|
||||
assert list(match_failed_error.constraints.states) == [MediaPlayerState.PLAYING]
|
||||
|
||||
# Test feature not supported
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
@@ -92,13 +100,20 @@ async def test_pause_media_player_intent(hass: HomeAssistant) -> None:
|
||||
attributes={ATTR_SUPPORTED_FEATURES: MediaPlayerEntityFeature(0)},
|
||||
)
|
||||
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
response = await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
media_player_intent.INTENT_MEDIA_PAUSE,
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.FEATURE
|
||||
assert match_failed_error.constraints.features == MediaPlayerEntityFeature.PAUSE
|
||||
|
||||
|
||||
async def test_unpause_media_player_intent(hass: HomeAssistant) -> None:
|
||||
"""Test HassMediaUnpause intent for media players."""
|
||||
@@ -151,13 +166,21 @@ async def test_next_media_player_intent(hass: HomeAssistant) -> None:
|
||||
# Test if not playing
|
||||
hass.states.async_set(entity_id, STATE_IDLE, attributes=attributes)
|
||||
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
response = await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
media_player_intent.INTENT_MEDIA_NEXT,
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.STATE
|
||||
assert match_failed_error.constraints.states
|
||||
assert list(match_failed_error.constraints.states) == [MediaPlayerState.PLAYING]
|
||||
|
||||
# Test feature not supported
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
@@ -165,7 +188,7 @@ async def test_next_media_player_intent(hass: HomeAssistant) -> None:
|
||||
attributes={ATTR_SUPPORTED_FEATURES: MediaPlayerEntityFeature(0)},
|
||||
)
|
||||
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
response = await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
@@ -173,6 +196,15 @@ async def test_next_media_player_intent(hass: HomeAssistant) -> None:
|
||||
{"name": {"value": "test media player"}},
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.FEATURE
|
||||
assert (
|
||||
match_failed_error.constraints.features == MediaPlayerEntityFeature.NEXT_TRACK
|
||||
)
|
||||
|
||||
|
||||
async def test_previous_media_player_intent(hass: HomeAssistant) -> None:
|
||||
"""Test HassMediaPrevious intent for media players."""
|
||||
@@ -202,13 +234,21 @@ async def test_previous_media_player_intent(hass: HomeAssistant) -> None:
|
||||
# Test if not playing
|
||||
hass.states.async_set(entity_id, STATE_IDLE, attributes=attributes)
|
||||
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
response = await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
media_player_intent.INTENT_MEDIA_PREVIOUS,
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.STATE
|
||||
assert match_failed_error.constraints.states
|
||||
assert list(match_failed_error.constraints.states) == [MediaPlayerState.PLAYING]
|
||||
|
||||
# Test feature not supported
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
@@ -216,7 +256,7 @@ async def test_previous_media_player_intent(hass: HomeAssistant) -> None:
|
||||
attributes={ATTR_SUPPORTED_FEATURES: MediaPlayerEntityFeature(0)},
|
||||
)
|
||||
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
response = await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
@@ -224,6 +264,16 @@ async def test_previous_media_player_intent(hass: HomeAssistant) -> None:
|
||||
{"name": {"value": "test media player"}},
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.FEATURE
|
||||
assert (
|
||||
match_failed_error.constraints.features
|
||||
== MediaPlayerEntityFeature.PREVIOUS_TRACK
|
||||
)
|
||||
|
||||
|
||||
async def test_volume_media_player_intent(hass: HomeAssistant) -> None:
|
||||
"""Test HassSetVolume intent for media players."""
|
||||
@@ -257,7 +307,7 @@ async def test_volume_media_player_intent(hass: HomeAssistant) -> None:
|
||||
attributes={ATTR_SUPPORTED_FEATURES: MediaPlayerEntityFeature(0)},
|
||||
)
|
||||
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
response = await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
@@ -265,6 +315,15 @@ async def test_volume_media_player_intent(hass: HomeAssistant) -> None:
|
||||
{"volume_level": {"value": 50}},
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.FEATURE
|
||||
assert (
|
||||
match_failed_error.constraints.features == MediaPlayerEntityFeature.VOLUME_SET
|
||||
)
|
||||
|
||||
|
||||
async def test_media_player_mute_intent(hass: HomeAssistant) -> None:
|
||||
"""Test HassMediaPlayerMute intent for media players."""
|
||||
@@ -298,7 +357,7 @@ async def test_media_player_mute_intent(hass: HomeAssistant) -> None:
|
||||
attributes={ATTR_SUPPORTED_FEATURES: MediaPlayerEntityFeature(0)},
|
||||
)
|
||||
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
response = await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
@@ -306,6 +365,15 @@ async def test_media_player_mute_intent(hass: HomeAssistant) -> None:
|
||||
{},
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.FEATURE
|
||||
assert (
|
||||
match_failed_error.constraints.features == MediaPlayerEntityFeature.VOLUME_MUTE
|
||||
)
|
||||
|
||||
|
||||
async def test_media_player_unmute_intent(hass: HomeAssistant) -> None:
|
||||
"""Test HassMediaPlayerMute intent for media players."""
|
||||
@@ -339,7 +407,7 @@ async def test_media_player_unmute_intent(hass: HomeAssistant) -> None:
|
||||
attributes={ATTR_SUPPORTED_FEATURES: MediaPlayerEntityFeature(0)},
|
||||
)
|
||||
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
response = await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
@@ -347,6 +415,15 @@ async def test_media_player_unmute_intent(hass: HomeAssistant) -> None:
|
||||
{},
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.FEATURE
|
||||
assert (
|
||||
match_failed_error.constraints.features == MediaPlayerEntityFeature.VOLUME_MUTE
|
||||
)
|
||||
|
||||
|
||||
async def test_multiple_media_players(
|
||||
hass: HomeAssistant,
|
||||
@@ -462,7 +539,7 @@ async def test_multiple_media_players(
|
||||
# -----
|
||||
|
||||
# There are multiple TV's currently playing
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
response = await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
@@ -470,6 +547,16 @@ async def test_multiple_media_players(
|
||||
{"name": {"value": "TV"}},
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert (
|
||||
match_failed_error.result.no_match_reason
|
||||
== intent.MatchFailedReason.DUPLICATE_NAME
|
||||
)
|
||||
assert match_failed_error.result.no_match_name == "TV"
|
||||
|
||||
# Pause the upstairs TV
|
||||
calls = async_mock_service(hass, DOMAIN, SERVICE_MEDIA_PAUSE)
|
||||
response = await intent.async_handle(
|
||||
@@ -826,7 +913,7 @@ async def test_search_and_play_media_player_intent(hass: HomeAssistant) -> None:
|
||||
STATE_IDLE,
|
||||
attributes={},
|
||||
)
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
@@ -834,13 +921,23 @@ async def test_search_and_play_media_player_intent(hass: HomeAssistant) -> None:
|
||||
{"search_query": {"value": "test query"}},
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.FEATURE
|
||||
assert (
|
||||
match_failed_error.constraints.features
|
||||
== MediaPlayerEntityFeature.SEARCH_MEDIA | MediaPlayerEntityFeature.PLAY_MEDIA
|
||||
)
|
||||
|
||||
# Test feature not supported (missing SEARCH_MEDIA)
|
||||
hass.states.async_set(
|
||||
entity_id,
|
||||
STATE_IDLE,
|
||||
attributes={ATTR_SUPPORTED_FEATURES: MediaPlayerEntityFeature.PLAY_MEDIA},
|
||||
)
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
@@ -848,6 +945,16 @@ async def test_search_and_play_media_player_intent(hass: HomeAssistant) -> None:
|
||||
{"search_query": {"value": "test query"}},
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.FEATURE
|
||||
assert (
|
||||
match_failed_error.constraints.features
|
||||
== MediaPlayerEntityFeature.SEARCH_MEDIA | MediaPlayerEntityFeature.PLAY_MEDIA
|
||||
)
|
||||
|
||||
# Test play media service errors
|
||||
search_results.append(search_result_item)
|
||||
hass.states.async_set(
|
||||
@@ -862,7 +969,7 @@ async def test_search_and_play_media_player_intent(hass: HomeAssistant) -> None:
|
||||
SERVICE_PLAY_MEDIA,
|
||||
raise_exception=HomeAssistantError("Play failed"),
|
||||
)
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
@@ -870,6 +977,16 @@ async def test_search_and_play_media_player_intent(hass: HomeAssistant) -> None:
|
||||
{"search_query": {"value": "play error query"}},
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.FEATURE
|
||||
assert (
|
||||
match_failed_error.constraints.features
|
||||
== MediaPlayerEntityFeature.SEARCH_MEDIA | MediaPlayerEntityFeature.PLAY_MEDIA
|
||||
)
|
||||
|
||||
# Test search service error
|
||||
hass.states.async_set(entity_id, STATE_IDLE, attributes=attributes)
|
||||
async_mock_service(
|
||||
@@ -1105,7 +1222,7 @@ async def test_volume_relative_media_player_intent(
|
||||
attributes={ATTR_SUPPORTED_FEATURES: MediaPlayerEntityFeature.VOLUME_SET},
|
||||
)
|
||||
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
@@ -1113,6 +1230,14 @@ async def test_volume_relative_media_player_intent(
|
||||
{"volume_step": {"value": direction}},
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.STATE
|
||||
assert match_failed_error.constraints.states
|
||||
assert list(match_failed_error.constraints.states) == [MediaPlayerState.PLAYING]
|
||||
|
||||
# Test feature not supported
|
||||
for entity_id in (idle_entity.entity_id, playing_entity.entity_id):
|
||||
hass.states.async_set(
|
||||
@@ -1121,10 +1246,19 @@ async def test_volume_relative_media_player_intent(
|
||||
attributes={ATTR_SUPPORTED_FEATURES: MediaPlayerEntityFeature(0)},
|
||||
)
|
||||
|
||||
with pytest.raises(intent.MatchFailedError):
|
||||
with pytest.raises(intent.MatchFailedError) as error_wrapper:
|
||||
await intent.async_handle(
|
||||
hass,
|
||||
"test",
|
||||
media_player_intent.INTENT_SET_VOLUME_RELATIVE,
|
||||
{"volume_step": {"value": direction}},
|
||||
)
|
||||
|
||||
# Verify match failure reason and info
|
||||
match_failed_error = error_wrapper.value
|
||||
assert isinstance(match_failed_error, intent.MatchFailedError)
|
||||
assert not match_failed_error.result.is_match
|
||||
assert match_failed_error.result.no_match_reason == intent.MatchFailedReason.FEATURE
|
||||
assert (
|
||||
match_failed_error.constraints.features == MediaPlayerEntityFeature.VOLUME_SET
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user