from pathlib import Path from pve_backup_report.config import EmailConfig from pve_backup_report.email_report import ( build_report_message, EmailReportError, message_id_domain, send_report_email, send_test_email, ) def test_build_report_message_attaches_pdf(tmp_path: Path) -> None: pdf_path = tmp_path / "rapport.pdf" pdf_path.write_bytes(b"%PDF-1.7") config = EmailConfig( enabled=True, smtp_host="smtp.example.invalid", smtp_from="report@example.invalid", smtp_to=("admin@example.invalid",), subject="Rapport PVE", ) message = build_report_message(config, pdf_path) assert message["Subject"] == "Rapport PVE" assert message["From"] == "report@example.invalid" assert message["To"] == "admin@example.invalid" assert message["Date"] assert message["Message-ID"].endswith("@example.invalid>") assert message["Auto-Submitted"] == "auto-generated" attachments = list(message.iter_attachments()) assert len(attachments) == 1 assert attachments[0].get_filename() == "rapport.pdf" assert attachments[0].get_content_type() == "application/pdf" assert attachments[0].get_payload(decode=True) == b"%PDF-1.7" def test_message_id_domain_uses_sender_domain() -> None: assert message_id_domain("PVE Report ") == "example.invalid" assert message_id_domain("pve@example.invalid") == "example.invalid" assert message_id_domain("invalid") is None assert message_id_domain(None) is None def test_send_test_email_builds_message_without_attachment(monkeypatch) -> None: sent = [] config = EmailConfig( enabled=True, smtp_host="smtp.example.invalid", smtp_from="report@example.invalid", smtp_to=("admin@example.invalid",), subject="Rapport PVE", ) monkeypatch.setattr( "pve_backup_report.email_report.send_email_message", lambda email_config, message: sent.append((email_config, message)), ) send_test_email(config) assert sent[0][0] == config message = sent[0][1] assert message["Subject"] == "[TEST] Rapport PVE" assert message["To"] == "admin@example.invalid" assert list(message.iter_attachments()) == [] def test_send_test_email_requires_enabled_config() -> None: config = EmailConfig( enabled=False, smtp_host="smtp.example.invalid", smtp_from="report@example.invalid", smtp_to=("admin@example.invalid",), ) try: send_test_email(config) except EmailReportError as exc: assert "REPORT_EMAIL_ENABLED=false" in str(exc) else: raise AssertionError("EmailReportError attendu") def test_send_report_email_uses_starttls_and_auth(tmp_path: Path, monkeypatch) -> None: pdf_path = tmp_path / "rapport.pdf" pdf_path.write_bytes(b"%PDF-1.7") calls = [] class FakeSmtp: def __init__(self, host: str, port: int, timeout: int) -> None: calls.append(("connect", host, port, timeout)) def __enter__(self): return self def __exit__(self, exc_type, exc, traceback) -> None: calls.append(("close",)) def starttls(self) -> None: calls.append(("starttls",)) def login(self, username: str, password: str) -> None: calls.append(("login", username, password)) def send_message(self, message) -> None: calls.append(("send", message["To"])) monkeypatch.setattr("pve_backup_report.email_report.smtplib.SMTP", FakeSmtp) config = EmailConfig( enabled=True, smtp_host="smtp.example.invalid", smtp_port=587, smtp_username="report@example.invalid", smtp_password="secret", smtp_from="report@example.invalid", smtp_to=("admin@example.invalid",), smtp_starttls=True, smtp_timeout_seconds=12, ) send_report_email(config, pdf_path) assert calls == [ ("connect", "smtp.example.invalid", 587, 12), ("starttls",), ("login", "report@example.invalid", "secret"), ("send", "admin@example.invalid"), ("close",), ]