From a913272136182e6f4b1e28337686dd14616ea0ca Mon Sep 17 00:00:00 2001 From: Yannick Tivisse Date: Tue, 5 Dec 2023 14:12:24 +0100 Subject: [PATCH] [FIX] base: Make tests demo data independent Part-of: odoo/odoo#146649 --- odoo/addons/base/tests/common.py | 75 ++++++++++++------- odoo/addons/base/tests/test_base.py | 1 + .../base/tests/test_format_address_mixin.py | 1 + odoo/addons/base/tests/test_ir_actions.py | 5 +- odoo/addons/base/tests/test_ir_attachment.py | 12 +-- odoo/addons/base/tests/test_ir_model.py | 6 ++ odoo/addons/base/tests/test_osv.py | 1 + odoo/addons/base/tests/test_res_config.py | 6 ++ odoo/addons/base/tests/test_res_partner.py | 7 +- odoo/addons/base/tests/test_views.py | 11 +-- odoo/addons/base/tests/test_xmlrpc.py | 1 + odoo/addons/test_apikeys/tests/test_flow.py | 13 +++- odoo/addons/test_http/tests/test_common.py | 4 +- .../addons/test_main_flows/tests/test_flow.py | 12 +++ .../test_new_api/tests/test_new_fields.py | 10 +-- .../tests/test_m2m_grouping.py | 5 +- odoo/tests/common.py | 2 + 17 files changed, 118 insertions(+), 54 deletions(-) diff --git a/odoo/addons/base/tests/common.py b/odoo/addons/base/tests/common.py index 937479ad452..c1f76a32437 100644 --- a/odoo/addons/base/tests/common.py +++ b/odoo/addons/base/tests/common.py @@ -105,25 +105,26 @@ class TransactionCaseWithUserDemo(TransactionCase): class HttpCaseWithUserDemo(HttpCase): - def setUp(self): - super(HttpCaseWithUserDemo, self).setUp() - self.user_admin = self.env.ref('base.user_admin') - self.user_admin.write({'name': 'Mitchell Admin'}) - self.partner_admin = self.user_admin.partner_id - self.user_demo = self.env['res.users'].search([('login', '=', 'demo')]) - self.partner_demo = self.user_demo.partner_id + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.user_admin = cls.env.ref('base.user_admin') + cls.user_admin.write({'name': 'Mitchell Admin'}) + cls.partner_admin = cls.user_admin.partner_id + cls.user_demo = cls.env['res.users'].search([('login', '=', 'demo')]) + cls.partner_demo = cls.user_demo.partner_id - if not self.user_demo: - self.env['ir.config_parameter'].sudo().set_param('auth_password_policy.minlength', 4) - self.partner_demo = self.env['res.partner'].create({ + if not cls.user_demo: + cls.env['ir.config_parameter'].sudo().set_param('auth_password_policy.minlength', 4) + cls.partner_demo = cls.env['res.partner'].create({ 'name': 'Marc Demo', 'email': 'mark.brown23@example.com', }) - self.user_demo = self.env['res.users'].create({ + cls.user_demo = cls.env['res.users'].create({ 'login': 'demo', 'password': 'demo', - 'partner_id': self.partner_demo.id, - 'groups_id': [Command.set([self.env.ref('base.group_user').id, self.env.ref('base.group_partner_manager').id])], + 'partner_id': cls.partner_demo.id, + 'groups_id': [Command.set([cls.env.ref('base.group_user').id, cls.env.ref('base.group_partner_manager').id])], }) @@ -131,7 +132,7 @@ class SavepointCaseWithUserDemo(TransactionCase): @classmethod def setUpClass(cls): - super(SavepointCaseWithUserDemo, cls).setUpClass() + super().setUpClass() cls.user_demo = cls.env['res.users'].search([('login', '=', 'demo')]) cls.partner_demo = cls.user_demo.partner_id @@ -252,24 +253,48 @@ class SavepointCaseWithUserDemo(TransactionCase): } ]) -class HttpCaseWithUserPortal(HttpCase): - def setUp(self): - super(HttpCaseWithUserPortal, self).setUp() - self.user_portal = self.env['res.users'].search([('login', '=', 'portal')]) - self.partner_portal = self.user_portal.partner_id +class TransactionCaseWithUserPortal(TransactionCase): - if not self.user_portal: - self.env['ir.config_parameter'].sudo().set_param('auth_password_policy.minlength', 4) - self.partner_portal = self.env['res.partner'].create({ + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.user_portal = cls.env['res.users'].sudo().search([('login', '=', 'portal')]) + cls.partner_portal = cls.user_portal.partner_id + + if not cls.user_portal: + cls.env['ir.config_parameter'].sudo().set_param('auth_password_policy.minlength', 4) + cls.partner_portal = cls.env['res.partner'].create({ 'name': 'Joel Willis', 'email': 'joel.willis63@example.com', }) - self.user_portal = self.env['res.users'].with_context(no_reset_password=True).create({ + cls.user_portal = cls.env['res.users'].with_context(no_reset_password=True).create({ 'login': 'portal', 'password': 'portal', - 'partner_id': self.partner_portal.id, - 'groups_id': [Command.set([self.env.ref('base.group_portal').id])], + 'partner_id': cls.partner_portal.id, + 'groups_id': [Command.set([cls.env.ref('base.group_portal').id])], + }) + + +class HttpCaseWithUserPortal(HttpCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.user_portal = cls.env['res.users'].sudo().search([('login', '=', 'portal')]) + cls.partner_portal = cls.user_portal.partner_id + + if not cls.user_portal: + cls.env['ir.config_parameter'].sudo().set_param('auth_password_policy.minlength', 4) + cls.partner_portal = cls.env['res.partner'].create({ + 'name': 'Joel Willis', + 'email': 'joel.willis63@example.com', + }) + cls.user_portal = cls.env['res.users'].with_context(no_reset_password=True).create({ + 'login': 'portal', + 'password': 'portal', + 'partner_id': cls.partner_portal.id, + 'groups_id': [Command.set([cls.env.ref('base.group_portal').id])], }) diff --git a/odoo/addons/base/tests/test_base.py b/odoo/addons/base/tests/test_base.py index c47009f012b..5ab2987a54e 100644 --- a/odoo/addons/base/tests/test_base.py +++ b/odoo/addons/base/tests/test_base.py @@ -7,6 +7,7 @@ from odoo import Command from odoo.tests.common import TransactionCase, BaseCase from odoo.tools import mute_logger from odoo.tools.safe_eval import safe_eval, const_eval, expr_eval +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo class TestSafeEval(BaseCase): diff --git a/odoo/addons/base/tests/test_format_address_mixin.py b/odoo/addons/base/tests/test_format_address_mixin.py index f2bb0fb3c79..78e827cbd99 100644 --- a/odoo/addons/base/tests/test_format_address_mixin.py +++ b/odoo/addons/base/tests/test_format_address_mixin.py @@ -59,4 +59,5 @@ class FormatAddressCase(ViewCase): class TestPartnerFormatAddress(FormatAddressCase): def test_address_view(self): + self.env.company.country_id = self.env.ref('base.us') self.assertAddressView('res.partner') diff --git a/odoo/addons/base/tests/test_ir_actions.py b/odoo/addons/base/tests/test_ir_actions.py index de30a10eebe..0579d453b5b 100644 --- a/odoo/addons/base/tests/test_ir_actions.py +++ b/odoo/addons/base/tests/test_ir_actions.py @@ -11,10 +11,11 @@ import odoo from odoo.exceptions import UserError, ValidationError, AccessError from odoo.tools import mute_logger from odoo.tests import common, tagged +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo from odoo import Command -class TestServerActionsBase(common.TransactionCase): +class TestServerActionsBase(TransactionCaseWithUserDemo): def setUp(self): super(TestServerActionsBase, self).setUp() @@ -461,7 +462,7 @@ ZeroDivisionError: division by zero""" % self.test_server_action.id 'code': """record.write({'date': datetime.date.today()})""", }) - user_demo = self.env.ref("base.user_demo") + user_demo = self.user_demo self_demo = self.action.with_user(user_demo.id) # can write on contact partner diff --git a/odoo/addons/base/tests/test_ir_attachment.py b/odoo/addons/base/tests/test_ir_attachment.py index 49d39543b6d..40178ab4c33 100644 --- a/odoo/addons/base/tests/test_ir_attachment.py +++ b/odoo/addons/base/tests/test_ir_attachment.py @@ -9,13 +9,13 @@ from PIL import Image import odoo from odoo.exceptions import AccessError -from odoo.tests.common import TransactionCase +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo from odoo.tools import image_to_base64 HASH_SPLIT = 2 # FIXME: testing implementations detail is not a good idea -class TestIrAttachment(TransactionCase): +class TestIrAttachment(TransactionCaseWithUserDemo): def setUp(self): super(TestIrAttachment, self).setUp() self.Attachment = self.env['ir.attachment'] @@ -91,7 +91,7 @@ class TestIrAttachment(TransactionCase): Tests the consistency of documents' mimetypes """ - Attachment = self.Attachment.with_user(self.env.ref('base.user_demo').id) + Attachment = self.Attachment.with_user(self.user_demo.id) a2 = Attachment.create({'name': 'a2', 'datas': self.blob1_b64, 'mimetype': 'image/png'}) self.assertEqual(a2.mimetype, 'image/png', "the new mimetype should be the one given on write") a3 = Attachment.create({'name': 'a3', 'datas': self.blob1_b64, 'mimetype': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'}) @@ -101,7 +101,7 @@ class TestIrAttachment(TransactionCase): """ Tests that potentially harmful mimetypes (XML mimetypes that can lead to XSS attacks) are converted to text """ - Attachment = self.Attachment.with_user(self.env.ref('base.user_demo').id) + Attachment = self.Attachment.with_user(self.user_demo.id) document = Attachment.create({'name': 'document', 'datas': self.blob1_b64}) document.write({'datas': self.blob1_b64, 'mimetype': 'text/xml'}) self.assertEqual(document.mimetype, 'text/plain', "XML mimetype should be forced to text") @@ -261,11 +261,11 @@ class TestIrAttachment(TransactionCase): self.assertFalse(os.path.isfile(store_path), 'file removed') -class TestPermissions(TransactionCase): +class TestPermissions(TransactionCaseWithUserDemo): def setUp(self): super().setUp() # replace self.env(uid=1) with an actual user environment so rules apply - self.env = self.env(user=self.env.ref('base.user_demo')) + self.env = self.env(user=self.user_demo) self.Attachments = self.env['ir.attachment'] # create a record with an attachment and a rule allowing Read access diff --git a/odoo/addons/base/tests/test_ir_model.py b/odoo/addons/base/tests/test_ir_model.py index 8232d94bcd7..1f4a36573f4 100644 --- a/odoo/addons/base/tests/test_ir_model.py +++ b/odoo/addons/base/tests/test_ir_model.py @@ -456,6 +456,12 @@ class TestEvalContext(TransactionCase): @tagged('-at_install', 'post_install') class TestIrModelFieldsTranslation(HttpCase): def test_ir_model_fields_translation(self): + # If not enabled (like in demo data), landing on res.config will try + # to disable module_sale_quotation_builder and raise an warning + group_order_template = self.env.ref('sale_management.group_sale_order_template', raise_if_not_found=False) + if group_order_template: + self.env.ref('base.group_user').write({"implied_ids": [(4, group_order_template.id)]}) + # modify en_US translation field = self.env['ir.model.fields'].search([('model_id.model', '=', 'res.users'), ('name', '=', 'login')]) self.assertEqual(field.with_context(lang='en_US').field_description, 'Login') diff --git a/odoo/addons/base/tests/test_osv.py b/odoo/addons/base/tests/test_osv.py index c4d4cab31f7..4bfdcd9ae52 100644 --- a/odoo/addons/base/tests/test_osv.py +++ b/odoo/addons/base/tests/test_osv.py @@ -104,6 +104,7 @@ class QueryTestCase(BaseCase): class TestQuery(TransactionCase): def test_auto(self): model = self.env['res.partner.category'] + model.create([{'name': 'Test Category 1'}, {'name': 'Test Category 2'}]) query = model._search([]) self.assertIsInstance(query, Query) diff --git a/odoo/addons/base/tests/test_res_config.py b/odoo/addons/base/tests/test_res_config.py index 4813a38cf0b..01391bb0150 100644 --- a/odoo/addons/base/tests/test_res_config.py +++ b/odoo/addons/base/tests/test_res_config.py @@ -178,6 +178,12 @@ class TestResConfigExecute(TransactionCase): 'groups_id': [Command.link(group_system.id)], }) + # If not enabled (like in demo data), landing on res.config will try + # to disable module_sale_quotation_builder and raise an issue + group_order_template = self.env.ref('sale_management.group_sale_order_template', raise_if_not_found=False) + if group_order_template: + self.env.ref('base.group_user').write({"implied_ids": [(4, group_order_template.id)]}) + _logger.info("Testing settings access for group %s", group_system.full_name) forbidden_models = self._test_user_settings_fields_access(settings_only_user) self._test_user_settings_view_save(settings_only_user) diff --git a/odoo/addons/base/tests/test_res_partner.py b/odoo/addons/base/tests/test_res_partner.py index 1b3d47dac79..dcf6c15170e 100644 --- a/odoo/addons/base/tests/test_res_partner.py +++ b/odoo/addons/base/tests/test_res_partner.py @@ -6,9 +6,10 @@ from unittest.mock import patch from odoo import Command from odoo.addons.base.models.res_partner import Partner +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo from odoo.exceptions import AccessError, RedirectWarning, UserError, ValidationError from odoo.tests import Form -from odoo.tests.common import TransactionCase, tagged +from odoo.tests.common import tagged, TransactionCase # samples use effective TLDs from the Mozilla public suffix # list at http://publicsuffix.org @@ -23,7 +24,7 @@ SAMPLES = [ @tagged('res_partner') -class TestPartner(TransactionCase): +class TestPartner(TransactionCaseWithUserDemo): @contextmanager def mockPartnerCalls(self): @@ -66,7 +67,7 @@ class TestPartner(TransactionCase): with self.assertRaises(RedirectWarning): test_partner.with_user(self.env.ref('base.user_admin')).toggle_active() with self.assertRaises(ValidationError): - test_partner.with_user(self.env.ref('base.user_demo')).toggle_active() + test_partner.with_user(self.user_demo).toggle_active() # Can archive the user but the partner stays active test_user.toggle_active() diff --git a/odoo/addons/base/tests/test_views.py b/odoo/addons/base/tests/test_views.py index 272586ba4db..52e074ca366 100644 --- a/odoo/addons/base/tests/test_views.py +++ b/odoo/addons/base/tests/test_views.py @@ -15,6 +15,7 @@ from psycopg2.extras import Json from odoo.exceptions import AccessError, ValidationError from odoo.tests import common, tagged +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo from odoo.tools import get_cache_key_counter, mute_logger, view_validation, safe_eval from odoo.addons.base.models import ir_ui_view @@ -29,7 +30,7 @@ class ViewXMLID(common.TransactionCase): self.assertTrue(view.model_data_id) self.assertEqual(view.model_data_id.complete_name, 'base.view_company_form') -class ViewCase(common.TransactionCase): +class ViewCase(TransactionCaseWithUserDemo): def setUp(self): super(ViewCase, self).setUp() self.View = self.env['ir.ui.view'] @@ -2304,7 +2305,7 @@ class TestViews(ViewCase): """, }) - user_demo = self.env.ref('base.user_demo') + user_demo = self.user_demo # Make sure demo doesn't have the base.group_system self.assertFalse(self.env['res.partner'].with_user(user_demo).env.user.has_group('base.group_system')) arch = self.env['res.partner'].with_user(user_demo).get_view(view_id=view.id)['arch'] @@ -3935,7 +3936,7 @@ class TestValidationTools(common.BaseCase): {'field'}, ) -class TestAccessRights(common.TransactionCase): +class TestAccessRights(TransactionCaseWithUserDemo): @common.users('demo') def test_access(self): @@ -3961,7 +3962,7 @@ class TestAllViews(common.TransactionCase): view._check_xml() @common.tagged('post_install', '-at_install', '-standard', 'render_all_views') -class TestRenderAllViews(common.TransactionCase): +class TestRenderAllViews(TransactionCaseWithUserDemo): @common.users('demo', 'admin') def test_render_all_views(self): @@ -4318,7 +4319,7 @@ class ViewModifiers(ViewCase): """, }) - user_demo = self.env.ref('base.user_demo') + user_demo = self.user_demo # Make sure demo doesn't have the base.group_system self.assertFalse(self.env['res.partner'].with_user(user_demo).env.user.has_group('base.group_system')) arch = self.env['res.partner'].with_user(user_demo).get_view(view_id=view.id)['arch'] diff --git a/odoo/addons/base/tests/test_xmlrpc.py b/odoo/addons/base/tests/test_xmlrpc.py index d4d683a8345..38363b512ec 100644 --- a/odoo/addons/base/tests/test_xmlrpc.py +++ b/odoo/addons/base/tests/test_xmlrpc.py @@ -67,6 +67,7 @@ class TestXMLRPC(common.HttpCase): def test_xmlrpc_frozendict_marshalling(self): """ Test that the marshalling of a frozendict object works properly over XMLRPC """ + self.env.ref('base.user_admin').tz = "Europe/Brussels" ctx = self.xmlrpc_object.execute( common.get_db_name(), self.admin_uid, 'admin', 'res.users', 'context_get', diff --git a/odoo/addons/test_apikeys/tests/test_flow.py b/odoo/addons/test_apikeys/tests/test_flow.py index 3a469e7d717..ccc3db58163 100644 --- a/odoo/addons/test_apikeys/tests/test_flow.py +++ b/odoo/addons/test_apikeys/tests/test_flow.py @@ -1,10 +1,15 @@ +import logging import json from odoo import api -from odoo.tests import tagged, HttpCase, get_db_name +from odoo.tests import tagged, get_db_name, loaded_demo_data +from odoo.addons.base.tests.common import HttpCaseWithUserDemo + +_logger = logging.getLogger(__name__) + @tagged('post_install', '-at_install') -class TestAPIKeys(HttpCase): +class TestAPIKeys(HttpCaseWithUserDemo): def setUp(self): super().setUp() @@ -18,6 +23,10 @@ class TestAPIKeys(HttpCase): del self.registry['ir.logging'].send_key def test_addremove(self): + # TODO: Make this work if no demo data + hr installed + if not loaded_demo_data(self.env): + _logger.warning("This test relies on demo data. To be rewritten independently of demo data for accurate and reliable results.") + return db = get_db_name() self.start_tour('/web', 'apikeys_tour_setup', login='demo') demo_user = self.env['res.users'].search([('login', '=', 'demo')]) diff --git a/odoo/addons/test_http/tests/test_common.py b/odoo/addons/test_http/tests/test_common.py index e2a4eabf262..7a106bfee2c 100644 --- a/odoo/addons/test_http/tests/test_common.py +++ b/odoo/addons/test_http/tests/test_common.py @@ -4,12 +4,12 @@ from unittest.mock import patch import odoo from odoo.http import Session -from odoo.tests.common import HttpCase +from odoo.addons.base.tests.common import HttpCaseWithUserDemo from odoo.tools.func import lazy_property from odoo.addons.test_http.utils import MemoryGeoipResolver, MemorySessionStore -class TestHttpBase(HttpCase): +class TestHttpBase(HttpCaseWithUserDemo): @classmethod def setUpClass(cls): super().setUpClass() diff --git a/odoo/addons/test_main_flows/tests/test_flow.py b/odoo/addons/test_main_flows/tests/test_flow.py index 69a029808d4..2a6e31a3784 100644 --- a/odoo/addons/test_main_flows/tests/test_flow.py +++ b/odoo/addons/test_main_flows/tests/test_flow.py @@ -2,8 +2,12 @@ from odoo import Command from odoo.tools import mute_logger +import logging import odoo.tests +_logger = logging.getLogger(__name__) + + class BaseTestUi(odoo.tests.HttpCase): def main_flow_tour(self): @@ -72,6 +76,10 @@ class BaseTestUi(odoo.tests.HttpCase): class TestUi(BaseTestUi): def test_01_main_flow_tour(self): + # TODO: Adapt to work without demo data + if not odoo.tests.loaded_demo_data(self.env): + _logger.warning("This test relies on demo data. To be rewritten independently of demo data for accurate and reliable results.") + return self.main_flow_tour() def test_company_switch_access_error(self): @@ -113,4 +121,8 @@ class TestUiMobile(BaseTestUi): touch_enabled = True def test_01_main_flow_tour_mobile(self): + # TODO: Adapt to work without demo data + if not odoo.tests.loaded_demo_data(self.env): + _logger.warning("This test relies on demo data. To be rewritten independently of demo data for accurate and reliable results.") + return self.main_flow_tour() diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py index 556ada90124..383364f3cbb 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -2448,9 +2448,7 @@ class TestFields(TransactionCaseWithUserDemo): def test_85_binary_guess_zip(self): from odoo.addons.base.tests.test_mimetypes import ZIP # Regular ZIP files can be uploaded by non-admin users - self.env['test_new_api.binary_svg'].with_user( - self.env.ref('base.user_demo'), - ).create({ + self.env['test_new_api.binary_svg'].with_user(self.user_demo).create({ 'name': 'Test without attachment', 'image_wo_attachment': base64.b64decode(ZIP), }) @@ -2458,9 +2456,7 @@ class TestFields(TransactionCaseWithUserDemo): def test_86_text_base64_guess_svg(self): from odoo.addons.base.tests.test_mimetypes import SVG with self.assertRaises(UserError) as e: - self.env['test_new_api.binary_svg'].with_user( - self.env.ref('base.user_demo'), - ).create({ + self.env['test_new_api.binary_svg'].with_user(self.user_demo).create({ 'name': 'Test without attachment', 'image_wo_attachment': SVG.decode("utf-8"), }) @@ -2841,7 +2837,7 @@ class TestFields(TransactionCaseWithUserDemo): }) # unlink the line, and check the recomputation of move.quantity - user = self.env.ref('base.user_demo') + user = self.user_demo line.with_user(user).unlink() self.assertEqual(move.quantity, 0) diff --git a/odoo/addons/test_read_group/tests/test_m2m_grouping.py b/odoo/addons/test_read_group/tests/test_m2m_grouping.py index d1797ec3fb7..63f6b879761 100644 --- a/odoo/addons/test_read_group/tests/test_m2m_grouping.py +++ b/odoo/addons/test_read_group/tests/test_m2m_grouping.py @@ -3,10 +3,11 @@ from odoo.fields import Command from odoo.tests import common +from odoo.addons.base.tests.common import TransactionCaseWithUserDemo @common.tagged('test_m2m_read_group') -class TestM2MGrouping(common.TransactionCase): +class TestM2MGrouping(TransactionCaseWithUserDemo): @classmethod def setUpClass(cls): @@ -176,7 +177,7 @@ class TestM2MGrouping(common.TransactionCase): ]) # as demo user, ir.rule should apply - tasks = self.tasks.with_user(self.browse_ref('base.user_demo')) + tasks = self.tasks.with_user(self.user_demo) # warming up various caches; this avoids extra queries tasks.read_group(domain=[], fields=['name:array_agg'], groupby=['user_ids']) diff --git a/odoo/tests/common.py b/odoo/tests/common.py index 21e7ae5b417..0c8c9de8b65 100644 --- a/odoo/tests/common.py +++ b/odoo/tests/common.py @@ -188,6 +188,8 @@ def new_test_user(env, login='', groups='base.group_user', context=None, **kwarg return env['res.users'].with_context(**context).create(create_values) +def loaded_demo_data(env): + return bool(env.ref('base.user_demo', raise_if_not_found=False)) class RecordCapturer: def __init__(self, model, domain):