Add tests
This commit is contained in:
parent
de66af9eb1
commit
61605ea6a2
5 changed files with 169 additions and 31 deletions
|
@ -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',
|
||||
|
|
|
@ -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)
|
||||
|
|
1
tests/components/ifttt/__init__.py
Normal file
1
tests/components/ifttt/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
"""Tests for the IFTTT component."""
|
54
tests/components/ifttt/test_init.py
Normal file
54
tests/components/ifttt/test_init.py
Normal 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'
|
98
tests/components/test_webhook.py
Normal file
98
tests/components/test_webhook.py
Normal 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] == {}
|
Loading…
Add table
Add a link
Reference in a new issue