diff --git a/homeassistant/setup.py b/homeassistant/setup.py index 82b7e1be039..70321d364b8 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -201,8 +201,12 @@ async def _async_setup_component( await asyncio.sleep(0) await hass.config_entries.flow.async_wait_init_flow_finish(domain) - for entry in hass.config_entries.async_entries(domain): - await entry.async_setup(hass, integration=integration) + await asyncio.gather( + *[ + entry.async_setup(hass, integration=integration) + for entry in hass.config_entries.async_entries(domain) + ] + ) hass.config.components.add(domain) diff --git a/tests/test_setup.py b/tests/test_setup.py index daa9c6e8406..a5e53861ef0 100644 --- a/tests/test_setup.py +++ b/tests/test_setup.py @@ -1,13 +1,15 @@ """Test component/platform setup.""" # pylint: disable=protected-access +import asyncio import logging import os import threading -from unittest import mock +from asynctest import Mock, patch +import pytest import voluptuous as vol -from homeassistant import setup +from homeassistant import config_entries, setup import homeassistant.config as config_util from homeassistant.const import EVENT_COMPONENT_LOADED, EVENT_HOMEASSISTANT_START from homeassistant.core import callback @@ -19,6 +21,7 @@ from homeassistant.helpers.config_validation import ( import homeassistant.util.dt as dt_util from tests.common import ( + MockConfigEntry, MockModule, MockPlatform, assert_setup_component, @@ -34,6 +37,19 @@ VERSION_PATH = os.path.join(get_test_config_dir(), config_util.VERSION_FILE) _LOGGER = logging.getLogger(__name__) +@pytest.fixture(autouse=True) +def mock_handlers(): + """Mock config flows.""" + + class MockFlowHandler(config_entries.ConfigFlow): + """Define a mock flow handler.""" + + VERSION = 1 + + with patch.dict(config_entries.HANDLERS, {"comp": MockFlowHandler}): + yield + + class TestSetup: """Test the bootstrap utils.""" @@ -239,7 +255,7 @@ class TestSetup: def test_component_not_double_initialized(self): """Test we do not set up a component twice.""" - mock_setup = mock.MagicMock(return_value=True) + mock_setup = Mock(return_value=True) mock_integration(self.hass, MockModule("comp", setup=mock_setup)) @@ -251,7 +267,7 @@ class TestSetup: assert setup.setup_component(self.hass, "comp", {}) assert not mock_setup.called - @mock.patch("homeassistant.util.package.install_package", return_value=False) + @patch("homeassistant.util.package.install_package", return_value=False) def test_component_not_installed_if_requirement_fails(self, mock_install): """Component setup should fail if requirement can't install.""" self.hass.config.skip_pip = False @@ -350,7 +366,7 @@ class TestSetup: {"valid": True}, extra=vol.PREVENT_EXTRA ) - mock_setup = mock.MagicMock(spec_set=True) + mock_setup = Mock(spec_set=True) mock_entity_platform( self.hass, @@ -469,7 +485,7 @@ async def test_component_cannot_depend_config(hass): async def test_component_warn_slow_setup(hass): """Warn we log when a component setup takes a long time.""" mock_integration(hass, MockModule("test_component1")) - with mock.patch.object(hass.loop, "call_later", mock.MagicMock()) as mock_call: + with patch.object(hass.loop, "call_later") as mock_call: result = await setup.async_setup_component(hass, "test_component1", {}) assert result assert mock_call.called @@ -488,7 +504,7 @@ async def test_platform_no_warn_slow(hass): mock_integration( hass, MockModule("test_component1", platform_schema=PLATFORM_SCHEMA) ) - with mock.patch.object(hass.loop, "call_later", mock.MagicMock()) as mock_call: + with patch.object(hass.loop, "call_later") as mock_call: result = await setup.async_setup_component(hass, "test_component1", {}) assert result assert not mock_call.called @@ -524,7 +540,30 @@ async def test_when_setup_already_loaded(hass): async def test_setup_import_blows_up(hass): """Test that we handle it correctly when importing integration blows up.""" - with mock.patch( + with patch( "homeassistant.loader.Integration.get_component", side_effect=ValueError ): assert not await setup.async_setup_component(hass, "sun", {}) + + +async def test_parallel_entry_setup(hass): + """Test config entries are set up in parallel.""" + MockConfigEntry(domain="comp", data={"value": 1}).add_to_hass(hass) + MockConfigEntry(domain="comp", data={"value": 2}).add_to_hass(hass) + + calls = [] + + async def mock_async_setup_entry(hass, entry): + """Mock setting up an entry.""" + calls.append(entry.data["value"]) + await asyncio.sleep(0) + calls.append(entry.data["value"]) + return True + + mock_integration( + hass, MockModule("comp", async_setup_entry=mock_async_setup_entry,), + ) + mock_entity_platform(hass, "config_flow.comp", None) + await setup.async_setup_component(hass, "comp", {}) + + assert calls == [1, 2, 1, 2]