1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
24 from tools.translate import _
25 from osv import osv, fields
28 class abstract_quality_check(object):
30 This Class is abstract class for all test
35 this method should initialize the variables
37 #This float have to store the rating of the module.
38 #Used to compute the final score (average of all scores).
42 #This char have to store the name of the test.
45 #This char have to store the aim of the test and eventually a note.
48 #This char have to store the result.
49 #Used to display the result of the test.
52 #This char have to store the result with more details.
53 #Used to provide more details if necessary.
54 self.result_details = ""
56 # This boolean variable defines that if you do not want to calculate score and just only need detail
57 # or summary report for some test then you will make it False.
58 self.bool_count_score = True
60 #This bool defines if the test can be run only if the module
62 #True => the module have to be installed.
63 #False => the module can be uninstalled.
64 self.bool_installed_only = True
66 #This variable is used to give result of test more weight,
67 #because some tests are more critical than others.
68 self.ponderation = 1.0
70 #Specify test got an error on module
73 #Specify the minimal score for the test (in percentage(%))
76 #Specify whether test should be consider for Quality checking of the module
79 #This variable used to give message if test result is good or not
81 self.log = logging.getLogger('module.quality')
83 #The tests have to subscribe itselfs in this list, that contains
84 #all the test that have to be performed.
86 module_path = addons.get_module_path('base_module_quality')
87 for item in os.listdir(module_path):
88 path = module_path + '/' + item
89 if os.path.isdir(path) and os.path.exists(path + '/' + item + '.py') and item not in ['report', 'wizard', 'security']:
90 item2 = 'base_module_quality.' + item +'.' + item
91 x_module = __import__(item2)
92 x_file = getattr(x_module, item)
93 x_obj = getattr(x_file, item)
94 self.tests.append(x_obj)
96 def run_test(self, cr, uid, module_path=""):
98 this method should do the test and fill the score, result and result_details var
100 raise osv.except_osv(_('Programming Error'), _('Test Is Not Implemented'))
102 def get_objects(self, cr, uid, module):
103 # This function returns all object of the given module..
104 pool = pooler.get_pool(cr.dbname)
105 ids2 = pool.get('ir.model.data').search(cr, uid,
106 [('module', '=', module), ('model', '=', 'ir.model')])
108 model_data = pool.get('ir.model.data').browse(cr, uid, ids2)
109 for model in model_data:
110 model_list.append(model.res_id)
111 self.log.debug('get_objects() model_list: %s', ','.join(map(str, model_list)))
113 for mod in pool.get('ir.model').browse(cr, uid, model_list):
114 obj_list.append(str(mod.model))
115 self.log.debug('get_objects() obj_list: %s', ','.join(obj_list))
118 def get_model_ids(self, cr, uid, models=[]):
119 # This function returns all ids of the given objects..
122 pool = pooler.get_pool(cr.dbname)
123 self.log.debug('get_model_ids([%s])', ', '.join(models))
124 return pool.get('ir.model').search(cr, uid, [('model', 'in', models)])
126 def get_ids(self, cr, uid, object_list):
127 #This method return dictionary with ids of records of object for module
128 pool = pooler.get_pool(cr.dbname)
130 for obj in object_list:
131 ids = pool.get(obj).search(cr, uid, [])
132 ids = filter(lambda id: id != None, ids or [])
133 result_ids[obj] = ids
136 def format_table(self, header=[], data_list={}): #This function can work forwidget="text_wiki"
138 detail += (header[0]) % tuple(header[1])
142 for key, value in data_list.items():
143 detail += (frow) % tuple(value)
144 detail = detail + '\n|}'
147 def format_html_table(self, header=[], data_list=[]): #This function can work for widget="html_tag"
148 # function create html table....
150 detail += (header[0]) % tuple(header[1])
153 frow += '<td>%s</td>'
155 for key, value in data_list.items():
156 detail += (frow) % tuple(value)
159 def add_quatation(self, x_no, y_no):
163 # This function return style tag with specified styles for html pages
167 border:1px solid #aaaaaa;
168 background-color:#f9f9f9;
173 border:1px dashed gray;
177 border:0.5px solid gray;
186 padding-bottom: .17em;
187 border-bottom: 1px solid #aaa;
194 class module_quality_check(osv.osv):
195 _name = 'module.quality.check'
197 'name': fields.char('Rated Module', size=64, ),
198 'final_score': fields.char('Final Score (%)', size=10,),
199 'check_detail_ids': fields.one2many('module.quality.detail', 'quality_check_id', 'Tests',)
202 def check_quality(self, cr, uid, module_name, module_state=None):
204 This function will calculate score of openerp module
205 It will return data in below format:
206 Format: {'final_score':'80.50', 'name': 'sale',
208 [(0,0,{'name':'workflow_test', 'score':'100', 'ponderation':'0', 'summary': text_wiki format data, 'detail': html format data, 'state':'done', 'note':'XXXX'}),
209 ((0,0,{'name':'terp_test', 'score':'60', 'ponderation':'1', 'summary': text_wiki format data, 'detail': html format data, 'state':'done', 'note':'terp desctioption'}),
211 So here the detail result is in html format and summary will be in text_wiki format.
213 pool = pooler.get_pool(cr.dbname)
214 log = logging.getLogger('module.quality')
215 obj_module = pool.get('ir.module.module')
217 module_id = obj_module.search(cr, uid, [('name', '=', module_name)])
219 module_state = obj_module.browse(cr, uid, module_id[0]).state
221 abstract_obj = abstract_quality_check()
223 ponderation_sum = 0.0
225 module_path = addons.get_module_path(module_name)
226 log.info('Performing quality tests for %s', module_name)
227 for test in abstract_obj.tests:
228 val = test.quality_test()
230 log.info('Skipping inactive step %s for %s', val.name, module_name)
233 log.info('Performing step %s for %s', val.name, module_name)
234 # Get a separate cursor per test, so that an SQL error in one
235 # will not block the others.
236 cr2 = pooler.get_db(cr.dbname).cursor()
239 if not val.bool_installed_only or module_state == "installed":
240 val.run_test(cr2, uid, str(module_path))
244 'score': val.score * 100,
245 'ponderation': val.ponderation,
246 'summary': val.result,
247 'detail': val.result_details,
250 'message': val.message
252 if val.bool_count_score:
253 score_sum += val.score * val.ponderation
254 ponderation_sum += val.ponderation
259 'summary': val.result,
269 'summary': _("The module has to be installed before running this test.")
271 create_ids.append((0, 0, data))
272 log.info('Finished quality test step')
274 log.exception("Could not finish test step %s due to %s", val.name, e)
278 final_score = ponderation_sum and '%.2f' % (score_sum / ponderation_sum * 100) or 0
281 'final_score': final_score,
282 'check_detail_ids' : create_ids,
286 module_quality_check()
288 class module_quality_detail(osv.osv):
289 _name = 'module.quality.detail'
291 'quality_check_id': fields.many2one('module.quality.check', 'Quality'),
292 'name': fields.char('Name',size=128),
293 'score': fields.float('Score (%)'),
294 'ponderation': fields.float('Ponderation', help='Some tests are more critical than others, so they have a bigger weight in the computation of final rating'),
295 'note': fields.text('Note'),
296 'summary': fields.text('Summary'),
297 'detail': fields.text('Details'),
298 'message': fields.char('Message', size=64),
299 'state': fields.selection([('done','Done'),('skipped','Skipped'),], 'State', size=24, help='The test will be completed only if the module is installed or if the test may be processed on uninstalled module.'),
302 module_quality_detail()
304 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: