From 3672b7947f1360a9ecd91ab4badbba2bb9124f99 Mon Sep 17 00:00:00 2001 From: Anastasia Kuznetsova Date: Thu, 23 Oct 2014 14:21:40 +0400 Subject: [PATCH] Add API integration tests for actions Added positive and negative API tests for 'actions' endpoint. Change-Id: I6e5fdb83359371e53c28873b74a77138dd38b6fe --- .../api/v2/test_mistral_basic_v2.py | 213 +++++++++++++++--- mistral/tests/functional/base.py | 24 +- mistral/tests/resources/action_v2.yaml | 21 ++ 3 files changed, 222 insertions(+), 36 deletions(-) create mode 100644 mistral/tests/resources/action_v2.yaml diff --git a/mistral/tests/functional/api/v2/test_mistral_basic_v2.py b/mistral/tests/functional/api/v2/test_mistral_basic_v2.py index 1a1b7c3cb..286a62ad1 100644 --- a/mistral/tests/functional/api/v2/test_mistral_basic_v2.py +++ b/mistral/tests/functional/api/v2/test_mistral_basic_v2.py @@ -59,8 +59,7 @@ class WorkflowTestsV2(base.TestCase): resp, body = self.client.get_list_obj('workflows') self.assertEqual(200, resp.status) - names = [body['workflows'][i]['name'] - for i in range(len(body['workflows']))] + names = [wf['name'] for wf in body['workflows']] self.assertIn('wf', names) self.client.delete_obj('workflows', 'wf') @@ -68,8 +67,7 @@ class WorkflowTestsV2(base.TestCase): _, body = self.client.get_list_obj('workflows') - names = [body['workflows'][i]['name'] - for i in range(len(body['workflows']))] + names = [wf['name'] for wf in body['workflows']] self.assertNotIn('wf', names) @test.attr(type='smoke') @@ -138,26 +136,25 @@ class CronTriggerTestsV2(base.TestCase): super(CronTriggerTestsV2, self).tearDown() @test.attr(type='smoke') - def test_get_list_triggers(self): + 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_triggers(self): + def test_create_and_delete_cron_triggers(self): tr_name = 'trigger' - resp, body = self.client.create_trigger( - tr_name, '5 * * * *', self.wf_name) + resp, body = self.client.create_cron_trigger( + tr_name, '5 * * * *', self.wf_name) 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 = [body['cron_triggers'][i]['name'] - for i in range(len(body['cron_triggers']))] + + trs_names = [tr['name'] for tr in body['cron_triggers']] self.assertIn(tr_name, trs_names) self.client.delete_obj('cron_triggers', tr_name) @@ -165,38 +162,35 @@ class CronTriggerTestsV2(base.TestCase): _, body = self.client.get_list_obj('cron_triggers') - trs_names = [body['cron_triggers'][i]['name'] - for i in range(len(body['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_triggers_for_one_wf(self): + def test_create_two_cron_triggers_for_one_wf(self): tr_name_1 = 'trigger1' tr_name_2 = 'trigger2' - resp, body = self.client.create_trigger( - tr_name_1, '5 * * * *', self.wf_name) + resp, body = self.client.create_cron_trigger( + tr_name_1, '5 * * * *', self.wf_name) self.assertEqual(201, resp.status) self.assertEqual(tr_name_1, body['name']) - resp, body = self.client.create_trigger( + resp, body = self.client.create_cron_trigger( tr_name_2, '15 * * * *', self.wf_name) - 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 = [body['cron_triggers'][i]['name'] - for i in range(len(body['cron_triggers']))] + + 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_trigger(self): + def test_get_cron_trigger(self): tr_name = 'trigger' - self.client.create_trigger( + self.client.create_cron_trigger( tr_name, '5 * * * *', self.wf_name) resp, body = self.client.get_object('cron_triggers', tr_name) @@ -205,13 +199,13 @@ class CronTriggerTestsV2(base.TestCase): self.assertEqual(tr_name, body['name']) @test.attr(type='negative') - def test_create_trigger_nonexistent_wf(self): + def test_create_cron_trigger_nonexistent_wf(self): self.assertRaises(exceptions.NotFound, - self.client.create_trigger, + self.client.create_cron_trigger, 'trigger', '5 * * * *', 'nonexist') @test.attr(type='negative') - def test_get_nonexistent_trigger(self): + def test_get_nonexistent_cron_trigger(self): self.assertRaises(exceptions.NotFound, self.client.get_object, 'cron_triggers', 'trigger') @@ -223,31 +217,180 @@ class CronTriggerTestsV2(base.TestCase): 'cron_triggers', 'trigger') @test.attr(type='negative') - def test_create_two_triggers_with_same_name(self): + def test_create_two_cron_triggers_with_same_name(self): tr_name = 'trigger' - self.client.create_trigger( + self.client.create_cron_trigger( tr_name, '5 * * * *', self.wf_name) self.assertRaises(exceptions.Conflict, - self.client.create_trigger, + self.client.create_cron_trigger, tr_name, '5 * * * *', self.wf_name) @test.skip_because(bug="1383146") @test.attr(type='negative') - def test_create_two_triggers_with_same_pattern(self): + def test_create_two_cron_triggers_with_same_pattern(self): self.client.create_trigger( 'trigger1', '5 * * * *', self.wf_name) self.assertRaises(exceptions.Conflict, - self.client.create_trigger, + self.client.create_cron_trigger, 'trigger2', '5 * * * *', self.wf_name) @test.attr(type='nagative') - def test_invalid_pattern_not_enough_params(self): + def test_invalid_cron_pattern_not_enough_params(self): self.assertRaises(exceptions.ServerFault, - self.client.create_trigger, + self.client.create_cron_trigger, 'trigger', '5 *', self.wf_name) @test.attr(type='nagative') - def test_invalid_pattern_out_of_range(self): + def test_invalid_cron_pattern_out_of_range(self): self.assertRaises(exceptions.ServerFault, - self.client.create_trigger, + self.client.create_cron_trigger, 'trigger', '88 * * * *', self.wf_name) + + +class ActionTestsV2(base.TestCase): + + _version = 2 + + 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']) + + @test.attr(type='sanity') + def test_create_and_delete_few_actions(self): + text = base.get_resource('resources/action_v2.yaml') + action1_name = 'greeting' + action2_name = 'farewell' + + resp, body = self.client.create_action(text) + self.assertEqual(201, resp.status) + + actions = [action['name'] for action in body['actions']] + self.assertIn(action1_name, actions) + self.assertIn(action2_name, actions) + + resp, body = self.client.get_list_obj('actions') + self.assertEqual(200, resp.status) + + actions = [action['name'] for action in body['actions']] + self.assertIn(action1_name, actions) + self.assertIn(action2_name, actions) + + self.client.delete_obj('actions', action1_name) + self.client.delete_obj('actions', action2_name) + + _, body = self.client.get_list_obj('actions') + + actions = [action['name'] for action in body['actions']] + self.assertNotIn(action1_name, actions) + self.assertNotIn(action2_name, actions) + self.client.actions.remove(action1_name) + self.client.actions.remove(action2_name) + + @test.attr(type='sanity') + def test_get_action(self): + text = base.get_resource('resources/action_v2.yaml') + action1_name = 'greeting' + self.client.create_action(text) + + resp, body = self.client.get_object('actions', action1_name) + + self.assertEqual(200, resp.status) + self.assertEqual(action1_name, body['name']) + + @test.attr(type='sanity') + def test_update_action(self): + text = base.get_resource('resources/action_v2.yaml') + act1_name = 'greeting' + act2_name = 'farewell' + + resp, body = self.client.create_action(text) + act1_created_at = self.get_field_value( + body=body, act_name=act1_name, field='created_at') + act2_created_at = self.get_field_value( + body=body, act_name=act2_name, field='created_at') + + self.assertNotIn('updated at', body['actions']) + + resp, body = self.client.update_action(text) + self.assertEqual(200, resp.status) + + actions = [action['name'] for action in body['actions']] + self.assertIn(act1_name, actions) + self.assertIn(act2_name, actions) + + updated1_created_at = self.get_field_value( + body=body, act_name=act1_name, field='created_at') + updated2_created_at = self.get_field_value( + body=body, act_name=act2_name, field='created_at') + + self.assertEqual(act1_created_at.split(".")[0], updated1_created_at) + self.assertEqual(act2_created_at.split(".")[0], updated2_created_at) + self.assertTrue(all(['updated_at' in item + for item in body['actions']])) + + @test.attr(type='sanity') + def test_get_action_definition(self): + text = base.get_resource('resources/action_v2.yaml') + action1_name = 'greeting' + action2_name = 'farewell' + self.client.create_action(text) + + resp, body = self.client.get_action_definition(action1_name) + self.assertEqual(200, resp.status) + self.assertIsNotNone(body) + + resp, body = self.client.get_action_definition(action2_name) + self.assertEqual(200, resp.status) + self.assertIsNotNone(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): + text = base.get_resource('resources/action_v2.yaml') + self.client.create_action(text) + + self.assertRaises(exceptions.Conflict, + self.client.create_action, + text) + + @test.attr(type='negative') + def test_create_action_invalid_def(self): + self.assertRaises(exceptions.ServerFault, + self.client.create_action, "") + + @test.attr(type='negative') + def test_update_action_invalid_def(self): + self.assertRaises(exceptions.ServerFault, + self.client.update_action, "") + + @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') diff --git a/mistral/tests/functional/base.py b/mistral/tests/functional/base.py index c3b3056d8..a8b74c939 100644 --- a/mistral/tests/functional/base.py +++ b/mistral/tests/functional/base.py @@ -73,6 +73,7 @@ class MistralClientBase(rest_client.RestClient): self.executions = [] self.workflows = [] self.triggers = [] + self.actions = [] def get_list_obj(self, name): resp, body = self.get(name) @@ -287,7 +288,7 @@ class MistralClientV2(MistralClientBase): return resp, json.loads(body) - def create_trigger(self, name, pattern, wf_name, wf_input=None): + def create_cron_trigger(self, name, pattern, wf_name, wf_input=None): post_body = { 'name': name, 'pattern': pattern, @@ -302,6 +303,27 @@ class MistralClientV2(MistralClientBase): return rest, json.loads(body) + def create_action(self, text): + post_body = {"definition": "%s" % text} + resp, body = self.post('actions', + json.dumps(post_body)) + self.actions.extend( + [action['name'] for action in json.loads(body)['actions']]) + + return resp, json.loads(body) + + def update_action(self, text): + post_body = {"definition": "%s" % text} + resp, body = self.put('actions', + json.dumps(post_body)) + + return resp, json.loads(body) + + def get_action_definition(self, name): + resp, body = self.get("actions/%s" % name) + + return resp, json.loads(body)['definition'] + class AuthProv(auth.KeystoneV2AuthProvider): diff --git a/mistral/tests/resources/action_v2.yaml b/mistral/tests/resources/action_v2.yaml new file mode 100644 index 000000000..ccca02c4a --- /dev/null +++ b/mistral/tests/resources/action_v2.yaml @@ -0,0 +1,21 @@ +--- +version: "2.0" + +greeting: + description: "This action says 'Hello'" + tags: [hello] + base: std.echo + base-input: + output: 'Hello, {$.name}' + input: + - name + output: + string: $.output + +farewell: + base: std.echo + base-input: + output: 'Bye!' + output: + info: $.output +