From 623e12320ec069a9ae9e05aeba7fc8a412e76d03 Mon Sep 17 00:00:00 2001 From: Sergey Murashov Date: Mon, 5 May 2014 17:18:25 +0400 Subject: [PATCH] Update mistral tests Update mistral tests for devstack gate job Change-Id: Ia56ea50d9f0da6ca0e98efa53a88ab2dfb499f3c Partly-Implements: blueprint mistral-open-qa-process --- .../contrib => functionaltests}/__init__.py | 0 functionaltests/api/__init__.py | 0 functionaltests/api/base.py | 99 +++++++++++++++ .../api/v1}/demo.yaml | 0 functionaltests/api/v1/test_mistral_basic.py | 115 +++++++++++++++++ functionaltests/post_test_hook.sh | 24 ++++ functionaltests/pre_test_hook.sh | 22 ++++ functionaltests/run_tests.sh | 31 +++++ mistral/tests/integration/contrib/base.py | 100 --------------- mistral/tests/integration/contrib/config.conf | 7 -- mistral/tests/integration/contrib/config.py | 40 ------ .../integration/contrib/test_mistral_basic.py | 118 ------------------ 12 files changed, 291 insertions(+), 265 deletions(-) rename {mistral/tests/integration/contrib => functionaltests}/__init__.py (100%) create mode 100644 functionaltests/api/__init__.py create mode 100644 functionaltests/api/base.py rename {mistral/tests/integration/contrib => functionaltests/api/v1}/demo.yaml (100%) create mode 100644 functionaltests/api/v1/test_mistral_basic.py create mode 100644 functionaltests/post_test_hook.sh create mode 100644 functionaltests/pre_test_hook.sh create mode 100644 functionaltests/run_tests.sh delete mode 100644 mistral/tests/integration/contrib/base.py delete mode 100644 mistral/tests/integration/contrib/config.conf delete mode 100644 mistral/tests/integration/contrib/config.py delete mode 100644 mistral/tests/integration/contrib/test_mistral_basic.py diff --git a/mistral/tests/integration/contrib/__init__.py b/functionaltests/__init__.py similarity index 100% rename from mistral/tests/integration/contrib/__init__.py rename to functionaltests/__init__.py diff --git a/functionaltests/api/__init__.py b/functionaltests/api/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/functionaltests/api/base.py b/functionaltests/api/base.py new file mode 100644 index 000000000..8b2862445 --- /dev/null +++ b/functionaltests/api/base.py @@ -0,0 +1,99 @@ + +# Copyright 2013 Mirantis, Inc. +# All Rights Reserved. +# +# 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 +import os +import testtools + +from tempest import clients +from tempest.common import rest_client +from tempest import config +from tempest import exceptions + +CONF = config.CONF + + +class MistralClient(rest_client.RestClient): + + def __init__(self, auth_provider): + super(MistralClient, self).__init__(auth_provider) + + self.service = 'workflow_service' + self.endpoint_url = 'publicURL' + + def get_list_obj(self, name): + resp, body = self.get(name) + return resp, json.loads(body) + + def create_obj(self, path, name): + post_body = '{"name": "%s"}' % name + resp, body = self.post(path, post_body) + return resp, json.loads(body) + + def delete_obj(self, path, name): + return self.delete('{path}/{name}'.format(path=path, name=name)) + + def update_obj(self, path, name): + post_body = '{"name": "%s"}' % (name + 'updated') + resp, body = self.put('{path}/{name}'.format(path=path, name=name), + post_body) + return resp, json.loads(body) + + def get_workbook_definition(self, name): + headers = {'X-Auth-Token': self.auth_provider.get_token()} + return self.get('v1/workbooks/{name}/definition'.format(name=name), + headers) + + def upload_workbook_definition(self, name): + headers = {'Content-Type': 'text/plain', + 'X-Auth-Token': self.auth_provider.get_token()} + + __location = os.path.realpath(os.path.join(os.getcwd(), + os.path.dirname(__file__))) + + file = open(os.path.join(__location, 'demo.yaml'), 'rb').read() + return self.put('v1/workbooks/{name}/definition'.format(name=name), + file, headers) + + +class TestCase(testtools.TestCase): + + @classmethod + def setUpClass(cls): + """ + This method allows to initialize authentication before + each test case and define parameters of Mistral API Service + """ + super(TestCase, cls).setUpClass() + + username = CONF.identity.username + password = CONF.identity.password + tenant_name = CONF.identity.tenant_name + + mgr = clients.Manager(username, password, tenant_name) + auth_provider = mgr.get_auth_provider(mgr.get_default_credentials()) + + cls.client = MistralClient(auth_provider) + cls.obj = [] + + def tearDown(self): + super(TestCase, self).tearDown() + + for i in self.obj: + try: + self.client.delete_obj(i[0], i[1]) + except exceptions.NotFound: + pass diff --git a/mistral/tests/integration/contrib/demo.yaml b/functionaltests/api/v1/demo.yaml similarity index 100% rename from mistral/tests/integration/contrib/demo.yaml rename to functionaltests/api/v1/demo.yaml diff --git a/functionaltests/api/v1/test_mistral_basic.py b/functionaltests/api/v1/test_mistral_basic.py new file mode 100644 index 000000000..ba35c66a7 --- /dev/null +++ b/functionaltests/api/v1/test_mistral_basic.py @@ -0,0 +1,115 @@ + + +# Copyright 2013 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 testtools + +from tempest import exceptions +from tempest import test + +from functionaltests.api import base + + +class SanityTests(base.TestCase): + + @test.attr(type='smoke') + def test_get_list_obj(self): + resp, _ = self.client.get_list_obj('') + self.assertEqual(200, resp.status) + + @test.attr(type='smoke') + def test_get_list_workbooks(self): + resp, body = self.client.get_list_obj('workbooks') + + self.assertEqual(200, resp.status) + self.assertEqual([], body['workbooks']) + + @test.attr(type='smoke') + def test_get_workbook(self): + self.client.create_obj('workbooks', 'test') + self.obj.append(['workbooks', 'test']) + resp, body = self.client.get_list_obj('workbooks/test') + + self.assertEqual(200, resp.status) + self.assertEqual('test', body['name']) + + @test.attr(type='smoke') + def test_get_executions(self): + self.client.create_obj('workbooks', 'test') + self.obj.append(['workbooks', 'test']) + resp, body = self.client.get_list_obj('workbooks/test/executions') + + self.assertEqual(200, resp.status) + self.assertEqual([], body['executions']) + + @test.attr(type='smoke') + def test_create_and_delete_workbook(self): + resp, body = self.client.create_obj('workbooks', 'test') + self.obj.append(['workbooks', 'test']) + + self.assertEqual(201, resp.status) + self.assertEqual('test', body['name']) + + resp, body = self.client.get_list_obj('workbooks') + + self.assertEqual(200, resp.status) + self.assertEqual('test', body['workbooks'][0]['name']) + + self.client.delete_obj('workbooks', 'test') + _, body = self.client.get_list_obj('workbooks') + + self.assertEqual([], body['workbooks']) + + @test.attr(type='smoke') + def test_update_workbook(self): + self.client.create_obj('workbooks', 'test') + self.obj.append(['workbooks', 'test']) + resp, body = self.client.update_obj('workbooks', 'test') + + self.assertEqual(200, resp.status) + self.assertEqual('testupdated', body['name']) + + self.obj.append(['workbooks', 'testupdated']) + + @test.attr(type='smoke') + def test_get_workbook_definition(self): + self.client.create_obj('workbooks', 'test') + self.obj.append(['workbooks', 'test']) + resp, body = self.client.get_workbook_definition('test') + + self.assertEqual(200, resp.status) + self.assertIsNotNone(body) + + @testtools.skip('It is not implemented') + @test.attr(type='smoke') + def test_upload_workbook_definition(self): + self.client.create_obj('workbooks', 'test1') + self.obj.append(['workbooks', 'test1']) + resp, body = self.client.upload_workbook_definition('test1') + + self.assertEqual(200, resp.status) + + @test.attr(type='negative') + def test_double_create_obj(self): + self.client.create_obj('workbooks', 'test') + self.obj.append(['workbooks', 'test']) + + self.assertRaises(exceptions.BadRequest, self.client.create_obj, + 'workbooks', 'test') + + self.client.delete_obj('workbooks', 'test') + _, body = self.client.get_list_obj('workbooks') + + self.assertEqual([], body['workbooks']) diff --git a/functionaltests/post_test_hook.sh b/functionaltests/post_test_hook.sh new file mode 100644 index 000000000..98cb78df9 --- /dev/null +++ b/functionaltests/post_test_hook.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# +# 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. + +# This script is executed inside post_test_hook function in devstack gate. + +cd /opt/stack/new/mistral/functionaltests +sudo ./run_tests.sh +RETVAL=$? + +# Copy tempest log files to be published among other logs upon job completion +sudo cp /opt/stack/new/mistral/functionaltests/tempest.log /opt/stack/logs + +exit $RETVAL diff --git a/functionaltests/pre_test_hook.sh b/functionaltests/pre_test_hook.sh new file mode 100644 index 000000000..2e1c1e182 --- /dev/null +++ b/functionaltests/pre_test_hook.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# +# 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. + +# This script is executed inside pre_test_hook function in desvstack gate. + +# Install Murano devstack integration +MISTRAL_BASE=/opt/stack/new/mistral/contrib/devstack +DEVSTACK_BASE=/opt/stack/new/devstack +cp $MISTRAL_BASE/lib/* $DEVSTACK_BASE/lib +cp $MISTRAL_BASE/extras.d/* $DEVSTACK_BASE/extras.d + diff --git a/functionaltests/run_tests.sh b/functionaltests/run_tests.sh new file mode 100644 index 000000000..845b1b84f --- /dev/null +++ b/functionaltests/run_tests.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# +# 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. + +# How many seconds to wait for the API to be responding before giving up +API_RESPONDING_TIMEOUT=20 + +if ! timeout ${API_RESPONDING_TIMEOUT} sh -c "while ! curl -s http://127.0.0.1:8989/v1/ 2>/dev/null | grep -q 'Authentication required' ; do sleep 1; done"; then + echo "Mistral API failed to respond within ${API_RESPONDING_TIMEOUT} seconds" + exit 1 +fi + +echo "Successfully contacted Mistral API" + +# Where tempest code lives +TEMPEST_DIR=${TEMPEST_DIR:-/opt/stack/new/tempest} + +# Add tempest source tree to PYTHONPATH +export PYTHONPATH=$PYTHONPATH:$TEMPEST_DIR + +nosetests -sv . diff --git a/mistral/tests/integration/contrib/base.py b/mistral/tests/integration/contrib/base.py deleted file mode 100644 index 390c638e0..000000000 --- a/mistral/tests/integration/contrib/base.py +++ /dev/null @@ -1,100 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Mirantis, Inc. -# All Rights Reserved. -# -# 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 tempest.test -import json -from tempest.common import rest_client -import os -import tempest.api.mistral.config as cfg - - -class MistralTest(tempest.test.BaseTestCase): - - @classmethod - def setUpClass(cls): - """ - This method allows to initialize authentication before - each test case and define parameters of Mistral API Service - """ - super(MistralTest, cls).setUpClass() - - if not cfg.mistral.service_available: - raise cls.skipException("Mistral tests are disabled") - - user = cfg.mistral.user - password = cfg.mistral.password - tenant = cfg.mistral.tenant - auth_url = cfg.mistral.auth_url - client_args = (cls.config, user, password, auth_url, tenant) - - cls.client = rest_client.RestClient(*client_args) - cls.client.service = 'identity' - cls.token = cls.client.get_auth() - cls.client.base_url = cfg.mistral.mistral_url - cls.obj = [] - - def tearDown(self): - super(MistralTest, self).tearDown() - - for i in self.obj: - try: - self.delete_obj(i[0], i[1]) - except Exception: - pass - - def check_base_url(self): - resp, body = self.client.get('', self.client.headers) - return resp, json.loads(body) - - def check_base_url_with_version(self): - resp, body = self.client.get('v1/', self.client.headers) - return resp, json.loads(body) - - def get_list_obj(self, name): - resp, body = self.client.get('v1/%s' % name, self.client.headers) - return resp, json.loads(body) - - def create_obj(self, path, name): - post_body = '{"name": "%s"}' % name - resp, body = self.client.post('v1/%s/' % path, post_body, - self.client.headers) - return resp, json.loads(body) - - def delete_obj(self, path, name): - self.client.delete('v1/%s/%s' % (path, name), self.client.headers) - - def update_obj(self, path, name): - post_body = '{"name": "%s"}' % (name + 'updated') - resp, body = self.client.put('v1/%s/%s' % (path, name), post_body, - self.client.headers) - return resp, json.loads(body) - - def get_workbook_definition(self, name): - headers = {'X-Auth-Token': self.client.headers['X-Auth-Token']} - resp, body = self.client.get('v1/workbooks/%s/definition' % name, - headers) - return resp, body - - def upload_workbook_definition(self, name): - headers = {'Content-Type': 'text/plain', - 'X-Auth-Token': self.client.headers['X-Auth-Token']} - __location = os.path.realpath(os.path.join(os.getcwd(), - os.path.dirname(__file__))) - f = open(os.path.join(__location, 'demo.yaml'), 'rb').read() - resp, body = self.client.put('v1/workbooks/%s/definition' % name, f, - headers) - return resp, body diff --git a/mistral/tests/integration/contrib/config.conf b/mistral/tests/integration/contrib/config.conf deleted file mode 100644 index e312f784f..000000000 --- a/mistral/tests/integration/contrib/config.conf +++ /dev/null @@ -1,7 +0,0 @@ -[mistral] -auth_url = http://127.0.0.1:5000/v2.0/ -mistral_url = http://127.0.0.1:8084 -user = admin -password = password -tenant = admin -service_available = True \ No newline at end of file diff --git a/mistral/tests/integration/contrib/config.py b/mistral/tests/integration/contrib/config.py deleted file mode 100644 index 4b76d5ef8..000000000 --- a/mistral/tests/integration/contrib/config.py +++ /dev/null @@ -1,40 +0,0 @@ -import os -from oslo.config import cfg - - -mistral_group = cfg.OptGroup(name='mistral', title='mistral') - -MistralGroup = [ - cfg.StrOpt('auth_url', - default='http://127.0.0.1:5000/v2.0/', - help="keystone url"), - cfg.StrOpt('mistral_url', - default='http://127.0.0.1:8084', - help="mistral url"), - cfg.StrOpt('user', - default='admin', - help="keystone user"), - cfg.StrOpt('password', - default='password', - help="password for keystone user"), - cfg.StrOpt('tenant', - default='admin', - help='keystone tenant'), - cfg.BoolOpt('service_available', - default='True', - help='mistral available') -] - - -def register_config(config, config_group, config_opts): - config.register_group(config_group) - config.register_opts(config_opts, config_group) - -path = os.path.join("%s/config.conf" % os.getcwd()) - -if os.path.exists(path): - cfg.CONF([], project='mistralintegration', default_config_files=[path]) - -register_config(cfg.CONF, mistral_group, MistralGroup) - -mistral = cfg.CONF.mistral diff --git a/mistral/tests/integration/contrib/test_mistral_basic.py b/mistral/tests/integration/contrib/test_mistral_basic.py deleted file mode 100644 index 1045c8db0..000000000 --- a/mistral/tests/integration/contrib/test_mistral_basic.py +++ /dev/null @@ -1,118 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 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 testtools -from tempest.api.mistral import base -from tempest.test import attr -from tempest import exceptions - - -class SanityTests(base.MistralTest): - - @attr(type='smoke') - def test_check_base_url(self): - resp, _ = self.check_base_url() - self.assertEqual(resp['status'], '200') - - @attr(type='smoke') - def test_get_list_obj(self): - resp, _ = self.check_base_url_with_version() - self.assertEqual(resp['status'], '200') - - @attr(type='smoke') - def test_get_list_workbooks(self): - resp, body = self.get_list_obj('workbooks') - - self.assertEqual(resp['status'], '200') - self.assertEqual(body['workbooks'], []) - - @attr(type='smoke') - def test_get_workbook(self): - self.create_obj('workbooks', 'test') - self.obj.append(['workbooks', 'test']) - resp, body = self.get_list_obj('workbooks/test') - - self.assertEqual(resp['status'], '200') - self.assertEqual(body['name'], 'test') - - @attr(type='smoke') - def test_get_executions(self): - self.create_obj('workbooks', 'test') - self.obj.append(['workbooks', 'test']) - resp, body = self.get_list_obj('workbooks/test/executions') - - self.assertEqual(resp['status'], '200') - self.assertEqual(body['executions'], []) - - @attr(type='smoke') - def test_create_and_delete_workbook(self): - resp, body = self.create_obj('workbooks', 'test') - self.obj.append(['workbooks', 'test']) - - self.assertEqual(resp['status'], '201') - self.assertEqual(body['name'], 'test') - - resp, body = self.get_list_obj('workbooks') - - self.assertEqual(resp['status'], '200') - self.assertEqual(body['workbooks'][0]['name'], 'test') - - self.delete_obj('workbooks', 'test') - _, body = self.get_list_obj('workbooks') - - self.assertEqual(body['workbooks'], []) - - @attr(type='smoke') - def test_update_workbook(self): - self.create_obj('workbooks', 'test') - self.obj.append(['workbooks', 'test']) - resp, body = self.update_obj('workbooks', 'test') - - self.assertEqual(resp['status'], '200') - self.assertEqual(body['name'], 'testupdated') - - self.obj.append(['workbooks', 'testupdated']) - - @attr(type='smoke') - def test_get_workbook_definition(self): - self.create_obj('workbooks', 'test') - self.obj.append(['workbooks', 'test']) - resp, body = self.get_workbook_definition('test') - - self.assertEqual(resp['status'], '200') - self.assertIsNotNone(body) - - @testtools.skip('It is not implemented') - @attr(type='smoke') - def test_upload_workbook_definition(self): - self.create_obj('workbooks', 'test1') - self.obj.append(['workbooks', 'test1']) - resp, body = self.upload_workbook_definition('test1') - - self.assertEqual(resp['status'], '200') - - @attr(type='negative') - def test_double_create_obj(self): - self.create_obj('workbooks', 'test') - self.obj.append(['workbooks', 'test']) - - self.assertRaises(exceptions.BadRequest, self.create_obj, 'workbooks', - 'test') - - self.delete_obj('workbooks', 'test') - _, body = self.get_list_obj('workbooks') - - self.assertEqual(body['workbooks'], [])