Tests - parallelize python tests w/ pytest-xdist

This commit is contained in:
Sam 2022-11-19 20:17:58 +01:00
parent df7532a633
commit 872105e2d3
11 changed files with 105 additions and 11 deletions

2
.gitignore vendored
View File

@ -8,7 +8,7 @@ Makefile.custom.config
__pycache__ __pycache__
uploads uploads
.cache .cache
.coverage .coverage*
coverage.xml coverage.xml
.env .env
.mypy_cache .mypy_cache

View File

@ -232,6 +232,8 @@ test-e2e-client:
E2E_ARGS=client $(PYTEST) e2e --driver firefox $(PYTEST_ARGS) E2E_ARGS=client $(PYTEST) e2e --driver firefox $(PYTEST_ARGS)
test-python: test-python:
# for tests parallelization: 4 workers max.
# make test-python PYTEST_ARGS="-p no:warnings -n auto --maxprocesses=4"
$(PYTEST) fittrackee --cov-config .coveragerc --cov=fittrackee --cov-report term-missing $(PYTEST_ARGS) $(PYTEST) fittrackee --cov-config .coveragerc --cov=fittrackee --cov-report term-missing $(PYTEST_ARGS)
test-client: test-client:

View File

@ -1,5 +1,9 @@
DROP DATABASE IF EXISTS fittrackee; DROP DATABASE IF EXISTS fittrackee;
DROP DATABASE IF EXISTS fittrackee_test; DROP DATABASE IF EXISTS fittrackee_test;
DROP DATABASE IF EXISTS fittrackee_test_gw0;
DROP DATABASE IF EXISTS fittrackee_test_gw1;
DROP DATABASE IF EXISTS fittrackee_test_gw2;
DROP DATABASE IF EXISTS fittrackee_test_gw3;
DROP SCHEMA IF EXISTS fittrackee; DROP SCHEMA IF EXISTS fittrackee;
DROP USER IF EXISTS fittrackee; DROP USER IF EXISTS fittrackee;
@ -7,3 +11,7 @@ CREATE USER fittrackee WITH PASSWORD 'fittrackee';
CREATE SCHEMA fittrackee AUTHORIZATION fittrackee; CREATE SCHEMA fittrackee AUTHORIZATION fittrackee;
CREATE DATABASE fittrackee OWNER fittrackee; CREATE DATABASE fittrackee OWNER fittrackee;
CREATE DATABASE fittrackee_test OWNER fittrackee; CREATE DATABASE fittrackee_test OWNER fittrackee;
CREATE DATABASE fittrackee_test_gw0 OWNER fittrackee;
CREATE DATABASE fittrackee_test_gw1 OWNER fittrackee;
CREATE DATABASE fittrackee_test_gw2 OWNER fittrackee;
CREATE DATABASE fittrackee_test_gw3 OWNER fittrackee;

View File

@ -10,6 +10,12 @@ if os.getenv('APP_SETTINGS') == 'fittrackee.config.TestingConfig':
else: else:
broker = RedisBroker broker = RedisBroker
XDIST_WORKER = (
f"_{os.getenv('PYTEST_XDIST_WORKER')}"
if os.getenv('PYTEST_XDIST_WORKER')
else ''
)
class BaseConfig: class BaseConfig:
@ -74,7 +80,13 @@ class DevelopmentConfig(BaseConfig):
class TestingConfig(BaseConfig): class TestingConfig(BaseConfig):
DEBUG = True DEBUG = True
TESTING = True TESTING = True
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_TEST_URL') SQLALCHEMY_DATABASE_URI = (
os.environ.get('DATABASE_TEST_URL', '') + XDIST_WORKER
)
UPLOAD_FOLDER = os.path.join(
os.getenv('UPLOAD_FOLDER', current_app.root_path),
'uploads' + XDIST_WORKER,
)
SECRET_KEY = 'test key' # nosec SECRET_KEY = 'test key' # nosec
BCRYPT_LOG_ROUNDS = 4 BCRYPT_LOG_ROUNDS = 4
TOKEN_EXPIRATION_DAYS = 0 TOKEN_EXPIRATION_DAYS = 0

View File

@ -41,7 +41,11 @@ class TestTestingConfig:
app.config.from_object('fittrackee.config.TestingConfig') app.config.from_object('fittrackee.config.TestingConfig')
assert app.config['SQLALCHEMY_DATABASE_URI'] == os.environ.get( assert app.config['SQLALCHEMY_DATABASE_URI'] == os.environ.get(
'DATABASE_TEST_URL' 'DATABASE_TEST_URL', ''
) + (
f"_{os.getenv('PYTEST_XDIST_WORKER')}"
if os.getenv('PYTEST_XDIST_WORKER')
else ''
) )
def test_it_does_not_preserve_context_on_exception( def test_it_does_not_preserve_context_on_exception(

View File

@ -8,6 +8,7 @@ os.environ['APP_SETTINGS'] = 'fittrackee.config.TestingConfig'
# to avoid resetting dev database during tests # to avoid resetting dev database during tests
os.environ['DATABASE_URL'] = os.environ['DATABASE_TEST_URL'] os.environ['DATABASE_URL'] = os.environ['DATABASE_TEST_URL']
TEMP_FOLDER = '/tmp/FitTrackee' TEMP_FOLDER = '/tmp/FitTrackee'
os.makedirs(TEMP_FOLDER, exist_ok=True)
os.environ['UPLOAD_FOLDER'] = TEMP_FOLDER os.environ['UPLOAD_FOLDER'] = TEMP_FOLDER
os.environ['APP_LOG'] = TEMP_FOLDER + '/fittrackee.log' os.environ['APP_LOG'] = TEMP_FOLDER + '/fittrackee.log'
os.environ['AUTHLIB_INSECURE_TRANSPORT'] = '1' os.environ['AUTHLIB_INSECURE_TRANSPORT'] = '1'

View File

@ -18,7 +18,11 @@ def get_app_config(
max_users: Optional[int] = None, max_users: Optional[int] = None,
) -> Optional[AppConfig]: ) -> Optional[AppConfig]:
if with_config: if with_config:
config = AppConfig() config = AppConfig.query.one_or_none()
if not config:
config = AppConfig()
db.session.add(config)
db.session.flush()
config.gpx_limit_import = 10 if max_workouts is None else max_workouts config.gpx_limit_import = 10 if max_workouts is None else max_workouts
config.max_single_file_size = ( config.max_single_file_size = (
(1 if max_single_file_size is None else max_single_file_size) (1 if max_single_file_size is None else max_single_file_size)
@ -31,7 +35,6 @@ def get_app_config(
* 1024 * 1024
) )
config.max_users = 100 if max_users is None else max_users config.max_users = 100 if max_users is None else max_users
db.session.add(config)
db.session.commit() db.session.commit()
return config return config
return None return None

View File

@ -172,7 +172,7 @@ class TestCreateOAuth2Client:
class TestOAuthCheckScopes: class TestOAuthCheckScopes:
@pytest.mark.parametrize( @pytest.mark.parametrize(
'input_scope', ['', 1, random_string(), [random_string(), 'readwrite']] 'input_scope', ['', 1, 'invalid_scope', ['invalid_scope', 'readwrite']]
) )
def test_it_raises_error_when_scope_is_invalid( def test_it_raises_error_when_scope_is_invalid(
self, input_scope: Any self, input_scope: Any
@ -184,11 +184,11 @@ class TestOAuthCheckScopes:
'input_scope,expected_scope', 'input_scope,expected_scope',
[ [
('profile:read', 'profile:read'), ('profile:read', 'profile:read'),
('profile:read ' + random_string(), 'profile:read'), ('profile:read invalid_scope:read', 'profile:read'),
('profile:write', 'profile:write'), ('profile:write', 'profile:write'),
('profile:read profile:write', 'profile:read profile:write'), ('profile:read profile:write', 'profile:read profile:write'),
( (
'profile:write profile:read ' + random_string(), 'profile:write invalid_scope:read profile:read',
'profile:write profile:read', 'profile:write profile:read',
), ),
], ],

View File

@ -1,5 +1,4 @@
from typing import Union from typing import Union
from uuid import uuid4
import pytest import pytest
@ -34,7 +33,7 @@ class TestReadableDuration:
('en', '30 seconds'), ('en', '30 seconds'),
('fr', '30 secondes'), ('fr', '30 secondes'),
(None, '30 seconds'), (None, '30 seconds'),
(uuid4().hex, '30 seconds'), ('invalid_locale', '30 seconds'),
], ],
) )
def test_it_returns_duration_in_locale( def test_it_returns_duration_in_locale(

66
poetry.lock generated
View File

@ -280,6 +280,17 @@ python-versions = ">=3.7"
[package.extras] [package.extras]
test = ["pytest (>=6)"] test = ["pytest (>=6)"]
[[package]]
name = "execnet"
version = "1.9.0"
description = "execnet: rapid multi-Python deployment"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[package.extras]
testing = ["pre-commit"]
[[package]] [[package]]
name = "flake8" name = "flake8"
version = "3.9.2" version = "3.9.2"
@ -745,6 +756,17 @@ python-versions = ">=3.6"
[package.extras] [package.extras]
twisted = ["twisted"] twisted = ["twisted"]
[[package]]
name = "psutil"
version = "5.9.4"
description = "Cross-platform lib for process and system monitoring in Python."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.extras]
test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
[[package]] [[package]]
name = "psycopg2-binary" name = "psycopg2-binary"
version = "2.9.5" version = "2.9.5"
@ -1002,6 +1024,24 @@ hjson = ["hjson"]
toml = ["toml"] toml = ["toml"]
yaml = ["PyYAML"] yaml = ["PyYAML"]
[[package]]
name = "pytest-xdist"
version = "3.0.2"
description = "pytest xdist plugin for distributed testing and loop-on-failing modes"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
execnet = ">=1.1"
psutil = {version = ">=3.0", optional = true, markers = "extra == \"psutil\""}
pytest = ">=6.2.0"
[package.extras]
psutil = ["psutil (>=3.0)"]
setproctitle = ["setproctitle"]
testing = ["filelock"]
[[package]] [[package]]
name = "python-dateutil" name = "python-dateutil"
version = "2.8.2" version = "2.8.2"
@ -1577,7 +1617,7 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools"
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.7" python-versions = "^3.7"
content-hash = "b8ef9801e4dcd04375d3a5e83303ddc8a1b65ad35a127e1e2fd115e85cbe095c" content-hash = "ae84573fe28fd08fc1a7917d20ca97f73e070a668cf0baa0ac546d3a6f7e58ae"
[metadata.files] [metadata.files]
alabaster = [ alabaster = [
@ -1840,6 +1880,10 @@ exceptiongroup = [
{file = "exceptiongroup-1.0.1-py3-none-any.whl", hash = "sha256:4d6c0aa6dd825810941c792f53d7b8d71da26f5e5f84f20f9508e8f2d33b140a"}, {file = "exceptiongroup-1.0.1-py3-none-any.whl", hash = "sha256:4d6c0aa6dd825810941c792f53d7b8d71da26f5e5f84f20f9508e8f2d33b140a"},
{file = "exceptiongroup-1.0.1.tar.gz", hash = "sha256:73866f7f842ede6cb1daa42c4af078e2035e5f7607f0e2c762cc51bb31bbe7b2"}, {file = "exceptiongroup-1.0.1.tar.gz", hash = "sha256:73866f7f842ede6cb1daa42c4af078e2035e5f7607f0e2c762cc51bb31bbe7b2"},
] ]
execnet = [
{file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"},
{file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"},
]
flake8 = [ flake8 = [
{file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"}, {file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
{file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
@ -2165,6 +2209,22 @@ prometheus-client = [
{file = "prometheus_client-0.15.0-py3-none-any.whl", hash = "sha256:db7c05cbd13a0f79975592d112320f2605a325969b270a94b71dcabc47b931d2"}, {file = "prometheus_client-0.15.0-py3-none-any.whl", hash = "sha256:db7c05cbd13a0f79975592d112320f2605a325969b270a94b71dcabc47b931d2"},
{file = "prometheus_client-0.15.0.tar.gz", hash = "sha256:be26aa452490cfcf6da953f9436e95a9f2b4d578ca80094b4458930e5f584ab1"}, {file = "prometheus_client-0.15.0.tar.gz", hash = "sha256:be26aa452490cfcf6da953f9436e95a9f2b4d578ca80094b4458930e5f584ab1"},
] ]
psutil = [
{file = "psutil-5.9.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c1ca331af862803a42677c120aff8a814a804e09832f166f226bfd22b56feee8"},
{file = "psutil-5.9.4-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:68908971daf802203f3d37e78d3f8831b6d1014864d7a85937941bb35f09aefe"},
{file = "psutil-5.9.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ff89f9b835100a825b14c2808a106b6fdcc4b15483141482a12c725e7f78549"},
{file = "psutil-5.9.4-cp27-cp27m-win32.whl", hash = "sha256:852dd5d9f8a47169fe62fd4a971aa07859476c2ba22c2254d4a1baa4e10b95ad"},
{file = "psutil-5.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:9120cd39dca5c5e1c54b59a41d205023d436799b1c8c4d3ff71af18535728e94"},
{file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6b92c532979bafc2df23ddc785ed116fced1f492ad90a6830cf24f4d1ea27d24"},
{file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:efeae04f9516907be44904cc7ce08defb6b665128992a56957abc9b61dca94b7"},
{file = "psutil-5.9.4-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:54d5b184728298f2ca8567bf83c422b706200bcbbfafdc06718264f9393cfeb7"},
{file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16653106f3b59386ffe10e0bad3bb6299e169d5327d3f187614b1cb8f24cf2e1"},
{file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54c0d3d8e0078b7666984e11b12b88af2db11d11249a8ac8920dd5ef68a66e08"},
{file = "psutil-5.9.4-cp36-abi3-win32.whl", hash = "sha256:149555f59a69b33f056ba1c4eb22bb7bf24332ce631c44a319cec09f876aaeff"},
{file = "psutil-5.9.4-cp36-abi3-win_amd64.whl", hash = "sha256:fd8522436a6ada7b4aad6638662966de0d61d241cb821239b2ae7013d41a43d4"},
{file = "psutil-5.9.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:6001c809253a29599bc0dfd5179d9f8a5779f9dffea1da0f13c53ee568115e1e"},
{file = "psutil-5.9.4.tar.gz", hash = "sha256:3d7f9739eb435d4b1338944abe23f49584bde5395f27487d2ee25ad9a8774a62"},
]
psycopg2-binary = [ psycopg2-binary = [
{file = "psycopg2-binary-2.9.5.tar.gz", hash = "sha256:33e632d0885b95a8b97165899006c40e9ecdc634a529dca7b991eb7de4ece41c"}, {file = "psycopg2-binary-2.9.5.tar.gz", hash = "sha256:33e632d0885b95a8b97165899006c40e9ecdc634a529dca7b991eb7de4ece41c"},
{file = "psycopg2_binary-2.9.5-cp310-cp310-macosx_10_15_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:0775d6252ccb22b15da3b5d7adbbf8cfe284916b14b6dc0ff503a23edb01ee85"}, {file = "psycopg2_binary-2.9.5-cp310-cp310-macosx_10_15_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:0775d6252ccb22b15da3b5d7adbbf8cfe284916b14b6dc0ff503a23edb01ee85"},
@ -2315,6 +2375,10 @@ pytest-variables = [
{file = "pytest-variables-2.0.0.tar.gz", hash = "sha256:1c9e4fc321e33be7d1b352ac9cf20fdd2c39a8e4e6fa2dcd042aaf70ed516be7"}, {file = "pytest-variables-2.0.0.tar.gz", hash = "sha256:1c9e4fc321e33be7d1b352ac9cf20fdd2c39a8e4e6fa2dcd042aaf70ed516be7"},
{file = "pytest_variables-2.0.0-py3-none-any.whl", hash = "sha256:1a24a30b7acf9654d71bcdc8b10c1eb0d81b73b3eec72d810703c522475d643b"}, {file = "pytest_variables-2.0.0-py3-none-any.whl", hash = "sha256:1a24a30b7acf9654d71bcdc8b10c1eb0d81b73b3eec72d810703c522475d643b"},
] ]
pytest-xdist = [
{file = "pytest-xdist-3.0.2.tar.gz", hash = "sha256:688da9b814370e891ba5de650c9327d1a9d861721a524eb917e620eec3e90291"},
{file = "pytest_xdist-3.0.2-py3-none-any.whl", hash = "sha256:9feb9a18e1790696ea23e1434fa73b325ed4998b0e9fcb221f16fd1945e6df1b"},
]
python-dateutil = [ python-dateutil = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},

View File

@ -59,6 +59,7 @@ pytest-flake8 = "^1.1"
pytest-isort = "^3.1" pytest-isort = "^3.1"
pytest-runner = "^6.0" pytest-runner = "^6.0"
pytest-selenium = "^2.0.1" pytest-selenium = "^2.0.1"
pytest-xdist = {extras = ["psutil"], version = "^3.0.2"}
recommonmark = "^0.7" recommonmark = "^0.7"
sphinx = "^5.1" sphinx = "^5.1"
sphinx-bootstrap-theme = "^0.8.1" sphinx-bootstrap-theme = "^0.8.1"