mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 16:57:53 +00:00
Add config flow to pushover
(#74500)
* Add config flow to `pushover` * Add tests for reauth * add deprecated yaml issue * address comments * fix test error, other fixes * update translations
This commit is contained in:
parent
09aaf45f0a
commit
72a4f8af3d
@ -848,6 +848,8 @@ build.json @home-assistant/supervisor
|
||||
/tests/components/pure_energie/ @klaasnicolaas
|
||||
/homeassistant/components/push/ @dgomes
|
||||
/tests/components/push/ @dgomes
|
||||
/homeassistant/components/pushover/ @engrbm87
|
||||
/tests/components/pushover/ @engrbm87
|
||||
/homeassistant/components/pvoutput/ @frenck
|
||||
/tests/components/pvoutput/ @frenck
|
||||
/homeassistant/components/pvpc_hourly_pricing/ @azogue
|
||||
|
@ -1 +1,55 @@
|
||||
"""The pushover component."""
|
||||
from __future__ import annotations
|
||||
|
||||
from pushover_complete import BadAPIRequestError, PushoverAPI
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_API_KEY, CONF_NAME, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
||||
from homeassistant.helpers import discovery
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from .const import CONF_USER_KEY, DATA_HASS_CONFIG, DOMAIN
|
||||
|
||||
PLATFORMS = [Platform.NOTIFY]
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up the pushover component."""
|
||||
|
||||
hass.data[DATA_HASS_CONFIG] = config
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Set up pushover from a config entry."""
|
||||
|
||||
pushover_api = PushoverAPI(entry.data[CONF_API_KEY])
|
||||
try:
|
||||
await hass.async_add_executor_job(
|
||||
pushover_api.validate, entry.data[CONF_USER_KEY]
|
||||
)
|
||||
|
||||
except BadAPIRequestError as err:
|
||||
if "application token is invalid" in str(err):
|
||||
raise ConfigEntryAuthFailed(err) from err
|
||||
raise ConfigEntryNotReady(err) from err
|
||||
|
||||
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = pushover_api
|
||||
|
||||
hass.async_create_task(
|
||||
discovery.async_load_platform(
|
||||
hass,
|
||||
Platform.NOTIFY,
|
||||
DOMAIN,
|
||||
{
|
||||
CONF_NAME: entry.data[CONF_NAME],
|
||||
CONF_USER_KEY: entry.data[CONF_USER_KEY],
|
||||
"entry_id": entry.entry_id,
|
||||
},
|
||||
hass.data[DATA_HASS_CONFIG],
|
||||
)
|
||||
)
|
||||
|
||||
return True
|
||||
|
106
homeassistant/components/pushover/config_flow.py
Normal file
106
homeassistant/components/pushover/config_flow.py
Normal file
@ -0,0 +1,106 @@
|
||||
"""Config flow for pushover integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Mapping
|
||||
from typing import Any
|
||||
|
||||
from pushover_complete import BadAPIRequestError, PushoverAPI
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_API_KEY, CONF_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResult
|
||||
|
||||
from .const import CONF_USER_KEY, DEFAULT_NAME, DOMAIN
|
||||
|
||||
USER_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): str,
|
||||
vol.Required(CONF_API_KEY): str,
|
||||
vol.Required(CONF_USER_KEY): str,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, str]:
|
||||
"""Validate user input."""
|
||||
errors = {}
|
||||
pushover_api = PushoverAPI(data[CONF_API_KEY])
|
||||
try:
|
||||
await hass.async_add_executor_job(pushover_api.validate, data[CONF_USER_KEY])
|
||||
except BadAPIRequestError as err:
|
||||
if "application token is invalid" in str(err):
|
||||
errors[CONF_API_KEY] = "invalid_api_key"
|
||||
elif "user key is invalid" in str(err):
|
||||
errors[CONF_USER_KEY] = "invalid_user_key"
|
||||
else:
|
||||
errors["base"] = "cannot_connect"
|
||||
return errors
|
||||
|
||||
|
||||
class PushBulletConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a config flow for pushover integration."""
|
||||
|
||||
_reauth_entry: config_entries.ConfigEntry | None
|
||||
|
||||
async def async_step_import(self, import_config: dict[str, Any]) -> FlowResult:
|
||||
"""Handle import from config."""
|
||||
return await self.async_step_user(import_config)
|
||||
|
||||
async def async_step_reauth(self, entry_data: Mapping[str, Any]) -> FlowResult:
|
||||
"""Perform reauth upon an API authentication error."""
|
||||
self._reauth_entry = self.hass.config_entries.async_get_entry(
|
||||
self.context["entry_id"]
|
||||
)
|
||||
return await self.async_step_reauth_confirm()
|
||||
|
||||
async def async_step_reauth_confirm(
|
||||
self, user_input: dict[str, str] | None = None
|
||||
) -> FlowResult:
|
||||
"""Confirm reauth dialog."""
|
||||
errors = {}
|
||||
if user_input is not None and self._reauth_entry:
|
||||
user_input = {**self._reauth_entry.data, **user_input}
|
||||
errors = await validate_input(self.hass, user_input)
|
||||
if not errors:
|
||||
self.hass.config_entries.async_update_entry(
|
||||
self._reauth_entry, data=user_input
|
||||
)
|
||||
await self.hass.config_entries.async_reload(self._reauth_entry.entry_id)
|
||||
return self.async_abort(reason="reauth_successful")
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="reauth_confirm",
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_API_KEY): str,
|
||||
}
|
||||
),
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> FlowResult:
|
||||
"""Handle the initial step."""
|
||||
errors = {}
|
||||
|
||||
if user_input is not None:
|
||||
await self.async_set_unique_id(user_input[CONF_USER_KEY])
|
||||
self._abort_if_unique_id_configured()
|
||||
|
||||
self._async_abort_entries_match({CONF_NAME: user_input[CONF_NAME]})
|
||||
|
||||
errors = await validate_input(self.hass, user_input)
|
||||
if not errors:
|
||||
return self.async_create_entry(
|
||||
title=user_input[CONF_NAME],
|
||||
data=user_input,
|
||||
)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
data_schema=USER_SCHEMA,
|
||||
errors=errors,
|
||||
)
|
20
homeassistant/components/pushover/const.py
Normal file
20
homeassistant/components/pushover/const.py
Normal file
@ -0,0 +1,20 @@
|
||||
"""Constants for pushover."""
|
||||
|
||||
from typing import Final
|
||||
|
||||
DOMAIN: Final = "pushover"
|
||||
DATA_HASS_CONFIG: Final = "pushover_hass_config"
|
||||
DEFAULT_NAME: Final = "Pushover"
|
||||
|
||||
ATTR_ATTACHMENT: Final = "attachment"
|
||||
ATTR_URL: Final = "url"
|
||||
ATTR_URL_TITLE: Final = "url_title"
|
||||
ATTR_PRIORITY: Final = "priority"
|
||||
ATTR_RETRY: Final = "retry"
|
||||
ATTR_SOUND: Final = "sound"
|
||||
ATTR_HTML: Final = "html"
|
||||
ATTR_CALLBACK_URL: Final = "callback_url"
|
||||
ATTR_EXPIRE: Final = "expire"
|
||||
ATTR_TIMESTAMP: Final = "timestamp"
|
||||
|
||||
CONF_USER_KEY: Final = "user_key"
|
@ -1,9 +1,11 @@
|
||||
{
|
||||
"domain": "pushover",
|
||||
"name": "Pushover",
|
||||
"dependencies": ["repairs"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/pushover",
|
||||
"requirements": ["pushover_complete==1.1.1"],
|
||||
"codeowners": [],
|
||||
"codeowners": ["@engrbm87"],
|
||||
"config_flow": true,
|
||||
"iot_class": "cloud_push",
|
||||
"loggers": ["pushover_complete"]
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
"""Pushover platform for notify component."""
|
||||
import logging
|
||||
from __future__ import annotations
|
||||
|
||||
from pushover_complete import PushoverAPI
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from pushover_complete import BadAPIRequestError, PushoverAPI
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.notify import (
|
||||
@ -12,47 +15,82 @@ from homeassistant.components.notify import (
|
||||
PLATFORM_SCHEMA,
|
||||
BaseNotificationService,
|
||||
)
|
||||
from homeassistant.components.repairs.issue_handler import async_create_issue
|
||||
from homeassistant.components.repairs.models import IssueSeverity
|
||||
from homeassistant.config_entries import SOURCE_IMPORT
|
||||
from homeassistant.const import CONF_API_KEY
|
||||
from homeassistant.core import HomeAssistant
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
||||
|
||||
from ...exceptions import HomeAssistantError
|
||||
from .const import (
|
||||
ATTR_ATTACHMENT,
|
||||
ATTR_CALLBACK_URL,
|
||||
ATTR_EXPIRE,
|
||||
ATTR_HTML,
|
||||
ATTR_PRIORITY,
|
||||
ATTR_RETRY,
|
||||
ATTR_SOUND,
|
||||
ATTR_TIMESTAMP,
|
||||
ATTR_URL,
|
||||
ATTR_URL_TITLE,
|
||||
CONF_USER_KEY,
|
||||
DOMAIN,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTR_ATTACHMENT = "attachment"
|
||||
ATTR_URL = "url"
|
||||
ATTR_URL_TITLE = "url_title"
|
||||
ATTR_PRIORITY = "priority"
|
||||
ATTR_RETRY = "retry"
|
||||
ATTR_SOUND = "sound"
|
||||
ATTR_HTML = "html"
|
||||
ATTR_CALLBACK_URL = "callback_url"
|
||||
ATTR_EXPIRE = "expire"
|
||||
ATTR_TIMESTAMP = "timestamp"
|
||||
|
||||
CONF_USER_KEY = "user_key"
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
{vol.Required(CONF_USER_KEY): cv.string, vol.Required(CONF_API_KEY): cv.string}
|
||||
)
|
||||
|
||||
|
||||
def get_service(hass, config, discovery_info=None):
|
||||
async def async_get_service(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> PushoverNotificationService | None:
|
||||
"""Get the Pushover notification service."""
|
||||
if discovery_info is None:
|
||||
|
||||
async_create_issue(
|
||||
hass,
|
||||
DOMAIN,
|
||||
"deprecated_yaml",
|
||||
breaks_in_ha_version="2022.11.0",
|
||||
is_fixable=False,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecated_yaml",
|
||||
)
|
||||
hass.async_create_task(
|
||||
hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
data=config,
|
||||
)
|
||||
)
|
||||
return None
|
||||
|
||||
pushover_api: PushoverAPI = hass.data[DOMAIN][discovery_info["entry_id"]]
|
||||
return PushoverNotificationService(
|
||||
hass, config[CONF_USER_KEY], config[CONF_API_KEY]
|
||||
hass, pushover_api, discovery_info[CONF_USER_KEY]
|
||||
)
|
||||
|
||||
|
||||
class PushoverNotificationService(BaseNotificationService):
|
||||
"""Implement the notification service for Pushover."""
|
||||
|
||||
def __init__(self, hass, user_key, api_token):
|
||||
def __init__(
|
||||
self, hass: HomeAssistant, pushover: PushoverAPI, user_key: str
|
||||
) -> None:
|
||||
"""Initialize the service."""
|
||||
self._hass = hass
|
||||
self._user_key = user_key
|
||||
self._api_token = api_token
|
||||
self.pushover = PushoverAPI(self._api_token)
|
||||
self.pushover = pushover
|
||||
|
||||
def send_message(self, message="", **kwargs):
|
||||
def send_message(self, message: str = "", **kwargs: dict[str, Any]) -> None:
|
||||
"""Send a message to a user."""
|
||||
|
||||
# Extract params from data dict
|
||||
@ -87,28 +125,22 @@ class PushoverNotificationService(BaseNotificationService):
|
||||
# Remove attachment key to send without attachment.
|
||||
image = None
|
||||
|
||||
targets = kwargs.get(ATTR_TARGET)
|
||||
|
||||
if not isinstance(targets, list):
|
||||
targets = [targets]
|
||||
|
||||
for target in targets:
|
||||
try:
|
||||
self.pushover.send_message(
|
||||
self._user_key,
|
||||
message,
|
||||
target,
|
||||
title,
|
||||
url,
|
||||
url_title,
|
||||
image,
|
||||
priority,
|
||||
retry,
|
||||
expire,
|
||||
callback_url,
|
||||
timestamp,
|
||||
sound,
|
||||
html,
|
||||
)
|
||||
except ValueError as val_err:
|
||||
_LOGGER.error(val_err)
|
||||
try:
|
||||
self.pushover.send_message(
|
||||
self._user_key,
|
||||
message,
|
||||
kwargs.get(ATTR_TARGET),
|
||||
title,
|
||||
url,
|
||||
url_title,
|
||||
image,
|
||||
priority,
|
||||
retry,
|
||||
expire,
|
||||
callback_url,
|
||||
timestamp,
|
||||
sound,
|
||||
html,
|
||||
)
|
||||
except BadAPIRequestError as err:
|
||||
raise HomeAssistantError(str(err)) from err
|
||||
|
34
homeassistant/components/pushover/strings.json
Normal file
34
homeassistant/components/pushover/strings.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_service%]",
|
||||
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||
"invalid_api_key": "[%key:common::config_flow::error::invalid_api_key%]",
|
||||
"invalid_user_key": "Invalid user key"
|
||||
},
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"name": "[%key:common::config_flow::data::name%]",
|
||||
"api_key": "[%key:common::config_flow::data::api_key%]",
|
||||
"user_key": "User key"
|
||||
}
|
||||
},
|
||||
"reauth_confirm": {
|
||||
"title": "[%key:common::config_flow::title::reauth%]",
|
||||
"data": {
|
||||
"api_key": "[%key:common::config_flow::data::api_key%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"deprecated_yaml": {
|
||||
"title": "The Pushover YAML configuration is being removed",
|
||||
"description": "Configuring Pushover using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the Pushover YAML configuration from your configuration.yaml file and restart Home Assistant to fix this issue."
|
||||
}
|
||||
}
|
||||
}
|
34
homeassistant/components/pushover/translations/en.json
Normal file
34
homeassistant/components/pushover/translations/en.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"already_configured": "Service is already configured",
|
||||
"reauth_successful": "Re-authentication was successful"
|
||||
},
|
||||
"error": {
|
||||
"cannot_connect": "Failed to connect",
|
||||
"invalid_api_key": "Invalid API key",
|
||||
"invalid_user_key": "Invalid user key"
|
||||
},
|
||||
"step": {
|
||||
"reauth_confirm": {
|
||||
"data": {
|
||||
"api_key": "API Key"
|
||||
},
|
||||
"title": "Reauthenticate Integration"
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"api_key": "API Key",
|
||||
"name": "Name",
|
||||
"user_key": "User key"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"deprecated_yaml": {
|
||||
"description": "Configuring Pushover using YAML is being removed.\n\nYour existing YAML configuration has been imported into the UI automatically.\n\nRemove the Pushover YAML configuration from your configuration.yaml file and restart Home Assistant to fix this issue.",
|
||||
"title": "The Pushover YAML configuration is being removed"
|
||||
}
|
||||
}
|
||||
}
|
@ -290,6 +290,7 @@ FLOWS = {
|
||||
"prosegur",
|
||||
"ps4",
|
||||
"pure_energie",
|
||||
"pushover",
|
||||
"pvoutput",
|
||||
"pvpc_hourly_pricing",
|
||||
"qingping",
|
||||
|
@ -918,6 +918,9 @@ pure-python-adb[async]==0.3.0.dev0
|
||||
# homeassistant.components.pushbullet
|
||||
pushbullet.py==0.11.0
|
||||
|
||||
# homeassistant.components.pushover
|
||||
pushover_complete==1.1.1
|
||||
|
||||
# homeassistant.components.pvoutput
|
||||
pvo==0.2.2
|
||||
|
||||
|
10
tests/components/pushover/__init__.py
Normal file
10
tests/components/pushover/__init__.py
Normal file
@ -0,0 +1,10 @@
|
||||
"""Tests for the pushover component."""
|
||||
|
||||
from homeassistant.components.pushover.const import CONF_USER_KEY
|
||||
from homeassistant.const import CONF_API_KEY, CONF_NAME
|
||||
|
||||
MOCK_CONFIG = {
|
||||
CONF_NAME: "Pushover",
|
||||
CONF_API_KEY: "MYAPIKEY",
|
||||
CONF_USER_KEY: "MYUSERKEY",
|
||||
}
|
218
tests/components/pushover/test_config_flow.py
Normal file
218
tests/components/pushover/test_config_flow.py
Normal file
@ -0,0 +1,218 @@
|
||||
"""Test pushbullet config flow."""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from pushover_complete import BadAPIRequestError
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries, data_entry_flow
|
||||
from homeassistant.components.pushover.const import CONF_USER_KEY, DOMAIN
|
||||
from homeassistant.const import CONF_API_KEY
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from . import MOCK_CONFIG
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_pushover():
|
||||
"""Mock pushover."""
|
||||
with patch(
|
||||
"pushover_complete.PushoverAPI._generic_post", return_value={}
|
||||
) as mock_generic_post:
|
||||
yield mock_generic_post
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def pushover_setup_fixture():
|
||||
"""Patch pushover setup entry."""
|
||||
with patch(
|
||||
"homeassistant.components.pushover.async_setup_entry", return_value=True
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
async def test_flow_user(hass: HomeAssistant) -> None:
|
||||
"""Test user initialized flow."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_USER},
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input=MOCK_CONFIG,
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == "Pushover"
|
||||
assert result["data"] == MOCK_CONFIG
|
||||
|
||||
|
||||
async def test_flow_user_key_already_configured(hass: HomeAssistant) -> None:
|
||||
"""Test user initialized flow with duplicate user key."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=MOCK_CONFIG,
|
||||
unique_id="MYUSERKEY",
|
||||
)
|
||||
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_USER},
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input=MOCK_CONFIG,
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_flow_name_already_configured(hass: HomeAssistant) -> None:
|
||||
"""Test user initialized flow with duplicate server."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=MOCK_CONFIG,
|
||||
unique_id="MYUSERKEY",
|
||||
)
|
||||
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
new_config = MOCK_CONFIG.copy()
|
||||
new_config[CONF_USER_KEY] = "NEUSERWKEY"
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_USER},
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input=new_config,
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_flow_invalid_user_key(
|
||||
hass: HomeAssistant, mock_pushover: MagicMock
|
||||
) -> None:
|
||||
"""Test user initialized flow with wrong user key."""
|
||||
|
||||
mock_pushover.side_effect = BadAPIRequestError("400: user key is invalid")
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_USER},
|
||||
data=MOCK_CONFIG,
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {CONF_USER_KEY: "invalid_user_key"}
|
||||
|
||||
|
||||
async def test_flow_invalid_api_key(
|
||||
hass: HomeAssistant, mock_pushover: MagicMock
|
||||
) -> None:
|
||||
"""Test user initialized flow with wrong api key."""
|
||||
|
||||
mock_pushover.side_effect = BadAPIRequestError("400: application token is invalid")
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_USER},
|
||||
data=MOCK_CONFIG,
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {CONF_API_KEY: "invalid_api_key"}
|
||||
|
||||
|
||||
async def test_flow_conn_err(hass: HomeAssistant, mock_pushover: MagicMock) -> None:
|
||||
"""Test user initialized flow with conn error."""
|
||||
|
||||
mock_pushover.side_effect = BadAPIRequestError
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_USER},
|
||||
data=MOCK_CONFIG,
|
||||
)
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {"base": "cannot_connect"}
|
||||
|
||||
|
||||
async def test_import(hass: HomeAssistant) -> None:
|
||||
"""Test user initialized flow with unreachable server."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_IMPORT},
|
||||
data=MOCK_CONFIG,
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert result["title"] == "Pushover"
|
||||
assert result["data"] == MOCK_CONFIG
|
||||
|
||||
|
||||
async def test_reauth_success(hass: HomeAssistant) -> None:
|
||||
"""Test we can reauth."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=MOCK_CONFIG,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={
|
||||
"source": config_entries.SOURCE_REAUTH,
|
||||
"entry_id": entry.entry_id,
|
||||
},
|
||||
data=MOCK_CONFIG,
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "reauth_confirm"
|
||||
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
CONF_API_KEY: "NEWAPIKEY",
|
||||
},
|
||||
)
|
||||
|
||||
assert result2["type"] == "abort"
|
||||
assert result2["reason"] == "reauth_successful"
|
||||
|
||||
|
||||
async def test_reauth_failed(hass: HomeAssistant, mock_pushover: MagicMock) -> None:
|
||||
"""Test we can reauth."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=MOCK_CONFIG,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={
|
||||
"source": config_entries.SOURCE_REAUTH,
|
||||
"entry_id": entry.entry_id,
|
||||
},
|
||||
data=MOCK_CONFIG,
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "reauth_confirm"
|
||||
|
||||
mock_pushover.side_effect = BadAPIRequestError("400: application token is invalid")
|
||||
result2 = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{
|
||||
CONF_API_KEY: "WRONGAPIKEY",
|
||||
},
|
||||
)
|
||||
|
||||
assert result2["type"] == "form"
|
||||
assert result2["errors"] == {
|
||||
CONF_API_KEY: "invalid_api_key",
|
||||
}
|
98
tests/components/pushover/test_init.py
Normal file
98
tests/components/pushover/test_init.py
Normal file
@ -0,0 +1,98 @@
|
||||
"""Test pushbullet integration."""
|
||||
from collections.abc import Awaitable
|
||||
from typing import Callable
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import aiohttp
|
||||
from pushover_complete import BadAPIRequestError
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.notify.const import DOMAIN as NOTIFY_DOMAIN
|
||||
from homeassistant.components.pushover.const import DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from . import MOCK_CONFIG
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.components.repairs import get_repairs
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_pushover():
|
||||
"""Mock pushover."""
|
||||
with patch(
|
||||
"pushover_complete.PushoverAPI._generic_post", return_value={}
|
||||
) as mock_generic_post:
|
||||
yield mock_generic_post
|
||||
|
||||
|
||||
async def test_setup(
|
||||
hass: HomeAssistant,
|
||||
hass_ws_client: Callable[
|
||||
[HomeAssistant], Awaitable[aiohttp.ClientWebSocketResponse]
|
||||
],
|
||||
) -> None:
|
||||
"""Test integration failed due to an error."""
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
NOTIFY_DOMAIN,
|
||||
{
|
||||
NOTIFY_DOMAIN: [
|
||||
{
|
||||
"name": "Pushover",
|
||||
"platform": "pushover",
|
||||
"api_key": "MYAPIKEY",
|
||||
"user_key": "MYUSERKEY",
|
||||
}
|
||||
]
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.config_entries.async_entries(DOMAIN)
|
||||
issues = await get_repairs(hass, hass_ws_client)
|
||||
assert len(issues) == 1
|
||||
assert issues[0]["issue_id"] == "deprecated_yaml"
|
||||
|
||||
|
||||
async def test_async_setup_entry_success(hass: HomeAssistant) -> None:
|
||||
"""Test pushover successful setup."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=MOCK_CONFIG,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert entry.state == ConfigEntryState.LOADED
|
||||
|
||||
|
||||
async def test_async_setup_entry_failed_invalid_api_key(
|
||||
hass: HomeAssistant, mock_pushover: MagicMock
|
||||
) -> None:
|
||||
"""Test pushover failed setup due to invalid api key."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=MOCK_CONFIG,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
mock_pushover.side_effect = BadAPIRequestError("400: application token is invalid")
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert entry.state == ConfigEntryState.SETUP_ERROR
|
||||
|
||||
|
||||
async def test_async_setup_entry_failed_conn_error(
|
||||
hass: HomeAssistant, mock_pushover: MagicMock
|
||||
) -> None:
|
||||
"""Test pushover failed setup due to conn error."""
|
||||
entry = MockConfigEntry(
|
||||
domain=DOMAIN,
|
||||
data=MOCK_CONFIG,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
mock_pushover.side_effect = BadAPIRequestError
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
assert entry.state == ConfigEntryState.SETUP_RETRY
|
Loading…
x
Reference in New Issue
Block a user