summaryrefslogtreecommitdiff
path: root/addons/test_website
diff options
context:
space:
mode:
authorAdrian Torres <adt@odoo.com>2020-04-17 14:07:27 +0000
committerRaphael Collet <rco@odoo.com>2020-04-22 07:45:53 +0000
commitca91e13dee168af45b12ec054b6dd57346f5c5f1 (patch)
tree8c18d1e1ccf41bc748504eeb54ad2788be7d46a1 /addons/test_website
parentbaf1c1406bcf148885fc40a9a050731bf4402f75 (diff)
[IMP] testing: forbid module operations during testing
With this commit, module operations such as install, upgrades and uninstalls are henceforth forbidden inside unit tests and instead such tests must be performed with standalone Odoo scripts. This is done because module operations during tests are not transactional, this can leave the registry in an unclean state and further tests may be affected by this, it also creates a new registry which complicates registry cleanup if anything crashes, because the registry to be cleaned up is not the same one that crashed. Instead, what should be done is a script that imports odoo as a library, and loads the database necessary then performs whichever operations necessary. This script should contain a single function with a single parameter (env) and should be decorated with @odoo.tests.common.standalone in order to be executed properly, this decorator accepts any amount of positional parameters as tags that can be specified when calling the script in order to execute only a select subset of scripts. Special tags are: 'all' and <module_name>, these are generated automatically, the first will execute ALL scripts available whereas <module_name> will execute all scripts introduced by said module. When calling the test_module_operations script, only scripts found in *installed* modules will be executed, script discovery is only possible if the code is loaded therefore it is only possible if the module is installed. closes odoo/odoo#49669 Signed-off-by: Adrian Torres (adt) <adt@odoo.com>
Diffstat (limited to 'addons/test_website')
-rw-r--r--addons/test_website/tests/test_views_during_module_operation.py135
1 files changed, 70 insertions, 65 deletions
diff --git a/addons/test_website/tests/test_views_during_module_operation.py b/addons/test_website/tests/test_views_during_module_operation.py
index e960291bf22..c078afc03fd 100644
--- a/addons/test_website/tests/test_views_during_module_operation.py
+++ b/addons/test_website/tests/test_views_during_module_operation.py
@@ -1,78 +1,83 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from odoo.tests import TransactionCase, tagged
+from odoo.tests import standalone
-@tagged('-at_install', 'post_install')
-class TestViewsDuringModuleOperation(TransactionCase):
- def test_01_cow_views_unlink_on_module_update(self):
- """ Ensure COW views are correctly removed during module update.
- Not removing the view could lead to traceback:
- - Having a view A
- - Having a view B that inherits from a view C
- - View B t-call view A
- - COW view B
- - Delete view A and B from module datas and update it
- - Rendering view C will crash since it will render child view B that
- t-call unexisting view A
- """
+@standalone('cow_views')
+def test_01_cow_views_unlink_on_module_update(env):
+ """ Ensure COW views are correctly removed during module update.
+ Not removing the view could lead to traceback:
+ - Having a view A
+ - Having a view B that inherits from a view C
+ - View B t-call view A
+ - COW view B
+ - Delete view A and B from module datas and update it
+ - Rendering view C will crash since it will render child view B that
+ t-call unexisting view A
+ """
- View = self.env['ir.ui.view']
- Imd = self.env['ir.model.data']
+ View = env['ir.ui.view']
+ Imd = env['ir.model.data']
- update_module_base_view = self.env.ref('test_website.update_module_base_view')
- update_module_view_to_be_t_called = View.create({
- 'name': 'View to be t-called',
- 'type': 'qweb',
- 'arch': '<div>I will be t-called</div>',
- 'key': 'test_website.update_module_view_to_be_t_called',
- })
- update_module_child_view = View.create({
- 'name': 'Child View',
- 'mode': 'extension',
- 'inherit_id': update_module_base_view.id,
- 'arch': '''
- <div position="inside">
- <t t-call="test_website.update_module_view_to_be_t_called"/>
- </div>
- ''',
- 'key': 'test_website.update_module_child_view',
- })
+ update_module_base_view = env.ref('test_website.update_module_base_view')
+ update_module_view_to_be_t_called = View.create({
+ 'name': 'View to be t-called',
+ 'type': 'qweb',
+ 'arch': '<div>I will be t-called</div>',
+ 'key': 'test_website.update_module_view_to_be_t_called',
+ })
+ update_module_child_view = View.create({
+ 'name': 'Child View',
+ 'mode': 'extension',
+ 'inherit_id': update_module_base_view.id,
+ 'arch': '''
+ <div position="inside">
+ <t t-call="test_website.update_module_view_to_be_t_called"/>
+ </div>
+ ''',
+ 'key': 'test_website.update_module_child_view',
+ })
- # Create IMD so when updating the module the views will be removed (not found in file)
- Imd.create({
- 'module': 'test_website',
- 'name': 'update_module_view_to_be_t_called',
- 'model': 'ir.ui.view',
- 'res_id': update_module_view_to_be_t_called.id,
- })
- Imd.create({
- 'module': 'test_website',
- 'name': 'update_module_child_view',
- 'model': 'ir.ui.view',
- 'res_id': update_module_child_view.id,
- })
+ # Create IMD so when updating the module the views will be removed (not found in file)
+ Imd.create({
+ 'module': 'test_website',
+ 'name': 'update_module_view_to_be_t_called',
+ 'model': 'ir.ui.view',
+ 'res_id': update_module_view_to_be_t_called.id,
+ })
+ Imd.create({
+ 'module': 'test_website',
+ 'name': 'update_module_child_view',
+ 'model': 'ir.ui.view',
+ 'res_id': update_module_child_view.id,
+ })
- # Trigger COW on child view
- update_module_child_view.with_context(website_id=1).write({'name': 'Child View (W1)'})
+ # Trigger COW on child view
+ update_module_child_view.with_context(website_id=1).write({'name': 'Child View (W1)'})
- # Ensure views are correctly setup
- self.assertEqual(View.search_count([('type', '=', 'qweb'), ('key', '=', update_module_child_view.key)]), 2)
- self.assertTrue(self.env.ref(update_module_view_to_be_t_called.key))
- self.assertTrue(self.env.ref(update_module_base_view.key))
+ # Ensure views are correctly setup
+ msg = "View '%s' does not exist!"
+ assert View.search_count([
+ ('type', '=', 'qweb'),
+ ('key', '=', update_module_child_view.key)
+ ]) == 2, msg % update_module_child_view.key
+ assert bool(env.ref(update_module_view_to_be_t_called.key)),\
+ msg % update_module_view_to_be_t_called.key
+ assert bool(env.ref(update_module_base_view.key)), msg % update_module_base_view.key
- # the upgrade of the module below instanciates a NEW registry, so we
- # have to restore the old one in order to perform the cleanups
- @self.addCleanup
- def cleanup():
- self.registry.registries[self.registry.db_name] = self.registry
+ # Upgrade the module
+ test_website_module = env['ir.module.module'].search([('name', '=', 'test_website')])
+ test_website_module.button_immediate_upgrade()
+ env.reset() # clear the set of environments
+ env = env() # get an environment that refers to the new registry
- # Update the module
- test_website_module = self.env['ir.module.module'].search([('name', '=', 'test_website')])
- test_website_module.button_immediate_upgrade()
+ # Ensure generic views got removed
+ view = env.ref('test_website.update_module_view_to_be_t_called', raise_if_not_found=False)
+ assert not view, "Generic view did not get removed!"
- # Ensure generic views got removed
- self.assertFalse(self.env.ref('test_website.update_module_view_to_be_t_called', raise_if_not_found=False))
- # Ensure specific COW views got removed
- self.assertEqual(View.search_count([('type', '=', 'qweb'), ('key', '=', 'test_website.update_module_child_view')]), 0)
+ # Ensure specific COW views got removed
+ assert not env['ir.ui.view'].search_count([
+ ('type', '=', 'qweb'),
+ ('key', '=', 'test_website.update_module_child_view'),
+ ]), "Specific COW views did not get removed!"