1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-15 13:01:22 +01:00
Files
core/tests/components/command_line/test_notify.py
T
2026-05-04 20:59:28 +02:00

297 lines
8.4 KiB
Python

"""The tests for the command line notification platform."""
import os
from pathlib import Path
import subprocess
import tempfile
from unittest.mock import patch
import pytest
from homeassistant import setup
from homeassistant.components.command_line import DOMAIN
from homeassistant.components.notify import DOMAIN as NOTIFY_DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import issue_registry as ir
async def test_setup_platform_yaml(
hass: HomeAssistant, issue_registry: ir.IssueRegistry
) -> None:
"""Test setting up the platform with platform yaml."""
await setup.async_setup_component(
hass,
"notify",
{
"notify": {
"platform": "command_line",
"command": "echo 1",
"payload_on": "1",
"payload_off": "0",
}
},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 0
issue = issue_registry.async_get_issue(DOMAIN, "notify_platform_yaml_not_supported")
assert issue is not None
assert issue.severity == ir.IssueSeverity.ERROR
assert issue.translation_placeholders == {"platform": NOTIFY_DOMAIN}
@pytest.mark.parametrize(
"get_config",
[
{
"command_line": [
{
"notify": {
"command": "exit 0",
"name": "Test2",
}
}
]
}
],
)
async def test_setup_integration_yaml(
hass: HomeAssistant, load_yaml_integration: None
) -> None:
"""Test sensor setup."""
assert hass.services.has_service(NOTIFY_DOMAIN, "test2")
async def test_bad_config(hass: HomeAssistant) -> None:
"""Test set up the platform with bad/missing configuration."""
assert await setup.async_setup_component(
hass,
NOTIFY_DOMAIN,
{
NOTIFY_DOMAIN: [
{"platform": "command_line"},
]
},
)
await hass.async_block_till_done()
assert not hass.services.has_service(NOTIFY_DOMAIN, "test")
async def test_command_line_output(hass: HomeAssistant) -> None:
"""Test the command line output."""
with tempfile.TemporaryDirectory() as tempdirname:
filename = os.path.join(tempdirname, "message.txt")
message = "one, two, testing, testing"
await setup.async_setup_component(
hass,
DOMAIN,
{
"command_line": [
{
"notify": {
"command": f"cat > {filename}",
"name": "Test3",
}
}
]
},
)
await hass.async_block_till_done()
assert hass.services.has_service(NOTIFY_DOMAIN, "test3")
await hass.services.async_call(
NOTIFY_DOMAIN, "test3", {"message": message}, blocking=True
)
assert message == await hass.async_add_executor_job(Path(filename).read_text)
async def test_command_line_output_single_command(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test the command line output."""
await setup.async_setup_component(
hass,
DOMAIN,
{
"command_line": [
{
"notify": {
"command": "echo",
"name": "Test3",
}
}
]
},
)
await hass.async_block_till_done()
assert hass.services.has_service(NOTIFY_DOMAIN, "test3")
await hass.services.async_call(
NOTIFY_DOMAIN, "test3", {"message": "test message"}, blocking=True
)
assert "Running command: echo" in caplog.text
assert "Running with message: test message" in caplog.text
async def test_command_template(hass: HomeAssistant) -> None:
"""Test the command line output using template as command."""
with tempfile.TemporaryDirectory() as tempdirname:
filename = os.path.join(tempdirname, "message.txt")
message = "one, two, testing, testing"
hass.states.async_set("sensor.test_state", filename)
await setup.async_setup_component(
hass,
DOMAIN,
{
"command_line": [
{
"notify": {
"command": "cat > {{ states.sensor.test_state.state }}",
"name": "Test3",
}
}
]
},
)
await hass.async_block_till_done()
assert hass.services.has_service(NOTIFY_DOMAIN, "test3")
await hass.services.async_call(
NOTIFY_DOMAIN, "test3", {"message": message}, blocking=True
)
assert message == await hass.async_add_executor_job(Path(filename).read_text)
async def test_command_incorrect_template(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test the command line output using template as command which isn't working."""
message = "one, two, testing, testing"
await setup.async_setup_component(
hass,
DOMAIN,
{
"command_line": [
{
"notify": {
"command": "cat > {{ this template doesn't parse ",
"name": "Test3",
}
}
]
},
)
await hass.async_block_till_done()
assert hass.services.has_service(NOTIFY_DOMAIN, "test3")
await hass.services.async_call(
NOTIFY_DOMAIN, "test3", {"message": message}, blocking=True
)
assert (
"Error rendering command template: TemplateSyntaxError: expected token"
in caplog.text
)
@pytest.mark.parametrize(
"get_config",
[
{
"command_line": [
{
"notify": {
"command": "exit 1",
"name": "Test4",
}
}
]
}
],
)
async def test_error_for_none_zero_exit_code(
caplog: pytest.LogCaptureFixture, hass: HomeAssistant, load_yaml_integration: None
) -> None:
"""Test if an error is logged for non zero exit codes."""
await hass.services.async_call(
NOTIFY_DOMAIN, "test4", {"message": "error"}, blocking=True
)
assert "Command failed" in caplog.text
assert "return code 1" in caplog.text
@pytest.mark.parametrize(
"get_config",
[
{
"command_line": [
{
"notify": {
"command": "sleep 10000",
"command_timeout": 0.0000001,
"name": "Test5",
}
}
]
}
],
)
async def test_timeout(
caplog: pytest.LogCaptureFixture, hass: HomeAssistant, load_yaml_integration: None
) -> None:
"""Test blocking is not forever."""
await hass.services.async_call(
NOTIFY_DOMAIN, "test5", {"message": "error"}, blocking=True
)
assert "Timeout" in caplog.text
@pytest.mark.parametrize(
"get_config",
[
{
"command_line": [
{
"notify": {
"command": "exit 0",
"name": "Test6",
}
}
]
}
],
)
async def test_subprocess_exceptions(
caplog: pytest.LogCaptureFixture, hass: HomeAssistant, load_yaml_integration: None
) -> None:
"""Test that notify subprocess exceptions are handled correctly."""
with patch(
"homeassistant.components.command_line.notify.subprocess.Popen"
) as check_output:
check_output.return_value.__enter__ = check_output
check_output.return_value.communicate.side_effect = [
subprocess.TimeoutExpired("cmd", 10),
None,
subprocess.SubprocessError(),
]
await hass.services.async_call(
NOTIFY_DOMAIN, "test6", {"message": "error"}, blocking=True
)
assert check_output.call_count == 2
assert "Timeout for command" in caplog.text
await hass.services.async_call(
NOTIFY_DOMAIN, "test6", {"message": "error"}, blocking=True
)
assert check_output.call_count == 4
assert "Error trying to exec command" in caplog.text