Since #121376 a clear_cache was removed when unlinking an attachment This clear_cache was not useful when restarting a server with new sources, an other operation changing the content of an assets should invalidate the cache manually. This is the case of ir.asset CUD operations. Unfortunately, a manual update was left missing in website, when archiving ir.assets used for snippets. This was discovered on runbot, with two workers, when the first workers generates assets before the cron, and the second one after the cron. The second worker unlinks attachments creating an inconsistency in the cache of the first one. This problem can be solved quickly by invalidating the assets cache in the cron manually but this will be done in all cases. The proposed solution will check the ir.asset that should change and only clear the cache if the state changed. Regarding performances, this should actually be a slight improvement in query count since at the cost of one more select to prefetch the record we can avoid multiple update, one per snippet. In most case no update at all should be done, at most 2 can be done (one for archive, one for unarchive). Example with some assets to unarchive: Before: TOTAL ENTRIES: 277 SELECT: 158 (~0.16591858863830566s) UNKWOW: 54 (~0.0202481746673584s) UPDATE: 65 (~0.03202557563781738s) After: TOTAL ENTRIES: 214 SELECT: 159 (~0.1663439826965332s) UNKWOW: 54 (~0.029229164123535156s) UPDATE: 1 (~0.0002865791320800781s) If the number of query is lowered, the python processing is slightly higher. Locally the test time is similar, slightly longer since an additional call to _disable_unused_snippets_assets was added to check the cache invalidation closes odoo/odoo#130973 X-original-commit: 3aeab51ff4379e6d76172614fd39f09d6c449ac6 Signed-off-by: Xavier Dollé (xdo) <xdo@odoo.com>
181 lines
8.5 KiB
Python
181 lines
8.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo.tests import TransactionCase, tagged
|
|
from unittest.mock import patch
|
|
|
|
@tagged('post_install', '-at_install')
|
|
class TestDisableSnippetsAssets(TransactionCase):
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.View = self.env['ir.ui.view']
|
|
self.WebsiteMenu = self.env['website.menu']
|
|
self.Website = self.env['website']
|
|
self.IrAsset = self.env['ir.asset']
|
|
|
|
self.homepage = self.View.create({
|
|
'name': 'Home',
|
|
'type': 'qweb',
|
|
'arch_db': HOMEPAGE_OUTDATED,
|
|
'key': 'website.homepage',
|
|
})
|
|
self.mega_menu = self.WebsiteMenu.create({
|
|
'name': 'Image Gallery V001',
|
|
'mega_menu_content': MEGA_MENU_UP_TO_DATE,
|
|
})
|
|
|
|
self.initial_active_snippets_assets = self._get_active_snippets_assets()
|
|
|
|
def test_homepage_outdated_and_mega_menu_up_to_date(self):
|
|
self.Website._disable_unused_snippets_assets()
|
|
# Old snippet with scss and js
|
|
s_website_form_000_scss = self._get_snippet_asset('s_website_form', '000', 'scss')
|
|
s_website_form_001_scss = self._get_snippet_asset('s_website_form', '001', 'scss')
|
|
s_website_form_000_js = self._get_snippet_asset('s_website_form', '000', 'js')
|
|
self.assertEqual(s_website_form_000_scss.active, True)
|
|
self.assertEqual(s_website_form_001_scss.active, True)
|
|
self.assertEqual(s_website_form_000_js.active, True)
|
|
|
|
# Old snippet with scss and scss variables
|
|
s_masonry_block_000_scss = self._get_snippet_asset('s_masonry_block', '000', 'scss')
|
|
s_masonry_block_000_variables_scss = self._get_snippet_asset('s_masonry_block', '000_variables', 'scss')
|
|
s_masonry_block_001_scss = self._get_snippet_asset('s_masonry_block', '001', 'scss')
|
|
self.assertEqual(s_masonry_block_000_scss.active, True)
|
|
self.assertEqual(s_masonry_block_000_variables_scss.active, True)
|
|
self.assertEqual(s_masonry_block_001_scss.active, True)
|
|
|
|
# New snippet
|
|
s_image_gallery_000 = self._get_snippet_asset('s_image_gallery', '000', 'scss')
|
|
s_image_gallery_001 = self._get_snippet_asset('s_image_gallery', '001', 'scss')
|
|
self.assertEqual(s_image_gallery_000.active, False)
|
|
self.assertEqual(s_image_gallery_001.active, True)
|
|
|
|
unwanted_snippets_assets_changes = set(self.initial_active_snippets_assets) - set(self._get_active_snippets_assets()) - set([s_image_gallery_000.path])
|
|
|
|
# The vaccuum should not have activated/deactivated any other snippet asset than the original ones
|
|
self.assertEqual(
|
|
len(unwanted_snippets_assets_changes),
|
|
0,
|
|
'Following snippets are not following the snippet versioning system structure, or their previous assets have not been deactivated:\n'
|
|
+ '\n'.join(unwanted_snippets_assets_changes))
|
|
|
|
def test_homepage_up_to_date_and_mega_menu_outdated(self):
|
|
self.homepage.write({
|
|
'arch_db': HOMEPAGE_UP_TO_DATE,
|
|
})
|
|
self.homepage.flush_recordset()
|
|
self.mega_menu.write({
|
|
'mega_menu_content': MEGA_MENU_OUTDATED,
|
|
})
|
|
self.mega_menu.flush_recordset()
|
|
cache_clears = []
|
|
|
|
init_clear_cache = self.env.registry.clear_cache
|
|
def patched_clear_cache(*cache_names):
|
|
for cache_name in cache_names:
|
|
cache_clears.append(cache_name)
|
|
init_clear_cache(*cache_names)
|
|
|
|
with patch.object(self.env.registry, 'clear_cache', patched_clear_cache):
|
|
self.Website._disable_unused_snippets_assets()
|
|
self.assertIn('assets', cache_clears, 'Assets cache should have been invalidated when updating ir_assets')
|
|
cache_clears.clear()
|
|
self.Website._disable_unused_snippets_assets()
|
|
self.assertNotIn('assets', cache_clears, 'No update on ir_assets expected, no invalidation should be triggered')
|
|
|
|
s_website_form_000_scss = self._get_snippet_asset('s_website_form', '000', 'scss')
|
|
s_website_form_001_scss = self._get_snippet_asset('s_website_form', '001', 'scss')
|
|
s_website_form_000_js = self._get_snippet_asset('s_website_form', '000', 'js')
|
|
self.assertEqual(s_website_form_000_scss.active, False)
|
|
self.assertEqual(s_website_form_001_scss.active, True)
|
|
self.assertEqual(s_website_form_000_js.active, True)
|
|
|
|
s_masonry_block_000_scss = self._get_snippet_asset('s_masonry_block', '000', 'scss')
|
|
s_masonry_block_000_variables_scss = self._get_snippet_asset('s_masonry_block', '000_variables', 'scss')
|
|
s_masonry_block_001_scss = self._get_snippet_asset('s_masonry_block', '001', 'scss')
|
|
self.assertEqual(s_masonry_block_000_scss.active, False)
|
|
self.assertEqual(s_masonry_block_000_variables_scss.active, False)
|
|
self.assertEqual(s_masonry_block_001_scss.active, True)
|
|
|
|
s_image_gallery_000 = self._get_snippet_asset('s_image_gallery', '000', 'scss')
|
|
s_image_gallery_001 = self._get_snippet_asset('s_image_gallery', '001', 'scss')
|
|
self.assertEqual(s_image_gallery_000.active, True)
|
|
self.assertEqual(s_image_gallery_001.active, True)
|
|
|
|
def _get_snippet_asset(self, snippet_id, asset_version, asset_type):
|
|
return self.IrAsset.search([('path', '=', 'website/static/src/snippets/' + snippet_id + '/' + asset_version + '.' + asset_type)], limit=1)
|
|
|
|
def _get_active_snippets_assets(self):
|
|
return self.IrAsset.search([('path', 'like', 'snippets'), ('active', '=', True)]).mapped('path')
|
|
|
|
HOMEPAGE_UP_TO_DATE = """
|
|
<t name="Homepage" t-name="website.homepage1">
|
|
<t t-call="website.layout">
|
|
<t t-set="pageName" t-value="'homepage'"/>
|
|
<div id="wrap" class="oe_structure oe_empty">
|
|
<section class="s_website_form pt16 pb16 o_colored_level" data-vcss="001" data-snippet="s_website_form" data-name="Form">
|
|
<div class="container">
|
|
<form action="/website_form/" method="post" enctype="multipart/form-data" class="o_mark_required" data-mark="*" data-success-mode="redirect" data-success-page="/contactus-thank-you" data-model_name="mail.mail">
|
|
</form>
|
|
</div>
|
|
</section>
|
|
<section class="s_masonry_block" data-vcss="001" data-snippet="s_masonry_block" data-name="Masonry">
|
|
<div class="container-fluid"/>
|
|
</section>
|
|
<section class="s_showcase pt48 pb48 o_colored_level" data-vcss="002" data-snippet="s_showcase" data-name="Showcase">
|
|
<div class="container">
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</t>
|
|
</t>
|
|
"""
|
|
|
|
HOMEPAGE_OUTDATED = """
|
|
<t name="Homepage" t-name="website.homepage1">
|
|
<t t-call="website.layout">
|
|
<t t-set="pageName" t-value="'homepage'"/>
|
|
<div id="wrap" class="oe_structure oe_empty">
|
|
<form action="/website_form/" method="post" class="s_website_form container-fluid mt32 o_fake_not_editable" enctype="multipart/form-data" data-name="Form Builder" data-model_name="mail.mail" data-success_page="/contactus-thank-you" data-snippet="s_website_form">
|
|
<div class="container">
|
|
</div>
|
|
</form>
|
|
<section class="s_masonry_block" data-vcss="001" data-snippet="s_masonry_block" data-name="Masonry">
|
|
<div class="container-fluid"/>
|
|
</section>
|
|
<section class="s_masonry_block" data-snippet="s_masonry_block" data-name="Masonry">
|
|
<div class="container-fluid"/>
|
|
</section>
|
|
<section class="s_showcase pt48 pb48 o_colored_level" data-vcss="002" data-snippet="s_showcase" data-name="Showcase">
|
|
<div class="container">
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</t>
|
|
</t>
|
|
"""
|
|
|
|
MEGA_MENU_UP_TO_DATE = """
|
|
<section class="s_mega_menu_multi_menus py-4 o_colored_level" data-name="Multi-Menus">
|
|
<div class="container">
|
|
</div>
|
|
</section>
|
|
|
|
<section class="s_image_gallery o_slideshow s_image_gallery_show_indicators s_image_gallery_indicators_rounded pt24 o_colored_level" data-vcss="001" data-columns="3" style="height: 500px; overflow: hidden;" data-snippet="s_image_gallery" data-name="Image Gallery">
|
|
<div class="container">
|
|
</div>
|
|
</section>
|
|
"""
|
|
|
|
MEGA_MENU_OUTDATED = """
|
|
<section class="s_mega_menu_multi_menus py-4 o_colored_level" data-name="Multi-Menus">
|
|
<div class="container">
|
|
</div>
|
|
</section>
|
|
|
|
<section class="s_image_gallery o_slideshow s_image_gallery_show_indicators s_image_gallery_indicators_rounded pt24 o_colored_level" data-columns="3" style="height: 500px; overflow: hidden;" data-snippet="s_image_gallery" data-name="Image Gallery">
|
|
<div class="container">
|
|
</div>
|
|
</section>
|
|
"""
|