diff --git a/addons/mail/tests/__init__.py b/addons/mail/tests/__init__.py index 4706daea1c6..15ce69a9bd7 100644 --- a/addons/mail/tests/__init__.py +++ b/addons/mail/tests/__init__.py @@ -2,3 +2,4 @@ from . import common from . import test_res_partner +from . import test_update_notification diff --git a/addons/test_mail/tests/test_update_notification.py b/addons/mail/tests/test_update_notification.py similarity index 100% rename from addons/test_mail/tests/test_update_notification.py rename to addons/mail/tests/test_update_notification.py diff --git a/addons/test_mail/models/__init__.py b/addons/test_mail/models/__init__.py index 420d064776c..0f5cea0a294 100644 --- a/addons/test_mail/models/__init__.py +++ b/addons/test_mail/models/__init__.py @@ -1,3 +1,5 @@ # -*- coding: utf-8 -*- -from . import test_mail_models \ No newline at end of file +from . import test_mail_models +from . import test_mail_corner_case_models +from . import test_mail_thread_models diff --git a/addons/test_mail/models/test_mail_corner_case_models.py b/addons/test_mail/models/test_mail_corner_case_models.py new file mode 100644 index 00000000000..7f65194cd8e --- /dev/null +++ b/addons/test_mail/models/test_mail_corner_case_models.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + + +class MailModel(models.Model): + _name = 'test_performance.mail' + _description = 'Test Performance Mail' + _inherit = 'mail.thread' + + name = fields.Char() + value = fields.Integer() + value_pc = fields.Float(compute="_value_pc", store=True) + track = fields.Char(default='test', tracking=True) + partner_id = fields.Many2one('res.partner', string='Customer') + + @api.depends('value') + def _value_pc(self): + for record in self: + record.value_pc = float(record.value) / 100 + + +class MailTrackingModel(models.Model): + _description = 'Test Tracking Model' + _name = 'mail.test.tracking' + _inherit = ['mail.thread'] + + name = fields.Char(required=True, tracking=True) + field_0 = fields.Char(tracking=True) + field_1 = fields.Char(tracking=True) + field_2 = fields.Char(tracking=True) + + +class MailCompute(models.Model): + _name = 'mail.test.compute' + _description = "Test model with several tracked computed fields" + _inherit = ['mail.thread'] + + partner_id = fields.Many2one('res.partner', tracking=True) + partner_name = fields.Char(related='partner_id.name', store=True, tracking=True) + partner_email = fields.Char(related='partner_id.email', store=True, tracking=True) + partner_phone = fields.Char(related='partner_id.phone', tracking=True) + + +class MailMultiCompany(models.Model): + """ This model can be used in multi company tests""" + _name = 'mail.test.multi.company' + _description = "Test Multi Company Mail" + _inherit = 'mail.thread' + + name = fields.Char() + company_id = fields.Many2one('res.company') diff --git a/addons/test_mail/models/test_mail_models.py b/addons/test_mail/models/test_mail_models.py index 0e420b83eba..55549133a3d 100644 --- a/addons/test_mail/models/test_mail_models.py +++ b/addons/test_mail/models/test_mail_models.py @@ -122,60 +122,3 @@ class MailTestAlias(models.Model): values['alias_force_thread_id'] = self.id values['alias_parent_thread_id'] = self.id return values - - -class MailModel(models.Model): - _name = 'test_performance.mail' - _description = 'Test Performance Mail' - _inherit = 'mail.thread' - - name = fields.Char() - value = fields.Integer() - value_pc = fields.Float(compute="_value_pc", store=True) - track = fields.Char(default='test', tracking=True) - partner_id = fields.Many2one('res.partner', string='Customer') - - @api.depends('value') - def _value_pc(self): - for record in self: - record.value_pc = float(record.value) / 100 - - -class MailCC(models.Model): - _name = 'mail.test.cc' - _description = "Test Email CC Thread" - _inherit = ['mail.thread.cc'] - - name = fields.Char() - - -class MailMultiCompany(models.Model): - """ This model can be used in multi company tests""" - _name = 'mail.test.multi.company' - _description = "Test Multi Company Mail" - _inherit = 'mail.thread' - - name = fields.Char() - company_id = fields.Many2one('res.company') - - -class MailTrackingModel(models.Model): - _description = 'Test Tracking Model' - _name = 'mail.test.tracking' - _inherit = ['mail.thread'] - - name = fields.Char(required=True, tracking=True) - field_0 = fields.Char(tracking=True) - field_1 = fields.Char(tracking=True) - field_2 = fields.Char(tracking=True) - - -class MailCompute(models.Model): - _name = 'mail.test.compute' - _description = "Test model with several tracked computed fields" - _inherit = ['mail.thread'] - - partner_id = fields.Many2one('res.partner', tracking=True) - partner_name = fields.Char(related='partner_id.name', store=True, tracking=True) - partner_email = fields.Char(related='partner_id.email', store=True, tracking=True) - partner_phone = fields.Char(related='partner_id.phone', tracking=True) diff --git a/addons/test_mail/models/test_mail_thread_models.py b/addons/test_mail/models/test_mail_thread_models.py new file mode 100644 index 00000000000..685b5c2afd1 --- /dev/null +++ b/addons/test_mail/models/test_mail_thread_models.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models + + +class MailCC(models.Model): + _name = 'mail.test.cc' + _description = "Test Email CC Thread" + _inherit = ['mail.thread.cc'] + + name = fields.Char() diff --git a/addons/test_mail/tests/__init__.py b/addons/test_mail/tests/__init__.py index 78d3b1516b6..3aac76d3df9 100644 --- a/addons/test_mail/tests/__init__.py +++ b/addons/test_mail/tests/__init__.py @@ -2,19 +2,16 @@ 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_channel from . import test_mail_gateway -from . import test_mail_redirect from . import test_mail_template +from . import test_mail_thread_internals from . import test_message_composer from . import test_message_management from . import test_message_post from . import test_message_track -from . import test_odoobot from . import test_performance -from . import test_update_notification diff --git a/addons/test_mail/tests/test_mail_redirect.py b/addons/test_mail/tests/test_mail_redirect.py deleted file mode 100644 index 706a9704319..00000000000 --- a/addons/test_mail/tests/test_mail_redirect.py +++ /dev/null @@ -1,67 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -from werkzeug.urls import url_decode, url_parse -from odoo.tests.common import HttpCase, tagged - - -@tagged('-at_install', 'post_install') -class TestMultiCompany(HttpCase): - - def test_redirect_to_records(self): - - self.company_A = self.env['res.company'].create({ - 'name': 'Company A', - 'user_ids': [(4, self.ref('base.user_admin'))], - }) - - self.company_B = self.env['res.company'].create({ - 'name': 'Company B', - }) - - self.multi_company_record = self.env['mail.test.multi.company'].create({ - 'name': 'Multi Company Record', - 'company_id': self.company_A.id, - }) - - # Test Case 0 - # Not logged, redirect to web/login - response = self.url_open('/mail/view?model=%s&res_id=%s' % ( - self.multi_company_record._name, - self.multi_company_record.id), timeout=15) - - path = url_parse(response.url).path - self.assertEqual(path, '/web/login') - - self.authenticate('admin', 'admin') - - # Test Case 1 - # Logged into company 1, try accessing record in company A - # _redirect_to_record should add company A in allowed_company_ids - response = self.url_open('/mail/view?model=%s&res_id=%s' % ( - self.multi_company_record._name, - self.multi_company_record.id), timeout=15) - - self.assertEqual(response.status_code, 200) - - fragment = url_parse(response.url).fragment - cids = url_decode(fragment)['cids'] - - self.assertEqual(cids, '1,%s' % (self.company_A.id)) - - # Test Case 2 - # Logged into company 1, try accessing record in company B - # _redirect_to_record should redirect to messaging as the user - # doesn't have any access for this company - self.multi_company_record.company_id = self.company_B - - response = self.url_open('/mail/view?model=%s&res_id=%s' % ( - self.multi_company_record._name, - self.multi_company_record.id), timeout=15) - - self.assertEqual(response.status_code, 200) - - fragment = url_parse(response.url).fragment - action = url_decode(fragment)['action'] - - self.assertEqual(action, 'mail.action_discuss') diff --git a/addons/test_mail/tests/test_discuss.py b/addons/test_mail/tests/test_mail_thread_internals.py similarity index 78% rename from addons/test_mail/tests/test_discuss.py rename to addons/test_mail/tests/test_mail_thread_internals.py index 86b9a7de0cb..1674d9ca312 100644 --- a/addons/test_mail/tests/test_discuss.py +++ b/addons/test_mail/tests/test_mail_thread_internals.py @@ -1,7 +1,10 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from werkzeug.urls import url_parse, url_decode + from odoo.addons.test_mail.tests.common import TestMailCommon, TestRecipients +from odoo.tests.common import tagged, HttpCase from odoo.tools import mute_logger @@ -141,3 +144,65 @@ class TestDiscuss(TestMailCommon, TestRecipients): (False, 'cc1@example.com', 'CC Email'), (False, 'cc2@example.com', 'CC Email'), ], 'cc should be in suggestions') + + +@tagged('-at_install', 'post_install') +class TestMultiCompany(HttpCase): + + def test_redirect_to_records(self): + + self.company_A = self.env['res.company'].create({ + 'name': 'Company A', + 'user_ids': [(4, self.ref('base.user_admin'))], + }) + + self.company_B = self.env['res.company'].create({ + 'name': 'Company B', + }) + + self.multi_company_record = self.env['mail.test.multi.company'].create({ + 'name': 'Multi Company Record', + 'company_id': self.company_A.id, + }) + + # Test Case 0 + # Not logged, redirect to web/login + response = self.url_open('/mail/view?model=%s&res_id=%s' % ( + self.multi_company_record._name, + self.multi_company_record.id), timeout=15) + + path = url_parse(response.url).path + self.assertEqual(path, '/web/login') + + self.authenticate('admin', 'admin') + + # Test Case 1 + # Logged into company 1, try accessing record in company A + # _redirect_to_record should add company A in allowed_company_ids + response = self.url_open('/mail/view?model=%s&res_id=%s' % ( + self.multi_company_record._name, + self.multi_company_record.id), timeout=15) + + self.assertEqual(response.status_code, 200) + + fragment = url_parse(response.url).fragment + cids = url_decode(fragment)['cids'] + + self.assertEqual(cids, '1,%s' % (self.company_A.id)) + + # Test Case 2 + # Logged into company 1, try accessing record in company B + # _redirect_to_record should redirect to messaging as the user + # doesn't have any access for this company + self.multi_company_record.company_id = self.company_B + + response = self.url_open('/mail/view?model=%s&res_id=%s' % ( + self.multi_company_record._name, + self.multi_company_record.id), timeout=15) + + self.assertEqual(response.status_code, 200) + + fragment = url_parse(response.url).fragment + action = url_decode(fragment)['action'] + + self.assertEqual(action, 'mail.action_discuss') diff --git a/addons/test_mail/tests/test_message_track.py b/addons/test_mail/tests/test_message_track.py index 20ee3d74c4b..45ae711d32b 100644 --- a/addons/test_mail/tests/test_message_track.py +++ b/addons/test_mail/tests/test_message_track.py @@ -4,8 +4,10 @@ from unittest.mock import patch from odoo.addons.test_mail.tests.common import TestMailCommon +from odoo.tests.common import tagged +@tagged('mail_track') class TestTracking(TestMailCommon): def setUp(self): @@ -127,61 +129,6 @@ class TestTracking(TestMailCommon): # one email send due to template self.assertSentEmail(self.record.env.user.partner_id, [self.partner_admin], body='

Hello Test

') - def test_message_tracking_sequence(self): - """ Update some tracked fields and check that the mail.tracking.value are ordered according to their tracking_sequence""" - self.record.write({ - 'name': 'Zboub', - 'customer_id': self.user_admin.partner_id.id, - 'user_id': self.user_admin.id, - 'umbrella_id': self.env['mail.test'].with_context(mail_create_nosubscribe=True).create({'name': 'Umbrella'}).id - }) - self.flush_tracking() - self.assertEqual(len(self.record.message_ids), 1, 'should have 1 tracking message') - - tracking_values = self.env['mail.tracking.value'].search([('mail_message_id', '=', self.record.message_ids.id)]) - self.assertEqual(tracking_values[0].tracking_sequence, 1) - self.assertEqual(tracking_values[1].tracking_sequence, 2) - self.assertEqual(tracking_values[2].tracking_sequence, 100) - - def test_track_groups(self): - # patch the group attribute - field = self.record._fields['email_from'] - self.addCleanup(setattr, field, 'groups', field.groups) - field.groups = 'base.group_erp_manager' - - self.record.sudo().write({'email_from': 'X'}) - self.flush_tracking() - - msg_emp = self.record.message_ids.message_format() - msg_sudo = self.record.sudo().message_ids.message_format() - self.assertFalse(msg_emp[0].get('tracking_value_ids'), "should not have protected tracking values") - self.assertTrue(msg_sudo[0].get('tracking_value_ids'), "should have protected tracking values") - - def test_notify_track_groups(self): - # patch the group attribute - field = self.record._fields['email_from'] - self.addCleanup(setattr, field, 'groups', field.groups) - field.groups = 'base.group_erp_manager' - - self.record.sudo().write({'email_from': 'X'}) - self.flush_tracking() - - msg_emp = self.record._notify_prepare_template_context(self.record.message_ids, {}) - msg_sudo = self.record.sudo()._notify_prepare_template_context(self.record.message_ids, {}) - self.assertFalse(msg_emp.get('tracking_values'), "should not have protected tracking values") - self.assertTrue(msg_sudo.get('tracking_values'), "should have protected tracking values") - - def test_unlinked_field(self): - record_sudo = self.record.sudo() - record_sudo.write({'email_from': 'X'}) # create a tracking value - self.flush_tracking() - self.assertEqual(len(record_sudo.message_ids.tracking_value_ids), 1) - ir_model_field = self.env['ir.model.fields'].search([ - ('model', '=', 'mail.test.full'), - ('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)]}) @@ -334,3 +281,61 @@ class TestTracking(TestMailCommon): ('partner_name', 'char', 'Fool', 'Bar'), ('partner_email', 'char', 'foo@example.com', 'bar@example.com'), ]) + + +@tagged('mail_track') +class TestTrackingInternals(TestMailCommon): + + def setUp(self): + super(TestTrackingInternals, self).setUp() + + record = self.env['mail.test.full'].with_user(self.user_employee).with_context(self._test_context).create({ + 'name': 'Test', + }) + self.flush_tracking() + self.record = record.with_context(mail_notrack=False) + + def test_track_groups(self): + field = self.record._fields['email_from'] + self.addCleanup(setattr, field, 'groups', field.groups) + field.groups = 'base.group_erp_manager' + + self.record.sudo().write({'email_from': 'X'}) + self.flush_tracking() + + msg_emp = self.record.message_ids.message_format() + msg_sudo = self.record.sudo().message_ids.message_format() + self.assertFalse(msg_emp[0].get('tracking_value_ids'), "should not have protected tracking values") + self.assertTrue(msg_sudo[0].get('tracking_value_ids'), "should have protected tracking values") + + msg_emp = self.record._notify_prepare_template_context(self.record.message_ids, {}) + msg_sudo = self.record.sudo()._notify_prepare_template_context(self.record.message_ids, {}) + self.assertFalse(msg_emp.get('tracking_values'), "should not have protected tracking values") + self.assertTrue(msg_sudo.get('tracking_values'), "should have protected tracking values") + + def test_track_sequence(self): + """ Update some tracked fields and check that the mail.tracking.value are ordered according to their tracking_sequence""" + self.record.write({ + 'name': 'Zboub', + 'customer_id': self.user_admin.partner_id.id, + 'user_id': self.user_admin.id, + 'umbrella_id': self.env['mail.test'].with_context(mail_create_nosubscribe=True).create({'name': 'Umbrella'}).id + }) + self.flush_tracking() + self.assertEqual(len(self.record.message_ids), 1, 'should have 1 tracking message') + + tracking_values = self.env['mail.tracking.value'].search([('mail_message_id', '=', self.record.message_ids.id)]) + self.assertEqual(tracking_values[0].tracking_sequence, 1) + self.assertEqual(tracking_values[1].tracking_sequence, 2) + self.assertEqual(tracking_values[2].tracking_sequence, 100) + + def test_unlinked_field(self): + record_sudo = self.record.sudo() + record_sudo.write({'email_from': 'new_value'}) # create a tracking value + self.flush_tracking() + self.assertEqual(len(record_sudo.message_ids.tracking_value_ids), 1) + ir_model_field = self.env['ir.model.fields'].search([ + ('model', '=', 'mail.test.full'), + ('name', '=', 'email_from')]) + ir_model_field.with_context(_force_unlink=True).unlink() + self.assertEqual(len(record_sudo.message_ids.tracking_value_ids), 0) diff --git a/addons/test_mail/tests/test_performance.py b/addons/test_mail/tests/test_performance.py index de82171251b..1d8ab7729c9 100644 --- a/addons/test_mail/tests/test_performance.py +++ b/addons/test_mail/tests/test_performance.py @@ -183,6 +183,11 @@ class TestMailAPIPerformance(BaseMailPerformance): 'notification_type': 'inbox', 'groups_id': [(6, 0, [self.env.ref('base.group_user').id])], }) + + # automatically follow activities, for backward compatibility concerning query count + self.env.ref('mail.mt_activities').write({'default': True}) + + def _create_test_records(self): self.test_record_full = self.env['mail.test.full'].with_context(self._quick_create_ctx).create({ 'name': 'TestRecord', 'customer_id': self.customer.id, @@ -199,9 +204,6 @@ class TestMailAPIPerformance(BaseMailPerformance): 'email_to': '${("%s Customer <%s>" % (object.name, object.email_from)) | safe}', }) - # automatically follow activities, for backward compatibility concerning query count - self.env.ref('mail.mt_activities').write({'default': True}) - @users('__system__', 'emp') @warmup def test_adv_activity(self): @@ -255,6 +257,7 @@ class TestMailAPIPerformance(BaseMailPerformance): @warmup @mute_logger('odoo.tests', 'odoo.addons.mail.models.mail_mail') def test_mail_composer(self): + self._create_test_records() test_record = self.env['mail.test.full'].browse(self.test_record_full.id) customer_id = self.customer.id with self.assertQueryCount(__system__=4, emp=4): @@ -274,6 +277,7 @@ class TestMailAPIPerformance(BaseMailPerformance): @warmup @mute_logger('odoo.tests', 'odoo.addons.mail.models.mail_mail', 'odoo.models.unlink') def test_mail_composer_w_template(self): + self._create_test_records() test_record = self.env['mail.test.full'].browse(self.test_record_full.id) test_template = self.env['mail.template'].browse(self.test_template_full.id) # TODO FIXME non deterministic, last check 25 Mar 2020. Runbot at most +7 compared to local. @@ -395,6 +399,25 @@ class TestMailAPIPerformance(BaseMailPerformance): with self.assertQueryCount(__system__=2, emp=2): record.message_subscribe(partner_ids=self.user_test.partner_id.ids, subtype_ids=subtype_ids) + @mute_logger('odoo.models.unlink') + @users('__system__', 'emp') + @warmup + def test_message_track(self): + record = self.env['mail.test.tracking'].create({'name': 'Zizizatestname'}) + with self.assertQueryCount(__system__=3, emp=3): + record.write({'name': 'Zizizanewtestname'}) + record.flush() + + with self.assertQueryCount(__system__=5, emp=5): + record.write({'field_%s' % (i): 'Tracked Char Fields %s' % (i) for i in range(3)}) + record.flush() + + with self.assertQueryCount(__system__=6, emp=6): + record.write({'field_%s' % (i): 'Field Without Cache %s' % (i) for i in range(3)}) + record.flush() + record.write({'field_%s' % (i): 'Field With Cache %s' % (i) for i in range(3)}) + record.flush() + @tagged('mail_performance') class TestMailComplexPerformance(BaseMailPerformance): @@ -949,27 +972,3 @@ class TestMailHeavyPerformancePost(BaseMailPerformance): self.assertEqual(self.attachements.mapped('res_model'), [record._name for i in range(3)]) self.assertEqual(self.attachements.mapped('res_id'), [record.id for i in range(3)]) # self.assertEqual(record.message_ids[0].notified_partner_ids, []) - - -@tagged('mail_performance') -class TestTrackingPerformance(BaseMailPerformance): - - @users('__system__', 'demo') - @warmup - def test_tracking_multiple_fields(self): - """ Check that tracking multiple fields is scalable """ - - record = self.env['mail.test.tracking'].create({'name': 'Zizizatestname'}) - with self.assertQueryCount(__system__=3, demo=3): - record.write({'name': 'Zizizanewtestname'}) - record.flush() - - with self.assertQueryCount(__system__=5, demo=5): - record.write({'field_%s' % (i): 'Tracked Char Fields %s' % (i) for i in range(3)}) - record.flush() - - with self.assertQueryCount(__system__=6, demo=6): - record.write({'field_%s' % (i): 'Field Without Cache %s' % (i) for i in range(3)}) - record.flush() - record.write({'field_%s' % (i): 'Field With Cache %s' % (i) for i in range(3)}) - record.flush() diff --git a/addons/test_mail_full/tests/__init__.py b/addons/test_mail_full/tests/__init__.py index ce173406381..149facf9fa7 100644 --- a/addons/test_mail_full/tests/__init__.py +++ b/addons/test_mail_full/tests/__init__.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from . import common +from . import test_odoobot from . import test_phone_blacklist from . import test_mass_sms from . import test_sms_composer diff --git a/addons/test_mail/tests/test_odoobot.py b/addons/test_mail_full/tests/test_odoobot.py similarity index 100% rename from addons/test_mail/tests/test_odoobot.py rename to addons/test_mail_full/tests/test_odoobot.py