[IMP] base, mail_*: use MockSmtplibCase and improve tests tooling

mail_* = mail, test_mail, test_mail_full, test_mass_mailing

PURPOSE

Improve tooling of mail tests. Use SMTP mockup class available in base tests
in mail tests to have a better and simplified mock tool when dealing with
mail tests. Remove old fashioned code.

SPECIFICATIONS

Include ``MockSmtplibCase`` directly into ``MockEmail`` so that we re-use
existing components for mocking outgoing emails. Also make parameters for
gateway coherent between those two classes (use same test values).

Remove 'sim_error' weird parameter of Mail ``mock_mail_gateway`` and use
standard mock 'side_effect' instead in some specific tests, notably on
SMTP.connect() mock.

Add some assert / tools method and improve existing tools, used for creating
or improving test data. This will be used in future commits when adding new
tests.

Add outgoing mail servers data in mail tests, allowing to make tests closer
to real life use cases.

Remove unnecessary calls to ``_init_mail_gateway`` as it is automatically
done in ``MailCommon.setUpClass()``.

Try to consolidate starting test data, notably with countries, phone numbers
or email in mind to be sure test mail are deterministic.

Task-2673913 (TestMail: Cleanup and improve test coverage)

Part-of: odoo/odoo#86393
This commit is contained in:
Thibault Delavallée
2022-03-24 13:57:35 +01:00
parent c2fd9a4965
commit 6d166d6088
17 changed files with 174 additions and 133 deletions
+106 -59
View File
@@ -11,10 +11,9 @@ from contextlib import contextmanager
from functools import partial
from lxml import html
from unittest.mock import patch
from smtplib import SMTPServerDisconnected
from odoo import exceptions
from odoo.addons.base.models.ir_mail_server import IrMailServer, MailDeliveryException
from odoo.addons.base.models.ir_mail_server import IrMailServer
from odoo.addons.base.tests.common import MockSmtplibCase
from odoo.addons.bus.models.bus import ImBus, json_dump
from odoo.addons.mail.models.mail_mail import MailMail
from odoo.addons.mail.models.mail_message import Message
@@ -22,10 +21,14 @@ from odoo.addons.mail.models.mail_notification import MailNotification
from odoo.tests import common, new_test_user
from odoo.tools import formataddr, pycompat
mail_new_test_user = partial(new_test_user, context={'mail_create_nolog': True, 'mail_create_nosubscribe': True, 'mail_notrack': True, 'no_reset_password': True})
mail_new_test_user = partial(new_test_user, context={'mail_create_nolog': True,
'mail_create_nosubscribe': True,
'mail_notrack': True,
'no_reset_password': True,
'mail_channel_nosubscribe': True})
class MockEmail(common.BaseCase):
class MockEmail(common.BaseCase, MockSmtplibCase):
""" Tools, helpers and asserts for mailgateway-related tests
Useful reminders
@@ -39,37 +42,19 @@ class MockEmail(common.BaseCase):
# ------------------------------------------------------------
@contextmanager
def mock_mail_gateway(self, mail_unlink_sent=False, sim_error=None):
def mock_mail_gateway(self, mail_unlink_sent=False):
build_email_origin = IrMailServer.build_email
send_email_origin = IrMailServer.send_email
mail_create_origin = MailMail.create
mail_unlink_origin = MailMail.unlink
self.mail_unlink_sent = mail_unlink_sent
self._init_mail_mock()
def _ir_mail_server_connect(model, *args, **kwargs):
if sim_error and sim_error == 'connect_smtp_notfound':
raise exceptions.UserError(
"Missing SMTP Server\nPlease define at least one SMTP server, or provide the SMTP parameters explicitly.")
if sim_error and sim_error == 'connect_failure':
raise Exception("Some exception")
return None
def _ir_mail_server_build_email(model, *args, **kwargs):
self._mails.append(kwargs)
self._mails_args.append(args)
return build_email_origin(model, *args, **kwargs)
def _ir_mail_server_send_email(model, message, *args, **kwargs):
if '@' not in message['To']:
raise AssertionError(model.NO_VALID_RECIPIENT)
if sim_error and sim_error == 'send_assert':
raise AssertionError('AssertionError')
elif sim_error and sim_error == 'send_disconnect':
raise SMTPServerDisconnected('SMTPServerDisconnected')
elif sim_error and sim_error == 'send_delivery':
raise MailDeliveryException('MailDeliveryException')
return message['Message-Id']
def _mail_mail_create(model, *args, **kwargs):
res = mail_create_origin(model, *args, **kwargs)
self._new_mails += res.sudo()
@@ -80,11 +65,13 @@ class MockEmail(common.BaseCase):
return mail_unlink_origin(model, *args, **kwargs)
return True
with patch.object(IrMailServer, 'connect', autospec=True, wraps=IrMailServer, side_effect=_ir_mail_server_connect) as ir_mail_server_connect_mock, \
patch.object(IrMailServer, 'build_email', autospec=True, wraps=IrMailServer, side_effect=_ir_mail_server_build_email) as ir_mail_server_build_email_mock, \
patch.object(IrMailServer, 'send_email', autospec=True, wraps=IrMailServer, side_effect=_ir_mail_server_send_email) as ir_mail_server_send_email_mock, \
patch.object(MailMail, 'create', autospec=True, wraps=MailMail, side_effect=_mail_mail_create) as _mail_mail_create_mock, \
patch.object(MailMail, 'unlink', autospec=True, wraps=MailMail, side_effect=_mail_mail_unlink) as mail_mail_unlink_mock:
with self.mock_smtplib_connection(), \
patch.object(IrMailServer, 'build_email', autospec=True, wraps=IrMailServer, side_effect=_ir_mail_server_build_email) as build_email_mocked, \
patch.object(IrMailServer, 'send_email', autospec=True, wraps=IrMailServer, side_effect=send_email_origin) as send_email_mocked, \
patch.object(MailMail, 'create', autospec=True, wraps=MailMail, side_effect=_mail_mail_create), \
patch.object(MailMail, 'unlink', autospec=True, wraps=MailMail, side_effect=_mail_mail_unlink):
self.build_email_mocked = build_email_mocked
self.send_email_mocked = send_email_mocked
yield
def _init_mail_mock(self):
@@ -92,10 +79,6 @@ class MockEmail(common.BaseCase):
self._mails_args = []
self._new_mails = self.env['mail.mail'].sudo()
# ------------------------------------------------------------
# GATEWAY TOOLS
# ------------------------------------------------------------
@classmethod
def _init_mail_gateway(cls):
cls.alias_domain = 'test.com'
@@ -108,6 +91,26 @@ class MockEmail(common.BaseCase):
cls.env['ir.config_parameter'].set_param('mail.default.from', cls.default_from)
cls.mailer_daemon_email = formataddr(('MAILER-DAEMON', '%s@%s' % (cls.alias_bounce, cls.alias_domain)))
@classmethod
def _init_outgoing_gateway(cls):
cls.env['ir.mail_server'].search([]).unlink()
cls.mail_server_domain, cls.mail_server_global = cls.env['ir.mail_server'].create([
{'from_filter': 'test.com',
'name': 'Domain Based Server',
'smtp_encryption': 'none',
'smtp_host': 'smtp_host',
},
{'from_filter': False,
'name': 'No FromFilter Server',
'smtp_encryption': 'none',
'smtp_host': 'smtp_host',
}
])
# ------------------------------------------------------------
# GATEWAY TOOLS
# ------------------------------------------------------------
def format(self, template, to='groups@example.com, other@gmail.com', subject='Frogs',
email_from='Sylvie Lelitre <test.sylvie.lelitre@agrolait.com>', return_path='', cc='',
extra='', msg_id='<1198923581.41972151344608186760.JavaMail@agrolait.com>',
@@ -316,7 +319,7 @@ class MockEmail(common.BaseCase):
# ------------------------------------------------------------
def assertMailMail(self, recipients, status,
check_mail_mail=True, mail_message=None, author=None,
mail_message=None, author=None,
content=None, fields_values=None, email_values=None):
""" Assert mail.mail records are created and maybe sent as emails. Allow
asserting their content. Records to check are the one generated when
@@ -335,8 +338,6 @@ class MockEmail(common.BaseCase):
:param email_values: if given, should be a dictionary of keys / values
allowing to check sent email additional values (if any).
See ``assertSentEmail``;
:param check_mail_mail: deprecated, use ``assertSentEmail`` if False
"""
found_mail = self._find_mail_mail_wpartners(recipients, status, mail_message=mail_message, author=author)
self.assertTrue(bool(found_mail))
@@ -370,8 +371,6 @@ class MockEmail(common.BaseCase):
:param email_values: if given, should be a dictionary of keys / values
allowing to check sent email additional values (if any).
See ``assertSentEmail``;
:param check_mail_mail: deprecated, use ``assertSentEmail`` if False
"""
for email_to in emails:
found_mail = self._find_mail_mail_wemail(email_to, status, mail_message=mail_message, author=author)
@@ -410,6 +409,16 @@ class MockEmail(common.BaseCase):
found_mail[fname], fvalue,
'Mail: expected %s for %s, got %s' % (fvalue, fname, found_mail[fname]))
def assertMessageFields(self, message, fields_values):
""" Just a quick helper to check a mail.message content by giving directly
a dict for fields. Allows to hide a lot of assertEqual under a simple
call with a dictionary of expected values. """
for fname, fvalue in fields_values.items():
self.assertEqual(
message[fname], fvalue,
'Message: expected %s for %s, got %s' % (fvalue, fname, message[fname])
)
def assertNoMail(self, recipients, mail_message=None, author=None):
""" Check no mail.mail and email was generated during gateway mock. """
try:
@@ -435,8 +444,10 @@ class MockEmail(common.BaseCase):
:param values: dictionary of additional values to check email content;
"""
base_expected = {}
for fname in ['reply_to', 'subject', 'attachments', 'body', 'references',
'body_content', 'body_alternative_content', 'references_content']:
for fname in ['author_id', 'reply_to',
'subject', 'body', 'body_content', 'body_alternative_content',
'references', 'references_content',
'attachments']:
if fname in values:
base_expected[fname] = values[fname]
@@ -461,9 +472,14 @@ class MockEmail(common.BaseCase):
debug_info = '-'.join('From: %s-To: %s' % (mail['email_from'], mail['email_to']) for mail in self._mails) if not bool(sent_mail) else ''
self.assertTrue(bool(sent_mail), 'Expected mail from %s to %s not found in %s' % (expected['email_from'], expected['email_to'], debug_info))
for val in ['reply_to', 'subject', 'references', 'attachments']:
for val in ['reply_to', 'subject', 'references']:
if val in expected:
self.assertEqual(expected[val], sent_mail[val], 'Value for %s: expected %s, received %s' % (val, expected[val], sent_mail[val]))
if 'attachments' in expected:
self.assertEqual(
sorted(expected['attachments']), sorted(sent_mail['attachments']),
'Value for %s: expected %s, received %s' % ('attachments', expected['attachments'], sent_mail['attachments'])
)
if 'attachments_info' in values:
attachments = sent_mail['attachments']
for attachment_info in values['attachments_info']:
@@ -473,12 +489,18 @@ class MockEmail(common.BaseCase):
if attachment_info.get('type'):
self.assertEqual(attachment[2], attachment_info['type'])
self.assertEqual(len(values['attachments_info']), len(attachments))
for val in ['body']:
for val in ['body', 'body_alternative']:
if val in expected:
self.assertHtmlEqual(expected[val], sent_mail[val], 'Value for %s: expected %s, received %s' % (val, expected[val], sent_mail[val]))
for val in ['body_content', 'body_alternative', 'references_content']:
self.assertHtmlEqual(
expected[val], sent_mail[val],
'Value for %s: expected %s, received %s' % (val, expected[val], sent_mail[val])
)
for val in ['body_content', 'body_alternative_content', 'references_content']:
if val in expected:
self.assertIn(expected[val], sent_mail[val[:-8]], 'Value for %s: %s does not contain %s' % (val, sent_mail[val[:-8]], expected[val]))
self.assertIn(
expected[val], sent_mail[val[:-8]],
'Value for %s: %s does not contain %s' % (val, sent_mail[val[:-8]], expected[val])
)
class MailCase(MockEmail):
@@ -496,10 +518,11 @@ class MailCase(MockEmail):
("UNKNOWN", "Unknown error")
"""
_test_context = {
'mail_channel_nosubscribe': True,
'mail_create_nolog': True,
'mail_create_nosubscribe': True,
'mail_notrack': True,
'no_reset_password': True
'no_reset_password': True,
}
@classmethod
@@ -507,7 +530,7 @@ class MailCase(MockEmail):
return record.with_context(
mail_create_nolog=False,
mail_create_nosubscribe=False,
mail_notrack=False
mail_notrack=False,
)
def flush_tracking(self):
@@ -627,19 +650,19 @@ class MailCase(MockEmail):
# ------------------------------------------------------------
@contextmanager
def assertSinglePostNotifications(self, recipients_info, message_info=None, mail_unlink_sent=False, sim_error=None):
def assertSinglePostNotifications(self, recipients_info, message_info=None, mail_unlink_sent=False):
""" Shortcut to assertMsgNotifications when having a single message to check. """
r_info = dict(message_info if message_info else {})
r_info.setdefault('content', '')
r_info['notif'] = recipients_info
with self.assertPostNotifications([r_info], mail_unlink_sent=mail_unlink_sent, sim_error=sim_error):
with self.assertPostNotifications([r_info], mail_unlink_sent=mail_unlink_sent):
yield
@contextmanager
def assertPostNotifications(self, recipients_info, mail_unlink_sent=False, sim_error=None):
def assertPostNotifications(self, recipients_info, mail_unlink_sent=False):
""" Check content of notifications. """
try:
with self.mock_mail_gateway(mail_unlink_sent=mail_unlink_sent, sim_error=sim_error), self.mock_bus(), self.mock_mail_app():
with self.mock_mail_gateway(mail_unlink_sent=mail_unlink_sent), self.mock_bus(), self.mock_mail_app():
yield
finally:
done_msgs, done_notifs = self.assertMailNotifications(self._new_msgs, recipients_info)
@@ -659,7 +682,7 @@ class MailCase(MockEmail):
@contextmanager
def assertNoNotifications(self):
try:
with self.mock_mail_gateway(mail_unlink_sent=False, sim_error=None), self.mock_bus(), self.mock_mail_app():
with self.mock_mail_gateway(mail_unlink_sent=False), self.mock_bus(), self.mock_mail_app():
yield
finally:
self.assertFalse(bool(self._new_msgs))
@@ -891,9 +914,14 @@ class MailCommon(common.TransactionCase, MailCase):
super(MailCommon, cls).setUpClass()
# give default values for all email aliases and domain
cls._init_mail_gateway()
cls._init_outgoing_gateway()
# ensure admin configuration
cls.user_admin = cls.env.ref('base.user_admin')
cls.user_admin.write({'notification_type': 'inbox'})
cls.user_admin.write({
'country_id': cls.env.ref('base.be').id,
'email': 'test.admin@test.example.com',
'notification_type': 'inbox',
})
cls.partner_admin = cls.env.ref('base.partner_admin')
cls.company_admin = cls.user_admin.company_id
cls.company_admin.write({'email': 'company@example.com'})
@@ -905,9 +933,11 @@ class MailCommon(common.TransactionCase, MailCase):
# test standard employee
cls.user_employee = mail_new_test_user(
cls.env, login='employee',
groups='base.group_user,mail.group_mail_template_editor',
cls.env,
company_id=cls.company_admin.id,
country_id=cls.env.ref('base.be').id,
groups='base.group_user,mail.group_mail_template_editor',
login='employee',
name='Ernest Employee',
notification_type='inbox',
signature='--\nErnest'
@@ -939,12 +969,26 @@ class MailCommon(common.TransactionCase, MailCase):
groups='base.group_user',
company_id=cls.company_2.id,
company_ids=[(4, cls.company_2.id)],
email='enguerrand@example.com',
name='Enguerrand Employee C2',
notification_type='inbox',
signature='--\nEnguerrand'
)
cls.partner_employee_c2 = cls.user_employee_c2.partner_id
# test erp manager employee
cls.user_erp_manager = mail_new_test_user(
cls.env,
company_id=cls.company_2.id,
company_ids=[(6, 0, (cls.company_admin + cls.company_2).ids)],
email='etchenne@example.com',
groups='base.group_user,base.group_erp_manager,mail.group_mail_template_editor',
login='erp_manager',
name='Etchenne Tchagada',
notification_type='inbox',
signature='--\nEtchenne',
)
@classmethod
def _activate_multi_lang(cls, lang_code='es_ES', layout_arch_db=None, test_record=False, test_template=False):
""" Summary of es_ES matching done here (a bit hardcoded to ease tests)
@@ -1097,15 +1141,18 @@ class MailCommon(common.TransactionCase, MailCase):
})
cls.env['ir.translation'].create(translations_tocreate)
def _generate_attachments_data(self, count, res_model=None, res_id=None):
def _generate_attachments_data(self, count, res_model=None, res_id=None, attach_values=None):
# attachment visibility depends on what they are attached to
attach_values = attach_values or {}
if res_model is None:
res_model = self.template._name
if res_id is None:
res_id = self.template.id
return [{
'name': '%02d.txt' % x,
'datas': base64.b64encode(b'Att%02d' % x),
'datas': base64.b64encode(b'AttContent_%02d' % x),
'name': 'AttFileName_%02d.txt' % x,
'mimetype': 'text/plain',
'res_model': res_model,
'res_id': res_id,
**attach_values,
} for x in range(count)]
@@ -1,10 +1,14 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from functools import partial
from odoo.addons.mail.tests.common import mail_new_test_user
from odoo.addons.mail.tests.common import MailCommon
from odoo.exceptions import AccessError, UserError
mail_channel_new_test_user = partial(mail_new_test_user, context={'mail_channel_nosubscribe': False})
class TestMailChannelMembers(MailCommon):
@@ -22,23 +26,23 @@ class TestMailChannelMembers(MailCommon):
'res_id': cls.secret_group.id,
})
cls.user_1 = mail_new_test_user(
cls.user_1 = mail_channel_new_test_user(
cls.env, login='user_1',
name='User 1',
groups='base.group_user,mail.secret_group')
cls.user_2 = mail_new_test_user(
cls.user_2 = mail_channel_new_test_user(
cls.env, login='user_2',
name='User 2',
groups='base.group_user,mail.secret_group')
cls.user_3 = mail_new_test_user(
cls.user_3 = mail_channel_new_test_user(
cls.env, login='user_3',
name='User 3',
groups='base.group_user,mail.secret_group')
cls.user_portal = mail_new_test_user(
cls.user_portal = mail_channel_new_test_user(
cls.env, login='user_portal',
name='User Portal',
groups='base.group_portal')
cls.user_public = mail_new_test_user(
cls.user_public = mail_channel_new_test_user(
cls.env, login='user_ublic',
name='User Public',
groups='base.group_public')
+18 -16
View File
@@ -9,27 +9,29 @@ class TestMailCommon(MailCommon):
""" Main entry point for functional tests. """
@classmethod
def _create_channel_listener(cls):
cls.channel_listen = cls.env['mail.channel'].with_context(cls._test_context).create({'name': 'Listener'})
@classmethod
def _create_records_for_batch(cls, model, count):
# TDE note: to be cleaned in master
def _create_records_for_batch(cls, model, count, additional_values=None):
additional_values = additional_values or {}
records = cls.env[model]
partners = cls.env['res.partner']
country_id = cls.env.ref('base.be').id
partners = cls.env['res.partner'].with_context(**cls._test_context).create([{
'name': 'Partner_%s' % (x),
'email': '_test_partner_%s@example.com' % (x),
'country_id': country_id,
'mobile': '047500%02d%02d' % (x, x)
} for x in range(count)])
base_values = [
{'name': 'Test_%s' % idx,
**additional_values,
} for idx in range(count)
]
records = cls.env[model].with_context(**cls._test_context).create([{
'name': 'Test_%s' % (x),
'customer_id': partners[x].id,
} for x in range(count)])
if 'customer_id' in cls.env[model]:
partners = cls.env['res.partner'].with_context(**cls._test_context).create([{
'name': 'Partner_%s' % idx,
'email': '_test_partner_%s@example.com' % idx,
'country_id': country_id,
'mobile': '047500%02d%02d' % (idx, idx)
} for idx in range(count)])
for values, partner in zip(base_values, partners):
values['customer_id'] = partner.id
records = cls.env[model].with_context(**cls._test_context).create(base_values)
cls.records = cls._reset_mail_context(records)
cls.partners = partners
+5 -6
View File
@@ -18,7 +18,6 @@ class TestMailComposer(TestMailCommon, TestRecipients):
@classmethod
def setUpClass(cls):
super(TestMailComposer, cls).setUpClass()
cls._init_mail_gateway()
# ensure employee can create partners, necessary for templates
cls.user_employee.write({
@@ -609,8 +608,8 @@ class TestComposerResultsComment(TestMailComposer):
'email_from': self.test_record.user_id.email_formatted, # set by template
'subject': 'TemplateSubject %s' % self.test_record.name,
'attachments_info': [
{'name': '00.txt', 'raw': b'Att00', 'type': 'text/plain'},
{'name': '01.txt', 'raw': b'Att01', 'type': 'text/plain'},
{'name': 'AttFileName_00.txt', 'raw': b'AttContent_00', 'type': 'text/plain'},
{'name': 'AttFileName_01.txt', 'raw': b'AttContent_01', 'type': 'text/plain'},
{'name': 'TestReport for %s.html' % self.test_record.name, 'type': 'text/plain'},
]
},
@@ -624,8 +623,8 @@ class TestComposerResultsComment(TestMailComposer):
'email_from': self.test_record.user_id.email_formatted, # set by template
'subject': 'TemplateSubject %s' % self.test_record.name,
'attachments_info': [
{'name': '00.txt', 'raw': b'Att00', 'type': 'text/plain'},
{'name': '01.txt', 'raw': b'Att01', 'type': 'text/plain'},
{'name': 'AttFileName_00.txt', 'raw': b'AttContent_00', 'type': 'text/plain'},
{'name': 'AttFileName_01.txt', 'raw': b'AttContent_01', 'type': 'text/plain'},
{'name': 'TestReport for %s.html' % self.test_record.name, 'type': 'text/plain'},
]
},
@@ -638,7 +637,7 @@ class TestComposerResultsComment(TestMailComposer):
# attachments are copied on message and linked to document
self.assertEqual(
set(message.attachment_ids.mapped('name')),
set(['00.txt', '01.txt', 'TestReport for %s.html' % self.test_record.name])
set(['AttFileName_00.txt', 'AttFileName_01.txt', 'TestReport for %s.html' % self.test_record.name])
)
self.assertEqual(set(message.attachment_ids.mapped('res_model')), set([self.test_record._name]))
self.assertEqual(set(message.attachment_ids.mapped('res_id')), set(self.test_record.ids))
@@ -12,7 +12,6 @@ class TestMailComposerMixin(TestMailCommon, TestRecipients):
@classmethod
def setUpClass(cls):
super(TestMailComposerMixin, cls).setUpClass()
cls._init_mail_gateway()
cls.mail_template = cls.env['mail.template'].create({
'subject': 'Subject for {{ object.name }}',
@@ -14,7 +14,6 @@ class BaseFollowersTest(TestMailCommon):
super(BaseFollowersTest, cls).setUpClass()
cls.test_record = cls.env['mail.test.simple'].with_context(cls._test_context).create({'name': 'Test', 'email_from': 'ignasse@example.com'})
cls._create_portal_user()
cls._create_channel_listener()
# allow employee to update partners
cls.user_employee.write({'groups_id': [(4, cls.env.ref('base.group_partner_manager').id)]})
@@ -247,8 +247,6 @@ class TestMailgateway(TestMailCommon):
'message_id': '<123456-openerp-%s-mail.test.gateway@%s>' % (cls.test_record.id, socket.gethostname()),
})
cls._init_mail_gateway()
# --------------------------------------------------
# Base low-level tests
# --------------------------------------------------
@@ -1277,8 +1275,6 @@ class TestMailThreadCC(TestMailCommon):
'alias_model_id': cls.env['ir.model']._get('mail.test.cc').id,
'alias_contact': 'everyone'})
cls._init_mail_gateway()
@mute_logger('odoo.addons.mail.models.mail_thread')
def test_message_cc_new(self):
record = self.format_and_process(MAIL_TEMPLATE, self.email_from, 'cc_record@test.com',
+2 -3
View File
@@ -5,19 +5,17 @@ import psycopg2
from unittest.mock import call
from odoo import api
from odoo.addons.base.tests.common import MockSmtplibCase
from odoo.addons.test_mail.tests.common import TestMailCommon
from odoo.tests import common, tagged
from odoo.tools import mute_logger
@tagged('mail_mail')
class TestMailMail(TestMailCommon, MockSmtplibCase):
class TestMailMail(TestMailCommon):
@classmethod
def setUpClass(cls):
super(TestMailMail, cls).setUpClass()
cls._init_mail_gateway()
cls._init_mail_servers()
cls.server_domain_2 = cls.env['ir.mail_server'].create({
@@ -133,6 +131,7 @@ class TestMailMail(TestMailCommon, MockSmtplibCase):
self.assert_email_sent_smtp(message_from='user_1@test_2.com', emails_count=5, from_filter=self.server_domain.from_filter)
@tagged('mail_mail')
class TestMailMailRace(common.TransactionCase):
@mute_logger('odoo.addons.mail.models.mail_mail')
@@ -18,7 +18,6 @@ class TestMessageValues(TestMailCommon):
def setUpClass(cls):
super(TestMessageValues, cls).setUpClass()
cls._init_mail_gateway()
cls.alias_record = cls.env['mail.test.container'].with_context(cls._test_context).create({
'name': 'Pigs',
'alias_name': 'pigs',
@@ -47,8 +47,6 @@ class TestMultiCompanySetup(TestMailCommon, TestRecipients):
'message_id': '<123456-openerp-%s-mail.test.gateway@%s>' % (cls.test_record.id, socket.gethostname()),
})
cls._init_mail_gateway()
@users('employee')
def test_notify_reply_to_computation(self):
test_record = self.env['mail.test.gateway'].browse(self.test_record.ids)
@@ -103,6 +103,7 @@ class TestChatterTweaks(TestMailCommon, TestRecipients):
self.assertTrue(record.name)
@tagged('mail_thread')
class TestDiscuss(TestMailCommon, TestRecipients):
@classmethod
@@ -239,7 +240,12 @@ class TestDiscuss(TestMailCommon, TestRecipients):
partner_ids=[self.user_employee.partner_id.id]
)
self.assertFalse(message.has_error)
with self.mock_mail_gateway(sim_error='connect_smtp_notfound'):
with self.mock_mail_gateway():
def _connect(*args, **kwargs):
raise Exception("Some exception")
self.connect_mocked.side_effect = _connect
self.user_admin.notification_type = 'email'
message2 = self.test_record.with_user(self.user_employee).message_post(
body='Test', message_type='comment', subtype_xmlid='mail.mt_comment',
@@ -34,8 +34,10 @@ class TestMailResend(TestMailCommon):
def test_mail_resend_workflow(self):
with self.assertSinglePostNotifications(
[{'partner': partner, 'type': 'email', 'status': 'exception'} for partner in self.partners],
message_info={'message_type': 'notification'},
sim_error='connect_failure'):
message_info={'message_type': 'notification'}):
def _connect(*args, **kwargs):
raise Exception("Some exception")
self.connect_mocked.side_effect = _connect
message = self.test_record.with_user(self.user_admin).message_post(partner_ids=self.partners.ids, subtype_xmlid='mail.mt_comment', message_type='notification')
wizard = self.env['mail.resend.message'].with_context({'mail_message_to_resend': message.id}).create({})
+3 -10
View File
@@ -48,6 +48,7 @@ class BaseMailPerformance(TransactionCaseWithUserDemo):
# patch registry to simulate a ready environment
self.patch(self.env.registry, 'ready', True)
self._flush_tracking()
self._init_mail_gateway()
def _init_mail_gateway(self):
# setup mail gateway
@@ -113,8 +114,6 @@ class TestBaseMailPerformance(BaseMailPerformance):
}
])
self._init_mail_gateway()
@users('__system__', 'demo')
@warmup
def test_read_mail(self):
@@ -223,8 +222,6 @@ class TestMailAPIPerformance(BaseMailPerformance):
'groups_id': [(6, 0, [self.env.ref('base.group_user').id])],
})
self._init_mail_gateway()
# automatically follow activities, for backward compatibility concerning query count
self.env.ref('mail.mt_activities').write({'default': True})
@@ -531,10 +528,8 @@ class TestMailComplexPerformance(BaseMailPerformance):
self.partners |= Partners.create({'name': 'Test %s' % x, 'email': 'test%s@example.com' % x})
self.container.message_subscribe(self.partners.ids, subtype_ids=[
self.env.ref('mail.mt_comment').id,
self.env.ref('test_mail.st_mail_test_container_child_full').id]
)
self._init_mail_gateway()
self.env.ref('test_mail.st_mail_test_container_child_full').id
])
# `test_complex_mail_mail_send`
self.container.flush()
@@ -991,8 +986,6 @@ class TestMailHeavyPerformancePost(BaseMailPerformance):
'res_id': 0,
} for i in range(3)]
self._init_mail_gateway()
@mute_logger('odoo.tests', 'odoo.addons.mail.models.mail_mail', 'odoo.models.unlink')
@users('employee')
@warmup
@@ -29,8 +29,6 @@ class TestSMSPerformance(BaseMailPerformance, sms_common.SMSCase):
} for x in range(0, 10)
])
self._init_mail_gateway()
@mute_logger('odoo.addons.sms.models.sms_sms')
@users('employee')
@warmup
@@ -2,20 +2,17 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mass_mailing.tests.common import TestMassMailCommon
from odoo.addons.base.tests.common import MockSmtplibCase
from odoo.tests import tagged
from odoo.tests.common import users
from odoo.tools import mute_logger
@tagged('mass_mailing')
class TestMassMailingServer(TestMassMailCommon, MockSmtplibCase):
class TestMassMailingServer(TestMassMailCommon):
@classmethod
def setUpClass(cls):
super(TestMassMailingServer, cls).setUpClass()
cls._init_mail_gateway()
cls.env['ir.mail_server'].search([]).unlink()
cls._init_mail_servers()
cls.recipients = cls._create_mailing_test_records(model='mailing.test.optout', count=8)
+14 -12
View File
@@ -252,14 +252,14 @@ class MockSmtplibCase:
self.testing_smtp_session = TestingSMTPSession()
IrMailServer = self.env['ir.mail_server']
connect = IrMailServer.connect
find_mail_server = IrMailServer._find_mail_server
connect_origin = IrMailServer.connect
find_mail_server_origin = IrMailServer._find_mail_server
with patch.object(type(IrMailServer), '_is_test_mode', lambda self: False), \
patch('smtplib.SMTP_SSL', side_effect=lambda *args, **kwargs: self.testing_smtp_session), \
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), 'connect', side_effect=connect) as connect_mocked, \
patch.object(type(IrMailServer), '_find_mail_server', side_effect=find_mail_server) as find_mail_server_mocked:
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
yield
@@ -298,14 +298,16 @@ class MockSmtplibCase:
)
@classmethod
def _init_mail_servers(cls):
cls.env['ir.config_parameter'].sudo().set_param('mail.catchall.domain', 'test.com')
cls.env['ir.config_parameter'].sudo().set_param('mail.default.from', 'notifications')
cls.env['ir.config_parameter'].sudo().set_param('mail.bounce.alias', 'bounce')
cls.alias_bounce = 'bounce'
def _init_mail_config(cls):
cls.alias_bounce = 'bounce.test'
cls.alias_domain = 'test.com'
cls.default_from = 'notifications'
cls.env['ir.config_parameter'].sudo().set_param('mail.catchall.domain', cls.alias_domain)
cls.env['ir.config_parameter'].sudo().set_param('mail.default.from', cls.default_from)
cls.env['ir.config_parameter'].sudo().set_param('mail.bounce.alias', cls.alias_bounce)
@classmethod
def _init_mail_servers(cls):
cls.env['ir.mail_server'].search([]).unlink()
ir_mail_server_values = {
@@ -15,6 +15,7 @@ from odoo.tools import mute_logger
class TestIrMailServer(TransactionCase, MockSmtplibCase):
def setUp(self):
self._init_mail_config()
self._init_mail_servers()
def _build_email(self, mail_from, return_path=None):
@@ -231,7 +232,7 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
self.assertEqual(len(self.emails), 1)
self.assert_email_sent_smtp(
smtp_from='bounce@xn--9caaaaaaa.com',
smtp_from='bounce.test@xn--9caaaaaaa.com',
smtp_to_list=['dest@xn--example--i1a.com'],
message_from='test@=?utf-8?b?w6nDqcOpw6nDqcOpw6k=?=.com',
from_filter=False,
@@ -322,7 +323,7 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
)
@mute_logger('odoo.models.unlink')
@patch.dict("odoo.tools.config.options", {"from_filter": "test.com"})
@patch.dict("odoo.tools.config.options", {"from_filter": "test.com", "smtp_server": "example.com"})
def test_mail_server_binary_arguments_domain(self):
"""Test the configuration provided in the odoo-bin arguments.
@@ -374,7 +375,7 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
)
@mute_logger('odoo.models.unlink')
@patch.dict("odoo.tools.config.options", {"from_filter": "test.com"})
@patch.dict("odoo.tools.config.options", {"from_filter": "test.com", "smtp_server": "example.com"})
def test_mail_server_binary_arguments_domain_smtp_session(self):
"""Test the configuration provided in the odoo-bin arguments.
@@ -417,7 +418,7 @@ class TestIrMailServer(TransactionCase, MockSmtplibCase):
)
@mute_logger('odoo.models.unlink')
@patch.dict('odoo.tools.config.options', {'from_filter': 'test.com'})
@patch.dict('odoo.tools.config.options', {'from_filter': 'test.com', 'smtp_server': 'example.com'})
def test_mail_server_mail_default_from_filter(self):
"""Test that the config parameter "mail.default.from_filter" overwrite the odoo-bin
argument "--from-filter"