From 70810383789e33dc388486e6d76fc4d05ccf95e4 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 12 Sep 2013 20:29:26 +0200 Subject: [PATCH] [IMP] validate custom views at the end of update of database bzr revid: chs@openerp.com-20130912182926-3lectt8mvd9smwfb --- openerp/addons/base/ir/ir_ui_view.py | 17 +++++++ openerp/addons/base/tests/test_views.py | 61 +++++++++++++++++++++++++ openerp/modules/loading.py | 12 ++++- 3 files changed, 89 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py index d7e433a6b47..4994ba9c99b 100644 --- a/openerp/addons/base/ir/ir_ui_view.py +++ b/openerp/addons/base/ir/ir_ui_view.py @@ -21,6 +21,7 @@ import logging from lxml import etree +from operator import itemgetter import os from openerp import tools @@ -280,6 +281,22 @@ class view(osv.osv): 'blank_nodes': blank_nodes, 'node_parent_field': _Model_Field,} + def _validate_custom_views(self, cr, uid, model): + """Validate architecture of custom views (= without xml id) for a given model. + This method is called at the end of registry update. + """ + cr.execute("""SELECT max(v.id) + FROM ir_ui_view v + LEFT JOIN ir_model_data md ON (md.model = 'ir.ui.view' AND md.res_id = v.id) + WHERE md.module IS NULL + AND v.model = %s + GROUP BY coalesce(v.inherit_id, v.id) + """, (model,)) + + ids = map(itemgetter(0), cr.fetchall()) + return self._check_xml(cr, uid, ids) + + class view_sc(osv.osv): _name = 'ir.ui.view_sc' _columns = { diff --git a/openerp/addons/base/tests/test_views.py b/openerp/addons/base/tests/test_views.py index 74f6f847dba..992ef0886da 100644 --- a/openerp/addons/base/tests/test_views.py +++ b/openerp/addons/base/tests/test_views.py @@ -1,3 +1,4 @@ +from functools import partial import unittest2 import openerp.tests.common as common @@ -39,6 +40,66 @@ class test_views(common.TransactionCase): """, }) + def _insert_view(self, **kw): + """Insert view into database via a query to passtrough validation""" + kw.pop('id', None) + + keys = sorted(kw.keys()) + fields = ','.join('"%s"' % (k.replace('"', r'\"'),) for k in keys) + params = ','.join('%%(%s)s' % (k,) for k in keys) + + query = 'INSERT INTO ir_ui_view(%s) VALUES(%s) RETURNING id' % (fields, params) + self.cr.execute(query, kw) + return self.cr.fetchone()[0] + + def test_10_validate_custom_views(self): + Views = self.registry('ir.ui.view') + model = 'ir.actions.act_url' + + validate = partial(Views._validate_custom_views, self.cr, self.uid, model) + + # validation of a single view + vid = self._insert_view(**{ + 'name': 'base view', + 'model': model, + 'priority': 1, + 'arch': """ + + + + """, + }) + self.assertTrue(validate()) # single view + + # validation of a inherited view + self._insert_view(**{ + 'name': 'inherited view', + 'model': model, + 'priority': 1, + 'inherit_id': vid, + 'arch': """ + + + + """, + }) + self.assertTrue(validate()) # inherited view + + # validation of a bad inherited view + self._insert_view(**{ + 'name': 'bad inherited view', + 'model': model, + 'priority': 2, + 'inherit_id': vid, + 'arch': """ + + + + """, + }) + with mute_logger('openerp.osv.orm', 'openerp.addons.base.ir.ir_ui_view'): + self.assertFalse(validate()) # bad inherited view + if __name__ == '__main__': unittest2.main() diff --git a/openerp/modules/loading.py b/openerp/modules/loading.py index f669d038b20..ed2119e7e40 100644 --- a/openerp/modules/loading.py +++ b/openerp/modules/loading.py @@ -414,12 +414,22 @@ def load_modules(db, force_demo=False, status=None, update_module=False): _logger.info('Reloading registry once more after uninstalling modules') return openerp.modules.registry.RegistryManager.new(cr.dbname, force_demo, status, update_module) + # STEP 7: verify custom views on every model + if update_module: + Views = registry['ir.ui.view'] + custom_view_test = True + for model in registry.models.keys(): + if not Views._validate_custom_views(cr, SUPERUSER_ID, model): + custom_view_test = False + _logger.error('invalid custom view(s) for model %s', model) + report.record_result(custom_view_test) + if report.failures: _logger.error('At least one test failed when loading the modules.') else: _logger.info('Modules loaded.') - # STEP 7: call _register_hook on every model + # STEP 8: call _register_hook on every model for model in registry.models.values(): model._register_hook(cr)