Report error code in log when command fails (#74319)

This commit is contained in:
atlflyer 2022-07-02 09:58:08 -04:00 committed by GitHub
parent 255c3c5b9a
commit da11cef29a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 59 additions and 7 deletions

View file

@ -23,7 +23,11 @@ def call_shell_with_timeout(
return 0
except subprocess.CalledProcessError as proc_exception:
if log_return_code:
_LOGGER.error("Command failed: %s", command)
_LOGGER.error(
"Command failed (with return code %s): %s",
proc_exception.returncode,
command,
)
return proc_exception.returncode
except subprocess.TimeoutExpired:
_LOGGER.error("Timeout for command: %s", command)
@ -40,8 +44,10 @@ def check_output_or_log(command: str, timeout: int) -> str | None:
command, shell=True, timeout=timeout # nosec # shell by design
)
return return_value.strip().decode("utf-8")
except subprocess.CalledProcessError:
_LOGGER.error("Command failed: %s", command)
except subprocess.CalledProcessError as err:
_LOGGER.error(
"Command failed (with return code %s): %s", err.returncode, command
)
except subprocess.TimeoutExpired:
_LOGGER.error("Timeout for command: %s", command)
except subprocess.SubprocessError:

View file

@ -115,10 +115,13 @@ class CommandCover(CoverEntity):
"""Execute the actual commands."""
_LOGGER.info("Running command: %s", command)
success = call_shell_with_timeout(command, self._timeout) == 0
returncode = call_shell_with_timeout(command, self._timeout)
success = returncode == 0
if not success:
_LOGGER.error("Command failed: %s", command)
_LOGGER.error(
"Command failed (with return code %s): %s", returncode, command
)
return success

View file

@ -57,7 +57,11 @@ class CommandLineNotificationService(BaseNotificationService):
try:
proc.communicate(input=message, timeout=self._timeout)
if proc.returncode != 0:
_LOGGER.error("Command failed: %s", self.command)
_LOGGER.error(
"Command failed (with return code %s): %s",
proc.returncode,
self.command,
)
except subprocess.TimeoutExpired:
_LOGGER.error("Timeout for command: %s", self.command)
kill_subprocess(proc)

View file

@ -3,6 +3,8 @@ from __future__ import annotations
from typing import Any
from pytest import LogCaptureFixture
from homeassistant import setup
from homeassistant.components.binary_sensor import DOMAIN
from homeassistant.const import STATE_OFF, STATE_ON
@ -112,3 +114,14 @@ async def test_unique_id(hass: HomeAssistant) -> None:
)
is not None
)
async def test_return_code(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:
"""Test setting the state with a template."""
await setup_test_entity(
hass,
{
"command": "exit 33",
},
)
assert "return code 33" in caplog.text

View file

@ -155,7 +155,7 @@ async def test_reload(hass: HomeAssistant) -> None:
async def test_move_cover_failure(
caplog: LogCaptureFixture, hass: HomeAssistant
) -> None:
"""Test with state value."""
"""Test command failure."""
await setup_test_entity(
hass,
@ -165,6 +165,7 @@ async def test_move_cover_failure(
DOMAIN, SERVICE_OPEN_COVER, {ATTR_ENTITY_ID: "cover.test"}, blocking=True
)
assert "Command failed" in caplog.text
assert "return code 1" in caplog.text
async def test_unique_id(hass: HomeAssistant) -> None:

View file

@ -77,6 +77,7 @@ async def test_error_for_none_zero_exit_code(
DOMAIN, "test", {"message": "error"}, blocking=True
)
assert "Command failed" in caplog.text
assert "return code 1" in caplog.text
async def test_timeout(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:

View file

@ -128,6 +128,17 @@ async def test_bad_command(hass: HomeAssistant) -> None:
assert entity_state.state == "unknown"
async def test_return_code(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:
"""Test that an error return code is logged."""
await setup_test_entities(
hass,
{
"command": "exit 33",
},
)
assert "return code 33" in caplog.text
async def test_update_with_json_attrs(hass: HomeAssistant) -> None:
"""Test attributes get extracted from a JSON result."""
await setup_test_entities(

View file

@ -419,3 +419,16 @@ async def test_unique_id(hass: HomeAssistant) -> None:
ent_reg.async_get_entity_id("switch", "command_line", "not-so-unique-anymore")
is not None
)
async def test_command_failure(caplog: LogCaptureFixture, hass: HomeAssistant) -> None:
"""Test command failure."""
await setup_test_entity(
hass,
{"test": {"command_off": "exit 33"}},
)
await hass.services.async_call(
DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: "switch.test"}, blocking=True
)
assert "return code 33" in caplog.text