Skip to content

Commit 9ee223f

Browse files
committed
Add support for distributed run
When tests are distributed, a copy of the database is created for each worker at the start of the test session. This is useful to avoid concurrent access to the same database, which can lead to deadlocks. The provided database is therefore used only as template. At the end of the tests, all the created databases are dropped.
1 parent b4e05a5 commit 9ee223f

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

README.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,5 @@ You can use the ``ODOO_RC`` environment variable using an odoo configuration fil
5151
export ODOO_RC=/path/to/odoo/config.cfg
5252
pytest ...
5353

54+
The plugin is also compatible with distributed run provided by the `pytest-xdist <https://pypi.org/project/pytest-xdist/>`_ library. When tests are distributed, a copy of the database is created for each worker at the start of the test session.
55+
This is useful to avoid concurrent access to the same database, which can lead to deadlocks. The provided database is therefore used only as template. At the end of the tests, all the created databases are dropped.

pytest_odoo.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import os
99
import signal
1010
import threading
11+
from contextlib import contextmanager
1112
from pathlib import Path
1213
from typing import Optional
1314

@@ -110,6 +111,30 @@ def load_http(request):
110111
signal.signal(signal.SIGINT, signal.default_int_handler)
111112

112113

114+
@contextmanager
115+
def _worker_db_name():
116+
# This method ensure that if tests are ran in a distributed way
117+
# thanks to the use of pytest-xdist addon, each worker will use
118+
# a specific copy of the initial database to run their tests.
119+
# In this way we prevent deadlock errors.
120+
xdist_worker = os.getenv("PYTEST_XDIST_WORKER")
121+
original_db_name = db_name = odoo.tests.common.get_db_name()
122+
try:
123+
if xdist_worker:
124+
db_name = f"{original_db_name}-{xdist_worker}"
125+
ret = os.system(f"psql -lqt | cut -d \| -f 1 | grep -w {db_name}")
126+
if ret == 0:
127+
os.system(f"dropdb {db_name}")
128+
os.system(f"createdb -T {original_db_name} {db_name}")
129+
odoo.tools.config["db_name"] = db_name
130+
yield db_name
131+
finally:
132+
if db_name != original_db_name:
133+
odoo.sql_db.close_db(db_name)
134+
os.system(f"dropdb {db_name}")
135+
odoo.tools.config["db_name"] = original_db_name
136+
137+
113138
@pytest.fixture(scope='session', autouse=True)
114139
def load_registry():
115140
# Initialize the registry before running tests.
@@ -121,7 +146,9 @@ def load_registry():
121146
# Finally we enable `testing` flag on current thread
122147
# since Odoo sets it when loading test suites.
123148
threading.current_thread().testing = True
124-
odoo.registry(odoo.tests.common.get_db_name())
149+
with _worker_db_name() as db_name:
150+
odoo.registry(db_name)
151+
yield
125152

126153

127154
@pytest.fixture(scope='module', autouse=True)

0 commit comments

Comments
 (0)