Fix unit and functional tests
stable/kilo branch is broken due to next reasons: 1) unittests requires capped oslo libraries and mock 2) functional tests cannot access to credentials via environment variables Both issues block each other, so we need to squach several commits. Fix for functional tests is done via backporting patches: * refactor functional test base class to no inherit from tempest_lib Conflicts: None Change-Id: I716be51d7d1825a757934298f06b2f04d64cf0dd (cherry picked from commit420dc2884a
) * pass credentials via config file instead of magic Conflicts: README.rst Change-Id: Ifdab38a03c94f51d30449149c0dbd9c6265460a5 (cherry picked from commit6379287480
) Unittest doesn't require full sync with global-requrements, so only oslo.i18n, oslo.serialization and mock are updated. Change-Id: I5ecd52abcaf0da1b067e70d7b19297305af19174
This commit is contained in:
parent
0ae7a08c08
commit
13463268db
13
README.rst
13
README.rst
|
@ -77,3 +77,16 @@ To use with nova, with keystone as the authentication system::
|
|||
[...]
|
||||
>>> nt.keypairs.list()
|
||||
[...]
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
There are multiple test targets that can be run to validate the code.
|
||||
|
||||
* tox -e pep8 - style guidelines enforcement
|
||||
* tox -e py27 - traditional unit testing
|
||||
* tox -e functional - live functional testing against an existing
|
||||
openstack
|
||||
|
||||
Functional testing assumes the existance of a functional_creds.conf in
|
||||
the root directory. See the .sample for example format.
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
# Credentials for functional testing
|
||||
[auth]
|
||||
uri = http://10.42.0.50:5000/v2.0
|
||||
|
||||
[admin]
|
||||
user = admin
|
||||
tenant = admin
|
||||
pass = secrete
|
|
@ -10,12 +10,47 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import ConfigParser
|
||||
import os
|
||||
|
||||
from tempest_lib.cli import base
|
||||
import fixtures
|
||||
import tempest_lib.cli.base
|
||||
import testtools
|
||||
|
||||
import novaclient.client
|
||||
|
||||
|
||||
class ClientTestBase(base.ClientTestBase):
|
||||
# The following are simple filter functions that filter our available
|
||||
# image / flavor list so that they can be used in standard testing.
|
||||
def pick_flavor(flavors):
|
||||
"""Given a flavor list pick a reasonable one."""
|
||||
for flavor in flavors:
|
||||
if flavor.name == 'm1.tiny':
|
||||
return flavor
|
||||
for flavor in flavors:
|
||||
if flavor.name == 'm1.small':
|
||||
return flavor
|
||||
raise NoFlavorException()
|
||||
|
||||
|
||||
def pick_image(images):
|
||||
for image in images:
|
||||
if image.name.startswith('cirros') and image.name.endswith('-uec'):
|
||||
return image
|
||||
raise NoImageException()
|
||||
|
||||
|
||||
class NoImageException(Exception):
|
||||
"""We couldn't find an acceptable image."""
|
||||
pass
|
||||
|
||||
|
||||
class NoFlavorException(Exception):
|
||||
"""We couldn't find an acceptable flavor."""
|
||||
pass
|
||||
|
||||
|
||||
class ClientTestBase(testtools.TestCase):
|
||||
"""
|
||||
This is a first pass at a simple read only python-novaclient test. This
|
||||
only exercises client commands that are read only.
|
||||
|
@ -27,18 +62,89 @@ class ClientTestBase(base.ClientTestBase):
|
|||
* initially just check return codes, and later test command outputs
|
||||
|
||||
"""
|
||||
def _get_clients(self):
|
||||
log_format = ('%(asctime)s %(process)d %(levelname)-8s '
|
||||
'[%(name)s] %(message)s')
|
||||
|
||||
def setUp(self):
|
||||
super(ClientTestBase, self).setUp()
|
||||
|
||||
test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
|
||||
try:
|
||||
test_timeout = int(test_timeout)
|
||||
except ValueError:
|
||||
test_timeout = 0
|
||||
if test_timeout > 0:
|
||||
self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
|
||||
|
||||
if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
|
||||
os.environ.get('OS_STDOUT_CAPTURE') == '1'):
|
||||
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
|
||||
if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
|
||||
os.environ.get('OS_STDERR_CAPTURE') == '1'):
|
||||
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
|
||||
|
||||
if (os.environ.get('OS_LOG_CAPTURE') != 'False' and
|
||||
os.environ.get('OS_LOG_CAPTURE') != '0'):
|
||||
self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
|
||||
format=self.log_format,
|
||||
level=None))
|
||||
|
||||
# Collecting of credentials:
|
||||
#
|
||||
# Support the existence of a functional_creds.conf for
|
||||
# testing. This makes it possible to use a config file.
|
||||
#
|
||||
# Those variables can be overridden by environmental variables
|
||||
# as well to support existing users running these the old
|
||||
# way. We should deprecate that.
|
||||
|
||||
# TODO(sdague): while we collect this information in
|
||||
# tempest-lib, we do it in a way that's not available for top
|
||||
# level tests. Long term this probably needs to be in the base
|
||||
# class.
|
||||
user = os.environ.get('OS_USERNAME')
|
||||
passwd = os.environ.get('OS_PASSWORD')
|
||||
tenant = os.environ.get('OS_TENANT_NAME')
|
||||
auth_url = os.environ.get('OS_AUTH_URL')
|
||||
|
||||
config = ConfigParser.RawConfigParser()
|
||||
if config.read('functional_creds.conf'):
|
||||
# the OR pattern means the environment is preferred for
|
||||
# override
|
||||
user = user or config.get('admin', 'user')
|
||||
passwd = passwd or config.get('admin', 'pass')
|
||||
tenant = tenant or config.get('admin', 'tenant')
|
||||
auth_url = auth_url or config.get('auth', 'uri')
|
||||
|
||||
# TODO(sdague): we made a lot of fun of the glanceclient team
|
||||
# for version as int in first parameter. I guess we know where
|
||||
# they copied it from.
|
||||
self.client = novaclient.client.Client(
|
||||
2, user, passwd, tenant,
|
||||
auth_url=auth_url)
|
||||
|
||||
# pick some reasonable flavor / image combo
|
||||
self.flavor = pick_flavor(self.client.flavors.list())
|
||||
self.image = pick_image(self.client.images.list())
|
||||
|
||||
# create a CLI client in case we'd like to do CLI
|
||||
# testing. tempest_lib does this realy weird thing where it
|
||||
# builds a giant factory of all the CLIs that it knows
|
||||
# about. Eventually that should really be unwound into
|
||||
# something more sensible.
|
||||
cli_dir = os.environ.get(
|
||||
'OS_NOVACLIENT_EXEC_DIR',
|
||||
os.path.join(os.path.abspath('.'), '.tox/functional/bin'))
|
||||
|
||||
return base.CLIClient(
|
||||
username=os.environ.get('OS_USERNAME'),
|
||||
password=os.environ.get('OS_PASSWORD'),
|
||||
tenant_name=os.environ.get('OS_TENANT_NAME'),
|
||||
uri=os.environ.get('OS_AUTH_URL'),
|
||||
self.cli_clients = tempest_lib.cli.base.CLIClient(
|
||||
username=user,
|
||||
password=passwd,
|
||||
tenant_name=tenant,
|
||||
uri=auth_url,
|
||||
cli_dir=cli_dir)
|
||||
|
||||
def nova(self, *args, **kwargs):
|
||||
return self.clients.nova(*args,
|
||||
**kwargs)
|
||||
return self.cli_clients.nova(*args,
|
||||
**kwargs)
|
||||
|
|
|
@ -28,15 +28,28 @@ function generate_testr_results {
|
|||
|
||||
export NOVACLIENT_DIR="$BASE/new/python-novaclient"
|
||||
|
||||
sudo chown -R jenkins:stack $NOVACLIENT_DIR
|
||||
|
||||
# Get admin credentials
|
||||
cd $BASE/new/devstack
|
||||
source openrc admin admin
|
||||
# pass the appropriate variables via a config file
|
||||
CREDS_FILE=$NOVACLIENT_DIR/functional_creds.conf
|
||||
cat <<EOF > $CREDS_FILE
|
||||
# Credentials for functional testing
|
||||
[auth]
|
||||
uri = $OS_AUTH_URL
|
||||
|
||||
[admin]
|
||||
user = $OS_USERNAME
|
||||
tenant = $OS_TENANT_NAME
|
||||
pass = $OS_PASSWORD
|
||||
|
||||
EOF
|
||||
|
||||
# Go to the novaclient dir
|
||||
cd $NOVACLIENT_DIR
|
||||
|
||||
sudo chown -R jenkins:stack $NOVACLIENT_DIR
|
||||
|
||||
# Run tests
|
||||
echo "Running novaclient functional test suite"
|
||||
set +e
|
||||
|
|
|
@ -10,33 +10,12 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import novaclient.client
|
||||
from novaclient.tests.functional import base
|
||||
|
||||
|
||||
# TODO(sdague): content that probably should be in utils, also throw
|
||||
# Exceptions when they fail.
|
||||
def pick_flavor(flavors):
|
||||
"""Given a flavor list pick a reasonable one."""
|
||||
for flavor in flavors:
|
||||
if flavor.name == 'm1.tiny':
|
||||
return flavor
|
||||
|
||||
for flavor in flavors:
|
||||
if flavor.name == 'm1.small':
|
||||
return flavor
|
||||
|
||||
|
||||
def pick_image(images):
|
||||
for image in images:
|
||||
if image.name.startswith('cirros') and image.name.endswith('-uec'):
|
||||
return image
|
||||
|
||||
|
||||
def volume_id_from_cli_create(output):
|
||||
"""Scrape the volume id out of the 'volume create' command
|
||||
|
||||
|
@ -67,27 +46,6 @@ def volume_at_status(output, volume_id, status):
|
|||
|
||||
|
||||
class TestInstanceCLI(base.ClientTestBase):
|
||||
def setUp(self):
|
||||
super(TestInstanceCLI, self).setUp()
|
||||
# TODO(sdague): while we collect this information in
|
||||
# tempest-lib, we do it in a way that's not available for top
|
||||
# level tests. Long term this probably needs to be in the base
|
||||
# class.
|
||||
user = os.environ['OS_USERNAME']
|
||||
passwd = os.environ['OS_PASSWORD']
|
||||
tenant = os.environ['OS_TENANT_NAME']
|
||||
auth_url = os.environ['OS_AUTH_URL']
|
||||
|
||||
# TODO(sdague): we made a lot of fun of the glanceclient team
|
||||
# for version as int in first parameter. I guess we know where
|
||||
# they copied it from.
|
||||
self.client = novaclient.client.Client(
|
||||
2, user, passwd, tenant,
|
||||
auth_url=auth_url)
|
||||
|
||||
# pick some reasonable flavor / image combo
|
||||
self.flavor = pick_flavor(self.client.flavors.list())
|
||||
self.image = pick_image(self.client.images.list())
|
||||
|
||||
def test_attach_volume(self):
|
||||
"""Test we can attach a volume via the cli.
|
||||
|
|
|
@ -10,13 +10,11 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import time
|
||||
import uuid
|
||||
|
||||
import six.moves
|
||||
|
||||
from novaclient import client
|
||||
from novaclient import exceptions
|
||||
from novaclient.tests.functional import base
|
||||
|
||||
|
@ -35,15 +33,6 @@ def wait_for_delete(test, name, thing, get_func):
|
|||
|
||||
class TestVolumesAPI(base.ClientTestBase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestVolumesAPI, self).setUp()
|
||||
user = os.environ['OS_USERNAME']
|
||||
passwd = os.environ['OS_PASSWORD']
|
||||
tenant = os.environ['OS_TENANT_NAME']
|
||||
auth_url = os.environ['OS_AUTH_URL']
|
||||
|
||||
self.client = client.Client(2, user, passwd, tenant, auth_url=auth_url)
|
||||
|
||||
def test_volumes_snapshots_types_create_get_list_delete(self):
|
||||
# Create a volume
|
||||
volume = self.client.volumes.create(1)
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
pbr>=0.6,!=0.7,<1.0
|
||||
argparse
|
||||
iso8601>=0.1.9
|
||||
oslo.i18n>=1.3.0 # Apache-2.0
|
||||
oslo.serialization>=1.2.0 # Apache-2.0
|
||||
oslo.i18n<1.6.0,>=1.5.0 # Apache-2.0
|
||||
oslo.serialization<1.5.0,>=1.4.0 # Apache-2.0
|
||||
oslo.utils>=1.2.0 # Apache-2.0
|
||||
PrettyTable>=0.7,<0.8
|
||||
requests>=2.2.0,!=2.4.0
|
||||
|
|
|
@ -7,7 +7,7 @@ coverage>=3.6
|
|||
discover
|
||||
fixtures>=0.3.14
|
||||
keyring>=2.1,!=3.3
|
||||
mock>=1.0
|
||||
mock<1.1.0,>=1.0
|
||||
requests-mock>=0.5.1 # Apache-2.0
|
||||
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
|
||||
oslosphinx>=2.2.0 # Apache-2.0
|
||||
|
|
Loading…
Reference in New Issue