From 1c2bce92927cd9354d894f3572b7a14d8edcd6f3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 20 Feb 2020 08:51:00 -0800 Subject: [PATCH] Fix recursion bug (#32009) * Fix recursion bug * Remove shield --- homeassistant/components/homeassistant/__init__.py | 12 +++++++++++- tests/components/homeassistant/test_init.py | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/homeassistant/__init__.py b/homeassistant/components/homeassistant/__init__.py index 17ab9ba3b44..7a0ae33345a 100644 --- a/homeassistant/components/homeassistant/__init__.py +++ b/homeassistant/components/homeassistant/__init__.py @@ -55,6 +55,15 @@ async def async_setup(hass: ha.HomeAssistant, config: dict) -> Awaitable[bool]: tasks = [] for domain, ent_ids in by_domain: + # This leads to endless loop. + if domain == DOMAIN: + _LOGGER.warning( + "Called service homeassistant.%s with invalid entity IDs %s", + service.service, + ", ".join(ent_ids), + ) + continue + # We want to block for all calls and only return when all calls # have been processed. If a service does not exist it causes a 10 # second delay while we're blocking waiting for a response. @@ -73,7 +82,8 @@ async def async_setup(hass: ha.HomeAssistant, config: dict) -> Awaitable[bool]: hass.services.async_call(domain, service.service, data, blocking) ) - await asyncio.wait(tasks) + if tasks: + await asyncio.gather(*tasks) service_schema = vol.Schema({ATTR_ENTITY_ID: cv.entity_ids}, extra=vol.ALLOW_EXTRA) diff --git a/tests/components/homeassistant/test_init.py b/tests/components/homeassistant/test_init.py index 0f7dc7ed309..38a76b7c3fb 100644 --- a/tests/components/homeassistant/test_init.py +++ b/tests/components/homeassistant/test_init.py @@ -372,3 +372,17 @@ async def test_turn_on_off_toggle_schema(hass, hass_read_only_user): context=ha.Context(user_id=hass_read_only_user.id), blocking=True, ) + + +async def test_not_allowing_recursion(hass, caplog): + """Test we do not allow recursion.""" + await async_setup_component(hass, "homeassistant", {}) + + for service in SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE: + await hass.services.async_call( + ha.DOMAIN, service, {"entity_id": "homeassistant.light"}, blocking=True, + ) + assert ( + f"Called service homeassistant.{service} with invalid entity IDs homeassistant.light" + in caplog.text + ), service