Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
Erik
02b9ad7cd3 Log go2rtc stderr output 2024-11-05 14:38:23 +01:00
3 changed files with 45 additions and 15 deletions

View file

@ -103,12 +103,15 @@ class Server:
"-c",
config_file,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT,
stderr=asyncio.subprocess.PIPE,
close_fds=False, # required for posix_spawn on CPython < 3.13
)
self._hass.async_create_background_task(
self._log_output(self._process), "Go2rtc log output"
self._log_output_stdout(self._process), "Go2rtc log stdout output"
)
self._hass.async_create_background_task(
self._log_output_stderr(self._process), "Go2rtc log stderr output"
)
try:
@ -125,7 +128,7 @@ class Server:
client = Go2RtcRestClient(async_get_clientsession(self._hass), HA_MANAGED_URL)
await client.validate_server_version()
async def _log_output(self, process: asyncio.subprocess.Process) -> None:
async def _log_output_stdout(self, process: asyncio.subprocess.Process) -> None:
"""Log the output of the process."""
assert process.stdout is not None
@ -136,6 +139,15 @@ class Server:
if not self._startup_complete.is_set() and _SUCCESSFUL_BOOT_MESSAGE in msg:
self._startup_complete.set()
async def _log_output_stderr(self, process: asyncio.subprocess.Process) -> None:
"""Log the output of the process."""
assert process.stderr is not None
async for line in process.stderr:
msg = "STDERR " + line[:-1].decode().strip()
self._log_buffer.append(msg)
_LOGGER.debug(msg)
def _log_server_output(self, loglevel: int) -> None:
"""Log captured process output, then clear the log buffer."""
for line in list(self._log_buffer): # Copy the deque to avoid mutation error

View file

@ -50,7 +50,15 @@ def server_stdout() -> list[str]:
@pytest.fixture
def mock_create_subprocess(server_stdout: list[str]) -> Generator[AsyncMock]:
def server_stderr() -> list[str]:
"""Server stderr lines."""
return []
@pytest.fixture
def mock_create_subprocess(
server_stdout: list[str], server_stderr: list[str]
) -> Generator[AsyncMock]:
"""Mock create_subprocess_exec."""
with patch(f"{GO2RTC_PATH}.server.asyncio.create_subprocess_exec") as mock_subproc:
subproc = AsyncMock()
@ -61,6 +69,9 @@ def mock_create_subprocess(server_stdout: list[str]) -> Generator[AsyncMock]:
subproc.stdout.__aiter__.return_value = iter(
[f"{entry}\n".encode() for entry in server_stdout]
)
subproc.stderr.__aiter__.return_value = iter(
[f"{entry}\n".encode() for entry in server_stderr]
)
mock_subproc.return_value = subproc
yield mock_subproc

View file

@ -39,39 +39,42 @@ def mock_tempfile() -> Generator[Mock]:
def _assert_server_output_logged(
server_stdout: list[str],
server_output: list[str],
caplog: pytest.LogCaptureFixture,
loglevel: int,
expect_logged: bool,
prefix: str,
) -> None:
"""Check server stdout was logged."""
for entry in server_stdout:
for entry in server_output:
assert (
(
"homeassistant.components.go2rtc.server",
loglevel,
entry,
prefix + entry,
)
in caplog.record_tuples
) is expect_logged
def assert_server_output_logged(
server_stdout: list[str],
server_output: list[str],
caplog: pytest.LogCaptureFixture,
loglevel: int,
prefix="",
) -> None:
"""Check server stdout was logged."""
_assert_server_output_logged(server_stdout, caplog, loglevel, True)
_assert_server_output_logged(server_output, caplog, loglevel, True, prefix)
def assert_server_output_not_logged(
server_stdout: list[str],
server_output: list[str],
caplog: pytest.LogCaptureFixture,
loglevel: int,
prefix="",
) -> None:
"""Check server stdout was logged."""
_assert_server_output_logged(server_stdout, caplog, loglevel, False)
_assert_server_output_logged(server_output, caplog, loglevel, False, prefix)
@pytest.mark.parametrize(
@ -99,7 +102,7 @@ async def test_server_run_success(
"-c",
"test.yaml",
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
stderr=subprocess.PIPE,
close_fds=False,
)
@ -190,16 +193,18 @@ async def test_server_failed_to_start(
"-c",
"test.yaml",
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
stderr=subprocess.PIPE,
close_fds=False,
)
@patch("homeassistant.components.go2rtc.server._RESPAWN_COOLDOWN", 0)
@pytest.mark.parametrize("server_stderr", [["exit with signal: terminated"]])
async def test_server_restart_process_exit(
hass: HomeAssistant,
mock_create_subprocess: AsyncMock,
server_stdout: list[str],
server_stderr: list[str],
rest_client: AsyncMock,
server: Server,
caplog: pytest.LogCaptureFixture,
@ -220,15 +225,17 @@ async def test_server_restart_process_exit(
await hass.async_block_till_done()
mock_create_subprocess.assert_not_awaited()
# Verify go2rtc binary stdout was not yet logged with warning level
# Verify go2rtc binary output was not yet logged with warning level
assert_server_output_not_logged(server_stdout, caplog, logging.WARNING)
assert_server_output_not_logged(server_stderr, caplog, logging.WARNING, "STDERR ")
evt.set()
await asyncio.sleep(0.1)
mock_create_subprocess.assert_awaited_once()
# Verify go2rtc binary stdout was logged with warning level
# Verify go2rtc binary output was logged with warning level
assert_server_output_logged(server_stdout, caplog, logging.WARNING)
assert_server_output_logged(server_stderr, caplog, logging.WARNING, "STDERR ")
await server.stop()