The `test_01_multi_domain_assets_generation` was introduced in PR [1]. But afterward, the commit [2] introduced a unique constraint on the `domain` field. With this additional constraint, this test broke when run with multiple existing websites as it assigns the same domain for each of them. This commit made the dummy domain assigned in this test non-unique, which doesn't alter the original meaning of the test but, allows to run it with multiple existing websites. [1]: https://github.com/odoo/odoo/pull/118526 [2]: https://github.com/odoo/odoo/commit/507db4e179514d171ec82e8ea0cbaf2323a6c30d runbot-20848 closes odoo/odoo#146666 X-original-commit: 0c522e42a82ec596e69611c556c4fc0d50e6e978 Signed-off-by: Romain Derie (rde) <rde@odoo.com> Signed-off-by: Pierre Paridans (app) <app@odoo.com>
261 lines
12 KiB
Python
261 lines
12 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
import re
|
|
|
|
import odoo.tests
|
|
|
|
from odoo.tools import config
|
|
|
|
|
|
@odoo.tests.common.tagged('post_install', '-at_install')
|
|
class TestWebsiteAssets(odoo.tests.HttpCase):
|
|
|
|
def test_01_multi_domain_assets_generation(self):
|
|
Website = self.env['website']
|
|
Attachment = self.env['ir.attachment']
|
|
# Create an additional website to ensure it works in multi-website setup
|
|
Website.create({'name': 'Second Website'})
|
|
# Simulate single website DBs: make sure other website do not interfer
|
|
# (We can't delete those, constraint will most likely be raised)
|
|
[w.write({'domain': f'inactive-{w.id}.test'}) for w in Website.search([])]
|
|
# Don't use HOST, hardcode it so it doesn't get changed one day and make
|
|
# the test useless
|
|
domain_1 = "http://127.0.0.1:%s" % config['http_port']
|
|
domain_2 = "http://localhost:%s" % config['http_port']
|
|
Website.browse(1).domain = domain_1
|
|
|
|
self.authenticate('admin', 'admin')
|
|
self.env['web_editor.assets'].with_context(website_id=1).make_scss_customization(
|
|
'/website/static/src/scss/options/colors/user_color_palette.scss',
|
|
{"o-cc1-bg": "'400'"},
|
|
)
|
|
|
|
def get_last_backend_asset_attach_id():
|
|
return Attachment.search([
|
|
('name', '=', 'web.assets_backend.min.js'),
|
|
], order="id desc", limit=1).id
|
|
|
|
def check_asset():
|
|
self.assertEqual(last_backend_asset_attach_id, get_last_backend_asset_attach_id())
|
|
|
|
last_backend_asset_attach_id = get_last_backend_asset_attach_id()
|
|
|
|
# The first call will generate the assets and populate the cache and
|
|
# take ~100 SQL Queries (~cold state).
|
|
# Any later call to `/web`, regardless of the domain, will take only
|
|
# ~10 SQL Queries (hot state).
|
|
# Without the calls the `check_asset()` (which would raise early and
|
|
# would not call other `url_open()`) and before the fix coming with this
|
|
# test, here is the logs:
|
|
# "GET /web HTTP/1.1" 200 - 222 0.135 3.840 <-- 222 Queries, ~4s
|
|
# "GET /web HTTP/1.1" 200 - 181 0.101 3.692 <-- 181 Queries, ~4s
|
|
# "GET /web HTTP/1.1" 200 - 215 0.121 3.704 <-- 215 Queries, ~4s
|
|
# "GET /web HTTP/1.1" 200 - 181 0.100 3.616 <-- 181 Queries, ~4s
|
|
# After the fix, here is the logs:
|
|
# "GET /web HTTP/1.1" 200 - 101 0.043 0.353 <-- 101 Queries, ~0.3s
|
|
# "GET /web HTTP/1.1" 200 - 11 0.004 0.007 <-- 11 Queries, ~10ms
|
|
# "GET /web HTTP/1.1" 200 - 11 0.003 0.005 <-- 11 Queries, ~10ms
|
|
# "GET /web HTTP/1.1" 200 - 11 0.003 0.008 <-- 11 Queries, ~10ms
|
|
self.url_open(domain_1 + '/web')
|
|
check_asset()
|
|
self.url_open(domain_2 + '/web')
|
|
check_asset()
|
|
self.url_open(domain_1 + '/web')
|
|
check_asset()
|
|
self.url_open(domain_2 + '/web')
|
|
check_asset()
|
|
self.url_open(domain_1 + '/web')
|
|
check_asset()
|
|
|
|
def test_02_t_cache_invalidation(self):
|
|
self.authenticate(None, None)
|
|
page = self.url_open('/').text # add to cache
|
|
public_assets_links = re.findall(r'(/web/assets/\d+/\w{7}/web.assets_frontend\..+)"/>', page)
|
|
self.assertTrue(public_assets_links)
|
|
self.authenticate('admin', 'admin')
|
|
page = self.url_open('/').text
|
|
admin_assets_links = re.findall(r'(/web/assets/\d+/\w{7}/web.assets_frontend\..+)"/>', page)
|
|
self.assertTrue(admin_assets_links)
|
|
|
|
self.assertEqual(public_assets_links, admin_assets_links)
|
|
|
|
snippets = self.env['ir.asset'].search([
|
|
('path', '=like', 'website/static/src/snippets/s_social_media/000.scss'), # arbitrary, a unused css one that doesn't make the page fail when archived.
|
|
('bundle', '=', 'web.assets_frontend'),
|
|
])
|
|
self.assertTrue(snippets)
|
|
write_dates = snippets.mapped('write_date')
|
|
snippets.write({'active': False})
|
|
snippets.flush_recordset()
|
|
self.assertNotEqual(write_dates, snippets.mapped('write_date'))
|
|
|
|
page = self.url_open('/').text
|
|
new_admin_assets_links = re.findall(r'(/web/assets/\d+/\w{7}/web.assets_frontend\..+)"/>', page)
|
|
self.assertTrue(new_admin_assets_links)
|
|
|
|
self.assertEqual(public_assets_links, admin_assets_links)
|
|
self.assertNotEqual(new_admin_assets_links, admin_assets_links, "we expect a change since ir_assets were written")
|
|
|
|
self.authenticate(None, None)
|
|
page = self.url_open('/').text
|
|
|
|
new_public_assets_links = re.findall(r'(/web/assets/\d+/\w{7}/web.assets_frontend\..+)"/>', page)
|
|
self.assertEqual(new_admin_assets_links, new_public_assets_links, "t-cache should have been invalidated for public user too")
|
|
|
|
def test_invalid_unlink(self):
|
|
self.env['ir.attachment'].search([('url', '=like', '/web/assets/%')]).unlink()
|
|
|
|
asset_bundle_xmlid = 'web.assets_frontend'
|
|
website_default = self.env['website'].search([], limit=1)
|
|
|
|
code = b"document.body.dataset.hello = 'world';"
|
|
attach = self.env['ir.attachment'].create({
|
|
'name': 'EditorExtension.css',
|
|
'mimetype': 'text/css',
|
|
'raw': code,
|
|
})
|
|
custom_url = '/_custom/web/content/%s/%s' % (attach.id, attach.name)
|
|
attach.url = custom_url
|
|
|
|
self.env['ir.asset'].create({
|
|
'name': 'EditorExtension',
|
|
'bundle': asset_bundle_xmlid,
|
|
'path': custom_url,
|
|
'website_id': website_default.id,
|
|
})
|
|
|
|
website_bundle = self.env['ir.qweb']._get_asset_bundle(asset_bundle_xmlid, assets_params={'website_id': website_default.id})
|
|
self.assertIn(custom_url, [f['url'] for f in website_bundle.files])
|
|
base_website_css_version = website_bundle.get_version('css')
|
|
|
|
no_website_bundle = self.env['ir.qweb']._get_asset_bundle(asset_bundle_xmlid)
|
|
self.assertNotIn(custom_url, [f['url'] for f in no_website_bundle.files])
|
|
self.assertNotEqual(no_website_bundle.get_version('css'), base_website_css_version)
|
|
|
|
website_attach = website_bundle.css()
|
|
self.assertTrue(website_attach.exists())
|
|
no_website_bundle.css()
|
|
self.assertTrue(website_attach.exists(), 'attachment for website should still exist after generating attachment for no website')
|
|
|
|
|
|
@odoo.tests.tagged('-at_install', 'post_install')
|
|
class TestWebAssets(odoo.tests.HttpCase):
|
|
def test_assets_url_validation(self):
|
|
website_id = self.env['website'].search([], limit=1, order='id desc').id
|
|
|
|
with odoo.tools.mute_logger('odoo.addons.web.controllers.binary'):
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/debug/hello/web.assets_frontend.css', allow_redirects=False).status_code,
|
|
404,
|
|
"unexpected direction extra",
|
|
)
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/debug/web.assets_f_ontend.js', allow_redirects=False).status_code,
|
|
404,
|
|
"bundle name contains `_` and should be escaped wildcard",
|
|
)
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/debug/web.assets_frontend.rtl.js', allow_redirects=False).status_code,
|
|
404,
|
|
"js cannot have `rtl` has extra",
|
|
)
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/debug/web.assets_frontend.rtl.js', allow_redirects=False).status_code,
|
|
404,
|
|
"js cannot have `rtl` has extra",
|
|
)
|
|
self.assertEqual(
|
|
self.url_open(f'/web/{website_id+1}/assets/debug/web.assets_frontend.css', allow_redirects=False).status_code,
|
|
404,
|
|
"website_id does not exist",
|
|
)
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/debug/web.assets_frontend.aa.css', allow_redirects=False).status_code,
|
|
404,
|
|
"invalid direction",
|
|
)
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/any/web.assets_frontend.min.rtl.css', allow_redirects=False).status_code,
|
|
404,
|
|
"min and direction inverted",
|
|
)
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/any/web.assets_frontend.js', allow_redirects=False).status_code,
|
|
404,
|
|
"missing min in non debug mode",
|
|
)
|
|
|
|
self.assertEqual(
|
|
self.url_open('/web/assets/debug/web.assets_frontend.css', allow_redirects=False).status_code,
|
|
200,
|
|
)
|
|
self.assertEqual(
|
|
self.url_open('/web/assets/debug/web.assets_frontend.js', allow_redirects=False).status_code,
|
|
200,
|
|
)
|
|
self.assertEqual(
|
|
self.url_open('/web/assets/debug/web.assets_frontend.rtl.css', allow_redirects=False).status_code,
|
|
200,
|
|
)
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/debug/web.assets_frontend.css', allow_redirects=False).status_code,
|
|
200,
|
|
)
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/debug/web.assets_frontend.rtl.css', allow_redirects=False).status_code,
|
|
200,
|
|
)
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/debug/web.assets_frontend.js', allow_redirects=False).status_code,
|
|
200,
|
|
)
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/any/web.assets_frontend.rtl.min.css', allow_redirects=False).status_code,
|
|
200,
|
|
)
|
|
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/any/web.assets_frontend.min.css', allow_redirects=False).status_code,
|
|
200,
|
|
)
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/any/web.assets_frontend.min.js', allow_redirects=False).status_code,
|
|
200,
|
|
)
|
|
|
|
# redirect urls
|
|
invalid_version = '1234567'
|
|
self.assertEqual(
|
|
self.url_open(f'/web/assets/{website_id}/{invalid_version}/web.assets_frontend.min.css', allow_redirects=False).headers['location'].split('/assets/')[1],
|
|
self.env['ir.qweb']._get_asset_bundle('web.assets_frontend', assets_params={'website_id': website_id}).get_link('css').split('/assets/')[1],
|
|
)
|
|
|
|
def test_ensure_correct_website_asset(self):
|
|
# when searching for an attachment, if the unique a wildcard, we want to ensute that we don't match a website one when seraching a no website one.
|
|
# this test should also wheck that the clean_attachement does not erase a website_attachement after generating a base attachment
|
|
website_id = self.env['website'].search([], limit=1, order='id desc').id
|
|
unique = self.env['ir.qweb']._get_asset_bundle('web.assets_frontend').get_version('js')
|
|
base_url = self.env['ir.asset']._get_asset_bundle_url('web.assets_frontend.min.js', '%', {})
|
|
base_url_versioned = self.env['ir.asset']._get_asset_bundle_url('web.assets_frontend.min.js', unique, {})
|
|
website_url = self.env['ir.asset']._get_asset_bundle_url('web.assets_frontend.min.js', '%', {'website_id': website_id})
|
|
# we expect the unique to be the same in this case, but there is no garantee
|
|
website_url_versioned = self.env['ir.asset']._get_asset_bundle_url('web.assets_frontend.min.js', unique, {'website_id': website_id})
|
|
|
|
self.env['ir.attachment'].search([('url', '=like', '%web.assets_frontend.min.js')]).unlink()
|
|
|
|
# generate website assets
|
|
self.assertEqual(self.url_open(website_url, allow_redirects=False).status_code, 200)
|
|
self.assertEqual(
|
|
self.env['ir.attachment'].search([('url', '=like', '%web.assets_frontend.min.js')]).mapped('url'),
|
|
[website_url_versioned],
|
|
'Only the website asset is expected to be present',
|
|
)
|
|
|
|
# generate base assets
|
|
self.assertEqual(self.url_open(base_url, allow_redirects=False).status_code, 200)
|
|
self.assertEqual(
|
|
self.env['ir.attachment'].search([('url', '=like', '%web.assets_frontend.min.js')]).mapped('url'),
|
|
[base_url_versioned, website_url_versioned],
|
|
'base asset is expected to be present',
|
|
)
|