[ADD] test_performance: check the performance of CRUD operations

This commit is contained in:
Raphael Collet
2017-09-06 16:05:10 +02:00
parent 68fb4b95b4
commit 81192d66d9
8 changed files with 291 additions and 0 deletions
+3
View File
@@ -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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_test_performance_base access_test_performance_base model_test_performance_base 1 1 1 1
3 access_test_performance_line access_test_performance_line model_test_performance_line 1 1 1 1
4 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'})