Add OSC commands functional test
This patch adds the basic files and only one test now. Consecutive patches will add more test cases. Change-Id: Iebc28e9781357c11a664c6b0d203a4c20a63a6ca
This commit is contained in:
parent
9163616a73
commit
6b5ef0dab2
3
.gitignore
vendored
3
.gitignore
vendored
@ -55,3 +55,6 @@ ChangeLog
|
|||||||
|
|
||||||
# Files created by releasenotes build
|
# Files created by releasenotes build
|
||||||
releasenotes/build
|
releasenotes/build
|
||||||
|
|
||||||
|
# Others
|
||||||
|
test.conf
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
pbr>=1.8 # Apache-2.0
|
pbr>=1.8 # Apache-2.0
|
||||||
PrettyTable>=0.7.1,<0.8 # BSD
|
PrettyTable>=0.7.1,<0.8 # BSD
|
||||||
|
python-openstackclient>=3.3.0 # Apache-2.0
|
||||||
osc-lib>=1.2.0 # Apache-2.0
|
osc-lib>=1.2.0 # Apache-2.0
|
||||||
oslo.i18n>=2.1.0 # Apache-2.0
|
oslo.i18n>=2.1.0 # Apache-2.0
|
||||||
oslo.utils>=3.16.0 # Apache-2.0
|
oslo.utils>=3.16.0 # Apache-2.0
|
||||||
|
@ -5,12 +5,14 @@
|
|||||||
bandit>=1.0.1 # Apache-2.0
|
bandit>=1.0.1 # Apache-2.0
|
||||||
coverage>=4.0 # Apache-2.0
|
coverage>=4.0 # Apache-2.0
|
||||||
doc8 # Apache-2.0
|
doc8 # Apache-2.0
|
||||||
|
ddt>=1.0.1 # MIT
|
||||||
hacking<0.12,>=0.11.0 # Apache-2.0
|
hacking<0.12,>=0.11.0 # Apache-2.0
|
||||||
oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
|
oslosphinx!=3.4.0,>=2.5.0 # Apache-2.0
|
||||||
oslotest>=1.10.0 # Apache-2.0
|
oslotest>=1.10.0 # Apache-2.0
|
||||||
os-testr>=0.8.0 # Apache-2.0
|
os-testr>=0.8.0 # Apache-2.0
|
||||||
python-subunit>=0.0.18 # Apache-2.0/BSD
|
python-subunit>=0.0.18 # Apache-2.0/BSD
|
||||||
sphinx!=1.3b1,<1.4,>=1.2.1 # BSD
|
sphinx!=1.3b1,<1.4,>=1.2.1 # BSD
|
||||||
|
tempest>=14.0.0 # Apache-2.0
|
||||||
testresources>=0.2.4 # Apache-2.0/BSD
|
testresources>=0.2.4 # Apache-2.0/BSD
|
||||||
testrepository>=0.0.18 # Apache-2.0/BSD
|
testrepository>=0.0.18 # Apache-2.0/BSD
|
||||||
testscenarios>=0.4 # Apache-2.0/BSD
|
testscenarios>=0.4 # Apache-2.0/BSD
|
||||||
|
29
tools/run_functional.sh
Executable file
29
tools/run_functional.sh
Executable file
@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
FUNC_TEST_DIR=$(dirname $0)/../zunclient/tests/functional/
|
||||||
|
CONFIG_FILE=$FUNC_TEST_DIR/test.conf
|
||||||
|
|
||||||
|
if [[ -n "$OS_AUTH_TOKEN" ]] && [[ -n "$ZUN_URL" ]]; then
|
||||||
|
cat <<END >$CONFIG_FILE
|
||||||
|
[functional]
|
||||||
|
api_version = 1
|
||||||
|
auth_strategy=noauth
|
||||||
|
os_auth_token=$OS_AUTH_TOKEN
|
||||||
|
zun_url=$ZUN_URL
|
||||||
|
END
|
||||||
|
else
|
||||||
|
cat <<END >$CONFIG_FILE
|
||||||
|
[functional]
|
||||||
|
api_version = 1
|
||||||
|
os_auth_url=$OS_AUTH_URL
|
||||||
|
os_identity_api_version = $OS_IDENTITY_API_VERSION
|
||||||
|
os_username=$OS_USERNAME
|
||||||
|
os_password=$OS_PASSWORD
|
||||||
|
os_project_name=$OS_PROJECT_NAME
|
||||||
|
os_user_domain_id=$OS_USER_DOMAIN_ID
|
||||||
|
os_project_domain_id=$OS_PROJECT_DOMAIN_ID
|
||||||
|
os_service_type=container
|
||||||
|
os_endpoint_type=public
|
||||||
|
END
|
||||||
|
fi
|
||||||
|
tox -e functional
|
10
tox.ini
10
tox.ini
@ -70,3 +70,13 @@ exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
|
|||||||
|
|
||||||
[hacking]
|
[hacking]
|
||||||
import_exceptions = zunclient._i18n
|
import_exceptions = zunclient._i18n
|
||||||
|
|
||||||
|
[testenv:functional]
|
||||||
|
commands = ostestr {posargs}
|
||||||
|
setenv =
|
||||||
|
{[testenv]setenv}
|
||||||
|
OS_TEST_PATH = ./zunclient/tests/functional/osc/v1
|
||||||
|
# The OS_CACERT environment variable should be passed to the test
|
||||||
|
# environments to specify a CA bundle file to use in verifying a
|
||||||
|
# TLS (https) server certificate.
|
||||||
|
passenv = OS_*
|
||||||
|
193
zunclient/tests/functional/base.py
Normal file
193
zunclient/tests/functional/base.py
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
# Copyright (c) 2016 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 os
|
||||||
|
|
||||||
|
import six
|
||||||
|
import six.moves.configparser as config_parser
|
||||||
|
from tempest.lib.cli import base
|
||||||
|
|
||||||
|
DEFAULT_CONFIG_FILE = os.path.join(os.path.dirname(__file__), 'test.conf')
|
||||||
|
|
||||||
|
|
||||||
|
class FunctionalTestBase(base.ClientTestBase):
|
||||||
|
"""Container base class, calls to zunclient."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(FunctionalTestBase, self).setUp()
|
||||||
|
self.client = self._get_clients()
|
||||||
|
|
||||||
|
def _get_clients(self):
|
||||||
|
# NOTE(aarefiev): {toxinidir} is a current working directory, so
|
||||||
|
# the tox env path is {toxinidir}/.tox
|
||||||
|
cli_dir = os.path.join(os.path.abspath('.'), '.tox/functional/bin')
|
||||||
|
|
||||||
|
config = self._get_config()
|
||||||
|
if config.get('os_auth_url'):
|
||||||
|
client = base.CLIClient(cli_dir=cli_dir,
|
||||||
|
username=config['os_username'],
|
||||||
|
password=config['os_password'],
|
||||||
|
tenant_name=config['os_project_name'],
|
||||||
|
uri=config['os_auth_url'])
|
||||||
|
for keystone_object in 'user', 'project':
|
||||||
|
domain_attr = 'os_%s_domain_id' % keystone_object
|
||||||
|
if config.get(domain_attr):
|
||||||
|
setattr(self, domain_attr, config[domain_attr])
|
||||||
|
else:
|
||||||
|
self.zun_url = config['zun_url']
|
||||||
|
self.os_auth_token = config['os_auth_token']
|
||||||
|
client = base.CLIClient(cli_dir=cli_dir,
|
||||||
|
zun_url=self.zun_url,
|
||||||
|
os_auth_token=self.os_auth_token)
|
||||||
|
return client
|
||||||
|
|
||||||
|
def _get_config(self):
|
||||||
|
config_file = os.environ.get('ZUNCLIENT_TEST_CONFIG',
|
||||||
|
DEFAULT_CONFIG_FILE)
|
||||||
|
# SafeConfigParser was deprecated in Python 3.2
|
||||||
|
if six.PY3:
|
||||||
|
config = config_parser.ConfigParser()
|
||||||
|
else:
|
||||||
|
config = config_parser.SafeConfigParser()
|
||||||
|
if not config.read(config_file):
|
||||||
|
self.skipTest('Skipping, no test config found @ %s' % config_file)
|
||||||
|
try:
|
||||||
|
auth_strategy = config.get('functional', 'auth_strategy')
|
||||||
|
except config_parser.NoOptionError:
|
||||||
|
auth_strategy = 'keystone'
|
||||||
|
if auth_strategy not in ['keystone', 'noauth']:
|
||||||
|
raise self.fail(
|
||||||
|
'Invalid auth type specified: %s in functional must be '
|
||||||
|
'one of: [keystone, noauth]' % auth_strategy)
|
||||||
|
|
||||||
|
conf_settings = []
|
||||||
|
keystone_v3_conf_settings = []
|
||||||
|
if auth_strategy == 'keystone':
|
||||||
|
conf_settings += ['os_auth_url', 'os_username',
|
||||||
|
'os_password', 'os_project_name']
|
||||||
|
keystone_v3_conf_settings += ['os_user_domain_id',
|
||||||
|
'os_project_domain_id']
|
||||||
|
else:
|
||||||
|
conf_settings += ['os_auth_token', 'zun_url']
|
||||||
|
|
||||||
|
cli_flags = {}
|
||||||
|
missing = []
|
||||||
|
for c in conf_settings + keystone_v3_conf_settings:
|
||||||
|
try:
|
||||||
|
cli_flags[c] = config.get('functional', c)
|
||||||
|
except config_parser.NoOptionError:
|
||||||
|
# NOTE(vdrok): Here we ignore the absence of KS v3 options as
|
||||||
|
# v2 may be used. Keystone client will do the actual check of
|
||||||
|
# the parameters' correctness.
|
||||||
|
if c not in keystone_v3_conf_settings:
|
||||||
|
missing.append(c)
|
||||||
|
if missing:
|
||||||
|
self.fail('Missing required setting in test.conf (%(conf)s) for '
|
||||||
|
'auth_strategy=%(auth)s: %(missing)s' %
|
||||||
|
{'conf': config_file,
|
||||||
|
'auth': auth_strategy,
|
||||||
|
'missing': ','.join(missing)})
|
||||||
|
return cli_flags
|
||||||
|
|
||||||
|
def _cmd_no_auth(self, cmd, action, flags='', params=''):
|
||||||
|
"""Execute given command with noauth attributes.
|
||||||
|
|
||||||
|
:param cmd: command to be executed
|
||||||
|
:type cmd: string
|
||||||
|
:param action: command on cli to run
|
||||||
|
:type action: string
|
||||||
|
:param flags: optional cli flags to use
|
||||||
|
:type flags: string
|
||||||
|
:param params: optional positional args to use
|
||||||
|
:type params: string
|
||||||
|
"""
|
||||||
|
flags = ('--os_auth_token %(token)s --zun_url %(url)s %(flags)s'
|
||||||
|
%
|
||||||
|
{'token': self.os_auth_token,
|
||||||
|
'url': self.zun_url,
|
||||||
|
'flags': flags})
|
||||||
|
return base.execute(cmd, action, flags, params,
|
||||||
|
cli_dir=self.client.cli_dir)
|
||||||
|
|
||||||
|
def _zun(self, action, flags='', params=''):
|
||||||
|
"""Execute zun command for the given action.
|
||||||
|
|
||||||
|
:param action: the cli command to run using Container
|
||||||
|
:type action: string
|
||||||
|
:param flags: any optional cli flags to use
|
||||||
|
:type flags: string
|
||||||
|
:param params: any optional positional args to use
|
||||||
|
:type params: string
|
||||||
|
"""
|
||||||
|
flags += ' --os-endpoint-type publicURL'
|
||||||
|
if hasattr(self, 'os_auth_token'):
|
||||||
|
return self._cmd_no_auth('appcontainer', action, flags, params)
|
||||||
|
else:
|
||||||
|
for keystone_object in 'user', 'project':
|
||||||
|
domain_attr = 'os_%s_domain_id' % keystone_object
|
||||||
|
if hasattr(self, domain_attr):
|
||||||
|
flags += ' --os-%(ks_obj)s-domain-id %(value)s' % {
|
||||||
|
'ks_obj': keystone_object,
|
||||||
|
'value': getattr(self, domain_attr)
|
||||||
|
}
|
||||||
|
return self.client.cmd_with_auth('zun',
|
||||||
|
action, flags, params)
|
||||||
|
|
||||||
|
def _zun_osc(self, action, flags='', params=''):
|
||||||
|
"""Execute container commands via OpenStack Client."""
|
||||||
|
config = self._get_config()
|
||||||
|
identity_api_version = config.get('functional',
|
||||||
|
'os_identity_api_version')
|
||||||
|
flags += ' --os-identity-api-version {0}'.format(identity_api_version)
|
||||||
|
|
||||||
|
for keystone_object in 'user', 'project':
|
||||||
|
domain_attr = 'os_%s_domain_id' % keystone_object
|
||||||
|
if hasattr(self, domain_attr):
|
||||||
|
flags += ' --os-%(ks_obj)s-domain-id %(value)s' % {
|
||||||
|
'ks_obj': keystone_object,
|
||||||
|
'value': getattr(self, domain_attr)
|
||||||
|
}
|
||||||
|
return self.client.cmd_with_auth(
|
||||||
|
'openstack', action, flags, params)
|
||||||
|
|
||||||
|
def zun(self, action, flags='', params='', parse=True):
|
||||||
|
"""Return parsed list of dicts with basic item info.
|
||||||
|
|
||||||
|
:param action: the cli command to run using Container
|
||||||
|
:type action: string
|
||||||
|
:param flags: any optional cli flags to use
|
||||||
|
:type flags: string
|
||||||
|
:param params: any optional positional args to use
|
||||||
|
:type params: string
|
||||||
|
:param parse: return parsed list or raw output
|
||||||
|
:type parse: bool
|
||||||
|
"""
|
||||||
|
output = self._zun(action=action, flags=flags, params=params)
|
||||||
|
return self.parser.listing(output) if parse else output
|
||||||
|
|
||||||
|
def get_table_headers(self, action, flags='', params=''):
|
||||||
|
output = self._zun(action=action, flags=flags, params=params)
|
||||||
|
table = self.parser.table(output)
|
||||||
|
return table['headers']
|
||||||
|
|
||||||
|
def assertTableHeaders(self, field_names, table_headers):
|
||||||
|
"""Assert that field_names and table_headers are equal.
|
||||||
|
|
||||||
|
:param field_names: field names from the output table of the cmd
|
||||||
|
:param table_headers: table headers output from cmd
|
||||||
|
"""
|
||||||
|
self.assertEqual(sorted(field_names), sorted(table_headers))
|
||||||
|
|
||||||
|
def list_containers(self, params=''):
|
||||||
|
return self.zun('container-list', params=params)
|
@ -59,11 +59,25 @@ cat etc/tempest.conf
|
|||||||
|
|
||||||
sudo -E tox -eall-plugin -- zun.tests.tempest.api --concurrency=1
|
sudo -E tox -eall-plugin -- zun.tests.tempest.api --concurrency=1
|
||||||
|
|
||||||
# NOTE(Namrata): Add more tests which uses OSC.
|
echo "Running OSC commands test for Zun"
|
||||||
|
|
||||||
|
export ZUNCLIENT_DIR="$BASE/new/python-zunclient"
|
||||||
|
|
||||||
|
sudo chown -R jenkins:stack $ZUNCLIENT_DIR
|
||||||
|
|
||||||
|
# Go to the zunclient dir
|
||||||
|
cd $ZUNCLIENT_DIR
|
||||||
|
|
||||||
|
# Run tests
|
||||||
|
set +e
|
||||||
|
source $BASE/new/devstack/openrc admin admin
|
||||||
|
sudo -E -H -u jenkins ./tools/run_functional.sh
|
||||||
|
|
||||||
EXIT_CODE=$?
|
EXIT_CODE=$?
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
|
||||||
$XTRACE
|
$XTRACE
|
||||||
exit $EXIT_CODE
|
exit $EXIT_CODE
|
||||||
|
0
zunclient/tests/functional/osc/__init__.py
Normal file
0
zunclient/tests/functional/osc/__init__.py
Normal file
0
zunclient/tests/functional/osc/v1/__init__.py
Normal file
0
zunclient/tests/functional/osc/v1/__init__.py
Normal file
45
zunclient/tests/functional/osc/v1/base.py
Normal file
45
zunclient/tests/functional/osc/v1/base.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# 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 json
|
||||||
|
|
||||||
|
from zunclient.tests.functional import base
|
||||||
|
|
||||||
|
|
||||||
|
class TestCase(base.FunctionalTestBase):
|
||||||
|
|
||||||
|
def openstack(self, *args, **kwargs):
|
||||||
|
return self._zun_osc(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_opts(self, fields=None, output_format='json'):
|
||||||
|
"""Get options for OSC output fields format.
|
||||||
|
|
||||||
|
:param List fields: List of fields to get
|
||||||
|
:param String output_format: Select output format
|
||||||
|
:return: String of formatted options
|
||||||
|
"""
|
||||||
|
if not fields:
|
||||||
|
return ' -f {0}'.format(output_format)
|
||||||
|
return ' -f {0} {1}'.format(output_format,
|
||||||
|
' '.join(['-c ' + it for it in fields]))
|
||||||
|
|
||||||
|
def container_list(self, fields=None, params=''):
|
||||||
|
"""List Container.
|
||||||
|
|
||||||
|
:param List fields: List of fields to show
|
||||||
|
:param String params: Additional kwargs
|
||||||
|
:return: list of JSON node objects
|
||||||
|
"""
|
||||||
|
opts = self.get_opts(fields=fields)
|
||||||
|
output = self.openstack('appcontainer list {0} {1}'
|
||||||
|
.format(opts, params))
|
||||||
|
return json.loads(output)
|
32
zunclient/tests/functional/osc/v1/test_container.py
Normal file
32
zunclient/tests/functional/osc/v1/test_container.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Copyright (c) 2016 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 ddt
|
||||||
|
|
||||||
|
from zunclient.tests.functional.osc.v1 import base
|
||||||
|
|
||||||
|
|
||||||
|
@ddt.ddt
|
||||||
|
class ContainerTests(base.TestCase):
|
||||||
|
"""Functional tests for container commands."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(ContainerTests, self).setUp()
|
||||||
|
|
||||||
|
def test_list(self):
|
||||||
|
"""Check container list command.
|
||||||
|
|
||||||
|
"""
|
||||||
|
container_list = self.container_list()
|
||||||
|
self.assertFalse(container_list)
|
Loading…
Reference in New Issue
Block a user