*: auth_password_policy, bus, calendar, event, mass_mailing, stock, survey, web_editor, web_tour, website, website_event, website_forum, website_mass_mailing, website_sale This commit is a first step towards a potential deletion of the assets_common bundle, although that step would need more work, specs and discussions as some layouts kinda only use the assets_common bundle (some take the full assets_common but parts of the assets_backend one for example). The main goal of this commit is to have the assets_frontend bundle directly include the "common" files we need. As a first step, this commit only blindly duplicates them all into assets_frontend (without removing the potentially useless ones). The goal is to have those advantages: - Reaching a frontend page only calls two main JS files (one normal and one lazy-loaded) instead of 4 (two normals and two lazy-loaded). This may help reach a better google page speed (which is becoming more and more strict). - The frontend CSS is built as one: the common SCSS which was using bootstrap variables, or even Odoo-based SCSS added by mistake in common instead of both backend and frontend is now computed with the right bootstrap customizations. E.g. the tempusdominus datetimepickers use bootstrap grays... after this PR, they use the right grays as customized by the user on the website. It was also chosen to not have a common "sub-asset" which is included in assets_frontend. Making assets_frontend completely independent makes sense (as it probably will for other "main" asset bundles): we can focus on adding the files each layout needs without the need of worrying if it impacts unrelated layouts. Sub-assets (when not strictly necessary) is also a source of errors: extending the "main" bundle instead of the right sub-asset it may use (like it was the case with the sub-assets of assets_common: _assets_common_scripts and _assets_common_styles as explained in the previous commit). So this is indeed a small drawback of not factorizing the code for the inclusion of "common" files in bundles but it seems more explicit and easier to maintain that way. Note that adding "common" file is not the most common usecase anyway, apps generally only need files in backend or frontend. The __manifest__ declaration will also likely evolve in more and more uses of wildcards to match entire directories. In the future, adding "common" web-app files in both backend, frontend and other "main" bundles could just be about one line duplicated into each bundle. closes odoo/odoo#100314 Related: odoo/enterprise#31394 Signed-off-by: Romain Derie (rde) <rde@odoo.com>
153 lines
6.1 KiB
Python
153 lines
6.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo.tools import mute_logger
|
|
from odoo.tests.common import HttpCase, tagged
|
|
|
|
EXTRA_REQUEST = 2 - 1
|
|
""" During tests, the query on 'base_registry_signaling, base_cache_signaling'
|
|
won't be executed on hot state, but new queries related to the test cursor will
|
|
be added:
|
|
|
|
cr = Cursor() # SAVEPOINT
|
|
cr.execute(...)
|
|
cr.commit() # RELEASE
|
|
cr.close()
|
|
"""
|
|
|
|
|
|
class UtilPerf(HttpCase):
|
|
def _get_url_hot_query(self, url, cache=True):
|
|
url += ('?' not in url and '?' or '')
|
|
if cache:
|
|
url += '&debug='
|
|
else:
|
|
url += '&debug=disable-t-cache'
|
|
|
|
# ensure worker is in hot state
|
|
self.url_open(url)
|
|
self.url_open(url)
|
|
|
|
sql_count = self.registry.test_cr.sql_log_count
|
|
self.url_open(url)
|
|
return self.registry.test_cr.sql_log_count - sql_count - EXTRA_REQUEST
|
|
|
|
|
|
class TestStandardPerformance(UtilPerf):
|
|
@mute_logger('odoo.http')
|
|
def test_10_perf_sql_img_controller(self):
|
|
self.authenticate('demo', 'demo')
|
|
# not published user, get the not found image placeholder
|
|
self.assertEqual(self.env['res.users'].sudo().browse(2).website_published, False)
|
|
url = '/web/image/res.users/2/image_256'
|
|
self.assertEqual(self._get_url_hot_query(url), 6)
|
|
self.assertEqual(self._get_url_hot_query(url, cache=False), 6)
|
|
|
|
@mute_logger('odoo.http')
|
|
def test_11_perf_sql_img_controller(self):
|
|
self.authenticate('demo', 'demo')
|
|
self.env['res.users'].sudo().browse(2).website_published = True
|
|
url = '/web/image/res.users/2/image_256'
|
|
self.assertEqual(self._get_url_hot_query(url), 6)
|
|
self.assertEqual(self._get_url_hot_query(url, cache=False), 6)
|
|
|
|
@mute_logger('odoo.http')
|
|
def test_20_perf_sql_img_controller_bis(self):
|
|
url = '/web/image/website/1/favicon'
|
|
self.assertEqual(self._get_url_hot_query(url), 5)
|
|
self.assertEqual(self._get_url_hot_query(url, cache=False), 5)
|
|
self.authenticate('portal', 'portal')
|
|
self.assertEqual(self._get_url_hot_query(url), 5)
|
|
self.assertEqual(self._get_url_hot_query(url, cache=False), 5)
|
|
|
|
|
|
class TestWebsitePerformance(UtilPerf):
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.page, self.menu = self._create_page_with_menu('/sql_page')
|
|
|
|
def _create_page_with_menu(self, url):
|
|
name = url[1:]
|
|
website = self.env['website'].browse(1)
|
|
page = self.env['website.page'].create({
|
|
'url': url,
|
|
'name': name,
|
|
'type': 'qweb',
|
|
'arch': '<t name="%s" t-name="website.page_test_%s"> \
|
|
<t t-call="website.layout"> \
|
|
<div id="wrap"><div class="oe_structure"/></div> \
|
|
</t> \
|
|
</t>' % (name, name),
|
|
'key': 'website.page_test_%s' % name,
|
|
'is_published': True,
|
|
'website_id': website.id,
|
|
'track': False,
|
|
})
|
|
menu = self.env['website.menu'].create({
|
|
'name': name,
|
|
'url': url,
|
|
'page_id': page.id,
|
|
'website_id': website.id,
|
|
'parent_id': website.menu_id.id
|
|
})
|
|
return (page, menu)
|
|
|
|
def test_10_perf_sql_queries_page(self):
|
|
# standard untracked website.page
|
|
self.assertEqual(self._get_url_hot_query(self.page.url), 6)
|
|
self.assertEqual(self._get_url_hot_query(self.page.url, cache=False), 10)
|
|
self.menu.unlink()
|
|
self.assertEqual(self._get_url_hot_query(self.page.url), 6)
|
|
self.assertEqual(self._get_url_hot_query(self.page.url, cache=False), 10)
|
|
|
|
def test_15_perf_sql_queries_page(self):
|
|
# standard tracked website.page
|
|
self.page.track = True
|
|
self.assertEqual(self._get_url_hot_query(self.page.url), 7)
|
|
self.assertEqual(self._get_url_hot_query(self.page.url, cache=False), 11)
|
|
self.menu.unlink()
|
|
self.assertEqual(self._get_url_hot_query(self.page.url), 7)
|
|
self.assertEqual(self._get_url_hot_query(self.page.url, cache=False), 11)
|
|
|
|
def test_20_perf_sql_queries_homepage(self):
|
|
# homepage "/" has its own controller
|
|
self.assertEqual(self._get_url_hot_query('/'), 7)
|
|
self.assertEqual(self._get_url_hot_query('/', cache=False), 9)
|
|
|
|
def test_30_perf_sql_queries_page_no_layout(self):
|
|
# website.page with no call to layout templates
|
|
self.page.arch = '<div>I am a blank page</div>'
|
|
self.assertEqual(self._get_url_hot_query(self.page.url), 5)
|
|
self.assertEqual(self._get_url_hot_query(self.page.url, cache=False), 5)
|
|
|
|
def test_40_perf_sql_queries_page_multi_level_menu(self):
|
|
# menu structure should not impact SQL requests
|
|
_, menu_a = self._create_page_with_menu('/a')
|
|
_, menu_aa = self._create_page_with_menu('/aa')
|
|
_, menu_b = self._create_page_with_menu('/b')
|
|
_, menu_bb = self._create_page_with_menu('/bb')
|
|
_, menu_bbb = self._create_page_with_menu('/bbb')
|
|
_, menu_bbbb = self._create_page_with_menu('/bbbb')
|
|
_, menu_bbbbb = self._create_page_with_menu('/bbbbb')
|
|
self._create_page_with_menu('c')
|
|
menu_bbbbb.parent_id = menu_bbbb
|
|
menu_bbbb.parent_id = menu_bbb
|
|
menu_bbb.parent_id = menu_bb
|
|
menu_bb.parent_id = menu_b
|
|
menu_aa.parent_id = menu_a
|
|
|
|
self.assertEqual(self._get_url_hot_query(self.page.url), 6)
|
|
self.assertEqual(self._get_url_hot_query(self.page.url, cache=False), 10)
|
|
|
|
|
|
@tagged('-at_install', 'post_install')
|
|
class TestWebsitePerformancePost(UtilPerf):
|
|
@mute_logger('odoo.http')
|
|
def test_50_perf_sql_web_assets(self):
|
|
# assets route /web/assets/..
|
|
self.env['ir.qweb']._generate_asset_nodes('web.assets_frontend_lazy', css=False, js=True)
|
|
assets_url = self.env['ir.attachment'].search([('url', '=like', '/web/assets/%/web.assets_frontend_lazy%.js')], limit=1).url
|
|
self.assertEqual(self._get_url_hot_query(assets_url), 4)
|
|
self.assertEqual(self._get_url_hot_query(assets_url, cache=False), 4)
|