diff options
| author | Adrian Torres <adt@odoo.com> | 2020-04-17 14:07:27 +0000 |
|---|---|---|
| committer | Raphael Collet <rco@odoo.com> | 2020-04-22 07:45:53 +0000 |
| commit | ca91e13dee168af45b12ec054b6dd57346f5c5f1 (patch) | |
| tree | 8c18d1e1ccf41bc748504eeb54ad2788be7d46a1 /addons/test_website | |
| parent | baf1c1406bcf148885fc40a9a050731bf4402f75 (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.py | 135 |
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!" |
