Add tests

This commit is contained in:
Paulus Schoutsen 2018-09-25 17:13:02 +02:00
parent de66af9eb1
commit 61605ea6a2
5 changed files with 169 additions and 31 deletions

View file

@ -42,27 +42,16 @@ SERVICE_TRIGGER_SCHEMA = vol.Schema({
})
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Optional(DOMAIN): vol.Schema({
vol.Required(CONF_KEY): cv.string,
}),
}, extra=vol.ALLOW_EXTRA)
def trigger(hass, event, value1=None, value2=None, value3=None):
"""Trigger a Maker IFTTT recipe."""
data = {
ATTR_EVENT: event,
ATTR_VALUE1: value1,
ATTR_VALUE2: value2,
ATTR_VALUE3: value3,
}
hass.services.call(DOMAIN, SERVICE_TRIGGER, data)
def async_setup(hass, config):
async def async_setup(hass, config):
"""Set up the IFTTT service component."""
if DOMAIN not in config:
return
return True
key = config[DOMAIN][CONF_KEY]
@ -87,11 +76,12 @@ def async_setup(hass, config):
async def handle_webhook(hass, webhook_id, data):
"""Handle webhook callback."""
data['webhook_id'] = webhook_id
if isinstance(data, dict):
data['webhook_id'] = webhook_id
hass.bus.async_fire(EVENT_RECEIVED, data)
def async_setup_entry(hass, entry):
async def async_setup_entry(hass, entry):
"""Configure based on config entry."""
hass.components.webhook.async_register(
entry.data['webhook_id'], handle_webhook)
@ -108,8 +98,6 @@ async def async_unload_entry(hass, entry):
class ConfigFlow(config_entries.ConfigFlow):
"""Handle an IFTTT config flow."""
webhook_id = None
async def async_step_user(self, user_input=None):
"""Handle a user initiated set up flow."""
if self._async_current_entries():
@ -121,25 +109,22 @@ class ConfigFlow(config_entries.ConfigFlow):
if is_local(ip_address(url_parts.hostname)):
return self.async_abort(reason='not_internet_accessible')
except ValueError:
return self.async_abort(reason='not_internet_accessible')
if self.webhook_id is None:
self.webhook_id = \
self.hass.components.webhook.async_generate_webhook_id()
# If it's not an IP address, it's very likely publicly accessible
pass
if user_input is None:
return self.async_show_form(
step_id='user',
)
webhook_id = self.hass.components.webhook.async_generate_id()
webhook_url = \
self.hass.components.webhook.async_generate_webhook_url(
self.webhook_id)
self.hass.components.webhook.async_generate_url(webhook_id)
return self.async_create_entry(
title='IFTTT Webhook',
data={
CONF_WEBHOOK_ID: self.webhook_id
CONF_WEBHOOK_ID: webhook_id
},
description_placeholders={
'applet_url': 'https://ifttt.com/maker_webhooks',

View file

@ -22,7 +22,7 @@ _LOGGER = logging.getLogger(__name__)
@bind_hass
def async_register(hass, webhook_id, handler):
"""Register a webhook."""
handlers = hass.data.setdefault(webhook_id, {})
handlers = hass.data.setdefault(DOMAIN, {})
if webhook_id in handlers:
raise ValueError('Handler is already defined!')
@ -34,19 +34,19 @@ def async_register(hass, webhook_id, handler):
@bind_hass
def async_unregister(hass, webhook_id):
"""Remove a webhook."""
handlers = hass.data.setdefault(webhook_id, {})
handlers = hass.data.setdefault(DOMAIN, {})
handlers.pop(webhook_id, None)
@callback
def async_generate_webhook_id():
def async_generate_id():
"""Generate a webhook_id."""
return generate_secret(entropy=32)
@callback
@bind_hass
def async_generate_webhook_url(hass, webhook_id):
def async_generate_url(hass, webhook_id):
"""Generate a webhook_id."""
return "{}/api/webhook/{}".format(hass.config.api.base_url, webhook_id)
@ -78,7 +78,7 @@ class WebhookView(HomeAssistantView):
body = await request.text()
try:
data = json.load(body) if body else {}
data = json.loads(body) if body else {}
except ValueError:
_LOGGER.warning(
'Received webhook %s with invalid JSON', webhook_id)

View file

@ -0,0 +1 @@
"""Tests for the IFTTT component."""

View file

@ -0,0 +1,54 @@
"""Test the init file of IFTTT."""
from unittest.mock import Mock, patch
from homeassistant import data_entry_flow
from homeassistant.core import callback
from homeassistant.components import ifttt
# @pytest.fixture
# def mock_client(hass, aiohttp_client):
# """Create http client for webhooks."""
# hass.loop.run_until_complete(async_setup_component(hass, 'http', {}))
# return hass.loop.run_until_complete(aiohttp_client(hass.http.app))
async def test_config_flow_registers_webhook(hass, aiohttp_client):
"""Test setting up IFTTT and sending webhook."""
with patch('homeassistant.util.get_local_ip', return_value='example.com'):
result = await hass.config_entries.flow.async_init('ifttt', context={
'source': 'user'
})
assert result['type'] == data_entry_flow.RESULT_TYPE_FORM, result
result = await hass.config_entries.flow.async_configure(result['flow_id'], {})
assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
webhook_id = result['result'].data['webhook_id']
ifttt_events = []
@callback
def handle_event(event):
"""Handle IFTTT event."""
ifttt_events.append(event)
hass.bus.async_listen(ifttt.EVENT_RECEIVED, handle_event)
client = await aiohttp_client(hass.http.app)
await client.post('/api/webhook/{}'.format(webhook_id), json={
'hello': 'ifttt'
})
assert len(ifttt_events) == 1
assert ifttt_events[0].data['webhook_id'] == webhook_id
assert ifttt_events[0].data['hello'] == 'ifttt'
async def test_config_flow_aborts_external_url(hass, aiohttp_client):
"""Test setting up IFTTT and sending webhook."""
hass.config.api = Mock(base_url='http://192.168.1.10')
result = await hass.config_entries.flow.async_init('ifttt', context={
'source': 'user'
})
assert result['type'] == data_entry_flow.RESULT_TYPE_ABORT
assert result['reason'] == 'not_internet_accessible'

View file

@ -0,0 +1,98 @@
"""Test the webhook component."""
from unittest.mock import Mock
import pytest
from homeassistant.setup import async_setup_component
@pytest.fixture
def mock_client(hass, aiohttp_client):
"""Create http client for webhooks."""
hass.loop.run_until_complete(async_setup_component(hass, 'webhook', {}))
return hass.loop.run_until_complete(aiohttp_client(hass.http.app))
async def test_unregistering_webhook(hass, mock_client):
"""Test unregistering a webhook."""
hooks = []
webhook_id = hass.components.webhook.async_generate_id()
async def handle(*args):
"""Handle webhook."""
hooks.append(args)
hass.components.webhook.async_register(webhook_id, handle)
resp = await mock_client.post('/api/webhook/{}'.format(webhook_id))
assert resp.status == 200
assert len(hooks) == 1
hass.components.webhook.async_unregister(webhook_id)
resp = await mock_client.post('/api/webhook/{}'.format(webhook_id))
assert resp.status == 200
assert len(hooks) == 1
async def test_generate_webhook_url(hass):
"""Test we generate a webhook url correctly."""
hass.config.api = Mock(base_url='https://example.com')
url = hass.components.webhook.async_generate_url('some_id')
assert url == 'https://example.com/api/webhook/some_id'
async def test_posting_webhook_nonexisting(hass, mock_client):
"""Test posting to a nonexisting webhook."""
resp = await mock_client.post('/api/webhook/non-existing')
assert resp.status == 200
async def test_posting_webhook_invalid_json(hass, mock_client):
"""Test posting to a nonexisting webhook."""
hass.components.webhook.async_register('hello', None)
resp = await mock_client.post('/api/webhook/hello', data='not-json')
assert resp.status == 200
async def test_posting_webhook_json(hass, mock_client):
"""Test posting a webhook with JSON data."""
hooks = []
webhook_id = hass.components.webhook.async_generate_id()
async def handle(*args):
"""Handle webhook."""
hooks.append(args)
hass.components.webhook.async_register(webhook_id, handle)
resp = await mock_client.post('/api/webhook/{}'.format(webhook_id), json={
'data': True
})
assert resp.status == 200
assert len(hooks) == 1
assert hooks[0][0] is hass
assert hooks[0][1] == webhook_id
assert hooks[0][2] == {
'data': True
}
async def test_posting_webhook_no_data(hass, mock_client):
"""Test posting a webhook with no data."""
hooks = []
webhook_id = hass.components.webhook.async_generate_id()
async def handle(*args):
"""Handle webhook."""
hooks.append(args)
hass.components.webhook.async_register(webhook_id, handle)
resp = await mock_client.post('/api/webhook/{}'.format(webhook_id))
assert resp.status == 200
assert len(hooks) == 1
assert hooks[0][0] is hass
assert hooks[0][1] == webhook_id
assert hooks[0][2] == {}