Compare commits
1 commit
dev
...
go2rtc_log
Author | SHA1 | Date | |
---|---|---|---|
|
02b9ad7cd3 |
3 changed files with 45 additions and 15 deletions
|
@ -103,12 +103,15 @@ class Server:
|
||||||
"-c",
|
"-c",
|
||||||
config_file,
|
config_file,
|
||||||
stdout=asyncio.subprocess.PIPE,
|
stdout=asyncio.subprocess.PIPE,
|
||||||
stderr=asyncio.subprocess.STDOUT,
|
stderr=asyncio.subprocess.PIPE,
|
||||||
close_fds=False, # required for posix_spawn on CPython < 3.13
|
close_fds=False, # required for posix_spawn on CPython < 3.13
|
||||||
)
|
)
|
||||||
|
|
||||||
self._hass.async_create_background_task(
|
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:
|
try:
|
||||||
|
@ -125,7 +128,7 @@ class Server:
|
||||||
client = Go2RtcRestClient(async_get_clientsession(self._hass), HA_MANAGED_URL)
|
client = Go2RtcRestClient(async_get_clientsession(self._hass), HA_MANAGED_URL)
|
||||||
await client.validate_server_version()
|
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."""
|
"""Log the output of the process."""
|
||||||
assert process.stdout is not None
|
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:
|
if not self._startup_complete.is_set() and _SUCCESSFUL_BOOT_MESSAGE in msg:
|
||||||
self._startup_complete.set()
|
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:
|
def _log_server_output(self, loglevel: int) -> None:
|
||||||
"""Log captured process output, then clear the log buffer."""
|
"""Log captured process output, then clear the log buffer."""
|
||||||
for line in list(self._log_buffer): # Copy the deque to avoid mutation error
|
for line in list(self._log_buffer): # Copy the deque to avoid mutation error
|
||||||
|
|
|
@ -50,7 +50,15 @@ def server_stdout() -> list[str]:
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@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."""
|
"""Mock create_subprocess_exec."""
|
||||||
with patch(f"{GO2RTC_PATH}.server.asyncio.create_subprocess_exec") as mock_subproc:
|
with patch(f"{GO2RTC_PATH}.server.asyncio.create_subprocess_exec") as mock_subproc:
|
||||||
subproc = AsyncMock()
|
subproc = AsyncMock()
|
||||||
|
@ -61,6 +69,9 @@ def mock_create_subprocess(server_stdout: list[str]) -> Generator[AsyncMock]:
|
||||||
subproc.stdout.__aiter__.return_value = iter(
|
subproc.stdout.__aiter__.return_value = iter(
|
||||||
[f"{entry}\n".encode() for entry in server_stdout]
|
[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
|
mock_subproc.return_value = subproc
|
||||||
yield mock_subproc
|
yield mock_subproc
|
||||||
|
|
||||||
|
|
|
@ -39,39 +39,42 @@ def mock_tempfile() -> Generator[Mock]:
|
||||||
|
|
||||||
|
|
||||||
def _assert_server_output_logged(
|
def _assert_server_output_logged(
|
||||||
server_stdout: list[str],
|
server_output: list[str],
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
loglevel: int,
|
loglevel: int,
|
||||||
expect_logged: bool,
|
expect_logged: bool,
|
||||||
|
prefix: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Check server stdout was logged."""
|
"""Check server stdout was logged."""
|
||||||
for entry in server_stdout:
|
for entry in server_output:
|
||||||
assert (
|
assert (
|
||||||
(
|
(
|
||||||
"homeassistant.components.go2rtc.server",
|
"homeassistant.components.go2rtc.server",
|
||||||
loglevel,
|
loglevel,
|
||||||
entry,
|
prefix + entry,
|
||||||
)
|
)
|
||||||
in caplog.record_tuples
|
in caplog.record_tuples
|
||||||
) is expect_logged
|
) is expect_logged
|
||||||
|
|
||||||
|
|
||||||
def assert_server_output_logged(
|
def assert_server_output_logged(
|
||||||
server_stdout: list[str],
|
server_output: list[str],
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
loglevel: int,
|
loglevel: int,
|
||||||
|
prefix="",
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Check server stdout was logged."""
|
"""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(
|
def assert_server_output_not_logged(
|
||||||
server_stdout: list[str],
|
server_output: list[str],
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
loglevel: int,
|
loglevel: int,
|
||||||
|
prefix="",
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Check server stdout was logged."""
|
"""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(
|
@pytest.mark.parametrize(
|
||||||
|
@ -99,7 +102,7 @@ async def test_server_run_success(
|
||||||
"-c",
|
"-c",
|
||||||
"test.yaml",
|
"test.yaml",
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.STDOUT,
|
stderr=subprocess.PIPE,
|
||||||
close_fds=False,
|
close_fds=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -190,16 +193,18 @@ async def test_server_failed_to_start(
|
||||||
"-c",
|
"-c",
|
||||||
"test.yaml",
|
"test.yaml",
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.STDOUT,
|
stderr=subprocess.PIPE,
|
||||||
close_fds=False,
|
close_fds=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@patch("homeassistant.components.go2rtc.server._RESPAWN_COOLDOWN", 0)
|
@patch("homeassistant.components.go2rtc.server._RESPAWN_COOLDOWN", 0)
|
||||||
|
@pytest.mark.parametrize("server_stderr", [["exit with signal: terminated"]])
|
||||||
async def test_server_restart_process_exit(
|
async def test_server_restart_process_exit(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
mock_create_subprocess: AsyncMock,
|
mock_create_subprocess: AsyncMock,
|
||||||
server_stdout: list[str],
|
server_stdout: list[str],
|
||||||
|
server_stderr: list[str],
|
||||||
rest_client: AsyncMock,
|
rest_client: AsyncMock,
|
||||||
server: Server,
|
server: Server,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
@ -220,15 +225,17 @@ async def test_server_restart_process_exit(
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
mock_create_subprocess.assert_not_awaited()
|
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_stdout, caplog, logging.WARNING)
|
||||||
|
assert_server_output_not_logged(server_stderr, caplog, logging.WARNING, "STDERR ")
|
||||||
|
|
||||||
evt.set()
|
evt.set()
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
mock_create_subprocess.assert_awaited_once()
|
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_stdout, caplog, logging.WARNING)
|
||||||
|
assert_server_output_logged(server_stderr, caplog, logging.WARNING, "STDERR ")
|
||||||
|
|
||||||
await server.stop()
|
await server.stop()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue