Use Ansible playbooks for functional testing gating

This patchset converts much of the previous logic in
functional-tests.sh into Ansible playbooks to be executed
by Zuul. This mainly includes all the Docker-related
deployment logic.

The functional-tests.sh script has been slimmed down to
just work with uwsgi so that a standalone functional
test deployment can be performed relatively easily,
mainly by developers.

Finally, py27 support for the gate has been dropped
as the Dockerfile in this project currently assumes
python3 for installing requirements and so forth,
leading to requirements issues blocking the gate.

Change-Id: I903a2845390061641d292fb0c016ba6a53723fc9
This commit is contained in:
Felipe Monteiro 2018-05-20 14:46:20 -04:00
parent 53a5145200
commit 119080b597
22 changed files with 362 additions and 122 deletions

View File

@ -16,8 +16,7 @@
- airship-deckhand-linter
- airship-deckhand-ubuntu:
voting: false
- airship-deckhand-tox-functional
- airship-deckhand-tox-functional-py35
- airship-deckhand-functional-docker-py35
gate:
jobs:
- airship-deckhand-linter
@ -27,8 +26,7 @@
# - ^.*\.rst$
# - ^doc/.*$
# - ^releasenotes/.*$
- airship-deckhand-tox-functional
- airship-deckhand-tox-functional-py35
- airship-deckhand-functional-docker-py35
- job:
name: airship-deckhand-linter
@ -64,7 +62,7 @@
- ^releasenotes/.*$
- job:
name: airship-deckhand-tox-functional-base
name: airship-deckhand-functional-docker-base
description: |
Base job for running airship-deckhand functional tests. Runs tests
against Docker image generated from source code.
@ -74,7 +72,7 @@
pre-run:
- tools/gate/playbooks/osh-infra-upgrade-host.yaml
- tools/gate/playbooks/osh-infra-deploy-docker.yaml
run: tools/gate/playbooks/run-functional-tests.yaml
run: tools/gate/playbooks/run-functional-tests-docker.yaml
required-projects:
- openstack/openstack-helm-infra
irrelevant-files:
@ -83,21 +81,12 @@
- ^releasenotes/.*$
- job:
name: airship-deckhand-tox-functional
description: |
Run tox-based functional tests for the Airship Deckhand project under
cPython version 2.7. Uses tox with the ``functional`` environment.
parent: airship-deckhand-tox-functional-base
nodeset: openstack-helm-single-node
vars:
tox_envlist: functional
- job:
name: airship-deckhand-tox-functional-py35
name: airship-deckhand-functional-docker-py35
description: |
Run tox-based functional tests for the Airship Deckhand project under
cPython version 3.5. Uses tox with the ``functional-py35`` environment.
parent: airship-deckhand-tox-functional-base
parent: airship-deckhand-functional-docker-base
nodeset: openstack-helm-single-node
vars:
tox_envlist: functional-py35
tox_envlist: functional
disable_keystone: true

View File

@ -37,7 +37,7 @@ def __create_temp_test_dir():
TEST_DIR = tempfile.mkdtemp(prefix='deckhand')
root_test_dir = os.getenv('DECKHAND_TESTS_DIR', 'gabbits')
root_test_dir = os.getenv('DECKHAND_TEST_DIR', 'gabbits')
test_files = []
for root, dirs, files in os.walk(root_test_dir):
@ -100,9 +100,12 @@ def pytest_generate_tests(metafunc):
global TEST_DIR
driver.py_test_generator(
TEST_DIR, url=os.environ['DECKHAND_TEST_URL'], host='localhost',
TEST_DIR,
url=os.environ.get('DECKHAND_TEST_URL', '127.0.0.1:9000'),
host='localhost',
# NOTE(fmontei): When there are multiple handlers listed that accept
# the same content-type, the one that is earliest in the list will be
# used. Thus, we cannot specify multiple content handlers for handling
# list/dictionary responses from the server using different handlers.
content_handlers=[MultidocJsonpaths], metafunc=metafunc)
content_handlers=[MultidocJsonpaths],
metafunc=metafunc)

View File

@ -10,7 +10,7 @@ policy_file = policy.yaml
[barbican]
[database]
connection = ${DATABASE_URL}
connection = ${AIRSHIP_DECKHAND_DATABASE_URL}
[keystone_authtoken]
# NOTE(fmontei): Values taken from clouds.yaml. Values only used for

View File

@ -38,6 +38,8 @@ function deploy_postgre {
--format='{{ .NetworkSettings.Networks.bridge.IPAddress }}' \
$POSTGRES_ID
)
echo $POSTGRES_IP
}

View File

@ -1,45 +1,24 @@
#!/usr/bin/env bash
# Script intended for running Deckhand functional tests via gabbi. Requires
# Docker CE (at least) to run.
# Script intended for running Deckhand functional tests via gabbi for
# developers. Dependencies include gabbi, pifpaf and uwsgi.
set -xe
# Meant for capturing output of Deckhand image. This requires that logging
# in the image be set up to pipe everything out to stdout/stderr.
STDOUT=$(mktemp)
# NOTE(fmontei): `DECKHAND_IMAGE` should only be specified if the desire is to
# run Deckhand functional tests against a specific Deckhand image, which is
# useful for CICD (as validating the image is vital). However, if the
# `DECKHAND_IMAGE` is not specified, then this implies that the most current
# version of the code should be used, which is in the repo itself.
DECKHAND_IMAGE=${DECKHAND_IMAGE:-}
ROOTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
source $ROOTDIR/common-tests.sh
CURRENT_DIR="$(pwd)"
function cleanup_deckhand {
set +e
if [ -n "$POSTGRES_ID" ]; then
sudo docker stop $POSTGRES_ID
fi
# Kill PostgreSQL if it is still running.
pifpaf_stop || deactive
if [ -n "$DECKHAND_ID" ]; then
sudo docker stop $DECKHAND_ID
fi
rm -rf $CONF_DIR
if [ -z "$DECKHAND_IMAGE" ]; then
# Kill uwsgi service if it is still running.
PID=$( sudo netstat -tulpn | grep ":9000" | head -n 1 | awk '{print $NF}' )
if [ -n $PID ]; then
PID=${PID%/*}
sudo kill -9 $PID
fi
# Kill uwsgi service if it is still running.
PID=$( sudo netstat -tulpn | grep ":9000" | head -n 1 | awk '{print $NF}' )
if [ -n $PID ]; then
PID=${PID%/*}
sudo kill -9 $PID
fi
}
@ -47,46 +26,21 @@ function cleanup_deckhand {
trap cleanup_deckhand EXIT
function deploy_postgresql {
eval `pifpaf run postgresql`
export POSTGRES_IP=${PIFPAF_POSTGRESQL_URL}
}
function deploy_deckhand {
source ${CURRENT_DIR}/common-tests.sh
gen_config true "127.0.0.1:9000"
gen_paste true
if [ -z "$DECKHAND_IMAGE" ]; then
log_section "Running Deckhand via uwsgi."
log_section "Running Deckhand via uwsgi."
alembic upgrade head
# NOTE(fmontei): Deckhand's database is not configured to work with
# multiprocessing. Currently there is a data race on acquiring shared
# SQLAlchemy engine pooled connection strings when workers > 1. As a
# workaround, we use multiple threads but only 1 worker. For more
# information, see: https://github.com/att-comdev/deckhand/issues/20
export DECKHAND_API_WORKERS=1
export DECKHAND_API_THREADS=4
source $ROOTDIR/../entrypoint.sh server &
else
log_section "Running Deckhand via Docker."
# If container is already running, kill it.
DECKHAND_ID=$(sudo docker ps --filter ancestor=$DECKHAND_IMAGE --format "{{.ID}}")
if [ -n "$DECKHAND_ID" ]; then
sudo docker stop $DECKHAND_ID
fi
sudo docker run \
--rm \
--net=host \
-v $CONF_DIR:/etc/deckhand \
$DECKHAND_IMAGE alembic upgrade head &> $STDOUT &
sudo docker run \
--rm \
--net=host \
-p 9000:9000 \
-v $CONF_DIR:/etc/deckhand \
$DECKHAND_IMAGE server &> $STDOUT &
DECKHAND_ID=$(sudo docker ps | grep deckhand | awk '{print $1}')
echo $DECKHAND_ID
fi
alembic upgrade head
source $ROOTDIR/../entrypoint.sh server &
# Give the server a chance to come up. Better to poll a health check.
sleep 5
@ -94,22 +48,19 @@ function deploy_deckhand {
# Deploy Deckhand and PostgreSQL and run tests.
deploy_postgre
deploy_postgresql
deploy_deckhand
log_section Running tests
# Create folder for saving HTML test results.
mkdir -p $ROOTDIR/results
export DECKHAND_TESTS_DIR=${ROOTDIR}/../deckhand/tests/functional/gabbits
export DECKHAND_TEST_DIR=${CURRENT_DIR}/../deckhand/tests/functional/gabbits
set +e
posargs=$@
if [ ${#posargs} -ge 1 ]; then
py.test -k $1 -svx $( dirname $ROOTDIR )/deckhand/tests/common/test_gabbi.py --html=results/index.html
py.test -k $1 -svx ${CURRENT_DIR}/../deckhand/tests/common/test_gabbi.py
else
py.test -svx $( dirname $ROOTDIR )/deckhand/tests/common/test_gabbi.py --html=results/index.html
py.test -svx ${CURRENT_DIR}/../deckhand/tests/common/test_gabbi.py
fi
TEST_STATUS=$?
set -e
@ -118,7 +69,6 @@ if [ "x$TEST_STATUS" = "x0" ]; then
log_section Done SUCCESS
else
log_section Deckhand Server Log
cat $STDOUT
log_section Done FAILURE
exit $TEST_STATUS
exit ${TEST_STATUS}
fi

View File

@ -0,0 +1,49 @@
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# 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.
- hosts: all
gather_facts: False
become: yes
roles:
- build-images
tags:
- build-images
- hosts: all
gather_facts: False
roles:
- deploy-postgresql
tags:
- deploy-postgresql
- hosts: all
gather_facts: False
roles:
- generate-test-config
tags:
- generate-test-config
- hosts: all
gather_facts: False
roles:
- deploy-deckhand
tags:
- deploy-deckhand
- hosts: all
gather_facts: False
roles:
- run-tests
tags:
- run-tests

View File

@ -12,14 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- hosts: all
gather_facts: False
become: yes
roles:
- build-images
tags:
- build-images
- hosts: all
gather_facts: False
roles:

View File

@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
null: null
zuul_airship_deckhand_relative_path: ../airship-deckhand

View File

@ -27,7 +27,6 @@
shell: cd "{{ work_dir }}"; pwd
register: airship_deckhand_path
vars:
zuul_airship_deckhand_relative_path: ../airship-deckhand
work_dir: "{{ zuul.project.src_dir }}/{{ zuul_airship_deckhand_relative_path | default('') }}"
- name: Airship-Deckhand image build path
@ -53,4 +52,6 @@
shell: |-
set -e;
echo $( docker images --filter label=zuul | awk '{print $3}' | head -2 | tail -1 )
register: deckhand_image_id
register: airship_deckhand_image_id
args:
chdir: "{{ airship_deckhand_path.stdout }}"

View File

@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- include: airship-deckhand.yaml
- include: build-deckhand-image.yaml

View File

@ -0,0 +1,43 @@
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# 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.
- name: Deploy Deckhand using Docker
shell: |-
set -ex;
echo "Running Deckhand via Docker."
# Do database migrations.
docker run \
--rm \
--net=host \
-v "{{ deckhand_conf_dir.stdout }}":/etc/deckhand \
"{{ airship_deckhand_image_id.stdout }}" alembic upgrade head &
# Allow migrations to complete.
sleep 5
# Start Deckhand container.
docker run \
--rm \
--net=host \
-p 9000:9000 \
-v "{{ deckhand_conf_dir.stdout }}":/etc/deckhand \
"{{ airship_deckhand_image_id.stdout }}" server &
# Give the server a chance to come up. Better to poll a health check.
sleep 5
args:
chdir: "{{ airship_deckhand_path.stdout }}"
become: yes

View File

@ -0,0 +1,15 @@
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# 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.
- include: deploy-deckhand.yaml

View File

@ -0,0 +1,28 @@
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# 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.
- name: Deploy PostgreSQL
shell: |-
set -e;
./tools/gate/scripts/020-deploy-postgresql.sh
args:
chdir: "{{ zuul.project.src_dir }}"
register: _airship_deckhand_database_url
become: yes
- name: Register PostgreSQL database IP address
set_fact:
airship_deckhand_database_url: "{{ _airship_deckhand_database_url.stdout_lines | last }}"
environment:
AIRSHIP_DECKHAND_DATABASE_URL: "{{ airship_deckhand_database_url }}"

View File

@ -0,0 +1,15 @@
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# 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.
- include: deploy-postgresql.yaml

View File

@ -0,0 +1,72 @@
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# 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.
- name: Create temporary deckhand conf directory
shell: |-
set - ex;
echo $( mktemp -d -p "{{ airship_deckhand_path.stdout }}" )
register: deckhand_conf_dir
environment:
# Used by Deckhand's initialization script to search for config files.
AIRSHIP_DECKHAND_CONFIG_DIR: "{{ deckhand_conf_dir.stdout }}"
args:
chdir: "{{ airship_deckhand_path.stdout }}"
- name: Generate test deckhand.conf file when disable_keystone is true
when: disable_keystone == true
shell: |-
set -ex;
chmod 777 -R "{{ deckhand_conf_dir.stdout }}"
conf_file="{{ deckhand_conf_dir.stdout }}"/deckhand.conf
echo "{{ airship_deckhand_database_url }}"
cp etc/deckhand/logging.conf.sample "{{ deckhand_conf_dir.stdout }}"/logging.conf
envsubst '$AIRSHIP_DECKHAND_DATABASE_URL' < deckhand/tests/deckhand.conf.test > $conf_file
echo "Toggling development_mode on to disable Keystone authentication."
sed -i -e 's/development_mode = false/development_mode = true/g' $conf_file
echo $conf_file 1>&2
cat $conf_file 1>&2
echo "{{ deckhand_conf_dir.stdout }}"/logging.conf 1>&2
cat "{{ deckhand_conf_dir.stdout }}"/logging.conf 1>&2
args:
chdir: "{{ airship_deckhand_path.stdout }}"
environment:
AIRSHIP_DECKHAND_DATABASE_URL: "{{ airship_deckhand_database_url }}"
become: yes
- name: Generate test deckhand.conf file when disable_keystone is false
when: disable_keystone == false
shell: |-
set -ex;
conf_file="{{ deckhand_conf_dir.stdout }}"/deckhand.conf
cp etc/deckhand/logging.conf.sample "{{ deckhand_conf_dir.stdout }}"/logging.conf
envsubst '$AIRSHIP_DECKHAND_DATABASE_URL' < deckhand/tests/deckhand.conf.test > $conf_file
echo $conf_file 1>&2
cat $conf_file 1>&2
echo "{{ deckhand_conf_dir.stdout }}"/logging.conf 1>&2
cat "{{ deckhand_conf_dir.stdout }}"/logging.conf 1>&2
args:
chdir: "{{ airship_deckhand_path.stdout }}"
environment:
AIRSHIP_DECKHAND_DATABASE_URL: "{{ airship_deckhand_database_url }}"
become: yes

View File

@ -0,0 +1,30 @@
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# 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.
- name: Generate test paste.ini file when disable_keystone is true
when: disable_keystone == true
shell: |-
set -ex;
echo "Using noauth-paste.ini to disable Keystone authentication."
cp etc/deckhand/noauth-paste.ini "{{ deckhand_conf_dir.stdout }}"/noauth-paste.ini
args:
chdir: "{{ airship_deckhand_path.stdout }}"
- name: Generate test paste.ini file when disable_keystone is false
when: disable_keystone == false
shell: |-
set -ex;
cp etc/deckhand/deckhand-paste.ini "{{ deckhand_conf_dir.stdout }}"/deckhand-paste.ini
args:
chdir: "{{ airship_deckhand_path.stdout }}"

View File

@ -0,0 +1,16 @@
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# 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.
- include: generate-test-config.yaml
- include: generate-test-paste.yaml

View File

@ -15,8 +15,9 @@
- name: Run Tox Tests
shell: |
set -xe;
tox -e {{ tox_envlist }}
tox -e "{{ tox_envlist }}"
args:
chdir: "{{ zuul.project.src_dir }}"
environment:
DECKHAND_IMAGE: "{{ deckhand_image_id.stdout }}"
DECKHAND_TEST_URL: "127.0.0.1:9000"
DECKHAND_TEST_DIR: "{{ airship_deckhand_path.stdout }}/deckhand/tests/functional/gabbits"

View File

@ -1,6 +1,6 @@
#!/bin/bash
# Copyright 2017 The Openstack-Helm Authors.
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# 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

View File

@ -0,0 +1,35 @@
#!/bin/bash
# Copyright 2018 AT&T Intellectual Property. All other rights reserved.
#
# 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.
set -e;
POSTGRES_ID=$(
sudo docker run \
--detach \
--publish :5432 \
-e POSTGRES_DB=deckhand \
-e POSTGRES_USER=deckhand \
-e POSTGRES_PASSWORD=password \
postgres:9.5
)
POSTGRES_IP=$(
sudo docker inspect \
--format='{{ .NetworkSettings.Networks.bridge.IPAddress }}' \
$POSTGRES_ID
)
echo "postgresql+psycopg2://deckhand:password@$POSTGRES_IP:5432/deckhand"

View File

@ -179,7 +179,7 @@ function deploy_deckhand {
function run_tests {
set +e
export DECKHAND_TESTS_DIR=${CURRENT_DIR}/deckhand/tests/integration/gabbits
export DECKHAND_TEST_DIR=${CURRENT_DIR}/deckhand/tests/integration/gabbits
posargs=$@
if [ ${#posargs} -ge 1 ]; then

15
tox.ini
View File

@ -11,7 +11,7 @@ setenv = VIRTUAL_ENV={envdir}
OS_TEST_PATH=./deckhand/tests/unit
LANGUAGE=en_US
LC_ALL=en_US.utf-8
passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH OS_TEST_PATH http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY DECKHAND_IMAGE
passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH OS_TEST_PATH http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY DECKHAND_IMAGE DECKHAND_TEST_URL DECKHAND_TEST_DIR
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands =
@ -41,21 +41,20 @@ commands =
{toxinidir}/tools/run_pifpaf.sh '{posargs}'
[testenv:functional]
basepython = python2.7
basepython=python3.5
setenv = VIRTUAL_ENV={envdir}
OS_TEST_PATH=./deckhand/tests/functional
LANGUAGE=en_US
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands =
find . -type f -name "*.pyc" -delete
{toxinidir}/tools/functional-tests.sh '{posargs}'
# TODO(felipemonteiro): Use OpenStack test runner.
py.test -svx {toxinidir}/deckhand/tests/common/test_gabbi.py -k '{posargs}'
[testenv:functional-py35]
[testenv:functional-dev]
basepython=python3.5
# Minimalistic functional test job for running Deckhand functional tests
# via uwsgi. Uses pifpaf for DB instantiation. Useful for developers.
setenv = VIRTUAL_ENV={envdir}
OS_TEST_PATH=./deckhand/tests/functional
LANGUAGE=en_US
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands =