diff options
Diffstat (limited to 'odoo/addons/base/tests/test_api.py')
| -rw-r--r-- | odoo/addons/base/tests/test_api.py | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/odoo/addons/base/tests/test_api.py b/odoo/addons/base/tests/test_api.py new file mode 100644 index 00000000000..99014af8ba6 --- /dev/null +++ b/odoo/addons/base/tests/test_api.py @@ -0,0 +1,488 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models +from odoo.tools import mute_logger +from odoo.tests import common +from odoo.exceptions import AccessError + + +class TestAPI(common.TransactionCase): + """ test the new API of the ORM """ + + def assertIsRecordset(self, value, model): + self.assertIsInstance(value, models.BaseModel) + self.assertEqual(value._name, model) + + def assertIsRecord(self, value, model): + self.assertIsRecordset(value, model) + self.assertTrue(len(value) <= 1) + + def assertIsNull(self, value, model): + self.assertIsRecordset(value, model) + self.assertFalse(value) + + @mute_logger('openerp.models') + def test_00_query(self): + """ Build a recordset, and check its contents. """ + domain = [('name', 'ilike', 'j')] + partners = self.env['res.partner'].search(domain) + + # partners is a collection of browse records + self.assertTrue(partners) + + # partners and its contents are instance of the model + self.assertIsRecordset(partners, 'res.partner') + for p in partners: + self.assertIsRecord(p, 'res.partner') + + @mute_logger('openerp.models') + def test_01_query_offset(self): + """ Build a recordset with offset, and check equivalence. """ + partners1 = self.env['res.partner'].search([], offset=10) + partners2 = self.env['res.partner'].search([])[10:] + self.assertIsRecordset(partners1, 'res.partner') + self.assertIsRecordset(partners2, 'res.partner') + self.assertEqual(list(partners1), list(partners2)) + + @mute_logger('openerp.models') + def test_02_query_limit(self): + """ Build a recordset with offset, and check equivalence. """ + partners1 = self.env['res.partner'].search([], limit=10) + partners2 = self.env['res.partner'].search([])[:10] + self.assertIsRecordset(partners1, 'res.partner') + self.assertIsRecordset(partners2, 'res.partner') + self.assertEqual(list(partners1), list(partners2)) + + @mute_logger('openerp.models') + def test_03_query_offset_limit(self): + """ Build a recordset with offset and limit, and check equivalence. """ + partners1 = self.env['res.partner'].search([], offset=3, limit=7) + partners2 = self.env['res.partner'].search([])[3:10] + self.assertIsRecordset(partners1, 'res.partner') + self.assertIsRecordset(partners2, 'res.partner') + self.assertEqual(list(partners1), list(partners2)) + + @mute_logger('openerp.models') + def test_04_query_count(self): + """ Test the search method with count=True. """ + self.cr.execute("SELECT COUNT(*) FROM res_partner WHERE active") + count1 = self.cr.fetchone()[0] + count2 = self.env['res.partner'].search([], count=True) + self.assertIsInstance(count1, (int, long)) + self.assertIsInstance(count2, (int, long)) + self.assertEqual(count1, count2) + + @mute_logger('openerp.models') + def test_05_immutable(self): + """ Check that a recordset remains the same, even after updates. """ + domain = [('name', 'ilike', 'j')] + partners = self.env['res.partner'].search(domain) + self.assertTrue(partners) + ids = map(int, partners) + + # modify those partners, and check that partners has not changed + partners.write({'active': False}) + self.assertEqual(ids, map(int, partners)) + + # redo the search, and check that the result is now empty + partners2 = self.env['res.partner'].search(domain) + self.assertFalse(partners2) + + @mute_logger('openerp.models') + def test_06_fields(self): + """ Check that relation fields return records, recordsets or nulls. """ + user = self.env.user + self.assertIsRecord(user, 'res.users') + self.assertIsRecord(user.partner_id, 'res.partner') + self.assertIsRecordset(user.groups_id, 'res.groups') + + partners = self.env['res.partner'].search([]) + for name, field in partners._fields.iteritems(): + if field.type == 'many2one': + for p in partners: + self.assertIsRecord(p[name], field.comodel_name) + elif field.type == 'reference': + for p in partners: + if p[name]: + self.assertIsRecord(p[name], field.comodel_name) + elif field.type in ('one2many', 'many2many'): + for p in partners: + self.assertIsRecordset(p[name], field.comodel_name) + + @mute_logger('openerp.models') + def test_07_null(self): + """ Check behavior of null instances. """ + # select a partner without a parent + partner = self.env['res.partner'].search([('parent_id', '=', False)])[0] + + # check partner and related null instances + self.assertTrue(partner) + self.assertIsRecord(partner, 'res.partner') + + self.assertFalse(partner.parent_id) + self.assertIsNull(partner.parent_id, 'res.partner') + + self.assertIs(partner.parent_id.id, False) + + self.assertFalse(partner.parent_id.user_id) + self.assertIsNull(partner.parent_id.user_id, 'res.users') + + self.assertIs(partner.parent_id.user_id.name, False) + + self.assertFalse(partner.parent_id.user_id.groups_id) + self.assertIsRecordset(partner.parent_id.user_id.groups_id, 'res.groups') + + @mute_logger('openerp.models') + def test_40_new_new(self): + """ Call new-style methods in the new API style. """ + partners = self.env['res.partner'].search([('name', 'ilike', 'j')]) + self.assertTrue(partners) + + # call method write on partners itself, and check its effect + partners.write({'active': False}) + for p in partners: + self.assertFalse(p.active) + + @mute_logger('openerp.models') + def test_45_new_new(self): + """ Call new-style methods on records (new API style). """ + partners = self.env['res.partner'].search([('name', 'ilike', 'j')]) + self.assertTrue(partners) + + # call method write on partner records, and check its effects + for p in partners: + p.write({'active': False}) + for p in partners: + self.assertFalse(p.active) + + @mute_logger('openerp.models') + @mute_logger('openerp.addons.base.ir.ir_model') + def test_50_environment(self): + """ Test environment on records. """ + # partners and reachable records are attached to self.env + partners = self.env['res.partner'].search([('name', 'ilike', 'j')]) + self.assertEqual(partners.env, self.env) + for x in (partners, partners[0], partners[0].company_id): + self.assertEqual(x.env, self.env) + for p in partners: + self.assertEqual(p.env, self.env) + + # check that the current user can read and modify company data + partners[0].company_id.name + partners[0].company_id.write({'name': 'Fools'}) + + # create an environment with the demo user + demo = self.env['res.users'].search([('login', '=', 'demo')])[0] + demo_env = self.env(user=demo) + self.assertNotEqual(demo_env, self.env) + + # partners and related records are still attached to self.env + self.assertEqual(partners.env, self.env) + for x in (partners, partners[0], partners[0].company_id): + self.assertEqual(x.env, self.env) + for p in partners: + self.assertEqual(p.env, self.env) + + # create record instances attached to demo_env + demo_partners = partners.sudo(demo) + self.assertEqual(demo_partners.env, demo_env) + for x in (demo_partners, demo_partners[0], demo_partners[0].company_id): + self.assertEqual(x.env, demo_env) + for p in demo_partners: + self.assertEqual(p.env, demo_env) + + # demo user can read but not modify company data + demo_partners[0].company_id.name + with self.assertRaises(AccessError): + demo_partners[0].company_id.write({'name': 'Pricks'}) + + # remove demo user from all groups + demo.write({'groups_id': [(5,)]}) + + # demo user can no longer access partner data + with self.assertRaises(AccessError): + demo_partners[0].company_id.name + + @mute_logger('openerp.models') + def test_55_draft(self): + """ Test draft mode nesting. """ + env = self.env + self.assertFalse(env.in_draft) + with env.do_in_draft(): + self.assertTrue(env.in_draft) + with env.do_in_draft(): + self.assertTrue(env.in_draft) + with env.do_in_draft(): + self.assertTrue(env.in_draft) + self.assertTrue(env.in_draft) + self.assertTrue(env.in_draft) + self.assertFalse(env.in_draft) + + @mute_logger('openerp.models') + def test_60_cache(self): + """ Check the record cache behavior """ + Partners = self.env['res.partner'] + pids = [] + data = { + 'partner One': ['Partner One - One', 'Partner One - Two'], + 'Partner Two': ['Partner Two - One'], + 'Partner Three': ['Partner Three - One'], + } + for p in data: + pids.append(Partners.create({ + 'name': p, + 'child_ids': [(0, 0, {'name': c}) for c in data[p]], + }).id) + + partners = Partners.search([('id', 'in', pids)]) + partner1, partner2 = partners[0], partners[1] + children1, children2 = partner1.child_ids, partner2.child_ids + self.assertTrue(children1) + self.assertTrue(children2) + + # take a child contact + child = children1[0] + self.assertEqual(child.parent_id, partner1) + self.assertIn(child, partner1.child_ids) + self.assertNotIn(child, partner2.child_ids) + + # fetch data in the cache + for p in partners: + p.name, p.company_id.name, p.user_id.name, p.contact_address + self.env.check_cache() + + # change its parent + child.write({'parent_id': partner2.id}) + self.env.check_cache() + + # check recordsets + self.assertEqual(child.parent_id, partner2) + self.assertNotIn(child, partner1.child_ids) + self.assertIn(child, partner2.child_ids) + self.assertEqual(set(partner1.child_ids + child), set(children1)) + self.assertEqual(set(partner2.child_ids), set(children2 + child)) + self.env.check_cache() + + # delete it + child.unlink() + self.env.check_cache() + + # check recordsets + self.assertEqual(set(partner1.child_ids), set(children1) - set([child])) + self.assertEqual(set(partner2.child_ids), set(children2)) + self.env.check_cache() + + @mute_logger('openerp.models') + def test_60_prefetch(self): + """ Check the record cache prefetching """ + partners = self.env['res.partner'].search([], limit=models.PREFETCH_MAX) + self.assertTrue(len(partners) > 1) + + # all the records in partners are ready for prefetching + self.assertItemsEqual(partners.ids, partners._prefetch['res.partner']) + + # reading ONE partner should fetch them ALL + partner = next(p for p in partners) + partner.country_id + country_id_cache = self.env.cache[type(partners).country_id] + self.assertItemsEqual(partners.ids, country_id_cache) + + # partners' countries are ready for prefetching + country_ids = set(cid for cids in country_id_cache.itervalues() for cid in cids) + self.assertTrue(len(country_ids) > 1) + self.assertItemsEqual(country_ids, partners._prefetch['res.country']) + + # reading ONE partner country should fetch ALL partners' countries + country = next(p.country_id for p in partners if p.country_id) + country.name + name_cache = self.env.cache[type(country).name] + self.assertItemsEqual(country_ids, name_cache) + + @mute_logger('openerp.models') + def test_60_prefetch_object(self): + """ Check the prefetching model. """ + partners = self.env['res.partner'].search([], limit=models.PREFETCH_MAX) + self.assertTrue(partners) + + def same_prefetch(a, b): + self.assertIs(a._prefetch, b._prefetch) + def diff_prefetch(a, b): + self.assertIsNot(a._prefetch, b._prefetch) + + # the recordset operations below should create new prefetch objects + diff_prefetch(partners, partners.browse()) + diff_prefetch(partners, partners.browse(partners.ids)) + diff_prefetch(partners, partners[0]) + diff_prefetch(partners, partners[:10]) + + # the recordset operations below should pass the prefetch object + same_prefetch(partners, partners.sudo(self.env.ref('base.user_demo'))) + same_prefetch(partners, partners.with_context(active_test=False)) + same_prefetch(partners, partners[:10].with_prefetch(partners._prefetch)) + + # iterating and reading relational fields should pass the prefetch object + self.assertEqual(type(partners).country_id.type, 'many2one') + self.assertEqual(type(partners).bank_ids.type, 'one2many') + self.assertEqual(type(partners).category_id.type, 'many2many') + + vals0 = { + 'name': 'Empty relational fields', + 'country_id': False, + 'bank_ids': [], + 'category_id': [], + } + vals1 = { + 'name': 'Non-empty relational fields', + 'country_id': self.ref('base.be'), + 'bank_ids': [(0, 0, {'acc_number': 'FOO42'})], + 'category_id': [(4, self.ref('base.res_partner_category_0'))], + } + partners = partners.create(vals0) + partners.create(vals1) + for partner in partners: + same_prefetch(partners, partner) + same_prefetch(partners, partner.country_id) + same_prefetch(partners, partner.bank_ids) + same_prefetch(partners, partner.category_id) + + # same with empty recordsets + empty = partners.browse() + same_prefetch(empty, empty.country_id) + same_prefetch(empty, empty.bank_ids) + same_prefetch(empty, empty.category_id) + + @mute_logger('openerp.models') + def test_70_one(self): + """ Check method one(). """ + # check with many records + ps = self.env['res.partner'].search([('name', 'ilike', 'a')]) + self.assertTrue(len(ps) > 1) + with self.assertRaises(ValueError): + ps.ensure_one() + + p1 = ps[0] + self.assertEqual(len(p1), 1) + self.assertEqual(p1.ensure_one(), p1) + + p0 = self.env['res.partner'].browse() + self.assertEqual(len(p0), 0) + with self.assertRaises(ValueError): + p0.ensure_one() + + @mute_logger('openerp.models') + def test_80_contains(self): + """ Test membership on recordset. """ + p1 = self.env['res.partner'].search([('name', 'ilike', 'a')], limit=1).ensure_one() + ps = self.env['res.partner'].search([('name', 'ilike', 'a')]) + self.assertTrue(p1 in ps) + + @mute_logger('openerp.models') + def test_80_set_operations(self): + """ Check set operations on recordsets. """ + pa = self.env['res.partner'].search([('name', 'ilike', 'a')]) + pb = self.env['res.partner'].search([('name', 'ilike', 'b')]) + self.assertTrue(pa) + self.assertTrue(pb) + self.assertTrue(set(pa) & set(pb)) + + concat = pa + pb + self.assertEqual(list(concat), list(pa) + list(pb)) + self.assertEqual(len(concat), len(pa) + len(pb)) + + difference = pa - pb + self.assertEqual(len(difference), len(set(difference))) + self.assertEqual(set(difference), set(pa) - set(pb)) + self.assertLessEqual(difference, pa) + + intersection = pa & pb + self.assertEqual(len(intersection), len(set(intersection))) + self.assertEqual(set(intersection), set(pa) & set(pb)) + self.assertLessEqual(intersection, pa) + self.assertLessEqual(intersection, pb) + + union = pa | pb + self.assertEqual(len(union), len(set(union))) + self.assertEqual(set(union), set(pa) | set(pb)) + self.assertGreaterEqual(union, pa) + self.assertGreaterEqual(union, pb) + + # one cannot mix different models with set operations + ps = pa + ms = self.env['ir.ui.menu'].search([]) + self.assertNotEqual(ps._name, ms._name) + self.assertNotEqual(ps, ms) + + with self.assertRaises(TypeError): + res = ps + ms + with self.assertRaises(TypeError): + res = ps - ms + with self.assertRaises(TypeError): + res = ps & ms + with self.assertRaises(TypeError): + res = ps | ms + with self.assertRaises(TypeError): + res = ps < ms + with self.assertRaises(TypeError): + res = ps <= ms + with self.assertRaises(TypeError): + res = ps > ms + with self.assertRaises(TypeError): + res = ps >= ms + + @mute_logger('openerp.models') + def test_80_filter(self): + """ Check filter on recordsets. """ + ps = self.env['res.partner'].search([]) + customers = ps.browse([p.id for p in ps if p.customer]) + + # filter on a single field + self.assertEqual(ps.filtered(lambda p: p.customer), customers) + self.assertEqual(ps.filtered('customer'), customers) + + # filter on a sequence of fields + self.assertEqual( + ps.filtered(lambda p: p.parent_id.customer), + ps.filtered('parent_id.customer') + ) + + @mute_logger('openerp.models') + def test_80_map(self): + """ Check map on recordsets. """ + ps = self.env['res.partner'].search([]) + parents = ps.browse() + for p in ps: parents |= p.parent_id + + # map a single field + self.assertEqual(ps.mapped(lambda p: p.parent_id), parents) + self.assertEqual(ps.mapped('parent_id'), parents) + + # map a sequence of fields + self.assertEqual( + ps.mapped(lambda p: p.parent_id.name), + [p.parent_id.name for p in ps] + ) + self.assertEqual( + ps.mapped('parent_id.name'), + [p.name for p in parents] + ) + + # map an empty sequence of fields + self.assertEqual(ps.mapped(''), ps) + + @mute_logger('openerp.models') + def test_80_sorted(self): + """ Check sorted on recordsets. """ + ps = self.env['res.partner'].search([]) + + # sort by model order + qs = ps[:len(ps) / 2] + ps[len(ps) / 2:] + self.assertEqual(qs.sorted().ids, ps.ids) + + # sort by name, with a function or a field name + by_name_ids = [p.id for p in sorted(ps, key=lambda p: p.name)] + self.assertEqual(ps.sorted(lambda p: p.name).ids, by_name_ids) + self.assertEqual(ps.sorted('name').ids, by_name_ids) + + # sort by inverse name, with a field name + by_name_ids.reverse() + self.assertEqual(ps.sorted('name', reverse=True).ids, by_name_ids) |
