Files
odoo_source/addons/base_module_quality/speed_test/speed_test.py
T
P. Christeas 49f8d24d4a [FIX]module_quality: trivial logging, multi-addons paths, Fix exceptions, use separate db cursors.
Log some of the exceptions that occur, so that we can understand why our
tests fail.
Run each test on its own cursor, don't let SQL errors render the whole

bzr revid: hmo@tinyerp.com-20100907095055-9sa11rnvir8y7npw
2010-09-07 15:20:55 +05:30

159 lines
6.8 KiB
Python

# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from tools.translate import _
import pooler
from base_module_quality import base_module_quality
class CounterCursor(object):
def __init__(self, real_cursor):
self.cr = real_cursor
self.count = 0
def reset(self):
self.count = 0
def execute(self, query, *args, **kwargs):
if query.lower().startswith('select '):
self.count += 1
return self.cr.execute(query, *args, **kwargs)
def __getattr__(self, attr):
return getattr(self.cr, attr)
class quality_test(base_module_quality.abstract_quality_check):
def __init__(self):
super(quality_test, self).__init__()
self.bool_installed_only = True
self.name = _("Speed Test")
self.note = _("""
This test checks the speed of the module. Note that at least 5 demo data is needed in order to run it.
""")
self.min_score = 30
return None
def run_test(self, cr, uid, module_path):
pool = pooler.get_pool(cr.dbname)
module_name = module_path.split('/')[-1]
obj_list = self.get_objects(cr, uid, module_name)
# remove osv_memory class becaz it does not have demo data
if obj_list:
cr.execute("select w.res_model from ir_actions_todo as t left join ir_act_window as w on t.action_id=w.id where w.res_model IN %s",(tuple(obj_list),))
res = cr.fetchall()
for remove_obj in res:
if remove_obj and (remove_obj[0] in obj_list):
obj_list.remove(remove_obj[0])
result_dict2 = {}
if not obj_list:
self.error = True
self.result += _("Given module has no objects.Speed test can work only when new objects are created in the module along with demo data")
return None
obj_counter = 0
score = 0.0
try:
obj_ids = self.get_ids(cr, uid, obj_list)
except Exception,e:
self.log.warning("Cannot get ids:", exc_info=True)
obj_ids= {}
self.result_details += e.message
result_dict = {}
result_dict2 = {}
self.result_details += _("<html>O(1) means that the number of SQL requests to read the object does not depand on the number of objects we are reading. This feature is mostly wished.\n</html>")
ccr = CounterCursor(cr)
for obj, ids in obj_ids.items():
code_base_complexity = 0
code_half_complexity = 0
code_size_complexity = 0
obj_counter += 1
ids = ids[:100]
size = len(ids)
list2 = []
if size:
speed_list = []
try:
# perform the operation once to put data in cache
pool.get(obj).read(cr, uid, ids)
ccr.reset()
pool.get(obj).read(ccr, uid, [ids[0]])
code_base_complexity = ccr.count
ccr.reset()
pool.get(obj).read(ccr, uid, ids[:size/2])
code_half_complexity = ccr.count
ccr.reset()
pool.get(obj).read(ccr, uid, ids)
code_size_complexity = ccr.count
except Exception, e:
self.log.warning('Error in read method', exc_info=True)
list2 = [obj, _("Error in Read method")]
speed_list = [obj, size, code_base_complexity, code_half_complexity, code_size_complexity, _("Error in Read method:" + str(e))]
else:
if size < 5:
speed_list = [obj, size, code_base_complexity, code_half_complexity, code_size_complexity, _("Warning! Not enough demo data")]
list2 = [obj, _("No enough data")]
else:
if code_size_complexity <= (code_base_complexity + size):
complexity = _("O(1)")
score += 1
list2 = [obj, _("Efficient")]
else:
complexity = _("O(n) or worst")
list2 = [obj, _("Not Efficient")]
speed_list = [obj, size, code_base_complexity, code_half_complexity, code_size_complexity, complexity]
else:
speed_list = [obj, size, "", "", "", _("Warning! Object has no demo data")]
list2 = [obj, _("No data")]
result_dict[obj] = speed_list
result_dict2[obj] = list2
self.score = obj_counter and score / obj_counter or 0.0
if self.score*100 < self.min_score:
self.message = _('Score is below than minimal score(%s%%)') % self.min_score
self.result_details += self.get_result_details(result_dict)
self.result += self.get_result(result_dict2)
return None
def get_result(self, dict_speed):
header = ('{| border="1" cellspacing="0" cellpadding="5" align="left" \n! %-40s \n! %-10s', [_('Object Name'), _('Result')])
if not self.error:
return self.format_table(header, data_list=dict_speed)
return ""
def get_result_details(self, dict_speed):
str_html = '''<html><head>%s</head><body><table class="tablestyle">'''%(self.get_style())
header = ('<tr><th class="tdatastyle" >%s</th><th class="tdatastyle">%s</th><th class="tdatastyle">%s</th><th class="tdatastyle">%s</th><th class="tdatastyle">%s</th><th class="tdatastyle">%s</th></tr>', [_('Object Name'), _('N (Number of Records)'), _('1'), _('N/2'), _('N'), _('Reading Complexity')])
if not self.error:
res = str_html + self.format_html_table(header, data_list=dict_speed) + '</table></body></html>'
res = res.replace('''<td''', '''<td class="tdatastyle" ''')
return res
return ""
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: