test(notifier): ✅ add tests for notifier module
This commit is contained in:
+23
-15
@@ -4,7 +4,7 @@ from pathlib import Path
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
from exchangelib import Message
|
||||
from exchangelib import Account, Message
|
||||
|
||||
from logwatcher.config import FIXTURE_PATH
|
||||
from logwatcher.logging_config import setup_logging
|
||||
@@ -23,7 +23,8 @@ os.environ["PYTEST_DEBUG_TEMPROOT"] = str(Path("output/test").absolute())
|
||||
|
||||
@pytest.fixture
|
||||
def tmp_log_file(tmp_path):
|
||||
return tmp_path / "logwatcher_test.log"
|
||||
"""Return path of logs logwatcher related."""
|
||||
return tmp_path / "logwatcher_test.log"
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def tmp_setup_logging(tmp_log_file):
|
||||
@@ -32,39 +33,46 @@ def tmp_setup_logging(tmp_log_file):
|
||||
|
||||
@pytest.fixture(name="original_log_dir")
|
||||
def original_log_dir_fixture() -> Path:
|
||||
"""
|
||||
All real log files provided by N2 technicians.
|
||||
Used for integration tests: these files contain both valid lines
|
||||
and lines to be ignored (system logs, empty lines, directory headers).
|
||||
"""Return log directory containing real logs.
|
||||
|
||||
All real log files provided by N2 technicians.
|
||||
Used for integration tests: these files contain both valid lines
|
||||
and lines to be ignored (system logs, empty lines, directory headers).
|
||||
"""
|
||||
return FIXTURE_PATH / "original_logs"
|
||||
|
||||
@pytest.fixture(name="valid_log_dir")
|
||||
def valid_log_dir_fixture() -> Path:
|
||||
"""
|
||||
All valid log files provided by N2 technicians.
|
||||
Used for integration tests: these files contain both relevant and irrelevant logs
|
||||
for N2 technicians.
|
||||
"""Return log directory containing only valid logs.
|
||||
|
||||
All valid log files provided by N2 technicians.
|
||||
Used for integration tests: these files contain both relevant and irrelevant logs
|
||||
for N2 technicians.
|
||||
"""
|
||||
return FIXTURE_PATH / "valid_logs"
|
||||
|
||||
@pytest.fixture(name="invalid_log_dir")
|
||||
def invalid_log_dir_fixture() -> Path:
|
||||
"""
|
||||
All invalid log files created for testing only.
|
||||
Used for integration tests of parsing.
|
||||
"""Return log directory containing invalid logs.
|
||||
|
||||
All invalid log files created for testing only.
|
||||
Used for integration tests of parsing.
|
||||
"""
|
||||
return FIXTURE_PATH / "invalid_logs"
|
||||
|
||||
|
||||
@pytest.fixture(scope="package")
|
||||
def make_mock_account():
|
||||
"""A fake Account with a msg_folder_root returning a fake Logs folder."""
|
||||
"""Create a fake Account.
|
||||
|
||||
A fake Account with a msg_folder_root returning a fake Logs folder.
|
||||
"""
|
||||
|
||||
def _make_mock_account(
|
||||
messages: list[Message] | None = None, analyzed_folder: MagicMock | None = None
|
||||
):
|
||||
account = MagicMock()
|
||||
account = MagicMock(spec=Account)
|
||||
account.fullname = "fake"
|
||||
logs_folder = account.msg_folder_root.__truediv__.return_value
|
||||
logs_folder.all.return_value = messages or []
|
||||
logs_folder.glob.return_value = [analyzed_folder] if analyzed_folder else []
|
||||
|
||||
@@ -24,13 +24,13 @@ from logwatcher.mail_reader import (
|
||||
|
||||
@pytest.fixture(name="empty_mail")
|
||||
def get_empty_mail_fixture() -> Message:
|
||||
"""A fake Message"""
|
||||
"""Return a fake Message."""
|
||||
return Message(subject="test without attachment", text_body="test")
|
||||
|
||||
|
||||
@pytest.fixture(name="log_mail_with_attachment")
|
||||
def get_log_mail_with_attachment(original_log_dir: Path) -> Message:
|
||||
"""A fake Message with a .txt file attachment."""
|
||||
"""Return a fake Message with a .txt file attachment."""
|
||||
file = original_log_dir / "CR_20260727110008.txt"
|
||||
|
||||
return Message(
|
||||
@@ -49,7 +49,7 @@ def get_log_mail_with_attachment(original_log_dir: Path) -> Message:
|
||||
|
||||
@pytest.fixture(name="log_mail_with_body")
|
||||
def get_log_mail_with_body() -> Message:
|
||||
"""A fake Message with logs in text body."""
|
||||
"""Return a fake Message with logs in text body."""
|
||||
return Message(
|
||||
subject="test with logs in text body",
|
||||
text_body="Compte-rendu du suivi des imports NOSYMAG du 02/09/2026 à 15:00:10\n\n\n"
|
||||
@@ -88,14 +88,14 @@ class FakeProtocol:
|
||||
"""Protocol whose .version access raises UnauthorizedError."""
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
def version(self): # noqa: D102
|
||||
raise UnauthorizedError("invalid credentials")
|
||||
|
||||
|
||||
class FakeAccount:
|
||||
"""Account with a protocol that raises on version access."""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self): # noqa: D107
|
||||
self.protocol = FakeProtocol()
|
||||
|
||||
|
||||
@@ -103,14 +103,14 @@ class OkProtocol:
|
||||
"""Protocol whose .version succeeds."""
|
||||
|
||||
@property
|
||||
def version(self):
|
||||
def version(self): # noqa: D102
|
||||
return MagicMock()
|
||||
|
||||
|
||||
class OkAccount:
|
||||
"""Account with a protocol that returns a version successfully."""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self): # noqa: D102
|
||||
self.protocol = OkProtocol()
|
||||
|
||||
|
||||
@@ -154,10 +154,7 @@ def test_find_log_attachment_accepts_no_extension(empty_mail: Message):
|
||||
def test_find_log_attachment_rejects_other_names(
|
||||
empty_mail: Message,
|
||||
):
|
||||
"""
|
||||
Rejects attachments not starting with CR_ even with .txt
|
||||
or .log extension or extensionless.
|
||||
"""
|
||||
"""Rejects attachments not starting with CR_ even with .txt or .log extension or extensionless."""
|
||||
attachments = (
|
||||
FileAttachment(
|
||||
name="attachment.pdf",
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import os
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from logwatcher.notifier import send_n2_report
|
||||
|
||||
|
||||
def mock_get_or_create_folder(account, folder_name): # noqa: D103
|
||||
return folder_name
|
||||
|
||||
|
||||
@pytest.mark.parametrize("vars", [("N2_REPORT_SUBJECT", "N2_REPORT_RECIPIENTS"), ("N2_REPORT_RECIPIENTS", "N2_REPORT_SUBJECT")])
|
||||
def test_send_n2_report_missing_recipients_env(vars, monkeypatch, ):
|
||||
"""Assert that missing values in environmnent file raises KeyError."""
|
||||
monkeypatch.delenv("N2_REPORT_RECIPIENTS")
|
||||
monkeypatch.delenv("N2_REPORT_SUBJECT")
|
||||
monkeypatch.setenv(vars[0], "test")
|
||||
|
||||
with pytest.raises(KeyError) as err:
|
||||
send_n2_report(account=MagicMock(), summary="summary", n2_log_file=MagicMock())
|
||||
|
||||
assert vars[1] in err.value.args
|
||||
|
||||
|
||||
@pytest.mark.parametrize("recipients", ["mail@client.fr", "mail@ client.fr ", "mail1@client.fr,mail2@client.fr,mail3@client.fr", "mail1@client.fr , mail2@client.fr , mail3@client.fr"])
|
||||
def test_send_n2_report_multiple_recipients(recipients, make_mock_account, monkeypatch):
|
||||
"""Assert gathering multiple account as recipients from env file is valid.
|
||||
|
||||
Tests with value having space characters.
|
||||
Mails must be seperated by a comma.
|
||||
|
||||
Args:
|
||||
recipients: e-mail recipients in one string
|
||||
make_mock_account: return a fake account used for tests
|
||||
monkeypatch: used to change environment variables and functions accross the script
|
||||
|
||||
"""
|
||||
monkeypatch.setenv("N2_REPORT_SUBJECT", "test")
|
||||
monkeypatch.setenv("N2_REPORT_RECIPIENTS", "mail@client.fr")
|
||||
|
||||
with monkeypatch.context() as m:
|
||||
m.setattr("logwatcher.notifier.get_or_create_folder", mock_get_or_create_folder)
|
||||
m.setattr("logwatcher.notifier.Message.send", MagicMock(id="1", return_value=None))
|
||||
send_n2_report(account=make_mock_account(), summary="summary", n2_log_file=MagicMock())
|
||||
Reference in New Issue
Block a user