diff --git a/addons/link_tracker/tests/__init__.py b/addons/link_tracker/tests/__init__.py new file mode 100644 index 00000000000..511e649c9e2 --- /dev/null +++ b/addons/link_tracker/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import common diff --git a/addons/link_tracker/tests/common.py b/addons/link_tracker/tests/common.py new file mode 100644 index 00000000000..16fe77aabce --- /dev/null +++ b/addons/link_tracker/tests/common.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import werkzeug + +from lxml import etree +from unittest.mock import patch + +from odoo.tests import common + + +class MockLinkTracker(common.BaseCase): + + def setUp(self): + super(MockLinkTracker, self).setUp() + + def _get_title_from_url(url): + return "Test_TITLE" + + link_tracker_title_patch = patch('odoo.addons.link_tracker.models.link_tracker.LinkTracker._get_title_from_url', wraps=_get_title_from_url) + link_tracker_title_patch.start() + self.addCleanup(link_tracker_title_patch.stop) + + def _get_href_from_anchor_id(self, body, anchor_id): + html = etree.fromstring(body) + return html.xpath("*[@id='%s']" % anchor_id)[0].attrib.get('href') + + def _get_tracker_from_short_url(self, short_url): + code = self.env['link.tracker.code'].sudo().search([ + ('code', '=', short_url.split('/r/')[-1]) + ]) + return code.link_id + + def assertLinkShortened(self, body, link_info, link_params=None): + """ Usage + + self.assertLinkShortened( + message.body, + ('url0', 'http://www.odoo.com', True), + {'utm_campaign': self.utm_c.name, 'utm_medium': self.utm_m.name} + ) + """ + (anchor_id, url, is_shortened) = link_info + anchor_href = self._get_href_from_anchor_id(body, anchor_id) + if is_shortened: + self.assertTrue('/r/' in anchor_href, '%s should be shortened: %s' % (anchor_id, anchor_href)) + link_tracker = self._get_tracker_from_short_url(anchor_href) + self.assertEqual(url, link_tracker.url) + self.assertLinkParams(url, link_tracker, link_params=link_params) + else: + self.assertTrue('/r/' not in anchor_href, '%s should not be shortened: %s' % (anchor_id, anchor_href)) + self.assertEqual(anchor_href, url) + + def assertLinkParams(self, url, link_tracker, link_params=None): + """ Usage + + self.assertLinkTracker( + 'http://www.example.com', + link_tracker, + {'utm_campaign': self.utm_c.name, 'utm_medium': self.utm_m.name} + ) + """ + # check UTMS are correctly set on redirect URL + original_url = werkzeug.urls.url_parse(url) + redirect_url = werkzeug.urls.url_parse(link_tracker.redirected_url) + redirect_params = redirect_url.decode_query().to_dict(flat=True) + self.assertEqual(redirect_url.scheme, original_url.scheme) + self.assertEqual(redirect_url.decode_netloc(), original_url.decode_netloc()) + self.assertEqual(redirect_url.path, original_url.path) + if link_params: + self.assertEqual(redirect_params, link_params) diff --git a/addons/mass_mailing/tests/__init__.py b/addons/mass_mailing/tests/__init__.py index 4d3ec554b79..49ff0a87784 100644 --- a/addons/mass_mailing/tests/__init__.py +++ b/addons/mass_mailing/tests/__init__.py @@ -3,5 +3,4 @@ from . import common from . import test_mailing_internals -from . import test_mass_mailing_list_merge -from . import test_mass_mailing_shortener +from . import test_mailing_list diff --git a/addons/mass_mailing/tests/common.py b/addons/mass_mailing/tests/common.py index 3eb93ea226f..9d49a5c5bcf 100644 --- a/addons/mass_mailing/tests/common.py +++ b/addons/mass_mailing/tests/common.py @@ -1,11 +1,106 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo.addons.link_tracker.tests.common import MockLinkTracker from odoo.addons.mail.tests.common import MailCase, mail_new_test_user from odoo.tests.common import SavepointCase -class TestMassMailCommon(SavepointCase, MailCase): +class MassMailCase(MailCase, MockLinkTracker): + + def _find_mail_mail_wemail(self, email_to, state, author=None): + for mail in self._new_mails: + if author is not None and mail.author_id != author: + continue + if mail.state != state: + continue + 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 / state %s in %s' % (email_to, state, repr([m.email_to for m in self._new_mails]))) + return mail + + def _find_mail_mail_wrecord(self, record): + for mail in self._new_mails: + if mail.model == record._name and mail.res_id == record.id: + break + else: + 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 assertMailMailWEmails(self, emails, state, 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 state: state of mail.mail; + :param content: content to check for each email; + :param fields_values: specific value to check on the mail.mail record; + """ + for email_to in emails: + sent_mail = self._find_mail_mail_wemail(email_to, state) + if content: + self.assertIn(content, sent_mail.body_html) + for fname, fvalue in (fields_values or {}).items(): + self.assertEqual(sent_mail[fname], fvalue) + + def assertMailTraces(self, recipients_info, mailing, records, check_mail=True): + """ Check content of traces. + + :param recipients_info: list[{ + 'partner': res.partner record (may be empty), + 'email': email used when sending email (may be empty, computed based on partner), + 'state': outgoing / sent / open / reply / error / cancel (sent by default), + 'record: linked record, + 'content': UDPATE ME + 'failure_type': optional: UPDATE ME + }, { ... }] + """ + traces = self.env['mailing.trace'].search([ + ('mass_mailing_id', 'in', mailing.ids), + ('res_id', 'in', records.ids) + ]) + + # ensure trace coherency + self.assertTrue(all(s.model == records._name for s in traces)) + self.assertEqual(set(s.res_id for s in traces), set(records.ids)) + + # check each traces + for recipient_info in recipients_info: + partner = recipient_info.get('partner', self.env['res.partner']) + email = recipient_info.get('email') + state = recipient_info.get('state', 'sent') + record = recipient_info.get('record') + content = recipient_info.get('content') + if email is None and partner: + email = partner.email_normalized + + recipient_trace = traces.filtered( + lambda t: t.email == email and t.state == state and (t.res_id == record.id if record else True) + ) + self.assertTrue( + len(recipient_trace) == 1, + 'MailTrace: email %s (recipient %s, state: %s, record: %s): found %s records (1 expected)' % (email, partner, state, record, len(recipient_trace)) + ) + + if check_mail: + fields_values = {'mailing_id': mailing} + if 'failure_type' in recipient_info: + fields_values['failure_type'] = recipient_info['failure_type'] + + if state == 'sent': + self.assertMailMailWEmails([email], 'sent', content, fields_values=fields_values) + elif state == 'ignored': + self.assertMailMailWEmails([email], 'cancel', content, fields_values=fields_values) + elif state == 'exception': + self.assertMailMailWEmails([email], 'exception', content, fields_values=fields_values) + elif state == 'canceled': + self.assertMailMailWEmails([email], 'canceled', content, fields_values=fields_values) + else: + raise NotImplementedError() + + +class TestMassMailCommon(SavepointCase, MassMailCase): @classmethod def setUpClass(cls): @@ -16,7 +111,13 @@ class TestMassMailCommon(SavepointCase, MailCase): groups='base.group_user,base.group_partner_manager,mass_mailing.group_mass_mailing_user', name='Martial Marketing', signature='--\nMartial') - cls.mailing_list_1 = cls.env['mailing.list'].create({ + cls.email_reply_to = 'MyCompany SomehowAlias ' + + @classmethod + def _create_mailing_list(cls): + """ Shortcut to create mailing lists. Currently hardcoded, maybe evolve + in a near future. """ + cls.mailing_list_1 = cls.env['mailing.list'].with_context(cls._test_context).create({ 'name': 'List1', 'contact_ids': [ (0, 0, {'name': 'Déboulonneur', 'email': 'fleurus@example.com'}), @@ -24,7 +125,7 @@ class TestMassMailCommon(SavepointCase, MailCase): (0, 0, {'name': 'Ybrant', 'email': 'ybrant@example.com'}), ] }) - cls.mailing_list_2 = cls.env['mailing.list'].create({ + cls.mailing_list_2 = cls.env['mailing.list'].with_context(cls._test_context).create({ 'name': 'List2', 'contact_ids': [ (0, 0, {'name': 'Gilberte', 'email': 'gilberte@example.com'}), @@ -33,5 +134,3 @@ class TestMassMailCommon(SavepointCase, MailCase): (0, 0, {'name': 'Ybrant', 'email': 'ybrant@example.com'}), ] }) - - cls.email_reply_to = 'MyCompany SomehowAlias ' diff --git a/addons/mass_mailing/tests/test_mailing_internals.py b/addons/mass_mailing/tests/test_mailing_internals.py index dd0af8584ab..50cb2e2f708 100644 --- a/addons/mass_mailing/tests/test_mailing_internals.py +++ b/addons/mass_mailing/tests/test_mailing_internals.py @@ -5,10 +5,48 @@ from ast import literal_eval from odoo.addons.mass_mailing.tests.common import TestMassMailCommon from odoo.tests.common import users, Form - +from odoo.tools import formataddr, mute_logger class TestMassMailValues(TestMassMailCommon): + @classmethod + def setUpClass(cls): + super(TestMassMailValues, cls).setUpClass() + cls._create_mailing_list() + + @users('user_marketing') + def test_mailing_body_responsive(self): + """ Testing mail mailing responsive mail body """ + recipient = self.env['res.partner'].create({ + 'name': 'Mass Mail Partner', + 'email': 'Customer ', + }) + mailing = self.env['mailing.mailing'].create({ + 'name': 'Test', + 'subject': 'Test', + 'state': 'draft', + 'mailing_model_id': self.env['ir.model']._get('res.partner').id, + }) + + composer = self.env['mail.compose.message'].with_user(self.user_marketing).with_context({ + 'default_composition_mode': 'mass_mail', + 'default_model': 'res.partner', + 'default_res_id': recipient.id, + }).create({ + 'subject': 'Mass Mail Responsive', + 'body': 'I am Responsive body', + 'mass_mailing_id': mailing.id + }) + + mail_values = composer.get_mail_values([recipient.id]) + body_html = str(mail_values[recipient.id]['body_html']) + + self.assertIn('', body_html) + self.assertIn('', body_html) + self.assertIn('viewport', body_html) + self.assertIn('@media', body_html) + self.assertIn('I am Responsive body', body_html) + @users('user_marketing') def test_mailing_computed_fields(self): # Create on res.partner, with default values for computed fields @@ -82,3 +120,140 @@ class TestMassMailValues(TestMassMailCommon): ['&', ('is_blacklisted', '=', False), ('email', 'ilike', 'test.example.com')] ) self.assertEqual(mailing_form.mailing_model_real, 'res.partner') + + +class TestMassMailFeatures(TestMassMailCommon): + + @classmethod + def setUpClass(cls): + super(TestMassMailFeatures, cls).setUpClass() + cls._create_mailing_list() + + @users('user_marketing') + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_channel_blacklisted_recipients(self): + """ Posting a message on a channel should send one email to all recipients, except the blacklisted ones """ + def _join_channel(channel, partners): + for partner in partners: + channel.write({'channel_last_seen_partner_ids': [(0, 0, {'partner_id': partner.id})]}) + channel.invalidate_cache() + + test_channel = self.env['mail.channel'].create({ + 'name': 'Test', + 'description': 'Description', + 'alias_name': 'test', + 'public': 'public', + 'email_send': True, + }) + test_partner = self.env['res.partner'].create({ + 'name': 'Test Partner', + 'email': 'test@example.com', + }) + + blacklisted_partner = self.env['res.partner'].create({ + 'name': 'Blacklisted Partner', + 'email': 'test@black.list', + }) + + # Set Blacklist + self.env['mail.blacklist'].create({ + 'email': 'test@black.list', + }) + + _join_channel(test_channel, test_partner) + _join_channel(test_channel, blacklisted_partner) + with self.mock_mail_gateway(): + test_channel.message_post(body="Test", message_type='comment', subtype_xmlid='mail.mt_comment') + + self.assertEqual(len(self._mails), 1, 'Number of mail incorrect. Should be equal to 1.') + for email in self._mails: + self.assertEqual( + set(email['email_to']), + set([formataddr((test_partner.name, test_partner.email))]), + 'email_to incorrect. Should be equal to "%s"' % ( + formataddr((test_partner.name, test_partner.email)))) + + @users('user_marketing') + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_mailing_on_res_partner(self): + """ Test mailing on res.partner model: ensure default recipients are + correctly computed """ + partner_a = self.env['res.partner'].create({ + 'name': 'test email 1', + 'email': 'test1@example.com', + }) + partner_b = self.env['res.partner'].create({ + 'name': 'test email 2', + 'email': 'test2@example.com', + }) + self.env['mail.blacklist'].create({'email': 'Test2@example.com',}) + + mailing = self.env['mailing.mailing'].create({ + 'name': 'One', + 'subject': 'One', + 'mailing_model_id': self.env['ir.model']._get('res.partner').id, + 'mailing_domain': [('id', 'in', (partner_a | partner_b).ids)], + 'body_html': 'This is mass mail marketing demo' + }) + mailing.action_put_in_queue() + with self.mock_mail_gateway(mail_unlink_sent=False): + mailing._process_mass_mailing_queue() + + self.assertMailTraces( + [{'email': 'test1@example.com'}, + {'email': 'test2@example.com', 'state': 'ignored'}], + mailing, partner_a | partner_b, check_mail=True + ) + + @users('user_marketing') + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_mailing_shortener(self): + mailing = self.env['mailing.mailing'].create({ + 'name': 'TestSource', + 'subject': 'TestShortener', + 'body_html': """
+Hi, +% set url = "www.odoo.com" +% set httpurl = "https://www.odoo.eu" +Website0: https://www.odoo.tz/my/${object.name} +Website1: https://www.odoo.be +Website2: https://${url} +Website3: ${httpurl} +External1: Youpie +Email: test@odoo.com
""", + 'mailing_model_id': self.env['ir.model']._get('mailing.list').id, + 'reply_to_mode': 'email', + 'reply_to': self.email_reply_to, + 'contact_list_ids': [(6, 0, self.mailing_list_1.ids)], + 'keep_archives': True, + }) + + mailing.action_put_in_queue() + + with self.mock_mail_gateway(mail_unlink_sent=False): + mailing._process_mass_mailing_queue() + + self.assertMailTraces( + [{'email': 'fleurus@example.com'}, + {'email': 'gorramts@example.com'}, + {'email': 'ybrant@example.com'}], + mailing, self.mailing_list_1.contact_ids, check_mail=True + ) + + for contact in self.mailing_list_1.contact_ids: + new_mail = self._find_mail_mail_wrecord(contact) + for link_info in [('url0', 'https://www.odoo.tz/my/%s' % contact.name, True), + ('url1', 'https://www.odoo.be', True), + ('url2', 'https://www.odoo.com', True), + ('url3', 'https://www.odoo.eu', True), + ('url4', 'https://www.example.com/foo/bar?baz=qux', True), + ('url5', 'mailto:test@odoo.com', False)]: + # TDE FIXME: why going to mail message id ? mail.body_html seems to fail, check + link_params = {'utm_medium': 'Email', 'utm_source': mailing.name} + if link_info[0] == 'url4': + link_params['baz'] = 'qux' + self.assertLinkShortened( + new_mail.mail_message_id.body, + link_info, + link_params=link_params, + ) diff --git a/addons/mass_mailing/tests/test_mass_mailing_list_merge.py b/addons/mass_mailing/tests/test_mailing_list.py similarity index 50% rename from addons/mass_mailing/tests/test_mass_mailing_list_merge.py rename to addons/mass_mailing/tests/test_mailing_list.py index e28ebfac323..4300f31a006 100644 --- a/addons/mass_mailing/tests/test_mass_mailing_list_merge.py +++ b/addons/mass_mailing/tests/test_mailing_list.py @@ -1,47 +1,34 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.tests import common +from odoo.addons.mass_mailing.tests.common import TestMassMailCommon +from odoo.tests.common import users -class TestMailingListMerge(common.TransactionCase): +class TestMailingListMerge(TestMassMailCommon): - def test_00_test_mass_mailing_list_merge(self): - # Data set up + @classmethod + def setUpClass(cls): + super(TestMailingListMerge, cls).setUpClass() + cls._create_mailing_list() - mailing_list_A = self.env['mailing.list'].create({ - 'name': 'A', - 'contact_ids': [ - (0, 0, {'name': 'Noel Flantier', 'email': 'noel.flantier@example.com'}), - (0, 0, {'name': 'Gorramts', 'email': 'gorramts@example.com'}), - (0, 0, {'name': 'Ybrant', 'email': 'ybrant@example.com'}), - ] - }) - - mailing_list_B = self.env['mailing.list'].create({ - 'name': 'B', - 'contact_ids': [ - (0, 0, {'name': 'Icallhimtest', 'email': 'icallhimtest@example.com'}), - (0, 0, {'name': 'Norbert', 'email': 'norbert@example.com'}), - (0, 0, {'name': 'Ybrant_Zoulou', 'email': 'ybrant@example.com'}), - ] - }) - - mailing_list_C = self.env['mailing.list'].create({ - 'name': 'C', + cls.mailing_list_3 = cls.env['mailing.list'].with_context(cls._test_context).create({ + 'name': 'ListC', 'contact_ids': [ (0, 0, {'name': 'Norberto', 'email': 'norbert@example.com'}), ] }) + @users('user_marketing') + def test_mailing_list_merge(self): # TEST CASE: Merge A,B into the existing mailing list C - # The mailing list C contains the same email address than 'Rorbert' in list B + # The mailing list C contains the same email address than 'Norbert' in list B # This test ensure that the mailing lists are correctly merged and no # duplicates are appearing in C result_list = self.env['mailing.list.merge'].create({ - 'src_list_ids': [(4, list_id) for list_id in [mailing_list_A.id, mailing_list_B.id]], - 'dest_list_id': mailing_list_C.id, + 'src_list_ids': [(4, list_id) for list_id in [self.mailing_list_1.id, self.mailing_list_2.id]], + 'dest_list_id': self.mailing_list_3.id, 'merge_options': 'existing', 'new_list_name': False, 'archive_src_lists': False, diff --git a/addons/mass_mailing/tests/test_mass_mailing_shortener.py b/addons/mass_mailing/tests/test_mass_mailing_shortener.py deleted file mode 100644 index 35ca6a978e3..00000000000 --- a/addons/mass_mailing/tests/test_mass_mailing_shortener.py +++ /dev/null @@ -1,122 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo.tests import common -from lxml import etree -from unittest.mock import patch - - -class TestMassMailingShortener(common.TransactionCase): - def getHrefFor(self, html, id): - return html.xpath("*[@id='%s']" % id)[0].attrib.get('href') - - def shorturl_to_link(self, short_url): - return self.env['link.tracker.code'].search([('code', '=', short_url.split('/r/')[-1])]).link_id - - def setUp(self): - super(TestMassMailingShortener, self).setUp() - - def _get_title_from_url(u): - return "Hello" - - patcher = patch('odoo.addons.link_tracker.models.link_tracker.LinkTracker._get_title_from_url', wraps=_get_title_from_url) - patcher.start() - self.addCleanup(patcher.stop) - - def test_00_test_mass_mailing_shortener(self): - mailing_list_A = self.env['mailing.list'].create({ - 'name': 'A', - }) - self.env['mailing.contact'].create({ - 'name': 'User 1', 'email': 'user1@example.com', 'list_ids': [(4, mailing_list_A.id)] - }) - self.env['mailing.contact'].create({ - 'name': 'User 2', 'email': 'user2@example.com', 'list_ids': [(4, mailing_list_A.id)] - }) - self.env['mailing.contact'].create({ - 'name': 'User 3', 'email': 'user3@example.com', 'list_ids': [(4, mailing_list_A.id)] - }) - - mass_mailing = self.env['mailing.mailing'].create({ - "reply_to_mode": "email", - "reply_to": "Administrator ", - "mailing_model_id": self.env.ref('mass_mailing.model_mailing_list').id, - "mailing_domain": "[('list_ids', 'in', [%d])]" % mailing_list_A.id, - "contact_list_ids": [[6, False, [mailing_list_A.id]]], - "campaign_id": False, - "name": "sdf", - "subject": "test_00_test_mass_mailing_shortener", - "body_html": """ -Hi, -% set url = "www.odoo.com" -% set httpurl = "https://www.odoo.eu" -Website0: https://www.odoo.tz/my/${object.name} -Website1: https://www.odoo.be -Website2: https://${url} -Website3: ${httpurl} -Email: test@odoo.com - """, - "schedule_date": False, - "state": "draft", - "keep_archives": True, - }) - - mass_mailing.action_put_in_queue() - mass_mailing._process_mass_mailing_queue() - - sent_mails = self.env['mail.mail'].sudo().search([('mailing_id', '=', mass_mailing.id)]) - sent_messages = sent_mails.mapped('mail_message_id') - - self.assertEqual(len(mailing_list_A.contact_ids), len(sent_messages), - 'Some message has not been sent') - - xbody = etree.fromstring(sent_messages[0].body) - after_url0 = self.getHrefFor(xbody, 'url0') - after_url1 = self.getHrefFor(xbody, 'url1') - after_url2 = self.getHrefFor(xbody, 'url2') - after_url3 = self.getHrefFor(xbody, 'url3') - after_url4 = self.getHrefFor(xbody, 'url4') - - self.assertTrue('/r/' in after_url0, 'URL0 should be shortened: %s' % after_url0) - self.assertTrue('/r/' in after_url1, 'URL1 should be shortened: %s' % after_url1) - self.assertTrue('/r/' in after_url2, 'URL2 should be shortened: %s' % after_url2) - self.assertTrue('/r/' in after_url3, 'URL3 should be shortened: %s' % after_url3) - self.assertEqual(after_url4, "mailto:test@odoo.com", 'mailto: has been converted') - - short0 = self.shorturl_to_link(after_url0) - short1 = self.shorturl_to_link(after_url1) - short2 = self.shorturl_to_link(after_url2) - short3 = self.shorturl_to_link(after_url3) - - self.assertTrue("https://www.odoo.tz/my/User" in short0.url, 'URL mismatch') - self.assertEqual(short1.url, "https://www.odoo.be", 'URL mismatch') - self.assertEqual(short2.url, "https://www.odoo.com", 'URL mismatch') - self.assertEqual(short3.url, "https://www.odoo.eu", 'URL mismatch') - - _xbody = etree.fromstring(sent_messages[1].body) - _after_url0 = self.getHrefFor(_xbody, 'url0') - _after_url1 = self.getHrefFor(_xbody, 'url1') - _after_url2 = self.getHrefFor(_xbody, 'url2') - _after_url3 = self.getHrefFor(_xbody, 'url3') - _after_url4 = self.getHrefFor(_xbody, 'url4') - - self.assertTrue('/r/' in _after_url0, 'URL0 should be shortened: %s' % _after_url0) - self.assertTrue('/r/' in _after_url1, 'URL1 should be shortened: %s' % _after_url1) - self.assertTrue('/r/' in _after_url2, 'URL2 should be shortened: %s' % _after_url2) - self.assertTrue('/r/' in _after_url3, 'URL3 should be shortened: %s' % _after_url3) - self.assertEqual(_after_url4, "mailto:test@odoo.com", 'mailto: has been converted') - - _short0 = self.shorturl_to_link(_after_url0) - _short1 = self.shorturl_to_link(_after_url1) - _short2 = self.shorturl_to_link(_after_url2) - _short3 = self.shorturl_to_link(_after_url3) - - self.assertTrue("https://www.odoo.tz/my/User" in _short0.url, 'URL mismatch') - self.assertEqual(_short1.url, "https://www.odoo.be", 'URL mismatch') - self.assertEqual(_short2.url, "https://www.odoo.com", 'URL mismatch') - self.assertEqual(_short3.url, "https://www.odoo.eu", 'URL mismatch') - - self.assertNotEqual(short0.url, _short0.url) - self.assertEqual(short1.url, _short1.url) - self.assertEqual(short2.url, _short2.url) - self.assertEqual(short3.url, _short3.url) diff --git a/addons/mass_mailing_sms/tests/test_mailing_internals.py b/addons/mass_mailing_sms/tests/test_mailing_internals.py index 333c9ec5ba2..a9c4c2f218a 100644 --- a/addons/mass_mailing_sms/tests/test_mailing_internals.py +++ b/addons/mass_mailing_sms/tests/test_mailing_internals.py @@ -5,7 +5,6 @@ from ast import literal_eval from odoo.addons.mass_mailing.tests.common import TestMassMailCommon from odoo.tests.common import users -from odoo.tools import mute_logger class TestMassMailValues(TestMassMailCommon): @@ -14,6 +13,7 @@ class TestMassMailValues(TestMassMailCommon): def setUpClass(cls): super(TestMassMailValues, cls).setUpClass() + cls._create_mailing_list() cls.sms_template_partner = cls.env['sms.template'].create({ 'name': 'Test Template', 'model_id': cls.env['ir.model']._get('res.partner').id, diff --git a/addons/test_mail_full/tests/common.py b/addons/test_mail_full/tests/common.py index a2e98e2a0a3..6fac92a5aab 100644 --- a/addons/test_mail_full/tests/common.py +++ b/addons/test_mail_full/tests/common.py @@ -6,7 +6,7 @@ from odoo.addons.test_mail.tests import common as test_mail_common from odoo.addons.test_mass_mailing.tests import common as test_mass_mailing_common -class TestSMSCommon(test_mass_mailing_common.TestMailCommon, mass_mailing_sms_common.MockSMS): +class TestSMSCommon(test_mass_mailing_common.TestMassMailCommon, mass_mailing_sms_common.MockSMS): @classmethod def setUpClass(cls): diff --git a/addons/test_mail_full/tests/test_mass_sms.py b/addons/test_mail_full/tests/test_mass_sms.py index 42d58bde0c7..b43ff773316 100644 --- a/addons/test_mail_full/tests/test_mass_sms.py +++ b/addons/test_mail_full/tests/test_mass_sms.py @@ -58,7 +58,7 @@ class TestMassSMS(test_mail_full_common.TestSMSCommon): }) def test_mass_sms_internals(self): - with self.with_user('marketing'): + with self.with_user('user_marketing'): mailing = self.env['mailing.mailing'].create({ 'name': 'Xmas Spam', 'subject': 'Xmas Spam', @@ -105,7 +105,7 @@ class TestMassSMS(test_mail_full_common.TestSMSCommon): }) records_numbers = self.records_numbers + ['+32456999999'] - with self.with_user('marketing'): + with self.with_user('user_marketing'): with self.mockSMSGateway(): self.mailing.action_send_sms() @@ -119,7 +119,7 @@ class TestMassSMS(test_mail_full_common.TestSMSCommon): ) def test_mass_sms_internals_done_ids(self): - with self.with_user('marketing'): + with self.with_user('user_marketing'): with self.mockSMSGateway(): self.mailing.action_send_sms(res_ids=self.records[:5].ids) @@ -131,7 +131,7 @@ class TestMassSMS(test_mail_full_common.TestSMSCommon): self.mailing, self.records[:5], check_sms=True ) - with self.with_user('marketing'): + with self.with_user('user_marketing'): with self.mockSMSGateway(): self.mailing.action_send_sms(res_ids=self.records.ids) diff --git a/addons/test_mass_mailing/models/__init__.py b/addons/test_mass_mailing/models/__init__.py index ab1b44a2dea..ea86084ecd7 100644 --- a/addons/test_mass_mailing/models/__init__.py +++ b/addons/test_mass_mailing/models/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from . import mass_mail_test +from . import mailing_mailing +from . import mailing_models diff --git a/addons/test_mass_mailing/models/mailing_mailing.py b/addons/test_mass_mailing/models/mailing_mailing.py new file mode 100644 index 00000000000..12c888dbb8a --- /dev/null +++ b/addons/test_mass_mailing/models/mailing_mailing.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import logging + +from odoo import models + +_logger = logging.getLogger(__name__) + + +class Mailing(models.Model): + _inherit = 'mailing.mailing' + + def _get_opt_out_list(self): + """Returns a set of emails opted-out in target model""" + self.ensure_one() + if self.mailing_model_real == 'mailing.test.optout': + res_ids = self._get_recipients() + opt_out_contacts = set(self.env['mailing.test.optout'].search([ + ('id', 'in', res_ids), + ('opt_out', '=', True) + ]).mapped('email_normalized')) + _logger.info( + "Mass-mailing %s targets %s, optout: %s emails", + self, self.mailing_model_real, len(opt_out_contacts)) + return opt_out_contacts + return super(Mailing, self)._get_opt_out_list() diff --git a/addons/test_mass_mailing/models/mailing_models.py b/addons/test_mass_mailing/models/mailing_models.py new file mode 100644 index 00000000000..826b52a2c51 --- /dev/null +++ b/addons/test_mass_mailing/models/mailing_models.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + + +class MailingSimple(models.Model): + """ A very simple model only inheriting from mail.thread to test pure mass + mailing features and base performances. """ + _description = 'Simple Mailing' + _name = 'mailing.test.simple' + _inherit = ['mail.thread'] + + name = fields.Char() + email_from = fields.Char() + + +class MailingBLacklist(models.Model): + """ Model using blacklist mechanism for mass mailing features. """ + _description = 'Mailing Blacklist Enabled' + _name = 'mailing.test.blacklist' + _inherit = ['mail.thread.blacklist'] + _primary_email = 'email_from' + + name = fields.Char() + email_from = fields.Char() + customer_id = fields.Many2one('res.partner', 'Customer', tracking=True) + user_id = fields.Many2one('res.users', 'Responsible', tracking=True) + + +class MailingOptOut(models.Model): + """ Model using blacklist mechanism and a hijacked opt-out mechanism for + mass mailing features. """ + _description = 'Mailing Blacklist / Optout Enabled' + _name = 'mailing.test.optout' + _inherit = ['mail.thread.blacklist'] + _primary_email = 'email_from' + + name = fields.Char() + email_from = fields.Char() + opt_out = fields.Boolean() + customer_id = fields.Many2one('res.partner', 'Customer', tracking=True) + user_id = fields.Many2one('res.users', 'Responsible', tracking=True) + + +class MailingPerformance(models.Model): + """ A very simple model only inheriting from mail.thread to test pure mass + mailing performances. """ + _name = 'mailing.performance' + _description = 'Mailing: base performance' + _inherit = ['mail.thread'] + + name = fields.Char() + email_from = fields.Char() + + +class MailingPerformanceBL(models.Model): + """ Model using blacklist mechanism for mass mailing performance. """ + _name = 'mailing.performance.blacklist' + _description = 'Mailing: blacklist performance' + _inherit = ['mail.thread.blacklist'] + _primary_email = 'email_from' # blacklist field to check + + name = fields.Char() + email_from = fields.Char() + user_id = fields.Many2one( + 'res.users', 'Responsible', + tracking=True) + container_id = fields.Many2one( + 'mail.test.container', 'Meta Container Record', + tracking=True) diff --git a/addons/test_mass_mailing/models/mass_mail_test.py b/addons/test_mass_mailing/models/mass_mail_test.py deleted file mode 100644 index 7b39c625a9a..00000000000 --- a/addons/test_mass_mailing/models/mass_mail_test.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo import api, fields, models - - -class MassMailTest(models.Model): - """ A very simple model only inheriting from mail.thread to test pure mass - mailing features and base performances. """ - _description = 'Simple Mass Mailing Model' - _name = 'mass.mail.test' - _inherit = ['mail.thread.blacklist'] - _primary_email = 'email_from' - - name = fields.Char() - email_from = fields.Char() - - -class MassMailTestBlacklist(models.Model): - """ Model using blacklist mechanism for mass mailing. """ - _description = 'Mass Mailing Model w Blacklist' - _name = 'mass.mail.test.bl' - _inherit = ['mail.thread.blacklist'] - - _primary_email = 'email_from' # blacklist field to check - - name = fields.Char() - email_from = fields.Char() - user_id = fields.Many2one( - 'res.users', 'Responsible', - tracking=True) - container_id = fields.Many2one( - 'mail.test.container', 'Meta Container Record', - tracking=True) diff --git a/addons/test_mass_mailing/security/ir.model.access.csv b/addons/test_mass_mailing/security/ir.model.access.csv index 9383184cb02..c4588843ba3 100644 --- a/addons/test_mass_mailing/security/ir.model.access.csv +++ b/addons/test_mass_mailing/security/ir.model.access.csv @@ -1,5 +1,11 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_mass_mail_test_all,mass.mail.test.all,model_mass_mail_test,,0,0,0,0 -access_mass_mail_test_user,mass.mail.test.user,model_mass_mail_test,base.group_user,1,1,1,1 -access_mass_mail_test_bl_all,mass.mail.test.bl.all,model_mass_mail_test_bl,,0,0,0,0 -access_mass_mail_test_bl_user,mass.mail.test.bl.user,model_mass_mail_test_bl,base.group_user,1,1,1,1 +access_mailing_test_simple_all,access.mailing.test.simple.all,model_mailing_test_simple,,0,0,0,0 +access_mailing_test_simple_user,access.mailing.test.simple.user,model_mailing_test_simple,base.group_user,1,1,1,1 +access_mailing_test_blacklist_all,access.mailing.test.blacklist.all,model_mailing_test_blacklist,,0,0,0,0 +access_mailing_test_blacklist_user,access.mailing.test.blacklist.user,model_mailing_test_blacklist,base.group_user,1,1,1,1 +access_mailing_test_optout_all,access.mailing.test.optout.all,model_mailing_test_optout,,0,0,0,0 +access_mailing_test_optout_user,access.mailing.test.optout.user,model_mailing_test_optout,base.group_user,1,1,1,1 +access_mailing_performance_all,access.mailing.performance.all,model_mailing_performance,,0,0,0,0 +access_mailing_performance_user,access.mailing.performance.user,model_mailing_performance,base.group_user,1,1,1,1 +access_mailing_performance_blacklist_all,access.mailing.performance.blacklist.all,model_mailing_performance_blacklist,,0,0,0,0 +access_mailing_performance_blacklist_user,access.mailing.performance.blacklist.user,model_mailing_performance_blacklist,base.group_user,1,1,1,1 diff --git a/addons/test_mass_mailing/tests/__init__.py b/addons/test_mass_mailing/tests/__init__.py index 652f56e3078..eb8c757f2ba 100644 --- a/addons/test_mass_mailing/tests/__init__.py +++ b/addons/test_mass_mailing/tests/__init__.py @@ -2,10 +2,8 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from . import test_blacklist +from . import test_blacklist_behavior from . import test_blacklist_mixin -from . import test_composer -from . import test_link -from . import test_mail_auto_blacklist -from . import test_mail_channel +from . import test_link_tracker from . import test_mass_mailing from . import test_performance diff --git a/addons/test_mass_mailing/tests/common.py b/addons/test_mass_mailing/tests/common.py index c66b92906b0..8691a4a20b9 100644 --- a/addons/test_mass_mailing/tests/common.py +++ b/addons/test_mass_mailing/tests/common.py @@ -1,17 +1,53 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.addons.mail.tests.common import mail_new_test_user -from odoo.addons.test_mail.tests import common +import datetime +import random + +from odoo.addons.mass_mailing.tests.common import TestMassMailCommon +from odoo.addons.test_mail.tests.common import TestMailCommon -class TestMailCommon(common.TestMailCommon): +class TestMassMailCommon(TestMassMailCommon, TestMailCommon): @classmethod def setUpClass(cls): - super(TestMailCommon, cls).setUpClass() + super(TestMassMailCommon, cls).setUpClass() - cls.user_marketing = mail_new_test_user( - cls.env, login='marketing', - groups='base.group_user,base.group_partner_manager,mass_mailing.group_mass_mailing_user', - name='Martial Marketing', signature='--\nMartial') + cls.mailing_bl = cls.env['mailing.mailing'].create({ + 'name': 'SourceName', + 'subject': 'MailingSubject', + 'body_html': '

Hello ${object.name}

', + 'mailing_type': 'mail', + 'mailing_model_id': cls.env['ir.model']._get('mailing.test.blacklist').id, + }) + + @classmethod + def _create_test_blacklist_records(cls, model='mailing.test.blacklist', count=1): + """ Helper to create data. Currently simple, to be improved. """ + records = cls.env[model].create([{ + 'name': 'TestRecord_%02d' % x, + 'email_from': '"TestCustomer %02d" ' % (x, x), + } for x in range(0, count)]) + return records + + @classmethod + def _create_bounce_trace(cls, record, dt=None): + if dt is None: + dt = datetime.datetime.now() - datetime.timedelta(days=1) + randomized = random.random() + if 'email_normalized' in record: + trace_email = record.email_normalized + elif 'email_from' in record: + trace_email = record.email_from + else: + trace_email = record.email + trace = cls.env['mailing.trace'].create({ + 'model': record._name, + 'res_id': record.id, + 'bounced': dt, + # TDE FIXME: improve this with a mail-enabled heuristics + 'email': trace_email, + 'message_id': '<%5f@gilbert.boitempomils>' % randomized, + }) + return trace diff --git a/addons/test_mass_mailing/tests/test_blacklist.py b/addons/test_mass_mailing/tests/test_blacklist.py index 58c7380b38d..c00a752c02e 100644 --- a/addons/test_mass_mailing/tests/test_blacklist.py +++ b/addons/test_mass_mailing/tests/test_blacklist.py @@ -6,7 +6,7 @@ from odoo.addons.test_mass_mailing.tests import common from odoo.exceptions import AccessError -class TestBLAccessRights(common.TestMailCommon): +class TestBLAccessRights(common.TestMassMailCommon): @classmethod def setUpClass(cls): @@ -46,7 +46,7 @@ class TestBLAccessRights(common.TestMailCommon): with self.assertRaises(AccessError): self.bl_rec.with_user(self.env.user).unlink() - @users('marketing') + @users('user_marketing') def test_bl_crud_marketing(self): self.env['mail.blacklist'].create([{'email': 'Arya.Stark@example.com'}]) @@ -59,7 +59,7 @@ class TestBLAccessRights(common.TestMailCommon): self.bl_rec.with_user(self.env.user).unlink() -class TestBLConsistency(common.TestMailCommon): +class TestBLConsistency(common.TestMassMailCommon): _base_list = ['Arya.Stark@example.com', 'ned.stark@example.com'] def setUp(self): @@ -70,7 +70,7 @@ class TestBLConsistency(common.TestMailCommon): self.bl_previous = self.env['mail.blacklist'].search([]) - @users('marketing') + @users('user_marketing') def test_bl_check_case_add(self): """ Test emails case when adding through _add """ bl_sudo = self.env['mail.blacklist'].sudo() @@ -83,7 +83,7 @@ class TestBLConsistency(common.TestMailCommon): self.assertEqual(existing, added) self.assertTrue(existing.active) - @users('marketing') + @users('user_marketing') def test_bl_check_case_remove(self): """ Test emails case when deactivating through _remove """ bl_sudo = self.env['mail.blacklist'].sudo() @@ -96,7 +96,7 @@ class TestBLConsistency(common.TestMailCommon): self.assertEqual(existing, added) self.assertFalse(existing.active) - @users('marketing') + @users('user_marketing') def test_bl_create_duplicate(self): """ Test emails are inserted only once if duplicated """ bl_sudo = self.env['mail.blacklist'].sudo() @@ -114,7 +114,7 @@ class TestBLConsistency(common.TestMailCommon): set(v.lower() for v in new_bl.mapped('email')) ) - @users('marketing') + @users('user_marketing') def test_bl_create_parsing(self): """ Test email is correctly extracted from given entries """ bl_sudo = self.env['mail.blacklist'].sudo() @@ -132,14 +132,15 @@ class TestBLConsistency(common.TestMailCommon): set(v.lower() for v in new_bl.mapped('email')) ) - @users('marketing') + @users('user_marketing') def test_bl_search_exact(self): search_res = self.env['mail.blacklist'].search([('email', '=', 'john.snow@example.com')]) self.assertEqual(search_res, self.bl_rec) - @users('marketing') + @users('user_marketing') def test_bl_search_parsing(self): search_res = self.env['mail.blacklist'].search([('email', '=', 'Not A Stark ')]) + self.assertEqual(search_res, self.bl_rec) search_res = self.env['mail.blacklist'].search([('email', '=', '"John J. Snow" ')]) @@ -151,12 +152,12 @@ class TestBLConsistency(common.TestMailCommon): search_res = self.env['mail.blacklist'].search([('email', '=', '"John; \"You know Nothing\" Snow" ')]) self.assertEqual(search_res, self.bl_rec) - @users('marketing') + @users('user_marketing') def test_bl_search_case(self): search_res = self.env['mail.blacklist'].search([('email', '=', 'john.SNOW@example.COM>')]) self.assertEqual(search_res, self.bl_rec) - @users('marketing') + @users('user_marketing') def test_bl_search_partial(self): search_res = self.env['mail.blacklist'].search([('email', 'ilike', 'John')]) self.assertEqual(search_res, self.bl_rec) diff --git a/addons/test_mass_mailing/tests/test_blacklist_behavior.py b/addons/test_mass_mailing/tests/test_blacklist_behavior.py new file mode 100644 index 00000000000..aa513d2a389 --- /dev/null +++ b/addons/test_mass_mailing/tests/test_blacklist_behavior.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import datetime + +from odoo.addons.test_mass_mailing.tests import common +from odoo.tests.common import users + + +class TestAutoBlacklist(common.TestMassMailCommon): + + @users('user_marketing') + def test_mailing_bounce_w_auto_bl(self): + mailing = self.mailing_bl.with_user(self.env.user) + base_parsed_values = { + 'email_from': 'toto@yaourth.com', 'to': 'tata@yaourth.com', 'message_id': '<123.321@yaourth.com>', + 'bounced_partner': self.env['res.partner'].sudo(), 'bounced_message': self.env['mail.message'].sudo() + } + + target = self._create_test_blacklist_records()[0] + # create bounced history of 4 statistics + for idx in range(4): + trace = self._create_bounce_trace(target, dt=datetime.datetime.now() - datetime.timedelta(weeks=idx+2)) + base_parsed_values.update({ + 'bounced_email': target.email_normalized, + 'bounced_msg_id': [trace.message_id], + }) + self.env['mail.thread']._routing_handle_bounce(False, base_parsed_values) + + # mass mail record: ok, not blacklisted yet + mailing.write({'mailing_domain': [('id', 'in', target.ids)]}) + mailing.action_put_in_queue() + with self.mock_mail_gateway(mail_unlink_sent=False): + mailing._process_mass_mailing_queue() + + self.assertMailTraces( + [{'email': 'test.record.00@test.example.com'}], + mailing, target, check_mail=True + ) + + # call bounced + trace = self._create_bounce_trace(target, dt=datetime.datetime.now()) + base_parsed_values.update({ + 'bounced_email': target.email_normalized, + 'bounced_msg_id': [trace.message_id], + }) + self.env['mail.thread']._routing_handle_bounce(False, base_parsed_values) + + # check blacklist + blacklist_record = self.env['mail.blacklist'].sudo().search([('email', '=', target.email_normalized)]) + self.assertEqual(len(blacklist_record), 1) + self.assertTrue(target.is_blacklisted) + + # mass mail record: ko, blacklisted + new_mailing = mailing.copy() + new_mailing.write({'mailing_domain': [('id', 'in', target.ids)]}) + new_mailing.action_put_in_queue() + with self.mock_mail_gateway(mail_unlink_sent=False): + new_mailing._process_mass_mailing_queue() + self.assertMailTraces( + [{'email': 'test.record.00@test.example.com', 'state': 'ignored'}], + new_mailing, target, check_mail=True + ) diff --git a/addons/test_mass_mailing/tests/test_blacklist_mixin.py b/addons/test_mass_mailing/tests/test_blacklist_mixin.py index 01f95496f6f..57504fb5a3c 100644 --- a/addons/test_mass_mailing/tests/test_blacklist_mixin.py +++ b/addons/test_mass_mailing/tests/test_blacklist_mixin.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo.addons.test_mass_mailing.models.mailing_models import MailingBLacklist from odoo.addons.test_mass_mailing.tests import common -from odoo.addons.test_mass_mailing.models.mass_mail_test import MassMailTestBlacklist from odoo.exceptions import UserError from odoo.tests.common import users -class TestBLMixin(common.TestMailCommon): +class TestBLMixin(common.TestMassMailCommon): @classmethod def setUpClass(cls): @@ -23,49 +23,49 @@ class TestBLMixin(common.TestMailCommon): @users('employee') def test_bl_mixin_primary_field_consistency(self): - MassMailTestBlacklist._primary_email = 'not_a_field' + MailingBLacklist._primary_email = 'not_a_field' with self.assertRaises(UserError): - self.env['mass.mail.test.bl'].search([('is_blacklisted', '=', False)]) + self.env['mailing.test.blacklist'].search([('is_blacklisted', '=', False)]) - MassMailTestBlacklist._primary_email = ['not_a_str'] + MailingBLacklist._primary_email = ['not_a_str'] with self.assertRaises(UserError): - self.env['mass.mail.test.bl'].search([('is_blacklisted', '=', False)]) + self.env['mailing.test.blacklist'].search([('is_blacklisted', '=', False)]) - MassMailTestBlacklist._primary_email = 'email_from' - self.env['mass.mail.test.bl'].search([('is_blacklisted', '=', False)]) + MailingBLacklist._primary_email = 'email_from' + self.env['mailing.test.blacklist'].search([('is_blacklisted', '=', False)]) @users('employee') def test_bl_mixin_is_blacklisted(self): """ Test is_blacklisted field computation """ - record = self.env['mass.mail.test.bl'].create({'email_from': 'arya.stark@example.com'}) + record = self.env['mailing.test.blacklist'].create({'email_from': 'arya.stark@example.com'}) self.assertTrue(record.is_blacklisted) - record = self.env['mass.mail.test.bl'].create({'email_from': 'not.arya.stark@example.com'}) + record = self.env['mailing.test.blacklist'].create({'email_from': 'not.arya.stark@example.com'}) self.assertFalse(record.is_blacklisted) @users('employee') def test_bl_mixin_search_blacklisted(self): """ Test is_blacklisted field search implementation """ - record1 = self.env['mass.mail.test.bl'].create({'email_from': 'arya.stark@example.com'}) - record2 = self.env['mass.mail.test.bl'].create({'email_from': 'not.arya.stark@example.com'}) + record1 = self.env['mailing.test.blacklist'].create({'email_from': 'arya.stark@example.com'}) + record2 = self.env['mailing.test.blacklist'].create({'email_from': 'not.arya.stark@example.com'}) - search_res = self.env['mass.mail.test.bl'].search([('is_blacklisted', '=', False)]) + search_res = self.env['mailing.test.blacklist'].search([('is_blacklisted', '=', False)]) self.assertEqual(search_res, record2) - search_res = self.env['mass.mail.test.bl'].search([('is_blacklisted', '!=', True)]) + search_res = self.env['mailing.test.blacklist'].search([('is_blacklisted', '!=', True)]) self.assertEqual(search_res, record2) - search_res = self.env['mass.mail.test.bl'].search([('is_blacklisted', '=', True)]) + search_res = self.env['mailing.test.blacklist'].search([('is_blacklisted', '=', True)]) self.assertEqual(search_res, record1) - search_res = self.env['mass.mail.test.bl'].search([('is_blacklisted', '!=', False)]) + search_res = self.env['mailing.test.blacklist'].search([('is_blacklisted', '!=', False)]) self.assertEqual(search_res, record1) @users('employee') def test_bl_mixin_search_blacklisted_format(self): """ Test is_blacklisted field search using email parsing """ - record1 = self.env['mass.mail.test.bl'].create({'email_from': 'Arya Stark '}) + record1 = self.env['mailing.test.blacklist'].create({'email_from': 'Arya Stark '}) self.assertTrue(record1.is_blacklisted) - search_res = self.env['mass.mail.test.bl'].search([('is_blacklisted', '=', True)]) + search_res = self.env['mailing.test.blacklist'].search([('is_blacklisted', '=', True)]) self.assertEqual(search_res, record1) diff --git a/addons/test_mass_mailing/tests/test_composer.py b/addons/test_mass_mailing/tests/test_composer.py deleted file mode 100644 index 2b43e87e6d9..00000000000 --- a/addons/test_mass_mailing/tests/test_composer.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo.addons.test_mass_mailing.tests import common - - -class TestComposer(common.TestMailCommon): - - def test_body_responsive(self): - """ Testing mail mailing responsive mail body """ - test_record = self.env['res.partner'].create({'name': 'Mass Mail Partner'}) - mass_mail_record = self.env['mailing.mailing'].with_user(self.user_marketing).create({ - 'name': 'Test', - 'subject': 'Test', - 'state': 'draft', - 'mailing_model_id': self.env.ref('base.model_res_partner').id, - }) - - composer = self.env['mail.compose.message'].with_user(self.user_marketing).with_context({ - 'default_composition_mode': 'mass_mail', - 'default_model': 'res.partner', - 'default_res_id': test_record.id, - }).create({ - 'subject': 'Mass Mail Responsive', - 'body': 'I am Responsive body', - 'mass_mailing_id': mass_mail_record.id - }) - - mail_values = composer.get_mail_values([test_record.id]) - body_html = str(mail_values[test_record.id]['body_html']) - - self.assertIn('', body_html) - self.assertIn('', body_html) - self.assertIn('viewport', body_html) - self.assertIn('@media', body_html) - self.assertIn('I am Responsive body', body_html) diff --git a/addons/test_mass_mailing/tests/test_link.py b/addons/test_mass_mailing/tests/test_link_tracker.py similarity index 96% rename from addons/test_mass_mailing/tests/test_link.py rename to addons/test_mass_mailing/tests/test_link_tracker.py index 6e5efae85e3..df2a23ae739 100644 --- a/addons/test_mass_mailing/tests/test_link.py +++ b/addons/test_mass_mailing/tests/test_link_tracker.py @@ -5,7 +5,7 @@ from odoo.tests.common import users from odoo.addons.test_mass_mailing.tests import common -class TestLinkTracker(common.TestMailCommon): +class TestLinkTracker(common.TestMassMailCommon): def setUp(self): super(TestLinkTracker, self).setUp() @@ -43,7 +43,7 @@ class TestLinkTracker(common.TestMailCommon): self.assertEqual(click, None) self.assertEqual(self.link.count, 2) - @users('marketing') + @users('user_marketing') def test_add_link_mail_stat(self): mailing = self.env['mailing.mailing'].create({'name': 'Test Mailing', "subject": "Hi!"}) code = self.link.code diff --git a/addons/test_mass_mailing/tests/test_mail_auto_blacklist.py b/addons/test_mass_mailing/tests/test_mail_auto_blacklist.py deleted file mode 100644 index af794593503..00000000000 --- a/addons/test_mass_mailing/tests/test_mail_auto_blacklist.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -import datetime - -from odoo import tools -from odoo.tests import common - - -class TestAutoBlacklist(common.TransactionCase): - - def test_mail_bounced_auto_blacklist(self): - mass_mailing_contacts = self.env['mailing.contact'] - mass_mailing = self.env['mailing.mailing'] - mail_blacklist = self.env['mail.blacklist'] - mail_statistics = self.env['mailing.trace'] - - # create mailing contact record - self.mailing_contact_1 = mass_mailing_contacts.create({'name': 'test email 1', 'email': 'Test1@email.com'}) - - base_parsed_values = { - 'email_from': 'toto@yaourth.com', 'to': 'tata@yaourth.com', 'message_id': '<123.321@yaourth.com>', - 'bounced_partner': self.env['res.partner'].sudo(), 'bounced_message': self.env['mail.message'].sudo() - } - - # create bounced history of 4 statistics - for idx in range(4): - mail_statistics.create({ - 'model': 'mailing.contact', - 'res_id': self.mailing_contact_1.id, - 'bounced': datetime.datetime.now() - datetime.timedelta(weeks=idx+2), - 'email': self.mailing_contact_1.email, - 'message_id': '<123.00%s@iron.sky>' % idx, - }) - base_parsed_values.update({ - 'bounced_email': tools.email_normalize(self.mailing_contact_1.email), - 'bounced_msg_id': ['<123.00%s@iron.sky>' % idx] - }) - self.env['mail.thread']._routing_handle_bounce(False, base_parsed_values) - - # create mass mailing record - self.mass_mailing = mass_mailing.create({ - 'name': 'test', - 'subject': 'Booooounce!', - 'mailing_domain': [('id', 'in', - [self.mailing_contact_1.id])], - 'body_html': 'This is a bounced mail for auto blacklist demo'}) - self.mass_mailing.action_put_in_queue() - res_ids = self.mass_mailing._get_remaining_recipients() - composer_values = { - 'body': self.mass_mailing.convert_links()[self.mass_mailing.id], - 'subject': self.mass_mailing.name, - 'model': self.mass_mailing.mailing_model_real, - 'email_from': self.mass_mailing.email_from, - 'composition_mode': 'mass_mail', - 'mass_mailing_id': self.mass_mailing.id, - 'mailing_list_ids': [(4, l.id) for l in self.mass_mailing.contact_list_ids], - } - composer = self.env['mail.compose.message'].with_context( - active_ids=res_ids, - mass_mailing_seen_list=self.mass_mailing._get_seen_list() - ).create(composer_values) - composer.send_mail() - - mail_statistics.create({ - 'model': 'mailing.contact', - 'res_id': self.mailing_contact_1.id, - 'bounced': datetime.datetime.now(), - 'email': self.mailing_contact_1.email, - 'message_id': '<123.004@iron.sky>', - }) - base_parsed_values.update({ - 'bounced_email': tools.email_normalize(self.mailing_contact_1.email), - 'bounced_msg_id': ['<123.004@iron.sky>'] - }) - # call bounced - self.env['mail.thread']._routing_handle_bounce(False, base_parsed_values) - - # check blacklist - blacklist_record = mail_blacklist.search([('email', '=', self.mailing_contact_1.email)]) - self.assertEqual(len(blacklist_record), 1, - 'The email %s must be blacklisted' % self.mailing_contact_1.email) diff --git a/addons/test_mass_mailing/tests/test_mail_channel.py b/addons/test_mass_mailing/tests/test_mail_channel.py deleted file mode 100644 index c5b903ff94d..00000000000 --- a/addons/test_mass_mailing/tests/test_mail_channel.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from odoo.addons.test_mail.tests import common -from odoo.tools import formataddr - - -class TestChannelPartnersNotification(common.TestMailCommon): - - def _join_channel(self, channel, partners): - for partner in partners: - channel.write({'channel_last_seen_partner_ids': [(0, 0, {'partner_id': partner.id})]}) - channel.invalidate_cache() - - def test_channel_blacklisted_recipients(self): - """ Posting a message on a channel should send one email to all recipients, except the blacklisted ones """ - - self.test_channel = self.env['mail.channel'].create({ - 'name': 'Test', - 'description': 'Description', - 'alias_name': 'test', - 'public': 'public', - }) - self.test_partner = self.env['res.partner'].create({ - 'name': 'Test Partner', - 'email': 'test@example.com', - }) - - self.blacklisted_partner = self.env['res.partner'].create({ - 'name': 'Blacklisted Partner', - 'email': 'test@black.list', - }) - - # Set Blacklist - self.env['mail.blacklist'].create({ - 'email': 'test@black.list', - }) - - self.env['ir.config_parameter'].set_param('mail.catchall.domain', 'schlouby.fr') - self.test_channel.write({'email_send': True}) - self._join_channel(self.test_channel, self.test_partner) - with self.mock_mail_gateway(): - self.test_channel.message_post(body="Test", message_type='comment', subtype_xmlid='mail.mt_comment') - - self.assertEqual(len(self._mails), 1, 'Number of mail incorrect. Should be equal to 1.') - for email in self._mails: - self.assertEqual( - set(email['email_to']), - set([formataddr((self.test_partner.name, self.test_partner.email))]), - 'email_to incorrect. Should be equal to "%s"' % ( - formataddr((self.test_partner.name, self.test_partner.email)))) diff --git a/addons/test_mass_mailing/tests/test_mass_mailing.py b/addons/test_mass_mailing/tests/test_mass_mailing.py index 47d372f986a..478f9ce061d 100644 --- a/addons/test_mass_mailing/tests/test_mass_mailing.py +++ b/addons/test_mass_mailing/tests/test_mass_mailing.py @@ -1,313 +1,126 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from werkzeug import urls - -from odoo.addons.test_mass_mailing.tests.common import TestMailCommon -from odoo.tests.common import TransactionCase, users +from odoo.addons.test_mass_mailing.tests.common import TestMassMailCommon +from odoo.tests.common import users from odoo.tools import mute_logger -class TestMassMail(TestMailCommon): +class TestMassMailing(TestMassMailCommon): - def setUp(self): - """ In this setup we prepare 20 blacklist entries. We therefore add - 20 recipients compared to first test in order to have comparable results. """ - super(TestMassMail, self).setUp() - values = [{ - 'name': 'Recipient %s' % x, - 'email_from': 'Recipient ' % x, - } for x in range(0, 6)] - self.mm_recs = self.env['mass.mail.test.bl'].create(values) + @classmethod + def setUpClass(cls): + super(TestMassMailing, cls).setUpClass() - self.env['mail.blacklist'].create({ - 'email': 'rec.2@example.com' + @users('user_marketing') + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_mailing_w_blacklist(self): + mailing = self.mailing_bl.with_user(self.env.user) + recipients = self._create_test_blacklist_records(count=5) + + # blacklist records 3 and 4 + self.env['mail.blacklist'].create({'email': recipients[3].email_normalized}) + self.env['mail.blacklist'].create({'email': recipients[4].email_normalized}) + + mailing.write({'mailing_domain': [('id', 'in', recipients.ids)]}) + mailing.action_put_in_queue() + with self.mock_mail_gateway(mail_unlink_sent=False): + mailing._process_mass_mailing_queue() + + self.assertMailTraces( + [{'email': 'test.record.00@test.example.com'}, + {'email': 'test.record.01@test.example.com'}, + {'email': 'test.record.02@test.example.com'}, + {'email': 'test.record.03@test.example.com', 'state': 'ignored'}, + {'email': 'test.record.04@test.example.com', 'state': 'ignored'}], + mailing, recipients, check_mail=True + ) + self.assertEqual(mailing.ignored, 2) + + @users('user_marketing') + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_mailing_w_opt_out(self): + mailing = self.mailing_bl.with_user(self.env.user) + recipients = self._create_test_blacklist_records(model='mailing.test.optout', count=5) + + # optout records 0 and 1 + (recipients[0] | recipients[1]).write({'opt_out': True}) + # blacklist records 4 + self.env['mail.blacklist'].create({'email': recipients[4].email_normalized}) + + mailing.write({ + 'mailing_model_id': self.env['ir.model']._get('mailing.test.optout'), + 'mailing_domain': [('id', 'in', recipients.ids)] }) + mailing.action_put_in_queue() + with self.mock_mail_gateway(mail_unlink_sent=False): + mailing._process_mass_mailing_queue() - self.test_medium = self.env['utm.medium'].create({'name': 'TestMedium'}) + self.assertMailTraces( + [{'email': 'test.record.00@test.example.com', 'state': 'ignored'}, + {'email': 'test.record.01@test.example.com', 'state': 'ignored'}, + {'email': 'test.record.02@test.example.com'}, + {'email': 'test.record.03@test.example.com'}, + {'email': 'test.record.04@test.example.com', 'state': 'ignored'}], + mailing, recipients, check_mail=True + ) + self.assertEqual(mailing.ignored, 3) - @users('marketing') - @mute_logger('odoo.addons.mail.models.mail_mail', 'odoo.models.unlink') - def test_link_tracker(self): - _url = 'https://www.example.com/foo/bar?baz=qux' - mailing = self.env['mailing.mailing'].create({ - 'name': 'TestMailing', - 'subject': 'Test', - 'medium_id': self.test_medium.id, - 'body_html': '

Hello ${object.name}Unsubscribe

' % _url, - 'reply_to_mode': 'email', - 'mailing_model_id': self.ref('test_mass_mailing.model_mass_mail_test_bl'), - 'mailing_domain': [('id', 'in', self.mm_recs.ids)], - }) - - mailing.action_send_mail() - - # basic test emails are sent - self.assertEqual(mailing.sent, 5) - self.assertEqual(mailing.delivered, 5) - - # link trackers - links = self.env['link.tracker'].sudo().search([('mass_mailing_id', '=', mailing.id)]) - self.assertEqual(len(links), 1) - self.assertEqual(links.mapped('url'), [_url]) - # check UTMS are correctly set on redirect URL - redirect_url = urls.url_parse(links.redirected_url) - redirect_params = redirect_url.decode_query().to_dict(flat=True) - self.assertEqual(redirect_url.scheme, 'https') - self.assertEqual(redirect_url.decode_netloc(), 'www.example.com') - self.assertEqual(redirect_url.path, '/foo/bar') - self.assertEqual(redirect_params, { - 'utm_source': mailing.name, - 'utm_medium': self.test_medium.name, - 'baz': 'qux', - }) - - -class TestAccessRights(TransactionCase): - - def test_01_mass_mail_blacklist(self): - mass_mailing_contacts = self.env['mailing.contact'] - mass_mailing = self.env['mailing.mailing'] - mail_blacklist = self.env['mail.blacklist'] - - # create mailing contact record - self.mailing_contact_1 = mass_mailing_contacts.create({'name': 'test email 1', 'email': 'test1@email.com'}) - self.mailing_contact_2 = mass_mailing_contacts.create({'name': 'test email 2', 'email': 'test2@email.com'}) - self.mailing_contact_3 = mass_mailing_contacts.create({'name': 'test email 3', 'email': 'test3@email.com'}) - self.mailing_contact_4 = mass_mailing_contacts.create({'name': 'test email 4', 'email': 'test4@email.com'}) - self.mailing_contact_5 = mass_mailing_contacts.create({'name': 'test email 5', 'email': 'test5@email.com'}) - - # create blacklist record - mail_blacklist.create({'email': self.mailing_contact_3.email}) - mail_blacklist.create({'email': self.mailing_contact_4.email}) - - # create mass mailing record - self.mass_mailing = mass_mailing.create({ - 'name': 'test', - 'subject': 'Blacklisted', - 'mailing_domain': [('id', 'in', - [self.mailing_contact_1.id, self.mailing_contact_2.id, self.mailing_contact_3.id, - self.mailing_contact_4.id, self.mailing_contact_5.id])], - 'body_html': 'This is mass mail marketing demo'}) - self.mass_mailing.action_put_in_queue() - res_ids = self.mass_mailing._get_remaining_recipients() - composer_values = { - 'body': self.mass_mailing.convert_links()[self.mass_mailing.id], - 'subject': self.mass_mailing.name, - 'model': self.mass_mailing.mailing_model_real, - 'email_from': self.mass_mailing.email_from, - 'composition_mode': 'mass_mail', - 'mass_mailing_id': self.mass_mailing.id, - 'mailing_list_ids': [(4, l.id) for l in self.mass_mailing.contact_list_ids], - } - composer = self.env['mail.compose.message'].with_context(active_ids=res_ids, - mass_mailing_seen_list=self.mass_mailing._get_seen_list()).create( - composer_values) - composer.send_mail() - self.assertEqual(self.mass_mailing.ignored, 2, - 'blacklist ignored email number incorrect, should be equals to 2') - - def test_02_mass_mail_simple_opt_out(self): - mass_mailing_contacts = self.env['mailing.contact'] - mass_mailing_lists = self.env['mailing.list'] - mass_mailing_optout = self.env['mailing.contact.subscription'] - mass_mailing = self.env['mailing.mailing'] - - # create mailing contact record - mailing_contact_1 = mass_mailing_contacts.create({'name': 'test email 1', 'email': 'test1@email.com'}) - mailing_contact_2 = mass_mailing_contacts.create({'name': 'test email 2', 'email': 'test2@email.com'}) + @users('user_marketing') + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_mailing_mailing_list_optout(self): + """ Test mailing list model specific optout behavior """ + mailing_contact_1 = self.env['mailing.contact'].create({'name': 'test 1A', 'email': 'test@test.example.com'}) + mailing_contact_2 = self.env['mailing.contact'].create({'name': 'test 1B', 'email': 'test@test.example.com'}) + mailing_contact_3 = self.env['mailing.contact'].create({'name': 'test 3', 'email': 'test3@test.example.com'}) + mailing_contact_4 = self.env['mailing.contact'].create({'name': 'test 4', 'email': 'test4@test.example.com'}) + mailing_contact_5 = self.env['mailing.contact'].create({'name': 'test 5', 'email': 'test5@test.example.com'}) # create mailing list record - mailing_list_1 = mass_mailing_lists.create({ + mailing_list_1 = self.env['mailing.list'].create({ 'name': 'A', 'contact_ids': [ (4, mailing_contact_1.id), - (4, mailing_contact_2.id) + (4, mailing_contact_2.id), + (4, mailing_contact_3.id), + (4, mailing_contact_5.id), ] }) - - # Set Opt out - mass_mailing_optout.search([('contact_id', '=', mailing_contact_1.id), ('list_id', '=', mailing_list_1.id)]).write({ - 'opt_out': True, - }) - - # create mass mailing record - self.mass_mailing = mass_mailing.create({ - 'name': 'One', - 'subject': 'One', - 'mailing_model_id': self.env['ir.model']._get('mailing.contact').id, - 'body_html': 'This is mass mail marketing demo'}) - self.mass_mailing.contact_list_ids = [mailing_list_1.id] - self.mass_mailing.action_put_in_queue() - composer_values = { - 'body': self.mass_mailing.convert_links()[self.mass_mailing.id], - 'subject': self.mass_mailing.name, - 'model': self.mass_mailing.mailing_model_real, - 'email_from': self.mass_mailing.email_from, - 'composition_mode': 'mass_mail', - 'mass_mailing_id': self.mass_mailing.id, - 'mailing_list_ids': [(4, l.id) for l in self.mass_mailing.contact_list_ids], - } - composer = self.env['mail.compose.message'].with_context( - active_ids=[mailing_contact_1.id, mailing_contact_2.id], - mass_mailing_seen_list=self.mass_mailing._get_seen_list(), - mass_mailing_opt_out_list=self.mass_mailing._get_opt_out_list()).create(composer_values) - composer.send_mail() - self.assertEqual(self.mass_mailing.ignored, 1, - 'Opt Out ignored email number incorrect, should be equals to 1') - - def test_03_mass_mail_multi_opt_out(self): - mass_mailing_contacts = self.env['mailing.contact'] - mass_mailing_lists = self.env['mailing.list'] - mass_mailing_optout = self.env['mailing.contact.subscription'] - mass_mailing = self.env['mailing.mailing'] - - # create mailing contact record - mailing_contact_1 = mass_mailing_contacts.create({'name': 'test email 1', 'email': 'test1@email.com'}) - mailing_contact_2 = mass_mailing_contacts.create({'name': 'test email 2', 'email': 'test2@email.com'}) - - # create mailing list record - mailing_list_1 = mass_mailing_lists.create({ - 'name': 'A', - 'contact_ids': [ - (4, mailing_contact_1.id), - (4, mailing_contact_2.id) - ] - }) - mailing_list_2 = mass_mailing_lists.create({ + mailing_list_2 = self.env['mailing.list'].create({ 'name': 'B', 'contact_ids': [ - (4, mailing_contact_1.id), - (4, mailing_contact_2.id) + (4, mailing_contact_3.id), + (4, mailing_contact_4.id), ] }) - - # Set Opt out - mass_mailing_optout.search([('contact_id', '=', mailing_contact_1.id), ('list_id', '=', mailing_list_1.id)]).write({ - 'opt_out': True, - }) + # contact_1 is optout but same email is not optout from the same list + # contact 3 is optout in list 1 but not in list 2 + # contact 5 is optout + Sub = self.env['mailing.contact.subscription'] + Sub.search([('contact_id', '=', mailing_contact_1.id), ('list_id', '=', mailing_list_1.id)]).write({'opt_out': True}) + Sub.search([('contact_id', '=', mailing_contact_3.id), ('list_id', '=', mailing_list_1.id)]).write({'opt_out': True}) + Sub.search([('contact_id', '=', mailing_contact_5.id), ('list_id', '=', mailing_list_1.id)]).write({'opt_out': True}) # create mass mailing record - self.mass_mailing = mass_mailing.create({ - 'name': 'One', - 'subject': 'One', - 'mailing_model_id': self.env['ir.model']._get('mailing.contact').id, - 'body_html': 'This is mass mail marketing demo'}) - self.mass_mailing.contact_list_ids = [mailing_list_1.id, mailing_list_2.id] - self.mass_mailing.action_put_in_queue() - composer_values = { - 'body': self.mass_mailing.convert_links()[self.mass_mailing.id], - 'subject': self.mass_mailing.name, - 'model': self.mass_mailing.mailing_model_real, - 'email_from': self.mass_mailing.email_from, - 'composition_mode': 'mass_mail', - 'mass_mailing_id': self.mass_mailing.id, - 'mailing_list_ids': [(4, l.id) for l in self.mass_mailing.contact_list_ids], - } - composer = self.env['mail.compose.message'].with_context( - active_ids=[mailing_contact_1.id, mailing_contact_2.id], - mass_mailing_seen_list=self.mass_mailing._get_seen_list(), - mass_mailing_opt_out_list=self.mass_mailing._get_opt_out_list()).create(composer_values) - composer.send_mail() - # if user is opt_out on One list but not on another, send the mail anyway - self.assertEqual(self.mass_mailing.ignored, 0, - 'Opt Out ignored email number incorrect, should be equals to 0') - - def test_04_mass_mail_multi_users_different_opt_out(self): - mass_mailing_contacts = self.env['mailing.contact'] - mass_mailing_lists = self.env['mailing.list'] - mass_mailing_optout = self.env['mailing.contact.subscription'] - mass_mailing = self.env['mailing.mailing'] - - # create mailing contact record - mailing_contact_1 = mass_mailing_contacts.create({'name': 'test email (A)', 'email': 'test@email.com'}) - mailing_contact_2 = mass_mailing_contacts.create({'name': 'test email (B)', 'email': 'test@email.com'}) - - # create mailing list record - mailing_list_1 = mass_mailing_lists.create({ - 'name': 'A', - 'contact_ids': [ - (4, mailing_contact_1.id), - (4, mailing_contact_2.id) - ] + mailing = self.env['mailing.mailing'].create({ + 'name': 'SourceName', + 'subject': 'MailingSubject', + 'body_html': '

Hello ${object.name}

', + 'mailing_model_id': self.env['ir.model']._get('mailing.list').id, + 'contact_list_ids': [(4, ml.id) for ml in mailing_list_1 | mailing_list_2], }) + mailing.action_put_in_queue() + with self.mock_mail_gateway(mail_unlink_sent=False): + mailing._process_mass_mailing_queue() - # Set Opt out - mass_mailing_optout.search([('contact_id', '=', mailing_contact_1.id), ('list_id', '=', mailing_list_1.id)]).write({ - 'opt_out': True, - }) - - # create mass mailing record - self.mass_mailing = mass_mailing.create({ - 'name': 'One', - 'subject': 'One', - 'mailing_model_id': self.env['ir.model']._get('mailing.contact').id, - 'body_html': 'This is mass mail marketing demo'}) - self.mass_mailing.contact_list_ids = [mailing_list_1.id] - self.mass_mailing.action_put_in_queue() - composer_values = { - 'body': self.mass_mailing.convert_links()[self.mass_mailing.id], - 'subject': self.mass_mailing.name, - 'model': self.mass_mailing.mailing_model_real, - 'email_from': self.mass_mailing.email_from, - 'composition_mode': 'mass_mail', - 'mass_mailing_id': self.mass_mailing.id, - 'mailing_list_ids': [(4, l.id) for l in self.mass_mailing.contact_list_ids], - } - composer = self.env['mail.compose.message'].with_context( - active_ids=[mailing_contact_1.id, mailing_contact_2.id], - mass_mailing_seen_list=self.mass_mailing._get_seen_list(), - mass_mailing_opt_out_list=self.mass_mailing._get_opt_out_list()).create(composer_values) - composer.send_mail() - # if user A is opt_out on One list but user B is not opt_out on same list, - # send the mail anyway to the opt-in contact. Ignore (as normal behaviour) opted-out contact. - self.assertEqual(self.mass_mailing.ignored, 1, - 'Opt Out ignored email number incorrect, should be equals to 1') - - -class TestOnResPartner(TransactionCase): - - def test_mass_mail_on_res_partner(self): - partners = self.env['res.partner'] - mass_mailing = self.env['mailing.mailing'] - - # create mailing contact record - partner_a = partners.create({ - 'name': 'test email 1', - 'email': 'test1@email.com', - }) - partner_b = partners.create({ - 'name': 'test email 2', - 'email': 'test2@email.com', - }) - - # Set Blacklist - self.blacklist_contact_entry = self.env['mail.blacklist'].create({ - 'email': 'Test2@email.com', - }) - - # create mass mailing record - self.mass_mailing = mass_mailing.create({ - 'name': 'One', - 'subject': 'One', - 'mailing_domain': [('id', 'in', [partner_a.id, partner_b.id])], - 'body_html': 'This is mass mail marketing demo'}) - self.mass_mailing.mailing_model_real = 'res.partner' - self.mass_mailing.action_put_in_queue() - res_ids = self.mass_mailing._get_remaining_recipients() - composer_values = { - 'body': self.mass_mailing.convert_links()[self.mass_mailing.id], - 'subject': self.mass_mailing.name, - 'model': self.mass_mailing.mailing_model_real, - 'email_from': self.mass_mailing.email_from, - 'composition_mode': 'mass_mail', - 'mass_mailing_id': self.mass_mailing.id, - 'mailing_list_ids': [(4, l.id) for l in self.mass_mailing.contact_list_ids], - } - composer = self.env['mail.compose.message'].with_context( - active_ids=res_ids, - mass_mailing_seen_list=self.mass_mailing._get_seen_list()).create(composer_values) - composer.send_mail() - # if user is opt_out on One list but not on another, send the mail anyway - self.assertEqual(self.mass_mailing.ignored, 1, - 'Blacklisted ignored email number incorrect, should be equals to 1') + self.assertMailTraces( + [{'email': 'test@test.example.com', 'state': 'ignored'}, + {'email': 'test@test.example.com', 'state': 'sent'}, + {'email': 'test3@test.example.com'}, + {'email': 'test4@test.example.com'}, + {'email': 'test5@test.example.com', 'state': 'ignored'}], + mailing, + mailing_contact_1 | mailing_contact_2 | mailing_contact_3 | mailing_contact_4 | mailing_contact_5, + check_mail=True + ) + self.assertEqual(mailing.ignored, 2) diff --git a/addons/test_mass_mailing/tests/test_performance.py b/addons/test_mass_mailing/tests/test_performance.py index 44a5545e876..956db8969e7 100644 --- a/addons/test_mass_mailing/tests/test_performance.py +++ b/addons/test_mass_mailing/tests/test_performance.py @@ -35,7 +35,7 @@ class TestMassMailPerformance(TestMassMailPerformanceBase): 'name': 'Recipient %s' % x, 'email_from': 'Recipient ' % x, } for x in range(0, 50)] - self.mm_recs = self.env['mass.mail.test'].create(values) + self.mm_recs = self.env['mailing.performance'].create(values) @users('__system__', 'marketing') @warmup @@ -46,7 +46,7 @@ class TestMassMailPerformance(TestMassMailPerformanceBase): 'subject': 'Test', 'body_html': '

Hello quuxUnsubscribe

', 'reply_to_mode': 'email', - 'mailing_model_id': self.ref('test_mass_mailing.model_mass_mail_test'), + 'mailing_model_id': self.ref('test_mass_mailing.model_mailing_performance'), 'mailing_domain': [('id', 'in', self.mm_recs.ids)], }) @@ -69,13 +69,13 @@ class TestMassMailBlPerformance(TestMassMailPerformanceBase): 'name': 'Recipient %s' % x, 'email_from': 'Recipient ' % x, } for x in range(0, 62)] - self.mm_recs = self.env['mass.mail.test.bl'].create(values) + self.mm_recs = self.env['mailing.performance.blacklist'].create(values) for x in range(1, 13): self.env['mail.blacklist'].create({ 'email': 'rec.%s@example.com' % (x * 5) }) - self.env['mass.mail.test.bl'].flush() + self.env['mailing.performance.blacklist'].flush() @users('__system__', 'marketing') @warmup @@ -86,7 +86,7 @@ class TestMassMailBlPerformance(TestMassMailPerformanceBase): 'subject': 'Test', 'body_html': '

Hello quuxUnsubscribe

', 'reply_to_mode': 'email', - 'mailing_model_id': self.ref('test_mass_mailing.model_mass_mail_test_bl'), + 'mailing_model_id': self.ref('test_mass_mailing.model_mailing_performance_blacklist'), 'mailing_domain': [('id', 'in', self.mm_recs.ids)], })