[ADD] test_performance: check the performance of CRUD operations
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
@@ -0,0 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
{
|
||||
'name': "Test Performance",
|
||||
'version': "1.0",
|
||||
'category': "Hidden",
|
||||
'depends': ['base', 'mail'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
'demo': [
|
||||
'demo/demo.xml',
|
||||
],
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="object0" model="test_performance.base">
|
||||
<field name="name">Object 0</field>
|
||||
<field name="value">0</field>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
</record>
|
||||
<record id="object1" model="test_performance.base">
|
||||
<field name="name">Object 1</field>
|
||||
<field name="value">10</field>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
</record>
|
||||
<record id="object2" model="test_performance.base">
|
||||
<field name="name">Object 2</field>
|
||||
<field name="value">20</field>
|
||||
<field name="partner_id" ref="base.res_partner_4"/>
|
||||
</record>
|
||||
<record id="object3" model="test_performance.base">
|
||||
<field name="name">Object 3</field>
|
||||
<field name="value">30</field>
|
||||
<field name="partner_id" ref="base.res_partner_10"/>
|
||||
</record>
|
||||
<record id="object4" model="test_performance.base">
|
||||
<field name="name">Object 4</field>
|
||||
<field name="value">40</field>
|
||||
<field name="partner_id" ref="base.res_partner_12"/>
|
||||
</record>
|
||||
|
||||
<record id="object5" model="test_performance.mail">
|
||||
<field name="name">Object 0</field>
|
||||
<field name="value">0</field>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
</record>
|
||||
<record id="object6" model="test_performance.mail">
|
||||
<field name="name">Object 1</field>
|
||||
<field name="value">10</field>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
</record>
|
||||
<record id="object7" model="test_performance.mail">
|
||||
<field name="name">Object 2</field>
|
||||
<field name="value">20</field>
|
||||
<field name="partner_id" ref="base.res_partner_4"/>
|
||||
</record>
|
||||
<record id="object8" model="test_performance.mail">
|
||||
<field name="name">Object 3</field>
|
||||
<field name="value">30</field>
|
||||
<field name="partner_id" ref="base.res_partner_10"/>
|
||||
</record>
|
||||
<record id="object9" model="test_performance.mail">
|
||||
<field name="name">Object 4</field>
|
||||
<field name="value">40</field>
|
||||
<field name="partner_id" ref="base.res_partner_12"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import models
|
||||
@@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class BaseModel(models.Model):
|
||||
_name = 'test_performance.base'
|
||||
|
||||
name = fields.Char()
|
||||
value = fields.Integer()
|
||||
value_pc = fields.Float(compute="_value_pc", store=True)
|
||||
partner_id = fields.Many2one('res.partner', string='Customer')
|
||||
|
||||
line_ids = fields.One2many('test_performance.line', 'base_id')
|
||||
total = fields.Integer(compute="_total", store=True)
|
||||
|
||||
@api.depends('value')
|
||||
def _value_pc(self):
|
||||
for record in self:
|
||||
record.value_pc = float(record.value) / 100
|
||||
|
||||
@api.depends('line_ids.value')
|
||||
def _total(self):
|
||||
for record in self:
|
||||
record.total = sum(line.value for line in record.line_ids)
|
||||
|
||||
|
||||
class LineModel(models.Model):
|
||||
_name = 'test_performance.line'
|
||||
|
||||
base_id = fields.Many2one('test_performance.base', required=True, ondelete='cascade')
|
||||
value = fields.Integer()
|
||||
|
||||
|
||||
class MailModel(models.Model):
|
||||
_name = 'test_performance.mail'
|
||||
_inherit = 'mail.thread'
|
||||
|
||||
name = fields.Char()
|
||||
value = fields.Integer()
|
||||
value_pc = fields.Float(compute="_value_pc", store=True)
|
||||
track = fields.Char(default='test', track_visibility="onchange")
|
||||
partner_id = fields.Many2one('res.partner', string='Customer')
|
||||
|
||||
@api.depends('value')
|
||||
def _value_pc(self):
|
||||
for record in self:
|
||||
record.value_pc = float(record.value) / 100
|
||||
@@ -0,0 +1,4 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_test_performance_base,access_test_performance_base,model_test_performance_base,,1,1,1,1
|
||||
access_test_performance_line,access_test_performance_line,model_test_performance_line,,1,1,1,1
|
||||
access_test_performance_mail,access_test_performance_mail,model_test_performance_mail,,1,1,1,1
|
||||
|
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import test_performance
|
||||
@@ -0,0 +1,161 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from contextlib import contextmanager
|
||||
import logging
|
||||
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
sql_logger = logging.getLogger('odoo.sql_db')
|
||||
|
||||
|
||||
class TestPerformance(TransactionCase):
|
||||
@contextmanager
|
||||
def assertMaxQueries(self, message, count):
|
||||
""" Check the number of queries made in this scope. """
|
||||
count0 = self.cr.sql_log_count
|
||||
yield
|
||||
count1 = self.cr.sql_log_count
|
||||
self.assertLessEqual(count1 - count0, count, message)
|
||||
|
||||
@contextmanager
|
||||
def logQueries(self):
|
||||
""" Log the queries that are made in this scope. """
|
||||
sql_log, level = self.cr.sql_log, sql_logger.getEffectiveLevel()
|
||||
try:
|
||||
sql_logger.setLevel(logging.DEBUG)
|
||||
self.cr.sql_log = True
|
||||
yield
|
||||
finally:
|
||||
self.cr.sql_log = sql_log
|
||||
sql_logger.setLevel(level)
|
||||
|
||||
def test_read_base(self):
|
||||
""" Check reading records. """
|
||||
records = self.env['test_performance.base'].search([])
|
||||
self.assertEqual(len(records), 5)
|
||||
|
||||
# without cache
|
||||
with self.assertMaxQueries("Prefetch records", 3):
|
||||
for record in records:
|
||||
record.partner_id.country_id.name
|
||||
|
||||
# with cache
|
||||
with self.assertMaxQueries("Read prefetched records", 0):
|
||||
for record in records:
|
||||
record.partner_id.country_id.name
|
||||
|
||||
# value_pc must have been prefetched, too
|
||||
with self.assertMaxQueries("Read another field on prefetched records", 0):
|
||||
for record in records:
|
||||
record.value_pc
|
||||
|
||||
def test_read_mail(self):
|
||||
""" Check reading records inheriting from 'mail.thread'. """
|
||||
records = self.env['test_performance.mail'].search([])
|
||||
self.assertEqual(len(records), 5)
|
||||
|
||||
# without cache
|
||||
with self.assertMaxQueries("Prefetch records", 3):
|
||||
for record in records:
|
||||
record.partner_id.country_id.name
|
||||
|
||||
# with cache
|
||||
with self.assertMaxQueries("Read prefetched records", 0):
|
||||
for record in records:
|
||||
record.partner_id.country_id.name
|
||||
|
||||
# value_pc must have been prefetched, too
|
||||
with self.assertMaxQueries("Read another field on prefetched records", 0):
|
||||
for record in records:
|
||||
record.value_pc
|
||||
|
||||
def test_write_base(self):
|
||||
""" Check writing records. """
|
||||
records = self.env['test_performance.base'].search([])
|
||||
self.assertEqual(len(records), 5)
|
||||
|
||||
# warm up the caches
|
||||
records.write({'name': 'Start', 'value': 10})
|
||||
|
||||
# write in batch, without recomputation
|
||||
with self.assertMaxQueries("Write in batch, no recomputation", 1):
|
||||
records.write({'name': 'X'})
|
||||
|
||||
# write one by one, without recomputation
|
||||
with self.assertMaxQueries("Write one by one, no recomputation", 5):
|
||||
for record in records:
|
||||
record.name = 'Y'
|
||||
|
||||
# write in batch, with recomputation
|
||||
with self.assertMaxQueries("Write in batch, with recomputation", 3):
|
||||
records.write({'value': 20})
|
||||
|
||||
# write one by one, with recomputation
|
||||
with self.assertMaxQueries("Write one by one, with recomputation", 15):
|
||||
for record in records:
|
||||
record.value = 30
|
||||
|
||||
def test_write_mail(self):
|
||||
""" Check writing records inheriting from 'mail.thread'. """
|
||||
records = self.env['test_performance.mail'].search([])
|
||||
self.assertEqual(len(records), 5)
|
||||
|
||||
# warm up the caches
|
||||
records.write({'value': 0})
|
||||
records.write({'name': '0'})
|
||||
|
||||
# write in batch, without recomputation
|
||||
with self.assertMaxQueries("Write in batch, no recomputation", 3):
|
||||
records.write({'name': 'X'})
|
||||
|
||||
# write one by one, without recomputation
|
||||
with self.assertMaxQueries("Write one by one, no recomputation", 15):
|
||||
for record in records:
|
||||
record.name = 'Y'
|
||||
|
||||
# write in batch, with recomputation
|
||||
with self.assertMaxQueries("Write in batch, with recomputation", 5):
|
||||
records.write({'value': 20})
|
||||
|
||||
# write one by one, with recomputation
|
||||
with self.assertMaxQueries("Write one by one, with recomputation", 25):
|
||||
for record in records:
|
||||
record.value = 30
|
||||
|
||||
# write on a tracked field
|
||||
with self.assertMaxQueries("Write on a tracked field", 49):
|
||||
records[0].track = 'X'
|
||||
|
||||
def test_create_base(self):
|
||||
""" Check creating records. """
|
||||
model = self.env['test_performance.base']
|
||||
|
||||
# warm up caches
|
||||
model.create({'name': 'X'})
|
||||
|
||||
# create record without lines
|
||||
with self.assertMaxQueries("Create record without lines", 6):
|
||||
model.create({'name': 'X'})
|
||||
|
||||
# create record with lines
|
||||
with self.assertMaxQueries("Create record with lines", 39):
|
||||
model.create({
|
||||
'name': 'X',
|
||||
'line_ids': [(0, 0, {'value': val}) for val in range(10)],
|
||||
})
|
||||
|
||||
def test_create_mail(self):
|
||||
""" Check creating records inheriting from 'mail.thread'. """
|
||||
model = self.env['test_performance.mail']
|
||||
|
||||
# warm up caches
|
||||
model.create({'name': 'X'})
|
||||
|
||||
# create without tracking changes
|
||||
with self.assertMaxQueries("Create record without tracking fields", 3):
|
||||
model.with_context(tracking_disable=True).create({'name': 'X'})
|
||||
|
||||
# create with tracking changes
|
||||
with self.assertMaxQueries("Create record with tracking fields", 88):
|
||||
model.create({'name': 'X'})
|
||||
Reference in New Issue
Block a user