diff --git a/tests/components/calendar/conftest.py b/tests/components/calendar/conftest.py index 5d506d67c6f..f42cc6fd508 100644 --- a/tests/components/calendar/conftest.py +++ b/tests/components/calendar/conftest.py @@ -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] diff --git a/tests/components/calendar/snapshots/test_init.ambr b/tests/components/calendar/snapshots/test_init.ambr index 67e8839f7a5..fe23c5dbac9 100644 --- a/tests/components/calendar/snapshots/test_init.ambr +++ b/tests/components/calendar/snapshots/test_init.ambr @@ -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', }), ]), diff --git a/tests/components/calendar/test_init.py b/tests/components/calendar/test_init.py index 25804287172..52d5855271d 100644 --- a/tests/components/calendar/test_init.py +++ b/tests/components/calendar/test_init.py @@ -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,40 +76,34 @@ 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"), - ): - response = await client.get( - f"/api/calendars/calendar.calendar_1?start={start.isoformat()}&end={end.isoformat()}" - ) - assert response.status == HTTPStatus.INTERNAL_SERVER_ERROR - assert await response.json() == {"message": "Error reading events: 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()}" + ) + assert response.status == HTTPStatus.INTERNAL_SERVER_ERROR + assert await response.json() == {"message": "Error reading events: Failure"} 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" diff --git a/tests/components/calendar/test_recorder.py b/tests/components/calendar/test_recorder.py index c529789b596..441d757aa4e 100644 --- a/tests/components/calendar/test_recorder.py +++ b/tests/components/calendar/test_recorder.py @@ -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 diff --git a/tests/components/calendar/test_trigger.py b/tests/components/calendar/test_trigger.py index 02aebf3ce92..120d2e8bfca 100644 --- a/tests/components/calendar/test_trigger.py +++ b/tests/components/calendar/test_trigger.py @@ -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),