parent
4e7dbf9ce5
commit
8213b1476f
|
@ -27,6 +27,8 @@ _LOGGER = logging.getLogger(__name__)
|
|||
|
||||
DOMAIN = 'hassio'
|
||||
DEPENDENCIES = ['http']
|
||||
STORAGE_KEY = DOMAIN
|
||||
STORAGE_VERSION = 1
|
||||
|
||||
CONF_FRONTEND_REPO = 'development_repo'
|
||||
|
||||
|
@ -167,6 +169,21 @@ def async_setup(hass, config):
|
|||
_LOGGER.error("Not connected with Hass.io")
|
||||
return False
|
||||
|
||||
store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
|
||||
data = yield from store.async_load()
|
||||
|
||||
if data is None:
|
||||
data = {}
|
||||
|
||||
if 'hassio_user' in data:
|
||||
user = yield from hass.auth.async_get_user(data['hassio_user'])
|
||||
refresh_token = list(user.refresh_tokens.values())[0]
|
||||
else:
|
||||
user = yield from hass.auth.async_create_system_user('Hass.io')
|
||||
refresh_token = yield from hass.auth.async_create_refresh_token(user)
|
||||
data['hassio_user'] = user.id
|
||||
yield from store.async_save(data)
|
||||
|
||||
# This overrides the normal API call that would be forwarded
|
||||
development_repo = config.get(DOMAIN, {}).get(CONF_FRONTEND_REPO)
|
||||
if development_repo is not None:
|
||||
|
@ -186,8 +203,13 @@ def async_setup(hass, config):
|
|||
embed_iframe=True,
|
||||
)
|
||||
|
||||
if 'http' in config:
|
||||
yield from hassio.update_hass_api(config['http'])
|
||||
# Temporary. No refresh token tells supervisor to use API password.
|
||||
if hass.auth.active:
|
||||
token = refresh_token.token
|
||||
else:
|
||||
token = None
|
||||
|
||||
yield from hassio.update_hass_api(config.get('http', {}), token)
|
||||
|
||||
if 'homeassistant' in config:
|
||||
yield from hassio.update_hass_timezone(config['homeassistant'])
|
||||
|
|
|
@ -23,10 +23,9 @@ X_HASSIO = 'X-HASSIO-KEY'
|
|||
|
||||
def _api_bool(funct):
|
||||
"""Return a boolean."""
|
||||
@asyncio.coroutine
|
||||
def _wrapper(*argv, **kwargs):
|
||||
async def _wrapper(*argv, **kwargs):
|
||||
"""Wrap function."""
|
||||
data = yield from funct(*argv, **kwargs)
|
||||
data = await funct(*argv, **kwargs)
|
||||
return data and data['result'] == "ok"
|
||||
|
||||
return _wrapper
|
||||
|
@ -34,10 +33,9 @@ def _api_bool(funct):
|
|||
|
||||
def _api_data(funct):
|
||||
"""Return data of an api."""
|
||||
@asyncio.coroutine
|
||||
def _wrapper(*argv, **kwargs):
|
||||
async def _wrapper(*argv, **kwargs):
|
||||
"""Wrap function."""
|
||||
data = yield from funct(*argv, **kwargs)
|
||||
data = await funct(*argv, **kwargs)
|
||||
if data and data['result'] == "ok":
|
||||
return data['data']
|
||||
return None
|
||||
|
@ -94,24 +92,23 @@ class HassIO:
|
|||
return self.send_command("/homeassistant/check", timeout=300)
|
||||
|
||||
@_api_bool
|
||||
def update_hass_api(self, http_config):
|
||||
"""Update Home Assistant API data on Hass.io.
|
||||
|
||||
This method return a coroutine.
|
||||
"""
|
||||
async def update_hass_api(self, http_config, refresh_token):
|
||||
"""Update Home Assistant API data on Hass.io."""
|
||||
port = http_config.get(CONF_SERVER_PORT) or SERVER_PORT
|
||||
options = {
|
||||
'ssl': CONF_SSL_CERTIFICATE in http_config,
|
||||
'port': port,
|
||||
'password': http_config.get(CONF_API_PASSWORD),
|
||||
'watchdog': True,
|
||||
'refresh_token': refresh_token,
|
||||
}
|
||||
|
||||
if CONF_SERVER_HOST in http_config:
|
||||
options['watchdog'] = False
|
||||
_LOGGER.warning("Don't use 'server_host' options with Hass.io")
|
||||
|
||||
return self.send_command("/homeassistant/options", payload=options)
|
||||
return await self.send_command("/homeassistant/options",
|
||||
payload=options)
|
||||
|
||||
@_api_bool
|
||||
def update_hass_timezone(self, core_config):
|
||||
|
|
|
@ -3,8 +3,11 @@ import asyncio
|
|||
import os
|
||||
from unittest.mock import patch, Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.components.hassio import async_check_config
|
||||
from homeassistant.components.hassio import (
|
||||
STORAGE_KEY, async_check_config)
|
||||
|
||||
from tests.common import mock_coro
|
||||
|
||||
|
@ -15,20 +18,28 @@ MOCK_ENVIRON = {
|
|||
}
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_setup_api_ping(hass, aioclient_mock):
|
||||
"""Test setup with API ping."""
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_all(aioclient_mock):
|
||||
"""Mock all setup requests."""
|
||||
aioclient_mock.post(
|
||||
"http://127.0.0.1/homeassistant/options", json={'result': 'ok'})
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json={'result': 'ok'})
|
||||
aioclient_mock.post(
|
||||
"http://127.0.0.1/supervisor/options", json={'result': 'ok'})
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/homeassistant/info", json={
|
||||
'result': 'ok', 'data': {'last_version': '10.0'}})
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_setup_api_ping(hass, aioclient_mock):
|
||||
"""Test setup with API ping."""
|
||||
with patch.dict(os.environ, MOCK_ENVIRON):
|
||||
result = yield from async_setup_component(hass, 'hassio', {})
|
||||
assert result
|
||||
|
||||
assert aioclient_mock.call_count == 2
|
||||
assert aioclient_mock.call_count == 3
|
||||
assert hass.components.hassio.get_homeassistant_version() == "10.0"
|
||||
assert hass.components.hassio.is_hassio()
|
||||
|
||||
|
@ -36,14 +47,6 @@ def test_setup_api_ping(hass, aioclient_mock):
|
|||
@asyncio.coroutine
|
||||
def test_setup_api_push_api_data(hass, aioclient_mock):
|
||||
"""Test setup with API push."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json={'result': 'ok'})
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/homeassistant/info", json={
|
||||
'result': 'ok', 'data': {'last_version': '10.0'}})
|
||||
aioclient_mock.post(
|
||||
"http://127.0.0.1/homeassistant/options", json={'result': 'ok'})
|
||||
|
||||
with patch.dict(os.environ, MOCK_ENVIRON):
|
||||
result = yield from async_setup_component(hass, 'hassio', {
|
||||
'http': {
|
||||
|
@ -64,14 +67,6 @@ def test_setup_api_push_api_data(hass, aioclient_mock):
|
|||
@asyncio.coroutine
|
||||
def test_setup_api_push_api_data_server_host(hass, aioclient_mock):
|
||||
"""Test setup with API push with active server host."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json={'result': 'ok'})
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/homeassistant/info", json={
|
||||
'result': 'ok', 'data': {'last_version': '10.0'}})
|
||||
aioclient_mock.post(
|
||||
"http://127.0.0.1/homeassistant/options", json={'result': 'ok'})
|
||||
|
||||
with patch.dict(os.environ, MOCK_ENVIRON):
|
||||
result = yield from async_setup_component(hass, 'hassio', {
|
||||
'http': {
|
||||
|
@ -90,19 +85,12 @@ def test_setup_api_push_api_data_server_host(hass, aioclient_mock):
|
|||
assert not aioclient_mock.mock_calls[1][2]['watchdog']
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_setup_api_push_api_data_default(hass, aioclient_mock):
|
||||
async def test_setup_api_push_api_data_default(hass, aioclient_mock,
|
||||
hass_storage):
|
||||
"""Test setup with API push default data."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json={'result': 'ok'})
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/homeassistant/info", json={
|
||||
'result': 'ok', 'data': {'last_version': '10.0'}})
|
||||
aioclient_mock.post(
|
||||
"http://127.0.0.1/homeassistant/options", json={'result': 'ok'})
|
||||
|
||||
with patch.dict(os.environ, MOCK_ENVIRON):
|
||||
result = yield from async_setup_component(hass, 'hassio', {
|
||||
with patch.dict(os.environ, MOCK_ENVIRON), \
|
||||
patch('homeassistant.auth.AuthManager.active', return_value=True):
|
||||
result = await async_setup_component(hass, 'hassio', {
|
||||
'http': {},
|
||||
'hassio': {}
|
||||
})
|
||||
|
@ -112,19 +100,61 @@ def test_setup_api_push_api_data_default(hass, aioclient_mock):
|
|||
assert not aioclient_mock.mock_calls[1][2]['ssl']
|
||||
assert aioclient_mock.mock_calls[1][2]['password'] is None
|
||||
assert aioclient_mock.mock_calls[1][2]['port'] == 8123
|
||||
refresh_token = aioclient_mock.mock_calls[1][2]['refresh_token']
|
||||
hassio_user = await hass.auth.async_get_user(
|
||||
hass_storage[STORAGE_KEY]['data']['hassio_user']
|
||||
)
|
||||
assert hassio_user is not None
|
||||
assert hassio_user.system_generated
|
||||
assert refresh_token in hassio_user.refresh_tokens
|
||||
|
||||
|
||||
async def test_setup_api_push_api_data_no_auth(hass, aioclient_mock,
|
||||
hass_storage):
|
||||
"""Test setup with API push default data."""
|
||||
with patch.dict(os.environ, MOCK_ENVIRON):
|
||||
result = await async_setup_component(hass, 'hassio', {
|
||||
'http': {},
|
||||
'hassio': {}
|
||||
})
|
||||
assert result
|
||||
|
||||
assert aioclient_mock.call_count == 3
|
||||
assert not aioclient_mock.mock_calls[1][2]['ssl']
|
||||
assert aioclient_mock.mock_calls[1][2]['password'] is None
|
||||
assert aioclient_mock.mock_calls[1][2]['port'] == 8123
|
||||
assert aioclient_mock.mock_calls[1][2]['refresh_token'] is None
|
||||
|
||||
|
||||
async def test_setup_api_existing_hassio_user(hass, aioclient_mock,
|
||||
hass_storage):
|
||||
"""Test setup with API push default data."""
|
||||
user = await hass.auth.async_create_system_user('Hass.io test')
|
||||
token = await hass.auth.async_create_refresh_token(user)
|
||||
hass_storage[STORAGE_KEY] = {
|
||||
'version': 1,
|
||||
'data': {
|
||||
'hassio_user': user.id
|
||||
}
|
||||
}
|
||||
with patch.dict(os.environ, MOCK_ENVIRON), \
|
||||
patch('homeassistant.auth.AuthManager.active', return_value=True):
|
||||
result = await async_setup_component(hass, 'hassio', {
|
||||
'http': {},
|
||||
'hassio': {}
|
||||
})
|
||||
assert result
|
||||
|
||||
assert aioclient_mock.call_count == 3
|
||||
assert not aioclient_mock.mock_calls[1][2]['ssl']
|
||||
assert aioclient_mock.mock_calls[1][2]['password'] is None
|
||||
assert aioclient_mock.mock_calls[1][2]['port'] == 8123
|
||||
assert aioclient_mock.mock_calls[1][2]['refresh_token'] == token.token
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_setup_core_push_timezone(hass, aioclient_mock):
|
||||
"""Test setup with API push default data."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json={'result': 'ok'})
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/homeassistant/info", json={
|
||||
'result': 'ok', 'data': {'last_version': '10.0'}})
|
||||
aioclient_mock.post(
|
||||
"http://127.0.0.1/supervisor/options", json={'result': 'ok'})
|
||||
|
||||
with patch.dict(os.environ, MOCK_ENVIRON):
|
||||
result = yield from async_setup_component(hass, 'hassio', {
|
||||
'hassio': {},
|
||||
|
@ -134,21 +164,13 @@ def test_setup_core_push_timezone(hass, aioclient_mock):
|
|||
})
|
||||
assert result
|
||||
|
||||
assert aioclient_mock.call_count == 3
|
||||
assert aioclient_mock.mock_calls[1][2]['timezone'] == "testzone"
|
||||
assert aioclient_mock.call_count == 4
|
||||
assert aioclient_mock.mock_calls[2][2]['timezone'] == "testzone"
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_setup_hassio_no_additional_data(hass, aioclient_mock):
|
||||
"""Test setup with API push default data."""
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/supervisor/ping", json={'result': 'ok'})
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/homeassistant/info", json={
|
||||
'result': 'ok', 'data': {'last_version': '10.0'}})
|
||||
aioclient_mock.get(
|
||||
"http://127.0.0.1/homeassistant/info", json={'result': 'ok'})
|
||||
|
||||
with patch.dict(os.environ, MOCK_ENVIRON), \
|
||||
patch.dict(os.environ, {'HASSIO_TOKEN': "123456"}):
|
||||
result = yield from async_setup_component(hass, 'hassio', {
|
||||
|
@ -156,7 +178,7 @@ def test_setup_hassio_no_additional_data(hass, aioclient_mock):
|
|||
})
|
||||
assert result
|
||||
|
||||
assert aioclient_mock.call_count == 2
|
||||
assert aioclient_mock.call_count == 3
|
||||
assert aioclient_mock.mock_calls[-1][3]['X-HASSIO-KEY'] == "123456"
|
||||
|
||||
|
||||
|
@ -234,14 +256,14 @@ def test_service_calls(hassio_env, hass, aioclient_mock):
|
|||
'hassio', 'addon_stdin', {'addon': 'test', 'input': 'test'})
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert aioclient_mock.call_count == 4
|
||||
assert aioclient_mock.call_count == 5
|
||||
assert aioclient_mock.mock_calls[-1][2] == 'test'
|
||||
|
||||
yield from hass.services.async_call('hassio', 'host_shutdown', {})
|
||||
yield from hass.services.async_call('hassio', 'host_reboot', {})
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert aioclient_mock.call_count == 6
|
||||
assert aioclient_mock.call_count == 7
|
||||
|
||||
yield from hass.services.async_call('hassio', 'snapshot_full', {})
|
||||
yield from hass.services.async_call('hassio', 'snapshot_partial', {
|
||||
|
@ -251,7 +273,7 @@ def test_service_calls(hassio_env, hass, aioclient_mock):
|
|||
})
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert aioclient_mock.call_count == 8
|
||||
assert aioclient_mock.call_count == 9
|
||||
assert aioclient_mock.mock_calls[-1][2] == {
|
||||
'addons': ['test'], 'folders': ['ssl'], 'password': "123456"}
|
||||
|
||||
|
@ -267,7 +289,7 @@ def test_service_calls(hassio_env, hass, aioclient_mock):
|
|||
})
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert aioclient_mock.call_count == 10
|
||||
assert aioclient_mock.call_count == 11
|
||||
assert aioclient_mock.mock_calls[-1][2] == {
|
||||
'addons': ['test'], 'folders': ['ssl'], 'homeassistant': False,
|
||||
'password': "123456"
|
||||
|
@ -289,17 +311,17 @@ def test_service_calls_core(hassio_env, hass, aioclient_mock):
|
|||
yield from hass.services.async_call('homeassistant', 'stop')
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert aioclient_mock.call_count == 1
|
||||
assert aioclient_mock.call_count == 2
|
||||
|
||||
yield from hass.services.async_call('homeassistant', 'check_config')
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert aioclient_mock.call_count == 2
|
||||
assert aioclient_mock.call_count == 3
|
||||
|
||||
yield from hass.services.async_call('homeassistant', 'restart')
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert aioclient_mock.call_count == 4
|
||||
assert aioclient_mock.call_count == 5
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
|
|
Loading…
Reference in New Issue