From 526205f7aec98030606f16ba871dbc96dd9f56cc Mon Sep 17 00:00:00 2001 From: Mathieu Benoit Date: Thu, 20 Nov 2025 02:44:44 -0500 Subject: [PATCH] [FIX] script test: async adapt python 3.12, support test odoo 18 erplibre --- conf/make.code_generator.Makefile | 9 + script/code_generator/search_class_model.py | 7 +- script/lib_asyncio.py | 67 +++++--- script/test/config_testcase.odoo18.0.json | 173 ++++++++++++++++++++ script/test/run_parallel_test.py | 8 +- 5 files changed, 228 insertions(+), 36 deletions(-) create mode 100644 script/test/config_testcase.odoo18.0.json diff --git a/conf/make.code_generator.Makefile b/conf/make.code_generator.Makefile index 751644c..0dbcb3f 100644 --- a/conf/make.code_generator.Makefile +++ b/conf/make.code_generator.Makefile @@ -242,6 +242,15 @@ test_code_generator_code_template_demo_portal: ./script/code_generator/search_class_model.py --quiet -d ./odoo$(ODOO_VERSION)/addons/TechnoLibre_odoo-code-generator-template/demo_portal -t ./odoo$(ODOO_VERSION)/addons/TechnoLibre_odoo-code-generator-template/code_generator_template_demo_portal --with_inherit ./script/code_generator/install_and_test_code_generator.sh test_template code_generator_template_demo_portal ./odoo$(ODOO_VERSION)/addons/TechnoLibre_odoo-code-generator-template code_generator_demo_portal +.PHONY: test_code_generator_code_template_demo_internal +test_code_generator_code_template_demo_internal: + #./script/code_generator/check_git_change_code_generator.sh ./odoo$(ODOO_VERSION)/addons/TechnoLibre_odoo-code-generator-template + ./script/database/db_restore.py --database test_template + ./script/addons/install_addons_dev.sh test_template demo_internal + #./script/addons/install_addons_dev.sh test_template code_generator_template_demo_internal + ./script/code_generator/search_class_model.py --quiet -d ./odoo$(ODOO_VERSION)/addons/TechnoLibre_odoo-code-generator-template/demo_internal -t ./odoo$(ODOO_VERSION)/addons/TechnoLibre_odoo-code-generator-template/code_generator_template_demo_internal + ./script/code_generator/install_and_test_code_generator.sh test_template code_generator_template_demo_internal ./odoo$(ODOO_VERSION)/addons/TechnoLibre_odoo-code-generator-template code_generator_demo_internal + .PHONY: test_code_generator_code_template_demo_internal_inherit test_code_generator_code_template_demo_internal_inherit: ./script/code_generator/check_git_change_code_generator.sh ./odoo$(ODOO_VERSION)/addons/TechnoLibre_odoo-code-generator-template diff --git a/script/code_generator/search_class_model.py b/script/code_generator/search_class_model.py index 1b8f92c..88e0bc5 100755 --- a/script/code_generator/search_class_model.py +++ b/script/code_generator/search_class_model.py @@ -311,16 +311,11 @@ def main(): lst_model_inherit_name.remove(ignored_inherit) models_inherit_name = "; ".join(lst_model_inherit_name) if not config.json: - if not models_name: - _logger.warning(f"Missing models class in {config.directory}") - elif not config.quiet: + if not config.quiet: # _logger.info(models_name) print(models_name) print(models_inherit_name) else: - if config.show_error_json and not models_name: - _logger.warning(f"Missing models class in {config.directory}") - if config.format_json: output = json.dumps(dct_model, indent=4, sort_keys=True) else: diff --git a/script/lib_asyncio.py b/script/lib_asyncio.py index 36843f2..661a59d 100644 --- a/script/lib_asyncio.py +++ b/script/lib_asyncio.py @@ -5,7 +5,10 @@ import asyncio from collections import deque -import uvloop +try: + import uvloop +except ImportError: + uvloop = None async def run_in_serial(task_list): @@ -95,40 +98,54 @@ def print_summary_task(task_list, lst_task_name=None): def execute(config, lst_task, use_uvloop=False): error_detected = False return_value = None - if not config.no_parallel and asyncio.get_event_loop().is_closed(): - asyncio.set_event_loop(asyncio.new_event_loop()) + # --- Mode 1 : pas de parallélisme → déjà OK avec asyncio.run --- if config.no_parallel: - return_value = asyncio.run(run_in_serial(lst_task)) - elif config.max_process: + # run_in_serial doit être une coroutine (async def) + try: + if use_uvloop and uvloop is not None: + # À faire AVANT la création de la loop + asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) + return_value = asyncio.run(run_in_serial(lst_task)) + except Exception as e: + error_detected = True + print(e) + return return_value, error_detected + + # --- Mode 2 : AsyncioPool (on suppose qu'il gère sa loop lui-même) --- + if config.max_process: pool = AsyncioPool(config.max_process) for task in lst_task: pool.add_coro(task) try: + # API existante, on ne touche pas return_value = pool.run_until_complete() - finally: - pool.close() - else: - # Use maximal resource - if use_uvloop: - uvloop.install() - loop = asyncio.get_event_loop() - # Can fix when cannot attach child to loop - # if sys.platform != "win32": - # policy = asyncio.get_event_loop_policy() - # watcher = asyncio.SafeChildWatcher() - # watcher.attach_loop(loop) - # policy.set_child_watcher(watcher) - if config.debug: - loop.set_debug(True) - try: - commands = asyncio.gather(*lst_task) - return_value = loop.run_until_complete(commands) - except RuntimeError as e: + except Exception as e: error_detected = True print(e) finally: - loop.close() + pool.close() + return return_value, error_detected + + # --- Mode 3 : utilisation maximale des ressources avec asyncio.gather --- + async def _run_max_resources(tasks, debug: bool): + if debug: + loop = asyncio.get_running_loop() + loop.set_debug(True) + # tasks doit être une liste de coroutines + results = await asyncio.gather(*tasks) + return results + + try: + if use_uvloop and uvloop is not None: + asyncio.set_event_loop_policy(uvloop.EventLoopPolicy()) + return_value = asyncio.run(_run_max_resources(lst_task, config.debug)) + except RuntimeError as e: + # par ex. si tu appelles ça depuis un environnement où il y a + # déjà une loop (Jupyter, certains frameworks) + error_detected = True + print(e) + return return_value, error_detected diff --git a/script/test/config_testcase.odoo18.0.json b/script/test/config_testcase.odoo18.0.json new file mode 100644 index 0000000..7cc5db2 --- /dev/null +++ b/script/test/config_testcase.odoo18.0.json @@ -0,0 +1,173 @@ +{ + "lst_test": [ + { + "run_command": true, + "test_name": "helloworld_test", + "sequence": 10, + "script": "./test/code_generator/hello_world.sh", + "restore_db_image_name": "odoo18.0_base", + "note": "Test helloword_test Will cause conflict with the other because write in code_generator_demo/hooks.py" + }, + { + "run_test_exec": true, + "test_name": "code_generator_theme_test", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "theme_website_demo_code_generator", + "tested_module": "code_generator_demo_theme_website", + "restore_db_image_name": "odoo18.0_base" + }, + { + "run_test_exec": true, + "disable": true, + "test_name": "code_generator_demo_test", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "code_generator_demo", + "tested_module": "code_generator_demo", + "restore_db_image_name": "odoo18.0_base" + }, + { + "run_test_exec": true, + "test_name": "code_generator_data_test", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "demo_helpdesk_data", + "tested_module": "code_generator_demo_export_helpdesk", + "restore_db_image_name": "odoo18.0_base" + }, + { + "run_test_exec": true, + "test_name": "code_generator_data_part_2_test", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "demo_website_data", + "tested_module": "code_generator_demo_export_website", + "restore_db_image_name": "odoo18.0_base", + "note": "Merge to code_generator_data_test when fix double export data." + }, + { + "run_test_exec": true, + "test_name": "code_generator_inherit_test", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "demo_internal_inherit", + "tested_module": "code_generator_demo_internal_inherit", + "restore_db_image_name": "odoo18.0_base" + }, + { + "run_test_exec": true, + "test_name": "code_generator_template_demo_internal", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "code_generator_demo_internal", + "tested_module": "code_generator_template_demo_internal", + "search_class_module": "demo_internal", + "init_module_name": "demo_internal", + "restore_db_image_name": "odoo18.0_base" + }, + { + "run_test_exec": true, + "test_name": "code_generator_template_demo_portal", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "code_generator_demo_portal", + "tested_module": "code_generator_template_demo_portal", + "search_class_module": "demo_portal", + "init_module_name": "demo_portal", + "restore_db_image_name": "odoo18.0_base" + }, + { + "run_test_exec": true, + "disable": true, + "test_name": "mariadb_test_template", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "code_generator_demo_mariadb_sql_example_1", + "tested_module": "code_generator_template_demo_mariadb_sql_example_1", + "search_class_module": "demo_mariadb_sql_example_1", + "init_module_name": "code_generator_portal,demo_mariadb_sql_example_1", + "restore_db_image_name": "odoo18.0_base" + }, + { + "run_test_exec": true, + "disable": true, + "test_name": "mariadb_test_migrator", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "demo_mariadb_sql_example_1", + "tested_module": "code_generator_migrator_demo_mariadb_sql_example_1", + "script_after_init_check": "./script/database/restore_mariadb_sql_example_1.sh", + "init_module_name": "code_generator_portal", + "restore_db_image_name": "odoo18.0_base" + }, + { + "run_test_exec": true, + "disable": true, + "test_name": "mariadb_test_code_generator", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "demo_mariadb_sql_example_1", + "tested_module": "code_generator_demo_mariadb_sql_example_1", + "init_module_name": "code_generator_portal", + "restore_db_image_name": "odoo18.0_base" + }, + { + "run_test_exec": true, + "test_name": "code_generator_template_demo_internal_inherit", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "code_generator_demo_internal_inherit", + "tested_module": "code_generator_template_demo_internal_inherit", + "search_class_module": "demo_internal_inherit", + "init_module_name": "demo_internal_inherit", + "restore_db_image_name": "odoo18.0_base" + }, + { + "run_test_exec": true, + "disable": true, + "test_name": "code_generator_template_demo_sysadmin_cron", + "path_module_check": "./odoo18.0/addons/OCA_server-tools", + "generated_module": "code_generator_auto_backup", + "generated_path": "./odoo18.0/addons/OCA_server-tools/", + "tested_module": "code_generator_template_demo_sysadmin_cron", + "search_class_module": "auto_backup", + "init_module_name": "auto_backup", + "install_path": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "restore_db_image_name": "odoo18.0_base" + }, + { + "run_test_exec": true, + "disable": true, + "test_name": "code_generator_export_website_attachments_test", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "demo_website_attachments_data", + "tested_module": "code_generator_demo_export_website_attachments", + "restore_db_image_name": "test_website_attachments" + }, + { + "run_test_exec": true, + "disable": true, + "test_name": "code_generator_demo_generic_test", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "demo_internal,demo_portal", + "tested_module": "code_generator_demo_internal,code_generator_demo_portal", + "restore_db_image_name": "odoo18.0_base" + }, + { + "run_test_exec": true, + "test_name": "code_generator_website_snippet_test", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "generated_module": "demo_website_leaflet,demo_website_snippet,demo_website_multiple_snippet", + "tested_module": "code_generator_demo_website_leaflet,code_generator_demo_website_snippet,code_generator_demo_website_multiple_snippet", + "file_to_restore": "demo_portal/i18n/demo_portal.pot,demo_portal/i18n/fr_CA.po", + "file_to_restore_origin": true, + "restore_db_image_name": "odoo18.0_base", + "note": "Because code_generator_demo_website_multiple_snippet depend on code_generator_demo_portal, it will execute it and this delete file demo_portal/i18n/demo_portal.pot and demo_portal/i18n/fr_CA.po" + }, + { + "run_test_exec": true, + "test_name": "demo_test", + "path_module_check": "./odoo18.0/addons/TechnoLibre_odoo-code-generator-template", + "init_module_name": "demo_helpdesk_data,demo_internal,demo_internal_inherit,demo_mariadb_sql_example_1,demo_portal,demo_website_data,demo_website_leaflet,demo_website_snippet", + "restore_db_image_name": "odoo18.0_base" + }, + { + "run_test_exec": true, + "test_name": "code_generator_auto_backup_test", + "path_module_check": "./odoo18.0/addons/OCA_server-tools/auto_backup", + "generated_module": "auto_backup", + "tested_module": "code_generator_auto_backup", + "restore_db_image_name": "odoo18.0_base" + } + ] +} diff --git a/script/test/run_parallel_test.py b/script/test/run_parallel_test.py index 837ab7b..6fd9966 100755 --- a/script/test/run_parallel_test.py +++ b/script/test/run_parallel_test.py @@ -790,7 +790,7 @@ async def test_exec( return test_result, test_status, test_name, total_time -def check_git_change(): +async def check_git_change(): """ return True if success """ @@ -810,10 +810,8 @@ def check_git_change(): test_name="Init check_git_change OCA_server-tools", ), ] - commands = asyncio.gather(*task_list) - tpl_result = loop.run_until_complete(commands) + tpl_result = await asyncio.gather(*task_list) status = any([a[1] for a in tpl_result]) - loop.close() return not status @@ -962,7 +960,7 @@ def main(): config = get_config() start_time = time.time() if not config.ignore_init_check_git: - success = check_git_change() + success = asyncio.run(check_git_change()) else: success = True status = False