"""The tests for the hassio component.""" import asyncio import os from unittest.mock import patch, Mock, MagicMock import pytest import homeassistant.components.hassio as ho from homeassistant.setup import async_setup_component from tests.common import mock_coro, mock_http_component_app @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(True))): yield @pytest.fixture def hassio_client(hassio_env, hass, test_client): """Create mock hassio http client.""" app = mock_http_component_app(hass) hass.loop.run_until_complete(async_setup_component(hass, 'hassio', {})) hass.http.views['api:hassio'].register(app.router) yield hass.loop.run_until_complete(test_client(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(False))): result = yield from async_setup_component(hass, 'hassio', {}) assert not result @asyncio.coroutine def test_invalid_path(hassio_client): """Test requesting invalid path.""" with patch.dict(ho.HASSIO_REST_COMMANDS, {}, clear=True): resp = yield from hassio_client.post('/api/hassio/beer') assert resp.status == 404 @asyncio.coroutine def test_invalid_method(hassio_client): """Test requesting path with invalid method.""" with patch.dict(ho.HASSIO_REST_COMMANDS, {'beer': ['POST']}): resp = yield from hassio_client.get('/api/hassio/beer') assert resp.status == 405 @asyncio.coroutine def test_forward_normal_path(hassio_client): """Test fetching normal path.""" response = MagicMock() response.read.return_value = mock_coro('data') with patch.dict(ho.HASSIO_REST_COMMANDS, {'beer': ['POST']}), \ 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') # 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_normal_log_path(hassio_client): """Test fetching normal log path.""" response = MagicMock() response.read.return_value = mock_coro('data') with patch.dict(ho.HASSIO_REST_COMMANDS, {'beer/logs': ['GET']}), \ 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') # 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_addon_path(hassio_client): """Test fetching addon path.""" response = MagicMock() response.read.return_value = mock_coro('data') with patch.dict(ho.ADDON_REST_COMMANDS, {'install': ['POST']}), \ patch('homeassistant.components.hassio.' 'HassIO.command_proxy') as proxy_command, \ patch('homeassistant.components.hassio._create_response') as mresp: proxy_command.return_value = mock_coro(response) mresp.return_value = 'response' resp = yield from hassio_client.post('/api/hassio/addons/beer/install') # Check we got right response assert resp.status == 200 body = yield from resp.text() assert body == 'response' assert proxy_command.mock_calls[0][1][0] == 'addons/beer/install' # Check we forwarded command assert len(mresp.mock_calls) == 1 assert mresp.mock_calls[0][1] == (response, 'data') @asyncio.coroutine def test_forward_addon_log_path(hassio_client): """Test fetching addon log path.""" response = MagicMock() response.read.return_value = mock_coro('data') with patch.dict(ho.ADDON_REST_COMMANDS, {'logs': ['GET']}), \ patch('homeassistant.components.hassio.' 'HassIO.command_proxy') as proxy_command, \ patch('homeassistant.components.hassio.' '_create_response_log') as mresp: proxy_command.return_value = mock_coro(response) mresp.return_value = 'response' resp = yield from hassio_client.get('/api/hassio/addons/beer/logs') # Check we got right response assert resp.status == 200 body = yield from resp.text() assert body == 'response' assert proxy_command.mock_calls[0][1][0] == 'addons/beer/logs' # Check we forwarded command assert len(mresp.mock_calls) == 1 assert mresp.mock_calls[0][1] == (response, 'data') @asyncio.coroutine def test_bad_request_when_wrong_addon_url(hassio_client): """Test we cannot mess with addon url.""" resp = yield from hassio_client.get('/api/hassio/addons/../../info') assert resp.status == 404 resp = yield from hassio_client.get('/api/hassio/addons/info') assert resp.status == 404 @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') assert resp.status == 502