Files
tryton/trytond/tests/test_modelstorage.py
T
Cédric Krier 340cb2f630 Loop over all expression of the relation domain to valid
When the field is a relation, the field name can not be used to inverse the
domain because the record evaluated it the Relation. So we inverse the domain
with all the field in the domain until find one invalid. If we find any then we
raise a generic error.

issue8597
review270141002
2019-08-28 22:31:22 +02:00

450 lines
16 KiB
Python

# This file is part of Tryton. The COPYRIGHT file at the top level of this
# repository contains the full copyright notices and license terms.
import unittest
from trytond.model.exceptions import (
RequiredValidationError, DomainValidationError)
from trytond.pool import Pool
from trytond.transaction import Transaction
from trytond.tests.test_tryton import activate_module, with_transaction
class ModelStorageTestCase(unittest.TestCase):
'Test ModelStorage'
@classmethod
def setUpClass(cls):
activate_module('tests')
@with_transaction()
def test_search_read_order(self):
'Test search_read order'
pool = Pool()
ModelStorage = pool.get('test.modelstorage')
ModelStorage.create([{'name': i} for i in ['foo', 'bar', 'test']])
rows = ModelStorage.search_read([])
self.assertTrue(
all(x['id'] < y['id'] for x, y in zip(rows, rows[1:])))
rows = ModelStorage.search_read([], order=[('name', 'ASC')])
self.assertTrue(
all(x['name'] <= y['name'] for x, y in zip(rows, rows[1:])))
rows = ModelStorage.search_read([], order=[('name', 'DESC')])
self.assertTrue(
all(x['name'] >= y['name'] for x, y in zip(rows, rows[1:])))
@with_transaction()
def test_copy_order(self):
"Test copy order"
pool = Pool()
ModelStorage = pool.get('test.modelstorage')
# Use both order to avoid false positive by chance
records = ModelStorage.create(
[{'name': n} for n in ['foo', 'bar', 'test']])
new_records = ModelStorage.copy(records)
reversed_records = list(reversed(records))
new_reversed_records = ModelStorage.copy(reversed_records)
self.assertListEqual(
[r.name for r in records],
[r.name for r in new_records])
self.assertListEqual(
[r.name for r in reversed_records],
[r.name for r in new_reversed_records])
@with_transaction()
def test_search_count(self):
"Test search_count"
pool = Pool()
ModelStorage = pool.get('test.modelstorage')
ModelStorage.create([{'name': 'Test %s' % i} for i in range(10)])
count = ModelStorage.search_count([])
self.assertEqual(count, 10)
count = ModelStorage.search_count([('name', '=', 'Test 5')])
self.assertEqual(count, 1)
@with_transaction()
def test_browse_context(self):
'Test context when browsing'
pool = Pool()
ModelStorageContext = pool.get('test.modelstorage.context')
record, = ModelStorageContext.create([{}])
record_context = {'_check_access': False} # From Function.get
self.assertDictEqual(record.context, record_context)
# Clean the instance cache
record = ModelStorageContext(record.id)
with Transaction().set_context(foo='bar'):
self.assertDictEqual(record.context, record_context)
record = ModelStorageContext(record.id)
self.assertEqual(record.context.get('foo'), 'bar')
@with_transaction()
def test_save_mixed_context(self):
'Test save with mixed context '
pool = Pool()
ModelStorage = pool.get('test.modelstorage.required')
foo = ModelStorage(name='foo')
with Transaction().set_context(bar=True):
bar = ModelStorage(name='bar')
ModelStorage.save([foo, bar])
self.assertNotEqual(foo._context, bar._context)
@with_transaction()
def test_fail_saving_mixed_context1(self):
'Test fail saving with mixed context '
pool = Pool()
ModelStorage = pool.get('test.modelstorage.required')
foo = ModelStorage(name='foo')
with Transaction().set_context(bar=True):
bar = ModelStorage(name='bar')
ModelStorage.save([foo, bar])
foo.name = None
with self.assertRaises(RequiredValidationError):
ModelStorage.save([foo, bar])
self.assertIsNone(foo.name)
self.assertEqual(bar.name, 'bar')
@with_transaction()
def test_fail_saving_mixed_context2(self):
'Test fail saving with mixed context '
pool = Pool()
ModelStorage = pool.get('test.modelstorage.required')
foo = ModelStorage(name='foo')
with Transaction().set_context(bar=True):
bar = ModelStorage(name='bar')
ModelStorage.save([foo, bar])
bar.name = None
foo.name = 'foo'
with self.assertRaises(RequiredValidationError):
ModelStorage.save([foo, bar])
self.assertEqual(foo.name, 'foo')
self.assertIsNone(bar.name)
@with_transaction(context={'_check_access': True})
def test_model_translations(self):
'Test any user can translate fields and duplicate its records'
pool = Pool()
Transalatable = pool.get('test.char_translate')
Lang = pool.get('ir.lang')
User = pool.get('res.user')
lang, = Lang.search([
('translatable', '=', False),
('code', '!=', 'en'),
], limit=1)
lang.translatable = True
lang.save()
user = User(login='test')
user.save()
with Transaction().set_user(user.id):
record = Transalatable(char='foo')
record.save()
with Transaction().set_context(lang=lang.code):
record = Transalatable(record.id)
record.char = 'bar'
record.save()
# Test we can copy and translations are copied
copied_record, = Transalatable.copy([record])
copied_record = Transalatable(copied_record.id)
self.assertEqual(copied_record.char, 'bar')
@with_transaction()
def test_pyson_domain_same(self):
"Test same pyson domain validation"
pool = Pool()
Model = pool.get('test.modelstorage.pyson_domain')
Model.create([{'constraint': 'foo', 'value': 'foo'}] * 10)
with self.assertRaises(DomainValidationError) as cm:
Model.create([{'constraint': 'foo', 'value': 'bar'}] * 10)
self.assertEqual(cm.exception.domain[0], [['value', '=', 'foo']])
self.assertTrue(cm.exception.domain[1]['value'])
@with_transaction()
def test_pyson_domain_unique(self):
"Test unique pyson domain validation"
pool = Pool()
Model = pool.get('test.modelstorage.pyson_domain')
Model.create(
[{'constraint': str(i), 'value': str(i)} for i in range(10)])
with self.assertRaises(DomainValidationError) as cm:
Model.create(
[{'constraint': str(i), 'value': str(i + 1)}
for i in range(10)])
self.assertTrue(cm.exception.domain[0])
self.assertTrue(cm.exception.domain[1]['value'])
@with_transaction()
def test_pyson_domain_unique_in_max(self):
"Test unique pyson domain validation with greater IN_MAX"
pool = Pool()
Model = pool.get('test.modelstorage.pyson_domain')
in_max = Transaction().database.IN_MAX
self.addCleanup(setattr, Transaction().database, 'IN_MAX', in_max)
Transaction().database.IN_MAX = 1
# Use modulo 6 so len(domains) is greater then len(records) * 0.5
# and more than 1 (IN_MAX) have the same domain
Model.create(
[{'constraint': str(i % 6), 'value': str(i % 6)}
for i in range(10)])
with self.assertRaises(DomainValidationError) as cm:
Model.create(
[{'constraint': str(i % 6), 'value': str(i)}
for i in range(10)])
self.assertTrue(cm.exception.domain[0])
self.assertTrue(cm.exception.domain[1]['value'])
@with_transaction()
def test_pyson_domain_single(self):
"Test pyson domain validation for 1 record"
pool = Pool()
Model = pool.get('test.modelstorage.pyson_domain')
Model.create([{'constraint': 'foo', 'value': 'foo'}])
with self.assertRaises(DomainValidationError) as cm:
Model.create([{'constraint': 'foo', 'value': 'bar'}])
self.assertEqual(cm.exception.domain[0], [['value', '=', 'foo']])
self.assertTrue(cm.exception.domain[1]['value'])
@with_transaction()
def test_relation_domain(self):
"Test valid relation domain"
pool = Pool()
Model = pool.get('test.modelstorage.relation_domain')
Target = pool.get('test.modelstorage.relation_domain.target')
target, = Target.create([{'value': 'valid'}])
record, = Model.create([{'relation': target.id}])
@with_transaction()
def test_relation_domain_invalid(self):
"Test invalid relation domain"
pool = Pool()
Model = pool.get('test.modelstorage.relation_domain')
Target = pool.get('test.modelstorage.relation_domain.target')
target, = Target.create([{'value': 'invalid'}])
with self.assertRaises(DomainValidationError) as cm:
Model.create([{'relation': target.id}])
self.assertEqual(cm.exception.domain[0], [('value', '=', 'valid')])
self.assertTrue(cm.exception.domain[1]['value'])
@with_transaction()
def test_relation2_domain_invalid(self):
"Test invalid relation domain with 2 level"
pool = Pool()
Model = pool.get('test.modelstorage.relation_domain2')
Target2 = pool.get('test.modelstorage.relation_domain2.target')
Target = pool.get('test.modelstorage.relation_domain.target')
target, = Target.create([{'value': 'invalid'}])
target2, = Target2.create([{'relation2': target.id}])
with self.assertRaises(DomainValidationError) as cm:
Model.create([{'relation': target2.id}])
self.assertEqual(
cm.exception.domain[0], [('relation2.value', '=', 'valid')])
self.assertTrue(cm.exception.domain[1]['relation2'])
self.assertTrue(
cm.exception.domain[1]['relation2']['relation_fields']['value'])
@with_transaction()
def test_check_xml_record_without_record(self):
"Test check_xml_record without record"
pool = Pool()
Model = pool.get('test.modelstorage')
record, = Model.create([{}])
result = Model.check_xml_record([record], {'name': "Test"})
self.assertTrue(result)
@with_transaction()
def test_check_xml_record_with_record_no_matching_values(self):
"Test check_xml_record with record and no matching values"
pool = Pool()
Model = pool.get('test.modelstorage')
ModelData = pool.get('ir.model.data')
record, = Model.create([{}])
ModelData.create([{
'fs_id': 'test',
'model': 'test.modelstorage',
'module': 'tests',
'db_id': record.id,
'values': ModelData.dump_values({}),
'noupdate': False,
}])
result = Model.check_xml_record([record], {'name': "Test"})
self.assertTrue(result)
@with_transaction()
def test_check_xml_record_with_record_matching_values(self):
"Test check_xml_record with record and matching values"
pool = Pool()
Model = pool.get('test.modelstorage')
ModelData = pool.get('ir.model.data')
record, = Model.create([{'name': "Foo"}])
ModelData.create([{
'fs_id': 'test',
'model': 'test.modelstorage',
'module': 'tests',
'db_id': record.id,
'values': ModelData.dump_values({'name': "Foo"}),
'noupdate': False,
}])
result = Model.check_xml_record([record], {'name': "Bar"})
self.assertFalse(result)
@with_transaction()
def test_check_xml_record_with_record_matching_values_noupdate(self):
"Test check_xml_record with record and matching values but noupdate"
pool = Pool()
Model = pool.get('test.modelstorage')
ModelData = pool.get('ir.model.data')
record, = Model.create([{'name': "Foo"}])
ModelData.create([{
'fs_id': 'test',
'model': 'test.modelstorage',
'module': 'tests',
'db_id': record.id,
'values': ModelData.dump_values({'name': "Foo"}),
'noupdate': True,
}])
result = Model.check_xml_record([record], {'name': "Bar"})
self.assertTrue(result)
@with_transaction(user=0)
def test_check_xml_record_with_record_matching_values_root(self):
"Test check_xml_record with record with matching values as root"
pool = Pool()
Model = pool.get('test.modelstorage')
ModelData = pool.get('ir.model.data')
record, = Model.create([{'name': "Foo"}])
ModelData.create([{
'fs_id': 'test',
'model': 'test.modelstorage',
'module': 'tests',
'db_id': record.id,
'values': ModelData.dump_values({'name': "Foo"}),
'noupdate': False,
}])
result = Model.check_xml_record([record], {'name': "Bar"})
self.assertTrue(result)
@with_transaction()
def test_check_xml_record_with_record_no_values(self):
"Test check_xml_record with record and no values"
pool = Pool()
Model = pool.get('test.modelstorage')
ModelData = pool.get('ir.model.data')
record, = Model.create([{'name': "Foo"}])
ModelData.create([{
'fs_id': 'test',
'model': 'test.modelstorage',
'module': 'tests',
'db_id': record.id,
'values': None,
'noupdate': False,
}])
result = Model.check_xml_record([record], None)
self.assertFalse(result)
@with_transaction()
def test_check_xml_record_with_record_no_values_noupdate(self):
"Test check_xml_record with record and no values but noupdate"
pool = Pool()
Model = pool.get('test.modelstorage')
ModelData = pool.get('ir.model.data')
record, = Model.create([{'name': "Foo"}])
ModelData.create([{
'fs_id': 'test',
'model': 'test.modelstorage',
'module': 'tests',
'db_id': record.id,
'values': None,
'noupdate': True,
}])
result = Model.check_xml_record([record], None)
self.assertTrue(result)
@with_transaction()
def test_delete_clear_db_id_model_data_noupdate(self):
"Test delete record clear DB id from model data"
pool = Pool()
Model = pool.get('test.modelstorage')
ModelData = pool.get('ir.model.data')
record, = Model.create([{'name': "Foo"}])
data, = ModelData.create([{
'fs_id': 'test',
'model': 'test.modelstorage',
'module': 'tests',
'db_id': record.id,
'values': None,
'noupdate': True,
}])
Model.delete([record])
self.assertIsNone(data.db_id)
@with_transaction(user=0)
def test_delete_model_data_without_noupdate(self):
"Test delete record from model data without noupdate"
pool = Pool()
Model = pool.get('test.modelstorage')
ModelData = pool.get('ir.model.data')
record, = Model.create([{'name': "Foo"}])
data, = ModelData.create([{
'fs_id': 'test',
'model': 'test.modelstorage',
'module': 'tests',
'db_id': record.id,
'values': None,
'noupdate': False,
}])
Model.delete([record])
def suite():
return unittest.TestLoader().loadTestsFromTestCase(ModelStorageTestCase)