From 36f136411f766427ede4a3dfcb5cb3c28c87e61e Mon Sep 17 00:00:00 2001 From: "Laurent Mignon (ACSONE)" Date: Tue, 8 Oct 2024 12:10:05 +0200 Subject: [PATCH 1/3] Ensure filestore is shared when ran in a distributed way When test are ran in a distributed way, we must ensure that each worker has access to the original filestore even if they uses a copy of the original database. This is done by patching the the filestore method of the odoo configuration to point to the original filestore and avoid to copy the original filestore for each created database --- pytest_odoo.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/pytest_odoo.py b/pytest_odoo.py index ad896f9..cb36180 100644 --- a/pytest_odoo.py +++ b/pytest_odoo.py @@ -9,6 +9,7 @@ import signal import threading from contextlib import contextmanager +from unittest import mock from pathlib import Path from typing import Optional @@ -110,6 +111,21 @@ def load_http(request): odoo.service.server.start(stop=True) signal.signal(signal.SIGINT, signal.default_int_handler) +@contextmanager +def _shared_filestore(original_db_name, db_name): + # This method ensure that if tests are ran in a distributed way + # we share the filestore between the original database and the + # copy of the database. This is useful to avoid copying the + # filestore for each worker. + # This is done by patching the filestore method of the odoo + # configuration to point to the original filestore. + if original_db_name == db_name: + yield + return + with mock.patch.object(odoo.tools.config, "filestore") as filestore: + fs_path = os.path.join(odoo.tools.config['data_dir'], 'filestore', original_db_name) + filestore.return_value = fs_path + yield @contextmanager def _worker_db_name(): @@ -125,7 +141,8 @@ def _worker_db_name(): os.system(f"dropdb {db_name} --if-exists") os.system(f"createdb -T {original_db_name} {db_name}") odoo.tools.config["db_name"] = db_name - yield db_name + with _shared_filestore(original_db_name, db_name): + yield db_name finally: if db_name != original_db_name: odoo.sql_db.close_db(db_name) From 1c9d17aec2cba837c02a307ff2bc4d7db38ddf54 Mon Sep 17 00:00:00 2001 From: "Laurent Mignon (ACSONE)" Date: Tue, 8 Oct 2024 14:07:13 +0200 Subject: [PATCH 2/3] Ensure dbfilter reference the database to use for tests --- pytest_odoo.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pytest_odoo.py b/pytest_odoo.py index cb36180..526710e 100644 --- a/pytest_odoo.py +++ b/pytest_odoo.py @@ -141,6 +141,7 @@ def _worker_db_name(): os.system(f"dropdb {db_name} --if-exists") os.system(f"createdb -T {original_db_name} {db_name}") odoo.tools.config["db_name"] = db_name + odoo.tools.config["dbfilter"] = f"^{db_name}$" with _shared_filestore(original_db_name, db_name): yield db_name finally: @@ -148,6 +149,7 @@ def _worker_db_name(): odoo.sql_db.close_db(db_name) os.system(f"dropdb {db_name}") odoo.tools.config["db_name"] = original_db_name + odoo.tools.config["dbfilter"] = f"^{original_db_name}$" @pytest.fixture(scope='session', autouse=True) From f9bd2d8f46875c8087525d00f17c7816c6cc6e90 Mon Sep 17 00:00:00 2001 From: "Laurent Mignon (ACSONE)" Date: Tue, 8 Oct 2024 14:13:10 +0200 Subject: [PATCH 3/3] Uses subprocess lib to call shell command This will prevent error in case the db name is not compatible with the shell separators --- pytest_odoo.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pytest_odoo.py b/pytest_odoo.py index 526710e..2d4aed5 100644 --- a/pytest_odoo.py +++ b/pytest_odoo.py @@ -7,6 +7,7 @@ import ast import os import signal +import subprocess import threading from contextlib import contextmanager from unittest import mock @@ -138,8 +139,8 @@ def _worker_db_name(): try: if xdist_worker: db_name = f"{original_db_name}-{xdist_worker}" - os.system(f"dropdb {db_name} --if-exists") - os.system(f"createdb -T {original_db_name} {db_name}") + subprocess.run(["dropdb", db_name, "--if-exists"], check=True) + subprocess.run(["createdb", "-T", original_db_name, db_name], check=True) odoo.tools.config["db_name"] = db_name odoo.tools.config["dbfilter"] = f"^{db_name}$" with _shared_filestore(original_db_name, db_name): @@ -147,7 +148,7 @@ def _worker_db_name(): finally: if db_name != original_db_name: odoo.sql_db.close_db(db_name) - os.system(f"dropdb {db_name}") + subprocess.run(["dropdb", db_name, "--if-exists"], check=True) odoo.tools.config["db_name"] = original_db_name odoo.tools.config["dbfilter"] = f"^{original_db_name}$"