Files
odoo_source/odoo/addons/test_new_api/tests/test_schema.py
T
Raphael Collet aa0cdacced [FIX] core: related field attributes
A related field copies the attributes from its target field, except for
the attributes defined on the related field itself.  The implementation
of this feature was not working properly for attributes with a truthy
default value.

closes odoo/odoo#79025

X-original-commit: dec4a7ec478fa02f19dee8c8426c88d17dc3c7f3
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
2021-10-26 16:06:48 +00:00

580 lines
24 KiB
Python

# -*- coding: utf-8 -*-
from odoo.models import MetaModel
from odoo.tests import common
from odoo.addons.base.models.ir_model import model_xmlid, field_xmlid, selection_xmlid
def get_model_name(cls):
name = cls._name
if not name:
[name] = cls._inherit if isinstance(cls._inherit, list) else [cls._inherit]
assert isinstance(name, str)
return name
class TestReflection(common.TransactionCase):
""" Test the reflection into 'ir.model', 'ir.model.fields', etc. """
def assertModelXID(self, record):
""" Check the XML id of the given 'ir.model' record. """
xid = model_xmlid('test_new_api', record.model)
self.assertEqual(record, self.env.ref(xid))
def assertFieldXID(self, record):
""" Check the XML id of the given 'ir.model.fields' record. """
xid = field_xmlid('test_new_api', record.model, record.name)
self.assertEqual(record, self.env.ref(xid))
def assertSelectionXID(self, record):
""" Check the XML id of the given 'ir.model.fields.selection' record. """
xid = selection_xmlid('test_new_api', record.field_id.model, record.field_id.name, record.value)
self.assertEqual(record, self.env.ref(xid))
def test_models_fields(self):
""" check that all models and fields are reflected as expected. """
# retrieve the models defined in this module, and check them
model_names = {
get_model_name(cls)
for cls in MetaModel.module_to_models['test_new_api']
}
ir_models = self.env['ir.model'].search([('model', 'in', list(model_names))])
self.assertEqual(len(ir_models), len(model_names))
for ir_model in ir_models:
with self.subTest(model=ir_model.model):
model = self.env[ir_model.model]
self.assertModelXID(ir_model)
self.assertEqual(ir_model.name, model._description or False)
self.assertEqual(ir_model.state, 'manual' if model._custom else 'base')
self.assertEqual(ir_model.transient, bool(model._transient))
self.assertItemsEqual(ir_model.mapped('field_id.name'), list(model._fields))
for ir_field in ir_model.field_id:
with self.subTest(field=ir_field.name):
field = model._fields[ir_field.name]
self.assertFieldXID(ir_field)
self.assertEqual(ir_field.model, field.model_name)
self.assertEqual(ir_field.field_description, field.string)
self.assertEqual(ir_field.help, field.help or False)
self.assertEqual(ir_field.ttype, field.type)
self.assertEqual(ir_field.state, 'manual' if field.manual else 'base')
self.assertEqual(ir_field.index, bool(field.index))
self.assertEqual(ir_field.store, bool(field.store))
self.assertEqual(ir_field.copied, bool(field.copy))
self.assertEqual(ir_field.related, field.related or False)
self.assertEqual(ir_field.readonly, bool(field.readonly))
self.assertEqual(ir_field.required, bool(field.required))
self.assertEqual(ir_field.selectable, bool(field.search or field.store))
self.assertEqual(ir_field.translate, bool(field.translate))
if field.relational:
self.assertEqual(ir_field.relation, field.comodel_name)
if field.type == 'one2many' and field.store:
self.assertEqual(ir_field.relation_field, field.inverse_name)
if field.type == 'many2many' and field.store:
self.assertEqual(ir_field.relation_table, field.relation)
self.assertEqual(ir_field.column1, field.column1)
self.assertEqual(ir_field.column2, field.column2)
relation = self.env['ir.model.relation'].search([('name', '=', field.relation)])
self.assertTrue(relation)
self.assertIn(relation.model.model, [field.model_name, field.comodel_name])
if field.type == 'selection':
selection = [(sel.value, sel.name) for sel in ir_field.selection_ids]
if isinstance(field.selection, list):
self.assertEqual(selection, field.selection)
else:
self.assertEqual(selection, [])
for sel in ir_field.selection_ids:
self.assertSelectionXID(sel)
field_description = field.get_description(self.env)
if field.type in ('many2many', 'one2many'):
self.assertFalse(field_description['sortable'])
elif field.store and field.column_type:
self.assertTrue(field_description['sortable'])
class TestSchema(common.TransactionCase):
def get_table_data(self, tablename):
query = ''' SELECT table_catalog, table_schema, table_name, table_type,
user_defined_type_catalog, user_defined_type_schema,
user_defined_type_name, is_insertable_into, is_typed
FROM information_schema.tables
WHERE table_name=%s '''
self.cr.execute(query, [tablename])
return self.cr.dictfetchone()
def get_columns_data(self, tablename):
query = ''' SELECT table_catalog, table_schema, table_name, column_name,
column_default, data_type, is_nullable, is_updatable,
character_maximum_length, numeric_precision,
numeric_precision_radix, numeric_scale,
datetime_precision, udt_catalog, udt_schema, udt_name
FROM information_schema.columns
WHERE table_name=%s '''
self.cr.execute(query, [tablename])
return {row['column_name']: row for row in self.cr.dictfetchall()}
def get_foreign_keys(self, tablename):
query = ''' SELECT a.table_name, a.column_name,
b.table_name, b.column_name, c.delete_rule
FROM information_schema.referential_constraints c,
information_schema.key_column_usage a,
information_schema.constraint_column_usage b
WHERE a.constraint_schema=c.constraint_schema
AND a.constraint_name=c.constraint_name
AND b.constraint_schema=c.constraint_schema
AND b.constraint_name=c.constraint_name
AND a.table_name=%s '''
self.cr.execute(query, [tablename])
return self.cr.fetchall()
def test_00_table(self):
""" check the database schema of a model """
model = self.env['test_new_api.foo']
self.assertEqual(model._table, 'test_new_api_foo')
# retrieve schema data about that table
table_data = self.get_table_data('test_new_api_foo')
self.assertEqual(table_data, {
'is_insertable_into': u'YES',
'is_typed': u'NO',
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_foo',
'table_schema': u'public',
'table_type': u'BASE TABLE',
'user_defined_type_catalog': None,
'user_defined_type_name': None,
'user_defined_type_schema': None,
})
# retrieve schema data about the table's columns
columns_data = self.get_columns_data('test_new_api_foo')
self.assertEqual(set(columns_data),
{'id', 'create_date', 'create_uid', 'write_date',
'write_uid', 'name', 'value1', 'value2', 'text'})
# retrieve schema data about the table's foreign keys
foreign_keys = self.get_foreign_keys('test_new_api_foo')
self.assertItemsEqual(foreign_keys, [
('test_new_api_foo', 'create_uid', 'res_users', 'id', 'SET NULL'),
('test_new_api_foo', 'write_uid', 'res_users', 'id', 'SET NULL'),
])
def test_10_boolean(self):
""" check the database representation of a boolean field """
model = self.env['test_new_api.message']
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['important'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'important',
'data_type': u'boolean',
'datetime_precision': None,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': None,
'numeric_precision_radix': None,
'numeric_scale': None,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_message',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'bool',
'udt_schema': u'pg_catalog',
})
def test_10_integer(self):
""" check the database representation of an integer field """
model = self.env['test_new_api.category']
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['color'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'color',
'data_type': u'integer',
'datetime_precision': None,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': 32,
'numeric_precision_radix': 2,
'numeric_scale': 0,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_category',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'int4',
'udt_schema': u'pg_catalog',
})
def test_10_float(self):
""" check the database representation of a float field """
model = self.env['test_new_api.mixed']
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['number'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'number',
'data_type': u'numeric',
'datetime_precision': None,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': None,
'numeric_precision_radix': 10,
'numeric_scale': None,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_mixed',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'numeric',
'udt_schema': u'pg_catalog',
})
def test_10_monetary(self):
""" check the database representation of a monetary field """
model = self.env['test_new_api.mixed']
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['amount'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'amount',
'data_type': u'numeric',
'datetime_precision': None,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': None,
'numeric_precision_radix': 10,
'numeric_scale': None,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_mixed',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'numeric',
'udt_schema': u'pg_catalog',
})
def test_10_char(self):
""" check the database representation of a char field """
model = self.env['res.country']
self.assertFalse(type(model).code.required)
self.assertEqual(type(model).code.size, 2)
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['code'], {
'character_maximum_length': 2,
'column_default': None,
'column_name': u'code',
'data_type': u'character varying',
'datetime_precision': None,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': None,
'numeric_precision_radix': None,
'numeric_scale': None,
'table_catalog': self.cr.dbname,
'table_name': u'res_country',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'varchar',
'udt_schema': u'pg_catalog',
})
model = self.env['test_new_api.message']
self.assertFalse(type(model).name.required)
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['name'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'name',
'data_type': u'character varying',
'datetime_precision': None,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': None,
'numeric_precision_radix': None,
'numeric_scale': None,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_message',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'varchar',
'udt_schema': u'pg_catalog',
})
model = self.env['test_new_api.category']
self.assertTrue(type(model).name.required)
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['name'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'name',
'data_type': u'character varying',
'datetime_precision': None,
'is_nullable': u'NO',
'is_updatable': u'YES',
'numeric_precision': None,
'numeric_precision_radix': None,
'numeric_scale': None,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_category',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'varchar',
'udt_schema': u'pg_catalog',
})
def test_10_text(self):
""" check the database representation of a text field """
model = self.env['test_new_api.message']
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['body'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'body',
'data_type': u'text',
'datetime_precision': None,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': None,
'numeric_precision_radix': None,
'numeric_scale': None,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_message',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'text',
'udt_schema': u'pg_catalog',
})
def test_10_html(self):
""" check the database representation of an html field """
model = self.env['test_new_api.mixed']
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['comment1'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'comment1',
'data_type': u'text',
'datetime_precision': None,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': None,
'numeric_precision_radix': None,
'numeric_scale': None,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_mixed',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'text',
'udt_schema': u'pg_catalog',
})
def test_10_date(self):
""" check the database representation of a date field """
model = self.env['test_new_api.mixed']
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['date'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'date',
'data_type': u'date',
'datetime_precision': 0,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': None,
'numeric_precision_radix': None,
'numeric_scale': None,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_mixed',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'date',
'udt_schema': u'pg_catalog',
})
def test_10_datetime(self):
""" check the database representation of a datetime field """
model = self.env['ir.property']
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['value_datetime'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'value_datetime',
'data_type': u'timestamp without time zone',
'datetime_precision': 6,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': None,
'numeric_precision_radix': None,
'numeric_scale': None,
'table_catalog': self.cr.dbname,
'table_name': u'ir_property',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'timestamp',
'udt_schema': u'pg_catalog',
})
model = self.env['test_new_api.mixed']
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['create_date'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'create_date',
'data_type': u'timestamp without time zone',
'datetime_precision': 6,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': None,
'numeric_precision_radix': None,
'numeric_scale': None,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_mixed',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'timestamp',
'udt_schema': u'pg_catalog',
})
def test_10_selection(self):
""" check the database representation of a selection field """
model = self.env['test_new_api.mixed']
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['lang'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'lang',
'data_type': u'character varying',
'datetime_precision': None,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': None,
'numeric_precision_radix': None,
'numeric_scale': None,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_mixed',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'varchar',
'udt_schema': u'pg_catalog',
})
def test_10_reference(self):
""" check the database representation of a reference field """
model = self.env['test_new_api.mixed']
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['reference'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'reference',
'data_type': u'character varying',
'datetime_precision': None,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': None,
'numeric_precision_radix': None,
'numeric_scale': None,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_mixed',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'varchar',
'udt_schema': u'pg_catalog',
})
def test_10_many2one(self):
""" check the database representation of a many2one field """
model = self.env['test_new_api.mixed']
columns_data = self.get_columns_data(model._table)
self.assertEqual(columns_data['currency_id'], {
'character_maximum_length': None,
'column_default': None,
'column_name': u'currency_id',
'data_type': u'integer',
'datetime_precision': None,
'is_nullable': u'YES',
'is_updatable': u'YES',
'numeric_precision': 32,
'numeric_precision_radix': 2,
'numeric_scale': 0,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_mixed',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'int4',
'udt_schema': u'pg_catalog',
})
foreign_keys = self.get_foreign_keys(model._table)
self.assertIn(
('test_new_api_mixed', 'currency_id', 'res_currency', 'id', 'SET NULL'),
foreign_keys,
)
def test_10_many2many(self):
""" check the database representation of a many2many field """
model = self.env['test_new_api.discussion']
field = type(model).categories
comodel = self.env[field.comodel_name]
self.assertTrue(field.relation)
self.assertTrue(field.column1)
self.assertTrue(field.column2)
columns_data = self.get_columns_data(model._table)
self.assertNotIn('categories', columns_data)
table_data = self.get_table_data(field.relation)
self.assertEqual(table_data, {
'is_insertable_into': u'YES',
'is_typed': u'NO',
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_discussion_category',
'table_schema': u'public',
'table_type': u'BASE TABLE',
'user_defined_type_catalog': None,
'user_defined_type_name': None,
'user_defined_type_schema': None,
})
columns_data = self.get_columns_data(field.relation)
self.assertEqual(columns_data, {
field.column1: {
'character_maximum_length': None,
'column_default': None,
'column_name': u'discussion',
'data_type': u'integer',
'datetime_precision': None,
'is_nullable': u'NO',
'is_updatable': u'YES',
'numeric_precision': 32,
'numeric_precision_radix': 2,
'numeric_scale': 0,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_discussion_category',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'int4',
'udt_schema': u'pg_catalog',
},
field.column2: {
'character_maximum_length': None,
'column_default': None,
'column_name': u'category',
'data_type': u'integer',
'datetime_precision': None,
'is_nullable': u'NO',
'is_updatable': u'YES',
'numeric_precision': 32,
'numeric_precision_radix': 2,
'numeric_scale': 0,
'table_catalog': self.cr.dbname,
'table_name': u'test_new_api_discussion_category',
'table_schema': u'public',
'udt_catalog': self.cr.dbname,
'udt_name': u'int4',
'udt_schema': u'pg_catalog'
},
})
foreign_keys = self.get_foreign_keys(field.relation)
self.assertItemsEqual(foreign_keys, [
(field.relation, field.column1, model._table, 'id', 'CASCADE'),
(field.relation, field.column2, comodel._table, 'id', 'CASCADE'),
])