[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:
+106
-59
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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({})
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user