Retry keyset cloud (#12270)
* Use less threads in helpers.event tests * Add helpers.event.async_call_later * Cloud: retry fetching keyset
This commit is contained in:
parent
a9412d27aa
commit
aad26599ae
6 changed files with 66 additions and 40 deletions
|
@ -16,8 +16,7 @@ import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
EVENT_HOMEASSISTANT_START, CONF_REGION, CONF_MODE, CONF_NAME, CONF_TYPE)
|
EVENT_HOMEASSISTANT_START, CONF_REGION, CONF_MODE, CONF_NAME, CONF_TYPE)
|
||||||
from homeassistant.helpers import entityfilter
|
from homeassistant.helpers import entityfilter, config_validation as cv
|
||||||
from homeassistant.helpers import config_validation as cv
|
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
from homeassistant.components.alexa import smart_home as alexa_sh
|
from homeassistant.components.alexa import smart_home as alexa_sh
|
||||||
|
@ -105,12 +104,7 @@ def async_setup(hass, config):
|
||||||
)
|
)
|
||||||
|
|
||||||
cloud = hass.data[DOMAIN] = Cloud(hass, **kwargs)
|
cloud = hass.data[DOMAIN] = Cloud(hass, **kwargs)
|
||||||
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, cloud.async_start)
|
||||||
success = yield from cloud.initialize()
|
|
||||||
|
|
||||||
if not success:
|
|
||||||
return False
|
|
||||||
|
|
||||||
yield from http_api.async_setup(hass)
|
yield from http_api.async_setup(hass)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -192,19 +186,6 @@ class Cloud:
|
||||||
|
|
||||||
return self._gactions_config
|
return self._gactions_config
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def initialize(self):
|
|
||||||
"""Initialize and load cloud info."""
|
|
||||||
jwt_success = yield from self._fetch_jwt_keyset()
|
|
||||||
|
|
||||||
if not jwt_success:
|
|
||||||
return False
|
|
||||||
|
|
||||||
self.hass.bus.async_listen_once(
|
|
||||||
EVENT_HOMEASSISTANT_START, self._start_cloud)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def path(self, *parts):
|
def path(self, *parts):
|
||||||
"""Get config path inside cloud dir.
|
"""Get config path inside cloud dir.
|
||||||
|
|
||||||
|
@ -234,8 +215,18 @@ class Cloud:
|
||||||
'refresh_token': self.refresh_token,
|
'refresh_token': self.refresh_token,
|
||||||
}, indent=4))
|
}, indent=4))
|
||||||
|
|
||||||
def _start_cloud(self, event):
|
@asyncio.coroutine
|
||||||
|
def async_start(self, _):
|
||||||
"""Start the cloud component."""
|
"""Start the cloud component."""
|
||||||
|
success = yield from self._fetch_jwt_keyset()
|
||||||
|
|
||||||
|
# Fetching keyset can fail if internet is not up yet.
|
||||||
|
if not success:
|
||||||
|
self.hass.helpers.async_call_later(5, self.async_start)
|
||||||
|
return
|
||||||
|
|
||||||
|
def load_config():
|
||||||
|
"""Load config."""
|
||||||
# Ensure config dir exists
|
# Ensure config dir exists
|
||||||
path = self.hass.config.path(CONFIG_DIR)
|
path = self.hass.config.path(CONFIG_DIR)
|
||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
|
@ -243,10 +234,15 @@ class Cloud:
|
||||||
|
|
||||||
user_info = self.user_info_path
|
user_info = self.user_info_path
|
||||||
if not os.path.isfile(user_info):
|
if not os.path.isfile(user_info):
|
||||||
return
|
return None
|
||||||
|
|
||||||
with open(user_info, 'rt') as file:
|
with open(user_info, 'rt') as file:
|
||||||
info = json.loads(file.read())
|
return json.loads(file.read())
|
||||||
|
|
||||||
|
info = yield from self.hass.async_add_job(load_config)
|
||||||
|
|
||||||
|
if info is None:
|
||||||
|
return
|
||||||
|
|
||||||
# Validate tokens
|
# Validate tokens
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Helpers for listening to events."""
|
"""Helpers for listening to events."""
|
||||||
|
from datetime import timedelta
|
||||||
import functools as ft
|
import functools as ft
|
||||||
|
|
||||||
from homeassistant.loader import bind_hass
|
from homeassistant.loader import bind_hass
|
||||||
|
@ -219,6 +220,14 @@ track_point_in_utc_time = threaded_listener_factory(
|
||||||
async_track_point_in_utc_time)
|
async_track_point_in_utc_time)
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
@bind_hass
|
||||||
|
def async_call_later(hass, delay, action):
|
||||||
|
"""Add a listener that is called in <delay>."""
|
||||||
|
return async_track_point_in_utc_time(
|
||||||
|
hass, action, dt_util.utcnow() + timedelta(seconds=delay))
|
||||||
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
@bind_hass
|
@bind_hass
|
||||||
def async_track_time_interval(hass, action, interval):
|
def async_track_time_interval(hass, action, interval):
|
||||||
|
|
|
@ -14,8 +14,8 @@ from tests.common import mock_coro
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def cloud_client(hass, test_client):
|
def cloud_client(hass, test_client):
|
||||||
"""Fixture that can fetch from the cloud client."""
|
"""Fixture that can fetch from the cloud client."""
|
||||||
with patch('homeassistant.components.cloud.Cloud.initialize',
|
with patch('homeassistant.components.cloud.Cloud.async_start',
|
||||||
return_value=mock_coro(True)):
|
return_value=mock_coro()):
|
||||||
hass.loop.run_until_complete(async_setup_component(hass, 'cloud', {
|
hass.loop.run_until_complete(async_setup_component(hass, 'cloud', {
|
||||||
'cloud': {
|
'cloud': {
|
||||||
'mode': 'development',
|
'mode': 'development',
|
||||||
|
|
|
@ -87,7 +87,7 @@ def test_initialize_loads_info(mock_os, hass):
|
||||||
|
|
||||||
with patch('homeassistant.components.cloud.open', mopen, create=True), \
|
with patch('homeassistant.components.cloud.open', mopen, create=True), \
|
||||||
patch('homeassistant.components.cloud.Cloud._decode_claims'):
|
patch('homeassistant.components.cloud.Cloud._decode_claims'):
|
||||||
cl._start_cloud(None)
|
yield from cl.async_start(None)
|
||||||
|
|
||||||
assert cl.id_token == 'test-id-token'
|
assert cl.id_token == 'test-id-token'
|
||||||
assert cl.access_token == 'test-access-token'
|
assert cl.access_token == 'test-access-token'
|
||||||
|
|
|
@ -266,8 +266,8 @@ def test_handler_alexa(hass):
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
'switch.test2', 'on', {'friendly_name': "Test switch 2"})
|
'switch.test2', 'on', {'friendly_name': "Test switch 2"})
|
||||||
|
|
||||||
with patch('homeassistant.components.cloud.Cloud.initialize',
|
with patch('homeassistant.components.cloud.Cloud.async_start',
|
||||||
return_value=mock_coro(True)):
|
return_value=mock_coro()):
|
||||||
setup = yield from async_setup_component(hass, 'cloud', {
|
setup = yield from async_setup_component(hass, 'cloud', {
|
||||||
'cloud': {
|
'cloud': {
|
||||||
'alexa': {
|
'alexa': {
|
||||||
|
@ -309,8 +309,8 @@ def test_handler_google_actions(hass):
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
'switch.test2', 'on', {'friendly_name': "Test switch 2"})
|
'switch.test2', 'on', {'friendly_name': "Test switch 2"})
|
||||||
|
|
||||||
with patch('homeassistant.components.cloud.Cloud.initialize',
|
with patch('homeassistant.components.cloud.Cloud.async_start',
|
||||||
return_value=mock_coro(True)):
|
return_value=mock_coro()):
|
||||||
setup = yield from async_setup_component(hass, 'cloud', {
|
setup = yield from async_setup_component(hass, 'cloud', {
|
||||||
'cloud': {
|
'cloud': {
|
||||||
'google_actions': {
|
'google_actions': {
|
||||||
|
|
|
@ -7,10 +7,12 @@ from datetime import datetime, timedelta
|
||||||
from astral import Astral
|
from astral import Astral
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.core import callback
|
||||||
from homeassistant.setup import setup_component
|
from homeassistant.setup import setup_component
|
||||||
import homeassistant.core as ha
|
import homeassistant.core as ha
|
||||||
from homeassistant.const import MATCH_ALL
|
from homeassistant.const import MATCH_ALL
|
||||||
from homeassistant.helpers.event import (
|
from homeassistant.helpers.event import (
|
||||||
|
async_call_later,
|
||||||
track_point_in_utc_time,
|
track_point_in_utc_time,
|
||||||
track_point_in_time,
|
track_point_in_time,
|
||||||
track_utc_time_change,
|
track_utc_time_change,
|
||||||
|
@ -52,7 +54,7 @@ class TestEventHelpers(unittest.TestCase):
|
||||||
runs = []
|
runs = []
|
||||||
|
|
||||||
track_point_in_utc_time(
|
track_point_in_utc_time(
|
||||||
self.hass, lambda x: runs.append(1), birthday_paulus)
|
self.hass, callback(lambda x: runs.append(1)), birthday_paulus)
|
||||||
|
|
||||||
self._send_time_changed(before_birthday)
|
self._send_time_changed(before_birthday)
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
|
@ -68,14 +70,14 @@ class TestEventHelpers(unittest.TestCase):
|
||||||
self.assertEqual(1, len(runs))
|
self.assertEqual(1, len(runs))
|
||||||
|
|
||||||
track_point_in_time(
|
track_point_in_time(
|
||||||
self.hass, lambda x: runs.append(1), birthday_paulus)
|
self.hass, callback(lambda x: runs.append(1)), birthday_paulus)
|
||||||
|
|
||||||
self._send_time_changed(after_birthday)
|
self._send_time_changed(after_birthday)
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
self.assertEqual(2, len(runs))
|
self.assertEqual(2, len(runs))
|
||||||
|
|
||||||
unsub = track_point_in_time(
|
unsub = track_point_in_time(
|
||||||
self.hass, lambda x: runs.append(1), birthday_paulus)
|
self.hass, callback(lambda x: runs.append(1)), birthday_paulus)
|
||||||
unsub()
|
unsub()
|
||||||
|
|
||||||
self._send_time_changed(after_birthday)
|
self._send_time_changed(after_birthday)
|
||||||
|
@ -642,3 +644,22 @@ class TestEventHelpers(unittest.TestCase):
|
||||||
self._send_time_changed(datetime(2014, 5, 2, 0, 0, 0))
|
self._send_time_changed(datetime(2014, 5, 2, 0, 0, 0))
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
self.assertEqual(0, len(specific_runs))
|
self.assertEqual(0, len(specific_runs))
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_async_call_later(hass):
|
||||||
|
"""Test calling an action later."""
|
||||||
|
def action(): pass
|
||||||
|
now = datetime(2017, 12, 19, 15, 40, 0, tzinfo=dt_util.UTC)
|
||||||
|
|
||||||
|
with patch('homeassistant.helpers.event'
|
||||||
|
'.async_track_point_in_utc_time') as mock, \
|
||||||
|
patch('homeassistant.util.dt.utcnow', return_value=now):
|
||||||
|
remove = async_call_later(hass, 3, action)
|
||||||
|
|
||||||
|
assert len(mock.mock_calls) == 1
|
||||||
|
p_hass, p_action, p_point = mock.mock_calls[0][1]
|
||||||
|
assert hass is hass
|
||||||
|
assert p_action is action
|
||||||
|
assert p_point == now + timedelta(seconds=3)
|
||||||
|
assert remove is mock()
|
||||||
|
|
Loading…
Add table
Reference in a new issue