diff --git a/addons/test_mail/tests/__init__.py b/addons/test_mail/tests/__init__.py index 00691b6ffca..78d3b1516b6 100644 --- a/addons/test_mail/tests/__init__.py +++ b/addons/test_mail/tests/__init__.py @@ -1,22 +1,20 @@ # -*- coding: utf-8 -*- +from . import test_invite +from . import test_ir_actions +from . import test_discuss from . import test_mail_activity from . import test_mail_followers from . import test_mail_message from . import test_mail_mail -from . import test_mail_race -from . import test_mail_resend -from . import test_mail_cc from . import test_mail_channel from . import test_mail_gateway +from . import test_mail_redirect from . import test_mail_template -from . import test_message_compose +from . import test_message_composer +from . import test_message_management +from . import test_message_post from . import test_message_track -from . import test_invite -from . import test_ir_actions -from . import test_update_notification -from . import test_discuss -from . import test_performance -from . import test_res_users from . import test_odoobot -from . import test_multi_company +from . import test_performance +from . import test_update_notification diff --git a/addons/test_mail/tests/common.py b/addons/test_mail/tests/common.py index d3c41a16ab1..17d8594a7d9 100644 --- a/addons/test_mail/tests/common.py +++ b/addons/test_mail/tests/common.py @@ -27,15 +27,43 @@ class BaseFunctionalTest(common.SavepointCase): def setUpClass(cls): super(BaseFunctionalTest, cls).setUpClass() - cls.user_employee = mail_new_test_user(cls.env, login='ernest', groups='base.group_user', signature='--\nErnest', name='Ernest Employee') + cls.user_employee = mail_new_test_user(cls.env, login='employee', groups='base.group_user', signature='--\nErnest', name='Ernest Employee') cls.partner_employee = cls.user_employee.partner_id cls.user_admin = cls.env.ref('base.user_admin') cls.partner_admin = cls.env.ref('base.partner_admin') + @classmethod + def _create_channel_listener(cls): cls.channel_listen = cls.env['mail.channel'].with_context(cls._test_context).create({'name': 'Listener'}) - cls.test_record = cls.env['mail.test.simple'].with_context(cls._test_context).create({'name': 'Test', 'email_from': 'ignasse@example.com'}) + @classmethod + def _create_portal_user(cls): + cls.user_portal = mail_new_test_user(cls.env, login='chell', groups='base.group_portal', name='Chell Gladys') + cls.partner_portal = cls.user_portal.partner_id + + @classmethod + def _create_template(cls, model, template_values=None): + create_values = { + 'name': 'TestTemplate', + 'subject': 'About ${object.name}', + 'body_html': '

Hello ${object.name}

', + 'model_id': cls.env['ir.model']._get(model).id, + 'user_signature': False, + } + if template_values: + create_values.update(template_values) + cls.email_template = cls.env['mail.template'].create(create_values) + return cls.email_template + + @classmethod + def _init_mail_gateway(cls): + cls.alias_domain = 'test.com' + cls.alias_catchall = 'catchall.test' + cls.alias_bounce = 'bounce.test' + cls.env['ir.config_parameter'].set_param('mail.bounce.alias', cls.alias_bounce) + cls.env['ir.config_parameter'].set_param('mail.catchall.domain', cls.alias_domain) + cls.env['ir.config_parameter'].set_param('mail.catchall.alias', cls.alias_catchall) @classmethod def _reset_mail_context(cls, record): @@ -62,6 +90,8 @@ class BaseFunctionalTest(common.SavepointCase): init[partner] = { 'na_counter': len([n for n in init_notifs if n.res_partner_id == partner and not n.is_read]), } + if hasattr(self, '_init_mock_build_email'): + self._init_mock_build_email() yield finally: new_notifications = self.env['mail.notification'].sudo().search([ @@ -143,12 +173,27 @@ class BaseFunctionalTest(common.SavepointCase): else: raise AssertionError('Keys %s not found (expected: %s - returned: %s)' % (not_found_keys, repr(expected), repr(notif_messages))) + def assertTracking(self, message, data): + tracking_values = message.sudo().tracking_value_ids + for field_name, value_type, old_value, new_value in data: + tracking = tracking_values.filtered(lambda track: track.field == field_name) + self.assertEqual(len(tracking), 1) + if value_type in ('char', 'integer'): + self.assertEqual(tracking.old_value_char, old_value) + self.assertEqual(tracking.new_value_char, new_value) + elif value_type in ('many2one'): + self.assertEqual(tracking.old_value_integer, old_value and old_value.id or False) + self.assertEqual(tracking.new_value_integer, new_value and new_value.id or False) + self.assertEqual(tracking.old_value_char, old_value and old_value.display_name or '') + self.assertEqual(tracking.new_value_char, new_value and new_value.display_name or '') + else: + self.assertEqual(1, 0) + @contextmanager def sudo(self, login): old_uid = self.uid try: user = self.env['res.users'].sudo().search([('login', '=', login)]) - self.test_record_old = self.test_record # switch user self.uid = user.id self.env = self.env(user=self.uid) diff --git a/addons/test_mail/tests/test_discuss.py b/addons/test_mail/tests/test_discuss.py index 23b707d263f..be255274ea3 100644 --- a/addons/test_mail/tests/test_discuss.py +++ b/addons/test_mail/tests/test_discuss.py @@ -2,11 +2,16 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.addons.test_mail.tests.common import BaseFunctionalTest, TestRecipients, MockEmails -from odoo.addons.test_mail.tests.common import mail_new_test_user +from odoo.tools import mute_logger class TestChatterTweaks(BaseFunctionalTest, TestRecipients): + @classmethod + def setUpClass(cls): + super(TestChatterTweaks, cls).setUpClass() + cls.test_record = cls.env['mail.test.simple'].with_context(cls._test_context).create({'name': 'Test', 'email_from': 'ignasse@example.com'}) + def test_post_no_subscribe_author(self): original = self.test_record.message_follower_ids self.test_record.with_user(self.user_employee).with_context({'mail_create_nosubscribe': True}).message_post( @@ -14,6 +19,7 @@ class TestChatterTweaks(BaseFunctionalTest, TestRecipients): self.assertEqual(self.test_record.message_follower_ids.mapped('partner_id'), original.mapped('partner_id')) self.assertEqual(self.test_record.message_follower_ids.mapped('channel_id'), original.mapped('channel_id')) + @mute_logger('odoo.addons.mail.models.mail_mail') def test_post_no_subscribe_recipients(self): original = self.test_record.message_follower_ids self.test_record.with_user(self.user_employee).with_context({'mail_create_nosubscribe': True}).message_post( @@ -21,6 +27,7 @@ class TestChatterTweaks(BaseFunctionalTest, TestRecipients): self.assertEqual(self.test_record.message_follower_ids.mapped('partner_id'), original.mapped('partner_id')) self.assertEqual(self.test_record.message_follower_ids.mapped('channel_id'), original.mapped('channel_id')) + @mute_logger('odoo.addons.mail.models.mail_mail') def test_post_subscribe_recipients(self): original = self.test_record.message_follower_ids self.test_record.with_user(self.user_employee).with_context({'mail_create_nosubscribe': True, 'mail_post_autofollow': True}).message_post( @@ -72,42 +79,23 @@ class TestChatterTweaks(BaseFunctionalTest, TestRecipients): self.assertEqual(len(rec.sudo().mapped('message_ids.tracking_value_ids')), 0, "Creation message without tracking values should have been posted") + def test_cache_invalidation(self): + """ Test that creating a mail-thread record does not invalidate the whole cache. """ + # make a new record in cache + record = self.env['res.partner'].new({'name': 'Brave New Partner'}) + self.assertTrue(record.name) -class TestNotifications(BaseFunctionalTest, MockEmails): + # creating a mail-thread record should not invalidate the whole cache + self.env['res.partner'].create({'name': 'Actual Partner'}) + self.assertTrue(record.name) - def setUp(self): - self.partner_1 = self.env['res.partner'].with_context(BaseFunctionalTest._test_context).create({ - 'name': 'Valid Lelitre', - 'email': 'valid.lelitre@agrolait.com'}) - (self.user_employee | self.user_admin).write({'notification_type': 'inbox'}) - super(TestNotifications, self).setUp() +class TestDiscuss(BaseFunctionalTest, TestRecipients, MockEmails): - def test_needaction(self): - with self.assertNotifications(partner_employee=(1, 'inbox', 'unread'), partner_admin=(0, '', '')): - self.test_record.message_post( - body='Test', message_type='comment', subtype='mail.mt_comment', - partner_ids=[self.user_employee.partner_id.id]) - - self.test_record.message_subscribe([self.partner_1.id]) - with self.assertNotifications(partner_employee=(1, 'inbox', 'unread'), partner_admin=(0, '', ''), partner_1=(1, 'email', 'read')): - self.test_record.message_post( - body='Test', message_type='comment', subtype='mail.mt_comment', - partner_ids=[self.user_employee.partner_id.id]) - - def test_inactive_follower(self): - # In some case odoobot is follower of a record. - # Even if it shouldn't be the case, we want to be sure that odoobot is not notified - self.test_record._message_subscribe(self.user_employee.partner_id.ids) - with self.assertNotifications(partner_employee=(1, 'inbox', 'unread')): - self.test_record.message_post( - body='Test', message_type='comment', subtype='mail.mt_comment') - self.user_employee.active = False - # at this point, partner is still active and would receive an email notification - self.user_employee.partner_id._write({'active': False}) - with self.assertNotifications(partner_employee=(0, '', '')): - self.test_record.message_post( - body='Test', message_type='comment', subtype='mail.mt_comment') + @classmethod + def setUpClass(cls): + super(TestDiscuss, cls).setUpClass() + cls.test_record = cls.env['mail.test.simple'].with_context(cls._test_context).create({'name': 'Test', 'email_from': 'ignasse@example.com'}) def test_set_message_done_user(self): with self.assertNotifications(partner_employee=(0, '', '')): @@ -116,16 +104,6 @@ class TestNotifications(BaseFunctionalTest, MockEmails): partner_ids=[self.user_employee.partner_id.id]) message.with_user(self.user_employee).set_message_done() - def test_set_message_done_portal(self): - user_portal = mail_new_test_user(self.env, login='chell', groups='base.group_portal', name='Chell Gladys', notification_type='inbox') - self.partner_portal = user_portal.partner_id - - with self.assertNotifications(partner_employee=(1, 'inbox', 'unread'), partner_portal=(1, 'inbox', 'read')): - message = self.test_record.message_post( - body='Test', message_type='comment', subtype='mail.mt_comment', - partner_ids=[self.user_employee.partner_id.id, user_portal.partner_id.id]) - message.with_user(user_portal).set_message_done() - def test_set_star(self): msg = self.test_record.with_user(self.user_admin).message_post(body='My Body', subject='1') msg_emp = self.env['mail.message'].with_user(self.user_employee).browse(msg.id) @@ -143,19 +121,12 @@ class TestNotifications(BaseFunctionalTest, MockEmails): self.assertFalse(msg.starred) self.assertTrue(msg_emp.starred) - -class TestChatterMisc(BaseFunctionalTest): - - def test_alias_setup(self): - alias = self.env['mail.alias'].with_context(alias_model_name='mail.test').create({'alias_name': 'b4r+_#_R3wl$$'}) - self.assertEqual(alias.alias_name, 'b4r+_-_r3wl-', 'Disallowed chars should be replaced by hyphens') - - def test_cache_invalidation(self): - """ Test that creating a mail-thread record does not invalidate the whole cache. """ - # make a new record in cache - record = self.env['res.partner'].new({'name': 'Brave New Partner'}) - self.assertTrue(record.name) - - # creating a mail-thread record should not invalidate the whole cache - self.env['res.partner'].create({'name': 'Actual Partner'}) - self.assertTrue(record.name) + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_mail_cc_recipient_suggestion(self): + record = self.env['mail.test.cc'].create({'email_cc': 'cc1@example.com, cc2@example.com, cc3 '}) + suggestions = record._message_get_suggested_recipients()[record.id] + self.assertEqual(sorted(suggestions), [ + (False, 'cc1@example.com', 'CC Email'), + (False, 'cc2@example.com', 'CC Email'), + (False, 'cc3 ', 'CC Email') + ], 'cc should be in suggestions') diff --git a/addons/test_mail/tests/test_invite.py b/addons/test_mail/tests/test_invite.py index 87a802820b8..841a980a517 100644 --- a/addons/test_mail/tests/test_invite.py +++ b/addons/test_mail/tests/test_invite.py @@ -9,21 +9,22 @@ class TestInvite(common.BaseFunctionalTest, common.MockEmails): @mute_logger('odoo.addons.mail.models.mail_mail') def test_invite_email(self): - test_partner = self.env['res.partner'].with_context(common.BaseFunctionalTest._test_context).create({ + test_record = self.env['mail.test.simple'].with_context(self._test_context).create({'name': 'Test', 'email_from': 'ignasse@example.com'}) + test_partner = self.env['res.partner'].with_context(self._test_context).create({ 'name': 'Valid Lelitre', 'email': 'valid.lelitre@agrolait.com'}) mail_invite = self.env['mail.wizard.invite'].with_context({ 'default_res_model': 'mail.test.simple', - 'default_res_id': self.test_record.id + 'default_res_id': test_record.id }).with_user(self.user_employee).create({ 'partner_ids': [(4, test_partner.id), (4, self.user_admin.partner_id.id)], 'send_mail': True}) mail_invite.add_followers() # check added followers and that emails were sent - self.assertEqual(self.test_record.message_partner_ids, + self.assertEqual(test_record.message_partner_ids, test_partner | self.user_admin.partner_id) - self.assertEqual(self.test_record.message_follower_ids.mapped('channel_id'), + self.assertEqual(test_record.message_follower_ids.mapped('channel_id'), self.env['mail.channel']) self.assertEqual(len(self._mails), 2) diff --git a/addons/test_mail/tests/test_ir_actions.py b/addons/test_mail/tests/test_ir_actions.py index 36ff2a5094e..9a20ee94db3 100644 --- a/addons/test_mail/tests/test_ir_actions.py +++ b/addons/test_mail/tests/test_ir_actions.py @@ -2,27 +2,20 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.addons.base.tests.test_ir_actions import TestServerActionsBase +from odoo.addons.test_mail.tests.common import BaseFunctionalTest -class TestServerActionsEmail(TestServerActionsBase): +class TestServerActionsEmail(BaseFunctionalTest, TestServerActionsBase): def test_action_email(self): - email_template = self.env['mail.template'].create({ - 'name': 'TestTemplate', - 'email_from': 'myself@example.com', - 'email_to': 'brigitte@example.com', - 'partner_to': '%s' % self.test_partner.id, - 'model_id': self.res_partner_model.id, - 'subject': 'About ${object.name}', - 'body_html': '

Dear ${object.name}, your parent is ${object.parent_id and object.parent_id.name or "False"}

', - }) + email_template = self._create_template('res.partner', {'partner_to': '%s' % self.test_partner.id}) self.action.write({'state': 'email', 'template_id': email_template.id}) self.action.with_context(self.context).run() # check an email is waiting for sending mail = self.env['mail.mail'].search([('subject', '=', 'About TestingPartner')]) self.assertEqual(len(mail), 1) # check email content - self.assertEqual(mail.body, '

Dear TestingPartner, your parent is False

') + self.assertEqual(mail.body, '

Hello TestingPartner

') def test_action_followers(self): self.test_partner.message_unsubscribe(self.test_partner.message_partner_ids.ids) diff --git a/addons/test_mail/tests/test_mail_activity.py b/addons/test_mail/tests/test_mail_activity.py index cb7d913a7e4..f72940b07a5 100644 --- a/addons/test_mail/tests/test_mail_activity.py +++ b/addons/test_mail/tests/test_mail_activity.py @@ -10,8 +10,8 @@ import pytz from odoo import exceptions, tests from odoo.addons.test_mail.tests.common import BaseFunctionalTest -from odoo.addons.test_mail.tests.common import mail_new_test_user from odoo.addons.test_mail.models.test_mail_models import MailTestActivity +from odoo.tools import mute_logger class TestActivityCommon(BaseFunctionalTest): @@ -19,7 +19,7 @@ class TestActivityCommon(BaseFunctionalTest): @classmethod def setUpClass(cls): super(TestActivityCommon, cls).setUpClass() - cls.test_record = cls.env['mail.test.activity'].with_context(BaseFunctionalTest._test_context).create({'name': 'Test'}) + cls.test_record = cls.env['mail.test.activity'].with_context(cls._test_context).create({'name': 'Test'}) # reset ctx cls.test_record = cls.test_record.with_context( mail_create_nolog=False, @@ -31,6 +31,7 @@ class TestActivityCommon(BaseFunctionalTest): @tests.tagged('mail_activity') class TestActivityRights(TestActivityCommon): + @mute_logger('odoo.addons.mail.models.mail_mail') def test_activity_security_user_access_other(self): activity = self.test_record.with_user(self.user_employee).activity_schedule( 'test_mail.mail_act_test_todo', @@ -38,12 +39,14 @@ class TestActivityRights(TestActivityCommon): self.assertTrue(activity.can_write) activity.write({'user_id': self.user_employee.id}) + @mute_logger('odoo.addons.mail.models.mail_mail') def test_activity_security_user_access_own(self): activity = self.test_record.with_user(self.user_employee).activity_schedule( 'test_mail.mail_act_test_todo') self.assertTrue(activity.can_write) activity.write({'user_id': self.user_admin.id}) + @mute_logger('odoo.addons.mail.models.mail_mail') def test_activity_security_user_noaccess_automated(self): def _employee_crash(*args, **kwargs): """ If employee is test employee, consider he has no access on document """ @@ -90,7 +93,7 @@ class TestActivityRights(TestActivityCommon): class TestActivityFlow(TestActivityCommon): def test_activity_flow_employee(self): - with self.sudo('ernest'): + with self.sudo('employee'): test_record = self.env['mail.test.activity'].browse(self.test_record.id) self.assertEqual(test_record.activity_ids, self.env['mail.activity']) @@ -118,19 +121,7 @@ class TestActivityFlow(TestActivityCommon): self.assertEqual(test_record.activity_ids, self.env['mail.activity']) self.assertEqual(test_record.message_ids[0].subtype_id, self.env.ref('mail.mt_activities')) - def test_activity_flow_portal(self): - portal_user = mail_new_test_user(self.env, login='chell', groups='base.group_portal', name='Chell Gladys') - - with self.sudo('chell'): - test_record = self.env['mail.test.activity'].browse(self.test_record.id) - with self.assertRaises(exceptions.AccessError): - self.env['mail.activity'].create({ - 'summary': 'Test Activity', - 'activity_type_id': self.env.ref('mail.mail_activity_data_email').id, - 'res_model_id': self.env['ir.model']._get(test_record._name).id, - 'res_id': test_record.id, - }) - + @mute_logger('odoo.addons.mail.models.mail_mail') def test_activity_notify_other_user(self): self.user_admin.notification_type = 'email' rec = self.test_record.with_user(self.user_employee) @@ -151,6 +142,7 @@ class TestActivityFlow(TestActivityCommon): self.assertEqual(activity.create_uid, self.user_employee) self.assertEqual(activity.user_id, self.user_employee) + @mute_logger('odoo.addons.mail.models.mail_mail') def test_activity_dont_notify_no_user_change(self): self.user_employee.notification_type = 'email' activity = self.test_record.activity_schedule('test_mail.mail_act_test_todo', user_id=self.user_employee.id) @@ -162,9 +154,10 @@ class TestActivityFlow(TestActivityCommon): @tests.tagged('mail_activity') class TestActivityMixin(TestActivityCommon): + @mute_logger('odoo.addons.mail.models.mail_mail') def test_activity_mixin(self): self.user_employee.tz = self.user_admin.tz - with self.sudo('ernest'): + with self.sudo('employee'): self.test_record = self.env['mail.test.activity'].browse(self.test_record.id) self.assertEqual(self.test_record.env.user, self.user_employee) @@ -242,6 +235,7 @@ class TestActivityMixin(TestActivityCommon): self.assertEqual(self.test_record.activity_ids, self.env['mail.activity']) self.assertEqual(len(self.test_record.message_ids), 2) + @mute_logger('odoo.addons.mail.models.mail_mail') def test_activity_mixin_archive(self): rec = self.test_record.with_user(self.user_employee) new_act = rec.activity_schedule( @@ -255,6 +249,7 @@ class TestActivityMixin(TestActivityCommon): self.assertEqual(rec.active, True) self.assertEqual(rec.activity_ids, self.env['mail.activity']) + @mute_logger('odoo.addons.mail.models.mail_mail') def test_activity_mixin_reschedule_user(self): rec = self.test_record.with_user(self.user_employee) rec.activity_schedule( diff --git a/addons/test_mail/tests/test_mail_cc.py b/addons/test_mail/tests/test_mail_cc.py deleted file mode 100644 index 45503d3b649..00000000000 --- a/addons/test_mail/tests/test_mail_cc.py +++ /dev/null @@ -1,63 +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.tests import tagged -from odoo.tools import mute_logger, email_split_and_format -from odoo.addons.test_mail.data.test_mail_data import MAIL_TEMPLATE - - -@tagged('mail_thread_cc') -class TestMailCc(common.BaseFunctionalTest, common.MockEmails): - - @classmethod - def setUpClass(cls): - super(TestMailCc, cls).setUpClass() - - cls.email_from = 'Sylvie Lelitre ' - cls.alias = cls.env['mail.alias'].create({ - 'alias_name': 'cc_record', - 'alias_user_id': False, - 'alias_model_id': cls.env['ir.model']._get('mail.test.cc').id, - 'alias_contact': 'everyone'}) - - cls.env['ir.config_parameter'].set_param('mail.bounce.alias', 'bounce.test') - cls.env['ir.config_parameter'].set_param('mail.catchall.domain', 'test.com') - cls.env['ir.config_parameter'].set_param('mail.catchall.alias', 'catchall.test') - - @mute_logger('odoo.addons.mail.models.mail_thread') - def test_message_cc_new(self): - record = self.format_and_process(MAIL_TEMPLATE, self.email_from, 'cc_record@test.com', - cc='cc1@example.com, cc2@example.com', target_model='mail.test.cc') - cc = email_split_and_format(record.email_cc) - self.assertEqual(sorted(cc), ['cc1@example.com', 'cc2@example.com']) - - @mute_logger('odoo.addons.mail.models.mail_thread') - def test_message_cc_update_with_old(self): - record = self.env['mail.test.cc'].create({'email_cc': 'cc1 , cc2@example.com'}) - self.alias.write({'alias_force_thread_id': record.id}) - - self.format_and_process(MAIL_TEMPLATE, self.email_from, 'cc_record@test.com', - cc='cc2 , cc3@example.com', target_model='mail.test.cc') - cc = email_split_and_format(record.email_cc) - self.assertEqual(sorted(cc), ['cc1 ', 'cc2@example.com', 'cc3@example.com'], 'new cc should have been added on record (unique)') - - @mute_logger('odoo.addons.mail.models.mail_thread') - def test_message_cc_update_no_old(self): - record = self.env['mail.test.cc'].create({}) - self.alias.write({'alias_force_thread_id': record.id}) - - self.format_and_process(MAIL_TEMPLATE, self.email_from, 'cc_record@test.com', - cc='cc2 , cc3@example.com', target_model='mail.test.cc') - cc = email_split_and_format(record.email_cc) - self.assertEqual(sorted(cc), ['cc2 ', 'cc3@example.com'], 'new cc should have been added on record (unique)') - - @mute_logger('odoo.addons.mail.models.mail_mail') - def test_mail_cc_recipient_suggestion(self): - record = self.env['mail.test.cc'].create({'email_cc': 'cc1@example.com, cc2@example.com, cc3 '}) - suggestions = record._message_get_suggested_recipients()[record.id] - self.assertEqual(sorted(suggestions), [ - (False, 'cc1@example.com', 'CC Email'), - (False, 'cc2@example.com', 'CC Email'), - (False, 'cc3 ', 'CC Email') - ], 'cc should be in suggestions') diff --git a/addons/test_mail/tests/test_mail_channel.py b/addons/test_mail/tests/test_mail_channel.py index f91084e50ba..f1b482028c9 100644 --- a/addons/test_mail/tests/test_mail_channel.py +++ b/addons/test_mail/tests/test_mail_channel.py @@ -13,7 +13,7 @@ class TestChannelAccessRights(common.BaseFunctionalTest, common.MockEmails): @classmethod def setUpClass(cls): super(TestChannelAccessRights, cls).setUpClass() - Channel = cls.env['mail.channel'].with_context(common.BaseFunctionalTest._test_context) + Channel = cls.env['mail.channel'].with_context(cls._test_context) cls.user_public = mail_new_test_user(cls.env, login='bert', groups='base.group_public', name='Bert Tartignole') cls.user_portal = mail_new_test_user(cls.env, login='chell', groups='base.group_portal', name='Chell Gladys') @@ -113,13 +113,13 @@ class TestChannelFeatures(common.BaseFunctionalTest, common.MockEmails): @classmethod def setUpClass(cls): super(TestChannelFeatures, cls).setUpClass() - cls.test_channel = cls.env['mail.channel'].with_context(common.BaseFunctionalTest._test_context).create({ + cls.test_channel = cls.env['mail.channel'].with_context(cls._test_context).create({ 'name': 'Test', 'description': 'Description', 'alias_name': 'test', 'public': 'public', }) - cls.test_partner = cls.env['res.partner'].with_context(common.BaseFunctionalTest._test_context).create({ + cls.test_partner = cls.env['res.partner'].with_context(cls._test_context).create({ 'name': 'Test Partner', 'email': 'test@example.com', }) @@ -202,7 +202,7 @@ class TestChannelFeatures(common.BaseFunctionalTest, common.MockEmails): @mute_logger('odoo.addons.mail.models.mail_mail') def test_channel_out_of_office(self): self.user_employee.out_of_office_message = 'Out' - test_chat = self.env['mail.channel'].with_context(common.BaseFunctionalTest._test_context).create({ + test_chat = self.env['mail.channel'].with_context(self._test_context).create({ 'channel_partner_ids': [(4, self.user_employee.partner_id.id), (4, self.user_admin.partner_id.id)], 'public': 'private', 'channel_type': 'chat', @@ -311,3 +311,24 @@ class TestChannelModeration(common.Moderation): self.assertEqual(accepted_messages, msg_moderator | msg_email2 | msg_notif) self.assertFalse(msg_admin.channel_ids) self.assertEqual(msg_email2.channel_ids, self.channel_1) + + def test_user_is_moderator(self): + self.assertTrue(self.user_employee.is_moderator) + self.assertFalse(self.user_admin.is_moderator) + self.assertTrue(self.user_employee_2.is_moderator) + + def test_user_moderation_counter(self): + self._create_new_message(self.channel_1.id, status='pending_moderation', author=self.partner_admin) + self._create_new_message(self.channel_1.id, status='accepted', author=self.partner_admin) + self._create_new_message(self.channel_1.id, status='accepted', author=self.partner_employee) + self._create_new_message(self.channel_1.id, status='pending_moderation', author=self.partner_employee) + self._create_new_message(self.channel_1.id, status='accepted', author=self.partner_employee_2) + + self.assertEqual(self.user_employee.moderation_counter, 2) + self.assertEqual(self.user_employee_2.moderation_counter, 0) + self.assertEqual(self.user_admin.moderation_counter, 0) + + self.channel_1.write({'channel_partner_ids': [(4, self.partner_employee_2.id)], 'moderator_ids': [(4, self.user_employee_2.id)]}) + self.assertEqual(self.user_employee.moderation_counter, 2) + self.assertEqual(self.user_employee_2.moderation_counter, 0) + self.assertEqual(self.user_admin.moderation_counter, 0) diff --git a/addons/test_mail/tests/test_mail_followers.py b/addons/test_mail/tests/test_mail_followers.py index 10c89ce0869..0d582c19bad 100644 --- a/addons/test_mail/tests/test_mail_followers.py +++ b/addons/test_mail/tests/test_mail_followers.py @@ -4,7 +4,6 @@ from psycopg2 import IntegrityError from odoo.addons.test_mail.tests import common -from odoo.addons.test_mail.tests.common import mail_new_test_user from odoo.tools.misc import mute_logger @@ -13,6 +12,10 @@ class BaseFollowersTest(common.BaseFunctionalTest): @classmethod def setUpClass(cls): super(BaseFollowersTest, cls).setUpClass() + cls.test_record = cls.env['mail.test.simple'].with_context(cls._test_context).create({'name': 'Test', 'email_from': 'ignasse@example.com'}) + cls._create_portal_user() + cls._create_channel_listener() + Subtype = cls.env['mail.message.subtype'] cls.mt_mg_def = Subtype.create({'name': 'mt_mg_def', 'default': True, 'res_model': 'mail.test.simple'}) cls.mt_cl_def = Subtype.create({'name': 'mt_cl_def', 'default': True, 'res_model': 'mail.test'}) @@ -54,15 +57,13 @@ class BaseFollowersTest(common.BaseFunctionalTest): self.assertEqual(follower.subtype_ids, self.default_group_subtypes) def test_followers_subtypes_default_internal(self): - user_portal = mail_new_test_user(self.env, login='chell', groups='base.group_portal', name='Chell Gladys') - test_record = self.test_record.with_user(self.user_employee) - test_record.message_subscribe(partner_ids=[user_portal.partner_id.id]) - self.assertEqual(test_record.message_partner_ids, user_portal.partner_id) + test_record.message_subscribe(partner_ids=[self.partner_portal.id]) + self.assertEqual(test_record.message_partner_ids, self.partner_portal) follower = self.env['mail.followers'].search([ ('res_model', '=', 'mail.test.simple'), ('res_id', '=', test_record.id), - ('partner_id', '=', user_portal.partner_id.id)]) + ('partner_id', '=', self.partner_portal.id)]) self.assertEqual(follower.subtype_ids, self.default_group_subtypes_portal) def test_followers_subtypes_specified(self): @@ -120,8 +121,7 @@ class AdvancedFollowersTest(common.BaseFunctionalTest): @classmethod def setUpClass(cls): super(AdvancedFollowersTest, cls).setUpClass() - - cls.user_portal = mail_new_test_user(cls.env, login='chell', groups='base.group_portal', name='Chell Gladys') + cls._create_portal_user() cls.test_track = cls.env['mail.test.track'].with_user(cls.user_employee).create({ 'name': 'Test', @@ -183,12 +183,12 @@ class AdvancedFollowersTest(common.BaseFunctionalTest): * subscribing to a sub-record as creator applies default subtype values * portal user should not have access to internal subtypes """ - umbrella = self.env['mail.test'].with_context(common.BaseFunctionalTest._test_context).create({ + umbrella = self.env['mail.test'].with_context(self._test_context).create({ 'name': 'Project-Like', }) - umbrella.message_subscribe(partner_ids=[self.user_portal.partner_id.id]) - self.assertEqual(umbrella.message_partner_ids, self.user_portal.partner_id) + umbrella.message_subscribe(partner_ids=[self.partner_portal.id]) + self.assertEqual(umbrella.message_partner_ids, self.partner_portal) sub1 = self.env['mail.test.track'].with_user(self.user_employee).create({ 'name': 'Task-Like Test', @@ -198,9 +198,9 @@ class AdvancedFollowersTest(common.BaseFunctionalTest): all_defaults = self.env['mail.message.subtype'].search([('default', '=', True), '|', ('res_model', '=', 'mail.test.track'), ('res_model', '=', False)]) external_defaults = all_defaults.filtered(lambda subtype: not subtype.internal) - self.assertEqual(sub1.message_partner_ids, self.user_portal.partner_id | self.user_employee.partner_id) + self.assertEqual(sub1.message_partner_ids, self.partner_portal | self.user_employee.partner_id) self.assertEqual( - sub1.message_follower_ids.filtered(lambda fol: fol.partner_id == self.user_portal.partner_id).subtype_ids, + sub1.message_follower_ids.filtered(lambda fol: fol.partner_id == self.partner_portal).subtype_ids, external_defaults | self.sub_umb1) self.assertEqual( sub1.message_follower_ids.filtered(lambda fol: fol.partner_id == self.user_employee.partner_id).subtype_ids, diff --git a/addons/test_mail/tests/test_mail_gateway.py b/addons/test_mail/tests/test_mail_gateway.py index 6784816dc9f..52ed239bc0e 100644 --- a/addons/test_mail/tests/test_mail_gateway.py +++ b/addons/test_mail/tests/test_mail_gateway.py @@ -15,7 +15,7 @@ from odoo.addons.test_mail.models.test_mail_models import MailTestGateway from odoo.addons.test_mail.tests.common import BaseFunctionalTest, MockEmails from odoo.addons.test_mail.tests.common import mail_new_test_user from odoo.tests import tagged -from odoo.tools import mute_logger, pycompat +from odoo.tools import email_split_and_format, mute_logger, pycompat @tagged('mail_gateway') @@ -69,6 +69,14 @@ class TestEmailParsing(BaseFunctionalTest, MockEmails): self.env['mail.thread'].message_parse(email.message_from_string(pycompat.to_text(test_mail_data.MAIL_XHTML))) +@tagged('mail_gateway') +class TestMailAlias(BaseFunctionalTest): + + def test_alias_setup(self): + alias = self.env['mail.alias'].with_context(alias_model_name='mail.test').create({'alias_name': 'b4r+_#_R3wl$$'}) + self.assertEqual(alias.alias_name, 'b4r+_-_r3wl-', 'Disallowed chars should be replaced by hyphens') + + @tagged('mail_gateway') class TestMailgateway(BaseFunctionalTest, MockEmails): @@ -105,9 +113,7 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): 'message_id': '<123456-openerp-%s-mail.test.gateway@%s>' % (cls.test_record.id, socket.gethostname()), }) - cls.env['ir.config_parameter'].set_param('mail.bounce.alias', 'bounce.test') - cls.env['ir.config_parameter'].set_param('mail.catchall.domain', 'test.com') - cls.env['ir.config_parameter'].set_param('mail.catchall.alias', 'catchall.test') + cls._init_mail_gateway() # -------------------------------------------------- # Base low-level tests @@ -740,3 +746,46 @@ class TestMailgateway(BaseFunctionalTest, MockEmails): self.assertEqual(len(record), 1) self.assertEqual(record.name, 'Spammy') self.assertEqual(record._name, 'mail.test.gateway') + + +class TestMailThreadCC(BaseFunctionalTest, MockEmails): + + @classmethod + def setUpClass(cls): + super(TestMailThreadCC, cls).setUpClass() + + cls.email_from = 'Sylvie Lelitre ' + cls.alias = cls.env['mail.alias'].create({ + 'alias_name': 'cc_record', + 'alias_user_id': False, + 'alias_model_id': cls.env['ir.model']._get('mail.test.cc').id, + 'alias_contact': 'everyone'}) + + cls._init_mail_gateway() + + @mute_logger('odoo.addons.mail.models.mail_thread') + def test_message_cc_new(self): + record = self.format_and_process(MAIL_TEMPLATE, self.email_from, 'cc_record@test.com', + cc='cc1@example.com, cc2@example.com', target_model='mail.test.cc') + cc = email_split_and_format(record.email_cc) + self.assertEqual(sorted(cc), ['cc1@example.com', 'cc2@example.com']) + + @mute_logger('odoo.addons.mail.models.mail_thread') + def test_message_cc_update_with_old(self): + record = self.env['mail.test.cc'].create({'email_cc': 'cc1 , cc2@example.com'}) + self.alias.write({'alias_force_thread_id': record.id}) + + self.format_and_process(MAIL_TEMPLATE, self.email_from, 'cc_record@test.com', + cc='cc2 , cc3@example.com', target_model='mail.test.cc') + cc = email_split_and_format(record.email_cc) + self.assertEqual(sorted(cc), ['cc1 ', 'cc2@example.com', 'cc3@example.com'], 'new cc should have been added on record (unique)') + + @mute_logger('odoo.addons.mail.models.mail_thread') + def test_message_cc_update_no_old(self): + record = self.env['mail.test.cc'].create({}) + self.alias.write({'alias_force_thread_id': record.id}) + + self.format_and_process(MAIL_TEMPLATE, self.email_from, 'cc_record@test.com', + cc='cc2 , cc3@example.com', target_model='mail.test.cc') + cc = email_split_and_format(record.email_cc) + self.assertEqual(sorted(cc), ['cc2 ', 'cc3@example.com'], 'new cc should have been added on record (unique)') diff --git a/addons/test_mail/tests/test_mail_mail.py b/addons/test_mail/tests/test_mail_mail.py index aebb4734fc3..912ed491aa9 100644 --- a/addons/test_mail/tests/test_mail_mail.py +++ b/addons/test_mail/tests/test_mail_mail.py @@ -2,27 +2,16 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import itertools +import psycopg2 +from odoo import api +from odoo.addons.base.models.ir_mail_server import MailDeliveryException from odoo.addons.test_mail.tests import common as mail_common from odoo.tests import common from odoo.tools import mute_logger -from odoo.addons.base.models.ir_mail_server import MailDeliveryException -class TestMail(common.SavepointCase, mail_common.MockEmails): - - @classmethod - def setUpClass(cls): - super(TestMail, cls).setUpClass() - - cls.user_employee = cls.env['res.users'].with_context(mail_common.BaseFunctionalTest._test_context).create({ - 'name': 'Ernest Employee', - 'login': 'ernest', - 'email': 'e.e@example.com', - 'signature': '--\nErnest', - 'notification_type': 'email', - 'groups_id': [(6, 0, [cls.env.ref('base.group_user').id])] - }) +class TestMail(mail_common.BaseFunctionalTest, mail_common.MockEmails): @mute_logger('odoo.addons.mail.models.mail_mail') def test_mail_message_notify_from_mail_mail(self): @@ -49,3 +38,67 @@ class TestMail(common.SavepointCase, mail_common.MockEmails): }) self.assertRaises(MailDeliveryException, lambda: mail.send(raise_exception=True)) + + +class TestMailRace(common.TransactionCase, mail_common.MockEmails): + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_mail_bounce_during_send(self): + self.partner = self.env['res.partner'].create({ + 'name': 'Ernest Partner', + }) + # we need to simulate a mail sent by the cron task, first create mail, message and notification by hand + mail = self.env['mail.mail'].create({ + 'body_html': '

Test

', + 'notification': True, + 'state': 'outgoing', + 'recipient_ids': [(4, self.partner.id)] + }) + message = self.env['mail.message'].create({ + 'subject': 'S', + 'body': 'B', + 'subtype_id': self.ref('mail.mt_comment'), + 'notification_ids': [(0, 0, { + 'res_partner_id': self.partner.id, + 'mail_id': mail.id, + 'notification_type': 'email', + 'is_read': True, + 'notification_status': 'ready', + })], + }) + notif = self.env['mail.notification'].search([('res_partner_id', '=', self.partner.id)]) + # we need to commit transaction or cr will keep the lock on notif + self.cr.commit() + + # patch send_email in order to create a concurent update and check the notif is already locked by _send() + this = self # coding in javascript ruinned my life + bounce_deferred = [] + @api.model + def send_email(self, message, *args, **kwargs): + with this.registry.cursor() as cr, mute_logger('odoo.sql_db'): + try: + # try ro aquire lock (no wait) on notification (should fail) + cr.execute("SELECT notification_status FROM mail_message_res_partner_needaction_rel WHERE id = %s FOR UPDATE NOWAIT", [notif.id]) + except psycopg2.OperationalError: + # record already locked by send, all good + bounce_deferred.append(True) + else: + # this should trigger psycopg2.extensions.TransactionRollbackError in send(). + # Only here to simulate the initial use case + # If the record is lock, this line would create a deadlock since we are in the same thread + # In practice, the update will wait the end of the send() transaction and set the notif as bounce, as expeced + cr.execute("UPDATE mail_message_res_partner_needaction_rel SET notification_status='bounce' WHERE id = %s", [notif.id]) + return message['Message-Id'] + self.env['ir.mail_server']._patch_method('send_email', send_email) + + mail.send() + + self.assertTrue(bounce_deferred, "The bounce should have been deferred") + self.assertEqual(notif.notification_status, 'sent') + + # some cleaning since we commited the cr + notif.unlink() + message.unlink() + mail.unlink() + self.partner.unlink() + self.env.cr.commit() diff --git a/addons/test_mail/tests/test_mail_message.py b/addons/test_mail/tests/test_mail_message.py index d4181f5b334..6d3290a8a95 100644 --- a/addons/test_mail/tests/test_mail_message.py +++ b/addons/test_mail/tests/test_mail_message.py @@ -16,17 +16,16 @@ class TestMessageValues(common.BaseFunctionalTest, common.MockEmails): def setUpClass(cls): super(TestMessageValues, cls).setUpClass() - cls.alias_record = cls.env['mail.test'].with_context(common.BaseFunctionalTest._test_context).create({ + cls._init_mail_gateway() + cls.alias_record = cls.env['mail.test'].with_context(cls._test_context).create({ 'name': 'Pigs', 'alias_name': 'pigs', 'alias_contact': 'followers', }) - cls.Message = cls.env['mail.message'].with_user(cls.user_employee) - def test_mail_message_values_basic(self): - self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink() - + @mute_logger('odoo.models.unlink') + def test_mail_message_values_no_document_values(self): msg = self.Message.create({ 'reply_to': 'test.reply@example.com', 'email_from': 'test.from@example.com', @@ -35,39 +34,45 @@ class TestMessageValues(common.BaseFunctionalTest, common.MockEmails): self.assertEqual(msg.reply_to, 'test.reply@example.com') self.assertEqual(msg.email_from, 'test.from@example.com') - def test_mail_message_values_default(self): - self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink() - - msg = self.Message.create({}) - self.assertIn('-private', msg.message_id.split('@')[0], 'mail_message: message_id for a void message should be a "private" one') - self.assertEqual(msg.reply_to, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) - self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) - @mute_logger('odoo.models.unlink') - def test_mail_message_values_alias(self): - alias_domain = 'example.com' - self.env['ir.config_parameter'].set_param('mail.catchall.domain', alias_domain) - self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.alias')]).unlink() - + def test_mail_message_values_no_document(self): msg = self.Message.create({}) self.assertIn('-private', msg.message_id.split('@')[0], 'mail_message: message_id for a void message should be a "private" one') - self.assertEqual(msg.reply_to, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) - self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) - - def test_mail_message_values_alias_catchall(self): - alias_domain = 'example.com' - alias_catchall = 'pokemon' - self.env['ir.config_parameter'].set_param('mail.catchall.domain', alias_domain) - self.env['ir.config_parameter'].set_param('mail.catchall.alias', alias_catchall) - - msg = self.Message.create({}) - self.assertIn('-private', msg.message_id.split('@')[0], 'mail_message: message_id for a void message should be a "private" one') - reply_to_name = self.env.company.name - reply_to_email = '%s@%s' % (alias_catchall, alias_domain) + reply_to_name = self.env.user.company_id.name + reply_to_email = '%s@%s' % (self.alias_catchall, self.alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) self.assertEqual(msg.email_from, formataddr((self.user_employee.name, self.user_employee.email))) - def test_mail_message_values_document_no_alias(self): + # no alias domain -> author + self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink() + + msg = self.Message.create({}) + self.assertIn('-private', msg.message_id.split('@')[0], 'mail_message: message_id for a void message should be a "private" one') + self.assertEqual(msg.reply_to, formataddr((self.user_employee.name, self.user_employee.email))) + self.assertEqual(msg.email_from, formataddr((self.user_employee.name, self.user_employee.email))) + + # no alias catchall, no alias -> author + self.env['ir.config_parameter'].set_param('mail.catchall.domain', self.alias_domain) + self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.alias')]).unlink() + + msg = self.Message.create({}) + self.assertIn('-private', msg.message_id.split('@')[0], 'mail_message: message_id for a void message should be a "private" one') + self.assertEqual(msg.reply_to, formataddr((self.user_employee.name, self.user_employee.email))) + self.assertEqual(msg.email_from, formataddr((self.user_employee.name, self.user_employee.email))) + + @mute_logger('odoo.models.unlink') + def test_mail_message_values_document_alias(self): + msg = self.Message.create({ + 'model': 'mail.test', + 'res_id': self.alias_record.id + }) + self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id.split('@')[0]) + reply_to_name = '%s %s' % (self.env.user.company_id.name, self.alias_record.name) + reply_to_email = '%s@%s' % (self.alias_record.alias_name, self.alias_domain) + self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) + self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) + + # no alias domain -> author self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.domain')]).unlink() msg = self.Message.create({ @@ -75,13 +80,11 @@ class TestMessageValues(common.BaseFunctionalTest, common.MockEmails): 'res_id': self.alias_record.id }) self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id.split('@')[0]) - self.assertEqual(msg.reply_to, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) - self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) + self.assertEqual(msg.reply_to, formataddr((self.user_employee.name, self.user_employee.email))) + self.assertEqual(msg.email_from, formataddr((self.user_employee.name, self.user_employee.email))) - @mute_logger('odoo.models.unlink') - def test_mail_message_values_document_alias(self): - alias_domain = 'example.com' - self.env['ir.config_parameter'].set_param('mail.catchall.domain', alias_domain) + # no catchall -> don't care, alias + self.env['ir.config_parameter'].set_param('mail.catchall.domain', self.alias_domain) self.env['ir.config_parameter'].search([('key', '=', 'mail.catchall.alias')]).unlink() msg = self.Message.create({ @@ -90,25 +93,45 @@ class TestMessageValues(common.BaseFunctionalTest, common.MockEmails): }) self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id.split('@')[0]) reply_to_name = '%s %s' % (self.env.company.name, self.alias_record.name) - reply_to_email = '%s@%s' % (self.alias_record.alias_name, alias_domain) + reply_to_email = '%s@%s' % (self.alias_record.alias_name, self.alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) - self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) + self.assertEqual(msg.email_from, formataddr((self.user_employee.name, self.user_employee.email))) - def test_mail_message_values_document_alias_catchall(self): - alias_domain = 'example.com' - alias_catchall = 'pokemon' - self.env['ir.config_parameter'].set_param('mail.catchall.domain', alias_domain) - self.env['ir.config_parameter'].set_param('mail.catchall.alias', alias_catchall) + @mute_logger('odoo.models.unlink') + def test_mail_message_values_document_no_alias(self): + test_record = self.env['mail.test.simple'].create({'name': 'Test', 'email_from': 'ignasse@example.com'}) msg = self.Message.create({ - 'model': 'mail.test', - 'res_id': self.alias_record.id + 'model': 'mail.test.simple', + 'res_id': test_record.id }) - self.assertIn('-openerp-%d-mail.test' % self.alias_record.id, msg.message_id.split('@')[0]) - reply_to_name = '%s %s' % (self.env.company.name, self.alias_record.name) - reply_to_email = '%s@%s' % (self.alias_record.alias_name, alias_domain) + self.assertIn('-openerp-%d-mail.test.simple' % test_record.id, msg.message_id.split('@')[0]) + reply_to_name = '%s %s' % (self.env.user.company_id.name, test_record.name) + reply_to_email = '%s@%s' % (self.alias_catchall, self.alias_domain) self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) - self.assertEqual(msg.email_from, '%s <%s>' % (self.user_employee.name, self.user_employee.email)) + self.assertEqual(msg.email_from, formataddr((self.user_employee.name, self.user_employee.email))) + + @mute_logger('odoo.models.unlink') + def test_mail_message_values_document_manual_alias(self): + test_record = self.env['mail.test.simple'].create({'name': 'Test', 'email_from': 'ignasse@example.com'}) + alias = self.env['mail.alias'].create({ + 'alias_name': 'MegaLias', + 'alias_user_id': False, + 'alias_model_id': self.env['ir.model']._get('mail.test.simple').id, + 'alias_parent_model_id': self.env['ir.model']._get('mail.test.simple').id, + 'alias_parent_thread_id': test_record.id, + }) + + msg = self.Message.create({ + 'model': 'mail.test.simple', + 'res_id': test_record.id + }) + + self.assertIn('-openerp-%d-mail.test.simple' % test_record.id, msg.message_id.split('@')[0]) + reply_to_name = '%s %s' % (self.env.user.company_id.name, test_record.name) + reply_to_email = '%s@%s' % (alias.alias_name, self.alias_domain) + self.assertEqual(msg.reply_to, formataddr((reply_to_name, reply_to_email))) + self.assertEqual(msg.email_from, formataddr((self.user_employee.name, self.user_employee.email))) def test_mail_message_values_no_auto_thread(self): msg = self.Message.create({ @@ -139,7 +162,7 @@ class TestMessageAccess(common.BaseFunctionalTest, common.MockEmails): cls.user_public = mail_new_test_user(cls.env, login='bert', groups='base.group_public', name='Bert Tartignole') cls.user_portal = mail_new_test_user(cls.env, login='chell', groups='base.group_portal', name='Chell Gladys') - Channel = cls.env['mail.channel'].with_context(common.BaseFunctionalTest._test_context) + Channel = cls.env['mail.channel'].with_context(cls._test_context) # Pigs: base group for tests cls.group_pigs = Channel.create({ 'name': 'Pigs', diff --git a/addons/test_mail/tests/test_mail_race.py b/addons/test_mail/tests/test_mail_race.py deleted file mode 100644 index 310051a7d68..00000000000 --- a/addons/test_mail/tests/test_mail_race.py +++ /dev/null @@ -1,73 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -import psycopg2 - -from odoo import api -from odoo.addons.test_mail.tests import common as mail_common -from odoo.tests import common -from odoo.tools import mute_logger - - -class TestMailRace(common.TransactionCase, mail_common.MockEmails): - - @mute_logger('odoo.addons.mail.models.mail_mail') - def test_mail_bounce_during_send(self): - self.partner = self.env['res.partner'].create({ - 'name': 'Ernest Partner', - }) - # we need to simulate a mail sent by the cron task, first create mail, message and notification by hand - mail = self.env['mail.mail'].create({ - 'body_html': '

Test

', - 'notification': True, - 'state': 'outgoing', - 'recipient_ids': [(4, self.partner.id)] - }) - message = self.env['mail.message'].create({ - 'subject': 'S', - 'body': 'B', - 'subtype_id': self.ref('mail.mt_comment'), - 'notification_ids': [(0, 0, { - 'res_partner_id': self.partner.id, - 'mail_id': mail.id, - 'notification_type': 'email', - 'is_read': True, - 'notification_status': 'ready', - })], - }) - notif = self.env['mail.notification'].search([('res_partner_id', '=', self.partner.id)]) - # we need to commit transaction or cr will keep the lock on notif - self.cr.commit() - - # patch send_email in order to create a concurent update and check the notif is already locked by _send() - this = self # coding in javascript ruinned my life - bounce_deferred = [] - @api.model - def send_email(self, message, *args, **kwargs): - with this.registry.cursor() as cr, mute_logger('odoo.sql_db'): - try: - # try ro aquire lock (no wait) on notification (should fail) - cr.execute("SELECT notification_status FROM mail_message_res_partner_needaction_rel WHERE id = %s FOR UPDATE NOWAIT", [notif.id]) - except psycopg2.OperationalError: - # record already locked by send, all good - bounce_deferred.append(True) - else: - # this should trigger psycopg2.extensions.TransactionRollbackError in send(). - # Only here to simulate the initial use case - # If the record is lock, this line would create a deadlock since we are in the same thread - # In practice, the update will wait the end of the send() transaction and set the notif as bounce, as expeced - cr.execute("UPDATE mail_message_res_partner_needaction_rel SET notification_status='bounce' WHERE id = %s", [notif.id]) - return message['Message-Id'] - self.env['ir.mail_server']._patch_method('send_email', send_email) - - mail.send() - - self.assertTrue(bounce_deferred, "The bounce should have been deferred") - self.assertEqual(notif.notification_status, 'sent') - - # some cleaning since we commited the cr - notif.unlink() - message.unlink() - mail.unlink() - self.partner.unlink() - self.env.cr.commit() diff --git a/addons/test_mail/tests/test_multi_company.py b/addons/test_mail/tests/test_mail_redirect.py similarity index 100% rename from addons/test_mail/tests/test_multi_company.py rename to addons/test_mail/tests/test_mail_redirect.py diff --git a/addons/test_mail/tests/test_mail_template.py b/addons/test_mail/tests/test_mail_template.py index df3f47b4d95..5ef9d8277a2 100644 --- a/addons/test_mail/tests/test_mail_template.py +++ b/addons/test_mail/tests/test_mail_template.py @@ -2,191 +2,54 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import base64 -from datetime import datetime, timedelta -from unittest.mock import patch from odoo.addons.test_mail.tests.common import BaseFunctionalTest, MockEmails, TestRecipients -from odoo.addons.test_mail.tests.common import mail_new_test_user -from odoo.tools import mute_logger, DEFAULT_SERVER_DATETIME_FORMAT +from odoo.tools import mute_logger class TestMailTemplate(BaseFunctionalTest, MockEmails, TestRecipients): - def setUp(self): - super(TestMailTemplate, self).setUp() + @classmethod + def setUpClass(cls): + super(TestMailTemplate, cls).setUpClass() + cls.test_record = cls.env['mail.test.simple'].with_context(cls._test_context).create({'name': 'Test', 'email_from': 'ignasse@example.com'}) - self.user_employee.write({ - 'groups_id': [(4, self.env.ref('base.group_partner_manager').id)], + cls.user_employee.write({ + 'groups_id': [(4, cls.env.ref('base.group_partner_manager').id)], }) - self._attachments = [{ + cls._attachments = [{ 'name': 'first.txt', 'datas': base64.b64encode(b'My first attachment'), 'res_model': 'res.partner', - 'res_id': self.user_admin.partner_id.id + 'res_id': cls.user_admin.partner_id.id }, { 'name': 'second.txt', 'datas': base64.b64encode(b'My second attachment'), 'res_model': 'res.partner', - 'res_id': self.user_admin.partner_id.id + 'res_id': cls.user_admin.partner_id.id }] - self.email_1 = 'test1@example.com' - self.email_2 = 'test2@example.com' - self.email_3 = self.partner_1.email - self.email_template = self.env['mail.template'].create({ - 'model_id': self.env['ir.model']._get('mail.test.simple').id, - 'name': 'Pigs Template', - 'subject': '${object.name}', - 'body_html': '${object.email_from}', - 'user_signature': False, - 'attachment_ids': [(0, 0, self._attachments[0]), (0, 0, self._attachments[1])], - 'partner_to': '%s,%s' % (self.partner_2.id, self.user_admin.partner_id.id), - 'email_to': '%s, %s' % (self.email_1, self.email_2), - 'email_cc': '%s' % self.email_3}) + cls.email_1 = 'test1@example.com' + cls.email_2 = 'test2@example.com' + cls.email_3 = cls.partner_1.email + cls._create_template('mail.test.simple', { + 'attachment_ids': [(0, 0, cls._attachments[0]), (0, 0, cls._attachments[1])], + 'partner_to': '%s,%s' % (cls.partner_2.id, cls.user_admin.partner_id.id), + 'email_to': '%s, %s' % (cls.email_1, cls.email_2), + 'email_cc': '%s' % cls.email_3, + }) # admin should receive emails - self.user_admin.write({'notification_type': 'email'}) + cls.user_admin.write({'notification_type': 'email'}) # Force the attachments of the template to be in the natural order. - self.email_template.invalidate_cache(['attachment_ids'], ids=self.email_template.ids) - - @mute_logger('odoo.addons.mail.models.mail_mail') - def test_composer_w_template(self): - composer = self.env['mail.compose.message'].with_user(self.user_employee).with_context({ - 'default_composition_mode': 'comment', - 'default_model': 'mail.test.simple', - 'default_res_id': self.test_record.id, - 'default_template_id': self.email_template.id, - }).create({'subject': 'Forget me subject', 'body': 'Dummy body'}) - - # perform onchange and send emails - values = composer.onchange_template_id(self.email_template.id, 'comment', self.test_record._name, self.test_record.id)['value'] - composer.write(values) - composer.send_mail() - - new_partners = self.env['res.partner'].search([('email', 'in', [self.email_1, self.email_2])]) - self.assertEmails( - self.user_employee.partner_id, - [[self.partner_1], [self.partner_2], [new_partners[0]], [new_partners[1]], [self.partner_admin]], - subject=self.test_record.name, - body_content=self.test_record.email_from, - 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, - static attachments are not duplicated and while reports are re-generated, - and that intermediary attachments are dropped.""" - - composer = self.env['mail.compose.message'].with_context(default_attachment_ids=[]).create({}) - report_template = self.env.ref('web.action_report_externalpreview') - template_1 = self.email_template.copy({ - 'report_template': report_template.id, - }) - template_2 = self.email_template.copy({ - 'attachment_ids': False, - 'report_template': report_template.id, - }) - - onchange_templates = [template_1, template_2, template_1, False] - attachments_onchange = [composer.attachment_ids] - # template_1 has two static attachments and one dynamically generated report, - # template_2 only has the report, so we should get 3, 1, 3 attachments - attachment_numbers = [0, 3, 1, 3, 0] - - for template in onchange_templates: - onchange = composer.onchange_template_id( - template.id if template else False, 'comment', self.test_record._name, self.test_record.id - ) - composer.update(onchange['value']) - attachments_onchange.append(composer.attachment_ids) - - self.assertEqual( - [len(attachments) for attachments in attachments_onchange], - attachment_numbers, - ) - - self.assertTrue( - len(attachments_onchange[1] & attachments_onchange[3]) == 2, - "The two static attachments on the template should be common to the two onchanges" - ) - - @mute_logger('odoo.addons.mail.models.mail_mail') - def test_post_post_w_template(self): - self.test_record.with_user(self.user_employee).message_post_with_template(self.email_template.id, composition_mode='comment') - - new_partners = self.env['res.partner'].search([('email', 'in', [self.email_1, self.email_2])]) - self.assertEmails( - self.user_employee.partner_id, - [[self.partner_1], [self.partner_2], [new_partners[0]], [new_partners[1]], [self.partner_admin]], - subject=self.test_record.name, - body_content=self.test_record.email_from, - attachments=[('first.txt', b'My first attachment', 'text/plain'), ('second.txt', b'My second attachment', 'text/plain')]) - - @mute_logger('odoo.addons.mail.models.mail_mail') - def test_composer_w_template_mass_mailing(self): - test_record_2 = self.env['mail.test.simple'].with_context(BaseFunctionalTest._test_context).create({'name': 'Test2', 'email_from': 'laurie.poiret@example.com'}) - - composer = self.env['mail.compose.message'].with_user(self.user_employee).with_context({ - 'default_composition_mode': 'mass_mail', - # 'default_notify': True, - 'default_notify': False, - 'default_model': 'mail.test.simple', - 'default_res_id': self.test_record.id, - 'default_template_id': self.email_template.id, - 'active_ids': [self.test_record.id, test_record_2.id] - }).create({}) - values = composer.onchange_template_id(self.email_template.id, 'mass_mail', 'mail.test.simple', self.test_record.id)['value'] - composer.write(values) - composer.send_mail() - - new_partners = self.env['res.partner'].search([('email', 'in', [self.email_1, self.email_2])]) - # hack to use assertEmails - self._mails_record1 = [dict(mail) for mail in self._mails if '%s-%s' % (self.test_record.id, self.test_record._name) in mail['message_id']] - 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.assertEmails( - self.user_employee.partner_id, - [[self.partner_1], [self.partner_2], [new_partners[0]], [new_partners[1]], [self.partner_admin]], - subject=self.test_record.name, - body_content=self.test_record.email_from, - attachments=[('first.txt', b'My first attachment', 'text/plain'), ('second.txt', b'My second attachment', 'text/plain')]) - - self._mails = self._mails_record2 - self.assertEmails( - self.user_employee.partner_id, - [[self.partner_1], [self.partner_2], [new_partners[0]], [new_partners[1]], [self.partner_admin]], - subject=test_record_2.name, - body_content=test_record_2.email_from, - 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] - - # messages effectively posted - self.assertEqual(message_1.subject, self.test_record.name) - self.assertEqual(message_2.subject, test_record_2.name) - self.assertIn(self.test_record.email_from, message_1.body) - self.assertIn(test_record_2.email_from, message_2.body) - - def test_composer_template_save(self): - self.env['mail.compose.message'].with_context({ - 'default_composition_mode': 'comment', - 'default_model': 'mail.test.simple', - 'default_res_id': self.test_record.id, - }).create({ - 'subject': 'Forget me subject', - 'body': '

Dummy body

' - }).save_as_template() - # Test: email_template subject, body_html, model - last_template = self.env['mail.template'].search([('model', '=', 'mail.test.simple'), ('subject', '=', 'Forget me subject')], limit=1) - self.assertEqual(last_template.body_html, '

Dummy body

', 'email_template incorrect body_html') + cls.email_template.invalidate_cache(['attachment_ids'], ids=cls.email_template.ids) @mute_logger('odoo.addons.mail.models.mail_mail') def test_template_send_email(self): mail_id = self.email_template.send_mail(self.test_record.id) mail = self.env['mail.mail'].browse(mail_id) - self.assertEqual(mail.subject, self.test_record.name) + self.assertEqual(mail.subject, 'About %s' % self.test_record.name) self.assertEqual(mail.email_to, self.email_template.email_to) self.assertEqual(mail.email_cc, self.email_template.email_cc) self.assertEqual(mail.recipient_ids, self.partner_2 | self.user_admin.partner_id) @@ -241,37 +104,3 @@ class TestMailTemplate(BaseFunctionalTest, MockEmails, TestRecipients): # self.env['mail.mail'].process_email_queue(ids=[mail_in_2_days.id]) # self.assertEqual(mail_in_2_days.state, 'outgoing') # self.assertEqual(mail_now.exists() | mail_in_2_days.exists(), mail_in_2_days) - - def test_create_partner_from_tracking_multicompany(self): - company1 = self.env['res.company'].create({'name': 'company1'}) - self.env.user.write({'company_ids': [(4, company1.id, False)]}) - self.assertNotEqual(self.env.company, company1) - - email_new_partner = "diamonds@rust.com" - Partner = self.env['res.partner'] - self.assertFalse(Partner.search([('email', '=', email_new_partner)])) - - template = self.env['mail.template'].create({ - 'model_id': self.env['ir.model']._get('mail.test.track').id, - 'name': 'AutoTemplate', - 'subject': 'autoresponse', - 'email_from': self.env.user.email_formatted, - 'email_to': "${object.email_from}", - 'body_html': "
A nice body
", - }) - - def patched_message_track_post_template(*args, **kwargs): - if args[0]._name == "mail.test.track": - args[0].message_post_with_template(template.id) - return True - - with patch('odoo.addons.mail.models.mail_thread.MailThread._message_track_post_template', patched_message_track_post_template): - self.env['mail.test.track'].create({ - 'email_from': email_new_partner, - 'company_id': company1.id, - 'user_id': self.env.user.id, # trigger track template - }) - - new_partner = Partner.search([('email', '=', email_new_partner)]) - self.assertTrue(new_partner) - self.assertEqual(new_partner.company_id, company1) diff --git a/addons/test_mail/tests/test_message_composer.py b/addons/test_mail/tests/test_message_composer.py new file mode 100644 index 00000000000..ae0ecbcd483 --- /dev/null +++ b/addons/test_mail/tests/test_message_composer.py @@ -0,0 +1,321 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import base64 + +from unittest.mock import patch + +from odoo.addons.test_mail.tests.common import BaseFunctionalTest, MockEmails, TestRecipients +from odoo.addons.test_mail.tests.common import mail_new_test_user +from odoo.addons.test_mail.models.test_mail_models import MailTestSimple +from odoo.tools import mute_logger + + +class TestComposer(BaseFunctionalTest, MockEmails, TestRecipients): + + @classmethod + def setUpClass(cls): + super(TestComposer, cls).setUpClass() + cls.test_record = cls.env['mail.test.simple'].with_context(cls._test_context).create({'name': 'Test', 'email_from': 'ignasse@example.com'}) + + # configure mailing + cls.alias_domain = 'schlouby.fr' + cls.alias_catchall = 'test+catchall' + cls.env['ir.config_parameter'].set_param('mail.catchall.domain', cls.alias_domain) + cls.env['ir.config_parameter'].set_param('mail.catchall.alias', cls.alias_catchall) + + # admin should not receive emails + cls.user_admin.write({'notification_type': 'email'}) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_composer_comment(self): + composer = self.env['mail.compose.message'].with_context({ + 'default_composition_mode': 'comment', + 'default_model': self.test_record._name, + 'default_res_id': self.test_record.id, + }).with_user(self.user_employee).create({ + 'body': '

Test Body

', + 'partner_ids': [(4, self.partner_1.id), (4, self.partner_2.id)] + }) + composer.send_mail() + + message = self.test_record.message_ids[0] + self.assertEqual(message.body, '

Test Body

') + self.assertEqual(message.author_id, self.user_employee.partner_id) + self.assertEqual(message.subject, 'Re: %s' % self.test_record.name) + self.assertEqual(message.subtype_id, self.env.ref('mail.mt_comment')) + self.assertEqual(message.partner_ids, self.partner_1 | self.partner_2) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_composer_comment_parent(self): + parent = self.test_record.message_post(body='Test') + + self.env['mail.compose.message'].with_context({ + 'default_composition_mode': 'comment', + 'default_parent_id': parent.id + }).with_user(self.user_employee).create({ + 'body': '

Mega

', + }).send_mail() + + message = self.test_record.message_ids[0] + self.assertEqual(message.body, '

Mega

') + self.assertEqual(message.parent_id, parent) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_composer_mass_mail(self): + test_record_2 = self.env['mail.test.simple'].with_context(self._test_context).create({'name': 'Test2'}) + + composer = self.env['mail.compose.message'].with_context({ + 'default_composition_mode': 'mass_mail', + 'default_model': self.test_record._name, + 'default_res_id': False, + 'active_ids': [self.test_record.id, test_record_2.id] + }).with_user(self.user_employee).create({ + 'subject': 'Testing ${object.name}', + 'body': '

${object.name}

', + 'partner_ids': [(4, self.partner_1.id), (4, self.partner_2.id)] + }) + composer.with_context({ + 'default_res_id': -1, + 'active_ids': [self.test_record.id, test_record_2.id] + }).send_mail() + + # check mail_mail + mails = self.env['mail.mail'].search([('subject', 'ilike', 'Testing')]) + for mail in mails: + self.assertEqual(mail.recipient_ids, self.partner_1 | self.partner_2, + 'compose wizard: mail_mail mass mailing: mail.mail in mass mail incorrect recipients') + + # check message on test_record + message1 = self.test_record.message_ids[0] + self.assertEqual(message1.subject, 'Testing %s' % self.test_record.name) + self.assertEqual(message1.body, '

%s

' % self.test_record.name) + + # check message on test_record_2 + message1 = test_record_2.message_ids[0] + self.assertEqual(message1.subject, 'Testing %s' % test_record_2.name) + self.assertEqual(message1.body, '

%s

' % test_record_2.name) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_composer_mass_mail_active_domain(self): + test_record_2 = self.env['mail.test.simple'].with_context(self._test_context).create({'name': 'Test2'}) + + self.env['mail.compose.message'].with_context({ + 'default_composition_mode': 'mass_mail', + 'default_model': self.test_record._name, + 'default_use_active_domain': True, + 'active_ids': [self.test_record.id], + 'active_domain': [('name', 'in', ['%s' % self.test_record.name, '%s' % test_record_2.name])], + }).with_user(self.user_employee).create({ + 'subject': 'From Composer Test', + 'body': '${object.name}', + }).send_mail() + + self.assertEqual(self.test_record.message_ids[0].subject, 'From Composer Test') + self.assertEqual(test_record_2.message_ids[0].subject, 'From Composer Test') + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_message_compose_mass_mail_no_active_domain(self): + test_record_2 = self.env['mail.test.simple'].with_context(self._test_context).create({'name': 'Test2'}) + + self.env['mail.compose.message'].with_context({ + 'default_composition_mode': 'mass_mail', + 'default_model': self.test_record._name, + 'default_use_active_domain': False, + 'active_ids': [self.test_record.id], + 'active_domain': [('name', 'in', ['%s' % self.test_record.name, '%s' % test_record_2.name])], + }).with_user(self.user_employee).create({ + 'subject': 'From Composer Test', + 'body': '${object.name}', + }).send_mail() + + self.assertEqual(self.test_record.message_ids[0].subject, 'From Composer Test') + self.assertFalse(test_record_2.message_ids.ids) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_message_compose_portal_ok(self): + portal_user = mail_new_test_user(self.env, login='chell', groups='base.group_portal', name='Chell Gladys') + + with patch.object(MailTestSimple, 'check_access_rights', return_value=True): + ComposerPortal = self.env['mail.compose.message'].with_user(portal_user) + + ComposerPortal.with_context({ + 'default_composition_mode': 'comment', + 'default_model': self.test_record._name, + 'default_res_id': self.test_record.id, + }).create({ + 'subject': 'Subject', + 'body': '

Body text

', + 'partner_ids': []}).send_mail() + + self.assertEqual(self.test_record.message_ids[0].body, '

Body text

') + self.assertEqual(self.test_record.message_ids[0].author_id, portal_user.partner_id) + + ComposerPortal.with_context({ + 'default_composition_mode': 'comment', + 'default_parent_id': self.test_record.message_ids.ids[0], + }).create({ + 'subject': 'Subject', + 'body': '

Body text 2

'}).send_mail() + + self.assertEqual(self.test_record.message_ids[0].body, '

Body text 2

') + self.assertEqual(self.test_record.message_ids[0].author_id, portal_user.partner_id) + + +class TestComposerWTpl(BaseFunctionalTest, MockEmails, TestRecipients): + + @classmethod + def setUpClass(cls): + super(TestComposerWTpl, cls).setUpClass() + cls.test_record = cls.env['mail.test.simple'].with_context(cls._test_context).create({'name': 'Test', 'email_from': 'ignasse@example.com'}) + + cls.user_employee.write({ + 'groups_id': [(4, cls.env.ref('base.group_partner_manager').id)], + }) + + cls._attachments = [{ + 'name': 'first.txt', + 'datas': base64.b64encode(b'My first attachment'), + 'res_model': 'res.partner', + 'res_id': cls.user_admin.partner_id.id + }, { + 'name': 'second.txt', + 'datas': base64.b64encode(b'My second attachment'), + 'res_model': 'res.partner', + 'res_id': cls.user_admin.partner_id.id + }] + + cls.email_1 = 'test1@example.com' + cls.email_2 = 'test2@example.com' + cls.email_3 = cls.partner_1.email + cls._create_template('mail.test.simple', { + 'attachment_ids': [(0, 0, cls._attachments[0]), (0, 0, cls._attachments[1])], + 'partner_to': '%s,%s' % (cls.partner_2.id, cls.user_admin.partner_id.id), + 'email_to': '%s, %s' % (cls.email_1, cls.email_2), + 'email_cc': '%s' % cls.email_3, + }) + + # admin should receive emails + cls.user_admin.write({'notification_type': 'email'}) + # Force the attachments of the template to be in the natural order. + cls.email_template.invalidate_cache(['attachment_ids'], ids=cls.email_template.ids) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_composer_w_template(self): + composer = self.env['mail.compose.message'].with_user(self.user_employee).with_context({ + 'default_composition_mode': 'comment', + 'default_model': 'mail.test.simple', + 'default_res_id': self.test_record.id, + 'default_template_id': self.email_template.id, + }).create({'subject': 'Forget me subject', 'body': 'Dummy body'}) + + # perform onchange and send emails + values = composer.onchange_template_id(self.email_template.id, 'comment', self.test_record._name, self.test_record.id)['value'] + composer.write(values) + composer.send_mail() + + new_partners = self.env['res.partner'].search([('email', 'in', [self.email_1, self.email_2])]) + self.assertEmails( + self.user_employee.partner_id, + [[self.partner_1], [self.partner_2], [new_partners[0]], [new_partners[1]], [self.partner_admin]], + 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, + static attachments are not duplicated and while reports are re-generated, + and that intermediary attachments are dropped.""" + + composer = self.env['mail.compose.message'].with_context(default_attachment_ids=[]).create({}) + report_template = self.env.ref('web.action_report_externalpreview') + template_1 = self.email_template.copy({ + 'report_template': report_template.id, + }) + template_2 = self.email_template.copy({ + 'attachment_ids': False, + 'report_template': report_template.id, + }) + + onchange_templates = [template_1, template_2, template_1, False] + attachments_onchange = [composer.attachment_ids] + # template_1 has two static attachments and one dynamically generated report, + # template_2 only has the report, so we should get 3, 1, 3 attachments + attachment_numbers = [0, 3, 1, 3, 0] + + for template in onchange_templates: + onchange = composer.onchange_template_id( + template.id if template else False, 'comment', self.test_record._name, self.test_record.id + ) + composer.update(onchange['value']) + attachments_onchange.append(composer.attachment_ids) + + self.assertEqual( + [len(attachments) for attachments in attachments_onchange], + attachment_numbers, + ) + + self.assertTrue( + len(attachments_onchange[1] & attachments_onchange[3]) == 2, + "The two static attachments on the template should be common to the two onchanges" + ) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_composer_w_template_mass_mailing(self): + test_record_2 = self.env['mail.test.simple'].with_context(self._test_context).create({'name': 'Test2', 'email_from': 'laurie.poiret@example.com'}) + + composer = self.env['mail.compose.message'].with_user(self.user_employee).with_context({ + 'default_composition_mode': 'mass_mail', + # 'default_notify': True, + 'default_notify': False, + 'default_model': 'mail.test.simple', + 'default_res_id': self.test_record.id, + 'default_template_id': self.email_template.id, + 'active_ids': [self.test_record.id, test_record_2.id] + }).create({}) + values = composer.onchange_template_id(self.email_template.id, 'mass_mail', 'mail.test.simple', self.test_record.id)['value'] + composer.write(values) + composer.send_mail() + + new_partners = self.env['res.partner'].search([('email', 'in', [self.email_1, self.email_2])]) + # hack to use assertEmails + self._mails_record1 = [dict(mail) for mail in self._mails if '%s-%s' % (self.test_record.id, self.test_record._name) in mail['message_id']] + 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.assertEmails( + self.user_employee.partner_id, + [[self.partner_1], [self.partner_2], [new_partners[0]], [new_partners[1]], [self.partner_admin]], + 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.assertEmails( + self.user_employee.partner_id, + [[self.partner_1], [self.partner_2], [new_partners[0]], [new_partners[1]], [self.partner_admin]], + 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] + + # messages effectively posted + self.assertEqual(message_1.subject, 'About %s' % self.test_record.name) + self.assertEqual(message_2.subject, 'About %s' % test_record_2.name) + self.assertIn(self.test_record.name, message_1.body) + self.assertIn(test_record_2.name, message_2.body) + + def test_composer_template_save(self): + self.env['mail.compose.message'].with_context({ + 'default_composition_mode': 'comment', + 'default_model': 'mail.test.simple', + 'default_res_id': self.test_record.id, + }).create({ + 'subject': 'Forget me subject', + 'body': '

Dummy body

' + }).save_as_template() + # Test: email_template subject, body_html, model + last_template = self.env['mail.template'].search([('model', '=', 'mail.test.simple'), ('subject', '=', 'Forget me subject')], limit=1) + self.assertEqual(last_template.body_html, '

Dummy body

', 'email_template incorrect body_html') diff --git a/addons/test_mail/tests/test_mail_resend.py b/addons/test_mail/tests/test_message_management.py similarity index 94% rename from addons/test_mail/tests/test_mail_resend.py rename to addons/test_mail/tests/test_message_management.py index cec04958a9a..557eebd4ca7 100644 --- a/addons/test_mail/tests/test_mail_resend.py +++ b/addons/test_mail/tests/test_message_management.py @@ -17,15 +17,17 @@ class TestMailResend(common.BaseFunctionalTest, common.MockEmails): @classmethod def setUpClass(cls): super(TestMailResend, cls).setUpClass() + cls.test_record = cls.env['mail.test.simple'].with_context(cls._test_context).create({'name': 'Test', 'email_from': 'ignasse@example.com'}) + #Two users cls.user1 = mail_new_test_user(cls.env, login='e1', groups='base.group_public', name='Employee 1', email='e1') # invalid email cls.user2 = mail_new_test_user(cls.env, login='e2', groups='base.group_portal', name='Employee 2', email='e2@example.com') #Two partner - cls.partner1 = cls.env['res.partner'].with_context(common.BaseFunctionalTest._test_context).create({ + cls.partner1 = cls.env['res.partner'].with_context(cls._test_context).create({ 'name': 'Partner 1', 'email': 'p1' # invalid email }) - cls.partner2 = cls.env['res.partner'].with_context(common.BaseFunctionalTest._test_context).create({ + cls.partner2 = cls.env['res.partner'].with_context(cls._test_context).create({ 'name': 'Partner 2', 'email': 'p2@example.com' }) diff --git a/addons/test_mail/tests/test_message_compose.py b/addons/test_mail/tests/test_message_post.py similarity index 57% rename from addons/test_mail/tests/test_message_compose.py rename to addons/test_mail/tests/test_message_post.py index adf1dd80ae6..2eecfb98b9e 100644 --- a/addons/test_mail/tests/test_message_compose.py +++ b/addons/test_mail/tests/test_message_post.py @@ -7,26 +7,61 @@ from email.utils import formataddr from unittest.mock import patch from odoo.addons.test_mail.tests.common import BaseFunctionalTest, MockEmails, TestRecipients -from odoo.addons.test_mail.tests.common import mail_new_test_user from odoo.addons.test_mail.data.test_mail_data import MAIL_TEMPLATE_PLAINTEXT from odoo.addons.test_mail.models.test_mail_models import MailTestSimple from odoo.exceptions import AccessError from odoo.tools import mute_logger -class TestMessagePost(BaseFunctionalTest, MockEmails, TestRecipients): +class TestMessagePost(BaseFunctionalTest, TestRecipients, MockEmails): - def setUp(self): - super(TestMessagePost, self).setUp() + @classmethod + def setUpClass(cls): + super(TestMessagePost, cls).setUpClass() + cls._create_portal_user() + cls.test_record = cls.env['mail.test.simple'].with_context(cls._test_context).create({'name': 'Test', 'email_from': 'ignasse@example.com'}) # configure mailing - self.alias_domain = 'schlouby.fr' - self.alias_catchall = 'test+catchall' - self.env['ir.config_parameter'].set_param('mail.catchall.domain', self.alias_domain) - self.env['ir.config_parameter'].set_param('mail.catchall.alias', self.alias_catchall) + cls.alias_domain = 'schlouby.fr' + cls.alias_catchall = 'test+catchall' + cls.env['ir.config_parameter'].set_param('mail.catchall.domain', cls.alias_domain) + cls.env['ir.config_parameter'].set_param('mail.catchall.alias', cls.alias_catchall) - # admin should not receive emails - self.user_admin.write({'notification_type': 'email'}) + cls.user_admin.write({'notification_type': 'email'}) + + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_post_needaction(self): + (self.user_employee | self.user_admin).write({'notification_type': 'inbox'}) + with self.assertNotifications(partner_employee=(1, 'inbox', 'unread'), partner_admin=(0, '', '')): + self.test_record.message_post( + body='Test', message_type='comment', subtype='mail.mt_comment', + partner_ids=[self.user_employee.partner_id.id]) + + self.test_record.message_subscribe([self.partner_1.id]) + with self.assertNotifications(partner_employee=(1, 'inbox', 'unread'), partner_admin=(0, '', ''), partner_1=(1, 'email', 'read')): + self.test_record.message_post( + body='Test', message_type='comment', subtype='mail.mt_comment', + partner_ids=[self.user_employee.partner_id.id]) + + with self.assertNotifications(partner_admin=(0, '', ''), partner_1=(1, 'email', 'read'), partner_portal=(1, 'email', 'read')): + self.test_record.message_post( + body='Test', message_type='comment', subtype='mail.mt_comment', + partner_ids=[self.partner_portal.id]) + + def test_post_inactive_follower(self): + # In some case odoobot is follower of a record. + # Even if it shouldn't be the case, we want to be sure that odoobot is not notified + (self.user_employee | self.user_admin).write({'notification_type': 'inbox'}) + self.test_record._message_subscribe(self.user_employee.partner_id.ids) + with self.assertNotifications(partner_employee=(1, 'inbox', 'unread')): + self.test_record.message_post( + body='Test', message_type='comment', subtype='mail.mt_comment') + self.user_employee.active = False + # at this point, partner is still active and would receive an email notification + self.user_employee.partner_id._write({'active': False}) + with self.assertNotifications(partner_employee=(0, '', '')): + self.test_record.message_post( + body='Test', message_type='comment', subtype='mail.mt_comment') @mute_logger('odoo.addons.mail.models.mail_mail') def test_post_notifications(self): @@ -153,22 +188,18 @@ class TestMessagePost(BaseFunctionalTest, MockEmails, TestRecipients): @mute_logger('odoo.addons.mail.models.mail_mail') def test_post_portal_ok(self): - portal_user = mail_new_test_user(self.env, login='chell', groups='base.group_portal', name='Chell Gladys') - with patch.object(MailTestSimple, 'check_access_rights', return_value=True): self.test_record.message_subscribe((self.partner_1 | self.user_employee.partner_id).ids) - new_msg = self.test_record.with_user(portal_user).message_post( + new_msg = self.test_record.with_user(self.user_portal).message_post( body='

Test

', subject='Subject', message_type='comment', subtype='mt_comment') self.assertEqual(new_msg.sudo().notified_partner_ids, (self.partner_1 | self.user_employee.partner_id)) - self.assertEmails(portal_user.partner_id, [[self.partner_1], [self.user_employee.partner_id]]) + self.assertEmails(self.user_portal.partner_id, [[self.partner_1], [self.user_employee.partner_id]]) def test_post_portal_crash(self): - portal_user = mail_new_test_user(self.env, login='chell', groups='base.group_portal', name='Chell Gladys') - with self.assertRaises(AccessError): - self.test_record.with_user(portal_user).message_post( + self.test_record.with_user(self.user_portal).message_post( body='

Test

', subject='Subject', message_type='comment', subtype='mt_comment') @@ -220,151 +251,43 @@ class TestMessagePost(BaseFunctionalTest, MockEmails, TestRecipients): self.assertNotIn(new_notification, self.test_record.message_ids) # todo xdo add test message_notify on thread with followers and stuff - -class TestComposer(BaseFunctionalTest, MockEmails, TestRecipients): - - def setUp(self): - super(TestComposer, self).setUp() - - # configure mailing - self.alias_domain = 'schlouby.fr' - self.alias_catchall = 'test+catchall' - self.env['ir.config_parameter'].set_param('mail.catchall.domain', self.alias_domain) - self.env['ir.config_parameter'].set_param('mail.catchall.alias', self.alias_catchall) - - # admin should not receive emails + @mute_logger('odoo.addons.mail.models.mail_mail') + def test_post_post_w_template(self): + test_record = self.env['mail.test.simple'].with_context(self._test_context).create({'name': 'Test', 'email_from': 'ignasse@example.com'}) + self.user_employee.write({ + 'groups_id': [(4, self.env.ref('base.group_partner_manager').id)], + }) + _attachments = [{ + 'name': 'first.txt', + 'datas': base64.b64encode(b'My first attachment'), + 'res_model': 'res.partner', + 'res_id': self.user_admin.partner_id.id + }, { + 'name': 'second.txt', + 'datas': base64.b64encode(b'My second attachment'), + 'res_model': 'res.partner', + 'res_id': self.user_admin.partner_id.id + }] + email_1 = 'test1@example.com' + email_2 = 'test2@example.com' + email_3 = self.partner_1.email + self._create_template('mail.test.simple', { + 'attachment_ids': [(0, 0, _attachments[0]), (0, 0, _attachments[1])], + 'partner_to': '%s,%s' % (self.partner_2.id, self.user_admin.partner_id.id), + 'email_to': '%s, %s' % (email_1, email_2), + 'email_cc': '%s' % email_3, + }) + # admin should receive emails self.user_admin.write({'notification_type': 'email'}) + # Force the attachments of the template to be in the natural order. + self.email_template.invalidate_cache(['attachment_ids'], ids=self.email_template.ids) - @mute_logger('odoo.addons.mail.models.mail_mail') - def test_composer_comment(self): - composer = self.env['mail.compose.message'].with_context({ - 'default_composition_mode': 'comment', - 'default_model': self.test_record._name, - 'default_res_id': self.test_record.id, - }).with_user(self.user_employee).create({ - 'body': '

Test Body

', - 'partner_ids': [(4, self.partner_1.id), (4, self.partner_2.id)] - }) - composer.send_mail() + test_record.with_user(self.user_employee).message_post_with_template(self.email_template.id, composition_mode='comment') - message = self.test_record.message_ids[0] - self.assertEqual(message.body, '

Test Body

') - self.assertEqual(message.author_id, self.user_employee.partner_id) - self.assertEqual(message.subject, 'Re: %s' % self.test_record.name) - self.assertEqual(message.subtype_id, self.env.ref('mail.mt_comment')) - self.assertEqual(message.partner_ids, self.partner_1 | self.partner_2) - - @mute_logger('odoo.addons.mail.models.mail_mail') - def test_composer_comment_parent(self): - parent = self.test_record.message_post(body='Test') - - self.env['mail.compose.message'].with_context({ - 'default_composition_mode': 'comment', - 'default_parent_id': parent.id - }).with_user(self.user_employee).create({ - 'body': '

Mega

', - }).send_mail() - - message = self.test_record.message_ids[0] - self.assertEqual(message.body, '

Mega

') - self.assertEqual(message.parent_id, parent) - - @mute_logger('odoo.addons.mail.models.mail_mail') - def test_composer_mass_mail(self): - test_record_2 = self.env['mail.test.simple'].with_context(BaseFunctionalTest._test_context).create({'name': 'Test2'}) - - composer = self.env['mail.compose.message'].with_context({ - 'default_composition_mode': 'mass_mail', - 'default_model': self.test_record._name, - 'default_res_id': False, - 'active_ids': [self.test_record.id, test_record_2.id] - }).with_user(self.user_employee).create({ - 'subject': 'Testing ${object.name}', - 'body': '

${object.name}

', - 'partner_ids': [(4, self.partner_1.id), (4, self.partner_2.id)] - }) - composer.with_context({ - 'default_res_id': -1, - 'active_ids': [self.test_record.id, test_record_2.id] - }).send_mail() - - # check mail_mail - mails = self.env['mail.mail'].search([('subject', 'ilike', 'Testing')]) - for mail in mails: - self.assertEqual(mail.recipient_ids, self.partner_1 | self.partner_2, - 'compose wizard: mail_mail mass mailing: mail.mail in mass mail incorrect recipients') - - # check message on test_record - message1 = self.test_record.message_ids[0] - self.assertEqual(message1.subject, 'Testing %s' % self.test_record.name) - self.assertEqual(message1.body, '

%s

' % self.test_record.name) - - # check message on test_record_2 - message1 = test_record_2.message_ids[0] - self.assertEqual(message1.subject, 'Testing %s' % test_record_2.name) - self.assertEqual(message1.body, '

%s

' % test_record_2.name) - - @mute_logger('odoo.addons.mail.models.mail_mail') - def test_composer_mass_mail_active_domain(self): - test_record_2 = self.env['mail.test.simple'].with_context(BaseFunctionalTest._test_context).create({'name': 'Test2'}) - - self.env['mail.compose.message'].with_context({ - 'default_composition_mode': 'mass_mail', - 'default_model': self.test_record._name, - 'default_use_active_domain': True, - 'active_ids': [self.test_record.id], - 'active_domain': [('name', 'in', ['%s' % self.test_record.name, '%s' % test_record_2.name])], - }).with_user(self.user_employee).create({ - 'subject': 'From Composer Test', - 'body': '${object.name}', - }).send_mail() - - self.assertEqual(self.test_record.message_ids[0].subject, 'From Composer Test') - self.assertEqual(test_record_2.message_ids[0].subject, 'From Composer Test') - - @mute_logger('odoo.addons.mail.models.mail_mail') - def test_message_compose_mass_mail_no_active_domain(self): - test_record_2 = self.env['mail.test.simple'].with_context(BaseFunctionalTest._test_context).create({'name': 'Test2'}) - - self.env['mail.compose.message'].with_context({ - 'default_composition_mode': 'mass_mail', - 'default_model': self.test_record._name, - 'default_use_active_domain': False, - 'active_ids': [self.test_record.id], - 'active_domain': [('name', 'in', ['%s' % self.test_record.name, '%s' % test_record_2.name])], - }).with_user(self.user_employee).create({ - 'subject': 'From Composer Test', - 'body': '${object.name}', - }).send_mail() - - self.assertEqual(self.test_record.message_ids[0].subject, 'From Composer Test') - self.assertFalse(test_record_2.message_ids.ids) - - @mute_logger('odoo.addons.mail.models.mail_mail') - def test_message_compose_portal_ok(self): - portal_user = mail_new_test_user(self.env, login='chell', groups='base.group_portal', name='Chell Gladys') - - with patch.object(MailTestSimple, 'check_access_rights', return_value=True): - ComposerPortal = self.env['mail.compose.message'].with_user(portal_user) - - ComposerPortal.with_context({ - 'default_composition_mode': 'comment', - 'default_model': self.test_record._name, - 'default_res_id': self.test_record.id, - }).create({ - 'subject': 'Subject', - 'body': '

Body text

', - 'partner_ids': []}).send_mail() - - self.assertEqual(self.test_record.message_ids[0].body, '

Body text

') - self.assertEqual(self.test_record.message_ids[0].author_id, portal_user.partner_id) - - ComposerPortal.with_context({ - 'default_composition_mode': 'comment', - 'default_parent_id': self.test_record.message_ids.ids[0], - }).create({ - 'subject': 'Subject', - 'body': '

Body text 2

'}).send_mail() - - self.assertEqual(self.test_record.message_ids[0].body, '

Body text 2

') - self.assertEqual(self.test_record.message_ids[0].author_id, portal_user.partner_id) + new_partners = self.env['res.partner'].search([('email', 'in', [email_1, email_2])]) + self.assertEmails( + self.user_employee.partner_id, + [[self.partner_1], [self.partner_2], [new_partners[0]], [new_partners[1]], [self.partner_admin]], + subject='About %s' % test_record.name, + body_content=test_record.name, + attachments=[('first.txt', b'My first attachment', 'text/plain'), ('second.txt', b'My second attachment', 'text/plain')]) diff --git a/addons/test_mail/tests/test_message_track.py b/addons/test_mail/tests/test_message_track.py index 49d5df613ab..2771e7b8d45 100644 --- a/addons/test_mail/tests/test_message_track.py +++ b/addons/test_mail/tests/test_message_track.py @@ -1,32 +1,17 @@ # -*- coding: utf-8 -*- from email.utils import formataddr +from unittest.mock import patch from odoo.addons.test_mail.tests import common class TestTracking(common.BaseFunctionalTest, common.MockEmails): - def assertTracking(self, message, data): - tracking_values = message.sudo().tracking_value_ids - for field_name, value_type, old_value, new_value in data: - tracking = tracking_values.filtered(lambda track: track.field == field_name) - self.assertEqual(len(tracking), 1) - if value_type in ('char', 'integer'): - self.assertEqual(tracking.old_value_char, old_value) - self.assertEqual(tracking.new_value_char, new_value) - elif value_type in ('many2one'): - self.assertEqual(tracking.old_value_integer, old_value and old_value.id or False) - self.assertEqual(tracking.new_value_integer, new_value and new_value.id or False) - self.assertEqual(tracking.old_value_char, old_value and old_value.display_name or '') - self.assertEqual(tracking.new_value_char, new_value and new_value.display_name or '') - else: - self.assertEqual(1, 0) - def setUp(self): super(TestTracking, self).setUp() - record = self.env['mail.test.full'].with_user(self.user_employee).with_context(common.BaseFunctionalTest._test_context).create({ + record = self.env['mail.test.full'].with_user(self.user_employee).with_context(self._test_context).create({ 'name': 'Test', }) self.record = record.with_context(mail_notrack=False) @@ -120,7 +105,7 @@ class TestTracking(common.BaseFunctionalTest, common.MockEmails): def test_message_track_template_at_create(self): """ Create a record with tracking template on create, template should be sent.""" - Model = self.env['mail.test.full'].with_user(self.user_employee).with_context(common.BaseFunctionalTest._test_context) + Model = self.env['mail.test.full'].with_user(self.user_employee).with_context(self._test_context) Model = Model.with_context(mail_notrack=False) record = Model.create({ 'name': 'Test', @@ -185,3 +170,37 @@ class TestTracking(common.BaseFunctionalTest, common.MockEmails): ('name', '=', 'email_from')]) ir_model_field.with_context(_force_unlink=True).unlink() self.assertEqual(len(record_sudo.message_ids.tracking_value_ids), 0) + + def test_create_partner_from_tracking_multicompany(self): + company1 = self.env['res.company'].create({'name': 'company1'}) + self.env.user.write({'company_ids': [(4, company1.id, False)]}) + self.assertNotEqual(self.env.company, company1) + + email_new_partner = "diamonds@rust.com" + Partner = self.env['res.partner'] + self.assertFalse(Partner.search([('email', '=', email_new_partner)])) + + template = self.env['mail.template'].create({ + 'model_id': self.env['ir.model']._get('mail.test.track').id, + 'name': 'AutoTemplate', + 'subject': 'autoresponse', + 'email_from': self.env.user.email_formatted, + 'email_to': "${object.email_from}", + 'body_html': "
A nice body
", + }) + + def patched_message_track_post_template(*args, **kwargs): + if args[0]._name == "mail.test.track": + args[0].message_post_with_template(template.id) + return True + + with patch('odoo.addons.mail.models.mail_thread.MailThread._message_track_post_template', patched_message_track_post_template): + self.env['mail.test.track'].create({ + 'email_from': email_new_partner, + 'company_id': company1.id, + 'user_id': self.env.user.id, # trigger track template + }) + + new_partner = Partner.search([('email', '=', email_new_partner)]) + self.assertTrue(new_partner) + self.assertEqual(new_partner.company_id, company1) diff --git a/addons/test_mail/tests/test_odoobot.py b/addons/test_mail/tests/test_odoobot.py index a494a84bf53..c8d00b31223 100644 --- a/addons/test_mail/tests/test_odoobot.py +++ b/addons/test_mail/tests/test_odoobot.py @@ -11,18 +11,21 @@ from odoo.tests import tagged @tagged("odoobot") class TestOdoobot(BaseFunctionalTest, MockEmails, TestRecipients): - def setUp(self): - super(TestOdoobot, self).setUp() - self.odoobot = self.env.ref("base.partner_root") - self.message_post_default_kwargs = { + @classmethod + def setUpClass(cls): + super(TestOdoobot, cls).setUpClass() + cls.test_record = cls.env['mail.test.simple'].with_context(cls._test_context).create({'name': 'Test', 'email_from': 'ignasse@example.com'}) + + cls.odoobot = cls.env.ref("base.partner_root") + cls.message_post_default_kwargs = { 'body': '', 'attachment_ids': [], 'message_type': 'comment', 'partner_ids': [], 'subtype': 'mail.mt_comment' } - self.odoobot_ping_body = '@OdooBot' % (self.odoobot.id, self.odoobot.id) - self.test_record_employe = self.test_record.with_user(self.user_employee) + cls.odoobot_ping_body = '@OdooBot' % (cls.odoobot.id, cls.odoobot.id) + cls.test_record_employe = cls.test_record.with_user(cls.user_employee) @mute_logger('odoo.addons.mail.models.mail_mail') def test_fetch_listener(self): diff --git a/addons/test_mail/tests/test_res_users.py b/addons/test_mail/tests/test_res_users.py deleted file mode 100644 index 4ae3ca00265..00000000000 --- a/addons/test_mail/tests/test_res_users.py +++ /dev/null @@ -1,34 +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.tests import tagged - - -@tagged('moderation') -class TestMessageModeration(common.Moderation): - - @classmethod - def setUpClass(cls): - super(TestMessageModeration, cls).setUpClass() - - def test_is_moderator(self): - self.assertTrue(self.user_employee.is_moderator) - self.assertFalse(self.user_admin.is_moderator) - self.assertTrue(self.user_employee_2.is_moderator) - - def test_moderation_counter(self): - self._create_new_message(self.channel_1.id, status='pending_moderation', author=self.partner_admin) - self._create_new_message(self.channel_1.id, status='accepted', author=self.partner_admin) - self._create_new_message(self.channel_1.id, status='accepted', author=self.partner_employee) - self._create_new_message(self.channel_1.id, status='pending_moderation', author=self.partner_employee) - self._create_new_message(self.channel_1.id, status='accepted', author=self.partner_employee_2) - - self.assertEqual(self.user_employee.moderation_counter, 2) - self.assertEqual(self.user_employee_2.moderation_counter, 0) - self.assertEqual(self.user_admin.moderation_counter, 0) - - self.channel_1.write({'channel_partner_ids': [(4, self.partner_employee_2.id)], 'moderator_ids': [(4, self.user_employee_2.id)]}) - self.assertEqual(self.user_employee.moderation_counter, 2) - self.assertEqual(self.user_employee_2.moderation_counter, 0) - self.assertEqual(self.user_admin.moderation_counter, 0)