Add test coverage for doorbird events (#122617)

This commit is contained in:
J. Nick Koston 2024-07-26 09:55:14 -05:00 committed by GitHub
parent 850703824b
commit 5bb6272dfa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 91 additions and 14 deletions

View file

@ -25,19 +25,12 @@ class DoorBirdRequestView(HomeAssistantView):
"""Respond to requests from the device.""" """Respond to requests from the device."""
hass = request.app[KEY_HASS] hass = request.app[KEY_HASS]
token: str | None = request.query.get("token") token: str | None = request.query.get("token")
if ( if not token or not (door_station := get_door_station_by_token(hass, token)):
token is None
or (door_station := get_door_station_by_token(hass, token)) is None
):
return web.Response( return web.Response(
status=HTTPStatus.UNAUTHORIZED, text="Invalid token provided." status=HTTPStatus.UNAUTHORIZED, text="Invalid token provided."
) )
if door_station: event_data = door_station.get_event_data(event)
event_data = door_station.get_event_data(event)
else:
event_data = {}
# #
# This integration uses a multiple different events. # This integration uses a multiple different events.
# It would be a major breaking change to change this to # It would be a major breaking change to change this to

View file

@ -6,7 +6,15 @@ from unittest.mock import AsyncMock, MagicMock, Mock
import aiohttp import aiohttp
from doorbirdpy import DoorBird, DoorBirdScheduleEntry from doorbirdpy import DoorBird, DoorBirdScheduleEntry
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_USERNAME from homeassistant import config_entries
from homeassistant.components.doorbird.const import API_URL
from homeassistant.const import (
CONF_HOST,
CONF_NAME,
CONF_PASSWORD,
CONF_TOKEN,
CONF_USERNAME,
)
VALID_CONFIG = { VALID_CONFIG = {
CONF_HOST: "1.2.3.4", CONF_HOST: "1.2.3.4",
@ -39,6 +47,7 @@ def get_mock_doorbird_api(
info: dict[str, Any] | None = None, info: dict[str, Any] | None = None,
info_side_effect: Exception | None = None, info_side_effect: Exception | None = None,
schedule: list[DoorBirdScheduleEntry] | None = None, schedule: list[DoorBirdScheduleEntry] | None = None,
favorites: dict[str, dict[str, Any]] | None = None,
favorites_side_effect: Exception | None = None, favorites_side_effect: Exception | None = None,
) -> DoorBird: ) -> DoorBird:
"""Return a mock DoorBirdAPI object with return values.""" """Return a mock DoorBirdAPI object with return values."""
@ -48,9 +57,10 @@ def get_mock_doorbird_api(
) )
type(doorbirdapi_mock).favorites = AsyncMock( type(doorbirdapi_mock).favorites = AsyncMock(
side_effect=favorites_side_effect, side_effect=favorites_side_effect,
return_value={"http": {"x": {"value": "http://webhook"}}}, return_value=favorites,
) )
type(doorbirdapi_mock).change_favorite = AsyncMock(return_value=True) type(doorbirdapi_mock).change_favorite = AsyncMock(return_value=True)
type(doorbirdapi_mock).change_schedule = AsyncMock(return_value=(True, 200))
type(doorbirdapi_mock).schedule = AsyncMock(return_value=schedule) type(doorbirdapi_mock).schedule = AsyncMock(return_value=schedule)
type(doorbirdapi_mock).energize_relay = AsyncMock(return_value=True) type(doorbirdapi_mock).energize_relay = AsyncMock(return_value=True)
type(doorbirdapi_mock).turn_light_on = AsyncMock(return_value=True) type(doorbirdapi_mock).turn_light_on = AsyncMock(return_value=True)
@ -59,3 +69,14 @@ def get_mock_doorbird_api(
side_effect=mock_unauthorized_exception() side_effect=mock_unauthorized_exception()
) )
return doorbirdapi_mock return doorbirdapi_mock
async def mock_webhook_call(
config_entry: config_entries.ConfigEntry,
aiohttp_client: aiohttp.ClientSession,
event: str,
) -> None:
"""Mock the webhook call."""
token = config_entry.data.get(CONF_TOKEN, config_entry.entry_id)
response = await aiohttp_client.get(f"{API_URL}/{event}?token={token}")
response.raise_for_status()

View file

@ -9,7 +9,12 @@ from unittest.mock import MagicMock, patch
from doorbirdpy import DoorBird, DoorBirdScheduleEntry from doorbirdpy import DoorBird, DoorBirdScheduleEntry
import pytest import pytest
from homeassistant.components.doorbird.const import CONF_EVENTS, DOMAIN from homeassistant.components.doorbird.const import (
CONF_EVENTS,
DEFAULT_DOORBELL_EVENT,
DEFAULT_MOTION_EVENT,
DOMAIN,
)
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from . import VALID_CONFIG, get_mock_doorbird_api from . import VALID_CONFIG, get_mock_doorbird_api
@ -41,6 +46,12 @@ def doorbird_schedule() -> list[DoorBirdScheduleEntry]:
) )
@pytest.fixture(scope="session")
def doorbird_favorites() -> dict[str, dict[str, Any]]:
"""Return a loaded DoorBird favorites fixture."""
return load_json_value_fixture("favorites.json", "doorbird")
@pytest.fixture @pytest.fixture
def doorbird_api( def doorbird_api(
doorbird_info: dict[str, Any], doorbird_schedule: dict[str, Any] doorbird_info: dict[str, Any], doorbird_schedule: dict[str, Any]
@ -72,6 +83,7 @@ async def doorbird_mocker(
hass: HomeAssistant, hass: HomeAssistant,
doorbird_info: dict[str, Any], doorbird_info: dict[str, Any],
doorbird_schedule: dict[str, Any], doorbird_schedule: dict[str, Any],
doorbird_favorites: dict[str, dict[str, Any]],
) -> DoorbirdMockerType: ) -> DoorbirdMockerType:
"""Create a MockDoorbirdEntry.""" """Create a MockDoorbirdEntry."""
@ -81,6 +93,7 @@ async def doorbird_mocker(
info: dict[str, Any] | None = None, info: dict[str, Any] | None = None,
info_side_effect: Exception | None = None, info_side_effect: Exception | None = None,
schedule: list[DoorBirdScheduleEntry] | None = None, schedule: list[DoorBirdScheduleEntry] | None = None,
favorites: dict[str, dict[str, Any]] | None = None,
favorites_side_effect: Exception | None = None, favorites_side_effect: Exception | None = None,
) -> MockDoorbirdEntry: ) -> MockDoorbirdEntry:
"""Create a MockDoorbirdEntry from defaults or specific values.""" """Create a MockDoorbirdEntry from defaults or specific values."""
@ -88,12 +101,13 @@ async def doorbird_mocker(
domain=DOMAIN, domain=DOMAIN,
unique_id="1CCAE3AAAAAA", unique_id="1CCAE3AAAAAA",
data=VALID_CONFIG, data=VALID_CONFIG,
options={CONF_EVENTS: ["event1", "event2", "event3"]}, options={CONF_EVENTS: [DEFAULT_DOORBELL_EVENT, DEFAULT_MOTION_EVENT]},
) )
api = api or get_mock_doorbird_api( api = api or get_mock_doorbird_api(
info=info or doorbird_info, info=info or doorbird_info,
info_side_effect=info_side_effect, info_side_effect=info_side_effect,
schedule=schedule or doorbird_schedule, schedule=schedule or doorbird_schedule,
favorites=favorites or doorbird_favorites,
favorites_side_effect=favorites_side_effect, favorites_side_effect=favorites_side_effect,
) )
entry.add_to_hass(hass) entry.add_to_hass(hass)

View file

@ -0,0 +1,12 @@
{
"http": {
"0": {
"title": "Home Assistant (mydoorbird_doorbell)",
"value": "http://127.0.0.1:8123/api/doorbird/mydoorbird_doorbell?token=01J2F4B97Y7P1SARXEJ6W07EKD"
},
"1": {
"title": "Home Assistant (mydoorbird_motion)",
"value": "http://127.0.0.1:8123/api/doorbird/mydoorbird_motion?token=01J2F4B97Y7P1SARXEJ6W07EKD"
}
}
}

View file

@ -49,4 +49,4 @@ async def test_reset_favorites_button(
DOMAIN, SERVICE_PRESS, {ATTR_ENTITY_ID: reset_entity_id}, blocking=True DOMAIN, SERVICE_PRESS, {ATTR_ENTITY_ID: reset_entity_id}, blocking=True
) )
assert hass.states.get(reset_entity_id).state != STATE_UNKNOWN assert hass.states.get(reset_entity_id).state != STATE_UNKNOWN
assert doorbird_entry.api.delete_favorite.call_count == 1 assert doorbird_entry.api.delete_favorite.call_count == 2

View file

@ -0,0 +1,37 @@
"""Test DoorBird events."""
from homeassistant.const import STATE_UNKNOWN
from homeassistant.core import HomeAssistant
from . import mock_webhook_call
from .conftest import DoorbirdMockerType
from tests.typing import ClientSessionGenerator
async def test_doorbell_ring_event(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
doorbird_mocker: DoorbirdMockerType,
) -> None:
"""Test a doorbell ring event."""
doorbird_entry = await doorbird_mocker()
relay_1_entity_id = "event.mydoorbird_doorbell"
assert hass.states.get(relay_1_entity_id).state == STATE_UNKNOWN
client = await hass_client()
await mock_webhook_call(doorbird_entry.entry, client, "mydoorbird_doorbell")
assert hass.states.get(relay_1_entity_id).state != STATE_UNKNOWN
async def test_motion_event(
hass: HomeAssistant,
hass_client: ClientSessionGenerator,
doorbird_mocker: DoorbirdMockerType,
) -> None:
"""Test a doorbell motion event."""
doorbird_entry = await doorbird_mocker()
relay_1_entity_id = "event.mydoorbird_motion"
assert hass.states.get(relay_1_entity_id).state == STATE_UNKNOWN
client = await hass_client()
await mock_webhook_call(doorbird_entry.entry, client, "mydoorbird_motion")
assert hass.states.get(relay_1_entity_id).state != STATE_UNKNOWN