From 2df15360fd61ac282fe6e93a9cb992b10a821c5a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 29 Nov 2018 21:00:05 +0100 Subject: [PATCH] Fix race condition in group.set --- homeassistant/components/group/__init__.py | 9 ++++++++- tests/helpers/test_entity_component.py | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/group/__init__.py b/homeassistant/components/group/__init__.py index 4dd3571e69c2a6..15a3816c559e83 100644 --- a/homeassistant/components/group/__init__.py +++ b/homeassistant/components/group/__init__.py @@ -207,6 +207,13 @@ async def reload_service_handler(service): DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=RELOAD_SERVICE_SCHEMA) + service_lock = asyncio.Lock() + + async def locked_service_handler(service): + """Handle a service with an async lock.""" + async with service_lock: + await groups_service_handler(service) + async def groups_service_handler(service): """Handle dynamic group service functions.""" object_id = service.data[ATTR_OBJECT_ID] @@ -284,7 +291,7 @@ async def groups_service_handler(service): await component.async_remove_entity(entity_id) hass.services.async_register( - DOMAIN, SERVICE_SET, groups_service_handler, + DOMAIN, SERVICE_SET, locked_service_handler, schema=SET_SERVICE_SCHEMA) hass.services.async_register( diff --git a/tests/helpers/test_entity_component.py b/tests/helpers/test_entity_component.py index 2bef8c0b53e5cc..7562a38d268e7a 100644 --- a/tests/helpers/test_entity_component.py +++ b/tests/helpers/test_entity_component.py @@ -431,3 +431,24 @@ async def test_update_entity(hass): assert len(entity.async_update_ha_state.mock_calls) == 2 assert entity.async_update_ha_state.mock_calls[-1][1][0] is True + + +async def test_set_service_race(hass): + """Test race condition on setting service.""" + exception = False + + def async_loop_exception_handler(_, _2) -> None: + """Handle all exception inside the core loop.""" + nonlocal exception + exception = True + + hass.loop.set_exception_handler(async_loop_exception_handler) + + await async_setup_component(hass, 'group', {}) + component = EntityComponent(_LOGGER, DOMAIN, hass, group_name='yo') + + for i in range(2): + hass.async_create_task(component.async_add_entities([MockEntity()])) + + await hass.async_block_till_done() + assert not exception