Support multiple responses for service calls (#96370)
* add supports_response to platform entity services * support multiple entities in entity_service_call * support legacy response format for service calls * revert changes to script/shell_command * add back test for multiple responses for legacy service * remove SupportsResponse.ONLY_LEGACY * Apply suggestion Co-authored-by: Allen Porter <allen.porter@gmail.com> * test for entity_id remove None * revert Apply suggestion * return EntityServiceResponse from _handle_entity_call * Use asyncio.gather * EntityServiceResponse not Optional * styling --------- Co-authored-by: Allen Porter <allen.porter@gmail.com>
This commit is contained in:
parent
b86f3be510
commit
06c9719cd6
8 changed files with 277 additions and 37 deletions
|
@ -9,7 +9,14 @@ from unittest.mock import ANY, Mock, patch
|
|||
import pytest
|
||||
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, PERCENTAGE
|
||||
from homeassistant.core import CoreState, HomeAssistant, callback
|
||||
from homeassistant.core import (
|
||||
CoreState,
|
||||
HomeAssistant,
|
||||
ServiceCall,
|
||||
ServiceResponse,
|
||||
SupportsResponse,
|
||||
callback,
|
||||
)
|
||||
from homeassistant.exceptions import HomeAssistantError, PlatformNotReady
|
||||
from homeassistant.helpers import (
|
||||
device_registry as dr,
|
||||
|
@ -1491,6 +1498,121 @@ async def test_platforms_sharing_services(hass: HomeAssistant) -> None:
|
|||
assert entity2 in entities
|
||||
|
||||
|
||||
async def test_register_entity_service_response_data(hass: HomeAssistant) -> None:
|
||||
"""Test an entity service that does supports response data."""
|
||||
|
||||
async def generate_response(
|
||||
target: MockEntity, call: ServiceCall
|
||||
) -> ServiceResponse:
|
||||
assert call.return_response
|
||||
return {"response-key": "response-value"}
|
||||
|
||||
entity_platform = MockEntityPlatform(
|
||||
hass, domain="mock_integration", platform_name="mock_platform", platform=None
|
||||
)
|
||||
entity = MockEntity(entity_id="mock_integration.entity")
|
||||
await entity_platform.async_add_entities([entity])
|
||||
|
||||
entity_platform.async_register_entity_service(
|
||||
"hello",
|
||||
{"some": str},
|
||||
generate_response,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
response_data = await hass.services.async_call(
|
||||
"mock_platform",
|
||||
"hello",
|
||||
service_data={"some": "data"},
|
||||
target={"entity_id": [entity.entity_id]},
|
||||
blocking=True,
|
||||
return_response=True,
|
||||
)
|
||||
assert response_data == {
|
||||
"mock_integration.entity": {"response-key": "response-value"}
|
||||
}
|
||||
|
||||
|
||||
async def test_register_entity_service_response_data_multiple_matches(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test an entity service that does supports response data and matching many entities."""
|
||||
|
||||
async def generate_response(
|
||||
target: MockEntity, call: ServiceCall
|
||||
) -> ServiceResponse:
|
||||
assert call.return_response
|
||||
return {"response-key": f"response-value-{target.entity_id}"}
|
||||
|
||||
entity_platform = MockEntityPlatform(
|
||||
hass, domain="mock_integration", platform_name="mock_platform", platform=None
|
||||
)
|
||||
entity1 = MockEntity(entity_id="mock_integration.entity1")
|
||||
entity2 = MockEntity(entity_id="mock_integration.entity2")
|
||||
await entity_platform.async_add_entities([entity1, entity2])
|
||||
|
||||
entity_platform.async_register_entity_service(
|
||||
"hello",
|
||||
{"some": str},
|
||||
generate_response,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
|
||||
response_data = await hass.services.async_call(
|
||||
"mock_platform",
|
||||
"hello",
|
||||
service_data={"some": "data"},
|
||||
target={"entity_id": [entity1.entity_id, entity2.entity_id]},
|
||||
blocking=True,
|
||||
return_response=True,
|
||||
)
|
||||
assert response_data == {
|
||||
"mock_integration.entity1": {
|
||||
"response-key": "response-value-mock_integration.entity1"
|
||||
},
|
||||
"mock_integration.entity2": {
|
||||
"response-key": "response-value-mock_integration.entity2"
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
async def test_register_entity_service_response_data_multiple_matches_raises(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Test entity service response matching many entities raises."""
|
||||
|
||||
async def generate_response(
|
||||
target: MockEntity, call: ServiceCall
|
||||
) -> ServiceResponse:
|
||||
assert call.return_response
|
||||
if target.entity_id == "mock_integration.entity1":
|
||||
raise RuntimeError("Something went wrong")
|
||||
return {"response-key": f"response-value-{target.entity_id}"}
|
||||
|
||||
entity_platform = MockEntityPlatform(
|
||||
hass, domain="mock_integration", platform_name="mock_platform", platform=None
|
||||
)
|
||||
entity1 = MockEntity(entity_id="mock_integration.entity1")
|
||||
entity2 = MockEntity(entity_id="mock_integration.entity2")
|
||||
await entity_platform.async_add_entities([entity1, entity2])
|
||||
|
||||
entity_platform.async_register_entity_service(
|
||||
"hello",
|
||||
{"some": str},
|
||||
generate_response,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
with pytest.raises(RuntimeError, match="Something went wrong"):
|
||||
await hass.services.async_call(
|
||||
"mock_platform",
|
||||
"hello",
|
||||
service_data={"some": "data"},
|
||||
target={"entity_id": [entity1.entity_id, entity2.entity_id]},
|
||||
blocking=True,
|
||||
return_response=True,
|
||||
)
|
||||
|
||||
|
||||
async def test_invalid_entity_id(hass: HomeAssistant) -> None:
|
||||
"""Test specifying an invalid entity id."""
|
||||
platform = MockEntityPlatform(hass)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue