Add functional tests for runtime

Change-Id: Ie1c77a86f7682a50d8b85b4ca19be6f1f38c431b
This commit is contained in:
Lingxian Kong 2017-09-04 16:18:57 +12:00
parent ac9d477112
commit be7a929743
11 changed files with 256 additions and 18 deletions

View File

@ -2,6 +2,7 @@
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 ./ . $LISTOPT $IDOPTION
OS_LOG_CAPTURE=${OS_LOG_CAPTURE:-1} \
${PYTHON:-python} -m subunit.run discover -t ./ ./qinling/tests $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

View File

@ -19,6 +19,13 @@ function install_qinlingclient {
}
function install_k8s {
pushd $QINLING_DIR
source tools/gate/setup_gate.sh
popd
}
function create_qinling_accounts {
create_service_user "qinling" "admin"
@ -60,6 +67,7 @@ function configure_qinling {
iniset $QINLING_CONF_FILE DEFAULT debug $QINLING_DEBUG
iniset $QINLING_CONF_FILE DEFAULT server all
iniset $QINLING_CONF_FILE storage file_system_dir $QINLING_FUNCTION_STORAGE_DIR
iniset $QINLING_CONF_FILE kubernetes qinling_service_address $DEFAULT_HOST_IP
# Setup keystone_authtoken section
configure_auth_token_middleware $QINLING_CONF_FILE qinling $QINLING_AUTH_CACHE_DIR
@ -116,6 +124,10 @@ if is_service_enabled qinling; then
if is_service_enabled key; then
create_qinling_accounts
fi
echo_summary "Installing kubernetes cluster"
install_k8s
configure_qinling
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then

View File

@ -13,5 +13,34 @@
# License for the specific language governing permissions and limitations
# under the License.
if __name__ == '__main__':
pass
from oslo_config import cfg
service_option = cfg.BoolOpt(
'qinling',
default=True,
help="Whether or not Qinling is expected to be"
"available"
)
qingling_group = cfg.OptGroup(name="qingling", title="Qinling Service Options")
QinlingGroup = [
cfg.StrOpt("region",
default="",
help="The region name to use. If empty, the value "
"of identity.region is used instead. If no such region "
"is found in the service catalog, the first found one is "
"used."),
cfg.StrOpt("catalog_type",
default="function",
help="Catalog type of the Qinling service."),
cfg.StrOpt('endpoint_type',
default='publicURL',
choices=['public', 'admin', 'internal',
'publicURL', 'adminURL', 'internalURL'],
help="The endpoint type to use for the qinling service."),
cfg.StrOpt('kube_host',
default='127.0.0.1:8001',
help="The Kubernetes service address."),
]

View File

@ -16,8 +16,11 @@
import os
from tempest import config
from tempest.test_discover import plugins
from qinling_tempest_plugin import config as qinling_config
class QinlingTempestPlugin(plugins.TempestPlugin):
def load_tests(self):
@ -29,7 +32,26 @@ class QinlingTempestPlugin(plugins.TempestPlugin):
return full_test_dir, base_path
def register_opts(self, conf):
pass
conf.register_opt(
qinling_config.service_option, group='service_available'
)
conf.register_group(qinling_config.qingling_group)
conf.register_opts(qinling_config.QinlingGroup, group='qinling')
def get_opt_lists(self):
pass
return [
('service_available', [qinling_config.service_option]),
(qinling_config.qingling_group.name, qinling_config.QinlingGroup)
]
def get_service_clients(self):
qinling_config = config.service_client_config('qinling')
params = {
'name': 'qinling',
'service_version': 'qinling',
'module_path': 'qinling_tempest_plugin.services.qinling_client',
'client_names': ['QinlingClient'],
}
params.update(qinling_config)
return [params]

View File

@ -14,15 +14,4 @@
# This script is executed inside pre_test_hook function in devstack gate.
set -ex
export localconf=$BASE/new/devstack/local.conf
export QINLING_CONF=/etc/qinling/qinling.conf
# Install k8s cluster
pushd $BASE/new/qinling/
bash tools/gate/setup_gate.sh
popd
echo -e "[[post-config|$QINLING_CONF]]\n[kubernetes]\n" >> $localconf
echo -e "qinling_service_address=${DEFAULT_HOST_IP}\n" >> $localconf
echo "Pass"

View File

@ -0,0 +1,44 @@
# Copyright 2017 Catalyst IT Ltd
#
# 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 tempest.lib.common import rest_client
class QinlingClientBase(rest_client.RestClient):
def __init__(self, auth_provider, **kwargs):
super(QinlingClientBase, self).__init__(auth_provider, **kwargs)
self.runtimes = []
def get_list_objs(self, url_path):
resp, body = self.get(url_path)
return resp, json.loads(body)
def delete_obj(self, obj, id):
return self.delete('{obj}/{id}'.format(obj=obj, id=id))
def get_obj(self, obj, id):
resp, body = self.get('{obj}/{id}'.format(obj=obj, id=id))
return resp, json.loads(body)
def post_json(self, url_path, obj, extra_headers={}):
headers = {"Content-Type": "application/json"}
headers = dict(headers, **extra_headers)
resp, body = self.post(url_path, json.dumps(obj), headers=headers)
return resp, json.loads(body)

View File

@ -0,0 +1,32 @@
# Copyright 2017 Catalyst IT Ltd
#
# 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 qinling_tempest_plugin.services import base as client_base
class QinlingClient(client_base.QinlingClientBase):
"""Tempest REST client for Qinling."""
def create_runtime(self, image, name=None):
body = {"image": image}
if name:
body.update({'name': name})
resp, body = self.post('runtimes', json.dumps(body))
self.runtimes.append(json.loads(body)['id'])
return resp, json.loads(body)

View File

@ -0,0 +1,55 @@
# Copyright 2017 Catalyst IT Ltd
#
# 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.
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from qinling_tempest_plugin.tests import base
class RuntimesTest(base.BaseQinlingTest):
name_prefix = 'RuntimesTest'
@decorators.idempotent_id('fdc2f07f-dd1d-4981-86d3-5bc7908d9a9b')
def test_create_delete_runtime(self):
name = data_utils.rand_name('runtime', prefix=self.name_prefix)
req_body = {
'name': name,
'image': 'openstackqinling/python-runtime'
}
resp, body = self.qinling_client.post_json('runtimes', req_body)
runtime_id = body['id']
self.assertEqual(201, resp.status)
self.assertEqual(name, body['name'])
resp, body = self.qinling_client.get_list_objs('runtimes')
self.assertEqual(200, resp.status)
self.assertIn(
runtime_id,
[runtime['id'] for runtime in body['runtimes']]
)
deploy = self.k8s_v1extention.read_namespaced_deployment(
runtime_id,
namespace=self.namespace
)
self.assertEqual(runtime_id, deploy.metadata.name)
resp, _ = self.qinling_client.delete_obj('runtimes', runtime_id)
self.assertEqual(204, resp.status)

View File

@ -0,0 +1,52 @@
# Copyright 2017 Catalyst IT Ltd
#
# 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.
from kubernetes import client as k8s_client
from tempest import config
from tempest import test
CONF = config.CONF
class BaseQinlingTest(test.BaseTestCase):
credentials = ('primary',)
force_tenant_isolation = False
@classmethod
def skip_checks(cls):
super(BaseQinlingTest, cls).skip_checks()
if not CONF.service_available.qinling:
raise cls.skipException("Qinling service is not available.")
@classmethod
def setup_clients(cls):
super(BaseQinlingTest, cls).setup_clients()
# os here is tempest.lib.services.clients.ServiceClients object
os = getattr(cls, 'os_%s' % cls.credentials[0])
cls.qinling_client = os.qinling.QinlingClient()
if CONF.identity.auth_version == 'v3':
project_id = os.auth_provider.auth_data[1]['project']['id']
else:
project_id = os.auth_provider.auth_data[1]['token']['tenant']['id']
cls.tenant_id = project_id
cls.user_id = os.auth_provider.auth_data[1]['user']['id']
# Initilize k8s client
k8s_client.Configuration().host = CONF.qinling.kube_host
cls.k8s_v1 = k8s_client.CoreV1Api()
cls.k8s_v1extention = k8s_client.ExtensionsV1beta1Api()
cls.namespace = 'qinling'

View File

@ -8,9 +8,11 @@ python-subunit>=0.0.18 # Apache-2.0/BSD
sphinx>=1.6.2 # BSD
oslosphinx>=4.7.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
os-testr>=0.8.0 # Apache-2.0
testrepository>=0.0.18 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
tempest>=16.1.0 # Apache-2.0
# releasenotes
reno!=2.3.1,>=1.8.0 # Apache-2.0

View File

@ -12,7 +12,7 @@ setenv =
deps = -r{toxinidir}/test-requirements.txt
commands =
find . -type f -name "*.pyc" -delete
python setup.py testr --slowest --testr-args='{posargs}'
ostestr {posargs}
whitelist_externals =
rm
find