From a6ae304e491603ad863a0f1f3c11f8e73251998d Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 25 Jul 2018 17:23:46 +0200 Subject: [PATCH] Add tests and support of _inherits --- server_environment/models/server_env_mixin.py | 12 +- server_environment/tests/common.py | 16 ++ .../models/server_env_test.py | 54 ++++++ .../security/ir.model.access.csv | 3 + test_server_environment/tests/__init__.py | 1 + .../tests/test_server_env_mixin.py | 19 --- .../tests/test_server_env_mixin_inherit.py | 161 ++++++++++++++++++ 7 files changed, 243 insertions(+), 23 deletions(-) create mode 100644 test_server_environment/tests/test_server_env_mixin_inherit.py diff --git a/server_environment/models/server_env_mixin.py b/server_environment/models/server_env_mixin.py index c4f4503..72eb23b 100644 --- a/server_environment/models/server_env_mixin.py +++ b/server_environment/models/server_env_mixin.py @@ -339,9 +339,9 @@ class ServerEnvMixin(models.AbstractModel): inverse_method_name = '_inverse_server_env_%s' % field.name inverse_method = partialmethod( - ServerEnvMixin._inverse_server_env, field.name + type(self)._inverse_server_env, field.name ) - setattr(ServerEnvMixin, inverse_method_name, inverse_method) + setattr(type(self), inverse_method_name, inverse_method) field.inverse = inverse_method_name field.store = False field.required = False @@ -356,7 +356,9 @@ class ServerEnvMixin(models.AbstractModel): and in the views to add 'readonly' on the fields. """ fieldname = self._server_env_is_editable_fieldname(base_field.name) - if fieldname not in self._fields: + # if the field is inherited, it's a related to its delegated model + # (inherits), we want to override it with a new one + if fieldname not in self._fields or self._fields[fieldname].inherited: field = fields.Boolean( compute='_compute_server_env_is_editable', automatic=True, @@ -378,7 +380,9 @@ class ServerEnvMixin(models.AbstractModel): fieldname = self._server_env_default_fieldname(base_field.name) if not fieldname: return - if fieldname not in self._fields: + # if the field is inherited, it's a related to its delegated model + # (inherits), we want to override it with a new one + if fieldname not in self._fields or self._fields[fieldname].inherited: base_field_cls = base_field.__class__ field_args = base_field.args.copy() field_args.pop('_sequence', None) diff --git a/server_environment/tests/common.py b/server_environment/tests/common.py index 37f3fb0..7ea1256 100644 --- a/server_environment/tests/common.py +++ b/server_environment/tests/common.py @@ -9,6 +9,9 @@ from odoo.tests import common from odoo.addons.server_environment import server_env from odoo.tools.config import config +import odoo.addons.server_environment.models.server_env_mixin as \ + server_env_mixin + class ServerEnvironmentCase(common.TransactionCase): @@ -41,3 +44,16 @@ class ServerEnvironmentCase(common.TransactionCase): newkeys['SERVER_ENV_CONFIG_SECRET'] = secret with patch.dict('os.environ', newkeys): yield + + @contextmanager + def load_config(self, public=None, secret=None): + original_serv_config = server_env_mixin.serv_config + try: + with self.set_config_dir(None), \ + self.set_env_variables(public, secret): + parser = server_env._load_config() + server_env_mixin.serv_config = parser + yield + + finally: + server_env_mixin.serv_config = original_serv_config diff --git a/test_server_environment/models/server_env_test.py b/test_server_environment/models/server_env_test.py index b18d1a1..0cbc793 100644 --- a/test_server_environment/models/server_env_test.py +++ b/test_server_environment/models/server_env_test.py @@ -59,3 +59,57 @@ class ServerEnvTestWithMixin(models.Model): def _inverse_alias_default(self): for record in self: record.alias_default = record.alias + + +class ServerEnvTest2(models.Model): + _name = 'server.env.test2' + _description = 'Server Environment Test Model 2' + # applied directly on the model + _inherit = 'server.env.mixin' + + name = fields.Char(required=True) + host = fields.Char() + + @property + def _server_env_fields(self): + base_fields = super()._server_env_fields + sftp_fields = { + "host": {}, + } + sftp_fields.update(base_fields) + return sftp_fields + + +class ServerEnvTestInherits1(models.Model): + _name = 'server.env.test.inherits1' + _description = 'Server Environment Test Model Inherits' + + base_id = fields.Many2one( + comodel_name='server.env.test', + delegate=True, + ) + # host is not redefined, handled by the delegated model + + +class ServerEnvTestInherits2(models.Model): + _name = 'server.env.test.inherits2' + _description = 'Server Environment Test Model Inherits' + # if you want to benefit from mixin in an inherits, + # even if the parent includes it, you have to + # add the inheritance here as well + _inherit = 'server.env.mixin' + + base_id = fields.Many2one( + comodel_name='server.env.test', + delegate=True, + ) + host = fields.Char() + + @property + def _server_env_fields(self): + base_fields = super()._server_env_fields + sftp_fields = { + "host": {}, + } + sftp_fields.update(base_fields) + return sftp_fields diff --git a/test_server_environment/security/ir.model.access.csv b/test_server_environment/security/ir.model.access.csv index 2d95da4..a2d18e6 100644 --- a/test_server_environment/security/ir.model.access.csv +++ b/test_server_environment/security/ir.model.access.csv @@ -1,2 +1,5 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_server_env_test,access_server_env_test,model_server_env_test,,1,0,0,0 +access_server_env_test2,access_server_env_test2,model_server_env_test2,,1,0,0,0 +access_server_env_test_inherits1,access_server_env_test_inherits1,model_server_env_test_inherits1,,1,0,0,0 +access_server_env_test_inherits2,access_server_env_test_inherits2,model_server_env_test_inherits2,,1,0,0,0 diff --git a/test_server_environment/tests/__init__.py b/test_server_environment/tests/__init__.py index 4952af4..4b0c4a6 100644 --- a/test_server_environment/tests/__init__.py +++ b/test_server_environment/tests/__init__.py @@ -1 +1,2 @@ from . import test_server_env_mixin +from . import test_server_env_mixin_inherit diff --git a/test_server_environment/tests/test_server_env_mixin.py b/test_server_environment/tests/test_server_env_mixin.py index 7f9b8ba..cc7b9cc 100644 --- a/test_server_environment/tests/test_server_env_mixin.py +++ b/test_server_environment/tests/test_server_env_mixin.py @@ -1,30 +1,11 @@ # Copyright 2018 Camptocamp (https://www.camptocamp.com). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from contextlib import contextmanager - -from odoo.addons.server_environment import server_env from odoo.addons.server_environment.tests.common import ServerEnvironmentCase -import odoo.addons.server_environment.models.server_env_mixin as \ - server_env_mixin - class TestServerEnvMixin(ServerEnvironmentCase): - @contextmanager - def load_config(self, public=None, secret=None): - original_serv_config = server_env_mixin.serv_config - try: - with self.set_config_dir(None), \ - self.set_env_variables(public, secret): - parser = server_env._load_config() - server_env_mixin.serv_config = parser - yield - - finally: - server_env_mixin.serv_config = original_serv_config - def test_env_computed_fields_read(self): """Read values from the config in env-computed fields""" public = ( diff --git a/test_server_environment/tests/test_server_env_mixin_inherit.py b/test_server_environment/tests/test_server_env_mixin_inherit.py new file mode 100644 index 0000000..3b93bdf --- /dev/null +++ b/test_server_environment/tests/test_server_env_mixin_inherit.py @@ -0,0 +1,161 @@ +# Copyright 2018 Camptocamp (https://www.camptocamp.com). +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.addons.server_environment.tests.common import ServerEnvironmentCase + + +class TestServerEnvMixinSameFieldName(ServerEnvironmentCase): + + def setUp(self): + super().setUp() + self.public = ( + # global for all server.env.test records + "[server_env_test]\n" + "host=global_value\n" + # for our server.env.test test record now + "[server_env_test.foo]\n" + "host=foo_value\n" + # for our server.env.test2 test record now + "[server_env_test2.foo]\n" + "host=foo2_value\n" + ) + self.foo = self.env['server.env.test'].create({'name': 'foo'}) + self.foo2 = self.env['server.env.test2'].create({ + 'name': 'foo', + }) + + def test_env_computed_fields_read(self): + """Read values from the config in env-computed fields""" + with self.load_config(self.public): + self.assertEqual(self.foo.name, 'foo') + self.assertEqual(self.foo2.name, 'foo') + self.assertEqual(self.foo.host, 'foo_value') + self.assertEqual(self.foo2.host, 'foo2_value') + + def test_env_computed_fields_not_editable(self): + """Env-computed fields without key in config can be written""" + # we can create the record even if we didn't provide + # the field host which was required + with self.load_config(self.public): + self.assertEqual(self.foo.host, 'foo_value') + self.assertFalse(self.foo.host_env_is_editable) + self.assertEqual(self.foo2.host, 'foo2_value') + self.assertFalse(self.foo2.host_env_is_editable) + + def test_env_computed_fields_editable(self): + """Env-computed fields without key in config can be written""" + # we can create the record even if we didn't provide + # the field host which was required + with self.load_config(): + self.assertFalse(self.foo.host) + self.assertTrue(self.foo.host_env_is_editable) + self.assertFalse(self.foo2.host) + self.assertTrue(self.foo2.host_env_is_editable) + + self.foo.host_env_default = 'foo_value' + self.foo.invalidate_cache() + self.assertEqual(self.foo.host, 'foo_value') + + self.foo2.host_env_default = 'foo2_value' + self.foo2.invalidate_cache() + self.assertEqual(self.foo2.host, 'foo2_value') + + self.foo.host = 'foo_new_value' + self.foo.invalidate_cache() + self.assertEqual(self.foo.host, 'foo_new_value') + + self.foo2.host = 'foo2_new_value' + self.foo2.invalidate_cache() + self.assertEqual(self.foo2.host, 'foo2_new_value') + + +class TestServerEnvMixinInherits(ServerEnvironmentCase): + + def setUp(self): + super().setUp() + self.public = ( + # global for all server.env.test records + "[server_env_test]\n" + "host=global_value\n" + # for our server.env.test test record now + "[server_env_test.foo]\n" + "host=foo_value\n" + # for our server.env.test.inherits1 test record now + "[server_env_test_inherits1.foo]\n" + "host=foo_inherits_value\n" + # for our server.env.test.inherits2 test record now + "[server_env_test_inherits2.foo]\n" + "host=foo_inherits_value\n" + ) + self.foo = self.env['server.env.test'].create({'name': 'foo'}) + self.foo_inh1 = self.env['server.env.test.inherits1'].create({ + 'name': 'foo' + }) + self.foo_inh2 = self.env['server.env.test.inherits2'].create({ + 'name': 'foo' + }) + + def test_env_computed_fields_read(self): + """Read values from the config in env-computed fields""" + with self.load_config(self.public): + self.assertEqual(self.foo.name, 'foo') + self.assertEqual(self.foo_inh1.name, 'foo') + self.assertEqual(self.foo_inh2.name, 'foo') + self.assertEqual(self.foo.host, 'foo_value') + # inh1 does not redefine the host field so has the + # same value than the parent record (delegate) + self.assertEqual(self.foo_inh1.host, 'foo_value') + # inh2 redefines self.the host field so has its own value + self.assertEqual(self.foo_inh2.host, 'foo_inherits_value') + + def test_env_computed_fields_not_editable(self): + """Env-computed fields without key in config can be written""" + with self.load_config(self.public): + self.assertEqual(self.foo.host, 'foo_value') + self.assertFalse(self.foo.host_env_is_editable) + self.assertEqual(self.foo_inh1.host, 'foo_value') + self.assertFalse(self.foo_inh1.host_env_is_editable) + self.assertEqual(self.foo_inh2.host, 'foo_inherits_value') + self.assertFalse(self.foo_inh2.host_env_is_editable) + + def test_env_computed_fields_editable(self): + """Env-computed fields without key in config can be written""" + with self.load_config(): + self.assertFalse(self.foo.host) + self.assertTrue(self.foo.host_env_is_editable) + self.assertFalse(self.foo_inh1.host) + self.assertTrue(self.foo_inh1.host_env_is_editable) + self.assertFalse(self.foo_inh2.host) + self.assertTrue(self.foo_inh2.host_env_is_editable) + + self.foo.host_env_default = 'foo_value' + self.foo.invalidate_cache() + self.assertEqual(self.foo.host, 'foo_value') + + self.foo.host = 'foo_new_value' + self.foo.invalidate_cache() + self.assertEqual(self.foo.host, 'foo_new_value') + + self.foo_inh1.host_env_default = 'foo2_value' + self.foo_inh1.invalidate_cache() + self.assertEqual(self.foo_inh1.host, 'foo2_value') + self.assertEqual(self.foo_inh1.base_id.host, 'foo2_value') + + self.foo_inh1.host = 'foo2_new_value' + self.foo_inh1.invalidate_cache() + self.assertEqual(self.foo_inh1.host, 'foo2_new_value') + self.assertEqual(self.foo_inh1.base_id.host, 'foo2_new_value') + + self.foo_inh2.host_env_default = 'foo_inherits_value' + self.foo_inh2.base_id.host_env_default = 'bar_value' + self.foo_inh2.invalidate_cache() + self.foo_inh2.base_id.invalidate_cache() + self.assertEqual(self.foo_inh2.host, 'foo_inherits_value') + self.assertEqual(self.foo_inh2.base_id.host, 'bar_value') + + self.foo_inh2.host = 'foo_inherits_new_value' + self.foo_inh2.base_id.host = 'bar_new_value' + self.foo_inh2.invalidate_cache() + self.foo_inh2.base_id.invalidate_cache() + self.assertEqual(self.foo_inh2.host, 'foo_inherits_new_value') + self.assertEqual(self.foo_inh2.base_id.host, 'bar_new_value')