Log directory blocking I/O functions that run in the event loop (#118529)
* Log directory I/O functions that run in the event loop * tests
This commit is contained in:
parent
1fef4fa1f6
commit
6656f7d6b9
2 changed files with 71 additions and 0 deletions
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
import builtins
|
import builtins
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
import glob
|
||||||
from http.client import HTTPConnection
|
from http.client import HTTPConnection
|
||||||
import importlib
|
import importlib
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
@ -59,8 +61,22 @@ def enable() -> None:
|
||||||
loop_thread_id=loop_thread_id,
|
loop_thread_id=loop_thread_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
glob.glob = protect_loop(
|
||||||
|
glob.glob, strict_core=False, strict=False, loop_thread_id=loop_thread_id
|
||||||
|
)
|
||||||
|
glob.iglob = protect_loop(
|
||||||
|
glob.iglob, strict_core=False, strict=False, loop_thread_id=loop_thread_id
|
||||||
|
)
|
||||||
|
|
||||||
if not _IN_TESTS:
|
if not _IN_TESTS:
|
||||||
# Prevent files being opened inside the event loop
|
# Prevent files being opened inside the event loop
|
||||||
|
os.listdir = protect_loop( # type: ignore[assignment]
|
||||||
|
os.listdir, strict_core=False, strict=False, loop_thread_id=loop_thread_id
|
||||||
|
)
|
||||||
|
os.scandir = protect_loop( # type: ignore[assignment]
|
||||||
|
os.scandir, strict_core=False, strict=False, loop_thread_id=loop_thread_id
|
||||||
|
)
|
||||||
|
|
||||||
builtins.open = protect_loop( # type: ignore[assignment]
|
builtins.open = protect_loop( # type: ignore[assignment]
|
||||||
builtins.open,
|
builtins.open,
|
||||||
strict_core=False,
|
strict_core=False,
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
"""Tests for async util methods from Python source."""
|
"""Tests for async util methods from Python source."""
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import glob
|
||||||
import importlib
|
import importlib
|
||||||
|
import os
|
||||||
from pathlib import Path, PurePosixPath
|
from pathlib import Path, PurePosixPath
|
||||||
import time
|
import time
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
@ -10,6 +12,7 @@ from unittest.mock import Mock, patch
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant import block_async_io
|
from homeassistant import block_async_io
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from tests.common import extract_stack_to_frame
|
from tests.common import extract_stack_to_frame
|
||||||
|
|
||||||
|
@ -235,3 +238,55 @@ async def test_protect_open_path(path: Any, caplog: pytest.LogCaptureFixture) ->
|
||||||
open(path).close()
|
open(path).close()
|
||||||
|
|
||||||
assert "Detected blocking call to open with args" in caplog.text
|
assert "Detected blocking call to open with args" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
async def test_protect_loop_glob(
|
||||||
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||||
|
) -> None:
|
||||||
|
"""Test glob calls in the loop are logged."""
|
||||||
|
block_async_io.enable()
|
||||||
|
glob.glob("/dev/null")
|
||||||
|
assert "Detected blocking call to glob with args" in caplog.text
|
||||||
|
caplog.clear()
|
||||||
|
await hass.async_add_executor_job(glob.glob, "/dev/null")
|
||||||
|
assert "Detected blocking call to glob with args" not in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
async def test_protect_loop_iglob(
|
||||||
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||||
|
) -> None:
|
||||||
|
"""Test iglob calls in the loop are logged."""
|
||||||
|
block_async_io.enable()
|
||||||
|
glob.iglob("/dev/null")
|
||||||
|
assert "Detected blocking call to iglob with args" in caplog.text
|
||||||
|
caplog.clear()
|
||||||
|
await hass.async_add_executor_job(glob.iglob, "/dev/null")
|
||||||
|
assert "Detected blocking call to iglob with args" not in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
async def test_protect_loop_scandir(
|
||||||
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||||
|
) -> None:
|
||||||
|
"""Test glob calls in the loop are logged."""
|
||||||
|
block_async_io.enable()
|
||||||
|
with contextlib.suppress(FileNotFoundError):
|
||||||
|
os.scandir("/path/that/does/not/exists")
|
||||||
|
assert "Detected blocking call to scandir with args" in caplog.text
|
||||||
|
caplog.clear()
|
||||||
|
with contextlib.suppress(FileNotFoundError):
|
||||||
|
await hass.async_add_executor_job(os.scandir, "/path/that/does/not/exists")
|
||||||
|
assert "Detected blocking call to listdir with args" not in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
async def test_protect_loop_listdir(
|
||||||
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||||
|
) -> None:
|
||||||
|
"""Test listdir calls in the loop are logged."""
|
||||||
|
block_async_io.enable()
|
||||||
|
with contextlib.suppress(FileNotFoundError):
|
||||||
|
os.listdir("/path/that/does/not/exists")
|
||||||
|
assert "Detected blocking call to listdir with args" in caplog.text
|
||||||
|
caplog.clear()
|
||||||
|
with contextlib.suppress(FileNotFoundError):
|
||||||
|
await hass.async_add_executor_job(os.listdir, "/path/that/does/not/exists")
|
||||||
|
assert "Detected blocking call to listdir with args" not in caplog.text
|
||||||
|
|
Loading…
Add table
Reference in a new issue