This patch aims to fix multiple issues with the removal of table
constraints at module uninstall.
1. We cannot remove `ir.model.constraint` records before calling
`_module_data_uninstall` on them. Otherwise we either won't find them
when performing the search
`self.env['ir.model.constraint'].search([('module', 'in',
modules.ids)]` or, if we somehow keep the ids and use `browse`
instead, would get an error because `_module_data_uninstall` tries to
access field values of records already removed. Note, although not an
issue, the removal is redundant for non FK constraints since
`_model_data_uninstall` already unlinks the record.
2. When a constraint has a name longer than 63 characters (Postgres
default) we would fail the check for the existence of the constraint
since the names are truncated.
3. When checking for the presence of a constraint we assumed its type
would be `u` in `pg_constraint` because for us that means non FK
(i.e. not `f` type). That's incorrect since there are many more
types. Here we propose to handle `c,u,x` types.
For bullet 2 we use `tools.make_identifier` that hashes the name and
ensures it fits in the 63 chars limit.
Revert "[IMP] models: warn if constraint key len exceed 63"
The check from commit 823d9e10dc is no
longer needed since the name is ensured to fit length limit.
[IMP] code: improve uninstall tests
Perform extra checks for removal of SQL constraints. Note the test is
commented out in `__init__.py`. It can be uncommented locally for
testing. It's kept commented out to avoid random errors in runbot.
closes odoo/odoo#129084
X-original-commit: af288b7178c25261329dd85a2e64b9dd635cd9e1
Signed-off-by: Raphael Collet <rco@odoo.com>
87 lines
3.0 KiB
Python
87 lines
3.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
# This assumes an existing but uninitialized database.
|
|
|
|
from contextlib import contextmanager
|
|
import unittest
|
|
|
|
from odoo import api, registry, SUPERUSER_ID
|
|
from odoo.tests import common
|
|
from odoo.tests.common import BaseCase
|
|
|
|
from odoo.modules.registry import Registry
|
|
|
|
|
|
@contextmanager
|
|
def environment():
|
|
""" Return an environment with a new cursor for the current database; the
|
|
cursor is committed and closed after the context block.
|
|
"""
|
|
reg = registry(common.get_db_name())
|
|
with reg.cursor() as cr:
|
|
yield api.Environment(cr, SUPERUSER_ID, {})
|
|
|
|
|
|
MODULE = 'test_uninstall'
|
|
MODEL = 'test_uninstall.model'
|
|
|
|
|
|
class TestUninstall(BaseCase):
|
|
"""
|
|
Test the install/uninstall of a test module. The module is available in
|
|
`odoo.tests` which should be present in the addons-path.
|
|
"""
|
|
|
|
def test_01_install(self):
|
|
""" Check a few things showing the module is installed. """
|
|
with environment() as env:
|
|
module = env['ir.module.module'].search([('name', '=', MODULE)])
|
|
assert len(module) == 1
|
|
module.button_install()
|
|
Registry.new(common.get_db_name(), update_module=True)
|
|
|
|
with environment() as env:
|
|
self.assertIn('test_uninstall.model', env.registry)
|
|
self.assertTrue(env['ir.model.data'].search([('module', '=', MODULE)]))
|
|
self.assertTrue(env['ir.model.fields'].search([('model', '=', MODEL)]))
|
|
|
|
env.cr.execute(
|
|
r"""
|
|
SELECT conname
|
|
FROM pg_constraint
|
|
WHERE conrelid = 'res_users'::regclass
|
|
AND conname LIKE 'res\_users\_test\_uninstall\_res\_user\_%'
|
|
"""
|
|
)
|
|
existing_constraints = [r[0] for r in env.cr.fetchall()]
|
|
self.assertTrue(len(existing_constraints) == 4, existing_constraints)
|
|
|
|
def test_02_uninstall(self):
|
|
""" Check a few things showing the module is uninstalled. """
|
|
with environment() as env:
|
|
module = env['ir.module.module'].search([('name', '=', MODULE)])
|
|
assert len(module) == 1
|
|
module.button_uninstall()
|
|
Registry.new(common.get_db_name(), update_module=True)
|
|
|
|
with environment() as env:
|
|
self.assertNotIn('test_uninstall.model', env.registry)
|
|
self.assertFalse(env['ir.model.data'].search([('module', '=', MODULE)]))
|
|
self.assertFalse(env['ir.model.fields'].search([('model', '=', MODEL)]))
|
|
|
|
env.cr.execute(
|
|
r"""
|
|
SELECT conname
|
|
FROM pg_constraint
|
|
WHERE conrelid = 'res_users'::regclass
|
|
AND conname LIKE 'res\_users\_test\_uninstall\_res\_user\_%'
|
|
"""
|
|
)
|
|
remaining_constraints = [r[0] for r in env.cr.fetchall()]
|
|
self.assertFalse(remaining_constraints)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|