mirror of
https://github.com/home-assistant/core.git
synced 2025-11-09 02:49:40 +00:00
Fallback to event loop import on deadlock (#111868)
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
"""Test to verify that we can load components."""
|
||||
import asyncio
|
||||
from unittest.mock import Mock, patch
|
||||
import sys
|
||||
from typing import Any
|
||||
from unittest.mock import MagicMock, Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -1033,3 +1035,161 @@ async def test_hass_components_use_reported(
|
||||
"Detected that custom integration 'test_integration_frame'"
|
||||
" accesses hass.components.http. This is deprecated"
|
||||
) in caplog.text
|
||||
|
||||
|
||||
async def test_async_get_component_deadlock_fallback(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Verify async_get_component fallback to importing in the event loop on deadlock."""
|
||||
executor_import_integration = _get_test_integration(
|
||||
hass, "executor_import", True, import_executor=True
|
||||
)
|
||||
assert executor_import_integration.import_executor is True
|
||||
module_mock = MagicMock()
|
||||
import_attempts = 0
|
||||
|
||||
def mock_import(module: str, *args: Any, **kwargs: Any) -> Any:
|
||||
nonlocal import_attempts
|
||||
if module == "homeassistant.components.executor_import":
|
||||
import_attempts += 1
|
||||
|
||||
if import_attempts == 1:
|
||||
# _DeadlockError inherits from RuntimeError
|
||||
raise RuntimeError(
|
||||
"Detected deadlock trying to import homeassistant.components.executor_import"
|
||||
)
|
||||
|
||||
return module_mock
|
||||
|
||||
assert "homeassistant.components.executor_import" not in sys.modules
|
||||
assert "custom_components.executor_import" not in sys.modules
|
||||
with patch("homeassistant.loader.importlib.import_module", mock_import):
|
||||
module = await executor_import_integration.async_get_component()
|
||||
|
||||
assert (
|
||||
"Detected deadlock trying to import homeassistant.components.executor_import"
|
||||
in caplog.text
|
||||
)
|
||||
assert "loaded_executor=False" in caplog.text
|
||||
assert module is module_mock
|
||||
|
||||
|
||||
async def test_async_get_component_raises_after_import_failure(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Verify async_get_component raises if we fail to import in both the executor and loop."""
|
||||
executor_import_integration = _get_test_integration(
|
||||
hass, "executor_import", True, import_executor=True
|
||||
)
|
||||
assert executor_import_integration.import_executor is True
|
||||
module_mock = MagicMock()
|
||||
import_attempts = 0
|
||||
|
||||
def mock_import(module: str, *args: Any, **kwargs: Any) -> Any:
|
||||
nonlocal import_attempts
|
||||
if module == "homeassistant.components.executor_import":
|
||||
import_attempts += 1
|
||||
|
||||
if import_attempts == 1:
|
||||
# _DeadlockError inherits from RuntimeError
|
||||
raise RuntimeError(
|
||||
"Detected deadlock trying to import homeassistant.components.executor_import"
|
||||
)
|
||||
|
||||
if import_attempts == 2:
|
||||
raise ImportError("Failed import homeassistant.components.executor_import")
|
||||
return module_mock
|
||||
|
||||
assert "homeassistant.components.executor_import" not in sys.modules
|
||||
assert "custom_components.executor_import" not in sys.modules
|
||||
with patch(
|
||||
"homeassistant.loader.importlib.import_module", mock_import
|
||||
), pytest.raises(ImportError):
|
||||
await executor_import_integration.async_get_component()
|
||||
|
||||
assert (
|
||||
"Detected deadlock trying to import homeassistant.components.executor_import"
|
||||
in caplog.text
|
||||
)
|
||||
assert "loaded_executor=False" not in caplog.text
|
||||
|
||||
|
||||
async def test_async_get_platform_deadlock_fallback(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Verify async_get_platform fallback to importing in the event loop on deadlock."""
|
||||
executor_import_integration = _get_test_integration(
|
||||
hass, "executor_import", True, import_executor=True
|
||||
)
|
||||
assert executor_import_integration.import_executor is True
|
||||
module_mock = MagicMock()
|
||||
import_attempts = 0
|
||||
|
||||
def mock_import(module: str, *args: Any, **kwargs: Any) -> Any:
|
||||
nonlocal import_attempts
|
||||
if module == "homeassistant.components.executor_import.config_flow":
|
||||
import_attempts += 1
|
||||
|
||||
if import_attempts == 1:
|
||||
# _DeadlockError inherits from RuntimeError
|
||||
raise RuntimeError(
|
||||
"Detected deadlock trying to import homeassistant.components.executor_import"
|
||||
)
|
||||
|
||||
return module_mock
|
||||
|
||||
assert "homeassistant.components.executor_import" not in sys.modules
|
||||
assert "custom_components.executor_import" not in sys.modules
|
||||
with patch("homeassistant.loader.importlib.import_module", mock_import):
|
||||
module = await executor_import_integration.async_get_platform("config_flow")
|
||||
|
||||
assert (
|
||||
"Detected deadlock trying to import homeassistant.components.executor_import"
|
||||
in caplog.text
|
||||
)
|
||||
assert "loaded_executor=False" in caplog.text
|
||||
assert module is module_mock
|
||||
|
||||
|
||||
async def test_async_get_platform_raises_after_import_failure(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Verify async_get_platform raises if we fail to import in both the executor and loop."""
|
||||
executor_import_integration = _get_test_integration(
|
||||
hass, "executor_import", True, import_executor=True
|
||||
)
|
||||
assert executor_import_integration.import_executor is True
|
||||
module_mock = MagicMock()
|
||||
import_attempts = 0
|
||||
|
||||
def mock_import(module: str, *args: Any, **kwargs: Any) -> Any:
|
||||
nonlocal import_attempts
|
||||
if module == "homeassistant.components.executor_import.config_flow":
|
||||
import_attempts += 1
|
||||
|
||||
if import_attempts == 1:
|
||||
# _DeadlockError inherits from RuntimeError
|
||||
raise RuntimeError(
|
||||
"Detected deadlock trying to import homeassistant.components.executor_import"
|
||||
)
|
||||
|
||||
if import_attempts == 2:
|
||||
# _DeadlockError inherits from RuntimeError
|
||||
raise ImportError(
|
||||
"Error trying to import homeassistant.components.executor_import"
|
||||
)
|
||||
|
||||
return module_mock
|
||||
|
||||
assert "homeassistant.components.executor_import" not in sys.modules
|
||||
assert "custom_components.executor_import" not in sys.modules
|
||||
with patch(
|
||||
"homeassistant.loader.importlib.import_module", mock_import
|
||||
), pytest.raises(ImportError):
|
||||
await executor_import_integration.async_get_platform("config_flow")
|
||||
|
||||
assert (
|
||||
"Detected deadlock trying to import homeassistant.components.executor_import"
|
||||
in caplog.text
|
||||
)
|
||||
assert "loaded_executor=False" not in caplog.text
|
||||
|
||||
Reference in New Issue
Block a user