193 lines
7.9 KiB
Python
193 lines
7.9 KiB
Python
import pytest
|
|
|
|
from infrasynth.notifications.channels.base import Attachment, BaseChannel
|
|
from infrasynth.notifications.channels.email_sendgrid import SendGridChannel
|
|
from infrasynth.notifications.channels.email_smtp import SMTPChannel
|
|
from infrasynth.notifications.channels.sms_twilio import TwilioSMSChannel
|
|
from infrasynth.notifications.channels.telegram import TelegramChannel
|
|
|
|
|
|
class TestBaseChannel:
|
|
def test_is_abstract(self):
|
|
with pytest.raises(TypeError):
|
|
BaseChannel()
|
|
|
|
def test_attachment_fields(self):
|
|
attachment = Attachment("f.txt", b"data", "text/plain")
|
|
assert attachment.filename == "f.txt"
|
|
assert attachment.content == b"data"
|
|
assert attachment.mime_type == "text/plain"
|
|
assert attachment.cid is None
|
|
assert attachment.inline is False
|
|
|
|
|
|
class TestSMTPChannel:
|
|
def test_from_config_lowercases_keys(self):
|
|
channel = SMTPChannel.from_config({"HOST": "smtp.example.com", "PORT": 2525, "USERNAME": "u"})
|
|
assert channel.host == "smtp.example.com"
|
|
assert channel.port == 2525
|
|
assert channel.username == "u"
|
|
|
|
def test_send_without_host_returns_err(self):
|
|
channel = SMTPChannel()
|
|
result = channel.send("a@b.com", "s", "b")
|
|
assert result.is_err
|
|
assert "SMTP host" in result.error
|
|
|
|
def test_send_success_with_locmem_backend(self, settings):
|
|
settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
|
channel = SMTPChannel.from_config(
|
|
{"host": "smtp.example.com", "backend": "django.core.mail.backends.locmem.EmailBackend"}
|
|
)
|
|
result = channel.send("a@b.com", "Hello", "<b>Hi</b>", is_html=True)
|
|
assert result.is_ok
|
|
|
|
def test_send_success_with_attachment(self, settings):
|
|
settings.EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"
|
|
channel = SMTPChannel.from_config(
|
|
{"host": "smtp.example.com", "backend": "django.core.mail.backends.locmem.EmailBackend"}
|
|
)
|
|
attachment = Attachment("doc.pdf", b"%PDF", "application/pdf")
|
|
result = channel.send("a@b.com", "Hello", "Hi", attachments=[attachment])
|
|
assert result.is_ok
|
|
|
|
def test_health_check(self):
|
|
assert SMTPChannel.from_config({"host": "x"}).health_check() is True
|
|
assert SMTPChannel().health_check() is False
|
|
|
|
|
|
class TestSendGridChannel:
|
|
def test_send_without_key_returns_err(self):
|
|
channel = SendGridChannel()
|
|
result = channel.send("a@b.com", "s", "b")
|
|
assert result.is_err
|
|
assert "API key" in result.error
|
|
|
|
def test_send_success(self):
|
|
channel = SendGridChannel(api_key="sg-key")
|
|
with __import__("unittest").mock.patch(
|
|
"infrasynth.notifications.channels.email_sendgrid.requests.post"
|
|
) as post:
|
|
post.return_value.status_code = 202
|
|
post.return_value.text = "accepted"
|
|
result = channel.send("a@b.com", "Hello", "World")
|
|
assert result.is_ok
|
|
payload = post.call_args.kwargs["json"]
|
|
assert payload["personalizations"][0]["to"][0]["email"] == "a@b.com"
|
|
assert payload["content"][0]["type"] == "text/html"
|
|
assert payload["from"]["email"] == "noreply@example.com"
|
|
|
|
def test_send_http_error_returns_err(self):
|
|
channel = SendGridChannel(api_key="sg-key")
|
|
with __import__("unittest").mock.patch(
|
|
"infrasynth.notifications.channels.email_sendgrid.requests.post"
|
|
) as post:
|
|
post.return_value.status_code = 401
|
|
post.return_value.text = "unauthorized"
|
|
result = channel.send("a@b.com", "Hello", "World")
|
|
assert result.is_err
|
|
assert "401" in result.error
|
|
|
|
def test_send_request_exception_returns_err(self):
|
|
import requests
|
|
|
|
channel = SendGridChannel(api_key="sg-key")
|
|
with __import__("unittest").mock.patch(
|
|
"infrasynth.notifications.channels.email_sendgrid.requests.post",
|
|
side_effect=requests.RequestException("timeout"),
|
|
):
|
|
result = channel.send("a@b.com", "Hello", "World")
|
|
assert result.is_err
|
|
assert "timeout" in result.error
|
|
|
|
def test_health_check(self):
|
|
assert SendGridChannel(api_key="k").health_check() is True
|
|
assert SendGridChannel().health_check() is False
|
|
|
|
|
|
class TestTwilioSMSChannel:
|
|
def test_send_without_credentials_returns_err(self):
|
|
channel = TwilioSMSChannel()
|
|
result = channel.send("+573001234567", "s", "b")
|
|
assert result.is_err
|
|
assert "credentials" in result.error
|
|
|
|
def test_send_success(self):
|
|
channel = TwilioSMSChannel(account_sid="sid", auth_token="token", from_number="+15005550006")
|
|
with __import__("unittest").mock.patch("infrasynth.notifications.channels.sms_twilio.Client") as client_cls:
|
|
client = client_cls.return_value
|
|
result = channel.send("+573001234567", "s", "Hello SMS")
|
|
assert result.is_ok
|
|
client.messages.create.assert_called_once_with(to="+573001234567", from_="+15005550006", body="Hello SMS")
|
|
|
|
def test_send_twilio_error_returns_err(self):
|
|
from twilio.base.exceptions import TwilioRestException
|
|
|
|
channel = TwilioSMSChannel(account_sid="sid", auth_token="token", from_number="+15005550006")
|
|
with __import__("unittest").mock.patch("infrasynth.notifications.channels.sms_twilio.Client") as client_cls:
|
|
client_cls.return_value.messages.create.side_effect = TwilioRestException(
|
|
400, "http://twilio", msg="Invalid number"
|
|
)
|
|
result = channel.send("+573001234567", "s", "Hello")
|
|
assert result.is_err
|
|
assert "400" in result.error
|
|
|
|
def test_health_check(self):
|
|
assert TwilioSMSChannel(account_sid="a", auth_token="b", from_number="c").health_check() is True
|
|
assert TwilioSMSChannel().health_check() is False
|
|
|
|
|
|
class TestTelegramChannel:
|
|
def test_send_without_token_returns_err(self):
|
|
channel = TelegramChannel()
|
|
result = channel.send("12345", "s", "b")
|
|
assert result.is_err
|
|
assert "bot token" in result.error
|
|
|
|
def test_send_without_chat_id_returns_err(self):
|
|
channel = TelegramChannel(bot_token="tok")
|
|
result = channel.send("", "s", "b")
|
|
assert result.is_err
|
|
assert "chat_id" in result.error
|
|
|
|
def test_send_success(self):
|
|
from unittest import mock
|
|
|
|
channel = TelegramChannel(bot_token="tok", chat_id="12345")
|
|
with mock.patch("infrasynth.notifications.channels.telegram.requests.post") as post:
|
|
post.return_value.json.return_value = {"ok": True}
|
|
result = channel.send("", "Subject", "Hello")
|
|
assert result.is_ok
|
|
call_kwargs = post.call_args.kwargs
|
|
assert "bot" not in str(call_kwargs["json"])
|
|
|
|
def test_send_api_error_returns_err(self):
|
|
from unittest import mock
|
|
|
|
channel = TelegramChannel(bot_token="tok", chat_id="12345")
|
|
with mock.patch("infrasynth.notifications.channels.telegram.requests.post") as post:
|
|
post.return_value.json.return_value = {
|
|
"ok": False,
|
|
"description": "chat not found",
|
|
}
|
|
result = channel.send("", "Subject", "Hello")
|
|
assert result.is_err
|
|
assert "chat not found" in result.error
|
|
|
|
def test_send_request_exception_returns_err(self):
|
|
from unittest import mock
|
|
|
|
import requests
|
|
|
|
channel = TelegramChannel(bot_token="tok", chat_id="12345")
|
|
with mock.patch(
|
|
"infrasynth.notifications.channels.telegram.requests.post",
|
|
side_effect=requests.RequestException("network"),
|
|
):
|
|
result = channel.send("", "Subject", "Hello")
|
|
assert result.is_err
|
|
assert "network" in result.error
|
|
|
|
def test_health_check(self):
|
|
assert TelegramChannel(bot_token="k").health_check() is True
|
|
assert TelegramChannel().health_check() is False
|