Migrate demo notify platform (#115448)

* Migrate demo notify platform

* Update homeassistant/components/demo/notify.py

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Remove no needed tests

* Cleanup redundant attribute assignment

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
Jan Bouwhuis 2024-04-13 14:27:07 +02:00 committed by GitHub
parent 5e8b46c670
commit 36bdda5669
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 67 additions and 184 deletions

View file

@ -38,6 +38,7 @@ COMPONENTS_WITH_CONFIG_ENTRY_DEMO_PLATFORM = [
Platform.LIGHT, Platform.LIGHT,
Platform.LOCK, Platform.LOCK,
Platform.MEDIA_PLAYER, Platform.MEDIA_PLAYER,
Platform.NOTIFY,
Platform.NUMBER, Platform.NUMBER,
Platform.SELECT, Platform.SELECT,
Platform.SENSOR, Platform.SENSOR,
@ -55,7 +56,6 @@ COMPONENTS_WITH_CONFIG_ENTRY_DEMO_PLATFORM = [
COMPONENTS_WITH_DEMO_PLATFORM = [ COMPONENTS_WITH_DEMO_PLATFORM = [
Platform.TTS, Platform.TTS,
Platform.MAILBOX, Platform.MAILBOX,
Platform.NOTIFY,
Platform.IMAGE_PROCESSING, Platform.IMAGE_PROCESSING,
Platform.DEVICE_TRACKER, Platform.DEVICE_TRACKER,
] ]

View file

@ -1,38 +1,44 @@
"""Demo notification service.""" """Demo notification entity."""
from __future__ import annotations from __future__ import annotations
from typing import Any from homeassistant.components.notify import DOMAIN, NotifyEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.components.notify import BaseNotificationService
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
EVENT_NOTIFY = "notify" EVENT_NOTIFY = "notify"
def get_service( async def async_setup_entry(
hass: HomeAssistant, hass: HomeAssistant,
config: ConfigType, config_entry: ConfigEntry,
discovery_info: DiscoveryInfoType | None = None, async_add_entities: AddEntitiesCallback,
) -> BaseNotificationService: ) -> None:
"""Get the demo notification service.""" """Set up the demo entity platform."""
return DemoNotificationService(hass) async_add_entities([DemoNotifyEntity(unique_id="notify", device_name="Notifier")])
class DemoNotificationService(BaseNotificationService): class DemoNotifyEntity(NotifyEntity):
"""Implement demo notification service.""" """Implement demo notification platform."""
def __init__(self, hass: HomeAssistant) -> None: _attr_has_entity_name = True
"""Initialize the service.""" _attr_name = None
self.hass = hass
@property def __init__(
def targets(self) -> dict[str, str]: self,
"""Return a dictionary of registered targets.""" unique_id: str,
return {"test target name": "test target id"} device_name: str,
) -> None:
"""Initialize the Demo button entity."""
self._attr_unique_id = unique_id
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, unique_id)},
name=device_name,
)
def send_message(self, message: str = "", **kwargs: Any) -> None: async def async_send_message(self, message: str) -> None:
"""Send a message to a user.""" """Send a message to a user."""
kwargs["message"] = message event_notitifcation = {"message": message}
self.hass.bus.fire(EVENT_NOTIFY, kwargs) self.hass.bus.async_fire(EVENT_NOTIFY, event_notitifcation)

View file

@ -1,29 +1,43 @@
"""The tests for the notify demo platform.""" """The tests for the notify demo platform."""
import logging from collections.abc import Generator
from unittest.mock import patch from unittest.mock import patch
import pytest import pytest
import voluptuous as vol
from homeassistant.components import notify from homeassistant.components import notify
from homeassistant.components.demo import DOMAIN
import homeassistant.components.demo.notify as demo import homeassistant.components.demo.notify as demo
from homeassistant.core import HomeAssistant, callback from homeassistant.const import Platform
from homeassistant.helpers import discovery from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from tests.common import assert_setup_component, async_capture_events from tests.common import MockConfigEntry, async_capture_events
CONFIG = {notify.DOMAIN: {"platform": "demo"}}
@pytest.fixture(autouse=True)
def autouse_disable_platforms(disable_platforms):
"""Auto use the disable_platforms fixture."""
@pytest.fixture @pytest.fixture
def events(hass): def notify_only() -> Generator[None, None]:
"""Enable only the notify platform."""
with patch(
"homeassistant.components.demo.COMPONENTS_WITH_CONFIG_ENTRY_DEMO_PLATFORM",
[Platform.NOTIFY],
):
yield
@pytest.fixture(autouse=True)
async def setup_notify(hass: HomeAssistant, notify_only: None) -> None:
"""Initialize setup demo Notify entity."""
entry = MockConfigEntry(domain=DOMAIN)
entry.add_to_hass(hass)
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
state = hass.states.get("notify.notifier")
assert state is not None
@pytest.fixture
def events(hass: HomeAssistant) -> list[Event]:
"""Fixture that catches notify events.""" """Fixture that catches notify events."""
return async_capture_events(hass, demo.EVENT_NOTIFY) return async_capture_events(hass, demo.EVENT_NOTIFY)
@ -46,104 +60,26 @@ def record_calls(calls):
return record_calls return record_calls
@pytest.fixture(name="mock_demo_notify") async def test_sending_message(hass: HomeAssistant, events: list[Event]) -> None:
def mock_demo_notify_fixture(): """Test sending a message."""
"""Mock demo notify service."""
with patch("homeassistant.components.demo.notify.get_service", autospec=True) as ns:
yield ns
async def setup_notify(hass):
"""Test setup."""
with assert_setup_component(1, notify.DOMAIN) as config:
assert await async_setup_component(hass, notify.DOMAIN, CONFIG)
assert config[notify.DOMAIN]
await hass.async_block_till_done()
async def test_no_notify_service(
hass: HomeAssistant, mock_demo_notify, caplog: pytest.LogCaptureFixture
) -> None:
"""Test missing platform notify service instance."""
caplog.set_level(logging.ERROR)
mock_demo_notify.return_value = None
await setup_notify(hass)
await hass.async_block_till_done()
assert mock_demo_notify.called
assert "Failed to initialize notification service demo" in caplog.text
async def test_discover_notify(hass: HomeAssistant, mock_demo_notify) -> None:
"""Test discovery of notify demo platform."""
assert notify.DOMAIN not in hass.config.components
mock_demo_notify.return_value = None
await discovery.async_load_platform(
hass, "notify", "demo", {"test_key": "test_val"}, {"notify": {}}
)
await hass.async_block_till_done()
assert notify.DOMAIN in hass.config.components
assert mock_demo_notify.called
assert mock_demo_notify.mock_calls[0][1] == (
hass,
{},
{"test_key": "test_val"},
)
async def test_sending_none_message(hass: HomeAssistant, events) -> None:
"""Test send with None as message."""
await setup_notify(hass)
with pytest.raises(vol.Invalid):
await hass.services.async_call(
notify.DOMAIN, notify.SERVICE_NOTIFY, {notify.ATTR_MESSAGE: None}
)
await hass.async_block_till_done()
assert len(events) == 0
async def test_sending_templated_message(hass: HomeAssistant, events) -> None:
"""Send a templated message."""
await setup_notify(hass)
hass.states.async_set("sensor.temperature", 10)
data = { data = {
notify.ATTR_MESSAGE: "{{states.sensor.temperature.state}}", "entity_id": "notify.notifier",
notify.ATTR_TITLE: "{{ states.sensor.temperature.name }}", notify.ATTR_MESSAGE: "Test message",
} }
await hass.services.async_call(notify.DOMAIN, notify.SERVICE_NOTIFY, data) await hass.services.async_call(notify.DOMAIN, notify.SERVICE_SEND_MESSAGE, data)
await hass.async_block_till_done() await hass.async_block_till_done()
last_event = events[-1] last_event = events[-1]
assert last_event.data[notify.ATTR_TITLE] == "temperature" assert last_event.data[notify.ATTR_MESSAGE] == "Test message"
assert last_event.data[notify.ATTR_MESSAGE] == "10"
async def test_method_forwards_correct_data(hass: HomeAssistant, events) -> None: async def test_calling_notify_from_script_loaded_from_yaml(
"""Test that all data from the service gets forwarded to service.""" hass: HomeAssistant, events: list[Event]
await setup_notify(hass)
data = {
notify.ATTR_MESSAGE: "my message",
notify.ATTR_TITLE: "my title",
notify.ATTR_DATA: {"hello": "world"},
}
await hass.services.async_call(notify.DOMAIN, notify.SERVICE_NOTIFY, data)
await hass.async_block_till_done()
assert len(events) == 1
data = events[0].data
assert {
"message": "my message",
"title": "my title",
"data": {"hello": "world"},
} == data
async def test_calling_notify_from_script_loaded_from_yaml_without_title(
hass: HomeAssistant, events
) -> None: ) -> None:
"""Test if we can call a notify from a script.""" """Test if we can call a notify from a script."""
await setup_notify(hass)
step = { step = {
"service": "notify.notify", "service": "notify.send_message",
"data": { "data": {
"data": {"push": {"sound": "US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav"}} "entity_id": "notify.notifier",
}, },
"data_template": {"message": "Test 123 {{ 2 + 2 }}\n"}, "data_template": {"message": "Test 123 {{ 2 + 2 }}\n"},
} }
@ -155,63 +91,4 @@ async def test_calling_notify_from_script_loaded_from_yaml_without_title(
assert len(events) == 1 assert len(events) == 1
assert { assert {
"message": "Test 123 4", "message": "Test 123 4",
"data": {"push": {"sound": "US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav"}},
} == events[0].data } == events[0].data
async def test_calling_notify_from_script_loaded_from_yaml_with_title(
hass: HomeAssistant, events
) -> None:
"""Test if we can call a notify from a script."""
await setup_notify(hass)
step = {
"service": "notify.notify",
"data": {
"data": {"push": {"sound": "US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav"}}
},
"data_template": {"message": "Test 123 {{ 2 + 2 }}\n", "title": "Test"},
}
await async_setup_component(
hass, "script", {"script": {"test": {"sequence": step}}}
)
await hass.services.async_call("script", "test")
await hass.async_block_till_done()
assert len(events) == 1
assert {
"message": "Test 123 4",
"title": "Test",
"data": {"push": {"sound": "US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav"}},
} == events[0].data
async def test_targets_are_services(hass: HomeAssistant) -> None:
"""Test that all targets are exposed as individual services."""
await setup_notify(hass)
assert hass.services.has_service("notify", "demo") is not None
service = "demo_test_target_name"
assert hass.services.has_service("notify", service) is not None
async def test_messages_to_targets_route(
hass: HomeAssistant, calls, record_calls
) -> None:
"""Test message routing to specific target services."""
await setup_notify(hass)
hass.bus.async_listen_once("notify", record_calls)
await hass.services.async_call(
"notify",
"demo_test_target_name",
{"message": "my message", "title": "my title", "data": {"hello": "world"}},
)
await hass.async_block_till_done()
data = calls[0][0].data
assert {
"message": "my message",
"target": ["test target id"],
"title": "my title",
"data": {"hello": "world"},
} == data