Migrate Mailgun to use the webhook component (#17464)
* Switch mailgun to use webhook api * Generalize webhook_config_entry_flow * Add tests for webhook_config_entry_flow * Add tests for mailgun * Remove old mailgun file from .coveragerc * Refactor WebhookFlowHandler into config_entry_flow * Remove test of helper func from IFTTT * Lintpull/17719/head
parent
277a9a3995
commit
d5a5695411
homeassistant
components
helpers
tests
components
ifttt
mailgun
helpers
|
@ -209,7 +209,6 @@ omit =
|
|||
homeassistant/components/lutron_caseta.py
|
||||
homeassistant/components/*/lutron_caseta.py
|
||||
|
||||
homeassistant/components/mailgun.py
|
||||
homeassistant/components/*/mailgun.py
|
||||
|
||||
homeassistant/components/matrix.py
|
||||
|
|
|
@ -4,18 +4,15 @@ Support to trigger Maker IFTTT recipes.
|
|||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/ifttt/
|
||||
"""
|
||||
from ipaddress import ip_address
|
||||
import json
|
||||
import logging
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import requests
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_WEBHOOK_ID
|
||||
from homeassistant.util.network import is_local
|
||||
from homeassistant.helpers import config_entry_flow
|
||||
|
||||
REQUIREMENTS = ['pyfttt==0.3']
|
||||
DEPENDENCIES = ['webhook']
|
||||
|
@ -100,43 +97,11 @@ async def async_unload_entry(hass, entry):
|
|||
hass.components.webhook.async_unregister(entry.data[CONF_WEBHOOK_ID])
|
||||
return True
|
||||
|
||||
|
||||
@config_entries.HANDLERS.register(DOMAIN)
|
||||
class ConfigFlow(config_entries.ConfigFlow):
|
||||
"""Handle an IFTTT config flow."""
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle a user initiated set up flow."""
|
||||
if self._async_current_entries():
|
||||
return self.async_abort(reason='one_instance_allowed')
|
||||
|
||||
try:
|
||||
url_parts = urlparse(self.hass.config.api.base_url)
|
||||
|
||||
if is_local(ip_address(url_parts.hostname)):
|
||||
return self.async_abort(reason='not_internet_accessible')
|
||||
except ValueError:
|
||||
# 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_url(webhook_id)
|
||||
|
||||
return self.async_create_entry(
|
||||
title='IFTTT Webhook',
|
||||
data={
|
||||
CONF_WEBHOOK_ID: webhook_id
|
||||
},
|
||||
description_placeholders={
|
||||
'applet_url': 'https://ifttt.com/maker_webhooks',
|
||||
'webhook_url': webhook_url,
|
||||
'docs_url':
|
||||
'https://www.home-assistant.io/components/ifttt/'
|
||||
}
|
||||
)
|
||||
config_entry_flow.register_webhook_flow(
|
||||
DOMAIN,
|
||||
'IFTTT Webhook',
|
||||
{
|
||||
'applet_url': 'https://ifttt.com/maker_webhooks',
|
||||
'docs_url': 'https://www.home-assistant.io/components/ifttt/'
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
"""
|
||||
Support for Mailgun.
|
||||
|
||||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/mailgun/
|
||||
"""
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.const import CONF_API_KEY, CONF_DOMAIN
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.components.http import HomeAssistantView
|
||||
|
||||
|
||||
DOMAIN = 'mailgun'
|
||||
API_PATH = '/api/{}'.format(DOMAIN)
|
||||
DATA_MAILGUN = DOMAIN
|
||||
DEPENDENCIES = ['http']
|
||||
MESSAGE_RECEIVED = '{}_message_received'.format(DOMAIN)
|
||||
CONF_SANDBOX = 'sandbox'
|
||||
DEFAULT_SANDBOX = False
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Required(CONF_API_KEY): cv.string,
|
||||
vol.Required(CONF_DOMAIN): cv.string,
|
||||
vol.Optional(CONF_SANDBOX, default=DEFAULT_SANDBOX): cv.boolean
|
||||
}),
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
"""Set up the Mailgun component."""
|
||||
hass.data[DATA_MAILGUN] = config[DOMAIN]
|
||||
hass.http.register_view(MailgunReceiveMessageView())
|
||||
return True
|
||||
|
||||
|
||||
class MailgunReceiveMessageView(HomeAssistantView):
|
||||
"""Handle data from Mailgun inbound messages."""
|
||||
|
||||
url = API_PATH
|
||||
name = 'api:{}'.format(DOMAIN)
|
||||
|
||||
@callback
|
||||
def post(self, request): # pylint: disable=no-self-use
|
||||
"""Handle Mailgun message POST."""
|
||||
hass = request.app['hass']
|
||||
data = yield from request.post()
|
||||
hass.bus.async_fire(MESSAGE_RECEIVED, dict(data))
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"config": {
|
||||
"title": "Mailgun",
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Set up the Mailgun Webhook",
|
||||
"description": "Are you sure you want to set up Mailgun?"
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"one_instance_allowed": "Only a single instance is necessary.",
|
||||
"not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive Mailgun messages."
|
||||
},
|
||||
"create_entry": {
|
||||
"default": "To send events to Home Assistant, you will need to setup [Webhooks with Mailgun]({mailgun_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/x-www-form-urlencoded\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data."
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
"""
|
||||
Support for Mailgun.
|
||||
|
||||
For more details about this component, please refer to the documentation at
|
||||
https://home-assistant.io/components/mailgun/
|
||||
"""
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.const import CONF_API_KEY, CONF_DOMAIN, CONF_WEBHOOK_ID
|
||||
from homeassistant.helpers import config_entry_flow
|
||||
|
||||
DOMAIN = 'mailgun'
|
||||
API_PATH = '/api/{}'.format(DOMAIN)
|
||||
DEPENDENCIES = ['webhook']
|
||||
MESSAGE_RECEIVED = '{}_message_received'.format(DOMAIN)
|
||||
CONF_SANDBOX = 'sandbox'
|
||||
DEFAULT_SANDBOX = False
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
vol.Optional(DOMAIN): vol.Schema({
|
||||
vol.Required(CONF_API_KEY): cv.string,
|
||||
vol.Required(CONF_DOMAIN): cv.string,
|
||||
vol.Optional(CONF_SANDBOX, default=DEFAULT_SANDBOX): cv.boolean,
|
||||
vol.Optional(CONF_WEBHOOK_ID): cv.string,
|
||||
}),
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
|
||||
async def async_setup(hass, config):
|
||||
"""Set up the Mailgun component."""
|
||||
if DOMAIN not in config:
|
||||
return True
|
||||
|
||||
hass.data[DOMAIN] = config[DOMAIN]
|
||||
return True
|
||||
|
||||
|
||||
async def handle_webhook(hass, webhook_id, request):
|
||||
"""Handle incoming webhook with Mailgun inbound messages."""
|
||||
data = dict(await request.post())
|
||||
data['webhook_id'] = webhook_id
|
||||
hass.bus.async_fire(MESSAGE_RECEIVED, data)
|
||||
|
||||
|
||||
async def async_setup_entry(hass, entry):
|
||||
"""Configure based on config entry."""
|
||||
hass.components.webhook.async_register(
|
||||
entry.data[CONF_WEBHOOK_ID], handle_webhook)
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass, entry):
|
||||
"""Unload a config entry."""
|
||||
hass.components.webhook.async_unregister(entry.data[CONF_WEBHOOK_ID])
|
||||
return True
|
||||
|
||||
config_entry_flow.register_webhook_flow(
|
||||
DOMAIN,
|
||||
'Mailgun Webhook',
|
||||
{
|
||||
'mailgun_url':
|
||||
'https://www.mailgun.com/blog/a-guide-to-using-mailguns-webhooks',
|
||||
'docs_url': 'https://www.home-assistant.io/components/mailgun/'
|
||||
}
|
||||
)
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"config": {
|
||||
"title": "Mailgun",
|
||||
"step": {
|
||||
"user": {
|
||||
"title": "Set up the Mailgun Webhook",
|
||||
"description": "Are you sure you want to set up Mailgun?"
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"one_instance_allowed": "Only a single instance is necessary.",
|
||||
"not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive Mailgun messages."
|
||||
},
|
||||
"create_entry": {
|
||||
"default": "To send events to Home Assistant, you will need to setup [Webhooks with Mailgun]({mailgun_url}).\n\nFill in the following info:\n\n- URL: `{webhook_url}`\n- Method: POST\n- Content Type: application/x-www-form-urlencoded\n\nSee [the documentation]({docs_url}) on how to configure automations to handle incoming data."
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,8 @@ import logging
|
|||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.mailgun import CONF_SANDBOX, DATA_MAILGUN
|
||||
from homeassistant.components.mailgun import (
|
||||
CONF_SANDBOX, DOMAIN as MAILGUN_DOMAIN)
|
||||
from homeassistant.components.notify import (
|
||||
PLATFORM_SCHEMA, BaseNotificationService, ATTR_TITLE, ATTR_TITLE_DEFAULT,
|
||||
ATTR_DATA)
|
||||
|
@ -35,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
|||
|
||||
def get_service(hass, config, discovery_info=None):
|
||||
"""Get the Mailgun notification service."""
|
||||
data = hass.data[DATA_MAILGUN]
|
||||
data = hass.data[MAILGUN_DOMAIN]
|
||||
mailgun_service = MailgunNotificationService(
|
||||
data.get(CONF_DOMAIN), data.get(CONF_SANDBOX),
|
||||
data.get(CONF_API_KEY), config.get(CONF_SENDER),
|
||||
|
|
|
@ -143,6 +143,7 @@ FLOWS = [
|
|||
'ifttt',
|
||||
'ios',
|
||||
'lifx',
|
||||
'mailgun',
|
||||
'mqtt',
|
||||
'nest',
|
||||
'openuv',
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
"""Helpers for data entry flows for config entries."""
|
||||
from functools import partial
|
||||
from ipaddress import ip_address
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.util.network import is_local
|
||||
|
||||
|
||||
def register_discovery_flow(domain, title, discovery_function,
|
||||
|
@ -12,6 +15,14 @@ def register_discovery_flow(domain, title, discovery_function,
|
|||
connection_class))
|
||||
|
||||
|
||||
def register_webhook_flow(domain, title, description_placeholder,
|
||||
allow_multiple=False):
|
||||
"""Register flow for webhook integrations."""
|
||||
config_entries.HANDLERS.register(domain)(
|
||||
partial(WebhookFlowHandler, domain, title, description_placeholder,
|
||||
allow_multiple))
|
||||
|
||||
|
||||
class DiscoveryFlowHandler(config_entries.ConfigFlow):
|
||||
"""Handle a discovery config flow."""
|
||||
|
||||
|
@ -84,3 +95,50 @@ class DiscoveryFlowHandler(config_entries.ConfigFlow):
|
|||
title=self._title,
|
||||
data={},
|
||||
)
|
||||
|
||||
|
||||
class WebhookFlowHandler(config_entries.ConfigFlow):
|
||||
"""Handle a webhook config flow."""
|
||||
|
||||
VERSION = 1
|
||||
|
||||
def __init__(self, domain, title, description_placeholder,
|
||||
allow_multiple):
|
||||
"""Initialize the discovery config flow."""
|
||||
self._domain = domain
|
||||
self._title = title
|
||||
self._description_placeholder = description_placeholder
|
||||
self._allow_multiple = allow_multiple
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle a user initiated set up flow to create a webhook."""
|
||||
if not self._allow_multiple and self._async_current_entries():
|
||||
return self.async_abort(reason='one_instance_allowed')
|
||||
|
||||
try:
|
||||
url_parts = urlparse(self.hass.config.api.base_url)
|
||||
|
||||
if is_local(ip_address(url_parts.hostname)):
|
||||
return self.async_abort(reason='not_internet_accessible')
|
||||
except ValueError:
|
||||
# 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_url(webhook_id)
|
||||
|
||||
self._description_placeholder['webhook_url'] = webhook_url
|
||||
|
||||
return self.async_create_entry(
|
||||
title=self._title,
|
||||
data={
|
||||
'webhook_id': webhook_id
|
||||
},
|
||||
description_placeholders=self._description_placeholder
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""Test the init file of IFTTT."""
|
||||
from unittest.mock import Mock, patch
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant import data_entry_flow
|
||||
from homeassistant.core import callback
|
||||
|
@ -36,13 +36,3 @@ async def test_config_flow_registers_webhook(hass, aiohttp_client):
|
|||
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'
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
"""Tests for the Mailgun component."""
|
|
@ -0,0 +1,39 @@
|
|||
"""Test the init file of Mailgun."""
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant import data_entry_flow
|
||||
from homeassistant.components import mailgun
|
||||
|
||||
from homeassistant.core import callback
|
||||
|
||||
|
||||
async def test_config_flow_registers_webhook(hass, aiohttp_client):
|
||||
"""Test setting up Mailgun and sending webhook."""
|
||||
with patch('homeassistant.util.get_local_ip', return_value='example.com'):
|
||||
result = await hass.config_entries.flow.async_init('mailgun', 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']
|
||||
|
||||
mailgun_events = []
|
||||
|
||||
@callback
|
||||
def handle_event(event):
|
||||
"""Handle Mailgun event."""
|
||||
mailgun_events.append(event)
|
||||
|
||||
hass.bus.async_listen(mailgun.MESSAGE_RECEIVED, handle_event)
|
||||
|
||||
client = await aiohttp_client(hass.http.app)
|
||||
await client.post('/api/webhook/{}'.format(webhook_id), data={
|
||||
'hello': 'mailgun'
|
||||
})
|
||||
|
||||
assert len(mailgun_events) == 1
|
||||
assert mailgun_events[0].data['webhook_id'] == webhook_id
|
||||
assert mailgun_events[0].data['hello'] == 'mailgun'
|
|
@ -1,5 +1,5 @@
|
|||
"""Tests for the Config Entry Flow helper."""
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import patch, Mock
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -9,7 +9,7 @@ from tests.common import MockConfigEntry, MockModule
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def flow_conf(hass):
|
||||
def discovery_flow_conf(hass):
|
||||
"""Register a handler."""
|
||||
handler_conf = {
|
||||
'discovered': False,
|
||||
|
@ -26,7 +26,18 @@ def flow_conf(hass):
|
|||
yield handler_conf
|
||||
|
||||
|
||||
async def test_single_entry_allowed(hass, flow_conf):
|
||||
@pytest.fixture
|
||||
def webhook_flow_conf(hass):
|
||||
"""Register a handler."""
|
||||
with patch.dict(config_entries.HANDLERS):
|
||||
config_entry_flow.register_webhook_flow(
|
||||
'test_single', 'Test Single', {}, False)
|
||||
config_entry_flow.register_webhook_flow(
|
||||
'test_multiple', 'Test Multiple', {}, True)
|
||||
yield {}
|
||||
|
||||
|
||||
async def test_single_entry_allowed(hass, discovery_flow_conf):
|
||||
"""Test only a single entry is allowed."""
|
||||
flow = config_entries.HANDLERS['test']()
|
||||
flow.hass = hass
|
||||
|
@ -38,7 +49,7 @@ async def test_single_entry_allowed(hass, flow_conf):
|
|||
assert result['reason'] == 'single_instance_allowed'
|
||||
|
||||
|
||||
async def test_user_no_devices_found(hass, flow_conf):
|
||||
async def test_user_no_devices_found(hass, discovery_flow_conf):
|
||||
"""Test if no devices found."""
|
||||
flow = config_entries.HANDLERS['test']()
|
||||
flow.hass = hass
|
||||
|
@ -51,18 +62,18 @@ async def test_user_no_devices_found(hass, flow_conf):
|
|||
assert result['reason'] == 'no_devices_found'
|
||||
|
||||
|
||||
async def test_user_has_confirmation(hass, flow_conf):
|
||||
async def test_user_has_confirmation(hass, discovery_flow_conf):
|
||||
"""Test user requires no confirmation to setup."""
|
||||
flow = config_entries.HANDLERS['test']()
|
||||
flow.hass = hass
|
||||
flow_conf['discovered'] = True
|
||||
discovery_flow_conf['discovered'] = True
|
||||
|
||||
result = await flow.async_step_user()
|
||||
|
||||
assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
|
||||
|
||||
|
||||
async def test_discovery_single_instance(hass, flow_conf):
|
||||
async def test_discovery_single_instance(hass, discovery_flow_conf):
|
||||
"""Test we ask for confirmation via discovery."""
|
||||
flow = config_entries.HANDLERS['test']()
|
||||
flow.hass = hass
|
||||
|
@ -74,7 +85,7 @@ async def test_discovery_single_instance(hass, flow_conf):
|
|||
assert result['reason'] == 'single_instance_allowed'
|
||||
|
||||
|
||||
async def test_discovery_confirmation(hass, flow_conf):
|
||||
async def test_discovery_confirmation(hass, discovery_flow_conf):
|
||||
"""Test we ask for confirmation via discovery."""
|
||||
flow = config_entries.HANDLERS['test']()
|
||||
flow.hass = hass
|
||||
|
@ -88,7 +99,7 @@ async def test_discovery_confirmation(hass, flow_conf):
|
|||
assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
|
||||
|
||||
async def test_multiple_discoveries(hass, flow_conf):
|
||||
async def test_multiple_discoveries(hass, discovery_flow_conf):
|
||||
"""Test we only create one instance for multiple discoveries."""
|
||||
loader.set_component(hass, 'test', MockModule('test'))
|
||||
|
||||
|
@ -102,7 +113,7 @@ async def test_multiple_discoveries(hass, flow_conf):
|
|||
assert result['type'] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
|
||||
|
||||
async def test_only_one_in_progress(hass, flow_conf):
|
||||
async def test_only_one_in_progress(hass, discovery_flow_conf):
|
||||
"""Test a user initialized one will finish and cancel discovered one."""
|
||||
loader.set_component(hass, 'test', MockModule('test'))
|
||||
|
||||
|
@ -127,22 +138,71 @@ async def test_only_one_in_progress(hass, flow_conf):
|
|||
assert len(hass.config_entries.flow.async_progress()) == 0
|
||||
|
||||
|
||||
async def test_import_no_confirmation(hass, flow_conf):
|
||||
async def test_import_no_confirmation(hass, discovery_flow_conf):
|
||||
"""Test import requires no confirmation to set up."""
|
||||
flow = config_entries.HANDLERS['test']()
|
||||
flow.hass = hass
|
||||
flow_conf['discovered'] = True
|
||||
discovery_flow_conf['discovered'] = True
|
||||
|
||||
result = await flow.async_step_import(None)
|
||||
assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
|
||||
|
||||
async def test_import_single_instance(hass, flow_conf):
|
||||
async def test_import_single_instance(hass, discovery_flow_conf):
|
||||
"""Test import doesn't create second instance."""
|
||||
flow = config_entries.HANDLERS['test']()
|
||||
flow.hass = hass
|
||||
flow_conf['discovered'] = True
|
||||
discovery_flow_conf['discovered'] = True
|
||||
MockConfigEntry(domain='test').add_to_hass(hass)
|
||||
|
||||
result = await flow.async_step_import(None)
|
||||
assert result['type'] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
|
||||
|
||||
async def test_webhook_single_entry_allowed(hass, webhook_flow_conf):
|
||||
"""Test only a single entry is allowed."""
|
||||
flow = config_entries.HANDLERS['test_single']()
|
||||
flow.hass = hass
|
||||
|
||||
MockConfigEntry(domain='test_single').add_to_hass(hass)
|
||||
result = await flow.async_step_user()
|
||||
|
||||
assert result['type'] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert result['reason'] == 'one_instance_allowed'
|
||||
|
||||
|
||||
async def test_webhook_multiple_entries_allowed(hass, webhook_flow_conf):
|
||||
"""Test multiple entries are allowed when specified."""
|
||||
flow = config_entries.HANDLERS['test_multiple']()
|
||||
flow.hass = hass
|
||||
|
||||
MockConfigEntry(domain='test_multiple').add_to_hass(hass)
|
||||
hass.config.api = Mock(base_url='http://example.com')
|
||||
|
||||
result = await flow.async_step_user()
|
||||
assert result['type'] == data_entry_flow.RESULT_TYPE_FORM
|
||||
|
||||
|
||||
async def test_webhook_config_flow_aborts_external_url(hass,
|
||||
webhook_flow_conf):
|
||||
"""Test configuring a webhook without an external url."""
|
||||
flow = config_entries.HANDLERS['test_single']()
|
||||
flow.hass = hass
|
||||
|
||||
hass.config.api = Mock(base_url='http://192.168.1.10')
|
||||
result = await flow.async_step_user()
|
||||
|
||||
assert result['type'] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert result['reason'] == 'not_internet_accessible'
|
||||
|
||||
|
||||
async def test_webhook_config_flow_registers_webhook(hass, webhook_flow_conf):
|
||||
"""Test setting up an entry creates a webhook."""
|
||||
flow = config_entries.HANDLERS['test_single']()
|
||||
flow.hass = hass
|
||||
|
||||
hass.config.api = Mock(base_url='http://example.com')
|
||||
result = await flow.async_step_user(user_input={})
|
||||
|
||||
assert result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result['data']['webhook_id'] is not None
|
||||
|
|
Loading…
Reference in New Issue