From 568bbf53844cc0dbee3bed0f7039a47f25943f6e Mon Sep 17 00:00:00 2001 From: hparekh Date: Wed, 20 Jan 2016 15:23:19 +0900 Subject: [PATCH] Removed mistral/tests/functional All the changes has been merged to mistral_tempest_tests. Also scrits has been changed. Change-Id: I6c514a3c75f1b6e3b94b0e9b0e542697b68d9a02 Partially-Implements: blueprint mistral-tempest-plugin --- functionaltests/run_tests.sh | 2 +- mistral/tests/functional/__init__.py | 0 mistral/tests/functional/api/__init__.py | 0 mistral/tests/functional/api/v2/__init__.py | 0 .../api/v2/test_mistral_basic_v2.py | 1156 ----------------- mistral/tests/functional/base.py | 309 ----- mistral/tests/functional/engine/__init__.py | 0 .../functional/engine/actions/__init__.py | 0 .../functional/engine/actions/v2/__init__.py | 0 .../actions/v2/test_openstack_actions.py | 86 -- .../engine/actions/v2/test_ssh_actions.py | 272 ---- mistral_tempest_tests/services/base.py | 16 +- .../tests/api/v2/test_mistral_basic_v2.py | 5 +- .../engine/actions/v2/test_ssh_actions.py | 33 +- run_functional_tests.sh | 2 +- 15 files changed, 32 insertions(+), 1849 deletions(-) delete mode 100644 mistral/tests/functional/__init__.py delete mode 100644 mistral/tests/functional/api/__init__.py delete mode 100644 mistral/tests/functional/api/v2/__init__.py delete mode 100644 mistral/tests/functional/api/v2/test_mistral_basic_v2.py delete mode 100644 mistral/tests/functional/base.py delete mode 100644 mistral/tests/functional/engine/__init__.py delete mode 100644 mistral/tests/functional/engine/actions/__init__.py delete mode 100644 mistral/tests/functional/engine/actions/v2/__init__.py delete mode 100644 mistral/tests/functional/engine/actions/v2/test_openstack_actions.py delete mode 100644 mistral/tests/functional/engine/actions/v2/test_ssh_actions.py diff --git a/functionaltests/run_tests.sh b/functionaltests/run_tests.sh index 99410e37f..162ea39de 100755 --- a/functionaltests/run_tests.sh +++ b/functionaltests/run_tests.sh @@ -38,4 +38,4 @@ MISTRALCLIENT_DIR=/opt/stack/new/python-mistralclient export PYTHONPATH=$PYTHONPATH:$TEMPEST_DIR pwd -nosetests -sv mistral/tests/functional/ +nosetests -sv mistral_tempest_tests/tests/ diff --git a/mistral/tests/functional/__init__.py b/mistral/tests/functional/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral/tests/functional/api/__init__.py b/mistral/tests/functional/api/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral/tests/functional/api/v2/__init__.py b/mistral/tests/functional/api/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral/tests/functional/api/v2/test_mistral_basic_v2.py b/mistral/tests/functional/api/v2/test_mistral_basic_v2.py deleted file mode 100644 index 5904129c2..000000000 --- a/mistral/tests/functional/api/v2/test_mistral_basic_v2.py +++ /dev/null @@ -1,1156 +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. - -import json - -from oslo_log import log as logging -import six -from tempest import test -from tempest_lib import decorators -from tempest_lib import exceptions - -from mistral.tests.functional import base -from mistral import utils - - -LOG = logging.getLogger(__name__) - - -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() - - @test.attr(type='smoke') - def test_get_list_workbooks(self): - resp, body = self.client.get_list_obj('workbooks') - - self.assertEqual(200, resp.status) - self.assertEqual([], body['workbooks']) - - @test.attr(type='sanity') - def test_create_and_delete_workbook(self): - 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.assertEqual([], body['workbooks']) - - @test.attr(type='sanity') - def test_get_workbook(self): - _, 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']) - - @test.attr(type='sanity') - def test_update_workbook(self): - _, 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']) - - @test.attr(type='sanity') - def test_get_workbook_definition(self): - _, 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) - - @test.attr(type='negative') - def test_get_nonexistent_workbook_definition(self): - self.assertRaises(exceptions.NotFound, - self.client.get_definition, - 'workbooks', 'nonexist') - - @test.attr(type='negative') - def test_get_nonexistent_workbook(self): - self.assertRaises(exceptions.NotFound, self.client.get_object, - 'workbooks', 'nonexist') - - @test.attr(type='negative') - def test_double_create_workbook(self): - _, 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.assertEqual([], body['workbooks']) - - @test.attr(type='negative') - def test_create_wb_with_invalid_def(self): - self.assertRaises( - exceptions.BadRequest, - self.client.create_workbook, - 'wb_v1.yaml' - ) - - @test.attr(type='negative') - def test_update_wb_with_invalid_def(self): - self.assertRaises( - exceptions.BadRequest, - self.client.update_request, - 'workbooks', - 'wb_v1.yaml' - ) - - -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() - - @test.attr(type='smoke') - 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) - - @test.attr(type='smoke') - 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(['id', 'name'], wf.keys()) - - @test.attr(type='smoke') - 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='&' - ) - - expected_sub_dict = { - 'limit': 1, - 'sort_keys': 'name', - 'sort_dirs': 'desc' - } - - 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) - - @test.attr(type='negative') - 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') - ) - - @test.attr(type='negative') - 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') - ) - - @test.attr(type='negative') - 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') - ) - - @test.attr(type='sanity') - def test_create_and_delete_workflow(self): - 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) - - @test.attr(type='sanity') - def test_get_workflow(self): - _, 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']) - - @test.attr(type='sanity') - def test_update_workflow(self): - _, body = self.client.create_workflow('wf_v2.yaml') - name = body['workflows'][0]['name'] - - resp, body = self.client.update_request('workflows', 'wf_v2.yaml') - - self.assertEqual(200, resp.status) - self.assertEqual(name, body['workflows'][0]['name']) - - @test.attr(type='sanity') - def test_get_workflow_definition(self): - _, 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) - - @test.attr(type='sanity') - def test_get_workflow_uploaded_in_wb(self): - _, 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) - - @test.attr(type='negative') - def test_get_nonexistent_workflow_definition(self): - self.assertRaises(exceptions.NotFound, - self.client.get_definition, - 'workflows', 'nonexist') - - @test.attr(type='negative') - def test_get_nonexistent_workflow(self): - self.assertRaises(exceptions.NotFound, self.client.get_object, - 'workflows', 'nonexist') - - @test.attr(type='negative') - def test_double_create_workflows(self): - _, body = self.client.create_workflow('wf_v2.yaml') - self.assertRaises(exceptions.Conflict, - self.client.create_workflow, - 'wf_v2.yaml') - - @test.attr(type='negative') - def test_create_wf_with_invalid_def(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_workflow, - 'wb_v1.yaml') - - @test.attr(type='negative') - def test_update_wf_with_invalid_def(self): - self.assertRaises(exceptions.BadRequest, - self.client.update_request, - 'workflows', 'wb_v1.yaml') - - @test.attr(type='negative') - 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) - - @test.attr(type='negative') - def test_delete_wf_with_trigger_associate_in_other_tenant(self): - 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 triggers associated", - exception.resp_body['faultstring'] - ) - finally: - self.alt_client.delete_obj('cron_triggers', tr_name) - self.alt_client.triggers.remove(tr_name) - - @test.attr(type='negative') - def test_delete_nonexistent_wf(self): - self.assertRaises(exceptions.NotFound, - self.client.delete_obj, - 'workflows', 'nonexist') - - -class ExecutionTestsV2(base.TestCase): - - _service = 'workflowv2' - - def setUp(self): - super(ExecutionTestsV2, self).setUp() - - _, body = self.client.create_workflow('wf_v2.yaml') - - self.direct_wf_name = 'wf' - self.direct_wf2_name = 'wf2' - 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() - - @test.attr(type='smoke') - def test_get_list_executions(self): - resp, body = self.client.get_list_obj('executions') - self.assertEqual(200, resp.status) - self.assertNotIn('next', body) - - @test.attr(type='smoke') - 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='&' - ) - - expected_dict = { - 'limit': 1, - 'sort_keys': 'workflow_name', - 'sort_dirs': '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) - - @test.attr(type='sanity') - 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']]) - - @test.attr(type='sanity') - def test_create_execution_for_reverse_wf(self): - resp, body = self.client.create_execution( - self.reverse_wf['name'], - {self.reverse_wf['input']: "Bye"}, - {"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']) - - @test.attr(type='sanity') - 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']) - - @test.attr(type='sanity') - 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']) - - @test.attr(type='sanity') - 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']) - - @test.attr(type='sanity') - 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']) - - @test.attr(type='negative') - def test_get_nonexistent_execution(self): - self.assertRaises(exceptions.NotFound, self.client.get_object, - 'executions', '1a2b3c') - - @test.attr(type='negative') - def test_update_nonexistent_execution(self): - put_body = '{"state": "STOPPED"}' - - self.assertRaises(exceptions.NotFound, - self.client.update_execution, - '1a2b3c', put_body) - - @test.attr(type='negative') - def test_delete_nonexistent_execution(self): - self.assertRaises(exceptions.NotFound, - self.client.delete_obj, - 'executions', 'nonexist') - - @test.attr(type='negative') - def test_create_ex_for_nonexistent_wf(self): - self.assertRaises(exceptions.NotFound, - self.client.create_execution, - 'nonexist') - - @test.attr(type='negative') - def test_create_execution_for_reverse_wf_invalid_start_task(self): - _, wf_ex = self.client.create_execution( - self.reverse_wf['name'], - { - self.reverse_wf['input']: "Bye"}, - { - "task_name": "nonexist" - } - ) - - self.assertEqual("ERROR", wf_ex['state']) - self.assertIn("Invalid task name", wf_ex['state_info']) - - @test.attr(type='negative') - def test_create_execution_forgot_input_params(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_execution, - self.reverse_wf['name'], - params={"task_name": "nonexist"}) - - @test.attr(type='sanity') - 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) - - @test.attr(type='sanity') - 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') - - -class CronTriggerTestsV2(base.TestCase): - - _service = 'workflowv2' - - def setUp(self): - super(CronTriggerTestsV2, self).setUp() - - _, 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() - - @test.attr(type='smoke') - def test_get_list_cron_triggers(self): - resp, body = self.client.get_list_obj('cron_triggers') - - self.assertEqual(200, resp.status) - self.assertEqual([], body['cron_triggers']) - - @test.attr(type='sanity') - 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) - - @test.attr(type='sanity') - 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) - - @test.attr(type='sanity') - 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) - - @test.attr(type='sanity') - 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']) - - @test.attr(type='negative') - def test_create_cron_trigger_nonexistent_wf(self): - self.assertRaises(exceptions.NotFound, - self.client.create_cron_trigger, - 'trigger', 'nonexist', None, '5 * * * *') - - @test.attr(type='negative') - def test_create_cron_trigger_invalid_count(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_cron_trigger, - 'trigger', 'nonexist', None, '5 * * * *', None, "q") - - @test.attr(type='negative') - def test_create_cron_trigger_negative_count(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_cron_trigger, - 'trigger', 'nonexist', None, '5 * * * *', None, -1) - - @test.attr(type='negative') - def test_create_cron_trigger_invalid_first_date(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_cron_trigger, - 'trigger', 'nonexist', None, '5 * * * *', "q") - - @test.attr(type='negative') - def test_create_cron_trigger_count_only(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_cron_trigger, - 'trigger', 'nonexist', None, None, None, "42") - - @test.attr(type='negative') - 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") - - @test.attr(type='negative') - def test_get_nonexistent_cron_trigger(self): - self.assertRaises(exceptions.NotFound, - self.client.get_object, - 'cron_triggers', 'trigger') - - @test.attr(type='negative') - def test_delete_nonexistent_trigger(self): - self.assertRaises(exceptions.NotFound, - self.client.delete_obj, - 'cron_triggers', 'trigger') - - @test.attr(type='negative') - 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.skip_because(bug="1383146") - @test.attr(type='negative') - def test_create_two_cron_triggers_with_same_pattern(self): - self.client.create_trigger( - 'trigger1', self.wf_name, None, '5 * * * *') - self.assertRaises(exceptions.Conflict, - self.client.create_cron_trigger, - 'trigger2', self.wf_name, None, '5 * * * *') - - @test.attr(type='negative') - def test_invalid_cron_pattern_not_enough_params(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_cron_trigger, - 'trigger', self.wf_name, None, '5 *') - - @test.attr(type='negative') - def test_invalid_cron_pattern_out_of_range(self): - self.assertRaises(exceptions.BadRequest, - self.client.create_cron_trigger, - 'trigger', self.wf_name, None, '88 * * * *') - - -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() - - @test.attr(type='smoke') - def test_get_list_actions(self): - resp, body = self.client.get_list_obj('actions') - - self.assertEqual(200, resp.status) - self.assertNotEqual([], body['actions']) - self.assertNotIn('next', body) - - @test.attr(type='smoke') - 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='&' - ) - - expected_sub_dict = { - 'limit': 1, - 'sort_keys': 'name', - 'sort_dirs': 'desc' - } - - 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) - - @test.attr(type='negative') - 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') - ) - - @test.attr(type='negative') - 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') - ) - - @test.attr(type='negative') - 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') - ) - - @test.attr(type='sanity') - 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) - - @test.attr(type='sanity') - 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']) - - @test.attr(type='sanity') - 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']])) - - @test.attr(type='sanity') - 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) - - @test.attr(type='negative') - def test_get_nonexistent_action(self): - self.assertRaises( - exceptions.NotFound, - self.client.get_object, - 'actions', 'nonexist' - ) - - @test.attr(type='negative') - def test_double_creation(self): - self.client.create_action('action_v2.yaml') - - self.assertRaises( - exceptions.Conflict, - self.client.create_action, - 'action_v2.yaml' - ) - - @test.attr(type='negative') - def test_create_action_invalid_def(self): - self.assertRaises( - exceptions.BadRequest, - self.client.create_action, - 'wb_v2.yaml' - ) - - @test.attr(type='negative') - def test_update_action_invalid_def(self): - self.assertRaises( - exceptions.BadRequest, - self.client.update_request, - 'actions', 'wb_v2.yaml' - ) - - @test.attr(type='negative') - def test_delete_nonexistent_action(self): - self.assertRaises( - exceptions.NotFound, - self.client.delete_obj, - 'actions', 'nonexist' - ) - - @test.attr(type='negative') - def test_delete_standard_action(self): - self.assertRaises( - exceptions.BadRequest, - self.client.delete_obj, - 'actions', 'nova.servers_create' - ) - - -class TasksTestsV2(base.TestCase): - - _service = 'workflowv2' - - def setUp(self): - super(TasksTestsV2, self).setUp() - - _, 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) - - 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() - - @test.attr(type='smoke') - def test_get_tasks_list(self): - resp, body = self.client.get_list_obj('tasks') - - self.assertEqual(200, resp.status) - self.assertNotEmpty(body['tasks']) - - @test.attr(type='sanity') - 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'] - ) - - -class ActionExecutionTestsV2(base.TestCase): - _service = 'workflowv2' - - @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() - - @test.attr(type='sanity') - 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 - ) - - @test.attr(type='sanity') - 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)) - - @test.attr(type='sanity') - 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']) - - @test.attr(type='sanity') - 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 - ) - - @test.attr(type='negative') - def test_delete_nonexistent_action_execution(self): - self.assertRaises( - exceptions.NotFound, - self.client.delete_obj, - 'action_executions', - 'nonexist' - ) diff --git a/mistral/tests/functional/base.py b/mistral/tests/functional/base.py deleted file mode 100644 index 4df8d378a..000000000 --- a/mistral/tests/functional/base.py +++ /dev/null @@ -1,309 +0,0 @@ -# Copyright 2013 Mirantis, Inc. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import json -import os -import time - -import mock -import six - -from tempest import clients -from tempest import config -from tempest import test as test -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/tests' - dir_path = __file__[0:__file__.find(main_package) + len(main_package) + 1] - - return open(dir_path + 'resources/' + path).read() - - -def find_items(items, **props): - def _matches(item, **props): - for prop_name, prop_val in six.iteritems(props): - if item[prop_name] != prop_val: - return False - - return True - - filtered = list(filter(lambda item: _matches(item, **props), items)) - - 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 - ) - - 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 = [] - - def get_list_obj(self, name): - resp, body = self.get(name) - - 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 MistralClientV2(MistralClientBase): - - def post_request(self, url, file_name): - headers = {"headers": "Content-Type:text/plain"} - - return self.post(url, get_resource(file_name), headers=headers) - - def post_json(self, url, obj): - headers = {"Content-Type": "application/json"} - - return self.post(url, json.dumps(obj), headers=headers) - - def update_request(self, url, file_name): - headers = {"headers": "Content-Type:text/plain"} - - resp, body = self.put(url, 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): - if scope: - resp, body = self.post_request('workflows?scope=public', yaml_file) - else: - resp, body = self.post_request('workflows', yaml_file) - - for wf in json.loads(body)['workflows']: - self.workflows.append(wf['name']) - - return resp, json.loads(body) - - def create_execution(self, wf_name, wf_input=None, params=None): - body = {"workflow_name": "%s" % wf_name} - - 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 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): - resp, body = self.post_json('action_executions', request_body) - - 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) - - -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 '' - - -class TestCase(test.BaseTestCase): - - credentials = ['primary', 'alt'] - - @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 = AuthProv() - cls.alt_mgr = cls.mgr - else: - cls.mgr = cls.manager - cls.alt_mgr = cls.alt_manager - - if cls._service == 'workflowv2': - cls.client = MistralClientV2( - cls.mgr.auth_provider, cls._service) - cls.alt_client = MistralClientV2( - cls.alt_mgr.auth_provider, cls._service) - - def setUp(self): - super(TestCase, self).setUp() - - 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.server_client = clients.ServersClient( - cls.mgr.auth_provider, - "compute", - region=CONF.identity.region - ) - - 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/tests/functional/engine/__init__.py b/mistral/tests/functional/engine/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral/tests/functional/engine/actions/__init__.py b/mistral/tests/functional/engine/actions/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral/tests/functional/engine/actions/v2/__init__.py b/mistral/tests/functional/engine/actions/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/mistral/tests/functional/engine/actions/v2/test_openstack_actions.py b/mistral/tests/functional/engine/actions/v2/test_openstack_actions.py deleted file mode 100644 index b7cfe26f2..000000000 --- a/mistral/tests/functional/engine/actions/v2/test_openstack_actions.py +++ /dev/null @@ -1,86 +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 import test - -from mistral.tests.functional 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') - - @test.attr(type='openstack') - 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']) - - @test.attr(type='openstack') - def test_keystone_actions(self): - wf_name = self.wb['name'] + '.keystone' - _, 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']) - - @test.attr(type='openstack') - 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']) - - @test.attr(type='openstack') - 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']) - - @test.attr(type='openstack') - 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']) - - @test.attr(type='openstack') - 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']) diff --git a/mistral/tests/functional/engine/actions/v2/test_ssh_actions.py b/mistral/tests/functional/engine/actions/v2/test_ssh_actions.py deleted file mode 100644 index 55f38a18e..000000000 --- a/mistral/tests/functional/engine/actions/v2/test_ssh_actions.py +++ /dev/null @@ -1,272 +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 import test - -from mistral.tests.functional import base -from mistral import utils -from mistral.utils import ssh_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.server_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( - filter(lambda fl_ip: fl_ip['instance_id'] is None, all_ips) - ) - - 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.server_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 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.server_client.show_server( - cls.public_vm['id'] - ).get('server') - - cls.guest_vm = cls.server_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.server_client.delete_server(cls.public_vm['id']) - cls.server_client.delete_server(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() - - @test.attr(type='sanity') - 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']) - - @test.attr(type='sanity') - 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/services/base.py b/mistral_tempest_tests/services/base.py index 815333c04..790f6b80a 100644 --- a/mistral_tempest_tests/services/base.py +++ b/mistral_tempest_tests/services/base.py @@ -20,7 +20,6 @@ import mock import six from tempest import clients -from tempest.common import credentials_factory as creds from tempest import config from tempest import test as test from tempest_lib import auth @@ -244,6 +243,9 @@ class AuthProv(auth.KeystoneV2AuthProvider): class TestCase(test.BaseTestCase): + + credentials = ['primary', 'alt'] + @classmethod def resource_setup(cls): """Client authentication. @@ -256,16 +258,10 @@ class TestCase(test.BaseTestCase): if 'WITHOUT_AUTH' in os.environ: cls.mgr = mock.MagicMock() cls.mgr.auth_provider = AuthProv() + cls.alt_mgr = cls.mgr else: - cls.creds = creds.get_configured_credentials( - credential_type='user' - ) - cls.mgr = clients.Manager(cls.creds) - - cls.alt_creds = creds.get_configured_credentials( - credential_type='alt_user' - ) - cls.alt_mgr = clients.Manager(cls.alt_creds) + cls.mgr = cls.manager + cls.alt_mgr = cls.alt_manager if cls._service == 'workflowv2': cls.client = MistralClientV2( diff --git a/mistral_tempest_tests/tests/api/v2/test_mistral_basic_v2.py b/mistral_tempest_tests/tests/api/v2/test_mistral_basic_v2.py index f546e955f..14ebd040d 100644 --- a/mistral_tempest_tests/tests/api/v2/test_mistral_basic_v2.py +++ b/mistral_tempest_tests/tests/api/v2/test_mistral_basic_v2.py @@ -382,9 +382,8 @@ class WorkflowTestsV2(base.TestCase): name ) - self.assertEqual( - "Can't delete workflow that has triggers " + - "[workflow_name=wf2],[cron_trigger_name(s)=trigger]", + self.assertIn( + "Can't delete workflow that has triggers associated", exception.resp_body['faultstring'] ) finally: 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 index 933af0125..684842807 100644 --- 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 @@ -38,19 +38,25 @@ class SSHActionsTestsV2(base.TestCaseAdvanced): @classmethod def _create_security_group_rule_ssh(cls): - sec_groups = cls.mgr.security_groups_client.list_security_groups() + 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.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" + 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'] @@ -201,11 +207,16 @@ class SSHActionsTestsV2(base.TestCaseAdvanced): @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.server_client.delete_server(cls.public_vm['id']) cls.server_client.delete_server(cls.guest_vm['id']) cls.mgr.keypairs_client.delete_keypair(cls.key_name) - cls.mgr.security_group_rules_client.delete_security_group_rule( + cls.mgr.compute_security_group_rules_client.delete_security_group_rule( cls.ssh_rule_id ) os.remove(cls.key_dir + cls.key_name) @@ -217,7 +228,7 @@ class SSHActionsTestsV2(base.TestCaseAdvanced): input_data = { 'cmd': 'hostname', 'host': self.public_vm_ip, - 'username': CONF.scenario.ssh_user, + 'username': CONF.validation.image_ssh_user, 'private_key_filename': self.key_name } @@ -241,10 +252,10 @@ class SSHActionsTestsV2(base.TestCaseAdvanced): input_data = { 'cmd': 'hostname', 'host': guest_vm_ip, - 'username': CONF.scenario.ssh_user, + 'username': CONF.validation.image_ssh_user, 'private_key_filename': self.key_name, 'gateway_host': self.public_vm_ip, - 'gateway_username': CONF.scenario.ssh_user + 'gateway_username': CONF.validation.image_ssh_user } resp, body = self.client.create_action_execution( diff --git a/run_functional_tests.sh b/run_functional_tests.sh index 5c5886a3d..1632fdcea 100755 --- a/run_functional_tests.sh +++ b/run_functional_tests.sh @@ -14,7 +14,7 @@ function pre_hook() { function run_tests_by_version() { echo "$(tput setaf 4)Running integration API and workflow execution tests for v$1$(tput sgr 0)" export VERSION="v$1" - nosetests -v mistral/tests/functional/api/v$1/ + nosetests -v mistral_tempest_tests/tests/api/v$1/ unset VERSION }