Update tox and tests to work with modern setups

While trying to make some changes I discovered that the tox
configuration for osc-placement was rather out of date and
functional tests were not working for python3. With this
change we bring tox.ini into a style that is more in keeping
with modern standards, use stestr, and update some functional
tests so they work with python3.

The functional tests changes are either:

* to fix the decoding of response
* to adapt argparse error response checking between python
  version.

These changes cascade some required change into how the gate-side
functional testing is performed. We make it explicit that in the
python2 job, the 'functional' tox job is run. When the python3
job is run, 'functional-py3' is run. Also stestr replaces
testr in the post-test hook.

When the functional-py3 test had been run in the past it
was actually running a python2 osc-placement against a
python3 devstack. We change that here to be python3 and
python3. Once that was happening, additional failures
were revealed, now fixed.

One particular issue was that while the json module
for python 3.6 and greater will decode strings or bytes,
the version of 3.5 will only do strings. We switch
to using simplejson throughout which smooths things over.
This is added as a new requirement but it isn't really:
simplejson is required by osc-lib.

Finally, some requirements need to be tuned to pass the
gate requirements job.

Change-Id: I999a3103dd85c0a437785766eef533875fca31fc
This commit is contained in:
Chris Dent 2019-03-01 00:05:57 +00:00 committed by Eric Fried
parent bffd59ea53
commit fc563d37bc
13 changed files with 84 additions and 49 deletions

3
.stestr.conf Normal file
View File

@ -0,0 +1,3 @@
[DEFAULT]
test_path=./osc_placement/tests/unit
top_dir=./

View File

@ -1,7 +0,0 @@
[DEFAULT]
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./osc_placement/tests/unit} $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

View File

@ -11,10 +11,10 @@
# under the License.
import contextlib
import json
import keystoneauth1.exceptions.http as ks_exceptions
import osc_lib.exceptions as exceptions
import simplejson as json
import six

View File

@ -10,15 +10,23 @@
# License for the specific language governing permissions and limitations
# under the License.
import json
import random
import six
import subprocess
from oslotest import base
import simplejson as json
RP_PREFIX = 'osc-placement-functional-tests-'
# argparse in python 2 and 3 have different error messages
ARGUMENTS_MISSING = 'too few arguments'
ARGUMENTS_REQUIRED = 'argument %s is required'
if six.PY3:
ARGUMENTS_MISSING = 'the following arguments are required'
ARGUMENTS_REQUIRED = 'the following arguments are required: %s'
class BaseTestCase(base.BaseTestCase):
VERSION = None
@ -74,7 +82,7 @@ class BaseTestCase(base.BaseTestCase):
except subprocess.CalledProcessError as e:
self.assertIn(
message, e.output,
message, six.text_type(e.output),
'Command "%s" fails with different message' % e.cmd)
def resource_provider_create(self,

View File

@ -14,9 +14,11 @@
# This script is executed inside post_test_hook function in devstack gate.
TOX_ENV=${TOX_ENV:-functional}
function generate_testr_results {
if [ -f .testrepository/0 ]; then
.tox/functional/bin/testr last --subunit > $WORKSPACE/testrepository.subunit
if [ -f .stestr/0 ]; then
.tox/$TOX_ENV/bin/stestr last --subunit > $WORKSPACE/testrepository.subunit
mv $WORKSPACE/testrepository.subunit $BASE/logs/testrepository.subunit
/usr/os-testr-env/bin/subunit2html $BASE/logs/testrepository.subunit $BASE/logs/testr_results.html
gzip -9 $BASE/logs/testrepository.subunit
@ -37,7 +39,7 @@ echo "Running osc-placement functional test suite"
set +e
# Preserve env for OS_ credentials
source $BASE/new/devstack/openrc admin admin
tox -e ${TOX_ENV:-functional}
tox -e $TOX_ENV
EXIT_CODE=$?
set -e

View File

@ -20,7 +20,7 @@ class TestAggregate(base.BaseTestCase):
def test_fail_if_no_rp(self):
self.assertCommandFailed(
'too few arguments',
base.ARGUMENTS_MISSING,
self.openstack,
'resource provider aggregate list')
@ -50,7 +50,7 @@ class TestAggregate(base.BaseTestCase):
def test_set_aggregate_fail_if_no_rp(self):
self.assertCommandFailed(
'too few arguments',
base.ARGUMENTS_MISSING,
self.openstack,
'resource provider aggregate set')

View File

@ -67,7 +67,7 @@ class TestInventory(base.BaseTestCase):
# Negative test to assert command failure because
# microversion < 1.5 and --resource-class is not specified.
self.assertCommandFailed(
'argument --resource-class is required',
base.ARGUMENTS_REQUIRED % '--resource-class',
self.resource_inventory_delete,
'fake_uuid')
@ -77,7 +77,7 @@ class TestSetInventory(base.BaseTestCase):
exc = self.assertRaises(
subprocess.CalledProcessError,
self.openstack, 'resource provider inventory set')
self.assertIn('too few arguments', exc.output.decode('utf-8'))
self.assertIn(base.ARGUMENTS_MISSING, exc.output.decode('utf-8'))
def test_set_empty_inventories(self):
rp = self.resource_provider_create()
@ -173,11 +173,11 @@ class TestSetInventory(base.BaseTestCase):
exc = self.assertRaises(
subprocess.CalledProcessError,
self.openstack, 'resource provider inventory class set')
self.assertIn('too few arguments', exc.output.decode('utf-8'))
self.assertIn(base.ARGUMENTS_MISSING, exc.output.decode('utf-8'))
exc = self.assertRaises(
subprocess.CalledProcessError,
self.openstack, 'resource provider inventory class set fake_uuid')
self.assertIn('too few arguments', exc.output.decode('utf-8'))
self.assertIn(base.ARGUMENTS_MISSING, exc.output.decode('utf-8'))
exc = self.assertRaises(
subprocess.CalledProcessError,
self.openstack,
@ -189,7 +189,7 @@ class TestSetInventory(base.BaseTestCase):
exc = self.assertRaises(
subprocess.CalledProcessError, self.openstack,
'resource provider inventory class set %s VCPU' % rp['uuid'])
self.assertIn('argument --total is required',
self.assertIn(base.ARGUMENTS_REQUIRED % '--total',
exc.output.decode('utf-8'))
def test_set_inventory_for_resource_class(self):

View File

@ -18,4 +18,4 @@ from oslotest import base
class TestPlugin(base.BaseTestCase):
def test_parser_options(self):
output = subprocess.check_output(['openstack', '--help'])
self.assertIn('--os-placement-api-version', output)
self.assertIn('--os-placement-api-version', output.decode('utf-8'))

View File

@ -10,7 +10,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import json
import mock
import six
@ -18,6 +17,7 @@ import six
import keystoneauth1.exceptions.http as ks_exceptions
import osc_lib.exceptions as exceptions
import oslotest.base as base
import simplejson as json
import osc_placement.http as http

View File

@ -47,6 +47,7 @@
export PYTHONUNBUFFERED=true
export DEVSTACK_PROJECT_FROM_GIT=osc-placement
export DEVSTACK_GATE_USE_PYTHON3=True
export TOX_ENV=functional-py3
function post_test_hook {
# Configure and run functional tests

View File

@ -5,4 +5,5 @@
pbr>=2.0.0 # Apache-2.0
six>=1.10.0 # MIT
keystoneauth1>=3.3.0 # Apache-2.0
simplejson>=3.16.0 # MIT
osc-lib>=1.2.0 # Apache-2.0

View File

@ -5,14 +5,11 @@
hacking>=0.12.0,<0.13 # Apache-2.0
coverage>=4.0 # Apache-2.0
python-subunit>=0.0.18 # Apache-2.0/BSD
sphinx>=1.2.1,!=1.3b1,<1.4 # BSD
sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
oslosphinx>=4.7.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
python-openstackclient>=3.3.0 # Apache-2.0
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
stestr>=1.0.0 # Apache-2.0
# releasenotes
reno>=1.8.0 # Apache-2.0

74
tox.ini
View File

@ -1,56 +1,86 @@
[tox]
minversion = 2.0
envlist = pep8,py{27,35},functional
minversion = 3.1.1
envlist = py{27,36},functional,functional-py36,pep8
skipsdist = True
# Automatic envs (pyXX) will use the python version appropriate to that
# env and ignore basepython inherited from [testenv]. That's what we
# want, and we don't need to be warned about it.
ignore_basepython_conflict = True
[testenv]
basepython = python3
usedevelop = True
whitelist_externals =
rm
install_command = pip install {opts} {packages}
setenv =
VIRTUAL_ENV={envdir}
PYTHONWARNINGS=default::DeprecationWarning
OS_TEST_PATH=./osc_placement/tests/unit
deps =
-c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
-r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt
commands = python setup.py test --slowest --testr-args='{posargs}'
[testenv:functional]
setenv =
VIRTUAL_ENV={envdir}
PYTHONWARNINGS=default::DeprecationWarning,ignore::DeprecationWarning:distutils,ignore::DeprecationWarning:site
OS_TEST_PATH=./osc_placement/tests/functional
PYTHONWARNINGS=ignore::DeprecationWarning:distutils,ignore::DeprecationWarning:site
PYTHONDONTWRITEBYTECODE=1
# NOTE(rpodolyaka): allow passing of keystone credentials via env variables
passenv = OS_*
deps =
-c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
-r{toxinidir}/test-requirements.txt
-r{toxinidir}/requirements.txt
commands = stestr run {posargs}
# NOTE(cdent): Functional tests require a running openstack
# and OS_* variables in the environment to allow authentication.
# This is because the openstack client is called against a
# real cloud.
# NOTE(cdent): Do not set envdir here, for the sake of the
# gate functional jobs, which use the 'functional' path when
# copying files.
[testenv:functional]
basepython = python2.7
commands = stestr --test-path=./osc_placement/tests/functional run {posargs}
# Used by the python3 functional job in the gate.
[testenv:functional-py3]
commands =
{[testenv:functional]commands}
[testenv:functional-py36]
envdir = {toxworkdir}/py36
commands =
{[testenv:functional]commands}
[testenv:functional-py37]
envdir = {toxworkdir}/py37
commands =
{[testenv:functional]commands}
[testenv:pep8]
basepython = python3
envdir = {toxworkdir}/shared
commands = flake8 {posargs}
[testenv:venv]
basepython = python3
commands = {posargs}
[testenv:cover]
basepython = python3
commands = python setup.py test --coverage --testr-args='{posargs}'
envdir = {toxworkdir}/shared
setenv =
{[testenv]setenv}
PYTHON=coverage run --source osc_placement --parallel-mode
commands =
coverage erase
stestr run {posargs}
coverage combine
coverage html -d cover
coverage xml -o cover/coverage.xml
coverage report
[testenv:docs]
basepython = python3
commands =
rm -rf doc/build
python setup.py build_sphinx
[testenv:releasenotes]
basepython = python3
commands =
sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
[testenv:debug]
basepython = python3
commands = oslo_debug_helper {posargs}
[flake8]