summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibault Delavallée <tde@odoo.com>2020-04-23 11:54:39 +0000
committerThibault Delavallée <tde@odoo.com>2020-04-24 15:35:43 +0000
commit7946b42ef546260f47566cd356eab5a911beff7a (patch)
treec0e29a5d7015f1006c80f160ff6adac6989df5c7
parent97214888173a830425616ceafb18e5f394b65c5c (diff)
[IMP] link_tracker, (test_)mass_mailing: improve test tools and clean existing tests
URPOSE Prepare code cleaning and optimization in mail, mass_mailing and SMS by cleaning models for readability and code complexity and footprint reduction. SPECIFICATIONS Add tool methods and asserts for link tracker tests. Add tool methods and assets for mass mailing tests, notably about mailing traces and their link with emails. Merge existing and duplicated tests and rewrite them a bit. Rename and improve test_mass_mailing models. LINKS Prepares task ID 2238597 (notification and trace models cleaning) Task ID 1906925 (mass mailing tests cleaning) PR #50169 Related: odoo/enterprise#10180 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
-rw-r--r--addons/link_tracker/tests/__init__.py4
-rw-r--r--addons/link_tracker/tests/common.py71
-rw-r--r--addons/mass_mailing/tests/__init__.py3
-rw-r--r--addons/mass_mailing/tests/common.py109
-rw-r--r--addons/mass_mailing/tests/test_mailing_internals.py177
-rw-r--r--addons/mass_mailing/tests/test_mailing_list.py (renamed from addons/mass_mailing/tests/test_mass_mailing_list_merge.py)41
-rw-r--r--addons/mass_mailing/tests/test_mass_mailing_shortener.py122
-rw-r--r--addons/mass_mailing_sms/tests/test_mailing_internals.py2
-rw-r--r--addons/test_mail_full/tests/common.py2
-rw-r--r--addons/test_mail_full/tests/test_mass_sms.py8
-rw-r--r--addons/test_mass_mailing/models/__init__.py3
-rw-r--r--addons/test_mass_mailing/models/mailing_mailing.py27
-rw-r--r--addons/test_mass_mailing/models/mailing_models.py71
-rw-r--r--addons/test_mass_mailing/models/mass_mail_test.py34
-rw-r--r--addons/test_mass_mailing/security/ir.model.access.csv14
-rw-r--r--addons/test_mass_mailing/tests/__init__.py6
-rw-r--r--addons/test_mass_mailing/tests/common.py52
-rw-r--r--addons/test_mass_mailing/tests/test_blacklist.py23
-rw-r--r--addons/test_mass_mailing/tests/test_blacklist_behavior.py63
-rw-r--r--addons/test_mass_mailing/tests/test_blacklist_mixin.py36
-rw-r--r--addons/test_mass_mailing/tests/test_composer.py36
-rw-r--r--addons/test_mass_mailing/tests/test_link_tracker.py (renamed from addons/test_mass_mailing/tests/test_link.py)4
-rw-r--r--addons/test_mass_mailing/tests/test_mail_auto_blacklist.py82
-rw-r--r--addons/test_mass_mailing/tests/test_mail_channel.py51
-rw-r--r--addons/test_mass_mailing/tests/test_mass_mailing.py397
-rw-r--r--addons/test_mass_mailing/tests/test_performance.py10
26 files changed, 737 insertions, 711 deletions
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 <test.alias@test.mycompany.com>'
+
+ @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 <test.alias@test.mycompany.com>'
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 <test.customer@example.com>',
+ })
+ 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('<!DOCTYPE html>', body_html)
+ self.assertIn('<head>', 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': """<div>
+Hi,
+% set url = "www.odoo.com"
+% set httpurl = "https://www.odoo.eu"
+Website0: <a id="url0" href="https://www.odoo.tz/my/${object.name}">https://www.odoo.tz/my/${object.name}</a>
+Website1: <a id="url1" href="https://www.odoo.be">https://www.odoo.be</a>
+Website2: <a id="url2" href="https://${url}">https://${url}</a>
+Website3: <a id="url3" href="${httpurl}">${httpurl}</a>
+External1: <a id="url4" href="https://www.example.com/foo/bar?baz=qux">Youpie</a>
+Email: <a id="url5" href="mailto:test@odoo.com">test@odoo.com</a></div>""",
+ '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
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 <admin@yourcompany.example.com>",
- "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: <a id="url0" href="https://www.odoo.tz/my/${object.name}">https://www.odoo.tz/my/${object.name}</h1>
-Website1: <a id="url1" href="https://www.odoo.be">https://www.odoo.be</h1>
-Website2: <a id="url2" href="https://${url}">https://${url}</h1>
-Website3: <a id="url3" href="${httpurl}">${httpurl}</h1>
-Email: <a id="url4" href="mailto:test@odoo.com">test@odoo.com</h1>
- """,
- "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.mailing_bl = cls.env['mailing.mailing'].create({
+ 'name': 'SourceName',
+ 'subject': 'MailingSubject',
+ 'body_html': '<p>Hello ${object.name}</p>',
+ 'mailing_type': 'mail',
+ 'mailing_model_id': cls.env['ir.model']._get('mailing.test.blacklist').id,
+ })
- 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')
+ @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" <test.record.%02d@test.example.com>' % (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 <john.snow@example.com>')])
+
self.assertEqual(search_res, self.bl_rec)
search_res = self.env['mail.blacklist'].search([('email', '=', '"John J. Snow" <john.snow@example.com>')])
@@ -151,12 +152,12 @@ class TestBLConsistency(common.TestMailCommon):
search_res = self.env['mail.blacklist'].search([('email', '=', '"John; \"You know Nothing\" Snow" <john.snow@example.com>')])
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 <arya.stark@example.com>'})
+ record1 = self.env['mailing.test.blacklist'].create({'email_from': 'Arya Stark <arya.stark@example.com>'})
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('<!DOCTYPE html>', body_html)
- self.assertIn('<head>', 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
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):
-
- 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 <rec.%s@example.com>' % x,
- } for x in range(0, 6)]
- self.mm_recs = self.env['mass.mail.test.bl'].create(values)
-
- self.env['mail.blacklist'].create({
- 'email': 'rec.2@example.com'
- })
-
- self.test_medium = self.env['utm.medium'].create({'name': 'TestMedium'})
-
- @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': '<p>Hello <a role="button" href="%s">${object.name}</a><a role="button" href="/unsubscribe_from_list">Unsubscribe</a></p>' % _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)],
+class TestMassMailing(TestMassMailCommon):
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestMassMailing, cls).setUpClass()
+
+ @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_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'})
+ 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', '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('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)
- ]
- })
-
- # 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',
+ mailing = self.env['mailing.mailing'].create({
+ 'name': 'SourceName',
+ 'subject': 'MailingSubject',
+ 'body_html': '<p>Hello ${object.name}</p>',
+ '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],
})
-
- # 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')
+ mailing.action_put_in_queue()
+ with self.mock_mail_gateway(mail_unlink_sent=False):
+ mailing._process_mass_mailing_queue()
+
+ 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 <rec.%s@example.com>' % 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': '<p>Hello <a role="button" href="https://www.example.com/foo/bar?baz=qux">quux</a><a role="button" href="/unsubscribe_from_list">Unsubscribe</a></p>',
'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 <rec.%s@example.com>' % 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': '<p>Hello <a role="button" href="https://www.example.com/foo/bar?baz=qux">quux</a><a role="button" href="/unsubscribe_from_list">Unsubscribe</a></p>',
'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)],
})