Update calendar tests to use mock entities instead of demo platform (#105317)
* Update calendar tests to use mock entities instead of demo platform * Add Generator type to fixture * Fix generator syntax --------- Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
18d395821d
commit
1069693292
5 changed files with 306 additions and 162 deletions
|
@ -1,14 +1,29 @@
|
|||
"""Test fixtures for calendar sensor platforms."""
|
||||
from collections.abc import Generator
|
||||
import datetime
|
||||
import secrets
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.calendar import DOMAIN, CalendarEntity, CalendarEvent
|
||||
from homeassistant.config_entries import ConfigEntry, ConfigFlow
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
MockModule,
|
||||
MockPlatform,
|
||||
mock_config_flow,
|
||||
mock_integration,
|
||||
mock_platform,
|
||||
)
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant(hass: HomeAssistant):
|
||||
"""Set up the homeassistant integration."""
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
TEST_DOMAIN = "test"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -17,3 +32,161 @@ def set_time_zone(hass: HomeAssistant) -> None:
|
|||
# Set our timezone to CST/Regina so we can check calculations
|
||||
# This keeps UTC-6 all year round
|
||||
hass.config.set_time_zone("America/Regina")
|
||||
|
||||
|
||||
class MockFlow(ConfigFlow):
|
||||
"""Test flow."""
|
||||
|
||||
|
||||
class MockCalendarEntity(CalendarEntity):
|
||||
"""Test Calendar entity."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(self, name: str, events: list[CalendarEvent] | None = None) -> None:
|
||||
"""Initialize entity."""
|
||||
self._attr_name = name.capitalize()
|
||||
self._events = events or []
|
||||
|
||||
@property
|
||||
def event(self) -> CalendarEvent | None:
|
||||
"""Return the next upcoming event."""
|
||||
return self._events[0] if self._events else None
|
||||
|
||||
def create_event(
|
||||
self,
|
||||
start: datetime.datetime,
|
||||
end: datetime.datetime,
|
||||
summary: str | None = None,
|
||||
description: str | None = None,
|
||||
location: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Create a new fake event, used by tests."""
|
||||
event = CalendarEvent(
|
||||
start=start,
|
||||
end=end,
|
||||
summary=summary if summary else f"Event {secrets.token_hex(16)}",
|
||||
description=description,
|
||||
location=location,
|
||||
)
|
||||
self._events.append(event)
|
||||
return event.as_dict()
|
||||
|
||||
async def async_get_events(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
start_date: datetime.datetime,
|
||||
end_date: datetime.datetime,
|
||||
) -> list[CalendarEvent]:
|
||||
"""Return calendar events within a datetime range."""
|
||||
assert start_date < end_date
|
||||
events = []
|
||||
for event in self._events:
|
||||
if event.start_datetime_local >= end_date:
|
||||
continue
|
||||
if event.end_datetime_local < start_date:
|
||||
continue
|
||||
events.append(event)
|
||||
return events
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def config_flow_fixture(hass: HomeAssistant) -> Generator[None, None, None]:
|
||||
"""Mock config flow."""
|
||||
mock_platform(hass, f"{TEST_DOMAIN}.config_flow")
|
||||
|
||||
with mock_config_flow(TEST_DOMAIN, MockFlow):
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_setup_integration(hass: HomeAssistant, config_flow_fixture: None) -> None:
|
||||
"""Fixture to set up a mock integration."""
|
||||
|
||||
async def async_setup_entry_init(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry
|
||||
) -> bool:
|
||||
"""Set up test config entry."""
|
||||
await hass.config_entries.async_forward_entry_setup(config_entry, DOMAIN)
|
||||
return True
|
||||
|
||||
async def async_unload_entry_init(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
) -> bool:
|
||||
await hass.config_entries.async_unload_platforms(
|
||||
config_entry, [Platform.CALENDAR]
|
||||
)
|
||||
return True
|
||||
|
||||
mock_platform(hass, f"{TEST_DOMAIN}.config_flow")
|
||||
mock_integration(
|
||||
hass,
|
||||
MockModule(
|
||||
TEST_DOMAIN,
|
||||
async_setup_entry=async_setup_entry_init,
|
||||
async_unload_entry=async_unload_entry_init,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def create_mock_platform(
|
||||
hass: HomeAssistant,
|
||||
entities: list[CalendarEntity],
|
||||
) -> MockConfigEntry:
|
||||
"""Create a calendar platform with the specified entities."""
|
||||
|
||||
async def async_setup_entry_platform(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up test event platform via config entry."""
|
||||
async_add_entities(entities)
|
||||
|
||||
mock_platform(
|
||||
hass,
|
||||
f"{TEST_DOMAIN}.{DOMAIN}",
|
||||
MockPlatform(async_setup_entry=async_setup_entry_platform),
|
||||
)
|
||||
|
||||
config_entry = MockConfigEntry(domain=TEST_DOMAIN)
|
||||
config_entry.add_to_hass(hass)
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
return config_entry
|
||||
|
||||
|
||||
@pytest.fixture(name="test_entities")
|
||||
def mock_test_entities() -> list[MockCalendarEntity]:
|
||||
"""Fixture to create fake entities used in the test."""
|
||||
half_hour_from_now = dt_util.now() + datetime.timedelta(minutes=30)
|
||||
entity1 = MockCalendarEntity(
|
||||
"Calendar 1",
|
||||
[
|
||||
CalendarEvent(
|
||||
start=half_hour_from_now,
|
||||
end=half_hour_from_now + datetime.timedelta(minutes=60),
|
||||
summary="Future Event",
|
||||
description="Future Description",
|
||||
location="Future Location",
|
||||
)
|
||||
],
|
||||
)
|
||||
entity1.async_get_events = AsyncMock(wraps=entity1.async_get_events)
|
||||
|
||||
middle_of_event = dt_util.now() - datetime.timedelta(minutes=30)
|
||||
entity2 = MockCalendarEntity(
|
||||
"Calendar 2",
|
||||
[
|
||||
CalendarEvent(
|
||||
start=middle_of_event,
|
||||
end=middle_of_event + datetime.timedelta(minutes=60),
|
||||
summary="Current Event",
|
||||
)
|
||||
],
|
||||
)
|
||||
entity2.async_get_events = AsyncMock(wraps=entity2.async_get_events)
|
||||
|
||||
return [entity1, entity2]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# serializer version: 1
|
||||
# name: test_list_events_service_duration[calendar.calendar_1-00:15:00-get_events]
|
||||
# name: test_list_events_service_duration[frozen_time-calendar.calendar_1-00:15:00-get_events]
|
||||
dict({
|
||||
'calendar.calendar_1': dict({
|
||||
'events': list([
|
||||
|
@ -7,59 +7,59 @@
|
|||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_list_events_service_duration[calendar.calendar_1-00:15:00-list_events]
|
||||
# name: test_list_events_service_duration[frozen_time-calendar.calendar_1-00:15:00-list_events]
|
||||
dict({
|
||||
'events': list([
|
||||
]),
|
||||
})
|
||||
# ---
|
||||
# name: test_list_events_service_duration[calendar.calendar_1-01:00:00-get_events]
|
||||
# name: test_list_events_service_duration[frozen_time-calendar.calendar_1-01:00:00-get_events]
|
||||
dict({
|
||||
'calendar.calendar_1': dict({
|
||||
'events': list([
|
||||
dict({
|
||||
'description': 'Future Description',
|
||||
'end': '2023-10-19T08:20:05-07:00',
|
||||
'end': '2023-10-19T09:20:05-06:00',
|
||||
'location': 'Future Location',
|
||||
'start': '2023-10-19T07:20:05-07:00',
|
||||
'start': '2023-10-19T08:20:05-06:00',
|
||||
'summary': 'Future Event',
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_list_events_service_duration[calendar.calendar_1-01:00:00-list_events]
|
||||
# name: test_list_events_service_duration[frozen_time-calendar.calendar_1-01:00:00-list_events]
|
||||
dict({
|
||||
'events': list([
|
||||
dict({
|
||||
'description': 'Future Description',
|
||||
'end': '2023-10-19T08:20:05-07:00',
|
||||
'end': '2023-10-19T09:20:05-06:00',
|
||||
'location': 'Future Location',
|
||||
'start': '2023-10-19T07:20:05-07:00',
|
||||
'start': '2023-10-19T08:20:05-06:00',
|
||||
'summary': 'Future Event',
|
||||
}),
|
||||
]),
|
||||
})
|
||||
# ---
|
||||
# name: test_list_events_service_duration[calendar.calendar_2-00:15:00-get_events]
|
||||
# name: test_list_events_service_duration[frozen_time-calendar.calendar_2-00:15:00-get_events]
|
||||
dict({
|
||||
'calendar.calendar_2': dict({
|
||||
'events': list([
|
||||
dict({
|
||||
'end': '2023-10-19T07:20:05-07:00',
|
||||
'start': '2023-10-19T06:20:05-07:00',
|
||||
'end': '2023-10-19T08:20:05-06:00',
|
||||
'start': '2023-10-19T07:20:05-06:00',
|
||||
'summary': 'Current Event',
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
})
|
||||
# ---
|
||||
# name: test_list_events_service_duration[calendar.calendar_2-00:15:00-list_events]
|
||||
# name: test_list_events_service_duration[frozen_time-calendar.calendar_2-00:15:00-list_events]
|
||||
dict({
|
||||
'events': list([
|
||||
dict({
|
||||
'end': '2023-10-19T07:20:05-07:00',
|
||||
'start': '2023-10-19T06:20:05-07:00',
|
||||
'end': '2023-10-19T08:20:05-06:00',
|
||||
'start': '2023-10-19T07:20:05-06:00',
|
||||
'summary': 'Current Event',
|
||||
}),
|
||||
]),
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
"""The tests for the calendar component."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Generator
|
||||
from datetime import timedelta
|
||||
from http import HTTPStatus
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
from freezegun import freeze_time
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.bootstrap import async_setup_component
|
||||
from homeassistant.components.calendar import (
|
||||
DOMAIN,
|
||||
LEGACY_SERVICE_LIST_EVENTS,
|
||||
|
@ -22,15 +21,46 @@ from homeassistant.exceptions import HomeAssistantError
|
|||
from homeassistant.helpers.issue_registry import IssueRegistry
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from .conftest import TEST_DOMAIN, MockCalendarEntity, create_mock_platform
|
||||
|
||||
from tests.typing import ClientSessionGenerator, WebSocketGenerator
|
||||
|
||||
|
||||
@pytest.fixture(name="frozen_time")
|
||||
def mock_frozen_time() -> None:
|
||||
"""Fixture to set a frozen time used in tests.
|
||||
|
||||
This is needed so that it can run before other fixtures.
|
||||
"""
|
||||
return None
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_set_frozen_time(frozen_time: Any) -> Generator[None, None, None]:
|
||||
"""Fixture to freeze time that also can work for other fixtures."""
|
||||
if not frozen_time:
|
||||
yield
|
||||
else:
|
||||
with freeze_time(frozen_time):
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(name="setup_platform", autouse=True)
|
||||
async def mock_setup_platform(
|
||||
hass: HomeAssistant,
|
||||
set_time_zone: Any,
|
||||
frozen_time: Any,
|
||||
mock_setup_integration: Any,
|
||||
test_entities: list[MockCalendarEntity],
|
||||
) -> None:
|
||||
"""Fixture to setup platforms used in the test and fixtures are set up in the right order."""
|
||||
await create_mock_platform(hass, test_entities)
|
||||
|
||||
|
||||
async def test_events_http_api(
|
||||
hass: HomeAssistant, hass_client: ClientSessionGenerator
|
||||
) -> None:
|
||||
"""Test the calendar demo view."""
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
client = await hass_client()
|
||||
start = dt_util.now()
|
||||
end = start + timedelta(days=1)
|
||||
|
@ -46,27 +76,23 @@ async def test_events_http_api_missing_fields(
|
|||
hass: HomeAssistant, hass_client: ClientSessionGenerator
|
||||
) -> None:
|
||||
"""Test the calendar demo view."""
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
client = await hass_client()
|
||||
response = await client.get("/api/calendars/calendar.calendar_2")
|
||||
assert response.status == HTTPStatus.BAD_REQUEST
|
||||
|
||||
|
||||
async def test_events_http_api_error(
|
||||
hass: HomeAssistant, hass_client: ClientSessionGenerator
|
||||
hass: HomeAssistant,
|
||||
hass_client: ClientSessionGenerator,
|
||||
test_entities: list[MockCalendarEntity],
|
||||
) -> None:
|
||||
"""Test the calendar demo view."""
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
client = await hass_client()
|
||||
start = dt_util.now()
|
||||
end = start + timedelta(days=1)
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.demo.calendar.DemoCalendar.async_get_events",
|
||||
side_effect=HomeAssistantError("Failure"),
|
||||
):
|
||||
test_entities[0].async_get_events.side_effect = HomeAssistantError("Failure")
|
||||
|
||||
response = await client.get(
|
||||
f"/api/calendars/calendar.calendar_1?start={start.isoformat()}&end={end.isoformat()}"
|
||||
)
|
||||
|
@ -78,8 +104,6 @@ async def test_events_http_api_dates_wrong_order(
|
|||
hass: HomeAssistant, hass_client: ClientSessionGenerator
|
||||
) -> None:
|
||||
"""Test the calendar demo view."""
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
client = await hass_client()
|
||||
start = dt_util.now()
|
||||
end = start + timedelta(days=-1)
|
||||
|
@ -93,8 +117,6 @@ async def test_calendars_http_api(
|
|||
hass: HomeAssistant, hass_client: ClientSessionGenerator
|
||||
) -> None:
|
||||
"""Test the calendar demo view."""
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
client = await hass_client()
|
||||
response = await client.get("/api/calendars")
|
||||
assert response.status == HTTPStatus.OK
|
||||
|
@ -180,8 +202,6 @@ async def test_unsupported_websocket(
|
|||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator, payload, code
|
||||
) -> None:
|
||||
"""Test unsupported websocket command."""
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
client = await hass_ws_client(hass)
|
||||
await client.send_json(
|
||||
{
|
||||
|
@ -198,9 +218,6 @@ async def test_unsupported_websocket(
|
|||
async def test_unsupported_create_event_service(hass: HomeAssistant) -> None:
|
||||
"""Test unsupported service call."""
|
||||
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
with pytest.raises(HomeAssistantError, match="does not support this service"):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
|
@ -377,9 +394,6 @@ async def test_create_event_service_invalid_params(
|
|||
) -> None:
|
||||
"""Test creating an event using the create_event service."""
|
||||
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
with pytest.raises(expected_error, match=error_match):
|
||||
await hass.services.async_call(
|
||||
"calendar",
|
||||
|
@ -393,7 +407,9 @@ async def test_create_event_service_invalid_params(
|
|||
)
|
||||
|
||||
|
||||
@freeze_time("2023-06-22 10:30:00+00:00")
|
||||
@pytest.mark.parametrize(
|
||||
"frozen_time", ["2023-06-22 10:30:00+00:00"], ids=["frozen_time"]
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("service", "expected"),
|
||||
[
|
||||
|
@ -439,7 +455,6 @@ async def test_create_event_service_invalid_params(
|
|||
)
|
||||
async def test_list_events_service(
|
||||
hass: HomeAssistant,
|
||||
set_time_zone: None,
|
||||
start_time: str,
|
||||
end_time: str,
|
||||
service: str,
|
||||
|
@ -451,9 +466,6 @@ async def test_list_events_service(
|
|||
string output values.
|
||||
"""
|
||||
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
response = await hass.services.async_call(
|
||||
DOMAIN,
|
||||
service,
|
||||
|
@ -487,7 +499,7 @@ async def test_list_events_service(
|
|||
("calendar.calendar_2", "00:15:00"),
|
||||
],
|
||||
)
|
||||
@pytest.mark.freeze_time("2023-10-19 13:50:05")
|
||||
@pytest.mark.parametrize("frozen_time", ["2023-10-19 13:50:05"], ids=["frozen_time"])
|
||||
async def test_list_events_service_duration(
|
||||
hass: HomeAssistant,
|
||||
entity: str,
|
||||
|
@ -496,9 +508,6 @@ async def test_list_events_service_duration(
|
|||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Test listing events using a time duration."""
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
response = await hass.services.async_call(
|
||||
DOMAIN,
|
||||
service,
|
||||
|
@ -514,9 +523,6 @@ async def test_list_events_service_duration(
|
|||
|
||||
async def test_list_events_positive_duration(hass: HomeAssistant) -> None:
|
||||
"""Test listing events requires a positive duration."""
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
with pytest.raises(vol.Invalid, match="should be positive"):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
|
@ -532,9 +538,6 @@ async def test_list_events_positive_duration(hass: HomeAssistant) -> None:
|
|||
|
||||
async def test_list_events_exclusive_fields(hass: HomeAssistant) -> None:
|
||||
"""Test listing events specifying fields that are exclusive."""
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
end = dt_util.now() + timedelta(days=1)
|
||||
|
||||
with pytest.raises(vol.Invalid, match="at most one of"):
|
||||
|
@ -553,9 +556,6 @@ async def test_list_events_exclusive_fields(hass: HomeAssistant) -> None:
|
|||
|
||||
async def test_list_events_missing_fields(hass: HomeAssistant) -> None:
|
||||
"""Test listing events missing some required fields."""
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
with pytest.raises(vol.Invalid, match="at least one of"):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
|
@ -575,9 +575,6 @@ async def test_issue_deprecated_service_calendar_list_events(
|
|||
) -> None:
|
||||
"""Test the issue is raised on deprecated service weather.get_forecast."""
|
||||
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
_ = await hass.services.async_call(
|
||||
DOMAIN,
|
||||
LEGACY_SERVICE_LIST_EVENTS,
|
||||
|
@ -594,7 +591,7 @@ async def test_issue_deprecated_service_calendar_list_events(
|
|||
"calendar", "deprecated_service_calendar_list_events"
|
||||
)
|
||||
assert issue
|
||||
assert issue.issue_domain == "demo"
|
||||
assert issue.issue_domain == TEST_DOMAIN
|
||||
assert issue.issue_id == "deprecated_service_calendar_list_events"
|
||||
assert issue.translation_key == "deprecated_service_calendar_list_events"
|
||||
|
||||
|
|
|
@ -1,41 +1,36 @@
|
|||
"""The tests for calendar recorder."""
|
||||
from datetime import timedelta
|
||||
from unittest.mock import patch
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.recorder import Recorder
|
||||
from homeassistant.components.recorder.history import get_significant_states
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME, Platform
|
||||
from homeassistant.const import ATTR_FRIENDLY_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .conftest import MockCalendarEntity, create_mock_platform
|
||||
|
||||
from tests.common import async_fire_time_changed
|
||||
from tests.components.recorder.common import async_wait_recording_done
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_homeassistant():
|
||||
"""Override the fixture in calendar.conftest."""
|
||||
async def mock_setup_dependencies(
|
||||
recorder_mock: Recorder,
|
||||
hass: HomeAssistant,
|
||||
set_time_zone: Any,
|
||||
mock_setup_integration: None,
|
||||
test_entities: list[MockCalendarEntity],
|
||||
) -> None:
|
||||
"""Fixture that ensures the recorder is setup in the right order."""
|
||||
await create_mock_platform(hass, test_entities)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def calendar_only() -> None:
|
||||
"""Enable only the calendar platform."""
|
||||
with patch(
|
||||
"homeassistant.components.demo.COMPONENTS_WITH_CONFIG_ENTRY_DEMO_PLATFORM",
|
||||
[Platform.CALENDAR],
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
async def test_exclude_attributes(recorder_mock: Recorder, hass: HomeAssistant) -> None:
|
||||
async def test_exclude_attributes(hass: HomeAssistant) -> None:
|
||||
"""Test sensor attributes to be excluded."""
|
||||
now = dt_util.utcnow()
|
||||
await async_setup_component(hass, "homeassistant", {})
|
||||
await async_setup_component(hass, "calendar", {"calendar": {"platform": "demo"}})
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get("calendar.calendar_1")
|
||||
assert state
|
||||
|
|
|
@ -12,7 +12,6 @@ from collections.abc import AsyncIterator, Callable, Generator
|
|||
from contextlib import asynccontextmanager
|
||||
import datetime
|
||||
import logging
|
||||
import secrets
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
import zoneinfo
|
||||
|
@ -28,13 +27,14 @@ from homeassistant.core import HomeAssistant
|
|||
from homeassistant.setup import async_setup_component
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from .conftest import MockCalendarEntity, create_mock_platform
|
||||
|
||||
from tests.common import async_fire_time_changed, async_mock_service
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
CALENDAR_ENTITY_ID = "calendar.calendar_2"
|
||||
CONFIG = {calendar.DOMAIN: {"platform": "demo"}}
|
||||
|
||||
TEST_AUTOMATION_ACTION = {
|
||||
"service": "test.automation",
|
||||
|
@ -59,44 +59,6 @@ class FakeSchedule:
|
|||
"""Initiailize FakeSchedule."""
|
||||
self.hass = hass
|
||||
self.freezer = freezer
|
||||
# Map of event start time to event
|
||||
self.events: list[calendar.CalendarEvent] = []
|
||||
|
||||
def create_event(
|
||||
self,
|
||||
start: datetime.datetime,
|
||||
end: datetime.datetime,
|
||||
summary: str | None = None,
|
||||
description: str | None = None,
|
||||
location: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Create a new fake event, used by tests."""
|
||||
event = calendar.CalendarEvent(
|
||||
start=start,
|
||||
end=end,
|
||||
summary=summary if summary else f"Event {secrets.token_hex(16)}",
|
||||
description=description,
|
||||
location=location,
|
||||
)
|
||||
self.events.append(event)
|
||||
return event.as_dict()
|
||||
|
||||
async def async_get_events(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
start_date: datetime.datetime,
|
||||
end_date: datetime.datetime,
|
||||
) -> list[calendar.CalendarEvent]:
|
||||
"""Get all events in a specific time frame, used by the demo calendar."""
|
||||
assert start_date < end_date
|
||||
values = []
|
||||
for event in self.events:
|
||||
if event.start_datetime_local >= end_date:
|
||||
continue
|
||||
if event.end_datetime_local < start_date:
|
||||
continue
|
||||
values.append(event)
|
||||
return values
|
||||
|
||||
async def fire_time(self, trigger_time: datetime.datetime) -> None:
|
||||
"""Fire an alarm and wait."""
|
||||
|
@ -130,19 +92,23 @@ def fake_schedule(
|
|||
# Setup start time for all tests
|
||||
freezer.move_to("2022-04-19 10:31:02+00:00")
|
||||
|
||||
schedule = FakeSchedule(hass, freezer)
|
||||
with patch(
|
||||
"homeassistant.components.demo.calendar.DemoCalendar.async_get_events",
|
||||
new=schedule.async_get_events,
|
||||
):
|
||||
yield schedule
|
||||
return FakeSchedule(hass, freezer)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_calendar(hass: HomeAssistant, fake_schedule: FakeSchedule) -> None:
|
||||
"""Initialize the demo calendar."""
|
||||
assert await async_setup_component(hass, calendar.DOMAIN, CONFIG)
|
||||
await hass.async_block_till_done()
|
||||
@pytest.fixture(name="test_entity")
|
||||
def mock_test_entity(test_entities: list[MockCalendarEntity]) -> MockCalendarEntity:
|
||||
"""Fixture to expose the calendar entity used in tests."""
|
||||
return test_entities[1]
|
||||
|
||||
|
||||
@pytest.fixture(name="setup_platform", autouse=True)
|
||||
async def mock_setup_platform(
|
||||
hass: HomeAssistant,
|
||||
mock_setup_integration: Any,
|
||||
test_entities: list[MockCalendarEntity],
|
||||
) -> None:
|
||||
"""Fixture to setup platforms used in the test."""
|
||||
await create_mock_platform(hass, test_entities)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
|
@ -207,9 +173,10 @@ async def test_event_start_trigger(
|
|||
hass: HomeAssistant,
|
||||
calls: Callable[[], list[dict[str, Any]]],
|
||||
fake_schedule: FakeSchedule,
|
||||
test_entity: MockCalendarEntity,
|
||||
) -> None:
|
||||
"""Test the a calendar trigger based on start time."""
|
||||
event_data = fake_schedule.create_event(
|
||||
event_data = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00"),
|
||||
)
|
||||
|
@ -240,11 +207,12 @@ async def test_event_start_trigger_with_offset(
|
|||
hass: HomeAssistant,
|
||||
calls: Callable[[], list[dict[str, Any]]],
|
||||
fake_schedule: FakeSchedule,
|
||||
test_entity: MockCalendarEntity,
|
||||
offset_str,
|
||||
offset_delta,
|
||||
) -> None:
|
||||
"""Test the a calendar trigger based on start time with an offset."""
|
||||
event_data = fake_schedule.create_event(
|
||||
event_data = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 12:00:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 12:30:00+00:00"),
|
||||
)
|
||||
|
@ -272,9 +240,10 @@ async def test_event_end_trigger(
|
|||
hass: HomeAssistant,
|
||||
calls: Callable[[], list[dict[str, Any]]],
|
||||
fake_schedule: FakeSchedule,
|
||||
test_entity: MockCalendarEntity,
|
||||
) -> None:
|
||||
"""Test the a calendar trigger based on end time."""
|
||||
event_data = fake_schedule.create_event(
|
||||
event_data = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 12:00:00+00:00"),
|
||||
)
|
||||
|
@ -309,11 +278,12 @@ async def test_event_end_trigger_with_offset(
|
|||
hass: HomeAssistant,
|
||||
calls: Callable[[], list[dict[str, Any]]],
|
||||
fake_schedule: FakeSchedule,
|
||||
test_entity: MockCalendarEntity,
|
||||
offset_str,
|
||||
offset_delta,
|
||||
) -> None:
|
||||
"""Test the a calendar trigger based on end time with an offset."""
|
||||
event_data = fake_schedule.create_event(
|
||||
event_data = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 12:00:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 12:30:00+00:00"),
|
||||
)
|
||||
|
@ -356,14 +326,15 @@ async def test_multiple_start_events(
|
|||
hass: HomeAssistant,
|
||||
calls: Callable[[], list[dict[str, Any]]],
|
||||
fake_schedule: FakeSchedule,
|
||||
test_entity: MockCalendarEntity,
|
||||
) -> None:
|
||||
"""Test that a trigger fires for multiple events."""
|
||||
|
||||
event_data1 = fake_schedule.create_event(
|
||||
event_data1 = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 10:45:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"),
|
||||
)
|
||||
event_data2 = fake_schedule.create_event(
|
||||
event_data2 = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 11:15:00+00:00"),
|
||||
)
|
||||
|
@ -389,14 +360,15 @@ async def test_multiple_end_events(
|
|||
hass: HomeAssistant,
|
||||
calls: Callable[[], list[dict[str, Any]]],
|
||||
fake_schedule: FakeSchedule,
|
||||
test_entity: MockCalendarEntity,
|
||||
) -> None:
|
||||
"""Test that a trigger fires for multiple events."""
|
||||
|
||||
event_data1 = fake_schedule.create_event(
|
||||
event_data1 = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 10:45:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"),
|
||||
)
|
||||
event_data2 = fake_schedule.create_event(
|
||||
event_data2 = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 11:15:00+00:00"),
|
||||
)
|
||||
|
@ -423,14 +395,15 @@ async def test_multiple_events_sharing_start_time(
|
|||
hass: HomeAssistant,
|
||||
calls: Callable[[], list[dict[str, Any]]],
|
||||
fake_schedule: FakeSchedule,
|
||||
test_entity: MockCalendarEntity,
|
||||
) -> None:
|
||||
"""Test that a trigger fires for every event sharing a start time."""
|
||||
|
||||
event_data1 = fake_schedule.create_event(
|
||||
event_data1 = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00"),
|
||||
)
|
||||
event_data2 = fake_schedule.create_event(
|
||||
event_data2 = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00"),
|
||||
)
|
||||
|
@ -457,14 +430,15 @@ async def test_overlap_events(
|
|||
hass: HomeAssistant,
|
||||
calls: Callable[[], list[dict[str, Any]]],
|
||||
fake_schedule: FakeSchedule,
|
||||
test_entity: MockCalendarEntity,
|
||||
) -> None:
|
||||
"""Test that a trigger fires for events that overlap."""
|
||||
|
||||
event_data1 = fake_schedule.create_event(
|
||||
event_data1 = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00"),
|
||||
)
|
||||
event_data2 = fake_schedule.create_event(
|
||||
event_data2 = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 11:15:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 11:45:00+00:00"),
|
||||
)
|
||||
|
@ -533,10 +507,11 @@ async def test_update_next_event(
|
|||
hass: HomeAssistant,
|
||||
calls: Callable[[], list[dict[str, Any]]],
|
||||
fake_schedule: FakeSchedule,
|
||||
test_entity: MockCalendarEntity,
|
||||
) -> None:
|
||||
"""Test detection of a new event after initial trigger is setup."""
|
||||
|
||||
event_data1 = fake_schedule.create_event(
|
||||
event_data1 = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 11:15:00+00:00"),
|
||||
)
|
||||
|
@ -548,7 +523,7 @@ async def test_update_next_event(
|
|||
assert len(calls()) == 0
|
||||
|
||||
# Create a new event between now and when the event fires
|
||||
event_data2 = fake_schedule.create_event(
|
||||
event_data2 = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 10:55:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 11:05:00+00:00"),
|
||||
)
|
||||
|
@ -575,10 +550,11 @@ async def test_update_missed(
|
|||
hass: HomeAssistant,
|
||||
calls: Callable[[], list[dict[str, Any]]],
|
||||
fake_schedule: FakeSchedule,
|
||||
test_entity: MockCalendarEntity,
|
||||
) -> None:
|
||||
"""Test that new events are missed if they arrive outside the update interval."""
|
||||
|
||||
event_data1 = fake_schedule.create_event(
|
||||
event_data1 = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 11:00:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00"),
|
||||
)
|
||||
|
@ -590,7 +566,7 @@ async def test_update_missed(
|
|||
)
|
||||
assert len(calls()) == 0
|
||||
|
||||
fake_schedule.create_event(
|
||||
test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 10:40:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 10:55:00+00:00"),
|
||||
)
|
||||
|
@ -664,13 +640,14 @@ async def test_event_payload(
|
|||
hass: HomeAssistant,
|
||||
calls: Callable[[], list[dict[str, Any]]],
|
||||
fake_schedule: FakeSchedule,
|
||||
test_entity: MockCalendarEntity,
|
||||
set_time_zone: None,
|
||||
create_data,
|
||||
fire_time,
|
||||
payload_data,
|
||||
) -> None:
|
||||
"""Test the fields in the calendar event payload are set."""
|
||||
fake_schedule.create_event(**create_data)
|
||||
test_entity.create_event(**create_data)
|
||||
async with create_automation(hass, EVENT_START):
|
||||
assert len(calls()) == 0
|
||||
|
||||
|
@ -688,13 +665,14 @@ async def test_trigger_timestamp_window_edge(
|
|||
hass: HomeAssistant,
|
||||
calls: Callable[[], list[dict[str, Any]]],
|
||||
fake_schedule: FakeSchedule,
|
||||
test_entity: MockCalendarEntity,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test that events in the edge of a scan are included."""
|
||||
freezer.move_to("2022-04-19 11:00:00+00:00")
|
||||
# Exactly at a TEST_UPDATE_INTERVAL boundary the start time,
|
||||
# making this excluded from the first window.
|
||||
event_data = fake_schedule.create_event(
|
||||
event_data = test_entity.create_event(
|
||||
start=datetime.datetime.fromisoformat("2022-04-19 11:14:00+00:00"),
|
||||
end=datetime.datetime.fromisoformat("2022-04-19 11:30:00+00:00"),
|
||||
)
|
||||
|
@ -717,6 +695,7 @@ async def test_event_start_trigger_dst(
|
|||
hass: HomeAssistant,
|
||||
calls: Callable[[], list[dict[str, Any]]],
|
||||
fake_schedule: FakeSchedule,
|
||||
test_entity: MockCalendarEntity,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test a calendar event trigger happening at the start of daylight savings time."""
|
||||
|
@ -725,19 +704,19 @@ async def test_event_start_trigger_dst(
|
|||
freezer.move_to("2023-03-12 01:00:00-08:00")
|
||||
|
||||
# Before DST transition starts
|
||||
event1_data = fake_schedule.create_event(
|
||||
event1_data = test_entity.create_event(
|
||||
summary="Event 1",
|
||||
start=datetime.datetime(2023, 3, 12, 1, 30, tzinfo=tzinfo),
|
||||
end=datetime.datetime(2023, 3, 12, 1, 45, tzinfo=tzinfo),
|
||||
)
|
||||
# During DST transition (Clocks are turned forward at 2am to 3am)
|
||||
event2_data = fake_schedule.create_event(
|
||||
event2_data = test_entity.create_event(
|
||||
summary="Event 2",
|
||||
start=datetime.datetime(2023, 3, 12, 2, 30, tzinfo=tzinfo),
|
||||
end=datetime.datetime(2023, 3, 12, 2, 45, tzinfo=tzinfo),
|
||||
)
|
||||
# After DST transition has ended
|
||||
event3_data = fake_schedule.create_event(
|
||||
event3_data = test_entity.create_event(
|
||||
summary="Event 3",
|
||||
start=datetime.datetime(2023, 3, 12, 3, 30, tzinfo=tzinfo),
|
||||
end=datetime.datetime(2023, 3, 12, 3, 45, tzinfo=tzinfo),
|
||||
|
|
Loading…
Add table
Reference in a new issue