mirror of
https://github.com/home-assistant/core.git
synced 2025-08-04 13:15:18 +02:00
Fix Google Calendar caching when offline
Events from Google Calendar were not firing under the following circumstances: 1. Start ha as normal with Google Calendar configured as per instructions. 2. ha loses network connectivity to Google 3. ha attempts update of Google Calendar 4. calendar/google component throws uncaught Exception causing update method to not return 5. (cached) Google Calendar event does not fire, remains "Off" Catching the Exception and returning False from the update() method causes the correct behavior (i.e., the calendar component firing the event as scheduled using cached data).
This commit is contained in:
@@ -8,6 +8,8 @@ https://home-assistant.io/components/binary_sensor.google_calendar/
|
|||||||
import logging
|
import logging
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from httplib2 import ServerNotFoundError
|
||||||
|
|
||||||
from homeassistant.components.calendar import CalendarEventDevice
|
from homeassistant.components.calendar import CalendarEventDevice
|
||||||
from homeassistant.components.google import (
|
from homeassistant.components.google import (
|
||||||
CONF_CAL_ID, CONF_ENTITIES, CONF_TRACK, TOKEN_FILE,
|
CONF_CAL_ID, CONF_ENTITIES, CONF_TRACK, TOKEN_FILE,
|
||||||
@@ -62,7 +64,12 @@ class GoogleCalendarData(object):
|
|||||||
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
@Throttle(MIN_TIME_BETWEEN_UPDATES)
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Get the latest data."""
|
"""Get the latest data."""
|
||||||
service = self.calendar_service.get()
|
try:
|
||||||
|
service = self.calendar_service.get()
|
||||||
|
except ServerNotFoundError:
|
||||||
|
_LOGGER.warning("Unable to connect to Google, using cached data")
|
||||||
|
return False
|
||||||
|
|
||||||
params = dict(DEFAULT_GOOGLE_SEARCH_PARAMS)
|
params = dict(DEFAULT_GOOGLE_SEARCH_PARAMS)
|
||||||
params['timeMin'] = dt.now().isoformat('T')
|
params['timeMin'] = dt.now().isoformat('T')
|
||||||
params['calendarId'] = self.calendar_id
|
params['calendarId'] = self.calendar_id
|
||||||
|
@@ -201,3 +201,6 @@ warrant==0.6.1
|
|||||||
|
|
||||||
# homeassistant.components.sensor.yahoo_finance
|
# homeassistant.components.sensor.yahoo_finance
|
||||||
yahoo-finance==1.4.0
|
yahoo-finance==1.4.0
|
||||||
|
|
||||||
|
# homeassistant.components.calendar.google
|
||||||
|
httplib2==0.10.3
|
@@ -2,9 +2,10 @@
|
|||||||
# pylint: disable=protected-access
|
# pylint: disable=protected-access
|
||||||
import logging
|
import logging
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch, Mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from httplib2 import ServerNotFoundError
|
||||||
|
|
||||||
import homeassistant.components.calendar as calendar_base
|
import homeassistant.components.calendar as calendar_base
|
||||||
import homeassistant.components.calendar.google as calendar
|
import homeassistant.components.calendar.google as calendar
|
||||||
@@ -42,16 +43,16 @@ class TestComponentsGoogleCalendar(unittest.TestCase):
|
|||||||
@patch('homeassistant.components.calendar.google.GoogleCalendarData')
|
@patch('homeassistant.components.calendar.google.GoogleCalendarData')
|
||||||
def test_all_day_event(self, mock_next_event):
|
def test_all_day_event(self, mock_next_event):
|
||||||
"""Test that we can create an event trigger on device."""
|
"""Test that we can create an event trigger on device."""
|
||||||
week_from_today = dt_util.dt.date.today() \
|
week_from_today = dt_util.dt.date.today() + dt_util.dt.timedelta(
|
||||||
+ dt_util.dt.timedelta(days=7)
|
days=7)
|
||||||
event = {
|
event = {
|
||||||
'summary': 'Test All Day Event',
|
'summary': 'Test All Day Event',
|
||||||
'start': {
|
'start': {
|
||||||
'date': week_from_today.isoformat()
|
'date': week_from_today.isoformat()
|
||||||
},
|
},
|
||||||
'end': {
|
'end': {
|
||||||
'date': (week_from_today + dt_util.dt.timedelta(days=1))
|
'date': (week_from_today + dt_util.dt.timedelta(
|
||||||
.isoformat()
|
days=1)).isoformat()
|
||||||
},
|
},
|
||||||
'location': 'Test Cases',
|
'location': 'Test Cases',
|
||||||
'description': 'We\'re just testing that all day events get setup '
|
'description': 'We\'re just testing that all day events get setup '
|
||||||
@@ -105,16 +106,14 @@ class TestComponentsGoogleCalendar(unittest.TestCase):
|
|||||||
@patch('homeassistant.components.calendar.google.GoogleCalendarData')
|
@patch('homeassistant.components.calendar.google.GoogleCalendarData')
|
||||||
def test_future_event(self, mock_next_event):
|
def test_future_event(self, mock_next_event):
|
||||||
"""Test that we can create an event trigger on device."""
|
"""Test that we can create an event trigger on device."""
|
||||||
one_hour_from_now = dt_util.now() \
|
one_hour_from_now = dt_util.now() + dt_util.dt.timedelta(minutes=30)
|
||||||
+ dt_util.dt.timedelta(minutes=30)
|
|
||||||
event = {
|
event = {
|
||||||
'start': {
|
'start': {
|
||||||
'dateTime': one_hour_from_now.isoformat()
|
'dateTime': one_hour_from_now.isoformat()
|
||||||
},
|
},
|
||||||
'end': {
|
'end': {
|
||||||
'dateTime': (one_hour_from_now
|
'dateTime': (one_hour_from_now
|
||||||
+ dt_util.dt.timedelta(minutes=60))
|
+ dt_util.dt.timedelta(minutes=60)).isoformat()
|
||||||
.isoformat()
|
|
||||||
},
|
},
|
||||||
'summary': 'Test Event in 30 minutes',
|
'summary': 'Test Event in 30 minutes',
|
||||||
'reminders': {'useDefault': True},
|
'reminders': {'useDefault': True},
|
||||||
@@ -157,8 +156,8 @@ class TestComponentsGoogleCalendar(unittest.TestCase):
|
|||||||
'offset_reached': False,
|
'offset_reached': False,
|
||||||
'start_time': one_hour_from_now.strftime(DATE_STR_FORMAT),
|
'start_time': one_hour_from_now.strftime(DATE_STR_FORMAT),
|
||||||
'end_time':
|
'end_time':
|
||||||
(one_hour_from_now + dt_util.dt.timedelta(minutes=60))
|
(one_hour_from_now + dt_util.dt.timedelta(
|
||||||
.strftime(DATE_STR_FORMAT),
|
minutes=60)).strftime(DATE_STR_FORMAT),
|
||||||
'location': '',
|
'location': '',
|
||||||
'description': ''
|
'description': ''
|
||||||
})
|
})
|
||||||
@@ -166,16 +165,14 @@ class TestComponentsGoogleCalendar(unittest.TestCase):
|
|||||||
@patch('homeassistant.components.calendar.google.GoogleCalendarData')
|
@patch('homeassistant.components.calendar.google.GoogleCalendarData')
|
||||||
def test_in_progress_event(self, mock_next_event):
|
def test_in_progress_event(self, mock_next_event):
|
||||||
"""Test that we can create an event trigger on device."""
|
"""Test that we can create an event trigger on device."""
|
||||||
middle_of_event = dt_util.now() \
|
middle_of_event = dt_util.now() - dt_util.dt.timedelta(minutes=30)
|
||||||
- dt_util.dt.timedelta(minutes=30)
|
|
||||||
event = {
|
event = {
|
||||||
'start': {
|
'start': {
|
||||||
'dateTime': middle_of_event.isoformat()
|
'dateTime': middle_of_event.isoformat()
|
||||||
},
|
},
|
||||||
'end': {
|
'end': {
|
||||||
'dateTime': (middle_of_event + dt_util.dt
|
'dateTime': (middle_of_event + dt_util.dt.timedelta(
|
||||||
.timedelta(minutes=60))
|
minutes=60)).isoformat()
|
||||||
.isoformat()
|
|
||||||
},
|
},
|
||||||
'summary': 'Test Event in Progress',
|
'summary': 'Test Event in Progress',
|
||||||
'reminders': {'useDefault': True},
|
'reminders': {'useDefault': True},
|
||||||
@@ -219,8 +216,8 @@ class TestComponentsGoogleCalendar(unittest.TestCase):
|
|||||||
'offset_reached': False,
|
'offset_reached': False,
|
||||||
'start_time': middle_of_event.strftime(DATE_STR_FORMAT),
|
'start_time': middle_of_event.strftime(DATE_STR_FORMAT),
|
||||||
'end_time':
|
'end_time':
|
||||||
(middle_of_event + dt_util.dt.timedelta(minutes=60))
|
(middle_of_event + dt_util.dt.timedelta(minutes=60)).strftime(
|
||||||
.strftime(DATE_STR_FORMAT),
|
DATE_STR_FORMAT),
|
||||||
'location': '',
|
'location': '',
|
||||||
'description': ''
|
'description': ''
|
||||||
})
|
})
|
||||||
@@ -228,17 +225,15 @@ class TestComponentsGoogleCalendar(unittest.TestCase):
|
|||||||
@patch('homeassistant.components.calendar.google.GoogleCalendarData')
|
@patch('homeassistant.components.calendar.google.GoogleCalendarData')
|
||||||
def test_offset_in_progress_event(self, mock_next_event):
|
def test_offset_in_progress_event(self, mock_next_event):
|
||||||
"""Test that we can create an event trigger on device."""
|
"""Test that we can create an event trigger on device."""
|
||||||
middle_of_event = dt_util.now() \
|
middle_of_event = dt_util.now() + dt_util.dt.timedelta(minutes=14)
|
||||||
+ dt_util.dt.timedelta(minutes=14)
|
|
||||||
event_summary = 'Test Event in Progress'
|
event_summary = 'Test Event in Progress'
|
||||||
event = {
|
event = {
|
||||||
'start': {
|
'start': {
|
||||||
'dateTime': middle_of_event.isoformat()
|
'dateTime': middle_of_event.isoformat()
|
||||||
},
|
},
|
||||||
'end': {
|
'end': {
|
||||||
'dateTime': (middle_of_event + dt_util.dt
|
'dateTime': (middle_of_event + dt_util.dt.timedelta(
|
||||||
.timedelta(minutes=60))
|
minutes=60)).isoformat()
|
||||||
.isoformat()
|
|
||||||
},
|
},
|
||||||
'summary': '{} !!-15'.format(event_summary),
|
'summary': '{} !!-15'.format(event_summary),
|
||||||
'reminders': {'useDefault': True},
|
'reminders': {'useDefault': True},
|
||||||
@@ -281,9 +276,8 @@ class TestComponentsGoogleCalendar(unittest.TestCase):
|
|||||||
'all_day': False,
|
'all_day': False,
|
||||||
'offset_reached': True,
|
'offset_reached': True,
|
||||||
'start_time': middle_of_event.strftime(DATE_STR_FORMAT),
|
'start_time': middle_of_event.strftime(DATE_STR_FORMAT),
|
||||||
'end_time':
|
'end_time': (middle_of_event + dt_util.dt.timedelta(
|
||||||
(middle_of_event + dt_util.dt.timedelta(minutes=60))
|
minutes=60)).strftime(DATE_STR_FORMAT),
|
||||||
.strftime(DATE_STR_FORMAT),
|
|
||||||
'location': '',
|
'location': '',
|
||||||
'description': ''
|
'description': ''
|
||||||
})
|
})
|
||||||
@@ -292,8 +286,7 @@ class TestComponentsGoogleCalendar(unittest.TestCase):
|
|||||||
@patch('homeassistant.components.calendar.google.GoogleCalendarData')
|
@patch('homeassistant.components.calendar.google.GoogleCalendarData')
|
||||||
def test_all_day_offset_in_progress_event(self, mock_next_event):
|
def test_all_day_offset_in_progress_event(self, mock_next_event):
|
||||||
"""Test that we can create an event trigger on device."""
|
"""Test that we can create an event trigger on device."""
|
||||||
tomorrow = dt_util.dt.date.today() \
|
tomorrow = dt_util.dt.date.today() + dt_util.dt.timedelta(days=1)
|
||||||
+ dt_util.dt.timedelta(days=1)
|
|
||||||
|
|
||||||
event_summary = 'Test All Day Event Offset In Progress'
|
event_summary = 'Test All Day Event Offset In Progress'
|
||||||
event = {
|
event = {
|
||||||
@@ -302,8 +295,7 @@ class TestComponentsGoogleCalendar(unittest.TestCase):
|
|||||||
'date': tomorrow.isoformat()
|
'date': tomorrow.isoformat()
|
||||||
},
|
},
|
||||||
'end': {
|
'end': {
|
||||||
'date': (tomorrow + dt_util.dt.timedelta(days=1))
|
'date': (tomorrow + dt_util.dt.timedelta(days=1)).isoformat()
|
||||||
.isoformat()
|
|
||||||
},
|
},
|
||||||
'location': 'Test Cases',
|
'location': 'Test Cases',
|
||||||
'description': 'We\'re just testing that all day events get setup '
|
'description': 'We\'re just testing that all day events get setup '
|
||||||
@@ -358,8 +350,7 @@ class TestComponentsGoogleCalendar(unittest.TestCase):
|
|||||||
@patch('homeassistant.components.calendar.google.GoogleCalendarData')
|
@patch('homeassistant.components.calendar.google.GoogleCalendarData')
|
||||||
def test_all_day_offset_event(self, mock_next_event):
|
def test_all_day_offset_event(self, mock_next_event):
|
||||||
"""Test that we can create an event trigger on device."""
|
"""Test that we can create an event trigger on device."""
|
||||||
tomorrow = dt_util.dt.date.today() \
|
tomorrow = dt_util.dt.date.today() + dt_util.dt.timedelta(days=2)
|
||||||
+ dt_util.dt.timedelta(days=2)
|
|
||||||
|
|
||||||
offset_hours = (1 + dt_util.now().hour)
|
offset_hours = (1 + dt_util.now().hour)
|
||||||
event_summary = 'Test All Day Event Offset'
|
event_summary = 'Test All Day Event Offset'
|
||||||
@@ -369,8 +360,7 @@ class TestComponentsGoogleCalendar(unittest.TestCase):
|
|||||||
'date': tomorrow.isoformat()
|
'date': tomorrow.isoformat()
|
||||||
},
|
},
|
||||||
'end': {
|
'end': {
|
||||||
'date': (tomorrow + dt_util.dt.timedelta(days=1))
|
'date': (tomorrow + dt_util.dt.timedelta(days=1)).isoformat()
|
||||||
.isoformat()
|
|
||||||
},
|
},
|
||||||
'location': 'Test Cases',
|
'location': 'Test Cases',
|
||||||
'description': 'We\'re just testing that all day events get setup '
|
'description': 'We\'re just testing that all day events get setup '
|
||||||
@@ -421,3 +411,14 @@ class TestComponentsGoogleCalendar(unittest.TestCase):
|
|||||||
'location': event['location'],
|
'location': event['location'],
|
||||||
'description': event['description']
|
'description': event['description']
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def test_update_false(self):
|
||||||
|
"""Test that the update returns False upon Error."""
|
||||||
|
mock_service = Mock()
|
||||||
|
mock_service.get = Mock(side_effect=ServerNotFoundError("unit test"))
|
||||||
|
|
||||||
|
cal = calendar.GoogleCalendarEventDevice(self.hass, mock_service, None,
|
||||||
|
{'name': "test"})
|
||||||
|
result = cal.data.update()
|
||||||
|
|
||||||
|
self.assertFalse(result)
|
||||||
|
Reference in New Issue
Block a user