Skip to content

Commit

Permalink
Updated tests for home-assistant#25814
Browse files Browse the repository at this point in the history
Please notes that unit tests were inadequate in the past, or 28514
would have been caught.  The new tests set one of three time zones
explicitly for all day event tests, and the all day event tests have
been modified to patch the return value of homeassistant.util.dt.now to
be in the local time zone, instead of always UTC.  By having it return
times in the local time zone, the tests better match real-world usage --
homeassistant.util.dt.now wouldn't return a UTC time when a different
time zone is set.

The unit tests now check for a single occurrence all day event at the
beginning of the local day, in the middle of the local day, and at the
end of the local day.  Each check is run in three separate time zones,
Asia/Baghdad, UTC, and America/New_York.  The times are chose such that
the early in the local day time for Asia/Baghdad is actually the day
before in UTC, and the late in the local day time for America/New_York
is actually the next day in UTC.  This guarantees that when the tests
pass, there are no internal checks that shifted what should be a local
time as if it were UTC being shifted to local time, which was bug home-assistant#25814.

Similar changes were made for the recurring all day event test, too.

Note that if you run the new unit tests without the fixed code in this
patch, that the following tests will fail:

test_all_day_event_returned_early[pyloop-baghdad]
test_all_day_event_returned_late[pyloop-new_york]
test_event_rrule_all_day_late[pyloop-new_york]

After applying the fix, all tests will succeed.  If you're wondering why
test_event_rrule_all_day_early[pyloop-baghdad] doesn't fail without the
fix, it's because we're not checking on the first occurrence of the
event.  If we did that, the test would fail just like
test_all_day_event_returned_early[pyloop-baghdad].  However, since by
checking the first occurrence we're running the same condition that
test_all_day_event_returned_early[pyloop-baghdad] already checks, it
would be redundant to add a test which fails for a recurring event in
that time zone.  The whole point of the test_event_rrule_all_day tests
is to ensure that recurrences are returned when it's not the first
occurrence.
  • Loading branch information
franc6 committed Jun 10, 2021
1 parent 0c4ae00 commit 4397362
Showing 1 changed file with 153 additions and 39 deletions.
192 changes: 153 additions & 39 deletions tests/components/caldav/test_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,39 @@
"custom_calendars": [],
}

ORIG_TZ = dt.DEFAULT_TIME_ZONE


@pytest.fixture(autouse=True)
def reset_tz():
"""Restore the default TZ after test runs."""
yield
dt.DEFAULT_TIME_ZONE = ORIG_TZ


@pytest.fixture
def set_tz(request):
"""Set the default TZ to the one requested."""
return request.getfixturevalue(request.param)


@pytest.fixture
def utc():
"""Set the default TZ to UTC."""
dt.set_default_time_zone(dt.get_time_zone("UTC"))


@pytest.fixture
def new_york():
"""Set the default TZ to America/New_York."""
dt.set_default_time_zone(dt.get_time_zone("America/New_York"))


@pytest.fixture
def baghdad():
"""Set the default TZ to Asia/Baghdad."""
dt.set_default_time_zone(dt.get_time_zone("Asia/Baghdad"))


@pytest.fixture(autouse=True)
def mock_http(hass):
Expand Down Expand Up @@ -526,30 +559,72 @@ async def test_no_result_with_filtering(mock_now, hass, calendar):
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."""
async def _day_event_returned(hass, calendar, config, date_time):
with patch("homeassistant.util.dt.now", return_value=date_time):
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",
}


@pytest.mark.parametrize("set_tz", ["utc", "new_york", "baghdad"], indirect=True)
async def test_all_day_event_returned_early(hass, calendar, set_tz):
"""Test that the event lasting the whole day is returned, if it's early in the local day."""
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()
await _day_event_returned(
hass,
calendar,
config,
datetime.datetime(2017, 11, 27, 0, 30).replace(tzinfo=dt.DEFAULT_TIME_ZONE),
)


@pytest.mark.parametrize("set_tz", ["utc", "new_york", "baghdad"], indirect=True)
async def test_all_day_event_returned_mid(hass, calendar, set_tz):
"""Test that the event lasting the whole day is returned, if it's in the middle of the local day."""
config = dict(CALDAV_CONFIG)
config["custom_calendars"] = [
{"name": "Private", "calendar": "Private", "search": ".*"}
]

await _day_event_returned(
hass,
calendar,
config,
datetime.datetime(2017, 11, 27, 12, 30).replace(tzinfo=dt.DEFAULT_TIME_ZONE),
)

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",
}

@pytest.mark.parametrize("set_tz", ["utc", "new_york", "baghdad"], indirect=True)
async def test_all_day_event_returned_late(hass, calendar, set_tz):
"""Test that the event lasting the whole day is returned, if it's late in the local day."""
config = dict(CALDAV_CONFIG)
config["custom_calendars"] = [
{"name": "Private", "calendar": "Private", "search": ".*"}
]

await _day_event_returned(
hass,
calendar,
config,
datetime.datetime(2017, 11, 27, 23, 30).replace(tzinfo=dt.DEFAULT_TIME_ZONE),
)


@patch("homeassistant.util.dt.now", return_value=_local_datetime(21, 45))
Expand Down Expand Up @@ -657,33 +732,72 @@ async def test_event_rrule_endless(mock_now, hass, calendar):
}


@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."""
async def _event_rrule_all_day(hass, calendar, config, date_time):
with patch("homeassistant.util.dt.now", return_value=date_time):
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",
}


@pytest.mark.parametrize("set_tz", ["utc", "new_york", "baghdad"], indirect=True)
async def test_event_rrule_all_day_early(hass, calendar, set_tz):
"""Test that the recurring all day event is returned early in the local day, and not on the first occurrence."""
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()
await _event_rrule_all_day(
hass,
calendar,
config,
datetime.datetime(2016, 12, 1, 0, 30).replace(tzinfo=dt.DEFAULT_TIME_ZONE),
)

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",
}

@pytest.mark.parametrize("set_tz", ["utc", "new_york", "baghdad"], indirect=True)
async def test_event_rrule_all_day_mid(hass, calendar, set_tz):
"""Test that the recurring all day event is returned in the middle of the local day, and not on the first occurrence."""
config = dict(CALDAV_CONFIG)
config["custom_calendars"] = [
{"name": "Private", "calendar": "Private", "search": ".*"}
]

await _event_rrule_all_day(
hass,
calendar,
config,
datetime.datetime(2016, 12, 1, 17, 30).replace(tzinfo=dt.DEFAULT_TIME_ZONE),
)


@pytest.mark.parametrize("set_tz", ["utc", "new_york", "baghdad"], indirect=True)
async def test_event_rrule_all_day_late(hass, calendar, set_tz):
"""Test that the recurring all day event is returned late in the local day, and not on the first occurrence."""
config = dict(CALDAV_CONFIG)
config["custom_calendars"] = [
{"name": "Private", "calendar": "Private", "search": ".*"}
]

await _event_rrule_all_day(
hass,
calendar,
config,
datetime.datetime(2016, 12, 1, 23, 30).replace(tzinfo=dt.DEFAULT_TIME_ZONE),
)


@patch(
Expand Down

0 comments on commit 4397362

Please sign in to comment.