Push Overseerr updates via webhook (#134187)
parent
0ef254bc9a
commit
23ed62c1bc
|
@ -2,9 +2,23 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
import json
|
||||
|
||||
from aiohttp.hdrs import METH_POST
|
||||
from aiohttp.web_request import Request
|
||||
from aiohttp.web_response import Response
|
||||
from python_overseerr import OverseerrConnectionError
|
||||
|
||||
from homeassistant.components.webhook import (
|
||||
async_generate_url,
|
||||
async_register,
|
||||
async_unregister,
|
||||
)
|
||||
from homeassistant.const import CONF_WEBHOOK_ID, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.http import HomeAssistantView
|
||||
|
||||
from .const import DOMAIN, JSON_PAYLOAD, LOGGER, REGISTERED_NOTIFICATIONS
|
||||
from .coordinator import OverseerrConfigEntry, OverseerrCoordinator
|
||||
|
||||
PLATFORMS: list[Platform] = [Platform.SENSOR]
|
||||
|
@ -19,6 +33,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: OverseerrConfigEntry) ->
|
|||
|
||||
entry.runtime_data = coordinator
|
||||
|
||||
webhook_manager = OverseerrWebhookManager(hass, entry)
|
||||
|
||||
try:
|
||||
await webhook_manager.register_webhook()
|
||||
except OverseerrConnectionError:
|
||||
LOGGER.error("Failed to register Overseerr webhook")
|
||||
|
||||
entry.async_on_unload(webhook_manager.unregister_webhook)
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
return True
|
||||
|
@ -27,3 +50,61 @@ async def async_setup_entry(hass: HomeAssistant, entry: OverseerrConfigEntry) ->
|
|||
async def async_unload_entry(hass: HomeAssistant, entry: OverseerrConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
||||
|
||||
|
||||
class OverseerrWebhookManager:
|
||||
"""Overseerr webhook manager."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, entry: OverseerrConfigEntry) -> None:
|
||||
"""Initialize Overseerr webhook manager."""
|
||||
self.hass = hass
|
||||
self.entry = entry
|
||||
self.client = entry.runtime_data.client
|
||||
|
||||
async def register_webhook(self) -> None:
|
||||
"""Register webhook."""
|
||||
async_register(
|
||||
self.hass,
|
||||
DOMAIN,
|
||||
self.entry.title,
|
||||
self.entry.data[CONF_WEBHOOK_ID],
|
||||
self.handle_webhook,
|
||||
allowed_methods=[METH_POST],
|
||||
)
|
||||
url = async_generate_url(self.hass, self.entry.data[CONF_WEBHOOK_ID])
|
||||
if not await self.check_need_change(url):
|
||||
return
|
||||
LOGGER.debug("Setting Overseerr webhook to %s", url)
|
||||
if not await self.client.test_webhook_notification_config(url, JSON_PAYLOAD):
|
||||
LOGGER.debug("Failed to set Overseerr webhook")
|
||||
return
|
||||
await self.client.set_webhook_notification_config(
|
||||
enabled=True,
|
||||
types=REGISTERED_NOTIFICATIONS,
|
||||
webhook_url=url,
|
||||
json_payload=JSON_PAYLOAD,
|
||||
)
|
||||
|
||||
async def check_need_change(self, url: str) -> bool:
|
||||
"""Check if webhook needs to be changed."""
|
||||
current_config = await self.client.get_webhook_notification_config()
|
||||
return (
|
||||
not current_config.enabled
|
||||
or current_config.options.webhook_url != url
|
||||
or current_config.options.json_payload != json.loads(JSON_PAYLOAD)
|
||||
or current_config.types != REGISTERED_NOTIFICATIONS
|
||||
)
|
||||
|
||||
async def handle_webhook(
|
||||
self, hass: HomeAssistant, webhook_id: str, request: Request
|
||||
) -> Response:
|
||||
"""Handle webhook."""
|
||||
data = await request.json()
|
||||
LOGGER.debug("Received webhook payload: %s", data)
|
||||
if data["notification_type"].startswith("MEDIA"):
|
||||
await self.entry.runtime_data.async_refresh()
|
||||
return HomeAssistantView.json({"message": "ok"})
|
||||
|
||||
async def unregister_webhook(self) -> None:
|
||||
"""Unregister webhook."""
|
||||
async_unregister(self.hass, self.entry.data[CONF_WEBHOOK_ID])
|
||||
|
|
|
@ -7,8 +7,16 @@ from python_overseerr.exceptions import OverseerrError
|
|||
import voluptuous as vol
|
||||
from yarl import URL
|
||||
|
||||
from homeassistant.components.webhook import async_generate_id
|
||||
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||
from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT, CONF_SSL, CONF_URL
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_HOST,
|
||||
CONF_PORT,
|
||||
CONF_SSL,
|
||||
CONF_URL,
|
||||
CONF_WEBHOOK_ID,
|
||||
)
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import DOMAIN
|
||||
|
@ -49,6 +57,7 @@ class OverseerrConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
CONF_PORT: port,
|
||||
CONF_SSL: url.scheme == "https",
|
||||
CONF_API_KEY: user_input[CONF_API_KEY],
|
||||
CONF_WEBHOOK_ID: async_generate_id(),
|
||||
},
|
||||
)
|
||||
return self.async_show_form(
|
||||
|
|
|
@ -2,7 +2,44 @@
|
|||
|
||||
import logging
|
||||
|
||||
from python_overseerr.models import NotificationType
|
||||
|
||||
DOMAIN = "overseerr"
|
||||
LOGGER = logging.getLogger(__package__)
|
||||
|
||||
REQUESTS = "requests"
|
||||
|
||||
REGISTERED_NOTIFICATIONS = (
|
||||
NotificationType.REQUEST_PENDING_APPROVAL
|
||||
| NotificationType.REQUEST_APPROVED
|
||||
| NotificationType.REQUEST_DECLINED
|
||||
| NotificationType.REQUEST_AVAILABLE
|
||||
| NotificationType.REQUEST_PROCESSING_FAILED
|
||||
| NotificationType.REQUEST_AUTOMATICALLY_APPROVED
|
||||
)
|
||||
JSON_PAYLOAD = (
|
||||
'"{\\"notification_type\\":\\"{{notification_type}}\\",\\"event\\":\\"'
|
||||
'{{event}}\\",\\"subject\\":\\"{{subject}}\\",\\"message\\":\\"{{messa'
|
||||
'ge}}\\",\\"image\\":\\"{{image}}\\",\\"{{media}}\\":{\\"media_type\\"'
|
||||
':\\"{{media_type}}\\",\\"tmdbId\\":\\"{{media_tmdbid}}\\",\\"tvdbId\\'
|
||||
'":\\"{{media_tvdbid}}\\",\\"status\\":\\"{{media_status}}\\",\\"statu'
|
||||
's4k\\":\\"{{media_status4k}}\\"},\\"{{request}}\\":{\\"request_id\\":'
|
||||
'\\"{{request_id}}\\",\\"requestedBy_email\\":\\"{{requestedBy_email}}'
|
||||
'\\",\\"requestedBy_username\\":\\"{{requestedBy_username}}\\",\\"requ'
|
||||
'estedBy_avatar\\":\\"{{requestedBy_avatar}}\\",\\"requestedBy_setting'
|
||||
's_discordId\\":\\"{{requestedBy_settings_discordId}}\\",\\"requestedB'
|
||||
'y_settings_telegramChatId\\":\\"{{requestedBy_settings_telegramChatId'
|
||||
'}}\\"},\\"{{issue}}\\":{\\"issue_id\\":\\"{{issue_id}}\\",\\"issue_ty'
|
||||
'pe\\":\\"{{issue_type}}\\",\\"issue_status\\":\\"{{issue_status}}\\",'
|
||||
'\\"reportedBy_email\\":\\"{{reportedBy_email}}\\",\\"reportedBy_usern'
|
||||
'ame\\":\\"{{reportedBy_username}}\\",\\"reportedBy_avatar\\":\\"{{rep'
|
||||
'ortedBy_avatar}}\\",\\"reportedBy_settings_discordId\\":\\"{{reported'
|
||||
'By_settings_discordId}}\\",\\"reportedBy_settings_telegramChatId\\":'
|
||||
'\\"{{reportedBy_settings_telegramChatId}}\\"},\\"{{comment}}\\":{\\"c'
|
||||
'omment_message\\":\\"{{comment_message}}\\",\\"commentedBy_email\\":'
|
||||
'\\"{{commentedBy_email}}\\",\\"commentedBy_username\\":\\"{{commented'
|
||||
'By_username}}\\",\\"commentedBy_avatar\\":\\"{{commentedBy_avatar}}'
|
||||
'\\",\\"commentedBy_settings_discordId\\":\\"{{commentedBy_settings_di'
|
||||
'scordId}}\\",\\"commentedBy_settings_telegramChatId\\":\\"{{commented'
|
||||
'By_settings_telegramChatId}}\\"},\\"{{extra}}\\":[]\\n}"'
|
||||
)
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
"name": "Overseerr",
|
||||
"codeowners": ["@joostlek"],
|
||||
"config_flow": true,
|
||||
"dependencies": ["http", "webhook"],
|
||||
"documentation": "https://www.home-assistant.io/integrations/overseerr",
|
||||
"integration_type": "service",
|
||||
"iot_class": "local_polling",
|
||||
"iot_class": "local_push",
|
||||
"quality_scale": "bronze",
|
||||
"requirements": ["python-overseerr==0.4.0"]
|
||||
}
|
||||
|
|
|
@ -4587,7 +4587,7 @@
|
|||
"name": "Overseerr",
|
||||
"integration_type": "service",
|
||||
"config_flow": true,
|
||||
"iot_class": "local_polling"
|
||||
"iot_class": "local_push"
|
||||
},
|
||||
"ovo_energy": {
|
||||
"name": "OVO Energy",
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
"""Tests for the Overseerr integration."""
|
||||
|
||||
from typing import Any
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from aiohttp.test_utils import TestClient
|
||||
|
||||
from homeassistant.components.webhook import async_generate_url
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from .const import WEBHOOK_ID
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
|
@ -11,3 +19,21 @@ async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry)
|
|||
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def call_webhook(
|
||||
hass: HomeAssistant, data: dict[str, Any], client: TestClient
|
||||
) -> None:
|
||||
"""Call the webhook."""
|
||||
webhook_url = async_generate_url(hass, WEBHOOK_ID)
|
||||
|
||||
resp = await client.post(
|
||||
urlparse(webhook_url).path,
|
||||
json=data,
|
||||
)
|
||||
|
||||
# Wait for remaining tasks to complete.
|
||||
await hass.async_block_till_done()
|
||||
|
||||
data = await resp.json()
|
||||
resp.close()
|
||||
|
|
|
@ -5,9 +5,18 @@ from unittest.mock import AsyncMock, patch
|
|||
|
||||
import pytest
|
||||
from python_overseerr import RequestCount
|
||||
from python_overseerr.models import WebhookNotificationConfig
|
||||
|
||||
from homeassistant.components.overseerr.const import DOMAIN
|
||||
from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT, CONF_SSL
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_HOST,
|
||||
CONF_PORT,
|
||||
CONF_SSL,
|
||||
CONF_WEBHOOK_ID,
|
||||
)
|
||||
|
||||
from .const import WEBHOOK_ID
|
||||
|
||||
from tests.common import MockConfigEntry, load_fixture
|
||||
|
||||
|
@ -39,6 +48,12 @@ def mock_overseerr_client() -> Generator[AsyncMock]:
|
|||
client.get_request_count.return_value = RequestCount.from_json(
|
||||
load_fixture("request_count.json", DOMAIN)
|
||||
)
|
||||
client.get_webhook_notification_config.return_value = (
|
||||
WebhookNotificationConfig.from_json(
|
||||
load_fixture("webhook_config.json", DOMAIN)
|
||||
)
|
||||
)
|
||||
client.test_webhook_notification_config.return_value = True
|
||||
yield client
|
||||
|
||||
|
||||
|
@ -53,6 +68,7 @@ def mock_config_entry() -> MockConfigEntry:
|
|||
CONF_PORT: 80,
|
||||
CONF_SSL: False,
|
||||
CONF_API_KEY: "test-key",
|
||||
CONF_WEBHOOK_ID: WEBHOOK_ID,
|
||||
},
|
||||
entry_id="01JG00V55WEVTJ0CJHM0GAD7PC",
|
||||
)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
"""Constants for the Overseerr tests."""
|
||||
|
||||
WEBHOOK_ID = "test-webhook-id"
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"enabled": true,
|
||||
"types": 222,
|
||||
"options": {
|
||||
"jsonPayload": "{\"notification_type\":\"{{notification_type}}\",\"event\":\"{{event}}\",\"subject\":\"{{subject}}\",\"message\":\"{{message}}\",\"image\":\"{{image}}\",\"{{media}}\":{\"media_type\":\"{{media_type}}\",\"tmdbId\":\"{{media_tmdbid}}\",\"tvdbId\":\"{{media_tvdbid}}\",\"status\":\"{{media_status}}\",\"status4k\":\"{{media_status4k}}\"},\"{{request}}\":{\"request_id\":\"{{request_id}}\",\"requestedBy_email\":\"{{requestedBy_email}}\",\"requestedBy_username\":\"{{requestedBy_username}}\",\"requestedBy_avatar\":\"{{requestedBy_avatar}}\",\"requestedBy_settings_discordId\":\"{{requestedBy_settings_discordId}}\",\"requestedBy_settings_telegramChatId\":\"{{requestedBy_settings_telegramChatId}}\"},\"{{issue}}\":{\"issue_id\":\"{{issue_id}}\",\"issue_type\":\"{{issue_type}}\",\"issue_status\":\"{{issue_status}}\",\"reportedBy_email\":\"{{reportedBy_email}}\",\"reportedBy_username\":\"{{reportedBy_username}}\",\"reportedBy_avatar\":\"{{reportedBy_avatar}}\",\"reportedBy_settings_discordId\":\"{{reportedBy_settings_discordId}}\",\"reportedBy_settings_telegramChatId\":\"{{reportedBy_settings_telegramChatId}}\"},\"{{comment}}\":{\"comment_message\":\"{{comment_message}}\",\"commentedBy_email\":\"{{commentedBy_email}}\",\"commentedBy_username\":\"{{commentedBy_username}}\",\"commentedBy_avatar\":\"{{commentedBy_avatar}}\",\"commentedBy_settings_discordId\":\"{{commentedBy_settings_discordId}}\",\"commentedBy_settings_telegramChatId\":\"{{commentedBy_settings_telegramChatId}}\"},\"{{extra}}\":[]\n}",
|
||||
"webhookUrl": "http://10.10.10.10:8123/api/webhook/test-webhook-id"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"notification_type": "MEDIA_AUTO_APPROVED",
|
||||
"event": "Movie Request Automatically Approved",
|
||||
"subject": "Something (2024)",
|
||||
"message": "Here is an interesting Linux ISO that was automatically approved.",
|
||||
"image": "https://image.tmdb.org/t/p/w600_and_h900_bestv2/something.jpg",
|
||||
"media": {
|
||||
"media_type": "movie",
|
||||
"tmdbId": "123",
|
||||
"tvdbId": "",
|
||||
"status": "PENDING",
|
||||
"status4k": "UNKNOWN"
|
||||
},
|
||||
"request": {
|
||||
"request_id": "16",
|
||||
"requestedBy_email": "my@email.com",
|
||||
"requestedBy_username": "henk",
|
||||
"requestedBy_avatar": "https://plex.tv/users/abc/avatar?c=123",
|
||||
"requestedBy_settings_discordId": "123",
|
||||
"requestedBy_settings_telegramChatId": ""
|
||||
},
|
||||
"issue": null,
|
||||
"comment": null,
|
||||
"extra": []
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"notification_type": "TEST_NOTIFICATION",
|
||||
"event": "",
|
||||
"subject": "Test Notification",
|
||||
"message": "Check check, 1, 2, 3. Are we coming in clear?",
|
||||
"image": "",
|
||||
"media": null,
|
||||
"request": null,
|
||||
"issue": null,
|
||||
"comment": null,
|
||||
"extra": []
|
||||
}
|
|
@ -1,18 +1,38 @@
|
|||
"""Tests for the Overseerr config flow."""
|
||||
|
||||
from unittest.mock import AsyncMock
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
from python_overseerr.exceptions import OverseerrConnectionError
|
||||
|
||||
from homeassistant.components.overseerr.const import DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
from homeassistant.const import CONF_API_KEY, CONF_HOST, CONF_PORT, CONF_SSL, CONF_URL
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_HOST,
|
||||
CONF_PORT,
|
||||
CONF_SSL,
|
||||
CONF_URL,
|
||||
CONF_WEBHOOK_ID,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
|
||||
from .const import WEBHOOK_ID
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def patch_webhook_id() -> None:
|
||||
"""Patch webhook ID generation."""
|
||||
with patch(
|
||||
"homeassistant.components.overseerr.config_flow.async_generate_id",
|
||||
return_value=WEBHOOK_ID,
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
async def test_full_flow(
|
||||
hass: HomeAssistant,
|
||||
mock_overseerr_client: AsyncMock,
|
||||
|
@ -37,6 +57,7 @@ async def test_full_flow(
|
|||
CONF_PORT: 80,
|
||||
CONF_SSL: False,
|
||||
CONF_API_KEY: "test-key",
|
||||
CONF_WEBHOOK_ID: "test-webhook-id",
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
"""Tests for the Overseerr integration."""
|
||||
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
from python_overseerr.models import WebhookNotificationOptions
|
||||
from syrupy import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.overseerr import JSON_PAYLOAD, REGISTERED_NOTIFICATIONS
|
||||
from homeassistant.components.overseerr.const import DOMAIN
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
|
@ -27,3 +31,100 @@ async def test_device_info(
|
|||
)
|
||||
assert device_entry is not None
|
||||
assert device_entry == snapshot
|
||||
|
||||
|
||||
async def test_proper_webhook_configuration(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_overseerr_client: AsyncMock,
|
||||
) -> None:
|
||||
"""Test the webhook configuration."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
assert REGISTERED_NOTIFICATIONS == 222
|
||||
|
||||
mock_overseerr_client.test_webhook_notification_config.assert_not_called()
|
||||
mock_overseerr_client.set_webhook_notification_config.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"update_mock",
|
||||
[
|
||||
{"return_value.enabled": False},
|
||||
{"return_value.types": 4},
|
||||
{"return_value.types": 4062},
|
||||
{
|
||||
"return_value.options": WebhookNotificationOptions(
|
||||
webhook_url="http://example.com", json_payload=JSON_PAYLOAD
|
||||
)
|
||||
},
|
||||
{
|
||||
"return_value.options": WebhookNotificationOptions(
|
||||
webhook_url="http://10.10.10.10:8123/api/webhook/test-webhook-id",
|
||||
json_payload='"{\\"message\\": \\"{{title}}\\"}"',
|
||||
)
|
||||
},
|
||||
],
|
||||
ids=[
|
||||
"Disabled",
|
||||
"Smaller scope",
|
||||
"Bigger scope",
|
||||
"Webhook URL",
|
||||
"JSON Payload",
|
||||
],
|
||||
)
|
||||
async def test_webhook_configuration_need_update(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_overseerr_client: AsyncMock,
|
||||
update_mock: dict[str, Any],
|
||||
) -> None:
|
||||
"""Test the webhook configuration."""
|
||||
mock_overseerr_client.get_webhook_notification_config.configure_mock(**update_mock)
|
||||
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
mock_overseerr_client.test_webhook_notification_config.assert_called_once()
|
||||
mock_overseerr_client.set_webhook_notification_config.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"update_mock",
|
||||
[
|
||||
{"return_value.enabled": False},
|
||||
{"return_value.types": 4},
|
||||
{"return_value.types": 4062},
|
||||
{
|
||||
"return_value.options": WebhookNotificationOptions(
|
||||
webhook_url="http://example.com", json_payload=JSON_PAYLOAD
|
||||
)
|
||||
},
|
||||
{
|
||||
"return_value.options": WebhookNotificationOptions(
|
||||
webhook_url="http://10.10.10.10:8123/api/webhook/test-webhook-id",
|
||||
json_payload='"{\\"message\\": \\"{{title}}\\"}"',
|
||||
)
|
||||
},
|
||||
],
|
||||
ids=[
|
||||
"Disabled",
|
||||
"Smaller scope",
|
||||
"Bigger scope",
|
||||
"Webhook URL",
|
||||
"JSON Payload",
|
||||
],
|
||||
)
|
||||
async def test_webhook_failing_test(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_overseerr_client: AsyncMock,
|
||||
update_mock: dict[str, Any],
|
||||
) -> None:
|
||||
"""Test the webhook configuration."""
|
||||
mock_overseerr_client.test_webhook_notification_config.return_value = False
|
||||
mock_overseerr_client.get_webhook_notification_config.configure_mock(**update_mock)
|
||||
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
mock_overseerr_client.test_webhook_notification_config.assert_called_once()
|
||||
mock_overseerr_client.set_webhook_notification_config.assert_not_called()
|
||||
|
|
|
@ -4,13 +4,15 @@ from unittest.mock import AsyncMock, patch
|
|||
|
||||
from syrupy import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.overseerr import DOMAIN
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import setup_integration
|
||||
from . import call_webhook, setup_integration
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
from tests.common import MockConfigEntry, load_json_object_fixture, snapshot_platform
|
||||
from tests.typing import ClientSessionGenerator
|
||||
|
||||
|
||||
async def test_all_entities(
|
||||
|
@ -25,3 +27,27 @@ async def test_all_entities(
|
|||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
async def test_webhook_trigger_update(
|
||||
hass: HomeAssistant,
|
||||
mock_overseerr_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
hass_client_no_auth: ClientSessionGenerator,
|
||||
) -> None:
|
||||
"""Test all entities."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
assert hass.states.get("sensor.overseerr_available_requests").state == "8"
|
||||
|
||||
mock_overseerr_client.get_request_count.return_value.available = 7
|
||||
client = await hass_client_no_auth()
|
||||
|
||||
await call_webhook(
|
||||
hass,
|
||||
load_json_object_fixture("webhook_request_automatically_approved.json", DOMAIN),
|
||||
client,
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert hass.states.get("sensor.overseerr_available_requests").state == "7"
|
||||
|
|
Loading…
Reference in New Issue