[FIX] base: fix mock of IrMailServer methods

Due to current implementation of mocks context is lost when accessing methods
'connect' and '_find_mail_server' of IrMailServer. Indeed self is replaced by
an instance of IrMailServer and code relying on context could not be called as
planned.

This commit aims at doing a custom mock so that we can correctly rely on self
and context in those methods. This is necessary for incoming changes in mail
notably to allow testing SMTP feature in multi domains environment.

Logged information when having failed SMTP check is improved: we now also
log found From in order to ease debugging failing tests due to invalid from.

Prepares Task-36879 (Mail: Support Multi Domains Aliases)

Part-of: odoo/odoo#76734
This commit is contained in:
Stephane Debauche
2023-10-24 19:24:50 +00:00
committed by Thibault Delavallée
parent 93f378ea4f
commit 503508fb8e
+28 -11
View File
@@ -4,7 +4,7 @@
import threading
from contextlib import contextmanager
from unittest.mock import patch
from unittest.mock import patch, Mock
from odoo.tests.common import TransactionCase, HttpCase
from odoo import Command
@@ -326,16 +326,27 @@ class MockSmtplibCase:
self.testing_smtp_session = TestingSMTPSession()
IrMailServer = self.env['ir.mail_server']
connect_origin = IrMailServer.connect
find_mail_server_origin = IrMailServer._find_mail_server
connect_origin = type(IrMailServer).connect
find_mail_server_origin = type(IrMailServer)._find_mail_server
# custom mock to avoid losing context
def mock_function(func):
mock = Mock()
def _call(*args, **kwargs):
mock(*args[1:], **kwargs)
return func(*args, **kwargs)
_call.mock = mock
return _call
with patch('smtplib.SMTP_SSL', side_effect=lambda *args, **kwargs: self.testing_smtp_session), \
patch('smtplib.SMTP', side_effect=lambda *args, **kwargs: self.testing_smtp_session), \
patch.object(type(IrMailServer), '_is_test_mode', lambda self: False), \
patch.object(type(IrMailServer), 'connect', wraps=IrMailServer, side_effect=connect_origin) as connect_mocked, \
patch.object(type(IrMailServer), '_find_mail_server', side_effect=find_mail_server_origin) as find_mail_server_mocked:
self.connect_mocked = connect_mocked
self.find_mail_server_mocked = find_mail_server_mocked
patch.object(type(IrMailServer), 'connect', mock_function(connect_origin)) as connect_mocked, \
patch.object(type(IrMailServer), '_find_mail_server', mock_function(find_mail_server_origin)) as find_mail_server_mocked:
self.connect_mocked = connect_mocked.mock
self.find_mail_server_mocked = find_mail_server_mocked.mock
yield
def _build_email(self, mail_from, return_path=None, **kwargs):
@@ -385,15 +396,21 @@ class MockSmtplibCase:
debug_info = ''
matching_emails_count = len(list(matching_emails))
if matching_emails_count != emails_count:
emails_from = []
for email in self.emails:
from_found = next((
line.split('From:')[1].strip() for line in email['message'].splitlines()
if line.startswith('From:')), '')
emails_from.append(from_found)
debug_info = '\n'.join(
f"SMTP-From: {email['smtp_from']}, SMTP-To: ({email['smtp_to_list']}) - From_filter {email['from_filter']})"
for email in self.emails
f"SMTP-From: {email['smtp_from']}, SMTP-To: {email['smtp_to_list']}, Msg-From: {email_msg_from}, From_filter: {email['from_filter']})"
for email, email_msg_from in zip(self.emails, emails_from)
)
self.assertEqual(
matching_emails_count, emails_count,
msg=f'Incorrect emails sent: {matching_emails_count} found, {emails_count} expected'
f'\nConditions: SMTP-From {smtp_from}, SMTP-To {smtp_to_list}, Msg-From {message_from}, From_filter {from_filter}'
f'\n{debug_info}'
f'\nConditions\nSMTP-From: {smtp_from}, SMTP-To: {smtp_to_list}, Msg-From: {message_from}, From_filter: {from_filter}'
f'\nNot found in\n{debug_info}'
)
@classmethod