diff options
| -rw-r--r-- | addons/event/tests/test_event_mail_schedule.py | 12 | ||||
| -rw-r--r-- | addons/mail/tests/common.py | 192 | ||||
| -rw-r--r-- | addons/mass_mailing/tests/common.py | 10 | ||||
| -rw-r--r-- | addons/sms/tests/test_sms_template.py | 9 | ||||
| -rw-r--r-- | addons/test_mail/tests/test_mail_channel.py | 4 | ||||
| -rw-r--r-- | addons/test_mail/tests/test_mail_composer.py | 5 | ||||
| -rw-r--r-- | addons/test_mail/tests/test_message_post.py | 10 |
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', |
