Add functional tests for runtime
Change-Id: Ie1c77a86f7682a50d8b85b4ca19be6f1f38c431b
This commit is contained in:
parent
ac9d477112
commit
be7a929743
@ -2,6 +2,7 @@
|
|||||||
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
|
test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
|
||||||
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
|
OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
|
||||||
OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \
|
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_id_option=--load-list $IDFILE
|
||||||
test_list_option=--list
|
test_list_option=--list
|
||||||
|
@ -19,6 +19,13 @@ function install_qinlingclient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function install_k8s {
|
||||||
|
pushd $QINLING_DIR
|
||||||
|
source tools/gate/setup_gate.sh
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function create_qinling_accounts {
|
function create_qinling_accounts {
|
||||||
create_service_user "qinling" "admin"
|
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 debug $QINLING_DEBUG
|
||||||
iniset $QINLING_CONF_FILE DEFAULT server all
|
iniset $QINLING_CONF_FILE DEFAULT server all
|
||||||
iniset $QINLING_CONF_FILE storage file_system_dir $QINLING_FUNCTION_STORAGE_DIR
|
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
|
# Setup keystone_authtoken section
|
||||||
configure_auth_token_middleware $QINLING_CONF_FILE qinling $QINLING_AUTH_CACHE_DIR
|
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
|
if is_service_enabled key; then
|
||||||
create_qinling_accounts
|
create_qinling_accounts
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo_summary "Installing kubernetes cluster"
|
||||||
|
install_k8s
|
||||||
|
|
||||||
configure_qinling
|
configure_qinling
|
||||||
|
|
||||||
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
|
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
|
||||||
|
@ -13,5 +13,34 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
if __name__ == '__main__':
|
from oslo_config import cfg
|
||||||
pass
|
|
||||||
|
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."),
|
||||||
|
]
|
||||||
|
@ -16,8 +16,11 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from tempest import config
|
||||||
from tempest.test_discover import plugins
|
from tempest.test_discover import plugins
|
||||||
|
|
||||||
|
from qinling_tempest_plugin import config as qinling_config
|
||||||
|
|
||||||
|
|
||||||
class QinlingTempestPlugin(plugins.TempestPlugin):
|
class QinlingTempestPlugin(plugins.TempestPlugin):
|
||||||
def load_tests(self):
|
def load_tests(self):
|
||||||
@ -29,7 +32,26 @@ class QinlingTempestPlugin(plugins.TempestPlugin):
|
|||||||
return full_test_dir, base_path
|
return full_test_dir, base_path
|
||||||
|
|
||||||
def register_opts(self, conf):
|
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):
|
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]
|
||||||
|
@ -14,15 +14,4 @@
|
|||||||
|
|
||||||
# This script is executed inside pre_test_hook function in devstack gate.
|
# This script is executed inside pre_test_hook function in devstack gate.
|
||||||
|
|
||||||
set -ex
|
echo "Pass"
|
||||||
|
|
||||||
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
|
|
||||||
|
44
qinling_tempest_plugin/services/base.py
Normal file
44
qinling_tempest_plugin/services/base.py
Normal 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)
|
32
qinling_tempest_plugin/services/qinling_client.py
Normal file
32
qinling_tempest_plugin/services/qinling_client.py
Normal 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)
|
55
qinling_tempest_plugin/tests/api/test_runtimes.py
Normal file
55
qinling_tempest_plugin/tests/api/test_runtimes.py
Normal 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)
|
52
qinling_tempest_plugin/tests/base.py
Normal file
52
qinling_tempest_plugin/tests/base.py
Normal 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'
|
@ -8,9 +8,11 @@ python-subunit>=0.0.18 # Apache-2.0/BSD
|
|||||||
sphinx>=1.6.2 # BSD
|
sphinx>=1.6.2 # BSD
|
||||||
oslosphinx>=4.7.0 # Apache-2.0
|
oslosphinx>=4.7.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
|
||||||
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
|
||||||
testtools>=1.4.0 # MIT
|
testtools>=1.4.0 # MIT
|
||||||
|
tempest>=16.1.0 # Apache-2.0
|
||||||
|
|
||||||
# releasenotes
|
# releasenotes
|
||||||
reno!=2.3.1,>=1.8.0 # Apache-2.0
|
reno!=2.3.1,>=1.8.0 # Apache-2.0
|
||||||
|
2
tox.ini
2
tox.ini
@ -12,7 +12,7 @@ setenv =
|
|||||||
deps = -r{toxinidir}/test-requirements.txt
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
commands =
|
commands =
|
||||||
find . -type f -name "*.pyc" -delete
|
find . -type f -name "*.pyc" -delete
|
||||||
python setup.py testr --slowest --testr-args='{posargs}'
|
ostestr {posargs}
|
||||||
whitelist_externals =
|
whitelist_externals =
|
||||||
rm
|
rm
|
||||||
find
|
find
|
||||||
|
Loading…
x
Reference in New Issue
Block a user