Parallel test execution with py.test

Patch adds ability to execute test run distributed over
several processes, each one with isolated database.

Assumptions:
- nailgun user, requires createdb permission, if not please precreate
  databases in format described below
- postgres database will be used for initial connection
- for environment where createdb can not be granted, like ci
  operator need to create several databases, nailgun[0-7],
  count of databases should be equal to TEST_WORKERS variable
- If no TEST_WORKERS provided - default database name will be used,
  it is almost every time nailgun, but you can overwrite it with
  TEST_NAILGUN_DB env variable

To execute tests on your local environment:
  py.test -n 4 nailgun/tests/

DocImpact
Partial-Bug: 1388751
Change-Id: I6037108f1888b61f971a10db5209b20712467173
This commit is contained in:
Dima Shulyak 2014-11-07 17:01:18 +02:00 committed by Dmitry Shulyak
parent 35946b1f22
commit 6b01a6c7d2
4 changed files with 64 additions and 2 deletions

55
nailgun/conftest.py Normal file
View File

@ -0,0 +1,55 @@
# Copyright 2014 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import re
from psycopg2 import connect
from nailgun.settings import settings
def pytest_addoption(parser):
parser.addoption("--dbname", default=settings.DATABASE['name'],
help="Overwrite database name")
def pytest_configure(config):
db_name = config.getoption('dbname')
if hasattr(config, 'slaveinput'):
#slaveid have next format gw1
#it is internal pytest thing, and we dont want to use it
uid = re.search(r'\d+', config.slaveinput['slaveid']).group(0)
db_name = '{0}{1}'.format(db_name, uid)
connection = connect(
dbname='postgres', user=settings.DATABASE['user'],
host=settings.DATABASE['host'],
password=settings.DATABASE['passwd'])
cursor = connection.cursor()
if not_present(cursor, db_name):
create_database(connection, cursor, db_name)
settings.DATABASE['name'] = db_name
def create_database(connection, cursor, name):
connection.set_isolation_level(0)
cursor.execute('create database {0}'.format(name))
connection.set_isolation_level(1)
cursor.close()
connection.close()
def not_present(cur, name):
cur.execute('select datname from pg_database;')
db_list = cur.fetchall()
return all([name not in row for row in db_list])

View File

@ -16,3 +16,5 @@ tox==1.7.1
webtest==2.0.14
pyprof2calltree==1.3.2
gprof2dot==2014.09.29
pytest
pytest-xdist

View File

@ -9,7 +9,7 @@ install_command = pip install {packages}
setenv = VIRTUAL_ENV={envdir}
deps = -r{toxinidir}/test-requirements.txt
commands =
nosetests {posargs:nailgun/test}
py.test {posargs:nailgun/test}
[tox:jenkins]
downloadcache = ~/cache/pip

View File

@ -97,6 +97,7 @@ UI_SERVER_PORT=${UI_SERVER_PORT:-5544}
FUELCLIENT_SERVER_PORT=${FUELCLIENT_SERVER_PORT:-8003}
TEST_NAILGUN_DB=${TEST_NAILGUN_DB:-nailgun}
ARTIFACTS=${ARTIFACTS:-`pwd`/test_run}
TEST_WORKERS=${TEST_WORKERS:-0}
mkdir -p $ARTIFACTS
# disabled/enabled flags that are setted from the cli.
@ -246,11 +247,15 @@ function run_nailgun_tests {
local result=0
local artifacts=$ARTIFACTS/nailgun
local config=$artifacts/test.yaml
local options="-vv --junit-xml $NAILGUN_XUNIT"
prepare_artifacts $artifacts $config
if [ $# -ne 0 ]; then
TESTS="$@"
fi
if [ ! $TEST_WORKERS -eq 0 ]; then
options+=" -n $TEST_WORKERS"
fi
# prepare database
dropdb $config
syncdb $config false
@ -258,7 +263,7 @@ function run_nailgun_tests {
pushd $ROOT/nailgun >> /dev/null
# # run tests
NAILGUN_CONFIG=$config \
tox -epy26 -- -vv $testropts $TESTS --xunit-file $NAILGUN_XUNIT || result=1
tox -epy26 -- $options $TESTS || result=1
popd >> /dev/null
return $result
}