Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hassio cleanup part2 #12588

Merged
merged 7 commits into from
Feb 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions homeassistant/components/hassio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,8 @@ def is_hassio(hass):
@asyncio.coroutine
def async_check_config(hass):
"""Check configuration over Hass.io API."""
result = yield from hass.data[DOMAIN].send_command(
'/homeassistant/check', timeout=300)
hassio = hass.data[DOMAIN]
result = yield from hassio.check_homeassistant_config()

if not result:
return "Hass.io config check API error"
Expand Down Expand Up @@ -197,8 +197,7 @@ def update_homeassistant_version(now):
"""Update last available Home Assistant version."""
data = yield from hassio.get_homeassistant_info()
if data:
hass.data[DATA_HOMEASSISTANT_VERSION] = \
data['data']['last_version']
hass.data[DATA_HOMEASSISTANT_VERSION] = data['last_version']

hass.helpers.event.async_track_point_in_utc_time(
update_homeassistant_version, utcnow() + HASSIO_UPDATE_INTERVAL)
Expand All @@ -210,7 +209,7 @@ def update_homeassistant_version(now):
def async_handle_core_service(call):
"""Service handler for handling core services."""
if call.service == SERVICE_HOMEASSISTANT_STOP:
yield from hassio.send_command('/homeassistant/stop')
yield from hassio.stop_homeassistant()
return

error = yield from async_check_config(hass)
Expand All @@ -222,7 +221,7 @@ def async_handle_core_service(call):
return

if call.service == SERVICE_HOMEASSISTANT_RESTART:
yield from hassio.send_command('/homeassistant/restart')
yield from hassio.restart_homeassistant()

# Mock core services
for service in (SERVICE_HOMEASSISTANT_STOP, SERVICE_HOMEASSISTANT_RESTART,
Expand Down
37 changes: 37 additions & 0 deletions homeassistant/components/hassio/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ def _wrapper(*argv, **kwargs):
return _wrapper


def _api_data(funct):
"""Return a api data."""
@asyncio.coroutine
def _wrapper(*argv, **kwargs):
"""Wrap function."""
data = yield from funct(*argv, **kwargs)
if data and data['result'] == "ok":
return data['data']
return None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this make you lose what's inside data if result != ok ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes: https://github.com/home-assistant/hassio/blob/dev/API.md#hassio-restful-api there is only a data on 'ok'. On 'error' there is a message. Maybe we can log this message if available.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be great. I am not a fan of silent errors. I prefer raising.


return _wrapper


class HassIO(object):
"""Small API wrapper for Hass.io."""

Expand All @@ -49,13 +62,37 @@ def is_connected(self):
"""
return self.send_command("/supervisor/ping", method="get")

@_api_data
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 restart_homeassistant(self):
"""Restart Home-Assistant container.

This method return a coroutine.
"""
return self.send_command("/homeassistant/restart")

@_api_bool
def stop_homeassistant(self):
"""Stop Home-Assistant container.

This method return a coroutine.
"""
return self.send_command("/homeassistant/stop")

def check_homeassistant_config(self):
"""Check Home-Assistant config with Hass.io API.

This method return a coroutine.
"""
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.
Expand Down
1 change: 1 addition & 0 deletions tests/components/hassio/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"""Tests for Hassio component."""

API_PASSWORD = 'pass1234'
HASSIO_TOKEN = '123456'
12 changes: 11 additions & 1 deletion tests/components/hassio/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import pytest

from homeassistant.setup import async_setup_component
from homeassistant.components.hassio.handler import HassIO

from tests.common import mock_coro
from . import API_PASSWORD
from . import API_PASSWORD, HASSIO_TOKEN


@pytest.fixture
Expand Down Expand Up @@ -38,3 +39,12 @@ def hassio_client(hassio_env, hass, test_client):
}
}))
yield hass.loop.run_until_complete(test_client(hass.http.app))


@pytest.fixture
def hassio_handler(hass, aioclient_mock):
"""Create mock hassio handler."""
websession = hass.helpers.aiohttp_client.async_get_clientsession()

with patch.dict(os.environ, {'HASSIO_TOKEN': HASSIO_TOKEN}):
yield HassIO(hass.loop, websession, "127.0.0.1")
165 changes: 52 additions & 113 deletions tests/components/hassio/test_handler.py
Original file line number Diff line number Diff line change
@@ -1,151 +1,90 @@
"""The tests for the hassio component."""
import asyncio
import os
from unittest.mock import patch

from homeassistant.setup import async_setup_component
import aiohttp


@asyncio.coroutine
def test_setup_api_ping(hass, aioclient_mock):
def test_api_ping(hassio_handler, 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()
assert (yield from hassio_handler.is_connected())
assert aioclient_mock.call_count == 1


@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'})
def test_api_ping_error(hassio_handler, aioclient_mock):
"""Test setup with API ping error."""
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
"http://127.0.0.1/supervisor/ping", json={'result': 'error'})

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']
assert not (yield from hassio_handler.is_connected())
assert aioclient_mock.call_count == 1


@asyncio.coroutine
def test_setup_api_push_api_data_server_host(hass, aioclient_mock):
"""Test setup with API push with active server host."""
def test_api_ping_exeption(hassio_handler, aioclient_mock):
"""Test setup with API ping exception."""
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']
"http://127.0.0.1/supervisor/ping", exc=aiohttp.ClientError())

assert not (yield from hassio_handler.is_connected())
assert aioclient_mock.call_count == 1


@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'})
def test_api_homeassistant_info(hassio_handler, aioclient_mock):
"""Test setup with API homeassistant info."""
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
data = yield from hassio_handler.get_homeassistant_info()
assert aioclient_mock.call_count == 1
assert data['last_version'] == "10.0"


@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'})
def test_api_homeassistant_info_error(hassio_handler, aioclient_mock):
"""Test setup with API homeassistant info error."""
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'})
'result': 'error', 'message': None})

data = yield from hassio_handler.get_homeassistant_info()
assert aioclient_mock.call_count == 1
assert data is None

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_api_homeassistant_stop(hassio_handler, aioclient_mock):
"""Test setup with API HomeAssistant stop."""
aioclient_mock.post(
"http://127.0.0.1/homeassistant/stop", json={'result': 'ok'})

assert (yield from hassio_handler.stop_homeassistant())
assert aioclient_mock.call_count == 1


@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'})
def test_api_homeassistant_restart(hassio_handler, aioclient_mock):
"""Test setup with API HomeAssistant restart."""
aioclient_mock.post(
"http://127.0.0.1/homeassistant/restart", 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 (yield from hassio_handler.restart_homeassistant())
assert aioclient_mock.call_count == 1


@asyncio.coroutine
def test_api_homeassistant_config(hassio_handler, aioclient_mock):
"""Test setup with API HomeAssistant restart."""
aioclient_mock.post(
"http://127.0.0.1/homeassistant/check", json={
'result': 'ok', 'data': {'test': 'bla'}})

assert aioclient_mock.call_count == 2
assert aioclient_mock.mock_calls[-1][3]['X-HASSIO-KEY'] == "123456"
data = yield from hassio_handler.check_homeassistant_config()
assert data['data']['test'] == 'bla'
assert aioclient_mock.call_count == 1
Loading