test(email): контактный адрес, Reply-To и тестовая отправка письма
Покрытие валидации/сохранения contact_email, простановки Reply-To в письмах регистрации/приглашений/саммари при включённом и выключенном контактном адресе, и эндпоинта тестовой отправки (успех, дефолтный получатель, сбой транспорта без утечки логина/пароля).
This commit is contained in:
@@ -19,6 +19,7 @@ from celery.exceptions import MaxRetriesExceededError
|
||||
from sqlalchemy import text
|
||||
|
||||
from core.db import engine
|
||||
from core.plugins.config import ChatConfig, InstanceConfig, SummarizerConfig, TranscriberConfig
|
||||
from services.conference_ids import generate_number, generate_slug
|
||||
from services.email import EmailAttachment, EmailSendError
|
||||
from workers.tasks import invitations as invitations_module
|
||||
@@ -65,10 +66,13 @@ class _FakeEmailBackend:
|
||||
body: str,
|
||||
html_body: str | None = None,
|
||||
attachments: tuple[EmailAttachment, ...] = (),
|
||||
reply_to: str | None = None,
|
||||
) -> None:
|
||||
if to in self._fail_for:
|
||||
raise EmailSendError(f"сбой отправки {to}", retryable=self._retryable)
|
||||
self.sent.append({"to": to, "subject": subject, "attachments": attachments})
|
||||
self.sent.append(
|
||||
{"to": to, "subject": subject, "attachments": attachments, "reply_to": reply_to}
|
||||
)
|
||||
|
||||
|
||||
class _Fixture:
|
||||
@@ -364,6 +368,48 @@ async def test_pinned_conference_sends_to_owner_and_past_participants_with_email
|
||||
assert delivered == sent_to
|
||||
|
||||
|
||||
def _cfg(
|
||||
*, contact_email_enabled: bool = False, contact_email: str | None = None
|
||||
) -> InstanceConfig:
|
||||
return InstanceConfig(
|
||||
transcriber=TranscriberConfig(),
|
||||
summarizer=SummarizerConfig(),
|
||||
chat=ChatConfig(),
|
||||
contact_email_enabled=contact_email_enabled,
|
||||
contact_email=contact_email,
|
||||
)
|
||||
|
||||
|
||||
async def test_invitations_set_reply_to_when_contact_email_enabled(
|
||||
fx: _Fixture, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""Включённый контактный адрес инстанса — приглашение несёт `Reply-To`."""
|
||||
mock_backend = _FakeEmailBackend()
|
||||
monkeypatch.setattr(invitations_module, "create_email_backend", lambda settings: mock_backend)
|
||||
|
||||
await send_invitations_async(
|
||||
_FakeTask(),
|
||||
fx.conference_id,
|
||||
plugins_config=_cfg(contact_email_enabled=True, contact_email="contact@vidconf.example"),
|
||||
)
|
||||
|
||||
assert mock_backend.sent
|
||||
assert all(call["reply_to"] == "contact@vidconf.example" for call in mock_backend.sent)
|
||||
|
||||
|
||||
async def test_invitations_no_reply_to_when_contact_email_disabled(
|
||||
fx: _Fixture, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
"""Контактный адрес выключен (дефолт) — `Reply-To` не проставляется."""
|
||||
mock_backend = _FakeEmailBackend()
|
||||
monkeypatch.setattr(invitations_module, "create_email_backend", lambda settings: mock_backend)
|
||||
|
||||
await send_invitations_async(_FakeTask(), fx.conference_id, plugins_config=_cfg())
|
||||
|
||||
assert mock_backend.sent
|
||||
assert all(call["reply_to"] is None for call in mock_backend.sent)
|
||||
|
||||
|
||||
async def test_explicit_emails_override_default_recipients(
|
||||
fx: _Fixture, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user