[MERGE] (test_)(mass_)mail(_full): reorganize test classes and helpers

PURPOSE

Improve marketing automation tests: improve their reading, add more tests
and notably SMS tests. For that purpose clean helpers and tools.

SPECIFICATIONS

Add some helpers to improve marketing tests (click on SMS, find sms / mail
based on data available in tests, ...).

Modules holding tests and helpers

  * link_tracker: mainly mock, asserts and tools for link tracker tests
    (MockLinkTracker);
  * mail: mainly gateway mock and base for mail tests
    * MockEmail -> mocks for mail gateway;
    * MailCase -> tools and asserts for mail tests;
    * MailCommon ->     base for mail functional tests);

  * sms: mainly SMS gateway mock and base for sms tests
    * MockSMS -> mocks for SMS gateway;
    * SMS Case -> tools and asserts for mail / SMS tests;
    * SMSCommon -> update of MailCommon with SMS capabilities);

  * mass_mailing: mainly asserts and tools for mass mailing tests
    * MassMailCase -> update of MailCase for mass mailing tools and asserts;
    * MassMailCommon -> update of MailCommon with mass mailing);

  * mass_mailing_sms: mainly asserts and tools for mass SMS tests
    * MockMassSMS -> update of MockSMS for mass SMS tools and asserts;
    * MassSMSCommon -> update of MassMailCommon with SMS capabilities);

Modules for tests

  * test_mail: module for mail app tests (TestMailCommon);
  * test_mass_mailing: module for mass mailing app tests (TestMassMailCommon);
  * test_mail_full: tests integrating all discuss features, currently mainly
    mail and SMS (TestMailFullCommon);

Enterprise: update test_mail_enterprise and test_marketing_automation

LINKS

Task ID 2247037
Community PR odoo/odoo#50384
Enterprise PR odoo/enterprise#10266
Upgrade PR odoo/upgrade#1122

Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Odoo's Mergebot
2020-05-26 14:22:54 +02:00
committed by GitHub
26 changed files with 319 additions and 235 deletions
+2 -2
View File
@@ -5,10 +5,10 @@ from dateutil.relativedelta import relativedelta
from odoo.addons.event.tests.common import TestEventCommon
from odoo.addons.phone_validation.tools import phone_validation
from odoo.addons.sms.tests.common import MockSMS
from odoo.addons.sms.tests.common import SMSCase
class TestSMSSchedule(TestEventCommon, MockSMS):
class TestSMSSchedule(TestEventCommon, SMSCase):
@classmethod
def setUpClass(cls):
+1 -1
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail.tests.common import mail_new_test_user
from odoo.addons.mail.tests.common import mail_new_test_user
from odoo.tests import common
+1 -1
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail.tests.common import mail_new_test_user
from odoo.addons.mail.tests.common import mail_new_test_user
from odoo.tests import common
+3 -3
View File
@@ -31,10 +31,10 @@ class MockLinkTracker(common.BaseCase):
])
return code.link_id
def assertLinkShortened(self, body, link_info, link_params=None):
""" Usage
def assertLinkShortenedHtml(self, body, link_info, link_params=None):
""" Find shortened links in an HTML content. Usage :
self.assertLinkShortened(
self.assertLinkShortenedHtml(
message.body,
('url0', 'http://www.odoo.com', True),
{'utm_campaign': self.utm_c.name, 'utm_medium': self.utm_m.name}
+105 -15
View File
@@ -3,7 +3,6 @@
import email
import email.policy
import json
import time
from collections import defaultdict
@@ -170,16 +169,32 @@ class MockEmail(common.BaseCase):
# GATEWAY ASSERTS
# ------------------------------------------------------------
def _find_mail(self, author, recipients, mail_message):
def _find_mail_mail_wpartners(self, recipients, status, mail_message=None, author=None):
for mail in self._new_mails:
if mail.mail_message_id != mail_message:
continue
if author is not None and mail.author_id != author:
continue
if mail_message is not None and mail.mail_message_id != mail_message:
continue
if status and mail.state != status:
continue
if all(p in mail.recipient_ids for p in recipients):
break
else:
raise AssertionError('mail.mail not found for message %s / recipients %s' % (mail_message, recipients.ids))
raise AssertionError('mail.mail not found for message %s / status %s / recipients %s' % (mail_message, status, recipients.ids))
return mail
def _find_mail_mail_wemail(self, email_to, status, mail_message=None, author=None):
for mail in self._new_mails:
if author is not None and mail.author_id != author:
continue
if mail_message is not None and mail.mail_message_id != mail_message:
continue
if status and mail.state != status:
continue
if (mail.email_to == email_to and not mail.recipient_ids) or (not mail.email_to and mail.recipient_ids.email) == email_to:
break
else:
raise AssertionError('mail.mail not found for email_to %s / status %s in %s' % (email_to, status, repr([m.email_to for m in self._new_mails])))
return mail
def _find_mail_mail_wrecord(self, record):
@@ -194,16 +209,33 @@ class MockEmail(common.BaseCase):
mail = self._find_mail(author, recipients, mail_message)
self.assertEqual(mail.state, 'exception')
def assertMailSent(self, author, recipients, mail_message, check_mail_mail=True, **values):
def assertMailMail(self, recipients, status, check_mail_mail=True, mail_message=None, author=None, email_values=None):
if check_mail_mail:
mail = self._find_mail(author, recipients, mail_message)
self.assertEqual(mail.state, 'sent')
for recipient in recipients:
self.assertSentEmail(author, [recipient], **values)
mail = self._find_mail_mail_wpartners(recipients, status, mail_message=mail_message, author=author)
self.assertTrue(bool(mail))
if status == 'sent':
for recipient in recipients:
self.assertSentEmail(author, [recipient], **email_values)
def assertMailMailWEmails(self, emails, status, content, fields_values=None):
""" Will check in self._new_mails to find a sent mail.mail. To use with
mail gateway mock.
:param emails: list of emails;
:param status: status of mail.mail;
:param content: content to check for each email;
:param fields_values: specific value to check on the mail.mail record;
"""
for email_to in emails:
sent_mail = self._find_mail_mail_wemail(email_to, status)
if content:
self.assertIn(content, sent_mail.body_html)
for fname, fvalue in (fields_values or {}).items():
self.assertEqual(sent_mail[fname], fvalue)
def assertNoMail(self, author, recipients, mail_message):
try:
self._find_mail(author, recipients, mail_message)
self._find_mail_mail_wpartners(recipients, False, mail_message=mail_message, author=author)
except AssertionError:
pass
else:
@@ -290,6 +322,11 @@ class MailCase(MockEmail):
mail_notrack=False
)
def flush_tracking(self):
""" Force the creation of tracking values. """
self.env['base'].flush()
self.cr.precommit()
# ------------------------------------------------------------
# MAIL MOCKS
# ------------------------------------------------------------
@@ -363,6 +400,19 @@ class MailCase(MockEmail):
return cls.env['mail.message'].sudo().create(create_vals)
@classmethod
def _create_template(cls, model, template_values=None):
create_values = {
'name': 'TestTemplate',
'subject': 'About ${object.name}',
'body_html': '<p>Hello ${object.name}</p>',
'model_id': cls.env['ir.model']._get(model).id,
}
if template_values:
create_values.update(template_values)
cls.email_template = cls.env['mail.template'].create(create_values)
return cls.email_template
# ------------------------------------------------------------
# MAIL ASSERTS WRAPPERS
# ------------------------------------------------------------
@@ -505,12 +555,16 @@ class MailCase(MockEmail):
for recipients in email_groups.values():
partners = self.env['res.partner'].sudo().concat(*recipients)
if all(p in mail_groups['failure'] for p in partners):
self.assertMailFailed(message.author_id, partners, message)
self.assertMailMail(partners, 'exception', author=message.author_id, mail_message=message)
else:
check_mail_mail = not self.mail_unlink_sent
self.assertMailSent(
message.author_id if message.author_id else message.email_from, partners, message,
check_mail_mail=check_mail_mail, body_content=mbody)
self.assertMailMail(
partners, 'sent',
author=message.author_id if message.author_id else message.email_from,
mail_message=message,
check_mail_mail=check_mail_mail,
email_values={'body_content': mbody}
)
if not any(p for recipients in email_groups.values() for p in recipients):
self.assertNoMail(message.author_id, partners, message)
@@ -580,3 +634,39 @@ class MailCase(MockEmail):
self.assertEqual(tracking.new_value_char, new_value and new_value.display_name or '')
else:
self.assertEqual(1, 0)
class MailCommon(common.SavepointCase, MailCase):
""" Almost-void class definition setting the savepoint case + mock of mail.
Used mainly for class inheritance in other applications and test modules. """
@classmethod
def setUpClass(cls):
super(MailCommon, cls).setUpClass()
# give default values for all email aliases and domain
cls._init_mail_gateway()
# ensure admin configuration
cls.user_admin = cls.env.ref('base.user_admin')
cls.user_admin.write({'notification_type': 'inbox'})
cls.partner_admin = cls.env.ref('base.partner_admin')
cls.company_admin = cls.user_admin.company_id
cls.company_admin.write({'email': 'company@example.com'})
# test standard employee
cls.user_employee = mail_new_test_user(
cls.env, login='employee',
groups='base.group_user',
company_id=cls.company_admin.id,
name='Ernest Employee',
notification_type='inbox',
signature='--\nErnest'
)
cls.partner_employee = cls.user_employee.partner_id
@classmethod
def _create_portal_user(cls):
cls.user_portal = mail_new_test_user(
cls.env, login='portal_test', groups='base.group_portal', company_id=cls.company_admin.id,
name='Chell Gladys', notification_type='email')
cls.partner_portal = cls.user_portal.partner_id
return cls.user_portal
+5 -40
View File
@@ -2,48 +2,11 @@
# 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
from odoo.addons.mail.tests.common import MailCase, MailCommon, mail_new_test_user
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.
@@ -90,6 +53,8 @@ class MassMailCase(MailCase, MockLinkTracker):
if state == 'sent':
self.assertMailMailWEmails([email], 'sent', content, fields_values=fields_values)
elif state == 'replied': # replied imply something has been 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':
@@ -100,11 +65,11 @@ class MassMailCase(MailCase, MockLinkTracker):
raise NotImplementedError()
class TestMassMailCommon(SavepointCase, MassMailCase):
class MassMailCommon(MailCommon, MassMailCase):
@classmethod
def setUpClass(cls):
super(TestMassMailCommon, cls).setUpClass()
super(MassMailCommon, cls).setUpClass()
cls.user_marketing = mail_new_test_user(
cls.env, login='user_marketing',
@@ -3,11 +3,11 @@
import werkzeug
from odoo.addons.mass_mailing.tests.common import TestMassMailCommon
from odoo.addons.mass_mailing.tests.common import MassMailCommon
from odoo.tests.common import HttpCase
class TestMassMailingControllers(TestMassMailCommon, HttpCase):
class TestMassMailingControllers(MassMailCommon, HttpCase):
def test_tracking_url_token(self):
mail_mail = self.env['mail.mail'].create({})
@@ -3,11 +3,11 @@
from ast import literal_eval
from odoo.addons.mass_mailing.tests.common import TestMassMailCommon
from odoo.addons.mass_mailing.tests.common import MassMailCommon
from odoo.tests.common import users, Form
from odoo.tools import formataddr, mute_logger
class TestMassMailValues(TestMassMailCommon):
class TestMassMailValues(MassMailCommon):
@classmethod
def setUpClass(cls):
@@ -122,7 +122,7 @@ class TestMassMailValues(TestMassMailCommon):
self.assertEqual(mailing_form.mailing_model_real, 'res.partner')
class TestMassMailFeatures(TestMassMailCommon):
class TestMassMailFeatures(MassMailCommon):
@classmethod
def setUpClass(cls):
@@ -252,7 +252,7 @@ Email: <a id="url5" href="mailto:test@odoo.com">test@odoo.com</a></div>""",
link_params = {'utm_medium': 'Email', 'utm_source': mailing.name}
if link_info[0] == 'url4':
link_params['baz'] = 'qux'
self.assertLinkShortened(
self.assertLinkShortenedHtml(
new_mail.mail_message_id.body,
link_info,
link_params=link_params,
@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.mass_mailing.tests.common import TestMassMailCommon
from odoo.addons.mass_mailing.tests.common import MassMailCommon
from odoo.tests.common import users
class TestMailingListMerge(TestMassMailCommon):
class TestMailingListMerge(MassMailCommon):
@classmethod
def setUpClass(cls):
+51 -16
View File
@@ -1,16 +1,41 @@
# -*- coding: utf-8 -*-
from contextlib import contextmanager
from unittest.mock import patch
import re
import werkzeug
from odoo import exceptions, tools
from odoo.addons.phone_validation.tools import phone_validation
from odoo.addons.sms.tests import common as sms_common
from odoo.tests import common
from odoo.addons.sms.models.sms_api import SmsApi
from odoo import tools
from odoo.addons.mass_mailing.tests.common import MassMailCommon
from odoo.addons.sms.tests.common import SMSCase, SMSCommon
class MockSMS(sms_common.MockSMS):
class MassSMSCase(SMSCase):
# ------------------------------------------------------------
# GATEWAY TOOLS
# ------------------------------------------------------------
def gateway_sms_click(self, sent_sms):
""" Simulate a click on a sent SMS. Usage: giving a partner and/or
a number, find an SMS sent to him, find shortened links in its body
and call add_click to simulate a click. """
for url in re.findall(tools.TEXT_URL_REGEX, sent_sms['body']):
if '/r' in url: # shortened link, like 'http://localhost:8069/r/LBG/s/53'
parsed_url = werkzeug.urls.url_parse(url)
path_items = parsed_url.path.split('/')
code, sms_sms_id = path_items[2], int(path_items[4])
trace_id = self.env['mailing.trace'].sudo().search([('sms_sms_id_int', '=', sms_sms_id)]).id
self.env['link.tracker.click'].sudo().add_click(
code,
ip='100.200.300.400',
country_code='BE',
mailing_trace_id=trace_id
)
# ------------------------------------------------------------
# ASSERTS
# ------------------------------------------------------------
def assertSMSOutgoingStatistics(self, partners, numbers, records, mailing):
found_sms = self.env['sms.sms'].sudo().search([
@@ -32,13 +57,16 @@ class MockSMS(sms_common.MockSMS):
def assertSMSStatistics(self, recipients_info, mailing, records, check_sms=True):
""" Check content of notifications.
:param recipients_info: list[{
'partner': res.partner record (may be empty),
'number': number used for notification (may be empty, computed based on partner),
'state': outgoing / sent / ignored / exception / opened (sent by default),
'record: linked record,
'failure_type': optional: sms_number_missing / sms_number_format / sms_credit / sms_server
}, { ... }]
:param recipients_info: list[{
'partner': res.partner record (may be empty),
'number': number used for notification (may be empty, computed based on partner),
'state': outgoing / sent / ignored / exception / opened (sent by default),
'record: linked record,
'content': optional: if set, check content of sent SMS
'failure_type': optional: sms_number_missing / sms_number_format / sms_credit / sms_server
},
{ ... }
]
"""
traces = self.env['mailing.trace'].search([
('mass_mailing_id', 'in', mailing.ids),
@@ -55,7 +83,7 @@ class MockSMS(sms_common.MockSMS):
state = recipient_info.get('state', 'outgoing')
content = recipient_info.get('content', None)
if number is None and partner:
number = phone_validation.phone_get_sanitized_record_number(partner)
number = partner._sms_get_recipients_info()[partner.id]['sanitized']
notif = traces.filtered(lambda s: s.sms_number == number and s.state == state)
self.assertTrue(notif, 'SMS: not found notification for number %s, (state: %s)' % (number, state))
@@ -71,3 +99,10 @@ class MockSMS(sms_common.MockSMS):
self.assertSMSCanceled(partner, number, recipient_info.get('failure_type', False), content)
else:
raise NotImplementedError()
class MassSMSCommon(MassMailCommon, SMSCommon, MassSMSCase):
@classmethod
def setUpClass(cls):
super(MassSMSCommon, cls).setUpClass()
@@ -3,11 +3,11 @@
from ast import literal_eval
from odoo.addons.mass_mailing.tests.common import TestMassMailCommon
from odoo.addons.mass_mailing_sms.tests.common import MassSMSCommon
from odoo.tests.common import users
class TestMassMailValues(TestMassMailCommon):
class TestMassMailValues(MassSMSCommon):
@classmethod
def setUpClass(cls):
+67 -23
View File
@@ -4,8 +4,9 @@ from contextlib import contextmanager
from unittest.mock import patch
from odoo import exceptions, tools
from odoo.addons.phone_validation.tools import phone_validation
from odoo.tests import common
from odoo.addons.mail.tests.common import MailCommon
from odoo.addons.phone_validation.tools import phone_validation
from odoo.addons.sms.models.sms_api import SmsApi
@@ -13,11 +14,11 @@ class MockSMS(common.BaseCase):
def tearDown(self):
super(MockSMS, self).tearDown()
self._clear_sms_sent
self._clear_sms_sent()
@contextmanager
def mockSMSGateway(self, sim_error=None, nbr_t_error=None):
self._sms = []
self._clear_sms_sent()
def _contact_iap(local_endpoint, params):
# mock single sms sending
@@ -60,7 +61,34 @@ class MockSMS(common.BaseCase):
def _clear_sms_sent(self):
self._sms = []
def assertSMSSent(self, numbers, content):
class SMSCase(MockSMS):
""" Main test class to use when testing SMS integrations. Contains helpers and tools related
to notification sent by SMS. """
def _find_sms_sent(self, partner, number):
if number is None and partner:
number = partner.phone_get_sanitized_number()
sent_sms = next((sms for sms in self._sms if sms['number'] == number), None)
if not sent_sms:
raise AssertionError('sent sms not found for %s (number: %s)' % (partner, number))
return sent_sms
def _find_sms_sms(self, partner, number, status):
if number is None and partner:
number = partner.phone_get_sanitized_number()
domain = [('partner_id', '=', partner.id), ('number', '=', number)]
if status:
domain += [('state', '=', status)]
sms = self.env['sms.sms'].sudo().search(domain)
if not sms:
raise AssertionError('sms.sms not found for %s (number: %s / status %s)' % (partner, number, status))
if len(sms) > 1:
raise NotImplementedError()
return sms
def assertSMSSent(self, numbers, content=None):
""" Check sent SMS. Order is not checked. Each number should have received
the same content. Useful to check batch sending.
@@ -70,17 +98,13 @@ class MockSMS(common.BaseCase):
for number in numbers:
sent_sms = next((sms for sms in self._sms if sms['number'] == number), None)
self.assertTrue(bool(sent_sms), 'Number %s not found in %s' % (number, repr([s['number'] for s in self._sms])))
self.assertEqual(sent_sms['body'], content)
if content is not None:
self.assertEqual(sent_sms['body'], content)
def assertSMSCanceled(self, partner, number, error_code, content=None):
""" Check canceled SMS. Search is done for a pair partner / number where
partner can be an empty recordset. """
if number is None and partner:
number = partner.phone_get_sanitized_number()
sms = self.env['sms.sms'].sudo().search([
('partner_id', '=', partner.id), ('number', '=', number),
('state', '=', 'canceled')
])
sms = self._find_sms_sms(partner, number, 'canceled')
self.assertTrue(sms, 'SMS: not found canceled SMS for %s (number: %s)' % (partner, number))
self.assertEqual(sms.error_code, error_code)
if content is not None:
@@ -89,12 +113,7 @@ class MockSMS(common.BaseCase):
def assertSMSFailed(self, partner, number, error_code, content=None):
""" Check failed SMS. Search is done for a pair partner / number where
partner can be an empty recordset. """
if number is None and partner:
number = partner.phone_get_sanitized_number()
sms = self.env['sms.sms'].sudo().search([
('partner_id', '=', partner.id), ('number', '=', number),
('state', '=', 'error')
])
sms = self._find_sms_sms(partner, number, 'error')
self.assertTrue(sms, 'SMS: not found failed SMS for %s (number: %s)' % (partner, number))
self.assertEqual(sms.error_code, error_code)
if content is not None:
@@ -103,12 +122,7 @@ class MockSMS(common.BaseCase):
def assertSMSOutgoing(self, partner, number, content=None):
""" Check outgoing SMS. Search is done for a pair partner / number where
partner can be an empty recordset. """
if number is None and partner:
number = partner.phone_get_sanitized_number()
sms = self.env['sms.sms'].sudo().search([
('partner_id', '=', partner.id), ('number', '=', number),
('state', '=', 'outgoing')
])
sms = self._find_sms_sms(partner, number, 'outgoing')
self.assertTrue(sms, 'SMS: not found failed SMS for %s (number: %s)' % (partner, number))
if content is not None:
self.assertEqual(sms.body, content)
@@ -180,3 +194,33 @@ class MockSMS(common.BaseCase):
self.assertEqual(message.subtype_id, self.env.ref('mail.mt_note'))
self.assertEqual(message.message_type, 'sms')
self.assertEqual(tools.html2plaintext(message.body).rstrip('\n'), body)
class SMSCommon(MailCommon, MockSMS):
@classmethod
def setUpClass(cls):
super(SMSCommon, cls).setUpClass()
cls.user_employee.write({'login': 'employee'})
# update country to belgium in order to test sanitization of numbers
cls.user_employee.company_id.write({'country_id': cls.env.ref('base.be').id})
# some numbers for testing
cls.random_numbers_str = '+32456998877, 0456665544'
cls.random_numbers = cls.random_numbers_str.split(', ')
cls.random_numbers_san = [phone_validation.phone_format(number, 'BE', '32', force_format='E164') for number in cls.random_numbers]
cls.test_numbers = ['+32456010203', '0456 04 05 06', '0032456070809']
cls.test_numbers_san = [phone_validation.phone_format(number, 'BE', '32', force_format='E164') for number in cls.test_numbers]
# some numbers for mass testing
cls.mass_numbers = ['04561%s2%s3%s' % (x, x, x) for x in range(0, 10)]
cls.mass_numbers_san = [phone_validation.phone_format(number, 'BE', '32', force_format='E164') for number in cls.mass_numbers]
@classmethod
def _create_sms_template(cls, model, body=False):
return cls.env['sms.template'].create({
'name': 'Test Template',
'model_id': cls.env['ir.model']._get(model).id,
'body': body if body else 'Dear ${object.display_name} this is an SMS.'
})
+6 -50
View File
@@ -1,63 +1,19 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.mail.tests import common as mail_common
from odoo.tests import common
mail_new_test_user = mail_common.mail_new_test_user
from odoo.addons.mail.tests.common import MailCommon
from odoo.tests.common import SavepointCase
class TestMailCommon(common.SavepointCase, mail_common.MailCase):
@classmethod
def setUpClass(cls):
super(TestMailCommon, cls).setUpClass()
# give default values for all email aliases and domain
cls._init_mail_gateway()
# ensure admin configuration
cls.user_admin = cls.env.ref('base.user_admin')
cls.user_admin.write({'notification_type': 'inbox'})
cls.partner_admin = cls.env.ref('base.partner_admin')
cls.company_admin = cls.user_admin.company_id
cls.company_admin.write({'email': 'company@example.com'})
# test standard employee
cls.user_employee = mail_new_test_user(
cls.env, login='employee', groups='base.group_user', company_id=cls.company_admin.id,
name='Ernest Employee', notification_type='inbox', signature='--\nErnest')
cls.partner_employee = cls.user_employee.partner_id
class TestMailCommon(MailCommon):
""" Main entry point for functional tests. """
@classmethod
def _create_channel_listener(cls):
cls.channel_listen = cls.env['mail.channel'].with_context(cls._test_context).create({'name': 'Listener'})
@classmethod
def _create_portal_user(cls):
cls.user_portal = mail_new_test_user(
cls.env, login='portal_test', groups='base.group_portal', company_id=cls.company_admin.id,
name='Chell Gladys', notification_type='email')
cls.partner_portal = cls.user_portal.partner_id
return cls.user_portal
@classmethod
def _create_template(cls, model, template_values=None):
create_values = {
'name': 'TestTemplate',
'subject': 'About ${object.name}',
'body_html': '<p>Hello ${object.name}</p>',
'model_id': cls.env['ir.model']._get(model).id,
}
if template_values:
create_values.update(template_values)
cls.email_template = cls.env['mail.template'].create(create_values)
return cls.email_template
def flush_tracking(self):
""" Force the creation of tracking values. """
self.env['base'].flush()
self.cr.precommit()
class TestMailMultiCompanyCommon(TestMailCommon):
class TestMailMultiCompanyCommon(MailCommon):
@classmethod
def setUpClass(cls):
@@ -67,7 +23,7 @@ class TestMailMultiCompanyCommon(TestMailCommon):
})
class TestRecipients(common.SavepointCase):
class TestRecipients(SavepointCase):
@classmethod
def setUpClass(cls):
+39 -18
View File
@@ -207,14 +207,21 @@ class TestComposerWTpl(TestMailCommon, TestRecipients):
composer.send_mail()
new_partners = self.env['res.partner'].search([('email', 'in', [self.email_1, self.email_2])])
self.assertMailSent(
self.user_employee.partner_id,
self.assertMailMail(
[self.partner_1, self.partner_2, new_partners[0], new_partners[1], self.partner_admin],
False,
'sent',
author=self.user_employee.partner_id,
mail_message=False,
check_mail_mail=False,
subject='About %s' % self.test_record.name,
body_content=self.test_record.name,
attachments=[('first.txt', b'My first attachment', 'text/plain'), ('second.txt', b'My second attachment', 'text/plain')])
email_values={
'subject': 'About %s' % self.test_record.name,
'body_content': self.test_record.name,
'attachments': [
('first.txt', b'My first attachment', 'text/plain'),
('second.txt', b'My second attachment', 'text/plain')
]
}
)
def test_composer_template_onchange_attachments(self):
"""Tests that all attachments are added to the composer,
@@ -278,24 +285,38 @@ class TestComposerWTpl(TestMailCommon, TestRecipients):
self._mails_record2 = [dict(mail) for mail in self._mails if '%s-%s' % (test_record_2.id, test_record_2._name) in mail['message_id']]
self._mails = self._mails_record1
self.assertMailSent(
self.user_employee.partner_id,
self.assertMailMail(
[self.partner_1, self.partner_2, new_partners[0], new_partners[1], self.partner_admin],
False,
'sent',
author=self.user_employee.partner_id,
mail_message=False,
check_mail_mail=False,
subject='About %s' % self.test_record.name,
body_content=self.test_record.name,
attachments=[('first.txt', b'My first attachment', 'text/plain'), ('second.txt', b'My second attachment', 'text/plain')])
email_values={
'subject': 'About %s' % self.test_record.name,
'body_content': self.test_record.name,
'attachments': [
('first.txt', b'My first attachment', 'text/plain'),
('second.txt', b'My second attachment', 'text/plain')
]
}
)
self._mails = self._mails_record2
self.assertMailSent(
self.user_employee.partner_id,
self.assertMailMail(
[self.partner_1, self.partner_2, new_partners[0], new_partners[1], self.partner_admin],
False,
'sent',
author=self.user_employee.partner_id,
mail_message=False,
check_mail_mail=False,
subject='About %s' % test_record_2.name,
body_content=test_record_2.name,
attachments=[('first.txt', b'My first attachment', 'text/plain'), ('second.txt', b'My second attachment', 'text/plain')])
email_values={
'subject': 'About %s' % test_record_2.name,
'body_content': test_record_2.name,
'attachments': [
('first.txt', b'My first attachment', 'text/plain'),
('second.txt', b'My second attachment', 'text/plain')
]
}
)
message_1 = self.test_record.message_ids[0]
message_2 = test_record_2.message_ids[0]
+5 -32
View File
@@ -1,39 +1,12 @@
# -*- coding: utf-8 -*-
from odoo.addons.phone_validation.tools import phone_validation
from odoo.addons.mass_mailing_sms.tests import common as mass_mailing_sms_common
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
from odoo.addons.mass_mailing_sms.tests.common import MassSMSCommon
from odoo.addons.test_mail.tests.common import TestRecipients
from odoo.addons.test_mass_mailing.tests.common import TestMassMailCommon
class TestSMSCommon(test_mass_mailing_common.TestMassMailCommon, mass_mailing_sms_common.MockSMS):
@classmethod
def setUpClass(cls):
super(TestSMSCommon, cls).setUpClass()
cls.user_employee.write({'login': 'employee'})
# update country to belgium in order to test sanitization of numbers
cls.user_employee.company_id.write({'country_id': cls.env.ref('base.be').id})
# some numbers for testing
cls.random_numbers_str = '+32456998877, 0456665544'
cls.random_numbers = cls.random_numbers_str.split(', ')
cls.random_numbers_san = [phone_validation.phone_format(number, 'BE', '32', force_format='E164') for number in cls.random_numbers]
cls.test_numbers = ['+32456010203', '0456 04 05 06', '0032456070809']
cls.test_numbers_san = [phone_validation.phone_format(number, 'BE', '32', force_format='E164') for number in cls.test_numbers]
# some numbers for mass testing
cls.mass_numbers = ['04561%s2%s3%s' % (x, x, x) for x in range(0, 10)]
cls.mass_numbers_san = [phone_validation.phone_format(number, 'BE', '32', force_format='E164') for number in cls.mass_numbers]
@classmethod
def _create_sms_template(cls, model, body=False):
return cls.env['sms.template'].create({
'name': 'Test Template',
'model_id': cls.env['ir.model']._get(model).id,
'body': body if body else 'Dear ${object.display_name} this is an SMS.'
})
class TestMailFullCommon(TestMassMailCommon, MassSMSCommon):
@classmethod
def _create_records_for_batch(cls, model, count):
@@ -55,7 +28,7 @@ class TestSMSCommon(test_mass_mailing_common.TestMassMailCommon, mass_mailing_sm
cls.partners = partners
class TestRecipients(test_mail_common.TestRecipients):
class TestRecipients(TestRecipients):
@classmethod
def setUpClass(cls):
+2 -2
View File
@@ -3,12 +3,12 @@
from odoo.addons.phone_validation.tools import phone_validation
from odoo.addons.test_mail_full.tests import common as test_mail_full_common
from odoo.addons.test_mail_full.tests.common import TestMailFullCommon
from odoo.tests import tagged
@tagged('mass_mailing')
class TestMassSMS(test_mail_full_common.TestSMSCommon):
class TestMassSMS(TestMailFullCommon):
@classmethod
def setUpClass(cls):
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail_full.tests import common as test_mail_full_common
from odoo.addons.test_mail_full.tests.common import TestMailFullCommon, TestRecipients
class TestPhoneBlacklist(test_mail_full_common.TestSMSCommon, test_mail_full_common.TestRecipients):
class TestPhoneBlacklist(TestMailFullCommon, TestRecipients):
""" TODO """
@classmethod
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail_full.tests import common as test_mail_full_common
from odoo.addons.test_mail_full.tests.common import TestMailFullCommon, TestRecipients
class TestSMSComposerComment(test_mail_full_common.TestSMSCommon, test_mail_full_common.TestRecipients):
class TestSMSComposerComment(TestMailFullCommon, TestRecipients):
""" TODO LIST
* add test for default_res_model / default_res_id and stuff like that;
@@ -201,7 +201,7 @@ class TestSMSComposerComment(test_mail_full_common.TestSMSCommon, test_mail_full
self.assertSMSSent(self.random_numbers_san, self._test_body)
class TestSMSComposerBatch(test_mail_full_common.TestSMSCommon):
class TestSMSComposerBatch(TestMailFullCommon):
@classmethod
def setUpClass(cls):
super(TestSMSComposerBatch, cls).setUpClass()
@@ -277,7 +277,7 @@ class TestSMSComposerBatch(test_mail_full_common.TestSMSCommon):
self.assertSMSNotification([{'partner': r.customer_id} for r in self.records], 'Zizisse an SMS.', messages)
class TestSMSComposerMass(test_mail_full_common.TestSMSCommon):
class TestSMSComposerMass(TestMailFullCommon):
@classmethod
def setUpClass(cls):
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail_full.tests import common as test_mail_full_common
from odoo.addons.test_mail_full.tests.common import TestMailFullCommon, TestRecipients
class TestSMSWizards(test_mail_full_common.TestSMSCommon, test_mail_full_common.TestRecipients):
class TestSMSWizards(TestMailFullCommon, TestRecipients):
@classmethod
def setUpClass(cls):
@@ -9,7 +9,7 @@ from odoo.tools import mute_logger
@tagged('mail_performance')
class TestSMSPerformance(BaseMailPerformance, sms_common.MockSMS):
class TestSMSPerformance(BaseMailPerformance, sms_common.SMSCase):
def setUp(self):
super(TestSMSPerformance, self).setUp()
+4 -4
View File
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail_full.tests import common as test_mail_full_common
from odoo.addons.test_mail_full.tests.common import TestMailFullCommon, TestRecipients
class TestSMSPost(test_mail_full_common.TestSMSCommon, test_mail_full_common.TestRecipients):
class TestSMSPost(TestMailFullCommon, TestRecipients):
""" TODO
* add tests for new mail.message and mail.thread fields;
@@ -233,7 +233,7 @@ class TestSMSPost(test_mail_full_common.TestSMSCommon, test_mail_full_common.Tes
self.assertSMSNotification([{'partner': self.partner_1, 'number': self.test_numbers_san[1]}], 'Dear %s this is an SMS.' % self.test_record.display_name, messages)
class TestSMSPostException(test_mail_full_common.TestSMSCommon, test_mail_full_common.TestRecipients):
class TestSMSPostException(TestMailFullCommon, TestRecipients):
@classmethod
def setUpClass(cls):
@@ -374,7 +374,7 @@ class TestSMSPostException(test_mail_full_common.TestSMSCommon, test_mail_full_c
], self._test_body, messages)
class TestSMSApi(test_mail_full_common.TestSMSCommon):
class TestSMSApi(TestMailFullCommon):
@classmethod
def setUpClass(cls):
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail_full.tests import common as test_mail_full_common
from odoo.addons.test_mail_full.tests.common import TestMailFullCommon, TestRecipients
class TestServerAction(test_mail_full_common.TestSMSCommon, test_mail_full_common.TestRecipients):
class TestServerAction(TestMailFullCommon, TestRecipients):
@classmethod
def setUpClass(cls):
+2 -2
View File
@@ -8,7 +8,7 @@ from unittest.mock import DEFAULT
from odoo import exceptions
from odoo.addons.sms.models.sms_sms import SmsSms as SmsSms
from odoo.addons.test_mail_full.tests import common as test_mail_full_common
from odoo.addons.test_mail_full.tests.common import TestMailFullCommon
from odoo.tests import common
@@ -47,7 +47,7 @@ class LinkTrackerMock(common.BaseCase):
self.assertEqual(redirect_params, url_params)
class TestSMSPost(test_mail_full_common.TestSMSCommon, LinkTrackerMock):
class TestSMSPost(TestMailFullCommon, LinkTrackerMock):
@classmethod
def setUpClass(cls):
@@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail_full.tests import common as test_mail_full_common
from odoo.addons.test_mail_full.tests.common import TestMailFullCommon, TestRecipients
class TestSmsTemplate(test_mail_full_common.TestSMSCommon, test_mail_full_common.TestRecipients):
class TestSmsTemplate(TestMailFullCommon, TestRecipients):
@classmethod
def setUpClass(cls):
+2 -2
View File
@@ -4,11 +4,11 @@
import datetime
import random
from odoo.addons.mass_mailing.tests.common import TestMassMailCommon
from odoo.addons.mass_mailing.tests.common import MassMailCommon
from odoo.addons.test_mail.tests.common import TestMailCommon
class TestMassMailCommon(TestMassMailCommon, TestMailCommon):
class TestMassMailCommon(MassMailCommon, TestMailCommon):
@classmethod
def setUpClass(cls):
+1 -1
View File
@@ -8,7 +8,7 @@ from unittest.mock import patch
from odoo import http
from odoo.tests import common, tagged
from odoo.addons.web.controllers.main import ExportXlsxWriter
from odoo.addons.test_mail.tests.common import mail_new_test_user
from odoo.addons.mail.tests.common import mail_new_test_user
class XlsxCreatorCase(common.HttpCase):