mirror of
https://github.com/home-assistant/core.git
synced 2025-11-09 10:59:40 +00:00
Fix shutdown deadlock with run_callback_threadsafe (#45807)
This commit is contained in:
@@ -50,7 +50,8 @@ def test_fire_coroutine_threadsafe_from_inside_event_loop(
|
||||
def test_run_callback_threadsafe_from_inside_event_loop(mock_ident, _):
|
||||
"""Testing calling run_callback_threadsafe from inside an event loop."""
|
||||
callback = MagicMock()
|
||||
loop = MagicMock()
|
||||
|
||||
loop = Mock(spec=["call_soon_threadsafe"])
|
||||
|
||||
loop._thread_ident = None
|
||||
mock_ident.return_value = 5
|
||||
@@ -168,3 +169,45 @@ async def test_gather_with_concurrency():
|
||||
)
|
||||
|
||||
assert results == [2, 2, -1, -1]
|
||||
|
||||
|
||||
async def test_shutdown_run_callback_threadsafe(hass):
|
||||
"""Test we can shutdown run_callback_threadsafe."""
|
||||
hasync.shutdown_run_callback_threadsafe(hass.loop)
|
||||
callback = MagicMock()
|
||||
|
||||
with pytest.raises(RuntimeError):
|
||||
hasync.run_callback_threadsafe(hass.loop, callback)
|
||||
|
||||
|
||||
async def test_run_callback_threadsafe(hass):
|
||||
"""Test run_callback_threadsafe runs code in the event loop."""
|
||||
it_ran = False
|
||||
|
||||
def callback():
|
||||
nonlocal it_ran
|
||||
it_ran = True
|
||||
|
||||
assert hasync.run_callback_threadsafe(hass.loop, callback)
|
||||
assert it_ran is False
|
||||
|
||||
# Verify that async_block_till_done will flush
|
||||
# out the callback
|
||||
await hass.async_block_till_done()
|
||||
assert it_ran is True
|
||||
|
||||
|
||||
async def test_callback_is_always_scheduled(hass):
|
||||
"""Test run_callback_threadsafe always calls call_soon_threadsafe before checking for shutdown."""
|
||||
# We have to check the shutdown state AFTER the callback is scheduled otherwise
|
||||
# the function could continue on and the caller call `future.result()` after
|
||||
# the point in the main thread where callbacks are no longer run.
|
||||
|
||||
callback = MagicMock()
|
||||
hasync.shutdown_run_callback_threadsafe(hass.loop)
|
||||
|
||||
with patch.object(hass.loop, "call_soon_threadsafe") as mock_call_soon_threadsafe:
|
||||
with pytest.raises(RuntimeError):
|
||||
hasync.run_callback_threadsafe(hass.loop, callback)
|
||||
|
||||
mock_call_soon_threadsafe.assert_called_once()
|
||||
|
||||
Reference in New Issue
Block a user