mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 06:07:17 +00:00
Cleanup hass.io component (#12556)
* Cleanup hass.io component * fix lint * Fix all tests * Fix lint * fix lint * fix doc lint
This commit is contained in:
parent
316eb59de2
commit
4f96eeb06e
@ -8,35 +8,25 @@ import asyncio
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
from aiohttp import web
|
|
||||||
from aiohttp.hdrs import CONTENT_TYPE
|
|
||||||
from aiohttp.web_exceptions import HTTPBadGateway
|
|
||||||
import async_timeout
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components import SERVICE_CHECK_CONFIG
|
from homeassistant.components import SERVICE_CHECK_CONFIG
|
||||||
from homeassistant.components.http import (
|
|
||||||
CONF_API_PASSWORD, CONF_SERVER_HOST, CONF_SERVER_PORT,
|
|
||||||
CONF_SSL_CERTIFICATE, KEY_AUTHENTICATED, HomeAssistantView)
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_TIME_ZONE, CONTENT_TYPE_TEXT_PLAIN, SERVER_PORT,
|
|
||||||
SERVICE_HOMEASSISTANT_RESTART, SERVICE_HOMEASSISTANT_STOP)
|
SERVICE_HOMEASSISTANT_RESTART, SERVICE_HOMEASSISTANT_STOP)
|
||||||
from homeassistant.core import DOMAIN as HASS_DOMAIN
|
from homeassistant.core import DOMAIN as HASS_DOMAIN
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.loader import bind_hass
|
from homeassistant.loader import bind_hass
|
||||||
from homeassistant.util.dt import utcnow
|
from homeassistant.util.dt import utcnow
|
||||||
|
from .handler import HassIO
|
||||||
|
from .http import HassIOView
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DOMAIN = 'hassio'
|
DOMAIN = 'hassio'
|
||||||
DEPENDENCIES = ['http']
|
DEPENDENCIES = ['http']
|
||||||
|
|
||||||
X_HASSIO = 'X-HASSIO-KEY'
|
|
||||||
|
|
||||||
DATA_HOMEASSISTANT_VERSION = 'hassio_hass_version'
|
DATA_HOMEASSISTANT_VERSION = 'hassio_hass_version'
|
||||||
HASSIO_UPDATE_INTERVAL = timedelta(minutes=55)
|
HASSIO_UPDATE_INTERVAL = timedelta(minutes=55)
|
||||||
|
|
||||||
@ -60,22 +50,6 @@ ATTR_HOMEASSISTANT = 'homeassistant'
|
|||||||
ATTR_NAME = 'name'
|
ATTR_NAME = 'name'
|
||||||
ATTR_PASSWORD = 'password'
|
ATTR_PASSWORD = 'password'
|
||||||
|
|
||||||
NO_TIMEOUT = {
|
|
||||||
re.compile(r'^homeassistant/update$'),
|
|
||||||
re.compile(r'^host/update$'),
|
|
||||||
re.compile(r'^supervisor/update$'),
|
|
||||||
re.compile(r'^addons/[^/]*/update$'),
|
|
||||||
re.compile(r'^addons/[^/]*/install$'),
|
|
||||||
re.compile(r'^addons/[^/]*/rebuild$'),
|
|
||||||
re.compile(r'^snapshots/.*/full$'),
|
|
||||||
re.compile(r'^snapshots/.*/partial$'),
|
|
||||||
}
|
|
||||||
|
|
||||||
NO_AUTH = {
|
|
||||||
re.compile(r'^app-(es5|latest)/(index|hassio-app).html$'),
|
|
||||||
re.compile(r'^addons/[^/]*/logo$')
|
|
||||||
}
|
|
||||||
|
|
||||||
SCHEMA_NO_DATA = vol.Schema({})
|
SCHEMA_NO_DATA = vol.Schema({})
|
||||||
|
|
||||||
SCHEMA_ADDON = vol.Schema({
|
SCHEMA_ADDON = vol.Schema({
|
||||||
@ -178,7 +152,7 @@ def async_setup(hass, config):
|
|||||||
_LOGGER.error("Not connected with Hass.io")
|
_LOGGER.error("Not connected with Hass.io")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
hass.http.register_view(HassIOView(hassio))
|
hass.http.register_view(HassIOView(host, websession))
|
||||||
|
|
||||||
if 'frontend' in hass.config.components:
|
if 'frontend' in hass.config.components:
|
||||||
yield from hass.components.frontend.async_register_built_in_panel(
|
yield from hass.components.frontend.async_register_built_in_panel(
|
||||||
@ -257,198 +231,3 @@ def async_setup(hass, config):
|
|||||||
HASS_DOMAIN, service, async_handle_core_service)
|
HASS_DOMAIN, service, async_handle_core_service)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _api_bool(funct):
|
|
||||||
"""Return a boolean."""
|
|
||||||
@asyncio.coroutine
|
|
||||||
def _wrapper(*argv, **kwargs):
|
|
||||||
"""Wrap function."""
|
|
||||||
data = yield from funct(*argv, **kwargs)
|
|
||||||
return data and data['result'] == "ok"
|
|
||||||
|
|
||||||
return _wrapper
|
|
||||||
|
|
||||||
|
|
||||||
class HassIO(object):
|
|
||||||
"""Small API wrapper for Hass.io."""
|
|
||||||
|
|
||||||
def __init__(self, loop, websession, ip):
|
|
||||||
"""Initialize Hass.io API."""
|
|
||||||
self.loop = loop
|
|
||||||
self.websession = websession
|
|
||||||
self._ip = ip
|
|
||||||
|
|
||||||
@_api_bool
|
|
||||||
def is_connected(self):
|
|
||||||
"""Return true if it connected to Hass.io supervisor.
|
|
||||||
|
|
||||||
This method return a coroutine.
|
|
||||||
"""
|
|
||||||
return self.send_command("/supervisor/ping", method="get")
|
|
||||||
|
|
||||||
def get_homeassistant_info(self):
|
|
||||||
"""Return data for Home Assistant.
|
|
||||||
|
|
||||||
This method return a coroutine.
|
|
||||||
"""
|
|
||||||
return self.send_command("/homeassistant/info", method="get")
|
|
||||||
|
|
||||||
@_api_bool
|
|
||||||
def update_hass_api(self, http_config):
|
|
||||||
"""Update Home Assistant API data on Hass.io.
|
|
||||||
|
|
||||||
This method return a coroutine.
|
|
||||||
"""
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
@_api_bool
|
|
||||||
def update_hass_timezone(self, core_config):
|
|
||||||
"""Update Home-Assistant timezone data on Hass.io.
|
|
||||||
|
|
||||||
This method return a coroutine.
|
|
||||||
"""
|
|
||||||
return self.send_command("/supervisor/options", payload={
|
|
||||||
'timezone': core_config.get(CONF_TIME_ZONE)
|
|
||||||
})
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def send_command(self, command, method="post", payload=None, timeout=10):
|
|
||||||
"""Send API command to Hass.io.
|
|
||||||
|
|
||||||
This method is a coroutine.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
with async_timeout.timeout(timeout, loop=self.loop):
|
|
||||||
request = yield from self.websession.request(
|
|
||||||
method, "http://{}{}".format(self._ip, command),
|
|
||||||
json=payload, headers={
|
|
||||||
X_HASSIO: os.environ.get('HASSIO_TOKEN', "")
|
|
||||||
})
|
|
||||||
|
|
||||||
if request.status not in (200, 400):
|
|
||||||
_LOGGER.error(
|
|
||||||
"%s return code %d.", command, request.status)
|
|
||||||
return None
|
|
||||||
|
|
||||||
answer = yield from request.json()
|
|
||||||
return answer
|
|
||||||
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
_LOGGER.error("Timeout on %s request", command)
|
|
||||||
|
|
||||||
except aiohttp.ClientError as err:
|
|
||||||
_LOGGER.error("Client error on %s request %s", command, err)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def command_proxy(self, path, request):
|
|
||||||
"""Return a client request with proxy origin for Hass.io supervisor.
|
|
||||||
|
|
||||||
This method is a coroutine.
|
|
||||||
"""
|
|
||||||
read_timeout = _get_timeout(path)
|
|
||||||
|
|
||||||
try:
|
|
||||||
data = None
|
|
||||||
headers = {X_HASSIO: os.environ.get('HASSIO_TOKEN', "")}
|
|
||||||
with async_timeout.timeout(10, loop=self.loop):
|
|
||||||
data = yield from request.read()
|
|
||||||
if data:
|
|
||||||
headers[CONTENT_TYPE] = request.content_type
|
|
||||||
else:
|
|
||||||
data = None
|
|
||||||
|
|
||||||
method = getattr(self.websession, request.method.lower())
|
|
||||||
client = yield from method(
|
|
||||||
"http://{}/{}".format(self._ip, path), data=data,
|
|
||||||
headers=headers, timeout=read_timeout
|
|
||||||
)
|
|
||||||
|
|
||||||
return client
|
|
||||||
|
|
||||||
except aiohttp.ClientError as err:
|
|
||||||
_LOGGER.error("Client error on api %s request %s", path, err)
|
|
||||||
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
_LOGGER.error("Client timeout error on API request %s", path)
|
|
||||||
|
|
||||||
raise HTTPBadGateway()
|
|
||||||
|
|
||||||
|
|
||||||
class HassIOView(HomeAssistantView):
|
|
||||||
"""Hass.io view to handle base part."""
|
|
||||||
|
|
||||||
name = "api:hassio"
|
|
||||||
url = "/api/hassio/{path:.+}"
|
|
||||||
requires_auth = False
|
|
||||||
|
|
||||||
def __init__(self, hassio):
|
|
||||||
"""Initialize a Hass.io base view."""
|
|
||||||
self.hassio = hassio
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def _handle(self, request, path):
|
|
||||||
"""Route data to Hass.io."""
|
|
||||||
if _need_auth(path) and not request[KEY_AUTHENTICATED]:
|
|
||||||
return web.Response(status=401)
|
|
||||||
|
|
||||||
client = yield from self.hassio.command_proxy(path, request)
|
|
||||||
|
|
||||||
data = yield from client.read()
|
|
||||||
if path.endswith('/logs'):
|
|
||||||
return _create_response_log(client, data)
|
|
||||||
return _create_response(client, data)
|
|
||||||
|
|
||||||
get = _handle
|
|
||||||
post = _handle
|
|
||||||
|
|
||||||
|
|
||||||
def _create_response(client, data):
|
|
||||||
"""Convert a response from client request."""
|
|
||||||
return web.Response(
|
|
||||||
body=data,
|
|
||||||
status=client.status,
|
|
||||||
content_type=client.content_type,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _create_response_log(client, data):
|
|
||||||
"""Convert a response from client request."""
|
|
||||||
# Remove color codes
|
|
||||||
log = re.sub(r"\x1b(\[.*?[@-~]|\].*?(\x07|\x1b\\))", "", data.decode())
|
|
||||||
|
|
||||||
return web.Response(
|
|
||||||
text=log,
|
|
||||||
status=client.status,
|
|
||||||
content_type=CONTENT_TYPE_TEXT_PLAIN,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _get_timeout(path):
|
|
||||||
"""Return timeout for a URL path."""
|
|
||||||
for re_path in NO_TIMEOUT:
|
|
||||||
if re_path.match(path):
|
|
||||||
return 0
|
|
||||||
return 300
|
|
||||||
|
|
||||||
|
|
||||||
def _need_auth(path):
|
|
||||||
"""Return if a path need authentication."""
|
|
||||||
for re_path in NO_AUTH:
|
|
||||||
if re_path.match(path):
|
|
||||||
return False
|
|
||||||
return True
|
|
117
homeassistant/components/hassio/handler.py
Normal file
117
homeassistant/components/hassio/handler.py
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
"""
|
||||||
|
Exposes regular REST commands as services.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/hassio/
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
import async_timeout
|
||||||
|
|
||||||
|
from homeassistant.components.http import (
|
||||||
|
CONF_API_PASSWORD, CONF_SERVER_HOST, CONF_SERVER_PORT,
|
||||||
|
CONF_SSL_CERTIFICATE)
|
||||||
|
from homeassistant.const import CONF_TIME_ZONE, SERVER_PORT
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
X_HASSIO = 'X-HASSIO-KEY'
|
||||||
|
|
||||||
|
|
||||||
|
def _api_bool(funct):
|
||||||
|
"""Return a boolean."""
|
||||||
|
@asyncio.coroutine
|
||||||
|
def _wrapper(*argv, **kwargs):
|
||||||
|
"""Wrap function."""
|
||||||
|
data = yield from funct(*argv, **kwargs)
|
||||||
|
return data and data['result'] == "ok"
|
||||||
|
|
||||||
|
return _wrapper
|
||||||
|
|
||||||
|
|
||||||
|
class HassIO(object):
|
||||||
|
"""Small API wrapper for Hass.io."""
|
||||||
|
|
||||||
|
def __init__(self, loop, websession, ip):
|
||||||
|
"""Initialize Hass.io API."""
|
||||||
|
self.loop = loop
|
||||||
|
self.websession = websession
|
||||||
|
self._ip = ip
|
||||||
|
|
||||||
|
@_api_bool
|
||||||
|
def is_connected(self):
|
||||||
|
"""Return true if it connected to Hass.io supervisor.
|
||||||
|
|
||||||
|
This method return a coroutine.
|
||||||
|
"""
|
||||||
|
return self.send_command("/supervisor/ping", method="get")
|
||||||
|
|
||||||
|
def get_homeassistant_info(self):
|
||||||
|
"""Return data for Home Assistant.
|
||||||
|
|
||||||
|
This method return a coroutine.
|
||||||
|
"""
|
||||||
|
return self.send_command("/homeassistant/info", method="get")
|
||||||
|
|
||||||
|
@_api_bool
|
||||||
|
def update_hass_api(self, http_config):
|
||||||
|
"""Update Home Assistant API data on Hass.io.
|
||||||
|
|
||||||
|
This method return a coroutine.
|
||||||
|
"""
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
@_api_bool
|
||||||
|
def update_hass_timezone(self, core_config):
|
||||||
|
"""Update Home-Assistant timezone data on Hass.io.
|
||||||
|
|
||||||
|
This method return a coroutine.
|
||||||
|
"""
|
||||||
|
return self.send_command("/supervisor/options", payload={
|
||||||
|
'timezone': core_config.get(CONF_TIME_ZONE)
|
||||||
|
})
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def send_command(self, command, method="post", payload=None, timeout=10):
|
||||||
|
"""Send API command to Hass.io.
|
||||||
|
|
||||||
|
This method is a coroutine.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with async_timeout.timeout(timeout, loop=self.loop):
|
||||||
|
request = yield from self.websession.request(
|
||||||
|
method, "http://{}{}".format(self._ip, command),
|
||||||
|
json=payload, headers={
|
||||||
|
X_HASSIO: os.environ.get('HASSIO_TOKEN', "")
|
||||||
|
})
|
||||||
|
|
||||||
|
if request.status not in (200, 400):
|
||||||
|
_LOGGER.error(
|
||||||
|
"%s return code %d.", command, request.status)
|
||||||
|
return None
|
||||||
|
|
||||||
|
answer = yield from request.json()
|
||||||
|
return answer
|
||||||
|
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
_LOGGER.error("Timeout on %s request", command)
|
||||||
|
|
||||||
|
except aiohttp.ClientError as err:
|
||||||
|
_LOGGER.error("Client error on %s request %s", command, err)
|
||||||
|
|
||||||
|
return None
|
140
homeassistant/components/hassio/http.py
Normal file
140
homeassistant/components/hassio/http.py
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
"""
|
||||||
|
Exposes regular REST commands as services.
|
||||||
|
|
||||||
|
For more details about this platform, please refer to the documentation at
|
||||||
|
https://home-assistant.io/components/hassio/
|
||||||
|
"""
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
import async_timeout
|
||||||
|
import aiohttp
|
||||||
|
from aiohttp import web
|
||||||
|
from aiohttp.hdrs import CONTENT_TYPE
|
||||||
|
from aiohttp.web_exceptions import HTTPBadGateway
|
||||||
|
|
||||||
|
from homeassistant.const import CONTENT_TYPE_TEXT_PLAIN
|
||||||
|
from homeassistant.components.http import KEY_AUTHENTICATED, HomeAssistantView
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
X_HASSIO = 'X-HASSIO-KEY'
|
||||||
|
|
||||||
|
NO_TIMEOUT = {
|
||||||
|
re.compile(r'^homeassistant/update$'),
|
||||||
|
re.compile(r'^host/update$'),
|
||||||
|
re.compile(r'^supervisor/update$'),
|
||||||
|
re.compile(r'^addons/[^/]*/update$'),
|
||||||
|
re.compile(r'^addons/[^/]*/install$'),
|
||||||
|
re.compile(r'^addons/[^/]*/rebuild$'),
|
||||||
|
re.compile(r'^snapshots/.*/full$'),
|
||||||
|
re.compile(r'^snapshots/.*/partial$'),
|
||||||
|
}
|
||||||
|
|
||||||
|
NO_AUTH = {
|
||||||
|
re.compile(r'^app-(es5|latest)/(index|hassio-app).html$'),
|
||||||
|
re.compile(r'^addons/[^/]*/logo$')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class HassIOView(HomeAssistantView):
|
||||||
|
"""Hass.io view to handle base part."""
|
||||||
|
|
||||||
|
name = "api:hassio"
|
||||||
|
url = "/api/hassio/{path:.+}"
|
||||||
|
requires_auth = False
|
||||||
|
|
||||||
|
def __init__(self, host, websession):
|
||||||
|
"""Initialize a Hass.io base view."""
|
||||||
|
self._host = host
|
||||||
|
self._websession = websession
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def _handle(self, request, path):
|
||||||
|
"""Route data to Hass.io."""
|
||||||
|
if _need_auth(path) and not request[KEY_AUTHENTICATED]:
|
||||||
|
return web.Response(status=401)
|
||||||
|
|
||||||
|
client = yield from self._command_proxy(path, request)
|
||||||
|
|
||||||
|
data = yield from client.read()
|
||||||
|
if path.endswith('/logs'):
|
||||||
|
return _create_response_log(client, data)
|
||||||
|
return _create_response(client, data)
|
||||||
|
|
||||||
|
get = _handle
|
||||||
|
post = _handle
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def _command_proxy(self, path, request):
|
||||||
|
"""Return a client request with proxy origin for Hass.io supervisor.
|
||||||
|
|
||||||
|
This method is a coroutine.
|
||||||
|
"""
|
||||||
|
read_timeout = _get_timeout(path)
|
||||||
|
hass = request.app['hass']
|
||||||
|
|
||||||
|
try:
|
||||||
|
data = None
|
||||||
|
headers = {X_HASSIO: os.environ.get('HASSIO_TOKEN', "")}
|
||||||
|
with async_timeout.timeout(10, loop=hass.loop):
|
||||||
|
data = yield from request.read()
|
||||||
|
if data:
|
||||||
|
headers[CONTENT_TYPE] = request.content_type
|
||||||
|
else:
|
||||||
|
data = None
|
||||||
|
|
||||||
|
method = getattr(self._websession, request.method.lower())
|
||||||
|
client = yield from method(
|
||||||
|
"http://{}/{}".format(self._host, path), data=data,
|
||||||
|
headers=headers, timeout=read_timeout
|
||||||
|
)
|
||||||
|
|
||||||
|
return client
|
||||||
|
|
||||||
|
except aiohttp.ClientError as err:
|
||||||
|
_LOGGER.error("Client error on api %s request %s", path, err)
|
||||||
|
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
_LOGGER.error("Client timeout error on API request %s", path)
|
||||||
|
|
||||||
|
raise HTTPBadGateway()
|
||||||
|
|
||||||
|
|
||||||
|
def _create_response(client, data):
|
||||||
|
"""Convert a response from client request."""
|
||||||
|
return web.Response(
|
||||||
|
body=data,
|
||||||
|
status=client.status,
|
||||||
|
content_type=client.content_type,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _create_response_log(client, data):
|
||||||
|
"""Convert a response from client request."""
|
||||||
|
# Remove color codes
|
||||||
|
log = re.sub(r"\x1b(\[.*?[@-~]|\].*?(\x07|\x1b\\))", "", data.decode())
|
||||||
|
|
||||||
|
return web.Response(
|
||||||
|
text=log,
|
||||||
|
status=client.status,
|
||||||
|
content_type=CONTENT_TYPE_TEXT_PLAIN,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_timeout(path):
|
||||||
|
"""Return timeout for a URL path."""
|
||||||
|
for re_path in NO_TIMEOUT:
|
||||||
|
if re_path.match(path):
|
||||||
|
return 0
|
||||||
|
return 300
|
||||||
|
|
||||||
|
|
||||||
|
def _need_auth(path):
|
||||||
|
"""Return if a path need authentication."""
|
||||||
|
for re_path in NO_AUTH:
|
||||||
|
if re_path.match(path):
|
||||||
|
return False
|
||||||
|
return True
|
3
tests/components/hassio/__init__.py
Normal file
3
tests/components/hassio/__init__.py
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
"""Tests for Hassio component."""
|
||||||
|
|
||||||
|
API_PASSWORD = 'pass1234'
|
40
tests/components/hassio/conftest.py
Normal file
40
tests/components/hassio/conftest.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
"""Fixtures for Hass.io."""
|
||||||
|
import os
|
||||||
|
from unittest.mock import patch, Mock
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
from tests.common import mock_coro
|
||||||
|
from . import API_PASSWORD
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def hassio_env():
|
||||||
|
"""Fixture to inject hassio env."""
|
||||||
|
with patch.dict(os.environ, {'HASSIO': "127.0.0.1"}), \
|
||||||
|
patch('homeassistant.components.hassio.HassIO.is_connected',
|
||||||
|
Mock(return_value=mock_coro(
|
||||||
|
{"result": "ok", "data": {}}))), \
|
||||||
|
patch.dict(os.environ, {'HASSIO_TOKEN': "123456"}), \
|
||||||
|
patch('homeassistant.components.hassio.HassIO.'
|
||||||
|
'get_homeassistant_info',
|
||||||
|
Mock(return_value=mock_coro(None))):
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def hassio_client(hassio_env, hass, test_client):
|
||||||
|
"""Create mock hassio http client."""
|
||||||
|
with patch('homeassistant.components.hassio.HassIO.update_hass_api',
|
||||||
|
Mock(return_value=mock_coro({"result": "ok"}))), \
|
||||||
|
patch('homeassistant.components.hassio.HassIO.'
|
||||||
|
'get_homeassistant_info',
|
||||||
|
Mock(return_value=mock_coro(None))):
|
||||||
|
hass.loop.run_until_complete(async_setup_component(hass, 'hassio', {
|
||||||
|
'http': {
|
||||||
|
'api_password': API_PASSWORD
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
yield hass.loop.run_until_complete(test_client(hass.http.app))
|
151
tests/components/hassio/test_handler.py
Normal file
151
tests/components/hassio/test_handler.py
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
"""The tests for the hassio component."""
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_setup_api_ping(hass, aioclient_mock):
|
||||||
|
"""Test setup with API ping."""
|
||||||
|
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'}})
|
||||||
|
|
||||||
|
with patch.dict(os.environ, {'HASSIO': "127.0.0.1"}):
|
||||||
|
result = yield from async_setup_component(hass, 'hassio', {})
|
||||||
|
assert result
|
||||||
|
|
||||||
|
assert aioclient_mock.call_count == 2
|
||||||
|
assert hass.components.hassio.get_homeassistant_version() == "10.0"
|
||||||
|
assert hass.components.hassio.is_hassio()
|
||||||
|
|
||||||
|
|
||||||
|
@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, {'HASSIO': "127.0.0.1"}):
|
||||||
|
result = yield from async_setup_component(hass, 'hassio', {
|
||||||
|
'http': {
|
||||||
|
'api_password': "123456",
|
||||||
|
'server_port': 9999
|
||||||
|
},
|
||||||
|
'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'] == "123456"
|
||||||
|
assert aioclient_mock.mock_calls[1][2]['port'] == 9999
|
||||||
|
assert aioclient_mock.mock_calls[1][2]['watchdog']
|
||||||
|
|
||||||
|
|
||||||
|
@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, {'HASSIO': "127.0.0.1"}):
|
||||||
|
result = yield from async_setup_component(hass, 'hassio', {
|
||||||
|
'http': {
|
||||||
|
'api_password': "123456",
|
||||||
|
'server_port': 9999,
|
||||||
|
'server_host': "127.0.0.1"
|
||||||
|
},
|
||||||
|
'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'] == "123456"
|
||||||
|
assert aioclient_mock.mock_calls[1][2]['port'] == 9999
|
||||||
|
assert not aioclient_mock.mock_calls[1][2]['watchdog']
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_setup_api_push_api_data_default(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/homeassistant/options", json={'result': 'ok'})
|
||||||
|
|
||||||
|
with patch.dict(os.environ, {'HASSIO': "127.0.0.1"}):
|
||||||
|
result = yield from 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
|
||||||
|
|
||||||
|
|
||||||
|
@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, {'HASSIO': "127.0.0.1"}):
|
||||||
|
result = yield from async_setup_component(hass, 'hassio', {
|
||||||
|
'hassio': {},
|
||||||
|
'homeassistant': {
|
||||||
|
'time_zone': 'testzone',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
assert result
|
||||||
|
|
||||||
|
assert aioclient_mock.call_count == 3
|
||||||
|
assert aioclient_mock.mock_calls[1][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, {'HASSIO': "127.0.0.1"}), \
|
||||||
|
patch.dict(os.environ, {'HASSIO_TOKEN': "123456"}):
|
||||||
|
result = yield from async_setup_component(hass, 'hassio', {
|
||||||
|
'hassio': {},
|
||||||
|
})
|
||||||
|
assert result
|
||||||
|
|
||||||
|
assert aioclient_mock.call_count == 2
|
||||||
|
assert aioclient_mock.mock_calls[-1][3]['X-HASSIO-KEY'] == "123456"
|
133
tests/components/hassio/test_http.py
Normal file
133
tests/components/hassio/test_http.py
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
"""The tests for the hassio component."""
|
||||||
|
import asyncio
|
||||||
|
from unittest.mock import patch, Mock, MagicMock
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.const import HTTP_HEADER_HA_AUTH
|
||||||
|
|
||||||
|
from tests.common import mock_coro
|
||||||
|
from . import API_PASSWORD
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_forward_request(hassio_client):
|
||||||
|
"""Test fetching normal path."""
|
||||||
|
response = MagicMock()
|
||||||
|
response.read.return_value = mock_coro('data')
|
||||||
|
|
||||||
|
with patch('homeassistant.components.hassio.HassIOView._command_proxy',
|
||||||
|
Mock(return_value=mock_coro(response))), \
|
||||||
|
patch('homeassistant.components.hassio.http'
|
||||||
|
'._create_response') as mresp:
|
||||||
|
mresp.return_value = 'response'
|
||||||
|
resp = yield from hassio_client.post('/api/hassio/beer', headers={
|
||||||
|
HTTP_HEADER_HA_AUTH: API_PASSWORD
|
||||||
|
})
|
||||||
|
|
||||||
|
# Check we got right response
|
||||||
|
assert resp.status == 200
|
||||||
|
body = yield from resp.text()
|
||||||
|
assert body == 'response'
|
||||||
|
|
||||||
|
# Check we forwarded command
|
||||||
|
assert len(mresp.mock_calls) == 1
|
||||||
|
assert mresp.mock_calls[0][1] == (response, 'data')
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_auth_required_forward_request(hassio_client):
|
||||||
|
"""Test auth required for normal request."""
|
||||||
|
resp = yield from hassio_client.post('/api/hassio/beer')
|
||||||
|
|
||||||
|
# Check we got right response
|
||||||
|
assert resp.status == 401
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'build_type', [
|
||||||
|
'es5/index.html', 'es5/hassio-app.html', 'latest/index.html',
|
||||||
|
'latest/hassio-app.html'
|
||||||
|
])
|
||||||
|
def test_forward_request_no_auth_for_panel(hassio_client, build_type):
|
||||||
|
"""Test no auth needed for ."""
|
||||||
|
response = MagicMock()
|
||||||
|
response.read.return_value = mock_coro('data')
|
||||||
|
|
||||||
|
with patch('homeassistant.components.hassio.HassIOView._command_proxy',
|
||||||
|
Mock(return_value=mock_coro(response))), \
|
||||||
|
patch('homeassistant.components.hassio.http.'
|
||||||
|
'_create_response') as mresp:
|
||||||
|
mresp.return_value = 'response'
|
||||||
|
resp = yield from hassio_client.get(
|
||||||
|
'/api/hassio/app-{}'.format(build_type))
|
||||||
|
|
||||||
|
# Check we got right response
|
||||||
|
assert resp.status == 200
|
||||||
|
body = yield from resp.text()
|
||||||
|
assert body == 'response'
|
||||||
|
|
||||||
|
# Check we forwarded command
|
||||||
|
assert len(mresp.mock_calls) == 1
|
||||||
|
assert mresp.mock_calls[0][1] == (response, 'data')
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_forward_request_no_auth_for_logo(hassio_client):
|
||||||
|
"""Test no auth needed for ."""
|
||||||
|
response = MagicMock()
|
||||||
|
response.read.return_value = mock_coro('data')
|
||||||
|
|
||||||
|
with patch('homeassistant.components.hassio.HassIOView._command_proxy',
|
||||||
|
Mock(return_value=mock_coro(response))), \
|
||||||
|
patch('homeassistant.components.hassio.http.'
|
||||||
|
'_create_response') as mresp:
|
||||||
|
mresp.return_value = 'response'
|
||||||
|
resp = yield from hassio_client.get('/api/hassio/addons/bl_b392/logo')
|
||||||
|
|
||||||
|
# Check we got right response
|
||||||
|
assert resp.status == 200
|
||||||
|
body = yield from resp.text()
|
||||||
|
assert body == 'response'
|
||||||
|
|
||||||
|
# Check we forwarded command
|
||||||
|
assert len(mresp.mock_calls) == 1
|
||||||
|
assert mresp.mock_calls[0][1] == (response, 'data')
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_forward_log_request(hassio_client):
|
||||||
|
"""Test fetching normal log path."""
|
||||||
|
response = MagicMock()
|
||||||
|
response.read.return_value = mock_coro('data')
|
||||||
|
|
||||||
|
with patch('homeassistant.components.hassio.HassIOView._command_proxy',
|
||||||
|
Mock(return_value=mock_coro(response))), \
|
||||||
|
patch('homeassistant.components.hassio.http.'
|
||||||
|
'_create_response_log') as mresp:
|
||||||
|
mresp.return_value = 'response'
|
||||||
|
resp = yield from hassio_client.get('/api/hassio/beer/logs', headers={
|
||||||
|
HTTP_HEADER_HA_AUTH: API_PASSWORD
|
||||||
|
})
|
||||||
|
|
||||||
|
# Check we got right response
|
||||||
|
assert resp.status == 200
|
||||||
|
body = yield from resp.text()
|
||||||
|
assert body == 'response'
|
||||||
|
|
||||||
|
# Check we forwarded command
|
||||||
|
assert len(mresp.mock_calls) == 1
|
||||||
|
assert mresp.mock_calls[0][1] == (response, 'data')
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_bad_gateway_when_cannot_find_supervisor(hassio_client):
|
||||||
|
"""Test we get a bad gateway error if we can't find supervisor."""
|
||||||
|
with patch('homeassistant.components.hassio.http.async_timeout.timeout',
|
||||||
|
side_effect=asyncio.TimeoutError):
|
||||||
|
resp = yield from hassio_client.get(
|
||||||
|
'/api/hassio/addons/test/info', headers={
|
||||||
|
HTTP_HEADER_HA_AUTH: API_PASSWORD
|
||||||
|
})
|
||||||
|
assert resp.status == 502
|
174
tests/components/hassio/test_init.py
Normal file
174
tests/components/hassio/test_init.py
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
"""The tests for the hassio component."""
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
from unittest.mock import patch, Mock
|
||||||
|
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
from homeassistant.components.hassio import async_check_config
|
||||||
|
|
||||||
|
from tests.common import mock_coro
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_fail_setup_without_environ_var(hass):
|
||||||
|
"""Fail setup if no environ variable set."""
|
||||||
|
with patch.dict(os.environ, {}, clear=True):
|
||||||
|
result = yield from async_setup_component(hass, 'hassio', {})
|
||||||
|
assert not result
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_fail_setup_cannot_connect(hass):
|
||||||
|
"""Fail setup if cannot connect."""
|
||||||
|
with patch.dict(os.environ, {'HASSIO': "127.0.0.1"}), \
|
||||||
|
patch('homeassistant.components.hassio.HassIO.is_connected',
|
||||||
|
Mock(return_value=mock_coro(None))):
|
||||||
|
result = yield from async_setup_component(hass, 'hassio', {})
|
||||||
|
assert not result
|
||||||
|
|
||||||
|
assert not hass.components.hassio.is_hassio()
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_service_register(hassio_env, hass):
|
||||||
|
"""Check if service will be setup."""
|
||||||
|
assert (yield from async_setup_component(hass, 'hassio', {}))
|
||||||
|
assert hass.services.has_service('hassio', 'addon_start')
|
||||||
|
assert hass.services.has_service('hassio', 'addon_stop')
|
||||||
|
assert hass.services.has_service('hassio', 'addon_restart')
|
||||||
|
assert hass.services.has_service('hassio', 'addon_stdin')
|
||||||
|
assert hass.services.has_service('hassio', 'host_shutdown')
|
||||||
|
assert hass.services.has_service('hassio', 'host_reboot')
|
||||||
|
assert hass.services.has_service('hassio', 'host_reboot')
|
||||||
|
assert hass.services.has_service('hassio', 'snapshot_full')
|
||||||
|
assert hass.services.has_service('hassio', 'snapshot_partial')
|
||||||
|
assert hass.services.has_service('hassio', 'restore_full')
|
||||||
|
assert hass.services.has_service('hassio', 'restore_partial')
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_service_calls(hassio_env, hass, aioclient_mock):
|
||||||
|
"""Call service and check the API calls behind that."""
|
||||||
|
assert (yield from async_setup_component(hass, 'hassio', {}))
|
||||||
|
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/addons/test/start", json={'result': 'ok'})
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/addons/test/stop", json={'result': 'ok'})
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/addons/test/restart", json={'result': 'ok'})
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/addons/test/stdin", json={'result': 'ok'})
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/host/shutdown", json={'result': 'ok'})
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/host/reboot", json={'result': 'ok'})
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/snapshots/new/full", json={'result': 'ok'})
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/snapshots/new/partial", json={'result': 'ok'})
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/snapshots/test/restore/full", json={'result': 'ok'})
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/snapshots/test/restore/partial",
|
||||||
|
json={'result': 'ok'})
|
||||||
|
|
||||||
|
yield from hass.services.async_call(
|
||||||
|
'hassio', 'addon_start', {'addon': 'test'})
|
||||||
|
yield from hass.services.async_call(
|
||||||
|
'hassio', 'addon_stop', {'addon': 'test'})
|
||||||
|
yield from hass.services.async_call(
|
||||||
|
'hassio', 'addon_restart', {'addon': 'test'})
|
||||||
|
yield from hass.services.async_call(
|
||||||
|
'hassio', 'addon_stdin', {'addon': 'test', 'input': 'test'})
|
||||||
|
yield from hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert aioclient_mock.call_count == 4
|
||||||
|
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
|
||||||
|
|
||||||
|
yield from hass.services.async_call('hassio', 'snapshot_full', {})
|
||||||
|
yield from hass.services.async_call('hassio', 'snapshot_partial', {
|
||||||
|
'addons': ['test'],
|
||||||
|
'folders': ['ssl'],
|
||||||
|
'password': "123456",
|
||||||
|
})
|
||||||
|
yield from hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert aioclient_mock.call_count == 8
|
||||||
|
assert aioclient_mock.mock_calls[-1][2] == {
|
||||||
|
'addons': ['test'], 'folders': ['ssl'], 'password': "123456"}
|
||||||
|
|
||||||
|
yield from hass.services.async_call('hassio', 'restore_full', {
|
||||||
|
'snapshot': 'test',
|
||||||
|
})
|
||||||
|
yield from hass.services.async_call('hassio', 'restore_partial', {
|
||||||
|
'snapshot': 'test',
|
||||||
|
'homeassistant': False,
|
||||||
|
'addons': ['test'],
|
||||||
|
'folders': ['ssl'],
|
||||||
|
'password': "123456",
|
||||||
|
})
|
||||||
|
yield from hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert aioclient_mock.call_count == 10
|
||||||
|
assert aioclient_mock.mock_calls[-1][2] == {
|
||||||
|
'addons': ['test'], 'folders': ['ssl'], 'homeassistant': False,
|
||||||
|
'password': "123456"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_service_calls_core(hassio_env, hass, aioclient_mock):
|
||||||
|
"""Call core service and check the API calls behind that."""
|
||||||
|
assert (yield from async_setup_component(hass, 'hassio', {}))
|
||||||
|
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/homeassistant/restart", json={'result': 'ok'})
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/homeassistant/stop", json={'result': 'ok'})
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/homeassistant/check", json={'result': 'ok'})
|
||||||
|
|
||||||
|
yield from hass.services.async_call('homeassistant', 'stop')
|
||||||
|
yield from hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert aioclient_mock.call_count == 1
|
||||||
|
|
||||||
|
yield from hass.services.async_call('homeassistant', 'check_config')
|
||||||
|
yield from hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert aioclient_mock.call_count == 2
|
||||||
|
|
||||||
|
yield from hass.services.async_call('homeassistant', 'restart')
|
||||||
|
yield from hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert aioclient_mock.call_count == 4
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_check_config_ok(hassio_env, hass, aioclient_mock):
|
||||||
|
"""Check Config that is okay."""
|
||||||
|
assert (yield from async_setup_component(hass, 'hassio', {}))
|
||||||
|
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/homeassistant/check", json={'result': 'ok'})
|
||||||
|
|
||||||
|
assert (yield from async_check_config(hass)) is None
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
def test_check_config_fail(hassio_env, hass, aioclient_mock):
|
||||||
|
"""Check Config that is wrong."""
|
||||||
|
assert (yield from async_setup_component(hass, 'hassio', {}))
|
||||||
|
|
||||||
|
aioclient_mock.post(
|
||||||
|
"http://127.0.0.1/homeassistant/check", json={
|
||||||
|
'result': 'error', 'message': "Error"})
|
||||||
|
|
||||||
|
assert (yield from async_check_config(hass)) == "Error"
|
@ -1,474 +0,0 @@
|
|||||||
"""The tests for the hassio component."""
|
|
||||||
import asyncio
|
|
||||||
import os
|
|
||||||
from unittest.mock import patch, Mock, MagicMock
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from homeassistant.const import HTTP_HEADER_HA_AUTH
|
|
||||||
from homeassistant.setup import async_setup_component
|
|
||||||
from homeassistant.components.hassio import async_check_config
|
|
||||||
|
|
||||||
from tests.common import mock_coro
|
|
||||||
|
|
||||||
API_PASSWORD = 'pass1234'
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def hassio_env():
|
|
||||||
"""Fixture to inject hassio env."""
|
|
||||||
with patch.dict(os.environ, {'HASSIO': "127.0.0.1"}), \
|
|
||||||
patch('homeassistant.components.hassio.HassIO.is_connected',
|
|
||||||
Mock(return_value=mock_coro(
|
|
||||||
{"result": "ok", "data": {}}))), \
|
|
||||||
patch.dict(os.environ, {'HASSIO_TOKEN': "123456"}), \
|
|
||||||
patch('homeassistant.components.hassio.HassIO.'
|
|
||||||
'get_homeassistant_info',
|
|
||||||
Mock(return_value=mock_coro(None))):
|
|
||||||
yield
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def hassio_client(hassio_env, hass, test_client):
|
|
||||||
"""Create mock hassio http client."""
|
|
||||||
with patch('homeassistant.components.hassio.HassIO.update_hass_api',
|
|
||||||
Mock(return_value=mock_coro({"result": "ok"}))), \
|
|
||||||
patch('homeassistant.components.hassio.HassIO.'
|
|
||||||
'get_homeassistant_info',
|
|
||||||
Mock(return_value=mock_coro(None))):
|
|
||||||
hass.loop.run_until_complete(async_setup_component(hass, 'hassio', {
|
|
||||||
'http': {
|
|
||||||
'api_password': API_PASSWORD
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
yield hass.loop.run_until_complete(test_client(hass.http.app))
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_fail_setup_without_environ_var(hass):
|
|
||||||
"""Fail setup if no environ variable set."""
|
|
||||||
with patch.dict(os.environ, {}, clear=True):
|
|
||||||
result = yield from async_setup_component(hass, 'hassio', {})
|
|
||||||
assert not result
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_fail_setup_cannot_connect(hass):
|
|
||||||
"""Fail setup if cannot connect."""
|
|
||||||
with patch.dict(os.environ, {'HASSIO': "127.0.0.1"}), \
|
|
||||||
patch('homeassistant.components.hassio.HassIO.is_connected',
|
|
||||||
Mock(return_value=mock_coro(None))):
|
|
||||||
result = yield from async_setup_component(hass, 'hassio', {})
|
|
||||||
assert not result
|
|
||||||
|
|
||||||
assert not hass.components.hassio.is_hassio()
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_setup_api_ping(hass, aioclient_mock):
|
|
||||||
"""Test setup with API ping."""
|
|
||||||
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'}})
|
|
||||||
|
|
||||||
with patch.dict(os.environ, {'HASSIO': "127.0.0.1"}):
|
|
||||||
result = yield from async_setup_component(hass, 'hassio', {})
|
|
||||||
assert result
|
|
||||||
|
|
||||||
assert aioclient_mock.call_count == 2
|
|
||||||
assert hass.components.hassio.get_homeassistant_version() == "10.0"
|
|
||||||
assert hass.components.hassio.is_hassio()
|
|
||||||
|
|
||||||
|
|
||||||
@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, {'HASSIO': "127.0.0.1"}):
|
|
||||||
result = yield from async_setup_component(hass, 'hassio', {
|
|
||||||
'http': {
|
|
||||||
'api_password': "123456",
|
|
||||||
'server_port': 9999
|
|
||||||
},
|
|
||||||
'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'] == "123456"
|
|
||||||
assert aioclient_mock.mock_calls[1][2]['port'] == 9999
|
|
||||||
assert aioclient_mock.mock_calls[1][2]['watchdog']
|
|
||||||
|
|
||||||
|
|
||||||
@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, {'HASSIO': "127.0.0.1"}):
|
|
||||||
result = yield from async_setup_component(hass, 'hassio', {
|
|
||||||
'http': {
|
|
||||||
'api_password': "123456",
|
|
||||||
'server_port': 9999,
|
|
||||||
'server_host': "127.0.0.1"
|
|
||||||
},
|
|
||||||
'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'] == "123456"
|
|
||||||
assert aioclient_mock.mock_calls[1][2]['port'] == 9999
|
|
||||||
assert not aioclient_mock.mock_calls[1][2]['watchdog']
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_setup_api_push_api_data_default(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/homeassistant/options", json={'result': 'ok'})
|
|
||||||
|
|
||||||
with patch.dict(os.environ, {'HASSIO': "127.0.0.1"}):
|
|
||||||
result = yield from 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
|
|
||||||
|
|
||||||
|
|
||||||
@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, {'HASSIO': "127.0.0.1"}):
|
|
||||||
result = yield from async_setup_component(hass, 'hassio', {
|
|
||||||
'hassio': {},
|
|
||||||
'homeassistant': {
|
|
||||||
'time_zone': 'testzone',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
assert result
|
|
||||||
|
|
||||||
assert aioclient_mock.call_count == 3
|
|
||||||
assert aioclient_mock.mock_calls[1][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, {'HASSIO': "127.0.0.1"}), \
|
|
||||||
patch.dict(os.environ, {'HASSIO_TOKEN': "123456"}):
|
|
||||||
result = yield from async_setup_component(hass, 'hassio', {
|
|
||||||
'hassio': {},
|
|
||||||
})
|
|
||||||
assert result
|
|
||||||
|
|
||||||
assert aioclient_mock.call_count == 2
|
|
||||||
assert aioclient_mock.mock_calls[-1][3]['X-HASSIO-KEY'] == "123456"
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_service_register(hassio_env, hass):
|
|
||||||
"""Check if service will be setup."""
|
|
||||||
assert (yield from async_setup_component(hass, 'hassio', {}))
|
|
||||||
assert hass.services.has_service('hassio', 'addon_start')
|
|
||||||
assert hass.services.has_service('hassio', 'addon_stop')
|
|
||||||
assert hass.services.has_service('hassio', 'addon_restart')
|
|
||||||
assert hass.services.has_service('hassio', 'addon_stdin')
|
|
||||||
assert hass.services.has_service('hassio', 'host_shutdown')
|
|
||||||
assert hass.services.has_service('hassio', 'host_reboot')
|
|
||||||
assert hass.services.has_service('hassio', 'host_reboot')
|
|
||||||
assert hass.services.has_service('hassio', 'snapshot_full')
|
|
||||||
assert hass.services.has_service('hassio', 'snapshot_partial')
|
|
||||||
assert hass.services.has_service('hassio', 'restore_full')
|
|
||||||
assert hass.services.has_service('hassio', 'restore_partial')
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_service_calls(hassio_env, hass, aioclient_mock):
|
|
||||||
"""Call service and check the API calls behind that."""
|
|
||||||
assert (yield from async_setup_component(hass, 'hassio', {}))
|
|
||||||
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/addons/test/start", json={'result': 'ok'})
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/addons/test/stop", json={'result': 'ok'})
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/addons/test/restart", json={'result': 'ok'})
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/addons/test/stdin", json={'result': 'ok'})
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/host/shutdown", json={'result': 'ok'})
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/host/reboot", json={'result': 'ok'})
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/snapshots/new/full", json={'result': 'ok'})
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/snapshots/new/partial", json={'result': 'ok'})
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/snapshots/test/restore/full", json={'result': 'ok'})
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/snapshots/test/restore/partial",
|
|
||||||
json={'result': 'ok'})
|
|
||||||
|
|
||||||
yield from hass.services.async_call(
|
|
||||||
'hassio', 'addon_start', {'addon': 'test'})
|
|
||||||
yield from hass.services.async_call(
|
|
||||||
'hassio', 'addon_stop', {'addon': 'test'})
|
|
||||||
yield from hass.services.async_call(
|
|
||||||
'hassio', 'addon_restart', {'addon': 'test'})
|
|
||||||
yield from hass.services.async_call(
|
|
||||||
'hassio', 'addon_stdin', {'addon': 'test', 'input': 'test'})
|
|
||||||
yield from hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert aioclient_mock.call_count == 4
|
|
||||||
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
|
|
||||||
|
|
||||||
yield from hass.services.async_call('hassio', 'snapshot_full', {})
|
|
||||||
yield from hass.services.async_call('hassio', 'snapshot_partial', {
|
|
||||||
'addons': ['test'],
|
|
||||||
'folders': ['ssl'],
|
|
||||||
'password': "123456",
|
|
||||||
})
|
|
||||||
yield from hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert aioclient_mock.call_count == 8
|
|
||||||
assert aioclient_mock.mock_calls[-1][2] == {
|
|
||||||
'addons': ['test'], 'folders': ['ssl'], 'password': "123456"}
|
|
||||||
|
|
||||||
yield from hass.services.async_call('hassio', 'restore_full', {
|
|
||||||
'snapshot': 'test',
|
|
||||||
})
|
|
||||||
yield from hass.services.async_call('hassio', 'restore_partial', {
|
|
||||||
'snapshot': 'test',
|
|
||||||
'homeassistant': False,
|
|
||||||
'addons': ['test'],
|
|
||||||
'folders': ['ssl'],
|
|
||||||
'password': "123456",
|
|
||||||
})
|
|
||||||
yield from hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert aioclient_mock.call_count == 10
|
|
||||||
assert aioclient_mock.mock_calls[-1][2] == {
|
|
||||||
'addons': ['test'], 'folders': ['ssl'], 'homeassistant': False,
|
|
||||||
'password': "123456"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_service_calls_core(hassio_env, hass, aioclient_mock):
|
|
||||||
"""Call core service and check the API calls behind that."""
|
|
||||||
assert (yield from async_setup_component(hass, 'hassio', {}))
|
|
||||||
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/homeassistant/restart", json={'result': 'ok'})
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/homeassistant/stop", json={'result': 'ok'})
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/homeassistant/check", json={'result': 'ok'})
|
|
||||||
|
|
||||||
yield from hass.services.async_call('homeassistant', 'stop')
|
|
||||||
yield from hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert aioclient_mock.call_count == 1
|
|
||||||
|
|
||||||
yield from hass.services.async_call('homeassistant', 'check_config')
|
|
||||||
yield from hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert aioclient_mock.call_count == 2
|
|
||||||
|
|
||||||
yield from hass.services.async_call('homeassistant', 'restart')
|
|
||||||
yield from hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert aioclient_mock.call_count == 4
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_check_config_ok(hassio_env, hass, aioclient_mock):
|
|
||||||
"""Check Config that is okay."""
|
|
||||||
assert (yield from async_setup_component(hass, 'hassio', {}))
|
|
||||||
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/homeassistant/check", json={'result': 'ok'})
|
|
||||||
|
|
||||||
assert (yield from async_check_config(hass)) is None
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_check_config_fail(hassio_env, hass, aioclient_mock):
|
|
||||||
"""Check Config that is wrong."""
|
|
||||||
assert (yield from async_setup_component(hass, 'hassio', {}))
|
|
||||||
|
|
||||||
aioclient_mock.post(
|
|
||||||
"http://127.0.0.1/homeassistant/check", json={
|
|
||||||
'result': 'error', 'message': "Error"})
|
|
||||||
|
|
||||||
assert (yield from async_check_config(hass)) == "Error"
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_forward_request(hassio_client):
|
|
||||||
"""Test fetching normal path."""
|
|
||||||
response = MagicMock()
|
|
||||||
response.read.return_value = mock_coro('data')
|
|
||||||
|
|
||||||
with patch('homeassistant.components.hassio.HassIO.command_proxy',
|
|
||||||
Mock(return_value=mock_coro(response))), \
|
|
||||||
patch('homeassistant.components.hassio._create_response') as mresp:
|
|
||||||
mresp.return_value = 'response'
|
|
||||||
resp = yield from hassio_client.post('/api/hassio/beer', headers={
|
|
||||||
HTTP_HEADER_HA_AUTH: API_PASSWORD
|
|
||||||
})
|
|
||||||
|
|
||||||
# Check we got right response
|
|
||||||
assert resp.status == 200
|
|
||||||
body = yield from resp.text()
|
|
||||||
assert body == 'response'
|
|
||||||
|
|
||||||
# Check we forwarded command
|
|
||||||
assert len(mresp.mock_calls) == 1
|
|
||||||
assert mresp.mock_calls[0][1] == (response, 'data')
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_auth_required_forward_request(hassio_client):
|
|
||||||
"""Test auth required for normal request."""
|
|
||||||
resp = yield from hassio_client.post('/api/hassio/beer')
|
|
||||||
|
|
||||||
# Check we got right response
|
|
||||||
assert resp.status == 401
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
'build_type', [
|
|
||||||
'es5/index.html', 'es5/hassio-app.html', 'latest/index.html',
|
|
||||||
'latest/hassio-app.html'
|
|
||||||
])
|
|
||||||
def test_forward_request_no_auth_for_panel(hassio_client, build_type):
|
|
||||||
"""Test no auth needed for ."""
|
|
||||||
response = MagicMock()
|
|
||||||
response.read.return_value = mock_coro('data')
|
|
||||||
|
|
||||||
with patch('homeassistant.components.hassio.HassIO.command_proxy',
|
|
||||||
Mock(return_value=mock_coro(response))), \
|
|
||||||
patch('homeassistant.components.hassio._create_response') as mresp:
|
|
||||||
mresp.return_value = 'response'
|
|
||||||
resp = yield from hassio_client.get(
|
|
||||||
'/api/hassio/app-{}'.format(build_type))
|
|
||||||
|
|
||||||
# Check we got right response
|
|
||||||
assert resp.status == 200
|
|
||||||
body = yield from resp.text()
|
|
||||||
assert body == 'response'
|
|
||||||
|
|
||||||
# Check we forwarded command
|
|
||||||
assert len(mresp.mock_calls) == 1
|
|
||||||
assert mresp.mock_calls[0][1] == (response, 'data')
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_forward_request_no_auth_for_logo(hassio_client):
|
|
||||||
"""Test no auth needed for ."""
|
|
||||||
response = MagicMock()
|
|
||||||
response.read.return_value = mock_coro('data')
|
|
||||||
|
|
||||||
with patch('homeassistant.components.hassio.HassIO.command_proxy',
|
|
||||||
Mock(return_value=mock_coro(response))), \
|
|
||||||
patch('homeassistant.components.hassio._create_response') as mresp:
|
|
||||||
mresp.return_value = 'response'
|
|
||||||
resp = yield from hassio_client.get('/api/hassio/addons/bl_b392/logo')
|
|
||||||
|
|
||||||
# Check we got right response
|
|
||||||
assert resp.status == 200
|
|
||||||
body = yield from resp.text()
|
|
||||||
assert body == 'response'
|
|
||||||
|
|
||||||
# Check we forwarded command
|
|
||||||
assert len(mresp.mock_calls) == 1
|
|
||||||
assert mresp.mock_calls[0][1] == (response, 'data')
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_forward_log_request(hassio_client):
|
|
||||||
"""Test fetching normal log path."""
|
|
||||||
response = MagicMock()
|
|
||||||
response.read.return_value = mock_coro('data')
|
|
||||||
|
|
||||||
with patch('homeassistant.components.hassio.HassIO.command_proxy',
|
|
||||||
Mock(return_value=mock_coro(response))), \
|
|
||||||
patch('homeassistant.components.hassio.'
|
|
||||||
'_create_response_log') as mresp:
|
|
||||||
mresp.return_value = 'response'
|
|
||||||
resp = yield from hassio_client.get('/api/hassio/beer/logs', headers={
|
|
||||||
HTTP_HEADER_HA_AUTH: API_PASSWORD
|
|
||||||
})
|
|
||||||
|
|
||||||
# Check we got right response
|
|
||||||
assert resp.status == 200
|
|
||||||
body = yield from resp.text()
|
|
||||||
assert body == 'response'
|
|
||||||
|
|
||||||
# Check we forwarded command
|
|
||||||
assert len(mresp.mock_calls) == 1
|
|
||||||
assert mresp.mock_calls[0][1] == (response, 'data')
|
|
||||||
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def test_bad_gateway_when_cannot_find_supervisor(hassio_client):
|
|
||||||
"""Test we get a bad gateway error if we can't find supervisor."""
|
|
||||||
with patch('homeassistant.components.hassio.async_timeout.timeout',
|
|
||||||
side_effect=asyncio.TimeoutError):
|
|
||||||
resp = yield from hassio_client.get(
|
|
||||||
'/api/hassio/addons/test/info', headers={
|
|
||||||
HTTP_HEADER_HA_AUTH: API_PASSWORD
|
|
||||||
})
|
|
||||||
assert resp.status == 502
|
|
Loading…
x
Reference in New Issue
Block a user