Add option to disable specific integrations (#16757)
* Add option to disable specific integrations * Lint
This commit is contained in:
parent
03de658d4d
commit
092c146eae
10 changed files with 222 additions and 28 deletions
|
@ -1529,3 +1529,8 @@ async def async_api_reportstate(hass, config, request, context, entity):
|
||||||
name='StateReport',
|
name='StateReport',
|
||||||
context={'properties': properties}
|
context={'properties': properties}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def turned_off_response(message):
|
||||||
|
"""Return a device turned off response."""
|
||||||
|
return api_error(message[API_DIRECTIVE], error_type='BRIDGE_UNREACHABLE')
|
||||||
|
|
|
@ -27,8 +27,13 @@ from . import http_api, iot, auth_api
|
||||||
from .const import CONFIG_DIR, DOMAIN, SERVERS
|
from .const import CONFIG_DIR, DOMAIN, SERVERS
|
||||||
|
|
||||||
REQUIREMENTS = ['warrant==0.6.1']
|
REQUIREMENTS = ['warrant==0.6.1']
|
||||||
|
STORAGE_KEY = DOMAIN
|
||||||
|
STORAGE_VERSION = 1
|
||||||
|
STORAGE_ENABLE_ALEXA = 'alexa_enabled'
|
||||||
|
STORAGE_ENABLE_GOOGLE = 'google_enabled'
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
_UNDEF = object()
|
||||||
|
|
||||||
CONF_ALEXA = 'alexa'
|
CONF_ALEXA = 'alexa'
|
||||||
CONF_ALIASES = 'aliases'
|
CONF_ALIASES = 'aliases'
|
||||||
|
@ -124,11 +129,13 @@ class Cloud:
|
||||||
self.alexa_config = alexa
|
self.alexa_config = alexa
|
||||||
self._google_actions = google_actions
|
self._google_actions = google_actions
|
||||||
self._gactions_config = None
|
self._gactions_config = None
|
||||||
|
self._prefs = None
|
||||||
self.jwt_keyset = None
|
self.jwt_keyset = None
|
||||||
self.id_token = None
|
self.id_token = None
|
||||||
self.access_token = None
|
self.access_token = None
|
||||||
self.refresh_token = None
|
self.refresh_token = None
|
||||||
self.iot = iot.CloudIoT(self)
|
self.iot = iot.CloudIoT(self)
|
||||||
|
self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
|
||||||
|
|
||||||
if mode == MODE_DEV:
|
if mode == MODE_DEV:
|
||||||
self.cognito_client_id = cognito_client_id
|
self.cognito_client_id = cognito_client_id
|
||||||
|
@ -193,6 +200,16 @@ class Cloud:
|
||||||
|
|
||||||
return self._gactions_config
|
return self._gactions_config
|
||||||
|
|
||||||
|
@property
|
||||||
|
def alexa_enabled(self):
|
||||||
|
"""Return if Alexa is enabled."""
|
||||||
|
return self._prefs[STORAGE_ENABLE_ALEXA]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def google_enabled(self):
|
||||||
|
"""Return if Google is enabled."""
|
||||||
|
return self._prefs[STORAGE_ENABLE_GOOGLE]
|
||||||
|
|
||||||
def path(self, *parts):
|
def path(self, *parts):
|
||||||
"""Get config path inside cloud dir.
|
"""Get config path inside cloud dir.
|
||||||
|
|
||||||
|
@ -231,10 +248,23 @@ class Cloud:
|
||||||
'refresh_token': self.refresh_token,
|
'refresh_token': self.refresh_token,
|
||||||
}, indent=4))
|
}, indent=4))
|
||||||
|
|
||||||
@asyncio.coroutine
|
async def async_start(self, _):
|
||||||
def async_start(self, _):
|
|
||||||
"""Start the cloud component."""
|
"""Start the cloud component."""
|
||||||
success = yield from self._fetch_jwt_keyset()
|
prefs = await self._store.async_load()
|
||||||
|
if prefs is None:
|
||||||
|
prefs = {}
|
||||||
|
if self.mode not in prefs:
|
||||||
|
# Default to True if already logged in to make this not a
|
||||||
|
# breaking change.
|
||||||
|
enabled = await self.hass.async_add_executor_job(
|
||||||
|
os.path.isfile, self.user_info_path)
|
||||||
|
prefs = {
|
||||||
|
STORAGE_ENABLE_ALEXA: enabled,
|
||||||
|
STORAGE_ENABLE_GOOGLE: enabled,
|
||||||
|
}
|
||||||
|
self._prefs = prefs
|
||||||
|
|
||||||
|
success = await self._fetch_jwt_keyset()
|
||||||
|
|
||||||
# Fetching keyset can fail if internet is not up yet.
|
# Fetching keyset can fail if internet is not up yet.
|
||||||
if not success:
|
if not success:
|
||||||
|
@ -255,7 +285,7 @@ class Cloud:
|
||||||
with open(user_info, 'rt') as file:
|
with open(user_info, 'rt') as file:
|
||||||
return json.loads(file.read())
|
return json.loads(file.read())
|
||||||
|
|
||||||
info = yield from self.hass.async_add_job(load_config)
|
info = await self.hass.async_add_job(load_config)
|
||||||
|
|
||||||
if info is None:
|
if info is None:
|
||||||
return
|
return
|
||||||
|
@ -274,6 +304,15 @@ class Cloud:
|
||||||
|
|
||||||
self.hass.add_job(self.iot.connect())
|
self.hass.add_job(self.iot.connect())
|
||||||
|
|
||||||
|
async def update_preferences(self, *, google_enabled=_UNDEF,
|
||||||
|
alexa_enabled=_UNDEF):
|
||||||
|
"""Update user preferences."""
|
||||||
|
if google_enabled is not _UNDEF:
|
||||||
|
self._prefs[STORAGE_ENABLE_GOOGLE] = google_enabled
|
||||||
|
if alexa_enabled is not _UNDEF:
|
||||||
|
self._prefs[STORAGE_ENABLE_ALEXA] = alexa_enabled
|
||||||
|
await self._store.async_save(self._prefs)
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def _fetch_jwt_keyset(self):
|
def _fetch_jwt_keyset(self):
|
||||||
"""Fetch the JWT keyset for the Cognito instance."""
|
"""Fetch the JWT keyset for the Cognito instance."""
|
||||||
|
|
|
@ -25,6 +25,14 @@ SCHEMA_WS_STATUS = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
WS_TYPE_UPDATE_PREFS = 'cloud/update_prefs'
|
||||||
|
SCHEMA_WS_UPDATE_PREFS = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
|
||||||
|
vol.Required('type'): WS_TYPE_UPDATE_PREFS,
|
||||||
|
vol.Optional('google_enabled'): bool,
|
||||||
|
vol.Optional('alexa_enabled'): bool,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
WS_TYPE_SUBSCRIPTION = 'cloud/subscription'
|
WS_TYPE_SUBSCRIPTION = 'cloud/subscription'
|
||||||
SCHEMA_WS_SUBSCRIPTION = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
|
SCHEMA_WS_SUBSCRIPTION = websocket_api.BASE_COMMAND_MESSAGE_SCHEMA.extend({
|
||||||
vol.Required('type'): WS_TYPE_SUBSCRIPTION,
|
vol.Required('type'): WS_TYPE_SUBSCRIPTION,
|
||||||
|
@ -41,6 +49,10 @@ async def async_setup(hass):
|
||||||
WS_TYPE_SUBSCRIPTION, websocket_subscription,
|
WS_TYPE_SUBSCRIPTION, websocket_subscription,
|
||||||
SCHEMA_WS_SUBSCRIPTION
|
SCHEMA_WS_SUBSCRIPTION
|
||||||
)
|
)
|
||||||
|
hass.components.websocket_api.async_register_command(
|
||||||
|
WS_TYPE_UPDATE_PREFS, websocket_update_prefs,
|
||||||
|
SCHEMA_WS_UPDATE_PREFS
|
||||||
|
)
|
||||||
hass.http.register_view(GoogleActionsSyncView)
|
hass.http.register_view(GoogleActionsSyncView)
|
||||||
hass.http.register_view(CloudLoginView)
|
hass.http.register_view(CloudLoginView)
|
||||||
hass.http.register_view(CloudLogoutView)
|
hass.http.register_view(CloudLogoutView)
|
||||||
|
@ -245,6 +257,26 @@ async def websocket_subscription(hass, connection, msg):
|
||||||
msg['id'], 'request_failed', 'Failed to request subscription'))
|
msg['id'], 'request_failed', 'Failed to request subscription'))
|
||||||
|
|
||||||
|
|
||||||
|
@websocket_api.async_response
|
||||||
|
async def websocket_update_prefs(hass, connection, msg):
|
||||||
|
"""Handle request for account info."""
|
||||||
|
cloud = hass.data[DOMAIN]
|
||||||
|
|
||||||
|
if not cloud.is_logged_in:
|
||||||
|
connection.to_write.put_nowait(websocket_api.error_message(
|
||||||
|
msg['id'], 'not_logged_in',
|
||||||
|
'You need to be logged in to the cloud.'))
|
||||||
|
return
|
||||||
|
|
||||||
|
changes = dict(msg)
|
||||||
|
changes.pop('id')
|
||||||
|
changes.pop('type')
|
||||||
|
await cloud.update_preferences(**changes)
|
||||||
|
|
||||||
|
connection.send_message_outside(websocket_api.result_message(
|
||||||
|
msg['id'], {'success': True}))
|
||||||
|
|
||||||
|
|
||||||
def _account_data(cloud):
|
def _account_data(cloud):
|
||||||
"""Generate the auth data JSON response."""
|
"""Generate the auth data JSON response."""
|
||||||
if not cloud.is_logged_in:
|
if not cloud.is_logged_in:
|
||||||
|
@ -259,4 +291,6 @@ def _account_data(cloud):
|
||||||
'logged_in': True,
|
'logged_in': True,
|
||||||
'email': claims['email'],
|
'email': claims['email'],
|
||||||
'cloud': cloud.iot.state,
|
'cloud': cloud.iot.state,
|
||||||
|
'google_enabled': cloud.google_enabled,
|
||||||
|
'alexa_enabled': cloud.alexa_enabled,
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,6 +227,9 @@ def async_handle_message(hass, cloud, handler_name, payload):
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_handle_alexa(hass, cloud, payload):
|
def async_handle_alexa(hass, cloud, payload):
|
||||||
"""Handle an incoming IoT message for Alexa."""
|
"""Handle an incoming IoT message for Alexa."""
|
||||||
|
if not cloud.alexa_enabled:
|
||||||
|
return alexa.turned_off_response(payload)
|
||||||
|
|
||||||
result = yield from alexa.async_handle_message(
|
result = yield from alexa.async_handle_message(
|
||||||
hass, cloud.alexa_config, payload)
|
hass, cloud.alexa_config, payload)
|
||||||
return result
|
return result
|
||||||
|
@ -236,6 +239,9 @@ def async_handle_alexa(hass, cloud, payload):
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def async_handle_google_actions(hass, cloud, payload):
|
def async_handle_google_actions(hass, cloud, payload):
|
||||||
"""Handle an incoming IoT message for Google Actions."""
|
"""Handle an incoming IoT message for Google Actions."""
|
||||||
|
if not cloud.google_enabled:
|
||||||
|
return ga.turned_off_response(payload)
|
||||||
|
|
||||||
result = yield from ga.async_handle_message(
|
result = yield from ga.async_handle_message(
|
||||||
hass, cloud.gactions_config, payload)
|
hass, cloud.gactions_config, payload)
|
||||||
return result
|
return result
|
||||||
|
|
|
@ -324,3 +324,11 @@ async def handle_devices_execute(hass, config, payload):
|
||||||
})
|
})
|
||||||
|
|
||||||
return {'commands': final_results}
|
return {'commands': final_results}
|
||||||
|
|
||||||
|
|
||||||
|
def turned_off_response(message):
|
||||||
|
"""Return a device turned off response."""
|
||||||
|
return {
|
||||||
|
'requestId': message.get('requestId'),
|
||||||
|
'payload': {'errorCode': 'deviceTurnedOff'}
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,32 @@
|
||||||
"""Tests for the cloud component."""
|
"""Tests for the cloud component."""
|
||||||
|
from unittest.mock import patch
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
from homeassistant.components import cloud
|
||||||
|
|
||||||
|
from jose import jwt
|
||||||
|
|
||||||
|
from tests.common import mock_coro
|
||||||
|
|
||||||
|
|
||||||
|
def mock_cloud(hass, config={}):
|
||||||
|
"""Mock cloud."""
|
||||||
|
with patch('homeassistant.components.cloud.Cloud.async_start',
|
||||||
|
return_value=mock_coro()):
|
||||||
|
assert hass.loop.run_until_complete(async_setup_component(
|
||||||
|
hass, cloud.DOMAIN, {
|
||||||
|
'cloud': config
|
||||||
|
}))
|
||||||
|
|
||||||
|
hass.data[cloud.DOMAIN]._decode_claims = \
|
||||||
|
lambda token: jwt.get_unverified_claims(token)
|
||||||
|
|
||||||
|
|
||||||
|
def mock_cloud_prefs(hass, prefs={}):
|
||||||
|
"""Fixture for cloud component."""
|
||||||
|
prefs_to_set = {
|
||||||
|
cloud.STORAGE_ENABLE_ALEXA: True,
|
||||||
|
cloud.STORAGE_ENABLE_GOOGLE: True,
|
||||||
|
}
|
||||||
|
prefs_to_set.update(prefs)
|
||||||
|
hass.data[cloud.DOMAIN]._prefs = prefs_to_set
|
||||||
|
return prefs_to_set
|
||||||
|
|
11
tests/components/cloud/conftest.py
Normal file
11
tests/components/cloud/conftest.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
"""Fixtures for cloud tests."""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from . import mock_cloud, mock_cloud_prefs
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_cloud_fixture(hass):
|
||||||
|
"""Fixture for cloud component."""
|
||||||
|
mock_cloud(hass)
|
||||||
|
return mock_cloud_prefs(hass)
|
|
@ -5,11 +5,12 @@ from unittest.mock import patch, MagicMock
|
||||||
import pytest
|
import pytest
|
||||||
from jose import jwt
|
from jose import jwt
|
||||||
|
|
||||||
from homeassistant.bootstrap import async_setup_component
|
from homeassistant.components.cloud import (
|
||||||
from homeassistant.components.cloud import DOMAIN, auth_api, iot
|
DOMAIN, auth_api, iot, STORAGE_ENABLE_GOOGLE, STORAGE_ENABLE_ALEXA)
|
||||||
|
|
||||||
from tests.common import mock_coro
|
from tests.common import mock_coro
|
||||||
|
|
||||||
|
from . import mock_cloud, mock_cloud_prefs
|
||||||
|
|
||||||
GOOGLE_ACTIONS_SYNC_URL = 'https://api-test.hass.io/google_actions_sync'
|
GOOGLE_ACTIONS_SYNC_URL = 'https://api-test.hass.io/google_actions_sync'
|
||||||
SUBSCRIPTION_INFO_URL = 'https://api-test.hass.io/subscription_info'
|
SUBSCRIPTION_INFO_URL = 'https://api-test.hass.io/subscription_info'
|
||||||
|
@ -25,22 +26,16 @@ def mock_auth():
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def setup_api(hass):
|
def setup_api(hass):
|
||||||
"""Initialize HTTP API."""
|
"""Initialize HTTP API."""
|
||||||
with patch('homeassistant.components.cloud.Cloud.async_start',
|
mock_cloud(hass, {
|
||||||
return_value=mock_coro()):
|
'mode': 'development',
|
||||||
assert hass.loop.run_until_complete(async_setup_component(
|
'cognito_client_id': 'cognito_client_id',
|
||||||
hass, 'cloud', {
|
'user_pool_id': 'user_pool_id',
|
||||||
'cloud': {
|
'region': 'region',
|
||||||
'mode': 'development',
|
'relayer': 'relayer',
|
||||||
'cognito_client_id': 'cognito_client_id',
|
'google_actions_sync_url': GOOGLE_ACTIONS_SYNC_URL,
|
||||||
'user_pool_id': 'user_pool_id',
|
'subscription_info_url': SUBSCRIPTION_INFO_URL,
|
||||||
'region': 'region',
|
})
|
||||||
'relayer': 'relayer',
|
return mock_cloud_prefs(hass)
|
||||||
'google_actions_sync_url': GOOGLE_ACTIONS_SYNC_URL,
|
|
||||||
'subscription_info_url': SUBSCRIPTION_INFO_URL,
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
hass.data['cloud']._decode_claims = \
|
|
||||||
lambda token: jwt.get_unverified_claims(token)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
@ -321,7 +316,7 @@ def test_resend_confirm_view_unknown_error(mock_cognito, cloud_client):
|
||||||
assert req.status == 502
|
assert req.status == 502
|
||||||
|
|
||||||
|
|
||||||
async def test_websocket_status(hass, hass_ws_client):
|
async def test_websocket_status(hass, hass_ws_client, mock_cloud_fixture):
|
||||||
"""Test querying the status."""
|
"""Test querying the status."""
|
||||||
hass.data[DOMAIN].id_token = jwt.encode({
|
hass.data[DOMAIN].id_token = jwt.encode({
|
||||||
'email': 'hello@home-assistant.io',
|
'email': 'hello@home-assistant.io',
|
||||||
|
@ -338,6 +333,8 @@ async def test_websocket_status(hass, hass_ws_client):
|
||||||
'logged_in': True,
|
'logged_in': True,
|
||||||
'email': 'hello@home-assistant.io',
|
'email': 'hello@home-assistant.io',
|
||||||
'cloud': 'connected',
|
'cloud': 'connected',
|
||||||
|
'alexa_enabled': True,
|
||||||
|
'google_enabled': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -407,3 +404,26 @@ async def test_websocket_subscription_not_logged_in(hass, hass_ws_client):
|
||||||
|
|
||||||
assert not response['success']
|
assert not response['success']
|
||||||
assert response['error']['code'] == 'not_logged_in'
|
assert response['error']['code'] == 'not_logged_in'
|
||||||
|
|
||||||
|
|
||||||
|
async def test_websocket_update_preferences(hass, hass_ws_client,
|
||||||
|
aioclient_mock, setup_api):
|
||||||
|
"""Test updating preference."""
|
||||||
|
assert setup_api[STORAGE_ENABLE_GOOGLE]
|
||||||
|
assert setup_api[STORAGE_ENABLE_ALEXA]
|
||||||
|
hass.data[DOMAIN].id_token = jwt.encode({
|
||||||
|
'email': 'hello@home-assistant.io',
|
||||||
|
'custom:sub-exp': '2018-01-03'
|
||||||
|
}, 'test')
|
||||||
|
client = await hass_ws_client(hass)
|
||||||
|
await client.send_json({
|
||||||
|
'id': 5,
|
||||||
|
'type': 'cloud/update_prefs',
|
||||||
|
'alexa_enabled': False,
|
||||||
|
'google_enabled': False,
|
||||||
|
})
|
||||||
|
response = await client.receive_json()
|
||||||
|
|
||||||
|
assert response['success']
|
||||||
|
assert not setup_api[STORAGE_ENABLE_GOOGLE]
|
||||||
|
assert not setup_api[STORAGE_ENABLE_ALEXA]
|
||||||
|
|
|
@ -141,9 +141,9 @@ def test_write_user_info():
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def test_subscription_expired():
|
def test_subscription_expired(hass):
|
||||||
"""Test subscription being expired."""
|
"""Test subscription being expired."""
|
||||||
cl = cloud.Cloud(None, cloud.MODE_DEV, None, None)
|
cl = cloud.Cloud(hass, cloud.MODE_DEV, None, None)
|
||||||
token_val = {
|
token_val = {
|
||||||
'custom:sub-exp': '2017-11-13'
|
'custom:sub-exp': '2017-11-13'
|
||||||
}
|
}
|
||||||
|
@ -154,9 +154,9 @@ def test_subscription_expired():
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def test_subscription_not_expired():
|
def test_subscription_not_expired(hass):
|
||||||
"""Test subscription not being expired."""
|
"""Test subscription not being expired."""
|
||||||
cl = cloud.Cloud(None, cloud.MODE_DEV, None, None)
|
cl = cloud.Cloud(hass, cloud.MODE_DEV, None, None)
|
||||||
token_val = {
|
token_val = {
|
||||||
'custom:sub-exp': '2017-11-13'
|
'custom:sub-exp': '2017-11-13'
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,14 @@ from aiohttp import WSMsgType, client_exceptions
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
from homeassistant.components.cloud import Cloud, iot, auth_api, MODE_DEV
|
from homeassistant.components.cloud import (
|
||||||
|
Cloud, iot, auth_api, MODE_DEV, STORAGE_ENABLE_ALEXA,
|
||||||
|
STORAGE_ENABLE_GOOGLE)
|
||||||
from tests.components.alexa import test_smart_home as test_alexa
|
from tests.components.alexa import test_smart_home as test_alexa
|
||||||
from tests.common import mock_coro
|
from tests.common import mock_coro
|
||||||
|
|
||||||
|
from . import mock_cloud_prefs
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_client():
|
def mock_client():
|
||||||
|
@ -284,6 +288,8 @@ def test_handler_alexa(hass):
|
||||||
})
|
})
|
||||||
assert setup
|
assert setup
|
||||||
|
|
||||||
|
mock_cloud_prefs(hass)
|
||||||
|
|
||||||
resp = yield from iot.async_handle_alexa(
|
resp = yield from iot.async_handle_alexa(
|
||||||
hass, hass.data['cloud'],
|
hass, hass.data['cloud'],
|
||||||
test_alexa.get_new_request('Alexa.Discovery', 'Discover'))
|
test_alexa.get_new_request('Alexa.Discovery', 'Discover'))
|
||||||
|
@ -299,6 +305,20 @@ def test_handler_alexa(hass):
|
||||||
assert device['manufacturerName'] == 'Home Assistant'
|
assert device['manufacturerName'] == 'Home Assistant'
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_handler_alexa_disabled(hass, mock_cloud_fixture):
|
||||||
|
"""Test handler Alexa when user has disabled it."""
|
||||||
|
mock_cloud_fixture[STORAGE_ENABLE_ALEXA] = False
|
||||||
|
|
||||||
|
resp = yield from iot.async_handle_alexa(
|
||||||
|
hass, hass.data['cloud'],
|
||||||
|
test_alexa.get_new_request('Alexa.Discovery', 'Discover'))
|
||||||
|
|
||||||
|
assert resp['event']['header']['namespace'] == 'Alexa'
|
||||||
|
assert resp['event']['header']['name'] == 'ErrorResponse'
|
||||||
|
assert resp['event']['payload']['type'] == 'BRIDGE_UNREACHABLE'
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def test_handler_google_actions(hass):
|
def test_handler_google_actions(hass):
|
||||||
"""Test handler Google Actions."""
|
"""Test handler Google Actions."""
|
||||||
|
@ -327,6 +347,8 @@ def test_handler_google_actions(hass):
|
||||||
})
|
})
|
||||||
assert setup
|
assert setup
|
||||||
|
|
||||||
|
mock_cloud_prefs(hass)
|
||||||
|
|
||||||
reqid = '5711642932632160983'
|
reqid = '5711642932632160983'
|
||||||
data = {'requestId': reqid, 'inputs': [{'intent': 'action.devices.SYNC'}]}
|
data = {'requestId': reqid, 'inputs': [{'intent': 'action.devices.SYNC'}]}
|
||||||
|
|
||||||
|
@ -351,6 +373,24 @@ def test_handler_google_actions(hass):
|
||||||
assert device['roomHint'] == 'living room'
|
assert device['roomHint'] == 'living room'
|
||||||
|
|
||||||
|
|
||||||
|
async def test_handler_google_actions_disabled(hass, mock_cloud_fixture):
|
||||||
|
"""Test handler Google Actions when user has disabled it."""
|
||||||
|
mock_cloud_fixture[STORAGE_ENABLE_GOOGLE] = False
|
||||||
|
|
||||||
|
with patch('homeassistant.components.cloud.Cloud.async_start',
|
||||||
|
return_value=mock_coro()):
|
||||||
|
assert await async_setup_component(hass, 'cloud', {})
|
||||||
|
|
||||||
|
reqid = '5711642932632160983'
|
||||||
|
data = {'requestId': reqid, 'inputs': [{'intent': 'action.devices.SYNC'}]}
|
||||||
|
|
||||||
|
resp = await iot.async_handle_google_actions(
|
||||||
|
hass, hass.data['cloud'], data)
|
||||||
|
|
||||||
|
assert resp['requestId'] == reqid
|
||||||
|
assert resp['payload']['errorCode'] == 'deviceTurnedOff'
|
||||||
|
|
||||||
|
|
||||||
async def test_refresh_token_expired(hass):
|
async def test_refresh_token_expired(hass):
|
||||||
"""Test handling Unauthenticated error raised if refresh token expired."""
|
"""Test handling Unauthenticated error raised if refresh token expired."""
|
||||||
cloud = Cloud(hass, MODE_DEV, None, None)
|
cloud = Cloud(hass, MODE_DEV, None, None)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue