From 4f57c90d69ff26fb4ea4000d01ec74fee0c0accc Mon Sep 17 00:00:00 2001 From: Chandan Kumar Date: Sun, 10 Dec 2017 15:25:48 +0530 Subject: [PATCH] Remove intree mistral tempest plugin * https://review.openstack.org/524869 moves the intree mistral tempest plugin to a new home openstack/mistral-tempest-plugin let's use it. * It also removed intree mistral tempest plugin as well as fix the jobs to use the same. Change-Id: I28ba8408452637aa093b343441f3715dc4754a3f --- .zuul.yaml | 3 + functionaltests/post_test_hook.sh | 3 +- mistral_tempest_tests/README.rst | 25 - mistral_tempest_tests/__init__.py | 0 mistral_tempest_tests/config.py | 21 - mistral_tempest_tests/plugin.py | 37 -- mistral_tempest_tests/services/__init__.py | 0 mistral_tempest_tests/services/base.py | 132 ------ mistral_tempest_tests/services/v2/__init__.py | 0 .../services/v2/mistral_client.py | 227 --------- mistral_tempest_tests/tests/__init__.py | 0 mistral_tempest_tests/tests/api/__init__.py | 0 .../tests/api/v2/__init__.py | 0 .../tests/api/v2/test_action_executions.py | 254 ---------- .../tests/api/v2/test_actions.py | 414 ---------------- .../tests/api/v2/test_cron_triggers.py | 237 ---------- .../tests/api/v2/test_event_triggers.py | 114 ----- .../tests/api/v2/test_executions.py | 440 ----------------- .../tests/api/v2/test_tasks.py | 108 ----- .../tests/api/v2/test_workbooks.py | 138 ------ .../tests/api/v2/test_workflows.py | 442 ------------------ mistral_tempest_tests/tests/base.py | 91 ---- .../tests/resources/action_v2.yaml | 21 - .../for_wf_namespace/lowest_level_wf.yaml | 6 - .../resources/for_wf_namespace/middle_wf.yaml | 6 - .../for_wf_namespace/top_level_wf.yaml | 6 - .../openstack/action_collection_wb.yaml | 75 --- .../tests/resources/single_wf.yaml | 11 - .../tests/resources/wb_v1.yaml | 12 - .../tests/resources/wb_v2.yaml | 13 - .../tests/resources/wb_with_nested_wf.yaml | 18 - .../resources/wf_action_ex_concurrency.yaml | 8 - .../resources/wf_task_ex_concurrency.yaml | 11 - .../tests/resources/wf_v2.yaml | 55 --- .../tests/scenario/__init__.py | 0 .../tests/scenario/engine/__init__.py | 0 .../tests/scenario/engine/actions/__init__.py | 0 .../scenario/engine/actions/v2/__init__.py | 0 .../v2/test_multi_vim_authentication.py | 145 ------ .../actions/v2/test_openstack_actions.py | 112 ----- .../engine/actions/v2/test_ssh_actions.py | 295 ------------ mistral_tempest_tests/tests/ssh_utils.py | 103 ---- mistral_tempest_tests/tests/utils.py | 152 ------ .../mistral-devstack-dsvm-kombu/run.yaml | 14 + .../mistral-devstack-dsvm-non-apache/run.yaml | 14 + .../legacy/mistral-devstack-dsvm/run.yaml | 14 + setup.cfg | 3 - tox.ini | 1 - 48 files changed, 46 insertions(+), 3735 deletions(-) delete mode 100644 mistral_tempest_tests/README.rst delete mode 100644 mistral_tempest_tests/__init__.py delete mode 100644 mistral_tempest_tests/config.py delete mode 100644 mistral_tempest_tests/plugin.py delete mode 100644 mistral_tempest_tests/services/__init__.py delete mode 100644 mistral_tempest_tests/services/base.py delete mode 100644 mistral_tempest_tests/services/v2/__init__.py delete mode 100644 mistral_tempest_tests/services/v2/mistral_client.py delete mode 100644 mistral_tempest_tests/tests/__init__.py delete mode 100644 mistral_tempest_tests/tests/api/__init__.py delete mode 100644 mistral_tempest_tests/tests/api/v2/__init__.py delete mode 100644 mistral_tempest_tests/tests/api/v2/test_action_executions.py delete mode 100644 mistral_tempest_tests/tests/api/v2/test_actions.py delete mode 100644 mistral_tempest_tests/tests/api/v2/test_cron_triggers.py delete mode 100644 mistral_tempest_tests/tests/api/v2/test_event_triggers.py delete mode 100644 mistral_tempest_tests/tests/api/v2/test_executions.py delete mode 100644 mistral_tempest_tests/tests/api/v2/test_tasks.py delete mode 100644 mistral_tempest_tests/tests/api/v2/test_workbooks.py delete mode 100644 mistral_tempest_tests/tests/api/v2/test_workflows.py delete mode 100644 mistral_tempest_tests/tests/base.py delete mode 100755 mistral_tempest_tests/tests/resources/action_v2.yaml delete mode 100755 mistral_tempest_tests/tests/resources/for_wf_namespace/lowest_level_wf.yaml delete mode 100755 mistral_tempest_tests/tests/resources/for_wf_namespace/middle_wf.yaml delete mode 100755 mistral_tempest_tests/tests/resources/for_wf_namespace/top_level_wf.yaml delete mode 100755 mistral_tempest_tests/tests/resources/openstack/action_collection_wb.yaml delete mode 100755 mistral_tempest_tests/tests/resources/single_wf.yaml delete mode 100755 mistral_tempest_tests/tests/resources/wb_v1.yaml delete mode 100755 mistral_tempest_tests/tests/resources/wb_v2.yaml delete mode 100755 mistral_tempest_tests/tests/resources/wb_with_nested_wf.yaml delete mode 100755 mistral_tempest_tests/tests/resources/wf_action_ex_concurrency.yaml delete mode 100755 mistral_tempest_tests/tests/resources/wf_task_ex_concurrency.yaml delete mode 100755 mistral_tempest_tests/tests/resources/wf_v2.yaml delete mode 100644 mistral_tempest_tests/tests/scenario/__init__.py delete mode 100644 mistral_tempest_tests/tests/scenario/engine/__init__.py delete mode 100644 mistral_tempest_tests/tests/scenario/engine/actions/__init__.py delete mode 100644 mistral_tempest_tests/tests/scenario/engine/actions/v2/__init__.py delete mode 100644 mistral_tempest_tests/tests/scenario/engine/actions/v2/test_multi_vim_authentication.py delete mode 100644 mistral_tempest_tests/tests/scenario/engine/actions/v2/test_openstack_actions.py delete mode 100644 mistral_tempest_tests/tests/scenario/engine/actions/v2/test_ssh_actions.py delete mode 100755 mistral_tempest_tests/tests/ssh_utils.py delete mode 100755 mistral_tempest_tests/tests/utils.py diff --git a/.zuul.yaml b/.zuul.yaml index 0e59a584d..e14799487 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -13,6 +13,7 @@ - openstack/python-mistralclient - openstack/zaqar - openstack/python-zaqarclient + - openstack/mistral-tempest-plugin - job: name: mistral-devstack-dsvm-kombu @@ -29,6 +30,7 @@ - openstack/python-mistralclient - openstack/zaqar - openstack/python-zaqarclient + - openstack/mistral-tempest-plugin - job: name: mistral-devstack-dsvm-non-apache @@ -45,6 +47,7 @@ - openstack/python-mistralclient - openstack/zaqar - openstack/python-zaqarclient + - openstack/mistral-tempest-plugin - job: name: mistral-docker-buildimage diff --git a/functionaltests/post_test_hook.sh b/functionaltests/post_test_hook.sh index 798ec2846..d126aa8dd 100755 --- a/functionaltests/post_test_hook.sh +++ b/functionaltests/post_test_hook.sh @@ -30,5 +30,4 @@ sudo cp $BASE/new/tempest/etc/logging.conf.sample $BASE/new/tempest/etc/logging. (cd $BASE/new/mistral/; sudo python setup.py install) export TOX_TESTENV_PASSENV=ZUUL_PROJECT -(cd $BASE/new/tempest/; sudo -E testr init) -(cd $BASE/new/tempest/; sudo -E tox -eall-plugin mistral) \ No newline at end of file +(cd $BASE/new/tempest/; sudo -E tox -evenv-tempest -- tempest run -r mistral) diff --git a/mistral_tempest_tests/README.rst b/mistral_tempest_tests/README.rst deleted file mode 100644 index 1a517fa85..000000000 --- a/mistral_tempest_tests/README.rst +++ /dev/null @@ -1,25 +0,0 @@ -============================== -Tempest Integration of Mistral -============================== - -This directory contains Tempest tests to cover the mistral project. - -To list all Mistral tempest cases, go to tempest directory, then run:: - - $ testr list-tests mistral - -To run only these tests in tempest, go to tempest directory, then run:: - - $ ./run_tempest.sh -N -- mistral - -To run a single test case, go to tempest directory, then run with test case name, e.g.:: - - $ ./run_tempest.sh -N -- mistral_tempest_tests.tests.api.v2.test_mistral_basic_v2.WorkbookTestsV2.test_get_workbook - -Alternatively, to run mistral tempest plugin tests using tox, go to tempest directory, then run:: - - $ tox -eall-plugin mistral - -And, to run a specific test:: - - $ tox -eall-plugin mistral_tempest_tests.tests.api.v2.test_mistral_basic_v2.WorkbookTestsV2.test_get_workbook diff --git a/mistral_tempest_tests/__init__.py b/mistral_tempest_tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral_tempest_tests/config.py b/mistral_tempest_tests/config.py deleted file mode 100644 index 23fe86215..000000000 --- a/mistral_tempest_tests/config.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2016 Catalyst IT Limited -# 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. - -from oslo_config import cfg - -service_option = cfg.BoolOpt('mistral', - default=True, - help="Whether or not Mistral is expected to be" - "available") diff --git a/mistral_tempest_tests/plugin.py b/mistral_tempest_tests/plugin.py deleted file mode 100644 index 15a9a95e4..000000000 --- a/mistral_tempest_tests/plugin.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2015 -# 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 os - -from tempest.test_discover import plugins - -from mistral_tempest_tests import config as mistral_config - - -class MistralTempestPlugin(plugins.TempestPlugin): - def load_tests(self): - base_path = os.path.split(os.path.dirname( - os.path.abspath(__file__)))[0] - test_dir = "mistral_tempest_tests/tests/" - full_test_dir = os.path.join(base_path, test_dir) - return full_test_dir, base_path - - def register_opts(self, conf): - conf.register_opt(mistral_config.service_option, - group='service_available') - - def get_opt_lists(self): - return [('service_available', [mistral_config.service_option])] diff --git a/mistral_tempest_tests/services/__init__.py b/mistral_tempest_tests/services/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral_tempest_tests/services/base.py b/mistral_tempest_tests/services/base.py deleted file mode 100644 index 5ee7d51b7..000000000 --- a/mistral_tempest_tests/services/base.py +++ /dev/null @@ -1,132 +0,0 @@ -# Copyright 2013 Mirantis, Inc. All Rights Reserved. -# Copyright 2016 NEC Corporation. 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 time - - -from tempest import config -from tempest.lib import auth -from tempest.lib.common import rest_client -from tempest.lib import exceptions - -CONF = config.CONF - - -def get_resource(path): - main_package = 'mistral_tempest_tests' - dir_path = __file__[0:__file__.find(main_package)] - - return open(dir_path + - 'mistral_tempest_tests/tests/resources/' + - path).read() - - -def find_items(items, **props): - def _matches(item, **props): - for prop_name, prop_val in props.items(): - if item[prop_name] != prop_val: - return False - - return True - - filtered = list([item for item in items if _matches(item, **props)]) - - if len(filtered) == 1: - return filtered[0] - - return filtered - - -class MistralClientBase(rest_client.RestClient): - def __init__(self, auth_provider, service_type): - super(MistralClientBase, self).__init__( - auth_provider=auth_provider, - service=service_type, - region=CONF.identity.region, - disable_ssl_certificate_validation=True - ) - - if service_type not in ('workflow', 'workflowv2'): - msg = "Invalid parameter 'service_type'. " - raise exceptions.UnprocessableEntity(msg) - - self.endpoint_url = 'publicURL' - - self.workbooks = [] - self.executions = [] - self.workflows = [] - self.triggers = [] - self.actions = [] - self.action_executions = [] - self.event_triggers = [] - - def get_list_obj(self, url_path): - resp, body = self.get(url_path) - - return resp, json.loads(body) - - def delete_obj(self, obj, name): - return self.delete('{obj}/{name}'.format(obj=obj, name=name)) - - def get_object(self, obj, id): - resp, body = self.get('{obj}/{id}'.format(obj=obj, id=id)) - - return resp, json.loads(body) - - def wait_execution_success(self, ex_body, timeout=180, url='executions'): - return self.wait_execution(ex_body, timeout=timeout, url=url) - - def wait_execution(self, ex_body, timeout=180, url='executions', - target_state='SUCCESS'): - start_time = time.time() - - expected_states = [target_state, 'RUNNING'] - - while ex_body['state'] != target_state: - if time.time() - start_time > timeout: - msg = ("Execution exceeds timeout {0} " - "to change state to {1}. " - "Execution: {2}".format(timeout, target_state, ex_body)) - raise exceptions.TimeoutException(msg) - - _, ex_body = self.get_object(url, ex_body['id']) - - if ex_body['state'] not in expected_states: - msg = ("Execution state %s is not in expected " - "states: %s" % (ex_body['state'], expected_states)) - raise exceptions.TempestException(msg) - - time.sleep(1) - - return ex_body - - -class AuthProv(auth.KeystoneV2AuthProvider): - def __init__(self): - self.alt_part = None - - def auth_request(self, method, url, *args, **kwargs): - req_url, headers, body = super(AuthProv, self).auth_request( - method, url, *args, **kwargs) - return 'http://localhost:8989/{0}/{1}'.format( - os.environ['VERSION'], url), headers, body - - def get_auth(self): - return 'mock_str', 'mock_str' - - def base_url(self, *args, **kwargs): - return '' diff --git a/mistral_tempest_tests/services/v2/__init__.py b/mistral_tempest_tests/services/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral_tempest_tests/services/v2/mistral_client.py b/mistral_tempest_tests/services/v2/mistral_client.py deleted file mode 100644 index 096161690..000000000 --- a/mistral_tempest_tests/services/v2/mistral_client.py +++ /dev/null @@ -1,227 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 - -from oslo_utils import uuidutils -from tempest import config - -from mistral_tempest_tests.services import base - -CONF = config.CONF - - -class MistralClientV2(base.MistralClientBase): - - def post_request(self, url_path, file_name): - headers = {"headers": "Content-Type:text/plain"} - - return self.post( - url_path, - base.get_resource(file_name), - headers=headers - ) - - def get_request(self, url_path): - headers = {"headers": "Content-Type:application/json"} - - return self.get(url_path, headers=headers) - - def post_json(self, url_path, obj, extra_headers={}): - headers = {"Content-Type": "application/json"} - headers = dict(headers, **extra_headers) - return self.post(url_path, json.dumps(obj), headers=headers) - - def update_request(self, url_path, file_name): - headers = {"headers": "Content-Type:text/plain"} - - resp, body = self.put( - url_path, - base.get_resource(file_name), - headers=headers - ) - - return resp, json.loads(body) - - def get_definition(self, item, name): - resp, body = self.get("%s/%s" % (item, name)) - - return resp, json.loads(body)['definition'] - - def create_workbook(self, yaml_file): - resp, body = self.post_request('workbooks', yaml_file) - - wb_name = json.loads(body)['name'] - self.workbooks.append(wb_name) - - _, wfs = self.get_list_obj('workflows') - - for wf in wfs['workflows']: - if wf['name'].startswith(wb_name): - self.workflows.append(wf['name']) - - return resp, json.loads(body) - - def create_workflow(self, yaml_file, scope=None, namespace=None): - url_path = 'workflows?' - - if scope: - url_path += 'scope=public&' - - if namespace: - url_path += 'namespace=' + namespace - - resp, body = self.post_request(url_path, yaml_file) - - for wf in json.loads(body)['workflows']: - identifier = wf['id'] if namespace else wf['name'] - self.workflows.append(identifier) - - return resp, json.loads(body) - - def get_workflow(self, wf_identifier, namespace=None): - - url_path = 'workflows/' + wf_identifier - if namespace: - url_path += 'namespace=' + namespace - - resp, body = self.get_request(url_path) - - return resp, json.loads(body) - - def update_workflow(self, file_name, namespace=None): - url_path = "workflows?" - - if namespace: - url_path += 'namespace=' + namespace - - return self.update_request(url_path, file_name=file_name) - - def get_action_execution(self, action_execution_id): - return self.get('action_executions/%s' % action_execution_id) - - def get_action_executions(self, task_id=None): - url_path = 'action_executions' - if task_id: - url_path += '?task_execution_id=%s' % task_id - - return self.get_list_obj(url_path) - - def create_execution(self, identifier, wf_namespace=None, wf_input=None, - params=None): - if uuidutils.is_uuid_like(identifier): - body = {"workflow_id": "%s" % identifier} - else: - body = {"workflow_name": "%s" % identifier} - - if wf_namespace: - body.update({'workflow_namespace': wf_namespace}) - - if wf_input: - body.update({'input': json.dumps(wf_input)}) - if params: - body.update({'params': json.dumps(params)}) - - resp, body = self.post('executions', json.dumps(body)) - - self.executions.append(json.loads(body)['id']) - - return resp, json.loads(body) - - def update_execution(self, execution_id, put_body): - resp, body = self.put('executions/%s' % execution_id, put_body) - - return resp, json.loads(body) - - def get_execution(self, execution_id): - return self.get('executions/%s' % execution_id) - - def get_executions(self, task_id): - url_path = 'executions' - if task_id: - url_path += '?task_execution_id=%s' % task_id - - return self.get_list_obj(url_path) - - def get_tasks(self, execution_id=None): - url_path = 'tasks' - if execution_id: - url_path += '?workflow_execution_id=%s' % execution_id - - return self.get_list_obj(url_path) - - def create_cron_trigger(self, name, wf_name, wf_input=None, pattern=None, - first_time=None, count=None): - post_body = { - 'name': name, - 'workflow_name': wf_name, - 'pattern': pattern, - 'remaining_executions': count, - 'first_execution_time': first_time - } - - if wf_input: - post_body.update({'workflow_input': json.dumps(wf_input)}) - - rest, body = self.post('cron_triggers', json.dumps(post_body)) - - self.triggers.append(name) - - return rest, json.loads(body) - - def create_action(self, yaml_file): - resp, body = self.post_request('actions', yaml_file) - - self.actions.extend( - [action['name'] for action in json.loads(body)['actions']]) - - return resp, json.loads(body) - - def get_wf_tasks(self, wf_name): - all_tasks = self.get_list_obj('tasks')[1]['tasks'] - - return [t for t in all_tasks if t['workflow_name'] == wf_name] - - def create_action_execution(self, request_body, extra_headers={}): - resp, body = self.post_json('action_executions', request_body, - extra_headers) - - params = json.loads(request_body.get('params', '{}')) - if params.get('save_result', False): - self.action_executions.append(json.loads(body)['id']) - - return resp, json.loads(body) - - def create_event_trigger(self, wf_id, exchange, topic, event, name='', - wf_input=None, wf_params=None): - post_body = { - 'workflow_id': wf_id, - 'exchange': exchange, - 'topic': topic, - 'event': event, - 'name': name - } - - if wf_input: - post_body.update({'workflow_input': json.dumps(wf_input)}) - - if wf_params: - post_body.update({'workflow_params': json.dumps(wf_params)}) - - rest, body = self.post('event_triggers', json.dumps(post_body)) - - event_trigger = json.loads(body) - self.event_triggers.append(event_trigger['id']) - - return rest, event_trigger diff --git a/mistral_tempest_tests/tests/__init__.py b/mistral_tempest_tests/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral_tempest_tests/tests/api/__init__.py b/mistral_tempest_tests/tests/api/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral_tempest_tests/tests/api/v2/__init__.py b/mistral_tempest_tests/tests/api/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral_tempest_tests/tests/api/v2/test_action_executions.py b/mistral_tempest_tests/tests/api/v2/test_action_executions.py deleted file mode 100644 index 6b5a30bcb..000000000 --- a/mistral_tempest_tests/tests/api/v2/test_action_executions.py +++ /dev/null @@ -1,254 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 six - -from oslo_log import log as logging -from tempest.lib import decorators -from tempest.lib import exceptions - -from mistral_tempest_tests.tests import base - - -LOG = logging.getLogger(__name__) - - -class ActionExecutionTestsV2(base.TestCase): - _service = 'workflowv2' - - @classmethod - def resource_setup(cls): - super(ActionExecutionTestsV2, cls).resource_setup() - - cls.client.create_action_execution( - { - 'name': 'std.echo', - 'input': '{"output": "Hello, Mistral!"}' - } - ) - - @classmethod - def resource_cleanup(cls): - for action_ex in cls.client.action_executions: - try: - cls.client.delete_obj('action_executions', action_ex) - except Exception as e: - LOG.exception( - 'Exception raised when deleting ' - 'action_executions %s, error message: %s.', - action_ex, six.text_type(e) - ) - - cls.client.action_executions = [] - - super(ActionExecutionTestsV2, cls).resource_cleanup() - - @decorators.attr(type='sanity') - @decorators.idempotent_id('a72603bd-5d49-4d92-9747-8da6322e867d') - def test_run_action_execution(self): - resp, body = self.client.create_action_execution( - { - 'name': 'std.echo', - 'input': '{"output": "Hello, Mistral!"}' - } - ) - - self.assertEqual(201, resp.status) - output = json.loads(body['output']) - self.assertDictEqual( - {'result': 'Hello, Mistral!'}, - output - ) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('0623cb62-b20a-45c8-afd9-8da46e1bb3cb') - def test_list_action_executions(self): - resp, body = self.client.get_list_obj('action_executions') - - self.assertEqual(200, resp.status) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('cd36ea00-7e22-4c3d-90c3-fb441b93cf12') - def test_output_appear_in_response_only_when_needed(self): - resp, body = self.client.get_list_obj('action_executions') - - self.assertEqual(200, resp.status) - action_execution = body['action_executions'][0] - self.assertNotIn("output", action_execution) - - resp, body = self.client.get_list_obj( - 'action_executions?include_output=True' - ) - - self.assertEqual(200, resp.status) - action_execution = body['action_executions'][0] - self.assertIn("output", action_execution) - - resp, body = self.client.get_action_execution(action_execution['id']) - self.assertIn("output", body) - - # Test when passing task execution ID - - resp, body = self.client.create_workflow('wf_v2.yaml') - wf_name = body['workflows'][0]['name'] - self.assertEqual(201, resp.status) - resp, body = self.client.create_execution(wf_name) - self.assertEqual(201, resp.status) - resp, body = self.client.get_list_obj('tasks') - self.assertEqual(200, resp.status) - task_id = body['tasks'][0]['id'] - - resp, body = self.client.get_list_obj( - 'action_executions?include_output=true&task_execution_id=%s' % - task_id - ) - - self.assertEqual(200, resp.status) - action_execution = body['action_executions'][0] - self.assertIn("output", action_execution) - - resp, body = self.client.get_list_obj( - 'action_executions?&task_execution_id=%s' % - task_id - ) - - self.assertEqual(200, resp.status) - action_execution = body['action_executions'][0] - self.assertNotIn("output", action_execution) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('dc76aeda-9243-45cf-bfd2-141d3af8b28b') - def test_run_action_std_http(self): - resp, body = self.client.create_action_execution( - { - 'name': 'std.http', - 'input': '{"url": "http://wiki.openstack.org"}' - } - ) - - self.assertEqual(201, resp.status) - output = json.loads(body['output']) - self.assertTrue(output['result']['status'] in range(200, 307)) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('befa9b1c-01a4-41bc-b060-88cb1b147dfb') - def test_run_action_std_http_error(self): - resp, body = self.client.create_action_execution( - { - 'name': 'std.http', - 'input': '{"url": "http://www.google.ru/not-found-test"}' - } - ) - - self.assertEqual(201, resp.status) - output = json.loads(body['output']) - self.assertEqual(404, output['result']['status']) - - @decorators.attr(type='sanity') - @decorators.related_bug('1667415') - @decorators.idempotent_id('3c73de7a-4af0-4657-90d6-d7ebd3c7da18') - def test_run_action_std_http_non_utf8_response(self): - resp, body = self.client.create_action_execution( - { - 'name': 'std.http', - 'input': - '{"url": "https://httpbin.org/encoding/utf8"}' - } - ) - - self.assertEqual(201, resp.status) - output = json.loads(body['output']) - self.assertEqual(200, output['result']['status']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('d98586bf-fdc4-44f6-9837-700d35b5f889') - def test_create_action_execution(self): - resp, body = self.client.create_action_execution( - { - 'name': 'std.echo', - 'input': '{"output": "Hello, Mistral!"}', - 'params': '{"save_result": true}' - } - ) - - self.assertEqual(201, resp.status) - self.assertEqual('RUNNING', body['state']) - - # We must reread action execution in order to get actual - # state and output. - body = self.client.wait_execution_success( - body, - url='action_executions' - ) - output = json.loads(body['output']) - - self.assertEqual('SUCCESS', body['state']) - self.assertDictEqual( - {'result': 'Hello, Mistral!'}, - output - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('99f22c17-6fb4-4480-96d3-4a82672916b7') - def test_delete_nonexistent_action_execution(self): - self.assertRaises( - exceptions.NotFound, - self.client.delete_obj, - 'action_executions', - 'nonexist' - ) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('2dbd74ba-4950-4c52-8bd3-070d634dcd05') - def test_create_action_execution_sync(self): - resp, body = self.client.create_action_execution( - { - 'name': 'std.echo', - 'input': '{"output": "Hello Tempest"}' - } - ) - - self.assertEqual(201, resp.status) - output = json.loads(body['output']) - self.assertEqual("Hello Tempest", output['result']) - - @decorators.idempotent_id('9438e195-031c-4502-b216-6d72941ec281') - @decorators.attr(type='sanity') - def test_action_execution_of_workflow_within_namespace(self): - - resp, body = self.client.create_workflow('wf_v2.yaml', namespace='abc') - wf_name = "wf" - wf_namespace = body['workflows'][0]['namespace'] - self.assertEqual(201, resp.status) - resp, execution = self.client.create_execution( - wf_name, - wf_namespace=wf_namespace - ) - self.client.wait_execution_success(execution) - self.assertEqual(201, resp.status) - resp, body = self.client.get_list_obj('tasks') - self.assertEqual(200, resp.status) - task_id = body['tasks'][0]['id'] - - resp, body = self.client.get_list_obj( - 'action_executions?include_output=true&task_execution_id=%s' % - task_id) - - self.assertEqual(200, resp.status) - action_execution = body['action_executions'][0] - - self.assertEqual(200, resp.status) - action_execution = body['action_executions'][0] - self.assertEqual(wf_namespace, action_execution['workflow_namespace']) diff --git a/mistral_tempest_tests/tests/api/v2/test_actions.py b/mistral_tempest_tests/tests/api/v2/test_actions.py deleted file mode 100644 index 0ee35df68..000000000 --- a/mistral_tempest_tests/tests/api/v2/test_actions.py +++ /dev/null @@ -1,414 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 datetime -from tempest.lib import decorators -from tempest.lib import exceptions - -from mistral_tempest_tests.tests import base -from mistral_tempest_tests.tests import utils - - -class ActionTestsV2(base.TestCase): - - _service = 'workflowv2' - - def get_field_value(self, body, act_name, field): - return [body['actions'][i][field] - for i in range(len(body['actions'])) - if body['actions'][i]['name'] == act_name][0] - - def tearDown(self): - for act in self.client.actions: - self.client.delete_obj('actions', act) - self.client.actions = [] - - super(ActionTestsV2, self).tearDown() - - @decorators.attr(type='smoke') - @decorators.idempotent_id('2e1a578a-1c27-409a-96be-84b5c41498cd') - def test_get_list_actions(self): - resp, body = self.client.get_list_obj('actions') - - self.assertEqual(200, resp.status) - self.assertNotEmpty(body['actions']) - self.assertNotIn('next', body) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('786ee85c-c32d-4ac9-8f45-79ab6bc47ef1') - def test_get_list_actions_with_pagination(self): - resp, body = self.client.get_list_obj( - 'actions?limit=1&sort_keys=name&sort_dirs=desc' - ) - - self.assertEqual(200, resp.status) - self.assertEqual(1, len(body['actions'])) - self.assertIn('next', body) - - name_1 = body['actions'][0].get('name') - next = body.get('next') - - param_dict = utils.get_dict_from_string( - next.split('?')[1], - delimiter='&' - ) - - # NOTE: 'id' gets included into sort keys automatically with 'desc' - # sorting to avoid pagination looping. - expected_sub_dict = { - 'limit': 1, - 'sort_keys': 'name,id', - 'sort_dirs': 'desc,asc' - } - - self.assertDictContainsSubset(expected_sub_dict, param_dict) - - # Query again using 'next' hint - url_param = next.split('/')[-1] - resp, body = self.client.get_list_obj(url_param) - - self.assertEqual(200, resp.status) - self.assertEqual(1, len(body['actions'])) - - name_2 = body['actions'][0].get('name') - - self.assertGreater(name_1, name_2) - - @decorators.attr(type='negative') - @decorators.idempotent_id('5148358e-200f-49c7-8e88-1ddeec61c6a9') - def test_get_list_actions_nonexist_sort_dirs(self): - context = self.assertRaises( - exceptions.BadRequest, - self.client.get_list_obj, - 'actions?limit=1&sort_keys=id&sort_dirs=nonexist' - ) - - self.assertIn( - 'Unknown sort direction', - context.resp_body.get('faultstring') - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('85482ce8-70f4-47a6-9e80-de1ac22b6412') - def test_get_list_actions_invalid_limit(self): - context = self.assertRaises( - exceptions.BadRequest, - self.client.get_list_obj, - 'actions?limit=-1&sort_keys=id&sort_dirs=asc' - ) - - self.assertIn( - 'Limit must be positive', - context.resp_body.get('faultstring') - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('a203e75b-2013-422f-b9eb-da4375041058') - def test_get_list_actions_duplicate_sort_keys(self): - context = self.assertRaises( - exceptions.BadRequest, - self.client.get_list_obj, - 'actions?limit=1&sort_keys=id,id&sort_dirs=asc,asc' - ) - - self.assertIn( - 'Length of sort_keys must be equal or greater than sort_dirs', - context.resp_body.get('faultstring') - ) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('9a53af71-8f1e-4ad5-b572-2c4c621715c0') - def test_get_list_actions_equal_to_filter(self): - resp, body = self.client.create_action('action_v2.yaml') - self.assertEqual(201, resp.status) - - resp, body = self.client.get_list_obj('actions?is_system=False') - - self.assertEqual(200, resp.status) - self.assertNotEmpty(body['actions']) - - for act in body['actions']: - self.assertFalse(act['is_system']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('3c3d28ce-9490-41ae-a918-c28f843841e1') - def test_get_list_actions_not_equal_to_filter(self): - resp, body = self.client.create_action('action_v2.yaml') - self.assertEqual(201, resp.status) - - resp, body = self.client.get_list_obj('actions?is_system=neq:False') - - self.assertEqual(200, resp.status) - self.assertNotEmpty(body['actions']) - - for act in body['actions']: - self.assertTrue(act['is_system']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('84823a84-5caa-427d-8a2c-622a1d1893b1') - def test_get_list_actions_in_list_filter(self): - resp, body = self.client.create_action('action_v2.yaml') - self.assertEqual(201, resp.status) - - created_acts = [action['name'] for action in body['actions']] - _, body = self.client.get_object('actions', created_acts[0]) - time = body['created_at'] - resp, body = self.client.get_list_obj( - 'actions?created_at=in:' + time.replace(' ', '%20')) - - self.assertEqual(200, resp.status) - action_names = [action['name'] for action in body['actions']] - self.assertListEqual(created_acts, action_names) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('4b05dfcf-ef39-4032-9528-c8422c7329dd') - def test_get_list_actions_not_in_list_filter(self): - resp, body = self.client.create_action('action_v2.yaml') - self.assertEqual(201, resp.status) - - created_acts = [action['name'] for action in body['actions']] - _, body = self.client.get_object('actions', created_acts[0]) - time = body['created_at'] - resp, body = self.client.get_list_obj( - 'actions?created_at=nin:' + time.replace(' ', '%20') - ) - - self.assertEqual(200, resp.status) - action_names = [action['name'] for action in body['actions']] - for act in created_acts: - self.assertNotIn(act, action_names) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('20b3d527-447d-492b-8cb7-ac5e3757d7d5') - def test_get_list_actions_greater_than_filter(self): - time = datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S") - resp, body = self.client.get_list_obj( - 'actions?created_at=gt:' + time.replace(' ', '%20') - ) - - self.assertEqual(200, resp.status) - self.assertEmpty(body['actions']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('7f598dba-f169-47ec-a487-f0ed31484aff') - def test_get_list_actions_greater_than_equal_to_filter(self): - resp, body = self.client.create_action('action_v2.yaml') - self.assertEqual(201, resp.status) - - created_acts = [action['name'] for action in body['actions']] - _, body = self.client.get_object('actions', created_acts[0]) - time = body['created_at'] - resp, body = self.client.get_list_obj( - 'actions?created_at=gte:' + time.replace(' ', '%20') - ) - - actions = [action['name'] for action in body['actions']] - self.assertEqual(200, resp.status) - self.assertIn(created_acts[0], actions) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('874fb57d-a762-4dc3-841d-396657510d23') - def test_get_list_actions_less_than_filter(self): - resp, body = self.client.create_action('action_v2.yaml') - self.assertEqual(201, resp.status) - - created_acts = [action['name'] for action in body['actions']] - _, body = self.client.get_object('actions', created_acts[0]) - time = body['created_at'] - resp, body = self.client.get_list_obj( - 'actions?created_at=lt:' + time.replace(' ', '%20') - ) - - actions = [action['name'] for action in body['actions']] - self.assertEqual(200, resp.status) - self.assertNotIn(created_acts[0], actions) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('1fda6c31-b0c3-4b78-9f67-b920e1f6c973') - def test_get_list_actions_less_than_equal_to_filter(self): - resp, body = self.client.create_action('action_v2.yaml') - self.assertEqual(201, resp.status) - - created_acts = [action['name'] for action in body['actions']] - _, body = self.client.get_object('actions', created_acts[0]) - time = body['created_at'] - resp, body = self.client.get_list_obj( - 'actions?created_at=lte:' + time.replace(' ', '%20') - ) - - actions = [action['name'] for action in body['actions']] - self.assertEqual(200, resp.status) - self.assertIn(created_acts[0], actions) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('cbb716f1-7fc7-4884-8fa9-6ff2bc35ee29') - def test_get_list_actions_multiple_filter(self): - resp, body = self.client.create_action('action_v2.yaml') - self.assertEqual(201, resp.status) - - created_acts = [action['name'] for action in body['actions']] - _, body = self.client.get_object('actions', created_acts[0]) - time = body['created_at'] - resp, body = self.client.get_list_obj( - 'actions?created_at=lte:' + time.replace(' ', '%20') + - '&is_system=False' - ) - - actions = [action['name'] for action in body['actions']] - self.assertEqual(200, resp.status) - self.assertIn(created_acts[0], actions) - - @decorators.attr(type='negative') - @decorators.idempotent_id('45fdc1f3-4d89-4035-9b76-08ef94c92628') - def test_get_list_actions_invalid_filter(self): - self.assertRaises( - exceptions.BadRequest, - self.client.get_list_obj, - 'actions?is_system2016-02-23%2008:51:26' - ) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('5dbceaf3-6a32-4a4f-9427-1bbdb6f3c574') - def test_create_and_delete_few_actions(self): - resp, body = self.client.create_action('action_v2.yaml') - self.assertEqual(201, resp.status) - - created_acts = [action['name'] for action in body['actions']] - - resp, body = self.client.get_list_obj('actions') - self.assertEqual(200, resp.status) - - actions = [action['name'] for action in body['actions']] - - for act in created_acts: - self.assertIn(act, actions) - self.client.delete_obj('actions', act) - - _, body = self.client.get_list_obj('actions') - actions = [action['name'] for action in body['actions']] - - for act in created_acts: - self.assertNotIn(act, actions) - self.client.actions.remove(act) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('d7dad5de-6b1f-4813-b789-78f075252639') - def test_get_action(self): - _, body = self.client.create_action('action_v2.yaml') - action_name = body['actions'][0]['name'] - resp, body = self.client.get_object('actions', action_name) - - self.assertEqual(200, resp.status) - self.assertEqual(action_name, body['name']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('21a031c8-8e2d-421f-8dfe-71a3b5e44381') - def test_update_action(self): - _, body = self.client.create_action('action_v2.yaml') - action = body['actions'][0]['name'] - - act_created_at = self.get_field_value( - body=body, act_name=action, field='created_at') - - self.assertNotIn('updated at', body['actions']) - - resp, body = self.client.update_request('actions', 'action_v2.yaml') - self.assertEqual(200, resp.status) - - actions = [act['name'] for act in body['actions']] - self.assertIn(action, actions) - - updated_act_created_at = self.get_field_value( - body=body, act_name=action, field='created_at') - - self.assertEqual(act_created_at.split(".")[0], updated_act_created_at) - self.assertTrue(all(['updated_at' in item - for item in body['actions']])) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('329b1030-c55c-45f0-8129-cc892bc23dcc') - def test_get_action_definition(self): - _, body = self.client.create_action('action_v2.yaml') - act_name = body['actions'][0]['name'] - - resp, body = self.client.get_definition('actions', act_name) - self.assertEqual(200, resp.status) - self.assertIsNotNone(body) - self.assertIn(act_name, body) - - @decorators.attr(type='negative') - @decorators.idempotent_id('c2b5be88-571a-4855-922f-9a338dba6adb') - def test_get_nonexistent_action(self): - self.assertRaises( - exceptions.NotFound, - self.client.get_object, - 'actions', 'nonexist' - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('fc2fafcb-9bb4-4a18-a507-3f9964f4a08a') - def test_double_creation(self): - self.client.create_action('action_v2.yaml') - - self.assertRaises( - exceptions.Conflict, - self.client.create_action, - 'action_v2.yaml' - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('0c456a73-9c39-4aeb-b3ca-3ea4338bc9ab') - def test_create_action_invalid_def(self): - self.assertRaises( - exceptions.BadRequest, - self.client.create_action, - 'wb_v2.yaml' - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('469677b5-22ab-4e2a-aee6-5bcc9dac93de') - def test_update_action_invalid_def(self): - self.assertRaises( - exceptions.BadRequest, - self.client.update_request, - 'actions', 'wb_v2.yaml' - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('ab444607-40fc-47cb-982f-83762d5b64c9') - def test_delete_nonexistent_action(self): - self.assertRaises( - exceptions.NotFound, - self.client.delete_obj, - 'actions', 'nonexist' - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('74d0d480-793a-46ca-b88a-8336c1897f3a') - def test_delete_standard_action(self): - self.assertRaises( - exceptions.BadRequest, - self.client.delete_obj, - 'actions', 'nova.servers_create' - ) diff --git a/mistral_tempest_tests/tests/api/v2/test_cron_triggers.py b/mistral_tempest_tests/tests/api/v2/test_cron_triggers.py deleted file mode 100644 index 1099c4ccd..000000000 --- a/mistral_tempest_tests/tests/api/v2/test_cron_triggers.py +++ /dev/null @@ -1,237 +0,0 @@ -# Copyright 2016 NEC Corporation. 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. - -from oslo_concurrency.fixture import lockutils -from tempest.lib import decorators -from tempest.lib import exceptions - -from mistral_tempest_tests.tests import base - - -class CronTriggerTestsV2(base.TestCase): - - _service = 'workflowv2' - - def setUp(self): - super(CronTriggerTestsV2, self).setUp() - self.useFixture(lockutils.LockFixture('mistral-workflow')) - _, body = self.client.create_workflow('wf_v2.yaml') - self.wf_name = body['workflows'][0]['name'] - - def tearDown(self): - - for tr in self.client.triggers: - self.client.delete_obj('cron_triggers', tr) - self.client.triggers = [] - - for wf in self.client.workflows: - self.client.delete_obj('workflows', wf) - self.client.workflows = [] - - super(CronTriggerTestsV2, self).tearDown() - - @decorators.attr(type='smoke') - @decorators.idempotent_id('c53b44dd-59b3-4a4b-b22a-21abb4cecea0') - def test_get_list_cron_triggers(self): - resp, body = self.client.get_list_obj('cron_triggers') - - self.assertEqual(200, resp.status) - self.assertEmpty(body['cron_triggers']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('fbc641fa-8704-45b3-b259-136eb956394c') - def test_create_and_delete_cron_triggers(self): - tr_name = 'trigger' - - resp, body = self.client.create_cron_trigger( - tr_name, self.wf_name, None, '5 * * * *') - self.assertEqual(201, resp.status) - self.assertEqual(tr_name, body['name']) - - resp, body = self.client.get_list_obj('cron_triggers') - self.assertEqual(200, resp.status) - - trs_names = [tr['name'] for tr in body['cron_triggers']] - self.assertIn(tr_name, trs_names) - - self.client.delete_obj('cron_triggers', tr_name) - self.client.triggers.remove(tr_name) - - _, body = self.client.get_list_obj('cron_triggers') - - trs_names = [tr['name'] for tr in body['cron_triggers']] - self.assertNotIn(tr_name, trs_names) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('b8b9102e-b323-492f-af41-4f5368971e36') - def test_create_and_delete_oneshot_cron_triggers(self): - tr_name = 'trigger' - - resp, body = self.client.create_cron_trigger( - tr_name, self.wf_name, None, None, "4242-12-25 13:37") - self.assertEqual(201, resp.status) - self.assertEqual(tr_name, body['name']) - self.assertEqual("4242-12-25 13:37:00", body['next_execution_time']) - - resp, body = self.client.get_list_obj('cron_triggers') - self.assertEqual(200, resp.status) - - trs_names = [tr['name'] for tr in body['cron_triggers']] - self.assertIn(tr_name, trs_names) - - self.client.delete_obj('cron_triggers', tr_name) - self.client.triggers.remove(tr_name) - - _, body = self.client.get_list_obj('cron_triggers') - - trs_names = [tr['name'] for tr in body['cron_triggers']] - self.assertNotIn(tr_name, trs_names) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('5224359b-3c31-4fe7-a4eb-dc9da843137e') - def test_create_two_cron_triggers_for_one_wf(self): - tr_name_1 = 'trigger1' - tr_name_2 = 'trigger2' - - resp, body = self.client.create_cron_trigger( - tr_name_1, self.wf_name, None, '5 * * * *') - self.assertEqual(201, resp.status) - self.assertEqual(tr_name_1, body['name']) - - resp, body = self.client.create_cron_trigger( - tr_name_2, self.wf_name, None, '15 * * * *') - self.assertEqual(201, resp.status) - self.assertEqual(tr_name_2, body['name']) - - resp, body = self.client.get_list_obj('cron_triggers') - self.assertEqual(200, resp.status) - - trs_names = [tr['name'] for tr in body['cron_triggers']] - self.assertIn(tr_name_1, trs_names) - self.assertIn(tr_name_2, trs_names) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('967da6e3-f9a2-430a-9390-0d73f2143aba') - def test_get_cron_trigger(self): - tr_name = 'trigger' - self.client.create_cron_trigger( - tr_name, self.wf_name, None, '5 * * * *') - - resp, body = self.client.get_object('cron_triggers', tr_name) - - self.assertEqual(200, resp.status) - self.assertEqual(tr_name, body['name']) - - @decorators.attr(type='negative') - @decorators.idempotent_id('d0e4d894-9a50-4919-a008-a9f255b6b6a3') - def test_create_cron_trigger_nonexistent_wf(self): - self.assertRaises(exceptions.NotFound, - self.client.create_cron_trigger, - 'trigger', 'nonexist', None, '5 * * * *') - - @decorators.attr(type='negative') - @decorators.idempotent_id('83f0d420-fd3c-4e75-87b1-854cefb28bda') - def test_create_cron_trigger_invalid_count(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_cron_trigger, - 'trigger', 'nonexist', None, '5 * * * *', None, "q") - - @decorators.attr(type='negative') - @decorators.idempotent_id('4190e0af-3c64-4f57-a0b8-d9d3d41fd323') - def test_create_cron_trigger_negative_count(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_cron_trigger, - 'trigger', 'nonexist', None, '5 * * * *', None, -1) - - @decorators.attr(type='negative') - @decorators.idempotent_id('210c37e8-990e-4260-b3b3-93f254e6a4d7') - def test_create_cron_trigger_invalid_first_date(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_cron_trigger, - 'trigger', 'nonexist', None, '5 * * * *', "q") - - @decorators.attr(type='negative') - @decorators.idempotent_id('17990a39-8f66-4748-8ba5-ca87befbb198') - def test_create_cron_trigger_count_only(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_cron_trigger, - 'trigger', 'nonexist', None, None, None, "42") - - @decorators.attr(type='negative') - @decorators.idempotent_id('029e0a1e-2252-4a37-b9bd-cfbe407c6ade') - def test_create_cron_trigger_date_and_count_without_pattern(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_cron_trigger, - 'trigger', 'nonexist', None, None, - "4242-12-25 13:37", "42") - - @decorators.attr(type='negative') - @decorators.idempotent_id('54650d60-ec17-44b7-8732-2183852789ae') - def test_get_nonexistent_cron_trigger(self): - self.assertRaises(exceptions.NotFound, - self.client.get_object, - 'cron_triggers', 'trigger') - - @decorators.attr(type='negative') - @decorators.idempotent_id('c663599e-5cd7-49ff-9c0f-f82a5bcc5fdb') - def test_delete_nonexistent_trigger(self): - self.assertRaises(exceptions.NotFound, - self.client.delete_obj, - 'cron_triggers', 'trigger') - - @decorators.attr(type='negative') - @decorators.idempotent_id('d1328d2b-5dc2-4521-93ec-d734d5fb4df7') - def test_create_two_cron_triggers_with_same_name(self): - tr_name = 'trigger' - self.client.create_cron_trigger( - tr_name, self.wf_name, None, '5 * * * *') - self.assertRaises(exceptions.Conflict, - self.client.create_cron_trigger, - tr_name, self.wf_name, None, '5 * * * *') - - @decorators.attr(type='negative') - @decorators.idempotent_id('3e51fc44-ce38-4653-9e4e-08b077a1dbc5') - def test_create_two_cron_triggers_with_same_pattern(self): - self.client.create_cron_trigger( - 'trigger1', - self.wf_name, - None, - '5 * * * *', - "4242-12-25 13:37", - "42" - ) - self.assertRaises( - exceptions.Conflict, - self.client.create_cron_trigger, - 'trigger2', - self.wf_name, - None, - '5 * * * *', - "4242-12-25 13:37", - "42" - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('6f3c08f3-9498-410e-a44b-4f9c6c971405') - def test_invalid_cron_pattern_not_enough_params(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_cron_trigger, - 'trigger', self.wf_name, None, '5 *') - - @decorators.attr(type='negative') - @decorators.idempotent_id('26cb52e7-1ef3-45a2-a870-1baec2382c55') - def test_invalid_cron_pattern_out_of_range(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_cron_trigger, - 'trigger', self.wf_name, None, '88 * * * *') diff --git a/mistral_tempest_tests/tests/api/v2/test_event_triggers.py b/mistral_tempest_tests/tests/api/v2/test_event_triggers.py deleted file mode 100644 index 2adfbdbae..000000000 --- a/mistral_tempest_tests/tests/api/v2/test_event_triggers.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2016 Catalyst IT Limited -# -# 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 import decorators -from tempest.lib import exceptions - -from mistral_tempest_tests.tests import base - -EXCHANGE = 'openstack' -EVENT_ENGINE_TOPIC = 'mistral_event_engine' -EVENT = 'fake.event' - - -class EventTriggerTestsV2(base.TestCase): - """Test class for event engine function. - - NOTE: This test class doesn't fully test event engine functions, because - we can not send real notifications to the internal message queue to - trigger the specified workflows. - - So, before notification is supported in Mistral, we can only test the API - functions. - """ - - _service = 'workflowv2' - - def setUp(self): - super(EventTriggerTestsV2, self).setUp() - _, body = self.client.create_workflow('wf_v2.yaml') - self.wf_id = body['workflows'][0]['id'] - - def tearDown(self): - for tr in self.client.event_triggers: - self.client.delete_obj('event_triggers', tr) - self.client.event_triggers = [] - - for wf in self.client.workflows: - self.client.delete_obj('workflows', wf) - self.client.workflows = [] - - super(EventTriggerTestsV2, self).tearDown() - - @decorators.attr(type='sanity') - @decorators.idempotent_id('cfdf9aee-09ce-49bf-af05-97c5542bc131') - def test_create_get_delete_event_trigger(self): - name = 'my_event_trigger' - - resp, body = self.client.create_event_trigger( - self.wf_id, EXCHANGE, EVENT_ENGINE_TOPIC, EVENT, name) - - trigger_id = body['id'] - - self.assertEqual(201, resp.status) - self.assertEqual(name, body['name']) - - resp, body = self.client.get_list_obj('event_triggers') - self.assertEqual(200, resp.status) - - trs_names = [tr['name'] for tr in body['event_triggers']] - self.assertIn(name, trs_names) - - self.client.delete_obj('event_triggers', trigger_id) - self.client.event_triggers.remove(trigger_id) - - _, body = self.client.get_list_obj('event_triggers') - - trs_names = [tr['name'] for tr in body['event_triggers']] - self.assertNotIn(name, trs_names) - - @decorators.attr(type='negative') - @decorators.idempotent_id('20e547d6-9a16-4cac-9b1a-f3520c58cdd7') - def test_create_event_trigger_without_necessary_param(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_event_trigger, - self.wf_id, EXCHANGE, EVENT_ENGINE_TOPIC, '') - - @decorators.attr(type='negative') - @decorators.idempotent_id('ed02f500-9436-4a7b-a135-f210e1c32b22') - def test_create_event_trigger_with_nonexist_wf(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_event_trigger, - 'nonexist', EXCHANGE, EVENT_ENGINE_TOPIC, EVENT) - - @decorators.attr(type='negative') - @decorators.idempotent_id('0ab556b6-ab76-492e-8eef-c79955003a93') - def test_create_event_trigger_duplicate(self): - name = 'my_event_trigger' - - self.client.create_event_trigger( - self.wf_id, EXCHANGE, EVENT_ENGINE_TOPIC, EVENT, name) - - self.assertRaises(exceptions.Conflict, - self.client.create_event_trigger, - self.wf_id, EXCHANGE, EVENT_ENGINE_TOPIC, EVENT) - - @decorators.attr(type='negative') - @decorators.idempotent_id('56b90a90-9ff3-42f8-a9eb-04a77198710e') - def test_get_nonexistent_event_trigger(self): - fake_id = '3771c152-d1a7-4a82-8a50-c79d122012dc' - - self.assertRaises(exceptions.NotFound, - self.client.get_object, - 'event_triggers', fake_id) diff --git a/mistral_tempest_tests/tests/api/v2/test_executions.py b/mistral_tempest_tests/tests/api/v2/test_executions.py deleted file mode 100644 index b577ff2dd..000000000 --- a/mistral_tempest_tests/tests/api/v2/test_executions.py +++ /dev/null @@ -1,440 +0,0 @@ -# Copyright 2016 NEC Corporation. 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. - -from oslo_concurrency.fixture import lockutils -from tempest.lib import decorators -from tempest.lib import exceptions - -from mistral_tempest_tests.tests import base -from mistral_tempest_tests.tests import utils - -import json - - -class ExecutionTestsV2(base.TestCase): - - _service = 'workflowv2' - - def setUp(self): - super(ExecutionTestsV2, self).setUp() - self.useFixture(lockutils.LockFixture('mistral-workflow')) - _, body = self.client.create_workflow('wf_v2.yaml') - - self.direct_wf_name = 'wf' - self.direct_wf2_name = 'wf2' - self.sub_wf_name = 'subwf1' - self.direct_wf_id = body['workflows'][0]['id'] - reverse_wfs = [wf for wf in body['workflows'] if wf['name'] == 'wf1'] - self.reverse_wf = reverse_wfs[0] - - def tearDown(self): - for wf in self.client.workflows: - self.client.delete_obj('workflows', wf) - self.client.workflows = [] - - for ex in self.client.executions: - self.client.delete_obj('executions', ex) - self.client.executions = [] - - super(ExecutionTestsV2, self).tearDown() - - @decorators.attr(type='smoke') - @decorators.idempotent_id('c0b4b658-6f01-4680-b402-2f683b3d78b6') - def test_get_list_executions(self): - resp, body = self.client.get_list_obj('executions') - self.assertEqual(200, resp.status) - self.assertNotIn('next', body) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('0bfcb4b0-b1e4-4499-b81b-0e86c8a2a841') - def test_get_list_executions_with_pagination(self): - resp, body = self.client.create_execution(self.direct_wf_name) - exec_id_1 = body['id'] - - self.assertEqual(201, resp.status) - - resp, body = self.client.create_execution(self.direct_wf2_name) - exec_id_2 = body['id'] - - self.assertEqual(201, resp.status) - - resp, body = self.client.get_list_obj('executions') - - self.assertIn(exec_id_1, [ex['id'] for ex in body['executions']]) - self.assertIn(exec_id_2, [ex['id'] for ex in body['executions']]) - - resp, body = self.client.get_list_obj( - 'executions?limit=1&sort_keys=workflow_name&sort_dirs=asc') - - self.assertEqual(200, resp.status) - self.assertEqual(1, len(body['executions'])) - self.assertIn('next', body) - - workflow_name_1 = body['executions'][0].get('workflow_name') - next = body.get('next') - param_dict = utils.get_dict_from_string( - next.split('?')[1], - delimiter='&' - ) - - # NOTE: 'id' gets included into sort keys automatically with 'desc' - # sorting to avoid pagination looping. - expected_dict = { - 'limit': 1, - 'sort_keys': 'workflow_name,id', - 'sort_dirs': 'asc,asc', - } - - self.assertTrue( - set(expected_dict.items()).issubset(set(param_dict.items())) - ) - - # Query again using 'next' link - url_param = next.split('/')[-1] - resp, body = self.client.get_list_obj(url_param) - - self.assertEqual(200, resp.status) - self.assertEqual(1, len(body['executions'])) - - workflow_name_2 = body['executions'][0].get('workflow_name') - - self.assertGreater(workflow_name_2, workflow_name_1) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('5d8ebe04-8de6-414d-908f-213af59e4c6a') - def test_create_execution_for_direct_wf(self): - resp, body = self.client.create_execution(self.direct_wf_name) - exec_id = body['id'] - self.assertEqual(201, resp.status) - self.assertEqual(self.direct_wf_name, body['workflow_name']) - self.assertEqual('RUNNING', body['state']) - - resp, body = self.client.get_list_obj('executions') - self.assertIn(exec_id, - [ex_id['id'] for ex_id in body['executions']]) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('101bfdff-8309-4add-9504-544b15f13d95') - def test_create_execution_for_reverse_wf(self): - resp, body = self.client.create_execution( - self.reverse_wf['name'], - wf_input={self.reverse_wf['input']: "Bye"}, - params={"task_name": "goodbye"}) - - exec_id = body['id'] - self.assertEqual(201, resp.status) - self.assertEqual(self.reverse_wf['name'], body['workflow_name']) - self.assertEqual('RUNNING', body['state']) - - resp, body = self.client.get_list_obj('executions') - self.assertIn(exec_id, - [ex_id['id'] for ex_id in body['executions']]) - - resp, body = self.client.get_object('executions', exec_id) - # TODO(nmakhotkin): Fix this loop. It is infinite now. - while body['state'] != 'SUCCESS': - resp, body = self.client.get_object('executions', exec_id) - self.assertEqual(200, resp.status) - self.assertEqual('SUCCESS', body['state']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('2df30966-9c45-4a2e-942d-e74bd92cb5aa') - def test_create_execution_by_wf_id(self): - resp, body = self.client.create_execution(self.direct_wf_id) - exec_id = body['id'] - self.assertEqual(201, resp.status) - self.assertEqual(self.direct_wf_id, body['workflow_id']) - self.assertEqual('RUNNING', body['state']) - - resp, body = self.client.get_list_obj('executions') - self.assertIn( - exec_id, - [ex_id['id'] for ex_id in body['executions']] - ) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('f7f50198-2dbd-4ca1-af51-d0eadc1108ac') - def test_get_execution(self): - _, execution = self.client.create_execution(self.direct_wf_name) - - resp, body = self.client.get_object('executions', execution['id']) - - del execution['state'] - del body['state'] - - self.assertEqual(200, resp.status) - self.assertEqual(execution['id'], body['id']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('2f142ba0-6b88-4d63-8544-05c3dbfe13cc') - def test_update_execution_pause(self): - _, execution = self.client.create_execution(self.direct_wf_name) - resp, body = self.client.update_execution( - execution['id'], '{"state": "PAUSED"}') - - self.assertEqual(200, resp.status) - self.assertEqual('PAUSED', body['state']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('f0557236-55ab-457d-9197-05bc2ae53e21') - def test_update_execution_description(self): - _, execution = self.client.create_execution(self.direct_wf_name) - resp, body = self.client.update_execution( - execution['id'], '{"description": "description"}') - - self.assertEqual(200, resp.status) - self.assertEqual('description', body['description']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('c54b4d68-b179-4339-bdab-a91cd6e819b7') - def test_update_execution_fail(self): - _, execution = self.client.create_execution(self.direct_wf_name) - resp, body = self.client.update_execution( - execution['id'], '{"state": "ERROR", "state_info": "Forced"}') - - self.assertEqual(200, resp.status) - self.assertEqual('ERROR', body['state']) - self.assertEqual('Forced', body['state_info']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('b5ce0d18-7d78-45bb-813e-ed94cea65fd0') - def test_update_execution_by_admin(self): - _, execution = self.client.create_execution(self.direct_wf_name) - resp, body = self.admin_client.update_execution( - execution['id'], '{"description": "description set by admin"}') - - self.assertEqual(200, resp.status) - self.assertEqual('description set by admin', body['description']) - - resp, body = self.client.get_object('executions', execution['id']) - - self.assertEqual(200, resp.status) - self.assertEqual("description set by admin", body['description']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('c6247362-a082-49ad-a2c3-aaf12419a477') - def test_update_execution_by_other_fail(self): - _, execution = self.client.create_execution(self.direct_wf_name) - - self.assertRaises( - exceptions.NotFound, - self.alt_client.update_execution, - execution['id'], - '{"description": "description set by admin"}' - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('d8bde271-6785-4ace-9173-a8a3a01d5eaa') - def test_get_nonexistent_execution(self): - self.assertRaises(exceptions.NotFound, self.client.get_object, - 'executions', '1a2b3c') - - @decorators.attr(type='negative') - @decorators.idempotent_id('e26e31ba-88cf-4b90-8b3a-fd4ecc612252') - def test_update_nonexistent_execution(self): - put_body = '{"state": "STOPPED"}' - - self.assertRaises(exceptions.NotFound, - self.client.update_execution, - '1a2b3c', put_body) - - @decorators.attr(type='negative') - @decorators.idempotent_id('b337e270-b3b6-41e2-8de2-05030b06fc37') - def test_delete_nonexistent_execution(self): - self.assertRaises(exceptions.NotFound, - self.client.delete_obj, - 'executions', 'nonexist') - - @decorators.attr(type='negative') - @decorators.idempotent_id('46f7b4b0-7d4a-4bdc-b2b6-46343cdd6f3a') - def test_create_ex_for_nonexistent_wf(self): - self.assertRaises(exceptions.NotFound, - self.client.create_execution, - 'nonexist') - - @decorators.attr(type='negative') - @decorators.idempotent_id('9d27247e-b4d4-40ab-9181-9986655a6be4') - def test_create_execution_for_reverse_wf_invalid_start_task(self): - self.assertRaises( - exceptions.BadRequest, - self.client.create_execution, - self.reverse_wf['name'], - {self.reverse_wf['input']: "Bye"}, - {"task_name": "nonexist"} - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('0d6ac42b-4059-40ef-99d0-a65b3cd1837c') - def test_create_execution_forgot_input_params(self): - self.assertRaises( - exceptions.BadRequest, - self.client.create_execution, - self.reverse_wf['name'], - params={"task_name": "nonexist"} - ) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('52779c73-7563-47b2-8231-a24d6bf531a7') - def test_action_ex_concurrency(self): - resp, wf = self.client.create_workflow("wf_action_ex_concurrency.yaml") - self.assertEqual(201, resp.status) - - wf_name = wf['workflows'][0]['name'] - resp, execution = self.client.create_execution(wf_name) - - self.assertEqual(201, resp.status) - self.assertEqual('RUNNING', execution['state']) - - self.client.wait_execution_success(execution) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('eb061c4d-2892-47f0-81e6-37ba15c376bb') - def test_task_ex_concurrency(self): - resp, wf = self.client.create_workflow("wf_task_ex_concurrency.yaml") - self.assertEqual(201, resp.status) - - wf_name = wf['workflows'][0]['name'] - resp, execution = self.client.create_execution(wf_name) - - self.assertEqual(201, resp.status) - self.assertEqual('RUNNING', execution['state']) - - self.client.wait_execution(execution, target_state='ERROR') - - @decorators.attr(type='sanity') - @decorators.idempotent_id('acc8e401-2b26-4c41-9e79-8da791da85c0') - def test_delete_execution_by_admin(self): - _, body = self.client.create_execution(self.direct_wf_id) - exec_id = body['id'] - resp, _ = self.admin_client.delete_obj('executions', exec_id) - - self.assertEqual(204, resp.status) - - self.client.executions.remove(exec_id) - - self.assertRaises( - exceptions.NotFound, - self.client.get_object, - 'executions', - exec_id - ) - - @decorators.idempotent_id('a882876b-7565-4f7f-9714-d99032ffaabb') - @decorators.attr(type='sanity') - def test_workflow_execution_of_nested_workflows_within_namespace(self): - low_wf = 'for_wf_namespace/lowest_level_wf.yaml' - middle_wf = 'for_wf_namespace/middle_wf.yaml' - top_wf = 'for_wf_namespace/top_level_wf.yaml' - - resp, wf = self.client.create_workflow(low_wf) - self.assertEqual(201, resp.status) - - namespace = 'abc' - resp, wf = self.client.create_workflow(low_wf, namespace=namespace) - self.assertEqual(201, resp.status) - - resp, wf = self.client.create_workflow(middle_wf) - self.assertEqual(201, resp.status) - - resp, wf = self.client.create_workflow(top_wf) - self.assertEqual(201, resp.status) - - resp, wf = self.client.create_workflow(top_wf, namespace=namespace) - self.assertEqual(201, resp.status) - - wf_name = wf['workflows'][0]['name'] - resp, top_execution = self.client.create_execution(wf_name, namespace) - - self.assertEqual(201, resp.status) - self.assertEqual('RUNNING', top_execution['state']) - self.assertEqual(wf_name, top_execution['workflow_name']) - self.assertEqual(wf_name, top_execution['workflow_name']) - self.assertEqual(namespace, top_execution['workflow_namespace']) - - self.client.wait_execution(top_execution, target_state='SUCCESS') - - self.assertEqual( - namespace, - json.loads(top_execution['params'])['namespace'] - ) - - resp, tasks = self.client.get_tasks(top_execution['id']) - top_task = tasks['tasks'][0] - - self.assertEqual(wf_name, top_task['workflow_name']) - self.assertEqual(namespace, top_task['workflow_namespace']) - - resp, executions = self.client.get_executions(top_task['id']) - middle_execution = executions['executions'][0] - - self.assertEqual('middle_wf', middle_execution['workflow_name']) - self.assertEqual('', middle_execution['workflow_namespace']) - - self.assertEqual( - namespace, - json.loads(middle_execution['params'])['namespace'] - ) - - resp, tasks = self.client.get_tasks(middle_execution['id']) - middle_task = tasks['tasks'][0] - - self.assertEqual('middle_wf', middle_task['workflow_name']) - self.assertEqual('', middle_task['workflow_namespace']) - - resp, executions = self.client.get_executions(middle_task['id']) - lowest_execution = executions['executions'][0] - - self.assertEqual('lowest_level_wf', lowest_execution['workflow_name']) - self.assertEqual(namespace, lowest_execution['workflow_namespace']) - - self.assertEqual( - namespace, - json.loads(lowest_execution['params'])['namespace'] - ) - - resp, tasks = self.client.get_tasks(lowest_execution['id']) - lowest_task = tasks['tasks'][0] - - self.assertEqual('lowest_level_wf', lowest_task['workflow_name']) - self.assertEqual(namespace, lowest_task['workflow_namespace']) - - resp, action_executions = self.client.get_action_executions( - lowest_task['id'] - ) - - action_execution = action_executions['action_executions'][0] - - self.assertEqual('lowest_level_wf', action_execution['workflow_name']) - self.assertEqual(namespace, action_execution['workflow_namespace']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('2baa25c5-0b65-4fbe-8d90-2c6599831b6b') - def test_root_execution_id(self): - resp, execution = self.client.create_execution(self.sub_wf_name) - - self.assertEqual(201, resp.status) - self.assertEqual('RUNNING', execution['state']) - - self.client.wait_execution_success(execution) - - resp, body = self.client.get_list_obj( - 'executions?root_execution_id={}'.format(execution['id'])) - - self.assertEqual(200, resp.status) - self.assertNotEmpty(body['executions']) - - self.assertEqual(2, len(body['executions'])) - - for exc in body['executions']: - self.assertEqual(exc['root_execution_id'], execution['id']) diff --git a/mistral_tempest_tests/tests/api/v2/test_tasks.py b/mistral_tempest_tests/tests/api/v2/test_tasks.py deleted file mode 100644 index 7527824b9..000000000 --- a/mistral_tempest_tests/tests/api/v2/test_tasks.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2016 NEC Corporation. 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. - -from oslo_concurrency.fixture import lockutils -from tempest.lib import decorators - -from mistral_tempest_tests.tests import base - - -class TasksTestsV2(base.TestCase): - - _service = 'workflowv2' - - def setUp(self): - super(TasksTestsV2, self).setUp() - self.useFixture(lockutils.LockFixture('mistral-workflow')) - _, body = self.client.create_workflow('wf_v2.yaml') - self.direct_wf_name = body['workflows'][0]['name'] - _, execution = self.client.create_execution(self.direct_wf_name) - self.execution_id = execution['id'] - - def tearDown(self): - for wf in self.client.workflows: - self.client.delete_obj('workflows', wf) - self.client.workflows = [] - - for wf in self.client.executions: - self.client.delete_obj('executions', wf) - self.client.executions = [] - - super(TasksTestsV2, self).tearDown() - - @decorators.attr(type='smoke') - @decorators.idempotent_id('81159dce-3802-44ee-a8d4-5ddca106fd91') - def test_get_tasks_list(self): - resp, body = self.client.get_list_obj('tasks') - - self.assertEqual(200, resp.status) - self.assertNotEmpty(body['tasks']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('f62664de-bd2b-4153-8d0f-5a76d78abbad') - def test_get_task(self): - resp, body = self.client.get_list_obj('tasks') - - self.assertEqual(200, resp.status) - self.assertEqual( - self.direct_wf_name, body['tasks'][-1]['workflow_name'] - ) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('3230d694-40fd-4094-ad12-024f40a21b94') - def test_get_tasks_of_execution(self): - resp, body = self.client.get_list_obj( - 'tasks?workflow_execution_id=%s' % self.execution_id) - - self.assertEqual(200, resp.status) - self.assertEqual( - self.direct_wf_name, body['tasks'][-1]['workflow_name'] - ) - - -class TaskTypesTestsV2(base.TestCase): - - _service = 'workflowv2' - - def setUp(self): - super(TaskTypesTestsV2, self).setUp() - - self.useFixture(lockutils.LockFixture('mistral-workflow')) - - _, wb_body = self.client.create_workbook('wb_with_nested_wf.yaml') - self.nested_wf_name = 'wb_with_nested_wf.wrapping_wf' - _, execution = self.client.create_execution(self.nested_wf_name) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('1ac726eb-b945-4b82-8755-a2fb2dc009bc') - def test_task_type(self): - resp, body = self.client.get_list_obj('tasks') - - self.assertEqual(200, resp.status) - - bt = body['tasks'] - ll = [[v for k, v in d.items() if 'type' in k] for d in bt] - types_list = [item for sublist in ll for item in sublist] - - self.assertIn( - 'WORKFLOW', types_list - ) - self.assertIn( - 'ACTION', types_list - ) - - # there are 2 tasks in the workflow one of each type - self.assertEqual( - 2, len(types_list) - ) diff --git a/mistral_tempest_tests/tests/api/v2/test_workbooks.py b/mistral_tempest_tests/tests/api/v2/test_workbooks.py deleted file mode 100644 index 186c1a9a5..000000000 --- a/mistral_tempest_tests/tests/api/v2/test_workbooks.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright 2016 NEC Corporation. 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. - -from oslo_concurrency.fixture import lockutils -from tempest.lib import decorators -from tempest.lib import exceptions - -from mistral_tempest_tests.tests import base - - -class WorkbookTestsV2(base.TestCase): - - _service = 'workflowv2' - - def tearDown(self): - for wf in self.client.workflows: - self.client.delete_obj('workflows', wf) - self.client.workflows = [] - - super(WorkbookTestsV2, self).tearDown() - - @decorators.attr(type='smoke') - @decorators.idempotent_id('4d8752b9-8d69-4d81-8710-5dd8ef699b95') - def test_get_list_workbooks(self): - resp, body = self.client.get_list_obj('workbooks') - - self.assertEqual(200, resp.status) - self.assertEmpty(body['workbooks']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('1a078ca2-bcf9-4eb9-8ed5-e3545038aa76') - def test_create_and_delete_workbook(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - resp, body = self.client.create_workbook('wb_v2.yaml') - name = body['name'] - self.assertEqual(201, resp.status) - - resp, body = self.client.get_list_obj('workbooks') - self.assertEqual(200, resp.status) - self.assertEqual(name, body['workbooks'][0]['name']) - - self.client.delete_obj('workbooks', name) - self.client.workbooks.remove(name) - - _, body = self.client.get_list_obj('workbooks') - self.assertEmpty(body['workbooks']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('80f7d7a6-2821-4ab0-b090-ca45c98258ba') - def test_get_workbook(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - _, body = self.client.create_workbook('wb_v2.yaml') - name = body['name'] - - resp, body = self.client.get_object('workbooks', name) - self.assertEqual(200, resp.status) - self.assertEqual(name, body['name']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('4d3b1e43-a493-41be-9c8a-389511675403') - def test_update_workbook(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - _, body = self.client.create_workbook('wb_v2.yaml') - name = body['name'] - resp, body = self.client.update_request('workbooks', 'wb_v2.yaml') - - self.assertEqual(200, resp.status) - self.assertEqual(name, body['name']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('506cdcc2-082f-4e1f-9ab2-717acd7f0eb5') - def test_get_workbook_definition(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - _, body = self.client.create_workbook('wb_v2.yaml') - name = body['name'] - resp, body = self.client.get_definition('workbooks', name) - - self.assertEqual(200, resp.status) - self.assertIsNotNone(body) - - @decorators.attr(type='negative') - @decorators.idempotent_id('d99f11c1-05a3-4d90-89c6-8d85558d3708') - def test_get_nonexistent_workbook_definition(self): - self.assertRaises(exceptions.NotFound, - self.client.get_definition, - 'workbooks', 'nonexist') - - @decorators.attr(type='negative') - @decorators.idempotent_id('61ed021e-ec56-42cb-ad05-eb6979aa00fd') - def test_get_nonexistent_workbook(self): - self.assertRaises(exceptions.NotFound, self.client.get_object, - 'workbooks', 'nonexist') - - @decorators.attr(type='negative') - @decorators.idempotent_id('e3d76f8b-220d-4250-8238-0ba27fda6de9') - def test_double_create_workbook(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - _, body = self.client.create_workbook('wb_v2.yaml') - name = body['name'] - self.assertRaises(exceptions.Conflict, - self.client.create_workbook, - 'wb_v2.yaml') - - self.client.delete_obj('workbooks', name) - self.client.workbooks.remove(name) - _, body = self.client.get_list_obj('workbooks') - - self.assertEmpty(body['workbooks']) - - @decorators.attr(type='negative') - @decorators.idempotent_id('1cd6f6f7-b166-454e-96d2-bf1f95c23015') - def test_create_wb_with_invalid_def(self): - self.assertRaises( - exceptions.BadRequest, - self.client.create_workbook, - 'wb_v1.yaml' - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('ac9a05d3-e285-4d88-91eb-fb9ad694a89a') - def test_update_wb_with_invalid_def(self): - self.assertRaises( - exceptions.BadRequest, - self.client.update_request, - 'workbooks', - 'wb_v1.yaml' - ) diff --git a/mistral_tempest_tests/tests/api/v2/test_workflows.py b/mistral_tempest_tests/tests/api/v2/test_workflows.py deleted file mode 100644 index 2b3c1c1ee..000000000 --- a/mistral_tempest_tests/tests/api/v2/test_workflows.py +++ /dev/null @@ -1,442 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 - -from oslo_concurrency.fixture import lockutils -from tempest.lib import decorators -from tempest.lib import exceptions - -from mistral_tempest_tests.tests import base -from mistral_tempest_tests.tests import utils - - -class WorkflowTestsV2(base.TestCase): - - _service = 'workflowv2' - - def tearDown(self): - for wf in self.client.workflows: - self.client.delete_obj('workflows', wf) - self.client.workflows = [] - - super(WorkflowTestsV2, self).tearDown() - - @decorators.attr(type='smoke') - @decorators.idempotent_id('e9cd6817-e8d1-4604-ba76-b0e17219f4c5') - def test_get_list_workflows(self): - resp, body = self.client.get_list_obj('workflows') - self.assertEqual(200, resp.status) - - names = [wf['name'] for wf in body['workflows']] - - self.assertIn('std.create_instance', names) - - self.assertNotIn('next', body) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('be8a4a44-eeb3-48e3-b11d-b83ba14dbf2c') - def test_get_list_workflows_by_admin(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - - _, body = self.client.create_workflow('wf_v2.yaml') - name = body['workflows'][0]['name'] - - resp, raw_body = self.admin_client.get('workflows?all_projects=true') - body = json.loads(raw_body) - - self.assertEqual(200, resp.status) - - names = [wf['name'] for wf in body['workflows']] - - self.assertIn(name, names) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('c9e2ebbc-02aa-4c33-b244-e471c8266aa7') - def test_get_list_workflows_with_project_by_admin(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - - _, body = self.client.create_workflow('wf_v2.yaml') - - name = body['workflows'][0]['name'] - - resp, raw_body = self.admin_client.get( - 'workflows?project_id=%s' % - self.client.auth_provider.credentials.tenant_id - ) - body = json.loads(raw_body) - - self.assertEqual(200, resp.status) - - names = [wf['name'] for wf in body['workflows']] - - self.assertIn(name, names) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('b8dc1b02-8509-45e2-9df7-4630cdcfa1ab') - def test_get_list_other_project_private_workflows(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - - _, body = self.client.create_workflow('wf_v2.yaml') - - name = body['workflows'][0]['name'] - - resp, raw_body = self.alt_client.get( - 'workflows?project_id=%s' % - self.client.auth_provider.credentials.tenant_id - ) - body = json.loads(raw_body) - - self.assertEqual(200, resp.status) - - names = [wf['name'] for wf in body['workflows']] - - self.assertNotIn(name, names) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('2063143b-ced8-4037-9383-e2504be581e6') - def test_get_list_workflows_with_fields(self): - resp, body = self.client.get_list_obj('workflows?fields=name') - - self.assertEqual(200, resp.status) - - for wf in body['workflows']: - self.assertListEqual(sorted(['id', 'name']), sorted(list(wf))) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('81f28735-e74e-4dc1-8b94-b548f8a80556') - def test_get_list_workflows_with_pagination(self): - resp, body = self.client.get_list_obj( - 'workflows?limit=1&sort_keys=name&sort_dirs=desc' - ) - - self.assertEqual(200, resp.status) - self.assertEqual(1, len(body['workflows'])) - self.assertIn('next', body) - - name_1 = body['workflows'][0].get('name') - next = body.get('next') - - param_dict = utils.get_dict_from_string( - next.split('?')[1], - delimiter='&' - ) - - # NOTE: 'id' gets included into sort keys automatically with 'desc' - # sorting to avoid pagination looping. - expected_sub_dict = { - 'limit': 1, - 'sort_keys': 'name,id', - 'sort_dirs': 'desc,asc' - } - - self.assertDictContainsSubset(expected_sub_dict, param_dict) - - # Query again using 'next' hint - url_param = next.split('/')[-1] - resp, body = self.client.get_list_obj(url_param) - - self.assertEqual(200, resp.status) - self.assertEqual(1, len(body['workflows'])) - - name_2 = body['workflows'][0].get('name') - - self.assertGreater(name_1, name_2) - - @decorators.attr(type='negative') - @decorators.idempotent_id('cdb5586f-a72f-4371-88d1-1472675915c3') - def test_get_list_workflows_nonexist_sort_dirs(self): - context = self.assertRaises( - exceptions.BadRequest, - self.client.get_list_obj, - 'workflows?limit=1&sort_keys=id&sort_dirs=nonexist' - ) - - self.assertIn( - 'Unknown sort direction', - context.resp_body.get('faultstring') - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('ac41a0ea-2be6-4307-9003-6b8dd52b0bf9') - def test_get_list_workflows_invalid_limit(self): - context = self.assertRaises( - exceptions.BadRequest, - self.client.get_list_obj, - 'workflows?limit=-1&sort_keys=id&sort_dirs=asc' - ) - - self.assertIn( - 'Limit must be positive', - context.resp_body.get('faultstring') - ) - - @decorators.attr(type='negative') - @decorators.idempotent_id('55759713-a8d7-44c2-aff1-2383f51136bd') - def test_get_list_workflows_duplicate_sort_keys(self): - context = self.assertRaises( - exceptions.BadRequest, - self.client.get_list_obj, - 'workflows?limit=1&sort_keys=id,id&sort_dirs=asc,asc' - ) - - self.assertIn( - 'Length of sort_keys must be equal or greater than sort_dirs', - context.resp_body.get('faultstring') - ) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('e26b30b9-6699-4020-93a0-e25c2daca59a') - def test_create_and_delete_workflow(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - resp, body = self.client.create_workflow('wf_v2.yaml') - name = body['workflows'][0]['name'] - - self.assertEqual(201, resp.status) - - resp, body = self.client.get_list_obj('workflows') - self.assertEqual(200, resp.status) - - names = [wf['name'] for wf in body['workflows']] - self.assertIn(name, names) - - self.client.delete_obj('workflows', name) - self.client.workflows.remove(name) - - _, body = self.client.get_list_obj('workflows') - - names = [wf['name'] for wf in body['workflows']] - self.assertNotIn(name, names) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('f5a4a771-79b2-4f28-bfac-940aa83990a4') - def test_get_workflow(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - _, body = self.client.create_workflow('wf_v2.yaml') - name = body['workflows'][0]['name'] - - resp, body = self.client.get_object('workflows', name) - - self.assertEqual(200, resp.status) - self.assertEqual(name, body['name']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('f516aad0-9a50-4ace-a217-fa1931fd9335') - def test_update_workflow(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - _, body = self.client.create_workflow('single_wf.yaml') - name = body['workflows'][0]['name'] - - resp, body = self.client.update_request('workflows', 'single_wf.yaml') - - self.assertEqual(200, resp.status) - self.assertEqual(name, body['workflows'][0]['name']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('42f5d135-a2b8-4a31-8135-c5ce8c5f1ed5') - def test_workflow_within_namespace(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - - namespace = 'abc' - resp, body = self.client.create_workflow( - 'single_wf.yaml', - namespace=namespace - ) - name = body['workflows'][0]['name'] - id = body['workflows'][0]['id'] - - self.assertEqual(201, resp.status) - self.assertEqual(name, body['workflows'][0]['name']) - - resp, body = self.client.get_workflow( - id - ) - - self.assertEqual(namespace, body['namespace']) - - resp, body = self.client.update_workflow('single_wf.yaml', namespace) - - self.assertEqual(200, resp.status) - self.assertEqual(name, body['workflows'][0]['name']) - self.assertEqual(namespace, body['workflows'][0]['namespace']) - - namespace = 'abc2' - resp, body = self.client.create_workflow( - 'single_wf.yaml', - namespace=namespace - ) - name = body['workflows'][0]['name'] - id = body['workflows'][0]['id'] - - self.assertEqual(201, resp.status) - self.assertEqual(name, body['workflows'][0]['name']) - - resp, body = self.client.get_workflow(id) - - self.assertEqual(namespace, body['namespace']) - - self.assertRaises(exceptions.NotFound, self.client.get_workflow, name) - - self.client.create_workflow( - 'single_wf.yaml' - ) - - resp, body = self.client.get_workflow(id) - self.assertEqual(200, resp.status) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('02bc1fc3-c31a-4e37-bb3d-eda46818505c') - def test_get_workflow_definition(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - _, body = self.client.create_workflow('wf_v2.yaml') - name = body['workflows'][0]['name'] - - resp, body = self.client.get_definition('workflows', name) - - self.assertEqual(200, resp.status) - self.assertIsNotNone(body) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('04fbd003-0e52-4034-858e-6634d4f84b29') - def test_get_workflow_uploaded_in_wb(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - _, body = self.client.create_workbook('wb_v2.yaml') - wb_name = body['name'] - - _, body = self.client.get_list_obj('workflows') - wf_names = [wf['name'] for wf in body['workflows'] - if wf['name'].startswith(wb_name)] - - self.assertNotEmpty(wf_names) - - @decorators.attr(type='negative') - @decorators.idempotent_id('5e5f0403-fb2c-41ae-bf6f-25c181515358') - def test_get_nonexistent_workflow_definition(self): - self.assertRaises(exceptions.NotFound, - self.client.get_definition, - 'workflows', 'nonexist') - - @decorators.attr(type='negative') - @decorators.idempotent_id('23c72d01-c3bb-43d6-ba15-9b49c15f800c') - def test_get_nonexistent_workflow(self): - self.assertRaises(exceptions.NotFound, self.client.get_object, - 'workflows', 'nonexist') - - exception = self.assertRaises( - exceptions.NotFound, - self.client.get_workflow, - 'nonexist_wf', - 'nonexist_namespace' - ) - self.assertIn('nonexist_wf', str(exception)) - self.assertIn('nonexist_namespace', str(exception)) - - @decorators.attr(type='negative') - @decorators.idempotent_id('6b917213-7f11-423a-8fe0-55795dcf0fb2') - def test_double_create_workflows(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - _, body = self.client.create_workflow('wf_v2.yaml') - self.assertRaises(exceptions.Conflict, - self.client.create_workflow, - 'wf_v2.yaml') - - @decorators.attr(type='negative') - @decorators.idempotent_id('ffcd63d2-1104-4320-a67b-fadc4e2a0631') - def test_create_wf_with_invalid_def(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_workflow, - 'wb_v1.yaml') - - @decorators.attr(type='negative') - @decorators.idempotent_id('eed46931-5485-436c-810f-1f63362223b9') - def test_update_wf_with_invalid_def(self): - self.assertRaises(exceptions.BadRequest, - self.client.update_request, - 'workflows', 'wb_v1.yaml') - - @decorators.attr(type='negative') - @decorators.idempotent_id('9b7f5b5a-cacd-4f98-a35a-decf065b8234') - def test_delete_wf_with_trigger_associate(self): - tr_name = 'trigger' - resp, body = self.client.create_workflow('wf_v2.yaml') - name = body['workflows'][0]['name'] - resp, body = self.client.create_cron_trigger( - tr_name, name, None, '5 * * * *') - - try: - self.assertRaises( - exceptions.BadRequest, - self.client.delete_obj, - 'workflows', - name - ) - finally: - self.client.delete_obj('cron_triggers', tr_name) - self.client.triggers.remove(tr_name) - - @decorators.attr(type='negative') - @decorators.idempotent_id('46325022-cbd2-48f3-95f3-e587aab3b655') - def test_delete_wf_with_event_trigger_associate(self): - _, body = self.client.create_workflow('wf_v2.yaml') - wf_id = body['workflows'][0]['id'] - resp, body = self.client.create_event_trigger( - wf_id, 'openstack', 'notification', 'fake.event') - self.assertEqual(201, resp.status) - - try: - self.assertRaises( - exceptions.BadRequest, - self.client.delete_obj, - 'workflows', - wf_id - ) - finally: - self.client.delete_obj('event_triggers', body['id']) - self.client.event_triggers.remove(body['id']) - - @decorators.attr(type='negative') - @decorators.idempotent_id('1cb929e6-d375-4dcb-ab7c-73aa205af896') - def test_delete_wf_with_trigger_associate_in_other_tenant(self): - self.useFixture(lockutils.LockFixture('mistral-workflow')) - tr_name = 'trigger' - _, body = self.client.create_workflow('wf_v2.yaml', scope='public') - name = body['workflows'][0]['name'] - resp, body = self.alt_client.create_cron_trigger( - tr_name, - name, - None, - '5 * * * *' - ) - - try: - exception = self.assertRaises( - exceptions.BadRequest, - self.client.delete_obj, - 'workflows', - name - ) - - self.assertIn( - "Can't delete workflow that has cron triggers associated", - exception.resp_body['faultstring'] - ) - finally: - self.alt_client.delete_obj('cron_triggers', tr_name) - self.alt_client.triggers.remove(tr_name) - - @decorators.attr(type='negative') - @decorators.idempotent_id('f575713b-27fd-4ec8-b84f-468a7adf5ed2') - def test_delete_nonexistent_wf(self): - self.assertRaises(exceptions.NotFound, - self.client.delete_obj, - 'workflows', 'nonexist') diff --git a/mistral_tempest_tests/tests/base.py b/mistral_tempest_tests/tests/base.py deleted file mode 100644 index 6f07194b2..000000000 --- a/mistral_tempest_tests/tests/base.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 os - -import mock -from tempest import config -from tempest import test as test - -from mistral_tempest_tests.services import base as service_base -from mistral_tempest_tests.services.v2 import mistral_client - -CONF = config.CONF - - -class TestCase(test.BaseTestCase): - credentials = ['admin', 'primary', 'alt'] - - @classmethod - def skip_checks(cls): - super(TestCase, cls).skip_checks() - - if not CONF.service_available.mistral: - raise cls.skipException("Mistral support is required.") - - @classmethod - def resource_setup(cls): - """Client authentication. - - This method allows to initialize authentication before - each test case and define parameters of Mistral API Service. - """ - super(TestCase, cls).resource_setup() - - if 'WITHOUT_AUTH' in os.environ: - cls.mgr = mock.MagicMock() - cls.mgr.auth_provider = service_base.AuthProv() - cls.admin_mgr = cls.alt_mgr = cls.mgr - else: - cls.admin_mgr = cls.os_admin - cls.mgr = cls.os_primary - cls.alt_mgr = cls.os_alt - - if cls._service == 'workflowv2': - cls.admin_client = mistral_client.MistralClientV2( - cls.admin_mgr.auth_provider, cls._service) - cls.client = mistral_client.MistralClientV2( - cls.mgr.auth_provider, cls._service) - cls.alt_client = mistral_client.MistralClientV2( - cls.alt_mgr.auth_provider, cls._service) - - def tearDown(self): - super(TestCase, self).tearDown() - - for wb in self.client.workbooks: - self.client.delete_obj('workbooks', wb) - - self.client.workbooks = [] - - -class TestCaseAdvanced(TestCase): - @classmethod - def resource_setup(cls): - super(TestCaseAdvanced, cls).resource_setup() - - cls.image_ref = CONF.compute.image_ref - cls.flavor_ref = CONF.compute.flavor_ref - - def tearDown(self): - for wb in self.client.workbooks: - self.client.delete_obj('workbooks', wb) - - self.client.workbooks = [] - - for ex in self.client.executions: - self.client.delete_obj('executions', ex) - - self.client.executions = [] - - super(TestCaseAdvanced, self).tearDown() diff --git a/mistral_tempest_tests/tests/resources/action_v2.yaml b/mistral_tempest_tests/tests/resources/action_v2.yaml deleted file mode 100755 index bf2b879db..000000000 --- a/mistral_tempest_tests/tests/resources/action_v2.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -version: "2.0" - -greeting: - description: "This action says 'Hello'" - tags: [hello] - base: std.echo - base-input: - output: 'Hello, <% $.name %>' - input: - - name - output: - string: <% $ %> - -farewell: - base: std.echo - base-input: - output: 'Bye!' - output: - info: <% $ %> - diff --git a/mistral_tempest_tests/tests/resources/for_wf_namespace/lowest_level_wf.yaml b/mistral_tempest_tests/tests/resources/for_wf_namespace/lowest_level_wf.yaml deleted file mode 100755 index 5d873f26f..000000000 --- a/mistral_tempest_tests/tests/resources/for_wf_namespace/lowest_level_wf.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -version: '2.0' -lowest_level_wf: - tasks: - noop_task: - action: std.noop \ No newline at end of file diff --git a/mistral_tempest_tests/tests/resources/for_wf_namespace/middle_wf.yaml b/mistral_tempest_tests/tests/resources/for_wf_namespace/middle_wf.yaml deleted file mode 100755 index e0cc2952f..000000000 --- a/mistral_tempest_tests/tests/resources/for_wf_namespace/middle_wf.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -version: '2.0' -middle_wf: - tasks: - run_workflow_with_name_lowest_level_wf: - workflow: lowest_level_wf \ No newline at end of file diff --git a/mistral_tempest_tests/tests/resources/for_wf_namespace/top_level_wf.yaml b/mistral_tempest_tests/tests/resources/for_wf_namespace/top_level_wf.yaml deleted file mode 100755 index 2bedcb1ec..000000000 --- a/mistral_tempest_tests/tests/resources/for_wf_namespace/top_level_wf.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -version: '2.0' -top_level_wf: - tasks: - run_workflow_with_name_middle_wf: - workflow: middle_wf \ No newline at end of file diff --git a/mistral_tempest_tests/tests/resources/openstack/action_collection_wb.yaml b/mistral_tempest_tests/tests/resources/openstack/action_collection_wb.yaml deleted file mode 100755 index e5a5a8e31..000000000 --- a/mistral_tempest_tests/tests/resources/openstack/action_collection_wb.yaml +++ /dev/null @@ -1,75 +0,0 @@ ---- -version: '2.0' -name: action_collection - -workflows: - keystone: - type: direct - tasks: - projects_list: - action: keystone.projects_list - publish: - result: <% task().result %> - - nova: - type: direct - tasks: - flavors_list: - action: nova.flavors_list - publish: - result: <% task().result %> - - glance: - type: direct - tasks: - images_list: - action: glance.images_list - publish: - result: <% task().result %> - - heat: - type: direct - tasks: - stacks_list: - action: heat.stacks_list - publish: - result: <% task().result %> - - neutron: - type: direct - tasks: - list_subnets: - action: neutron.list_subnets - publish: - result: <% task().result %> - - cinder: - type: direct - tasks: - volumes_list: - action: cinder.volumes_list - publish: - result: <% task().result %> - - swift: - type: direct - tasks: - get_account: - action: swift.get_account - publish: - result: <% task().result %> - - zaqar: - type: direct - tasks: - send_message: - action: zaqar.queue_post - input: - queue_name: test - messages: - body: - type: action_collection.zaqar - payload: - status: <% $.get(status, 'SUCCESS') %> - publish: - result: <% task().result %> diff --git a/mistral_tempest_tests/tests/resources/single_wf.yaml b/mistral_tempest_tests/tests/resources/single_wf.yaml deleted file mode 100755 index 1dc2c6b05..000000000 --- a/mistral_tempest_tests/tests/resources/single_wf.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -version: '2.0' - -single_wf: - type: direct - - tasks: - hello: - action: std.echo output="Hello" - publish: - result: <% task(hello).result %> diff --git a/mistral_tempest_tests/tests/resources/wb_v1.yaml b/mistral_tempest_tests/tests/resources/wb_v1.yaml deleted file mode 100755 index dc4702943..000000000 --- a/mistral_tempest_tests/tests/resources/wb_v1.yaml +++ /dev/null @@ -1,12 +0,0 @@ -Namespaces: - Greetings: - actions: - hello: - class: std.echo - base-parameters: - output: Hello! - -Workflow: - tasks: - hello: - action: Greetings.hello \ No newline at end of file diff --git a/mistral_tempest_tests/tests/resources/wb_v2.yaml b/mistral_tempest_tests/tests/resources/wb_v2.yaml deleted file mode 100755 index 1c0cd3b28..000000000 --- a/mistral_tempest_tests/tests/resources/wb_v2.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -version: '2.0' -name: test - -workflows: - test: - type: direct - - tasks: - hello: - action: std.echo output="Hello" - publish: - result: <% task(hello).result %> diff --git a/mistral_tempest_tests/tests/resources/wb_with_nested_wf.yaml b/mistral_tempest_tests/tests/resources/wb_with_nested_wf.yaml deleted file mode 100755 index 717855aa6..000000000 --- a/mistral_tempest_tests/tests/resources/wb_with_nested_wf.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -version: "2.0" - -name: wb_with_nested_wf - -workflows: - - wrapping_wf: - type: direct - tasks: - call_inner_wf: - workflow: inner_wf - - inner_wf: - type: direct - tasks: - hello: - action: std.echo output="Hello from inner workflow" \ No newline at end of file diff --git a/mistral_tempest_tests/tests/resources/wf_action_ex_concurrency.yaml b/mistral_tempest_tests/tests/resources/wf_action_ex_concurrency.yaml deleted file mode 100755 index 0dee5505c..000000000 --- a/mistral_tempest_tests/tests/resources/wf_action_ex_concurrency.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -version: '2.0' - -test_action_ex_concurrency: - tasks: - test_with_items: - with-items: index in <% range(2) %> - action: std.echo output='<% $.index %>' \ No newline at end of file diff --git a/mistral_tempest_tests/tests/resources/wf_task_ex_concurrency.yaml b/mistral_tempest_tests/tests/resources/wf_task_ex_concurrency.yaml deleted file mode 100755 index 45894088c..000000000 --- a/mistral_tempest_tests/tests/resources/wf_task_ex_concurrency.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -version: '2.0' - -test_task_ex_concurrency: - tasks: - task1: - action: std.async_noop - timeout: 2 - task2: - action: std.async_noop - timeout: 2 \ No newline at end of file diff --git a/mistral_tempest_tests/tests/resources/wf_v2.yaml b/mistral_tempest_tests/tests/resources/wf_v2.yaml deleted file mode 100755 index 189c0fbcf..000000000 --- a/mistral_tempest_tests/tests/resources/wf_v2.yaml +++ /dev/null @@ -1,55 +0,0 @@ ---- -version: '2.0' - -wf: - type: direct - - tasks: - hello: - action: std.echo output="Hello" - wait-before: 1 - publish: - result: <% task(hello).result %> - -wf1: - type: reverse - input: - - farewell - - tasks: - addressee: - action: std.echo output="John" - publish: - name: <% task(addressee).result %> - - goodbye: - action: std.echo output="<% $.farewell %>, <% $.name %>" - requires: [addressee] - -wf2: - type: direct - - tasks: - hello: - action: std.echo output="Doe" - -subwf1: - type: direct - - tasks: - task1: - workflow: subwf2 - -subwf2: - type: direct - - tasks: - task1: - workflow: subwf3 - -subwf3: - type: direct - - tasks: - task1: - action: std.noop diff --git a/mistral_tempest_tests/tests/scenario/__init__.py b/mistral_tempest_tests/tests/scenario/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral_tempest_tests/tests/scenario/engine/__init__.py b/mistral_tempest_tests/tests/scenario/engine/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral_tempest_tests/tests/scenario/engine/actions/__init__.py b/mistral_tempest_tests/tests/scenario/engine/actions/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral_tempest_tests/tests/scenario/engine/actions/v2/__init__.py b/mistral_tempest_tests/tests/scenario/engine/actions/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral_tempest_tests/tests/scenario/engine/actions/v2/test_multi_vim_authentication.py b/mistral_tempest_tests/tests/scenario/engine/actions/v2/test_multi_vim_authentication.py deleted file mode 100644 index 760844e1b..000000000 --- a/mistral_tempest_tests/tests/scenario/engine/actions/v2/test_multi_vim_authentication.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright 2016 - Nokia, 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 base64 - -from keystoneclient import service_catalog as ks_service_catalog -from oslo_serialization import jsonutils -from oslo_utils import uuidutils -from six.moves.urllib.parse import urlparse -from tempest.lib import decorators - -from mistral_tempest_tests.tests import base - - -class MultiVimActionsTests(base.TestCase): - _service = 'workflowv2' - - @classmethod - def resource_setup(cls): - super(MultiVimActionsTests, cls).resource_setup() - - @decorators.attr(type='openstack') - @decorators.idempotent_id('dadc9960-9c03-41a9-9a9d-7e97d527e6dd') - def test_multi_vim_support_target_headers(self): - client_1 = self.alt_client - client_2 = self.client - - # Create stack with client2. - result = _execute_action(client_2, _get_create_stack_request()) - stack_id = str( - jsonutils.loads(result['output'])['result']['stack']['id'] - ) - - # List stacks with client1, and assert that there is no stack. - result = _execute_action(client_1, _get_list_stack_request()) - self.assertEmpty(jsonutils.loads(result['output'])['result']) - - # List stacks with client1, but with the target headers of client2, - # and assert the created stack is there. - result = _execute_action( - client_1, - _get_list_stack_request(), - extra_headers=_extract_target_headers_from_client(client_2) - ) - self.assertEqual( - stack_id, - str(jsonutils.loads(result['output'])['result'][0]['id']) - ) - - @decorators.attr(type='openstack') - @decorators.idempotent_id('bc0e9b99-62b0-4d96-95c9-016a3f69b02a') - @decorators.skip_because(bug="1736685") - def test_multi_vim_support_target_headers_and_service_catalog(self): - client_1 = self.alt_client - client_2 = self.client - - # List stacks with client1, but with the target headers of client2, - # and additionally with an invalid X-Target-Service-Catalog. - extra_headers = _extract_target_headers_from_client(client_2) - - # Use ServiceCatalog to eliminate differences between keystone v2 and - # v3. - token_data = client_2.auth_provider.auth_data[1] - service_catalog = ks_service_catalog.ServiceCatalog.factory( - token_data - ).get_data() - - for service in service_catalog: - if service['name'] == 'heat': - for ep in service['endpoints']: - if 'publicURL' in ep: - ep['publicURL'] = "invalid" - elif ep['interface'] == 'public': - ep['url'] = "invalid" - break - break - - if 'catalog' in token_data: - token_data['catalog'] = service_catalog - else: - token_data['serviceCatalog'] = service_catalog - - invalid_service_catalog = { - "X-Target-Service-Catalog": base64.b64encode( - jsonutils.dumps(token_data) - ) - } - extra_headers.update(invalid_service_catalog) - result = _execute_action( - client_1, - _get_list_stack_request(), - extra_headers=extra_headers - ) - - # Assert that the invalid catalog was used. - self.assertIn("Invalid URL", result['output']) - - -def _extract_target_headers_from_client(client): - u = urlparse(client.auth_provider.auth_url) - v3_auth_url = '{}://{}/identity/v3/'.format(u.scheme, u.netloc) - return { - 'X-Target-Auth-Token': client.token, - 'X-Target-Auth-Uri': v3_auth_url, - 'X-Target-Project-Id': client.tenant_id, - 'X-Target-User-Id': client.user_id, - } - - -def _execute_action(client, request, extra_headers={}): - _, result = client.create_action_execution( - request, - extra_headers=extra_headers - ) - - return result - - -def _get_create_stack_request(): - stack_name = 'multi_vim_test_stack_{}'.format( - uuidutils.generate_uuid()[:8]) - - return { - 'name': 'heat.stacks_create', - 'input': { - 'stack_name': stack_name, - "template": {"heat_template_version": "2013-05-23"} - } - } - - -def _get_list_stack_request(): - return { - 'name': 'heat.stacks_list', - } diff --git a/mistral_tempest_tests/tests/scenario/engine/actions/v2/test_openstack_actions.py b/mistral_tempest_tests/tests/scenario/engine/actions/v2/test_openstack_actions.py deleted file mode 100644 index 403e38fe0..000000000 --- a/mistral_tempest_tests/tests/scenario/engine/actions/v2/test_openstack_actions.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2015 - 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. - -from tempest.lib import decorators - -from mistral_tempest_tests.tests import base - - -class OpenStackActionsTestsV2(base.TestCase): - - _service = 'workflowv2' - - # TODO(akuznetsova): add checks for task result after task_output - # TODO(akuznetsova): refactoring will be finished - - @classmethod - def resource_setup(cls): - super(OpenStackActionsTestsV2, cls).resource_setup() - - _, cls.wb = cls.client.create_workbook( - 'openstack/action_collection_wb.yaml') - - @decorators.attr(type='openstack') - @decorators.idempotent_id('9a999fc2-a089-4375-bc69-e1ed85b17a82') - def test_nova_actions(self): - wf_name = self.wb['name'] + '.nova' - _, execution = self.client.create_execution(wf_name) - self.client.wait_execution_success(execution) - executed_task = self.client.get_wf_tasks(wf_name)[-1] - - self.assertEqual('SUCCESS', executed_task['state']) - - @decorators.attr(type='openstack') - @decorators.idempotent_id('81bdc1c9-cd9a-4c97-b8ce-e44f5211eace') - def test_keystone_actions(self): - wf_name = self.wb['name'] + '.keystone' - _, execution = self.admin_client.create_execution(wf_name) - self.admin_client.wait_execution_success(execution) - executed_task = self.admin_client.get_wf_tasks(wf_name)[-1] - - self.assertEqual('SUCCESS', executed_task['state']) - - @decorators.attr(type='openstack') - @decorators.idempotent_id('fde681b8-3e1b-4172-a4b8-2fcac1f070d9') - def test_heat_actions(self): - wf_name = self.wb['name'] + '.heat' - _, execution = self.client.create_execution(wf_name) - self.client.wait_execution_success(execution) - executed_task = self.client.get_wf_tasks(wf_name)[-1] - - self.assertEqual('SUCCESS', executed_task['state']) - - @decorators.attr(type='openstack') - @decorators.idempotent_id('5981360d-f336-45ca-9d38-799c7a8ade26') - def test_glance_actions(self): - wf_name = self.wb['name'] + '.glance' - _, execution = self.client.create_execution(wf_name) - self.client.wait_execution_success(execution) - executed_task = self.client.get_wf_tasks(wf_name)[-1] - - self.assertEqual('SUCCESS', executed_task['state']) - - @decorators.attr(type='openstack') - @decorators.idempotent_id('a1f71a72-3681-4d32-aad9-117068717b33') - def test_cinder_actions(self): - wf_name = self.wb['name'] + '.cinder' - _, execution = self.client.create_execution(wf_name) - self.client.wait_execution_success(execution) - executed_task = self.client.get_wf_tasks(wf_name)[-1] - - self.assertEqual('SUCCESS', executed_task['state']) - - @decorators.attr(type='openstack') - @decorators.idempotent_id('586dd973-fc65-40e2-9a85-31418b22473a') - def test_neutron_actions(self): - wf_name = self.wb['name'] + '.neutron' - _, execution = self.client.create_execution(wf_name) - self.client.wait_execution_success(execution) - executed_task = self.client.get_wf_tasks(wf_name)[-1] - - self.assertEqual('SUCCESS', executed_task['state']) - - @decorators.attr(type='openstack') - @decorators.idempotent_id('985c1051-cf2e-4fd0-8ceb-a9b8110597a1') - def test_swift_actions(self): - wf_name = self.wb['name'] + '.swift' - _, execution = self.client.create_execution(wf_name) - self.client.wait_execution_success(execution) - executed_task = self.client.get_wf_tasks(wf_name)[-1] - - self.assertEqual('SUCCESS', executed_task['state']) - - @decorators.attr(type='openstack') - @decorators.idempotent_id('6f000ae8-3f41-49bd-b7a7-ad2256d80076') - def test_zaqar_actions(self): - wf_name = self.wb['name'] + '.zaqar' - _, execution = self.client.create_execution(wf_name) - self.client.wait_execution_success(execution) - executed_task = self.client.get_wf_tasks(wf_name)[-1] - - self.assertEqual('SUCCESS', executed_task['state']) diff --git a/mistral_tempest_tests/tests/scenario/engine/actions/v2/test_ssh_actions.py b/mistral_tempest_tests/tests/scenario/engine/actions/v2/test_ssh_actions.py deleted file mode 100644 index 1666d15dd..000000000 --- a/mistral_tempest_tests/tests/scenario/engine/actions/v2/test_ssh_actions.py +++ /dev/null @@ -1,295 +0,0 @@ -# Copyright 2015 - 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 json -import os -from os import path -import time - -from oslo_log import log as logging -from paramiko import ssh_exception -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions - -from mistral_tempest_tests.tests import base -from mistral_tempest_tests.tests import ssh_utils -from mistral_tempest_tests.tests import utils - - -LOG = logging.getLogger(__name__) -CONF = config.CONF -SSH_KEYS_DIRECTORY = path.expanduser("~/.ssh/") - - -class SSHActionsTestsV2(base.TestCaseAdvanced): - - _service = 'workflowv2' - - @classmethod - def _create_security_group_rule_ssh(cls): - sec_groups = ( - cls.mgr.compute_security_groups_client. - list_security_groups() - ) - sec_groups = sec_groups['security_groups'] - - default_group = next( - g for g in sec_groups if g['name'] == 'default' - ) - - rule = ( - cls.mgr.compute_security_group_rules_client - .create_security_group_rule( - parent_group_id=default_group['id'], - ip_protocol="tcp", - from_port=22, - to_port=22, - cidr="0.0.0.0/0" - ) - ) - - cls.ssh_rule_id = rule['security_group_rule']['id'] - - @classmethod - def _create_server(cls, server_name, **kwargs): - return cls.mgr.servers_client.create_server( - name=server_name, - imageRef=CONF.compute.image_ref, - flavorRef=CONF.compute.flavor_ref, - **kwargs - ).get('server') - - @classmethod - def _associate_floating_ip_to_server(cls, server_id): - fl_ip_client = cls.mgr.compute_floating_ips_client - - all_ips = fl_ip_client.list_floating_ips().get( - 'floating_ips' - ) - free_ips = list( - [fl_ip for fl_ip in all_ips if fl_ip['instance_id'] is None] - ) - - if free_ips: - ip = free_ips[0]['ip'] - else: - # Allocate new floating ip. - ip = fl_ip_client.create_floating_ip()['floating_ip']['ip'] - - # Associate IP. - fl_ip_client.associate_floating_ip_to_server( - floating_ip=ip, - server_id=server_id - ) - - return ip - - @classmethod - def _wait_until_server_up(cls, server_ip, timeout=120, delay=2): - seconds_remain = timeout - - LOG.info("Waiting server SSH [IP=%s]...", server_ip) - - while seconds_remain > 0: - try: - ssh_utils.execute_command('cd', server_ip, None) - except ssh_exception.SSHException: - LOG.info("Server %s: SSH service is ready.") - return - except Exception as e: - LOG.info(str(e)) - seconds_remain -= delay - time.sleep(delay) - else: - return - - raise Exception( - "Failed waiting until server's '%s' SSH is up." % server_ip - ) - - @classmethod - def _wait_until_server_active(cls, server_id, timeout=60, delay=2): - seconds_remain = timeout - - LOG.info("Waiting server [id=%s]...", server_id) - - while seconds_remain > 0: - server_info = cls.mgr.servers_client.show_server(server_id) - if server_info['server']['status'] == 'ACTIVE': - return - - seconds_remain -= delay - time.sleep(delay) - - raise Exception( - "Failed waiting until server %s is active." % server_id - ) - - @classmethod - def _wait_until_server_delete(cls, server_id, timeout=60, delay=2): - seconds_remain = timeout - - LOG.info("Deleting server [id=%s]...", server_id) - - while seconds_remain > 0: - try: - cls.mgr.servers_client.show_server(server_id) - seconds_remain -= delay - time.sleep(delay) - except exceptions.NotFound: - return - - raise RuntimeError("Server delete timeout!") - - @classmethod - def resource_setup(cls): - super(SSHActionsTestsV2, cls).resource_setup() - - # Modify security group for accessing VM via SSH. - cls._create_security_group_rule_ssh() - - # Create keypair (public and private keys). - cls.private_key, cls.public_key = utils.generate_key_pair() - cls.key_name = 'mistral-functional-tests-key' - - # If ZUUL_PROJECT is specified, it means - # tests are running on Jenkins gate. - - if os.environ.get('ZUUL_PROJECT'): - cls.key_dir = "/opt/stack/new/.ssh/" - - if not path.exists(cls.key_dir): - os.mkdir(cls.key_dir) - else: - cls.key_dir = SSH_KEYS_DIRECTORY - - utils.save_text_to( - cls.private_key, - cls.key_dir + cls.key_name, - overwrite=True - ) - - LOG.info("Private key saved to %s", cls.key_dir + cls.key_name) - - # Create keypair in nova. - cls.mgr.keypairs_client.create_keypair( - name=cls.key_name, - public_key=cls.public_key - ) - - # Start servers and provide key_name. - # Note: start public vm only after starting the guest one, - # so we can track public vm launching using ssh, but can't - # do the same with guest VM. - cls.guest_vm = cls._create_server( - 'mistral-guest-vm', - key_name=cls.key_name - ) - cls.public_vm = cls._create_server( - 'mistral-public-vm', - key_name=cls.key_name - ) - - cls._wait_until_server_active(cls.public_vm['id']) - - cls.public_vm_ip = cls._associate_floating_ip_to_server( - cls.public_vm['id'] - ) - - # Wait until server is up. - cls._wait_until_server_up(cls.public_vm_ip) - - # Update servers info. - cls.public_vm = cls.mgr.servers_client.show_server( - cls.public_vm['id'] - ).get('server') - - cls.guest_vm = cls.mgr.servers_client.show_server( - cls.guest_vm['id'] - ).get('server') - - @classmethod - def resource_cleanup(cls): - fl_ip_client = cls.mgr.compute_floating_ips_client - fl_ip_client.disassociate_floating_ip_from_server( - cls.public_vm_ip, - cls.public_vm['id'] - ) - - cls.mgr.servers_client.delete_server(cls.public_vm['id']) - cls.mgr.servers_client.delete_server(cls.guest_vm['id']) - - cls._wait_until_server_delete(cls.public_vm['id']) - cls._wait_until_server_delete(cls.guest_vm['id']) - - cls.mgr.keypairs_client.delete_keypair(cls.key_name) - - cls.mgr.compute_security_group_rules_client.delete_security_group_rule( - cls.ssh_rule_id - ) - os.remove(cls.key_dir + cls.key_name) - - super(SSHActionsTestsV2, cls).resource_cleanup() - - @decorators.attr(type='sanity') - @decorators.idempotent_id('3e12a2ad-5b10-46b0-ae1f-ed34d3cc6ae2') - def test_run_ssh_action(self): - input_data = { - 'cmd': 'hostname', - 'host': self.public_vm_ip, - 'username': CONF.validation.image_ssh_user, - 'private_key_filename': self.key_name - } - - resp, body = self.client.create_action_execution( - { - 'name': 'std.ssh', - 'input': json.dumps(input_data) - } - ) - - self.assertEqual(201, resp.status) - - output = json.loads(body['output']) - - self.assertIn(self.public_vm['name'], output['result']) - - @decorators.attr(type='sanity') - @decorators.idempotent_id('6c09fb04-70b4-43a6-b5f8-a53ca92e66e0') - @decorators.skip_because(bug="1736685") - def test_run_ssh_proxied_action(self): - guest_vm_ip = self.guest_vm['addresses'].popitem()[1][0]['addr'] - - input_data = { - 'cmd': 'hostname', - 'host': guest_vm_ip, - 'username': CONF.validation.image_ssh_user, - 'private_key_filename': self.key_name, - 'gateway_host': self.public_vm_ip, - 'gateway_username': CONF.validation.image_ssh_user - } - - resp, body = self.client.create_action_execution( - { - 'name': 'std.ssh_proxied', - 'input': json.dumps(input_data) - } - ) - - self.assertEqual(201, resp.status) - - output = json.loads(body['output']) - - self.assertIn(self.guest_vm['name'], output['result']) diff --git a/mistral_tempest_tests/tests/ssh_utils.py b/mistral_tempest_tests/tests/ssh_utils.py deleted file mode 100755 index a8f9feb21..000000000 --- a/mistral_tempest_tests/tests/ssh_utils.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2014 - 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. - -from os import path -from oslo_log import log as logging -import paramiko -import six - -KEY_PATH = path.expanduser("~/.ssh/") -LOG = logging.getLogger(__name__) - - -def _read_paramimko_stream(recv_func): - result = '' - buf = recv_func(1024) - while buf != '': - result += buf - buf = recv_func(1024) - - return result - - -def _to_paramiko_private_key(private_key_filename, password=None): - if '../' in private_key_filename or '..\\' in private_key_filename: - raise OSError( - "Private key filename must not contain '..'. " - "Actual: %s" % private_key_filename - ) - - private_key_path = KEY_PATH + private_key_filename - - return paramiko.RSAKey( - filename=private_key_path, - password=password - ) - - -def _connect(host, username, password=None, pkey=None, proxy=None): - if isinstance(pkey, six.string_types): - pkey = _to_paramiko_private_key(pkey, password) - - LOG.debug('Creating SSH connection to %s', host) - - ssh_client = paramiko.SSHClient() - ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - - ssh_client.connect( - host, - username=username, - password=password, - pkey=pkey, - sock=proxy - ) - - return ssh_client - - -def _cleanup(ssh_client): - ssh_client.close() - - -def _execute_command(ssh_client, cmd, get_stderr=False, - raise_when_error=True): - try: - chan = ssh_client.get_transport().open_session() - chan.exec_command(cmd) - - # TODO(nmakhotkin): that could hang if stderr buffer overflows - stdout = _read_paramimko_stream(chan.recv) - stderr = _read_paramimko_stream(chan.recv_stderr) - - ret_code = chan.recv_exit_status() - - if ret_code and raise_when_error: - raise RuntimeError("Cmd: %s\nReturn code: %s\nstdout: %s" - % (cmd, ret_code, stdout)) - if get_stderr: - return ret_code, stdout, stderr - else: - return ret_code, stdout - finally: - _cleanup(ssh_client) - - -def execute_command(cmd, host, username, password=None, - private_key_filename=None, get_stderr=False, - raise_when_error=True): - ssh_client = _connect(host, username, password, private_key_filename) - - LOG.debug("Executing command %s", cmd) - - return _execute_command(ssh_client, cmd, get_stderr, raise_when_error) diff --git a/mistral_tempest_tests/tests/utils.py b/mistral_tempest_tests/tests/utils.py deleted file mode 100755 index 05487b772..000000000 --- a/mistral_tempest_tests/tests/utils.py +++ /dev/null @@ -1,152 +0,0 @@ -# Copyright 2013 - Mirantis, Inc. -# Copyright 2015 - Huawei Technologies Co. Ltd -# Copyright 2016 - Brocade Communications Systems, 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 contextlib -import json -import os -import shutil -import tempfile - -from oslo_concurrency import processutils - - -class NotDefined(object): - """Marker of an empty value. - - In a number of cases None can't be used to express the semantics of - a not defined value because None is just a normal value rather than - a value set to denote that it's not defined. This class can be used - in such cases instead of None. - """ - - pass - - -def get_dict_from_string(string, delimiter=','): - if not string: - return {} - - kv_dicts = [] - - for kv_pair_str in string.split(delimiter): - kv_str = kv_pair_str.strip() - kv_list = kv_str.split('=') - - if len(kv_list) > 1: - try: - value = json.loads(kv_list[1]) - except ValueError: - value = kv_list[1] - - kv_dicts += [{kv_list[0]: value}] - else: - kv_dicts += [kv_list[0]] - - return get_dict_from_entries(kv_dicts) - - -def get_dict_from_entries(entries): - """Transforms a list of entries into dictionary. - - :param entries: A list of entries. - If an entry is a dictionary the method simply updates the result - dictionary with its content. - If an entry is not a dict adds {entry, NotDefined} into the result. - """ - - result = {} - - for e in entries: - if isinstance(e, dict): - result.update(e) - else: - # NOTE(kong): we put NotDefined here as the value of - # param without value specified, to distinguish from - # the valid values such as None, ''(empty string), etc. - result[e] = NotDefined - - return result - - -@contextlib.contextmanager -def tempdir(**kwargs): - argdict = kwargs.copy() - - if 'dir' not in argdict: - argdict['dir'] = '/tmp/' - - tmpdir = tempfile.mkdtemp(**argdict) - - try: - yield tmpdir - finally: - try: - shutil.rmtree(tmpdir) - except OSError as e: - raise OSError( - "Failed to delete temp dir %(dir)s (reason: %(reason)s)" % - {'dir': tmpdir, 'reason': e} - ) - - -def save_text_to(text, file_path, overwrite=False): - if os.path.exists(file_path) and not overwrite: - raise OSError( - "Cannot save data to file. File %s already exists." - ) - - with open(file_path, 'w') as f: - f.write(text) - - -def generate_key_pair(key_length=2048): - """Create RSA key pair with specified number of bits in key. - - Returns tuple of private and public keys. - """ - with tempdir() as tmpdir: - keyfile = os.path.join(tmpdir, 'tempkey') - args = [ - 'ssh-keygen', - '-q', # quiet - '-N', '', # w/o passphrase - '-t', 'rsa', # create key of rsa type - '-f', keyfile, # filename of the key file - '-C', 'Generated-by-Mistral' # key comment - ] - - if key_length is not None: - args.extend(['-b', key_length]) - - processutils.execute(*args) - - if not os.path.exists(keyfile): - # raise exc.DataAccessException( - # "Private key file hasn't been created" - # ) - raise OSError("Private key file hasn't been created") - - private_key = open(keyfile).read() - public_key_path = keyfile + '.pub' - - if not os.path.exists(public_key_path): - # raise exc.DataAccessException( - # "Public key file hasn't been created" - # ) - raise OSError("Private key file hasn't been created") - public_key = open(public_key_path).read() - - return private_key, public_key diff --git a/playbooks/legacy/mistral-devstack-dsvm-kombu/run.yaml b/playbooks/legacy/mistral-devstack-dsvm-kombu/run.yaml index 4592844ba..c7a5dbe33 100644 --- a/playbooks/legacy/mistral-devstack-dsvm-kombu/run.yaml +++ b/playbooks/legacy/mistral-devstack-dsvm-kombu/run.yaml @@ -23,6 +23,18 @@ chdir: '{{ ansible_user_dir }}/workspace' environment: '{{ zuul | zuul_legacy_vars }}' + - shell: + cmd: | + set -e + set -x + cat << 'EOF' >>"/tmp/dg-local.conf" + [[local|localrc]] + TEMPEST_PLUGINS='/opt/stack/new/mistral-tempest-plugin' + EOF + executable: /bin/bash + chdir: '{{ ansible_user_dir }}/workspace' + environment: '{{ zuul | zuul_legacy_vars }}' + - shell: cmd: | set -e @@ -38,11 +50,13 @@ fi export ENABLED_SERVICES=heat,h-api,h-api-cfn,h-api-cw,h-eng,tempest + export DEVSTACK_GATE_TEMPEST=1 export PROJECTS="openstack/zaqar $PROJECTS" export PROJECTS="openstack/python-zaqarclient $PROJECTS" export PROJECTS="openstack/heat $PROJECTS" export PROJECTS="openstack/mistral $PROJECTS" export PROJECTS="openstack/mistral-dashboard $PROJECTS" + export PROJECTS="openstack/mistral-tempest-plugin $PROJECTS" export DEVSTACK_LOCAL_CONFIG="enable_plugin mistral https://git.openstack.org/openstack/mistral" export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin heat git://git.openstack.org/openstack/heat" export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin zaqar git://git.openstack.org/openstack/zaqar" diff --git a/playbooks/legacy/mistral-devstack-dsvm-non-apache/run.yaml b/playbooks/legacy/mistral-devstack-dsvm-non-apache/run.yaml index 03777afc7..2fef857bd 100644 --- a/playbooks/legacy/mistral-devstack-dsvm-non-apache/run.yaml +++ b/playbooks/legacy/mistral-devstack-dsvm-non-apache/run.yaml @@ -23,6 +23,18 @@ chdir: '{{ ansible_user_dir }}/workspace' environment: '{{ zuul | zuul_legacy_vars }}' + - shell: + cmd: | + set -e + set -x + cat << 'EOF' >>"/tmp/dg-local.conf" + [[local|localrc]] + TEMPEST_PLUGINS='/opt/stack/new/mistral-tempest-plugin' + EOF + executable: /bin/bash + chdir: '{{ ansible_user_dir }}/workspace' + environment: '{{ zuul | zuul_legacy_vars }}' + - shell: cmd: | set -e @@ -38,11 +50,13 @@ fi export ENABLED_SERVICES=heat,h-api,h-api-cfn,h-api-cw,h-eng,tempest + export DEVSTACK_GATE_TEMPEST=1 export PROJECTS="openstack/zaqar $PROJECTS" export PROJECTS="openstack/python-zaqarclient $PROJECTS" export PROJECTS="openstack/heat $PROJECTS" export PROJECTS="openstack/mistral $PROJECTS" export PROJECTS="openstack/mistral-dashboard $PROJECTS" + export PROJECTS="openstack/mistral-tempest-plugin $PROJECTS" export DEVSTACK_LOCAL_CONFIG="enable_plugin mistral https://git.openstack.org/openstack/mistral" export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin heat git://git.openstack.org/openstack/heat" export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin zaqar git://git.openstack.org/openstack/zaqar" diff --git a/playbooks/legacy/mistral-devstack-dsvm/run.yaml b/playbooks/legacy/mistral-devstack-dsvm/run.yaml index a85d5d633..65470394b 100644 --- a/playbooks/legacy/mistral-devstack-dsvm/run.yaml +++ b/playbooks/legacy/mistral-devstack-dsvm/run.yaml @@ -23,6 +23,18 @@ chdir: '{{ ansible_user_dir }}/workspace' environment: '{{ zuul | zuul_legacy_vars }}' + - shell: + cmd: | + set -e + set -x + cat << 'EOF' >>"/tmp/dg-local.conf" + [[local|localrc]] + TEMPEST_PLUGINS='/opt/stack/new/mistral-tempest-plugin' + EOF + executable: /bin/bash + chdir: '{{ ansible_user_dir }}/workspace' + environment: '{{ zuul | zuul_legacy_vars }}' + - shell: cmd: | set -e @@ -38,11 +50,13 @@ fi export ENABLED_SERVICES=heat,h-api,h-api-cfn,h-api-cw,h-eng,tempest + export DEVSTACK_GATE_TEMPEST=1 export PROJECTS="openstack/zaqar $PROJECTS" export PROJECTS="openstack/python-zaqarclient $PROJECTS" export PROJECTS="openstack/heat $PROJECTS" export PROJECTS="openstack/mistral $PROJECTS" export PROJECTS="openstack/mistral-dashboard $PROJECTS" + export PROJECTS="openstack/mistral-tempest-plugin $PROJECTS" export DEVSTACK_LOCAL_CONFIG="enable_plugin mistral https://git.openstack.org/openstack/mistral" export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin heat git://git.openstack.org/openstack/heat" export DEVSTACK_LOCAL_CONFIG+=$'\n'"enable_plugin zaqar git://git.openstack.org/openstack/zaqar" diff --git a/setup.cfg b/setup.cfg index 447178d80..56b1adf3a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -56,9 +56,6 @@ oslo.config.opts.defaults = oslo.policy.policies = mistral = mistral.policies:list_rules -tempest.test_plugins = - mistral_test = mistral_tempest_tests.plugin:MistralTempestPlugin - mistral.actions = std.async_noop = mistral.actions.std_actions:AsyncNoOpAction std.noop = mistral.actions.std_actions:NoOpAction diff --git a/tox.ini b/tox.ini index 302ae0cf8..a1066a024 100644 --- a/tox.ini +++ b/tox.ini @@ -37,7 +37,6 @@ basepython = python2.7 commands = doc8 doc/source flake8 {posargs} . {toxinidir}/tools/get_action_list.py {toxinidir}/tools/sync_db.py - check-uuid --package mistral_tempest_tests [testenv:cover] # Also do not run test_coverage_ext tests while gathering coverage as those