summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--addons/event/tests/test_event_mail_schedule.py12
-rw-r--r--addons/mail/tests/common.py192
-rw-r--r--addons/mass_mailing/tests/common.py10
-rw-r--r--addons/sms/tests/test_sms_template.py9
-rw-r--r--addons/test_mail/tests/test_mail_channel.py4
-rw-r--r--addons/test_mail/tests/test_mail_composer.py5
-rw-r--r--addons/test_mail/tests/test_message_post.py10
7 files changed, 177 insertions, 65 deletions
diff --git a/addons/event/tests/test_event_mail_schedule.py b/addons/event/tests/test_event_mail_schedule.py
index 896a5873205..5e8e908cb29 100644
--- a/addons/event/tests/test_event_mail_schedule.py
+++ b/addons/event/tests/test_event_mail_schedule.py
@@ -106,7 +106,8 @@ class TestMailSchedule(TestEventCommon, MockEmail):
self.assertEqual(len(self._new_mails), 2, 'event: should have 2 scheduled emails (1 / registration)')
self.assertMailMailWEmails(
[formataddr((reg1.name, reg1.email)), formataddr((reg2.name, reg2.email))],
- 'outgoing', '',
+ 'outgoing',
+ content=None,
fields_values={'subject': 'Your registration at %s' % test_event.name,
'email_from': self.user_eventmanager.company_id.email_formatted,
})
@@ -140,7 +141,8 @@ class TestMailSchedule(TestEventCommon, MockEmail):
self.assertEqual(len(self._new_mails), 2, 'event: should have 2 scheduled emails (1 / registration)')
self.assertMailMailWEmails(
[formataddr((reg1.name, reg1.email)), formataddr((reg2.name, reg2.email))],
- 'outgoing', '',
+ 'outgoing',
+ content=None,
fields_values={'subject': 'Your registration at %s' % test_event.name,
'email_from': self.user_eventmanager.company_id.email_formatted,
})
@@ -173,7 +175,8 @@ class TestMailSchedule(TestEventCommon, MockEmail):
self.assertEqual(len(self._new_mails), 2, 'event: should have scheduled 2 mails (1 / registration)')
self.assertMailMailWEmails(
[formataddr((reg1.name, reg1.email)), formataddr((reg2.name, reg2.email))],
- 'outgoing', '',
+ 'outgoing',
+ content=None,
fields_values={'subject': '%s: tomorrow' % test_event.name,
'email_from': self.user_eventmanager.company_id.email_formatted,
})
@@ -248,7 +251,8 @@ class TestMailSchedule(TestEventCommon, MockEmail):
self.assertEqual(len(self._new_mails), 3, 'event: should have scheduled 3 mails, one for each registration')
self.assertMailMailWEmails(
[formataddr((reg1.name, reg1.email)), formataddr((reg2.name, reg2.email)), formataddr((reg3.name, reg3.email))],
- 'outgoing', '',
+ 'outgoing',
+ content=None,
fields_values={'subject': '%s: today' % test_event.name,
'email_from': self.user_eventmanager.company_id.email_formatted,
})
diff --git a/addons/mail/tests/common.py b/addons/mail/tests/common.py
index 25d1768e4a0..bfed47a57bc 100644
--- a/addons/mail/tests/common.py
+++ b/addons/mail/tests/common.py
@@ -8,6 +8,7 @@ import time
from collections import defaultdict
from contextlib import contextmanager
from functools import partial
+from lxml import html
from unittest.mock import patch
from smtplib import SMTPServerDisconnected
@@ -32,13 +33,17 @@ class MockEmail(common.BaseCase):
('cancel', 'Cancelled')
"""
+ # ------------------------------------------------------------
+ # GATEWAY MOCK
+ # ------------------------------------------------------------
+
@contextmanager
def mock_mail_gateway(self, mail_unlink_sent=False, sim_error=None):
build_email_origin = IrMailServer.build_email
mail_create_origin = MailMail.create
mail_unlink_origin = MailMail.unlink
- self._init_mail_mock()
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':
@@ -147,8 +152,6 @@ class MockEmail(common.BaseCase):
return email.message_from_string(pycompat.to_text(text), policy=email.policy.SMTP)
def assertHtmlEqual(self, value, expected, message=None):
- from lxml import html
-
tree = html.fragment_fromstring(value, parser=html.HTMLParser(encoding='utf-8'), create_parent='body')
# mass mailing: add base tag we have to remove
@@ -166,19 +169,38 @@ class MockEmail(common.BaseCase):
self.assertEqual(tree, expected_node)
# ------------------------------------------------------------
- # GATEWAY ASSERTS
+ # GATEWAY GETTERS
# ------------------------------------------------------------
def _find_sent_mail_wemail(self, email_to):
- for email in self._mails:
- if set(email['email_to']) == set([email_to]):
+ """ Find a sent email with a given list of recipients. Email should match
+ exactly the recipients.
+
+ :return email: a dictionary mapping values given to ``build_email``;
+ """
+ for sent_email in self._mails:
+ if set(sent_email['email_to']) == set([email_to]):
break
else:
raise AssertionError('sent mail not found for email_to %s' % (email_to))
- return email
-
+ return sent_email
def _find_mail_mail_wpartners(self, recipients, status, mail_message=None, author=None):
+ """ Find a mail.mail record based on various parameters, notably a list
+ of recipients (partners).
+
+ :param recipients: a ``res.partner`` recordset Check all of them are in mail
+ recipients to find the right mail.mail record;
+ :param status: state of mail.mail. If not void use it to filter mail.mail
+ record;
+ :param mail_message: optional check/filter on mail_message_id field aka
+ a ``mail.message`` record;
+ :param author: optional check/filter on author_id field aka a ``res.partner``
+ record;
+
+ :return mail: a ``mail.mail`` record generated during the mock and matching
+ given parameters and filters;
+ """
for mail in self._new_mails:
if author is not None and mail.author_id != author:
continue
@@ -193,6 +215,21 @@ class MockEmail(common.BaseCase):
return mail
def _find_mail_mail_wemail(self, email_to, status, mail_message=None, author=None):
+ """ Find a mail.mail record based on various parameters, notably a list
+ of email to (string emails).
+
+ :param email_to: either matching mail.email_to value, either a mail sent
+ to a single recipient whose email is email_to;
+ :param status: state of mail.mail. If not void use it to filter mail.mail
+ record;
+ :param mail_message: optional check/filter on mail_message_id field aka
+ a ``mail.message`` record;
+ :param author: optional check/filter on author_id field aka a ``res.partner``
+ record;
+
+ :return mail: a ``mail.mail`` record generated during the mock and matching
+ given parameters and filters;
+ """
for mail in self._new_mails:
if author is not None and mail.author_id != author:
continue
@@ -200,13 +237,17 @@ class MockEmail(common.BaseCase):
continue
if status and mail.state != status:
continue
- if (mail.email_to == email_to and not mail.recipient_ids) or (not mail.email_to and mail.recipient_ids.email) == email_to:
+ if (mail.email_to == email_to and not mail.recipient_ids) or (not mail.email_to and mail.recipient_ids.email == email_to):
break
else:
raise AssertionError('mail.mail not found for email_to %s / status %s in %s' % (email_to, status, repr([m.email_to for m in self._new_mails])))
return mail
def _find_mail_mail_wrecord(self, record):
+ """ Find a mail.mail record based on model / res_id of a record.
+
+ :return mail: a ``mail.mail`` record generated during the mock;
+ """
for mail in self._new_mails:
if mail.model == record._name and mail.res_id == record.id:
break
@@ -214,45 +255,78 @@ class MockEmail(common.BaseCase):
raise AssertionError('mail.mail not found for record %s in %s' % (record, repr([m.email_to for m in self._new_mails])))
return mail
- def assertMailFailed(self, author, recipients, mail_message):
- mail = self._find_mail(author, recipients, mail_message)
- self.assertEqual(mail.state, 'exception')
+ # ------------------------------------------------------------
+ # GATEWAY ASSERTS
+ # ------------------------------------------------------------
def assertMailMail(self, recipients, status,
check_mail_mail=True, mail_message=None, author=None,
content=None, fields_values=None, email_values=None):
- if check_mail_mail:
- found_mail = self._find_mail_mail_wpartners(recipients, status, mail_message=mail_message, author=author)
- self.assertTrue(bool(found_mail))
- if content:
- self.assertIn(content, found_mail.body_html)
- for fname, fvalue in (fields_values or {}).items():
- self.assertEqual(
- found_mail[fname], fvalue,
- 'Mail: expected %s for %s, got %s' % (fvalue, fname, found_mail[fname]))
+ """ Assert mail.mail records are created and maybe sent as emails. Allow
+ asserting their content. Records to check are the one generated when
+ using mock (mail.mail and outgoing emails). This method takes partners
+ as source of record fetch and assert.
+
+ :param recipients: a ``res.partner`` recordset. See ``_find_mail_mail_wpartners``;
+ :param status: mail.mail state used to filter mails. If ``sent`` this method
+ also check that emails have been sent trough gateway;
+ :param mail_message: see ``_find_mail_mail_wpartners``;
+ :param author: see ``_find_mail_mail_wpartners``;;
+ :param content: if given, check it is contained within mail html body;
+ :param fields_values: if given, should be a dictionary of field names /
+ values allowing to check ``mail.mail`` additional values (subject,
+ reply_to, ...);
+ :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))
+ if content:
+ self.assertIn(content, found_mail.body_html)
+ for fname, fvalue in (fields_values or {}).items():
+ self.assertEqual(
+ found_mail[fname], fvalue,
+ 'Mail: expected %s for %s, got %s' % (fvalue, fname, found_mail[fname]))
if status == 'sent':
for recipient in recipients:
self.assertSentEmail(email_values['email_from'] if email_values and email_values.get('email_from') else author, [recipient], **(email_values or {}))
- def assertMailMailWEmails(self, emails, status, content, fields_values=None):
- """ Will check in self._new_mails to find a sent mail.mail. To use with
- mail gateway mock.
-
- :param emails: list of emails;
- :param status: status of mail.mail;
- :param content: content to check for each email;
- :param fields_values: specific value to check on the mail.mail record;
+ def assertMailMailWEmails(self, emails, status,
+ 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
+ using mock (mail.mail and outgoing emails). This method takes emails
+ as source of record fetch and assert.
+
+ :param emails: a list of emails. See ``_find_mail_mail_wemail``;
+ :param status: mail.mail state used to filter mails. If ``sent`` this method
+ also check that emails have been sent trough gateway;
+ :param mail_message: see ``_find_mail_mail_wemail``;
+ :param author: see ``_find_mail_mail_wemail``;;
+ :param content: if given, check it is contained within mail html body;
+ :param fields_values: if given, should be a dictionary of field names /
+ values allowing to check ``mail.mail`` additional values (subject,
+ reply_to, ...);
+ :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:
- sent_mail = self._find_mail_mail_wemail(email_to, status)
+ found_mail = self._find_mail_mail_wemail(email_to, status, mail_message=mail_message, author=author)
if content:
- self.assertIn(content, sent_mail.body_html)
+ self.assertIn(content, found_mail.body_html)
for fname, fvalue in (fields_values or {}).items():
self.assertEqual(
- sent_mail[fname], fvalue,
- 'Mail: expected %s for %s, got %s' % (fvalue, fname, sent_mail[fname]))
+ found_mail[fname], fvalue,
+ 'Mail: expected %s for %s, got %s' % (fvalue, fname, found_mail[fname]))
- def assertNoMail(self, author, recipients, mail_message):
+ def assertNoMail(self, recipients, mail_message=None, author=None):
try:
self._find_mail_mail_wpartners(recipients, False, mail_message=mail_message, author=author)
except AssertionError:
@@ -602,18 +676,27 @@ class MailCase(MockEmail):
for recipients in email_groups.values():
partners = self.env['res.partner'].sudo().concat(*recipients)
if all(p in mail_groups['failure'] for p in partners):
- self.assertMailMail(partners, 'exception', author=message.author_id, mail_message=message)
+ if not self.mail_unlink_sent:
+ self.assertMailMail(partners, 'exception',
+ author=message.author_id,
+ mail_message=message)
+ else:
+ for recipient in partners:
+ self.assertSentEmail(message.author_id, [recipient])
else:
- check_mail_mail = not self.mail_unlink_sent
- self.assertMailMail(
- partners, 'sent',
- author=message.author_id if message.author_id else message.email_from,
- mail_message=message,
- check_mail_mail=check_mail_mail,
- email_values={'body_content': mbody}
- )
+ if not self.mail_unlink_sent:
+ self.assertMailMail(
+ partners, 'sent',
+ author=message.author_id if message.author_id else message.email_from,
+ mail_message=message,
+ email_values={'body_content': mbody}
+ )
+ else:
+ for recipient in partners:
+ self.assertSentEmail(message.author_id if message.author_id else message.email_from, [recipient],
+ email_values={'body_content': mbody})
if not any(p for recipients in email_groups.values() for p in recipients):
- self.assertNoMail(message.author_id, partners, message)
+ self.assertNoMail(partners, mail_message=message, author=message.author_id)
return done_msgs, done_notifs
@@ -741,3 +824,24 @@ class MailCommon(common.SavepointCase, MailCase):
name='Chell Gladys', notification_type='email')
cls.partner_portal = cls.user_portal.partner_id
return cls.user_portal
+
+ @classmethod
+ def _activate_multi_company(cls):
+ """ Create another company, add it to admin and create an user that
+ belongs to that new company. It allows to test flows with users from
+ different companies. """
+ cls.company_2 = cls.env['res.company'].create({
+ 'name': 'Company 2',
+ 'email': 'company_2@test.example.com',
+ })
+ cls.user_admin.write({'company_ids': [(4, cls.company_2.id)]})
+
+ cls.user_employee_c2 = mail_new_test_user(
+ cls.env, login='employee_c2',
+ groups='base.group_user',
+ company_id=cls.company_2.id,
+ name='Enguerrand Employee C2',
+ notification_type='inbox',
+ signature='--\nEnguerrand'
+ )
+ cls.partner_employee_c2 = cls.user_employee_c2.partner_id
diff --git a/addons/mass_mailing/tests/common.py b/addons/mass_mailing/tests/common.py
index 6b893e7e0b3..5f6d8fa8f73 100644
--- a/addons/mass_mailing/tests/common.py
+++ b/addons/mass_mailing/tests/common.py
@@ -52,15 +52,15 @@ class MassMailCase(MailCase, MockLinkTracker):
fields_values['failure_type'] = recipient_info['failure_type']
if state == 'sent':
- self.assertMailMailWEmails([email], 'sent', content, fields_values=fields_values)
+ self.assertMailMailWEmails([email], 'sent', content=content, fields_values=fields_values)
elif state == 'replied': # replied imply something has been sent
- self.assertMailMailWEmails([email], 'sent', content, fields_values=fields_values)
+ self.assertMailMailWEmails([email], 'sent', content=content, fields_values=fields_values)
elif state == 'ignored':
- self.assertMailMailWEmails([email], 'cancel', content, fields_values=fields_values)
+ self.assertMailMailWEmails([email], 'cancel', content=content, fields_values=fields_values)
elif state == 'exception':
- self.assertMailMailWEmails([email], 'exception', content, fields_values=fields_values)
+ self.assertMailMailWEmails([email], 'exception', content=content, fields_values=fields_values)
elif state == 'canceled':
- self.assertMailMailWEmails([email], 'canceled', content, fields_values=fields_values)
+ self.assertMailMailWEmails([email], 'canceled', content=content, fields_values=fields_values)
else:
raise NotImplementedError()
diff --git a/addons/sms/tests/test_sms_template.py b/addons/sms/tests/test_sms_template.py
index 8e3bbfae3a6..9483ecaf7bc 100644
--- a/addons/sms/tests/test_sms_template.py
+++ b/addons/sms/tests/test_sms_template.py
@@ -3,8 +3,9 @@
from odoo.tests.common import SavepointCase, users
from odoo.addons.mail.tests.common import mail_new_test_user
-from odoo.tests import tagged
from odoo.exceptions import AccessError
+from odoo.tests import tagged
+from odoo.tools import mute_logger
@tagged('post_install')
@@ -26,7 +27,8 @@ class TestSmsTemplateAccessRights(SavepointCase):
cls.sms_templates = cls.env['sms.template'].create(vals)
@users('user_employee')
- def test_access_rights_user_sms_template(self):
+ @mute_logger('odoo.models.unlink')
+ def test_access_rights_user(self):
# Check if a member of group_user can only read on sms.template
for sms_template in self.env['sms.template'].browse(self.sms_templates.ids):
self.assertTrue(bool(sms_template.name))
@@ -42,7 +44,8 @@ class TestSmsTemplateAccessRights(SavepointCase):
sms_template.unlink()
@users('user_system')
- def test_access_rights_manager_sms_template(self):
+ @mute_logger('odoo.models.unlink', 'odoo.addons.base.models.ir_model')
+ def test_access_rights_system(self):
admin = self.env.ref('base.user_admin')
for sms_template in self.env['sms.template'].browse(self.sms_templates.ids):
self.assertTrue(bool(sms_template.name))
diff --git a/addons/test_mail/tests/test_mail_channel.py b/addons/test_mail/tests/test_mail_channel.py
index 3fec6b8594c..239e76ccb41 100644
--- a/addons/test_mail/tests/test_mail_channel.py
+++ b/addons/test_mail/tests/test_mail_channel.py
@@ -8,6 +8,7 @@ from odoo.exceptions import AccessError, ValidationError, UserError
from odoo.tools import mute_logger, formataddr
+@tagged('mail_channel')
class TestChannelAccessRights(TestMailCommon):
@classmethod
@@ -107,6 +108,7 @@ class TestChannelAccessRights(TestMailCommon):
trigger_read = partner.with_user(self.user_portal).name
+@tagged('mail_channel')
class TestChannelFeatures(TestMailCommon):
@classmethod
@@ -348,7 +350,7 @@ class TestChannelFeatures(TestMailCommon):
self.assertTrue(initial_channel_info, 'should be able to chat with multi company user')
-@tagged('moderation')
+@tagged('moderation', 'mail_channel')
class TestChannelModeration(TestMailCommon):
@classmethod
diff --git a/addons/test_mail/tests/test_mail_composer.py b/addons/test_mail/tests/test_mail_composer.py
index e22a875a5a6..0547caca98d 100644
--- a/addons/test_mail/tests/test_mail_composer.py
+++ b/addons/test_mail/tests/test_mail_composer.py
@@ -520,7 +520,6 @@ class TestComposerResultsComment(TestMailComposer):
# template is sent only to partners (email_to are transformed)
message = self.test_record.message_ids[0]
self.assertMailMail(self.partner_employee_2, 'sent',
- check_mail_mail=True,
mail_message=message,
author=self.partner_employee, # author != email_from (template sets only email_from)
email_values={
@@ -536,7 +535,6 @@ class TestComposerResultsComment(TestMailComposer):
fields_values={},
)
self.assertMailMail(self.test_record.customer_id + new_partners, 'sent',
- check_mail_mail=True,
mail_message=message,
author=self.partner_employee, # author != email_from (template sets only email_from)
email_values={
@@ -597,7 +595,7 @@ class TestComposerResultsMass(TestMailComposer):
message = record.message_ids[0]
# template is sent directly using customer field, meaning we have recipients
- self.assertMailMail(record.customer_id, 'sent', check_mail_mail=True,
+ self.assertMailMail(record.customer_id, 'sent',
mail_message=message,
author=self.partner_employee)
@@ -668,7 +666,6 @@ class TestComposerResultsMass(TestMailComposer):
self._mails = _mails
self.assertMailMail(record.customer_id + new_partners + self.partner_admin,
'sent',
- check_mail_mail=True,
mail_message=message,
author=self.partner_employee,
email_values={
diff --git a/addons/test_mail/tests/test_message_post.py b/addons/test_mail/tests/test_message_post.py
index 09370bd9ade..129406567e5 100644
--- a/addons/test_mail/tests/test_message_post.py
+++ b/addons/test_mail/tests/test_message_post.py
@@ -113,10 +113,12 @@ class TestMessagePost(TestMailCommon, TestRecipients):
# subscribe second employee to the group to test notifications
self.test_record.message_subscribe(partner_ids=[self.user_admin.partner_id.id])
- with self.assertSinglePostNotifications([
- {'partner': self.partner_1, 'type': 'email'},
- {'partner': self.partner_2, 'type': 'email'},
- {'partner': self.partner_admin, 'type': 'email'}], {'content': _body}, mail_unlink_sent=True):
+ with self.assertSinglePostNotifications(
+ [{'partner': self.partner_1, 'type': 'email'},
+ {'partner': self.partner_2, 'type': 'email'},
+ {'partner': self.partner_admin, 'type': 'email'}],
+ {'content': _body},
+ mail_unlink_sent=True):
msg = self.test_record.with_user(self.user_employee).message_post(
body=_body, subject=_subject,
message_type='comment', subtype_xmlid='mail.mt_comment',