Commit e30ad2c1 authored by Georges Racinet's avatar Georges Racinet 🦑
Browse files

Ability to run the tests in concurrent (multithreaded) mode

Since 14a569275d1c, the name of projects used in fixtures are
unique, hence it's in theory possible to run the tests in parallel.

In practice, as of this writing, some of our tests are flaky when
run concurrently.

We should not run the tests with several processes, because each will
want to set the GitLab user tokens independently in the `heptapod`
session scoped fixture. However, in multithreaded mode, we can
guarantee that the `heptapod` fixture gets set up exactly once.

Besides being faster, this is interesting to exert Heptapod on the current
GitLab 12, by upping the chances of race conditions, notably in the
asynchronous handling of post-receives.
parent 19369d78a14e
......@@ -96,6 +96,14 @@ These are available in all cases
set for the `root` user. The default value is the same as with the GitLab
Development Kit (GDK).
### Running the tests concurrently
Use the `---tests-per-worker` option only.
Do *NOT* use the `--workers` option: it would setup the `Heptapod` session
fixture several times, leading to problems with GitLab user tokens and other
shared data that are session-local.
### Testing a Docker container
Being the default, this is the simplest. If you followed the default namings
......
......@@ -2,6 +2,7 @@
import contextlib
import logging
import pytest
import threading
import time
import os
......@@ -82,8 +83,20 @@ def pytest_collection_modifyitems(config, items):
item.add_marker(skip_reverse_call)
heptapod_instance = None
lock = threading.Lock()
active_threads = 0
@pytest.fixture(scope="session")
def heptapod(pytestconfig):
global lock
global active_threads
global heptapod_instance
lock.acquire()
active_threads += 1
url = pytestconfig.getoption('heptapod_url')
common = dict(
url=url,
......@@ -96,23 +109,37 @@ def heptapod(pytestconfig):
wait_after_first_response=pytestconfig.getoption(
'heptapod_wait_after_first_response'),
)
if pytestconfig.getoption('heptapod_source_install'):
repos_root = pytestconfig.getoption('heptapod_repositories_root')
heptapod = SourceHeptapod(repositories_root=repos_root, **common)
elif pytestconfig.getoption('heptapod_remote'):
heptapod = Heptapod(**common)
else:
ct = pytestconfig.getoption('heptapod_docker_container')
heptapod = DockerHeptapod(docker_container=ct, **common)
# make tests fully independent of current user settings
os.environ['HGRCPATH'] = ''
try:
if active_threads == 1: # we're the first
if pytestconfig.getoption('heptapod_source_install'):
repos_root = pytestconfig.getoption(
'heptapod_repositories_root')
heptapod = SourceHeptapod(repositories_root=repos_root,
**common)
elif pytestconfig.getoption('heptapod_remote'):
heptapod = Heptapod(**common)
else:
ct = pytestconfig.getoption('heptapod_docker_container')
heptapod = DockerHeptapod(docker_container=ct, **common)
# make tests fully independent of current user settings
os.environ['HGRCPATH'] = ''
heptapod.prepare(pytestconfig.getoption('heptapod_root_password'))
heptapod_instance = heptapod
finally:
lock.release()
yield heptapod_instance
lock.acquire()
active_threads -= 1
try:
heptapod.prepare(pytestconfig.getoption('heptapod_root_password'))
yield heptapod
if active_threads == 0:
heptapod_instance.close()
finally:
heptapod.close()
lock.release()
@contextlib.contextmanager
......
......@@ -7,5 +7,6 @@ deps =
docker
pytest
selenium
pytest-parallel
commands =
py.test {posargs}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment