# # 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 mock from heat.common import exception from heat.common import template_format from heat.engine.clients.os import mistral as client from heat.engine import resource from heat.engine.resources.openstack.mistral import external_resource from heat.engine import scheduler from heat.engine import template from heat.tests import common from heat.tests import utils external_resource_template = """ heat_template_version: ocata resources: custom: type: OS::Mistral::ExternalResource properties: actions: CREATE: workflow: some_workflow params: target: create_my_custom_thing UPDATE: workflow: another_workflow DELETE: workflow: yet_another_workflow input: foo1: 123 foo2: 456 replace_on_change_inputs: - foo2 """ class FakeExecution(object): def __init__(self, id='1234', output='{}', state='IDLE'): self.id = id self.output = output self.state = state class TestMistralExternalResource(common.HeatTestCase): def setUp(self): super(TestMistralExternalResource, self).setUp() self.ctx = utils.dummy_context() tmpl = template_format.parse(external_resource_template) self.stack = utils.parse_stack(tmpl, stack_name='test_stack') resource_defns = self.stack.t.resource_definitions(self.stack) self.rsrc_defn = resource_defns['custom'] self.mistral = mock.Mock() self.patchobject(external_resource.MistralExternalResource, 'client', return_value=self.mistral) self.patchobject(client, 'mistral_base') self.patchobject(client.MistralClientPlugin, '_create') self.client = client.MistralClientPlugin(self.ctx) def _create_resource(self, name, snippet, stack, output='{}', get_state='SUCCESS'): execution = external_resource.MistralExternalResource(name, snippet, stack) self.mistral.executions.get.return_value = ( FakeExecution('test_stack-execution-b5fiekfci3yc', output, get_state)) self.mistral.executions.create.return_value = ( FakeExecution('test_stack-execution-b5fiekfci3yc')) return execution def test_create(self): execution = self._create_resource('execution', self.rsrc_defn, self.stack) scheduler.TaskRunner(execution.create)() expected_state = (execution.CREATE, execution.COMPLETE) self.assertEqual(expected_state, execution.state) self.assertEqual('test_stack-execution-b5fiekfci3yc', execution.resource_id) def test_create_with_resource_id_output(self): output = '{"resource_id": "my-fake-resource-id"}' execution = self._create_resource('execution', self.rsrc_defn, self.stack, output) scheduler.TaskRunner(execution.create)() expected_state = (execution.CREATE, execution.COMPLETE) self.assertEqual(expected_state, execution.state) self.assertEqual('my-fake-resource-id', execution.resource_id) def test_replace_on_change(self): execution = self._create_resource('execution', self.rsrc_defn, self.stack) scheduler.TaskRunner(execution.create)() expected_state = (execution.CREATE, execution.COMPLETE) self.assertEqual(expected_state, execution.state) tmpl = template_format.parse(external_resource_template) tmpl['resources']['custom']['properties']['input']['foo2'] = '4567' res_defns = template.Template(tmpl).resource_definitions(self.stack) new_custom_defn = res_defns['custom'] self.assertRaises(resource.UpdateReplace, scheduler.TaskRunner(execution.update, new_custom_defn)) def test_create_failed(self): execution = self._create_resource('execution', self.rsrc_defn, self.stack, get_state='ERROR') self.assertRaises(exception.ResourceFailure, scheduler.TaskRunner(execution.create)) expected_state = (execution.CREATE, execution.FAILED) self.assertEqual(expected_state, execution.state)