Fix, improve input validation and add tests to ClickSend tts (#76669)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
d03e0380bb
commit
107e1ed16c
3 changed files with 136 additions and 9 deletions
|
@ -9,6 +9,7 @@ import voluptuous as vol
|
|||
from homeassistant.components.notify import PLATFORM_SCHEMA, BaseNotificationService
|
||||
from homeassistant.const import (
|
||||
CONF_API_KEY,
|
||||
CONF_NAME,
|
||||
CONF_RECIPIENT,
|
||||
CONF_USERNAME,
|
||||
CONTENT_TYPE_JSON,
|
||||
|
@ -23,20 +24,27 @@ HEADERS = {"Content-Type": CONTENT_TYPE_JSON}
|
|||
|
||||
CONF_LANGUAGE = "language"
|
||||
CONF_VOICE = "voice"
|
||||
CONF_CALLER = "caller"
|
||||
|
||||
MALE_VOICE = "male"
|
||||
FEMALE_VOICE = "female"
|
||||
|
||||
DEFAULT_NAME = "clicksend_tts"
|
||||
DEFAULT_LANGUAGE = "en-us"
|
||||
DEFAULT_VOICE = "female"
|
||||
DEFAULT_VOICE = FEMALE_VOICE
|
||||
TIMEOUT = 5
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_API_KEY): cv.string,
|
||||
vol.Required(CONF_RECIPIENT): cv.string,
|
||||
vol.Required(CONF_RECIPIENT): vol.All(
|
||||
cv.string, vol.Match(r"^\+?[1-9]\d{1,14}$")
|
||||
),
|
||||
vol.Optional(CONF_LANGUAGE, default=DEFAULT_LANGUAGE): cv.string,
|
||||
vol.Optional(CONF_VOICE, default=DEFAULT_VOICE): cv.string,
|
||||
vol.Optional(CONF_CALLER): cv.string,
|
||||
vol.Optional(CONF_VOICE, default=DEFAULT_VOICE): vol.In(
|
||||
[MALE_VOICE, FEMALE_VOICE]
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -60,9 +68,6 @@ class ClicksendNotificationService(BaseNotificationService):
|
|||
self.recipient = config[CONF_RECIPIENT]
|
||||
self.language = config[CONF_LANGUAGE]
|
||||
self.voice = config[CONF_VOICE]
|
||||
self.caller = config.get(CONF_CALLER)
|
||||
if self.caller is None:
|
||||
self.caller = self.recipient
|
||||
|
||||
def send_message(self, message="", **kwargs):
|
||||
"""Send a voice call to a user."""
|
||||
|
@ -70,7 +75,6 @@ class ClicksendNotificationService(BaseNotificationService):
|
|||
"messages": [
|
||||
{
|
||||
"source": "hass.notify",
|
||||
"from": self.caller,
|
||||
"to": self.recipient,
|
||||
"body": message,
|
||||
"lang": self.language,
|
||||
|
|
1
tests/components/clicksend_tts/__init__.py
Normal file
1
tests/components/clicksend_tts/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
"""Tests for the ClickSend TTS component."""
|
122
tests/components/clicksend_tts/test_notify.py
Normal file
122
tests/components/clicksend_tts/test_notify.py
Normal file
|
@ -0,0 +1,122 @@
|
|||
"""The test for the Facebook notify module."""
|
||||
import base64
|
||||
from http import HTTPStatus
|
||||
import logging
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
import requests_mock
|
||||
|
||||
from homeassistant.components import notify
|
||||
import homeassistant.components.clicksend_tts.notify as cs_tts
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import assert_setup_component
|
||||
|
||||
# Infos from https://developers.clicksend.com/docs/rest/v3/#testing
|
||||
TEST_USERNAME = "nocredit"
|
||||
TEST_API_KEY = "D83DED51-9E35-4D42-9BB9-0E34B7CA85AE"
|
||||
TEST_VOICE_NUMBER = "+61411111111"
|
||||
|
||||
TEST_VOICE = "male"
|
||||
TEST_LANGUAGE = "fr-fr"
|
||||
TEST_MESSAGE = "Just a test message!"
|
||||
|
||||
|
||||
CONFIG = {
|
||||
notify.DOMAIN: {
|
||||
"platform": "clicksend_tts",
|
||||
cs_tts.CONF_USERNAME: TEST_USERNAME,
|
||||
cs_tts.CONF_API_KEY: TEST_API_KEY,
|
||||
cs_tts.CONF_RECIPIENT: TEST_VOICE_NUMBER,
|
||||
cs_tts.CONF_LANGUAGE: TEST_LANGUAGE,
|
||||
cs_tts.CONF_VOICE: TEST_VOICE,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_clicksend_tts_notify():
|
||||
"""Mock Clicksend TTS notify service."""
|
||||
with patch(
|
||||
"homeassistant.components.clicksend_tts.notify.get_service", autospec=True
|
||||
) as ns:
|
||||
yield ns
|
||||
|
||||
|
||||
async def setup_notify(hass):
|
||||
"""Test setup."""
|
||||
with assert_setup_component(1, notify.DOMAIN) as config:
|
||||
assert await async_setup_component(hass, notify.DOMAIN, CONFIG)
|
||||
assert config[notify.DOMAIN]
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def test_no_notify_service(hass, mock_clicksend_tts_notify, caplog):
|
||||
"""Test missing platform notify service instance."""
|
||||
caplog.set_level(logging.ERROR)
|
||||
mock_clicksend_tts_notify.return_value = None
|
||||
await setup_notify(hass)
|
||||
await hass.async_block_till_done()
|
||||
assert mock_clicksend_tts_notify.called
|
||||
assert "Failed to initialize notification service clicksend_tts" in caplog.text
|
||||
|
||||
|
||||
async def test_send_simple_message(hass):
|
||||
"""Test sending a simple message with success."""
|
||||
|
||||
with requests_mock.Mocker() as mock:
|
||||
# Mocking authentication endpoint
|
||||
mock.get(
|
||||
f"{cs_tts.BASE_API_URL}/account",
|
||||
status_code=HTTPStatus.OK,
|
||||
)
|
||||
|
||||
# Mocking TTS endpoint
|
||||
mock.post(
|
||||
f"{cs_tts.BASE_API_URL}/voice/send",
|
||||
status_code=HTTPStatus.OK,
|
||||
)
|
||||
|
||||
# Setting up integration
|
||||
await setup_notify(hass)
|
||||
|
||||
# Sending message
|
||||
data = {
|
||||
notify.ATTR_MESSAGE: TEST_MESSAGE,
|
||||
}
|
||||
await hass.services.async_call(
|
||||
notify.DOMAIN, cs_tts.DEFAULT_NAME, data, blocking=True
|
||||
)
|
||||
|
||||
# Checking if everything went well
|
||||
assert mock.called
|
||||
assert mock.call_count == 2
|
||||
|
||||
expected_body = {
|
||||
"messages": [
|
||||
{
|
||||
"source": "hass.notify",
|
||||
"to": TEST_VOICE_NUMBER,
|
||||
"body": TEST_MESSAGE,
|
||||
"lang": TEST_LANGUAGE,
|
||||
"voice": TEST_VOICE,
|
||||
}
|
||||
]
|
||||
}
|
||||
assert mock.last_request.json() == expected_body
|
||||
|
||||
expected_content_type = "application/json"
|
||||
assert (
|
||||
"Content-Type" in mock.last_request.headers.keys()
|
||||
and mock.last_request.headers["Content-Type"] == expected_content_type
|
||||
)
|
||||
|
||||
encoded_auth = base64.b64encode(
|
||||
f"{TEST_USERNAME}:{TEST_API_KEY}".encode()
|
||||
).decode()
|
||||
expected_auth = f"Basic {encoded_auth}"
|
||||
assert (
|
||||
"Authorization" in mock.last_request.headers
|
||||
and mock.last_request.headers["Authorization"] == expected_auth
|
||||
)
|
Loading…
Add table
Reference in a new issue