* Fix CalDAV parsing of recurring events Some CaDAV servers (see: SOGo) return the original event that contains the recurrence rules. The CalDAV calendar component sorts and filters events based on their start and end dates, and was failing to properly show recurring events based on these recurrence rules. This this change checks if an event has recurrence rules and changes the start/end dates of the event to today if the event is set to occur today. This allows the rest of the component logic to function properly. * Use date from nextmost occurence * Adding unit tests * Add endless event unit test * Create new vevent for each event recurrence today * Remove redundant unit test * Add timezone to events that have none Python cannot compare them otherwise. * Simplify code, add comments & guard clause * Add test for recurring all day event * Account for all-day events * Remove redundant code * Remove redundant code * Remove unnecessary deepcopy * Add hourly recurring tests * Add tests for hourly repeating event * Fix unit test * Use event.copy()
777 lines
24 KiB
Python
777 lines
24 KiB
Python
"""The tests for the webdav calendar component."""
|
|
import datetime
|
|
from unittest.mock import MagicMock, Mock
|
|
|
|
from asynctest import patch
|
|
from caldav.objects import Event
|
|
import pytest
|
|
|
|
from homeassistant.const import STATE_OFF, STATE_ON
|
|
from homeassistant.setup import async_setup_component
|
|
from homeassistant.util import dt
|
|
|
|
# pylint: disable=redefined-outer-name
|
|
|
|
DEVICE_DATA = {"name": "Private Calendar", "device_id": "Private Calendar"}
|
|
|
|
EVENTS = [
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//E-Corp.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:1
|
|
DTSTAMP:20171125T000000Z
|
|
DTSTART:20171127T170000Z
|
|
DTEND:20171127T180000Z
|
|
SUMMARY:This is a normal event
|
|
LOCATION:Hamburg
|
|
DESCRIPTION:Surprisingly rainy
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//Global Dynamics.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:2
|
|
DTSTAMP:20171125T000000Z
|
|
DTSTART:20171127T100000Z
|
|
DTEND:20171127T110000Z
|
|
SUMMARY:This is an offset event !!-02:00
|
|
LOCATION:Hamburg
|
|
DESCRIPTION:Surprisingly shiny
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//Global Corp.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:3
|
|
DTSTAMP:20171125T000000Z
|
|
DTSTART:20171127
|
|
DTEND:20171128
|
|
SUMMARY:This is an all day event
|
|
LOCATION:Hamburg
|
|
DESCRIPTION:What a beautiful day
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//Global Corp.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:4
|
|
DTSTAMP:20171125T000000Z
|
|
DTSTART:20171127
|
|
SUMMARY:This is an event without dtend or duration
|
|
LOCATION:Hamburg
|
|
DESCRIPTION:What an endless day
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//Global Corp.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:5
|
|
DTSTAMP:20171125T000000Z
|
|
DTSTART:20171127
|
|
DURATION:PT1H
|
|
SUMMARY:This is an event with duration
|
|
LOCATION:Hamburg
|
|
DESCRIPTION:What a day
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//Global Corp.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:6
|
|
DTSTAMP:20171125T000000Z
|
|
DTSTART:20171127T100000Z
|
|
DURATION:PT1H
|
|
SUMMARY:This is an event with duration
|
|
LOCATION:Hamburg
|
|
DESCRIPTION:What a day
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//Global Corp.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:7
|
|
DTSTART;TZID=America/Los_Angeles:20171127T083000
|
|
DTSTAMP:20180301T020053Z
|
|
DTEND;TZID=America/Los_Angeles:20171127T093000
|
|
SUMMARY:Enjoy the sun
|
|
LOCATION:San Francisco
|
|
DESCRIPTION:Sunny day
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//Global Corp.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:8
|
|
DTSTART:20171127T190000
|
|
DTEND:20171127T200000
|
|
SUMMARY:This is a floating Event
|
|
LOCATION:Hamburg
|
|
DESCRIPTION:What a day
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//E-Corp.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:9
|
|
DTSTAMP:20171125T000000Z
|
|
DTSTART:20171027T220000Z
|
|
DTEND:20171027T223000Z
|
|
SUMMARY:This is a recurring event
|
|
LOCATION:Hamburg
|
|
DESCRIPTION:Every day for a while
|
|
RRULE:FREQ=DAILY;UNTIL=20171227T215959
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//E-Corp.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:10
|
|
DTSTAMP:20171125T000000Z
|
|
DTSTART:20171027T230000Z
|
|
DURATION:PT30M
|
|
SUMMARY:This is a recurring event with a duration
|
|
LOCATION:Hamburg
|
|
DESCRIPTION:Every day for a while as well
|
|
RRULE:FREQ=DAILY;UNTIL=20171227T215959
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//E-Corp.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:11
|
|
DTSTAMP:20171125T000000Z
|
|
DTSTART:20171027T233000Z
|
|
DTEND:20171027T235959Z
|
|
SUMMARY:This is a recurring event that has ended
|
|
LOCATION:Hamburg
|
|
DESCRIPTION:Every day for a while
|
|
RRULE:FREQ=DAILY;UNTIL=20171127T225959
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//E-Corp.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:12
|
|
DTSTAMP:20171125T000000Z
|
|
DTSTART:20171027T234500Z
|
|
DTEND:20171027T235959Z
|
|
SUMMARY:This is a recurring event that never ends
|
|
LOCATION:Hamburg
|
|
DESCRIPTION:Every day forever
|
|
RRULE:FREQ=DAILY
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//Global Corp.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:13
|
|
DTSTAMP:20161125T000000Z
|
|
DTSTART:20161127
|
|
DTEND:20161128
|
|
SUMMARY:This is a recurring all day event
|
|
LOCATION:Hamburg
|
|
DESCRIPTION:Groundhog Day
|
|
RRULE:FREQ=DAILY;COUNT=100
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
"""BEGIN:VCALENDAR
|
|
VERSION:2.0
|
|
PRODID:-//Global Corp.//CalDAV Client//EN
|
|
BEGIN:VEVENT
|
|
UID:14
|
|
DTSTAMP:20151125T000000Z
|
|
DTSTART:20151127T000000Z
|
|
DTEND:20151127T003000Z
|
|
SUMMARY:This is an hourly recurring event
|
|
LOCATION:Hamburg
|
|
DESCRIPTION:The bell tolls for thee
|
|
RRULE:FREQ=HOURLY;INTERVAL=1;COUNT=12
|
|
END:VEVENT
|
|
END:VCALENDAR
|
|
""",
|
|
]
|
|
|
|
CALDAV_CONFIG = {
|
|
"platform": "caldav",
|
|
"url": "http://test.local",
|
|
"custom_calendars": [],
|
|
}
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def mock_http(hass):
|
|
"""Mock the http component."""
|
|
hass.http = Mock()
|
|
|
|
|
|
@pytest.fixture
|
|
def mock_dav_client():
|
|
"""Mock the dav client."""
|
|
patch_dav_client = patch(
|
|
"caldav.DAVClient", return_value=_mocked_dav_client("First", "Second")
|
|
)
|
|
with patch_dav_client as dav_client:
|
|
yield dav_client
|
|
|
|
|
|
@pytest.fixture(name="calendar")
|
|
def mock_private_cal():
|
|
"""Mock a private calendar."""
|
|
_calendar = _mock_calendar("Private")
|
|
calendars = [_calendar]
|
|
client = _mocked_dav_client(calendars=calendars)
|
|
patch_dav_client = patch("caldav.DAVClient", return_value=client)
|
|
with patch_dav_client:
|
|
yield _calendar
|
|
|
|
|
|
def _local_datetime(hours, minutes):
|
|
"""Build a datetime object for testing in the correct timezone."""
|
|
return dt.as_local(datetime.datetime(2017, 11, 27, hours, minutes, 0))
|
|
|
|
|
|
def _mocked_dav_client(*names, calendars=None):
|
|
"""Mock requests.get invocations."""
|
|
if calendars is None:
|
|
calendars = [_mock_calendar(name) for name in names]
|
|
principal = Mock()
|
|
principal.calendars = MagicMock(return_value=calendars)
|
|
|
|
client = Mock()
|
|
client.principal = MagicMock(return_value=principal)
|
|
return client
|
|
|
|
|
|
def _mock_calendar(name):
|
|
events = []
|
|
for idx, event in enumerate(EVENTS):
|
|
events.append(Event(None, "%d.ics" % idx, event, None, str(idx)))
|
|
|
|
calendar = Mock()
|
|
calendar.date_search = MagicMock(return_value=events)
|
|
calendar.name = name
|
|
return calendar
|
|
|
|
|
|
async def test_setup_component(hass, mock_dav_client):
|
|
"""Test setup component with calendars."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.first")
|
|
assert state.name == "First"
|
|
state = hass.states.get("calendar.second")
|
|
assert state.name == "Second"
|
|
|
|
|
|
async def test_setup_component_with_no_calendar_matching(hass, mock_dav_client):
|
|
"""Test setup component with wrong calendar."""
|
|
config = dict(CALDAV_CONFIG)
|
|
config["calendars"] = ["none"]
|
|
|
|
assert await async_setup_component(hass, "calendar", {"calendar": config})
|
|
await hass.async_block_till_done()
|
|
|
|
all_calendar_states = hass.states.async_entity_ids("calendar")
|
|
assert not all_calendar_states
|
|
|
|
|
|
async def test_setup_component_with_a_calendar_match(hass, mock_dav_client):
|
|
"""Test setup component with right calendar."""
|
|
config = dict(CALDAV_CONFIG)
|
|
config["calendars"] = ["Second"]
|
|
|
|
assert await async_setup_component(hass, "calendar", {"calendar": config})
|
|
await hass.async_block_till_done()
|
|
|
|
all_calendar_states = hass.states.async_entity_ids("calendar")
|
|
assert len(all_calendar_states) == 1
|
|
state = hass.states.get("calendar.second")
|
|
assert state.name == "Second"
|
|
|
|
|
|
async def test_setup_component_with_one_custom_calendar(hass, mock_dav_client):
|
|
"""Test setup component with custom calendars."""
|
|
config = dict(CALDAV_CONFIG)
|
|
config["custom_calendars"] = [
|
|
{"name": "HomeOffice", "calendar": "Second", "search": "HomeOffice"}
|
|
]
|
|
|
|
assert await async_setup_component(hass, "calendar", {"calendar": config})
|
|
await hass.async_block_till_done()
|
|
|
|
all_calendar_states = hass.states.async_entity_ids("calendar")
|
|
assert len(all_calendar_states) == 1
|
|
state = hass.states.get("calendar.second_homeoffice")
|
|
assert state.name == "HomeOffice"
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(17, 45))
|
|
async def test_ongoing_event(mock_now, hass, calendar):
|
|
"""Test that the ongoing event is returned."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_ON
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is a normal event",
|
|
"all_day": False,
|
|
"offset_reached": False,
|
|
"start_time": "2017-11-27 17:00:00",
|
|
"end_time": "2017-11-27 18:00:00",
|
|
"location": "Hamburg",
|
|
"description": "Surprisingly rainy",
|
|
}
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(17, 30))
|
|
async def test_just_ended_event(mock_now, hass, calendar):
|
|
"""Test that the next ongoing event is returned."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_ON
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is a normal event",
|
|
"all_day": False,
|
|
"offset_reached": False,
|
|
"start_time": "2017-11-27 17:00:00",
|
|
"end_time": "2017-11-27 18:00:00",
|
|
"location": "Hamburg",
|
|
"description": "Surprisingly rainy",
|
|
}
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(17, 00))
|
|
async def test_ongoing_event_different_tz(mock_now, hass, calendar):
|
|
"""Test that the ongoing event with another timezone is returned."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_ON
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "Enjoy the sun",
|
|
"all_day": False,
|
|
"offset_reached": False,
|
|
"start_time": "2017-11-27 16:30:00",
|
|
"description": "Sunny day",
|
|
"end_time": "2017-11-27 17:30:00",
|
|
"location": "San Francisco",
|
|
}
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(19, 10))
|
|
async def test_ongoing_floating_event_returned(mock_now, hass, calendar):
|
|
"""Test that floating events without timezones work."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
print(dt.DEFAULT_TIME_ZONE)
|
|
print(state)
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_ON
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is a floating Event",
|
|
"all_day": False,
|
|
"offset_reached": False,
|
|
"start_time": "2017-11-27 19:00:00",
|
|
"end_time": "2017-11-27 20:00:00",
|
|
"location": "Hamburg",
|
|
"description": "What a day",
|
|
}
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(8, 30))
|
|
async def test_ongoing_event_with_offset(mock_now, hass, calendar):
|
|
"""Test that the offset is taken into account."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_OFF
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is an offset event",
|
|
"all_day": False,
|
|
"offset_reached": True,
|
|
"start_time": "2017-11-27 10:00:00",
|
|
"end_time": "2017-11-27 11:00:00",
|
|
"location": "Hamburg",
|
|
"description": "Surprisingly shiny",
|
|
}
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(12, 00))
|
|
async def test_matching_filter(mock_now, hass, calendar):
|
|
"""Test that the matching event is returned."""
|
|
config = dict(CALDAV_CONFIG)
|
|
config["custom_calendars"] = [
|
|
{"name": "Private", "calendar": "Private", "search": "This is a normal event"}
|
|
]
|
|
|
|
assert await async_setup_component(hass, "calendar", {"calendar": config})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private_private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_OFF
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is a normal event",
|
|
"all_day": False,
|
|
"offset_reached": False,
|
|
"start_time": "2017-11-27 17:00:00",
|
|
"end_time": "2017-11-27 18:00:00",
|
|
"location": "Hamburg",
|
|
"description": "Surprisingly rainy",
|
|
}
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(12, 00))
|
|
async def test_matching_filter_real_regexp(mock_now, hass, calendar):
|
|
"""Test that the event matching the regexp is returned."""
|
|
config = dict(CALDAV_CONFIG)
|
|
config["custom_calendars"] = [
|
|
{"name": "Private", "calendar": "Private", "search": r".*rainy"}
|
|
]
|
|
|
|
assert await async_setup_component(hass, "calendar", {"calendar": config})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private_private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_OFF
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is a normal event",
|
|
"all_day": False,
|
|
"offset_reached": False,
|
|
"start_time": "2017-11-27 17:00:00",
|
|
"end_time": "2017-11-27 18:00:00",
|
|
"location": "Hamburg",
|
|
"description": "Surprisingly rainy",
|
|
}
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(20, 00))
|
|
async def test_filter_matching_past_event(mock_now, hass, calendar):
|
|
"""Test that the matching past event is not returned."""
|
|
config = dict(CALDAV_CONFIG)
|
|
config["custom_calendars"] = [
|
|
{"name": "Private", "calendar": "Private", "search": "This is a normal event"}
|
|
]
|
|
|
|
assert await async_setup_component(hass, "calendar", {"calendar": config})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private_private")
|
|
assert state.name == calendar.name
|
|
assert state.state == "off"
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(12, 00))
|
|
async def test_no_result_with_filtering(mock_now, hass, calendar):
|
|
"""Test that nothing is returned since nothing matches."""
|
|
config = dict(CALDAV_CONFIG)
|
|
config["custom_calendars"] = [
|
|
{
|
|
"name": "Private",
|
|
"calendar": "Private",
|
|
"search": "This is a non-existing event",
|
|
}
|
|
]
|
|
|
|
assert await async_setup_component(hass, "calendar", {"calendar": config})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private_private")
|
|
assert state.name == calendar.name
|
|
assert state.state == "off"
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(17, 30))
|
|
async def test_all_day_event_returned(mock_now, hass, calendar):
|
|
"""Test that the event lasting the whole day is returned."""
|
|
config = dict(CALDAV_CONFIG)
|
|
config["custom_calendars"] = [
|
|
{"name": "Private", "calendar": "Private", "search": ".*"}
|
|
]
|
|
|
|
assert await async_setup_component(hass, "calendar", {"calendar": config})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private_private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_ON
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is an all day event",
|
|
"all_day": True,
|
|
"offset_reached": False,
|
|
"start_time": "2017-11-27 00:00:00",
|
|
"end_time": "2017-11-28 00:00:00",
|
|
"location": "Hamburg",
|
|
"description": "What a beautiful day",
|
|
}
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(21, 45))
|
|
async def test_event_rrule(mock_now, hass, calendar):
|
|
"""Test that the future recurring event is returned."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_OFF
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is a recurring event",
|
|
"all_day": False,
|
|
"offset_reached": False,
|
|
"start_time": "2017-11-27 22:00:00",
|
|
"end_time": "2017-11-27 22:30:00",
|
|
"location": "Hamburg",
|
|
"description": "Every day for a while",
|
|
}
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(22, 15))
|
|
async def test_event_rrule_ongoing(mock_now, hass, calendar):
|
|
"""Test that the current recurring event is returned."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_ON
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is a recurring event",
|
|
"all_day": False,
|
|
"offset_reached": False,
|
|
"start_time": "2017-11-27 22:00:00",
|
|
"end_time": "2017-11-27 22:30:00",
|
|
"location": "Hamburg",
|
|
"description": "Every day for a while",
|
|
}
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(22, 45))
|
|
async def test_event_rrule_duration(mock_now, hass, calendar):
|
|
"""Test that the future recurring event is returned."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_OFF
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is a recurring event with a duration",
|
|
"all_day": False,
|
|
"offset_reached": False,
|
|
"start_time": "2017-11-27 23:00:00",
|
|
"end_time": "2017-11-27 23:30:00",
|
|
"location": "Hamburg",
|
|
"description": "Every day for a while as well",
|
|
}
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(23, 15))
|
|
async def test_event_rrule_duration_ongoing(mock_now, hass, calendar):
|
|
"""Test that the ongoing recurring event is returned."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_ON
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is a recurring event with a duration",
|
|
"all_day": False,
|
|
"offset_reached": False,
|
|
"start_time": "2017-11-27 23:00:00",
|
|
"end_time": "2017-11-27 23:30:00",
|
|
"location": "Hamburg",
|
|
"description": "Every day for a while as well",
|
|
}
|
|
|
|
|
|
@patch("homeassistant.util.dt.now", return_value=_local_datetime(23, 37))
|
|
async def test_event_rrule_endless(mock_now, hass, calendar):
|
|
"""Test that the endless recurring event is returned."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_OFF
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is a recurring event that never ends",
|
|
"all_day": False,
|
|
"offset_reached": False,
|
|
"start_time": "2017-11-27 23:45:00",
|
|
"end_time": "2017-11-27 23:59:59",
|
|
"location": "Hamburg",
|
|
"description": "Every day forever",
|
|
}
|
|
|
|
|
|
@patch(
|
|
"homeassistant.util.dt.now",
|
|
return_value=dt.as_local(datetime.datetime(2016, 12, 1, 17, 30)),
|
|
)
|
|
async def test_event_rrule_all_day(mock_now, hass, calendar):
|
|
"""Test that the recurring all day event is returned."""
|
|
config = dict(CALDAV_CONFIG)
|
|
config["custom_calendars"] = [
|
|
{"name": "Private", "calendar": "Private", "search": ".*"}
|
|
]
|
|
|
|
assert await async_setup_component(hass, "calendar", {"calendar": config})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private_private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_ON
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is a recurring all day event",
|
|
"all_day": True,
|
|
"offset_reached": False,
|
|
"start_time": "2016-12-01 00:00:00",
|
|
"end_time": "2016-12-02 00:00:00",
|
|
"location": "Hamburg",
|
|
"description": "Groundhog Day",
|
|
}
|
|
|
|
|
|
@patch(
|
|
"homeassistant.util.dt.now",
|
|
return_value=dt.as_local(datetime.datetime(2015, 11, 27, 0, 15)),
|
|
)
|
|
async def test_event_rrule_hourly_on_first(mock_now, hass, calendar):
|
|
"""Test that the endless recurring event is returned."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_ON
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is an hourly recurring event",
|
|
"all_day": False,
|
|
"offset_reached": False,
|
|
"start_time": "2015-11-27 00:00:00",
|
|
"end_time": "2015-11-27 00:30:00",
|
|
"location": "Hamburg",
|
|
"description": "The bell tolls for thee",
|
|
}
|
|
|
|
|
|
@patch(
|
|
"homeassistant.util.dt.now",
|
|
return_value=dt.as_local(datetime.datetime(2015, 11, 27, 11, 15)),
|
|
)
|
|
async def test_event_rrule_hourly_on_last(mock_now, hass, calendar):
|
|
"""Test that the endless recurring event is returned."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_ON
|
|
assert dict(state.attributes) == {
|
|
"friendly_name": "Private",
|
|
"message": "This is an hourly recurring event",
|
|
"all_day": False,
|
|
"offset_reached": False,
|
|
"start_time": "2015-11-27 11:00:00",
|
|
"end_time": "2015-11-27 11:30:00",
|
|
"location": "Hamburg",
|
|
"description": "The bell tolls for thee",
|
|
}
|
|
|
|
|
|
@patch(
|
|
"homeassistant.util.dt.now",
|
|
return_value=dt.as_local(datetime.datetime(2015, 11, 27, 0, 45)),
|
|
)
|
|
async def test_event_rrule_hourly_off_first(mock_now, hass, calendar):
|
|
"""Test that the endless recurring event is returned."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_OFF
|
|
|
|
|
|
@patch(
|
|
"homeassistant.util.dt.now",
|
|
return_value=dt.as_local(datetime.datetime(2015, 11, 27, 11, 45)),
|
|
)
|
|
async def test_event_rrule_hourly_off_last(mock_now, hass, calendar):
|
|
"""Test that the endless recurring event is returned."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_OFF
|
|
|
|
|
|
@patch(
|
|
"homeassistant.util.dt.now",
|
|
return_value=dt.as_local(datetime.datetime(2015, 11, 27, 12, 15)),
|
|
)
|
|
async def test_event_rrule_hourly_ended(mock_now, hass, calendar):
|
|
"""Test that the endless recurring event is returned."""
|
|
assert await async_setup_component(hass, "calendar", {"calendar": CALDAV_CONFIG})
|
|
await hass.async_block_till_done()
|
|
|
|
state = hass.states.get("calendar.private")
|
|
assert state.name == calendar.name
|
|
assert state.state == STATE_OFF
|