From 3751379f1e9a4c215fb6eb898b4ccc67659b9ace Mon Sep 17 00:00:00 2001 From: stephanchrst Date: Tue, 10 May 2022 21:51:50 +0700 Subject: initial commit 2 --- addons/web/tests/test_serving_base.py | 1002 +++++++++++++++++++++++++++++++++ 1 file changed, 1002 insertions(+) create mode 100644 addons/web/tests/test_serving_base.py (limited to 'addons/web/tests/test_serving_base.py') diff --git a/addons/web/tests/test_serving_base.py b/addons/web/tests/test_serving_base.py new file mode 100644 index 00000000..d7d83c25 --- /dev/null +++ b/addons/web/tests/test_serving_base.py @@ -0,0 +1,1002 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import random +import re +from unittest.mock import patch +import textwrap +from datetime import datetime, timedelta +from lxml import etree +import logging + +from odoo.tests.common import BaseCase, tagged +from odoo.tools import topological_sort +from odoo.addons.web.controllers.main import HomeStaticTemplateHelpers + +_logger = logging.getLogger(__name__) + +def sample(population): + return random.sample( + population, + random.randint(0, min(len(population), 5))) + + +class TestModulesLoading(BaseCase): + def setUp(self): + self.mods = [str(i) for i in range(1000)] + + def test_topological_sort(self): + random.shuffle(self.mods) + modules = [ + (k, sample(self.mods[:i])) + for i, k in enumerate(self.mods)] + random.shuffle(modules) + ms = dict(modules) + + seen = set() + sorted_modules = topological_sort(ms) + for module in sorted_modules: + deps = ms[module] + self.assertGreaterEqual( + seen, set(deps), + 'Module %s (index %d), ' \ + 'missing dependencies %s from loaded modules %s' % ( + module, sorted_modules.index(module), deps, seen + )) + seen.add(module) + + +class TestStaticInheritanceCommon(BaseCase): + + def setUp(self): + super(TestStaticInheritanceCommon, self).setUp() + # output is "manifest_glob" return + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ('module_2_file_1', None, 'module_2'), + ] + + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
Kept thinking I could never live without you by my side
+
+ +
And I grew strong
+
+
+ """, + + 'module_2_file_1': b""" + +
+ +
I was petrified
+
+ +
But then I spent so many nights thinking how you did me wrong
+
+
+
+
And I learned how to get along
+
+
+ +
And I learned how to get along
+
+
+
+ """, + } + self._set_patchers() + self._toggle_patchers('start') + self._reg_replace_ws = r"\s|\t" + + def tearDown(self): + super(TestStaticInheritanceCommon, self).tearDown() + self._toggle_patchers('stop') + + # Custom Assert + def assertXMLEqual(self, output, expected): + self.assertTrue(output) + self.assertTrue(expected) + output = textwrap.dedent(output.decode('UTF-8')).strip() + output = re.sub(self._reg_replace_ws, '', output) + + expected = textwrap.dedent(expected.decode('UTF-8')).strip() + expected = re.sub(self._reg_replace_ws, '', expected) + self.assertEqual(output, expected) + + # Private methods + def _get_module_names(self): + return ','.join([glob[2] for glob in self.modules]) + + def _set_patchers(self): + def _patched_for_manifest_glob(*args, **kwargs): + # Ordered by module + return self.modules + + def _patch_for_read_addon_file(*args, **kwargs): + return self.template_files[args[1]] + + self.patchers = [ + patch.object(HomeStaticTemplateHelpers, '_manifest_glob', _patched_for_manifest_glob), + patch.object(HomeStaticTemplateHelpers, '_read_addon_file', _patch_for_read_addon_file), + ] + + def _toggle_patchers(self, mode): + self.assertTrue(mode in ('start', 'stop')) + for p in self.patchers: + getattr(p, mode)() + + +@tagged('static_templates') +class TestStaticInheritance(TestStaticInheritanceCommon): + # Actual test cases + def test_static_inheritance_01(self): + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+
Kept thinking I could never live without you by my side
+
+ +
And I grew strong
+ +
And I learned how to get along
+
+
+
At first I was afraid
+
I was petrified
+
But then I spent so many nights thinking how you did me wrong
+
Kept thinking I could never live without you by my side
+
+
+
And I learned how to get along
+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_static_inheritance_02(self): + self.template_files = { + 'module_1_file_1': b''' + +
+
At first I was afraid
+
Kept thinking I could never live without you by my side
+
+
+ +
I was petrified
+
+
+
+ ''' + } + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+
Kept thinking I could never live without you by my side
+
+
+
At first I was afraid
+
I was petrified
+
Kept thinking I could never live without you by my side
+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_static_inheritance_03(self): + self.maxDiff = None + self.template_files = { + 'module_1_file_1': b''' + +
+
At first I was afraid
+
Kept thinking I could never live without you by my side
+
+
+ +
I was petrified
+
+
+
+ + +
+ ''' + } + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+
Kept thinking I could never live without you by my side
+
+
+
At first I was afraid
+
I was petrified
+
Kept thinking I could never live without you by my side
+
+
+
At first I was afraid
+
Kept thinking I could never live without you by my side
+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_static_inheritance_in_same_module(self): + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ('module_1_file_2', None, 'module_1'), + ] + + self.template_files = { + 'module_1_file_1': b''' + +
+
At first I was afraid
+
Kept thinking I could never live without you by my side
+
+
+ ''', + + 'module_1_file_2': b''' + +
+ +
I was petrified
+
+
+
+ ''' + } + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+
Kept thinking I could never live without you by my side
+
+
+
At first I was afraid
+
I was petrified
+
Kept thinking I could never live without you by my side
+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_static_inheritance_in_same_file(self): + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + + self.template_files = { + 'module_1_file_1': b''' + +
+
At first I was afraid
+
Kept thinking I could never live without you by my side
+
+
+ +
I was petrified
+
+
+
+ ''', + } + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+
Kept thinking I could never live without you by my side
+
+
+
At first I was afraid
+
I was petrified
+
Kept thinking I could never live without you by my side
+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_static_inherit_extended_template(self): + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b''' + +
+
At first I was afraid
+
Kept thinking I could never live without you by my side
+
+
+ +
I was petrified
+
+
+
+ +
But then I spent so many nights thinking how you did me wrong
+
+
+
+ ''', + } + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+ +
I was petrified
+
Kept thinking I could never live without you by my side
+
+
+
At first I was afraid
+
I was petrified
+
Kept thinking I could never live without you by my side
+
But then I spent so many nights thinking how you did me wrong
+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_sibling_extension(self): + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ('module_2_file_1', None, 'module_2'), + ('module_3_file_1', None, 'module_3'), + ] + self.template_files = { + 'module_1_file_1': b''' + +
+
I am a man of constant sorrow
+
I've seen trouble all my days
+
+
+ ''', + + 'module_2_file_1': b''' + +
+ +
In constant sorrow all through his days
+
+
+
+ ''', + + 'module_3_file_1': b''' + +
+ +
Oh Brother !
+
+
+
+ ''' + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
I am a man of constant sorrow
+ +
In constant sorrow all through his days
+ +
Oh Brother !
+
I've seen trouble all my days
+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_static_misordered_modules(self): + self.modules.reverse() + with self.assertRaises(ValueError) as ve: + HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + + self.assertEqual( + str(ve.exception), + 'Module module_1 not loaded or inexistent, or templates of addon being loaded (module_2) are misordered' + ) + + def test_static_misordered_templates(self): + self.template_files['module_2_file_1'] = b""" + +
+ +
I was petrified
+
+
+
+
And I learned how to get along
+
+
+ """ + with self.assertRaises(ValueError) as ve: + HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + + self.assertEqual( + str(ve.exception), + 'No template found to inherit from. Module module_2 and template name template_2_2' + ) + + def test_replace_in_debug_mode(self): + """ + Replacing a template's meta definition in place doesn't keep the original attrs of the template + """ + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
And I grew strong
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+ And I grew strong +
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_replace_in_debug_mode2(self): + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
+ And I grew strong +

And I learned how to get along

+ And so you're back +
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+ + And I grew strong +

And I learned how to get along

+ And so you're back +
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_replace_in_debug_mode3(self): + """Text outside of a div which will replace a whole template + becomes outside of the template + This doesn't mean anything in terms of the business of template inheritance + But it is in the XPATH specs""" + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
+ And I grew strong +

And I learned how to get along

+
+ And so you're back +
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+ + And I grew strong +

And I learned how to get along

+
+ And so you're back +
+ """ + + self.assertXMLEqual(contents, expected) + + def test_replace_root_node_tag(self): + """ + Root node IS targeted by //NODE_TAG in xpath + """ + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+ Inner Form
+ + + +
+ Form replacer +
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+ + Form replacer +
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_replace_root_node_tag_in_primary(self): + """ + Root node IS targeted by //NODE_TAG in xpath + """ + self.maxDiff = None + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+ Inner Form
+ +
+ +
Form replacer
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+ Inner Form
+ +
+ Form replacer +
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_inherit_primary_replace_debug(self): + """ + The inheriting template has got both its own defining attrs + and new ones if one is to replace its defining root node + """ + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
+ And I grew strong +

And I learned how to get along

+
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+
+
+ And I grew strong +

And I learned how to get along

+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_replace_in_nodebug_mode1(self): + """Comments already in the arch are ignored""" + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
+ + And I grew strong +

And I learned how to get along

+ And so you're back +
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=False) + expected = b""" + +
+ And I grew strong +

And I learned how to get along

+ And so you're back +
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_inherit_from_dotted_tname_1(self): + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
+ And I grew strong +

And I learned how to get along

+
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+
+
+ And I grew strong +

And I learned how to get along

+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_inherit_from_dotted_tname_2(self): + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
+ And I grew strong +

And I learned how to get along

+
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+
+
+ And I grew strong +

And I learned how to get along

+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_inherit_from_dotted_tname_2bis(self): + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
+ And I grew strong +

And I learned how to get along

+
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+
+
+ And I grew strong +

And I learned how to get along

+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_inherit_from_dotted_tname_2ter(self): + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+ + +
+ And I grew strong +

And I learned how to get along

+
+
+
+
+ """, + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+
+
+ And I grew strong +

And I learned how to get along

+
+
+ """ + + self.assertXMLEqual(contents, expected) + + def test_inherit_from_dotted_tname_3(self): + self.modules = [ + ('module_1_file_1', None, 'module_1'), + ('module_2_file_1', None, 'module_2'), + ] + self.template_files = { + 'module_1_file_1': b""" + +
+
At first I was afraid
+
+
+ """, + + 'module_2_file_1': b""" + + + +
+ And I grew strong +

And I learned how to get along

+
+
+
+
+ """ + } + + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + expected = b""" + +
+
At first I was afraid
+
+
+ And I grew strong +

And I learned how to get along

+
+
+ """ + + self.assertXMLEqual(contents, expected) + + +@tagged('-standard', 'static_templates_performance') +class TestStaticInheritancePerformance(TestStaticInheritanceCommon): + def _sick_script(self, nMod, nFilePerMod, nTemplatePerFile, stepInheritInModule=2, stepInheritPreviousModule=3): + """ + Make a sick amount of templates to test perf + nMod modules + each module: has nFilesPerModule files, each of which contains nTemplatePerFile templates + """ + self.modules = [] + self.template_files = {} + number_templates = 0 + for m in range(nMod): + for f in range(nFilePerMod): + mname = 'mod_%s' % m + fname = 'mod_%s_file_%s' % (m, f) + self.modules.append((fname, None, mname)) + + _file = '' + + for t in range(nTemplatePerFile): + _template = '' + if t % stepInheritInModule or t % stepInheritPreviousModule or t == 0: + _template += """ +
+
Parent
+
+ """ + + elif not t % stepInheritInModule and t >= 1: + _template += """ +
+ +
Sick XPath
+
+
+ """ + + elif not t % stepInheritPreviousModule and m >= 1: + _template += """ +
+ +
Mental XPath
+
+
+ """ + if _template: + number_templates += 1 + + _template_number = 1000 * f + t + _file += _template % { + 't_number': _template_number, + 'm_number': m, + 't_inherit': _template_number - 1, + 't_module_inherit': _template_number, + 'm_module_inherit': m - 1, + } + _file += '
' + + self.template_files[fname] = _file.encode() + self.assertEqual(number_templates, nMod * nFilePerMod * nTemplatePerFile) + + def test_static_templates_treatment_linearity(self): + # With 2500 templates for starters + nMod, nFilePerMod, nTemplatePerFile = 50, 5, 10 + self._sick_script(nMod, nFilePerMod, nTemplatePerFile) + + before = datetime.now() + contents = HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + after = datetime.now() + delta2500 = after - before + _logger.runbot('Static Templates Inheritance: 2500 templates treated in %s seconds' % delta2500.total_seconds()) + + whole_tree = etree.fromstring(contents) + self.assertEqual(len(whole_tree), nMod * nFilePerMod * nTemplatePerFile) + + # With 25000 templates next + nMod, nFilePerMod, nTemplatePerFile = 50, 5, 100 + self._sick_script(nMod, nFilePerMod, nTemplatePerFile) + + before = datetime.now() + HomeStaticTemplateHelpers.get_qweb_templates(addons=self._get_module_names(), debug=True) + after = datetime.now() + delta25000 = after - before + + time_ratio = delta25000.total_seconds() / delta2500.total_seconds() + _logger.runbot('Static Templates Inheritance: 25000 templates treated in %s seconds' % delta25000.total_seconds()) + _logger.runbot('Static Templates Inheritance: Computed linearity ratio: %s' % time_ratio) + self.assertLessEqual(time_ratio, 12) -- cgit v1.2.3