d0dd65e72f
Change-Id: I42f8664eaca5f025a87212d9455df15db7fce032
260 lines
9.2 KiB
Python
260 lines
9.2 KiB
Python
#
|
|
# 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 lifecycle_plugin_utils
|
|
from heat.engine import lifecycle_plugin
|
|
from heat.engine import resources
|
|
from heat.tests import common
|
|
|
|
|
|
empty_template = '''
|
|
heat_template_version: '2013-05-23'
|
|
description: Empty stack
|
|
resources:
|
|
'''
|
|
|
|
|
|
class LifecyclePluginUtilsTest(common.HeatTestCase):
|
|
"""Basic tests for :module:'heat.common.lifecycle_plugin_utils'.
|
|
|
|
Basic tests for the helper methods in
|
|
:module:'heat.common.lifecycle_plugin_utils'.
|
|
"""
|
|
|
|
def setUp(self):
|
|
super(LifecyclePluginUtilsTest, self).setUp()
|
|
|
|
def tearDown(self):
|
|
super(LifecyclePluginUtilsTest, self).tearDown()
|
|
lifecycle_plugin_utils.pp_class_instances = None
|
|
|
|
def mock_lcp_class_map(self, lcp_mappings):
|
|
self.m.UnsetStubs()
|
|
self.m.StubOutWithMock(resources.global_env(),
|
|
'get_stack_lifecycle_plugins')
|
|
resources.global_env().get_stack_lifecycle_plugins(
|
|
).MultipleTimes().AndReturn(lcp_mappings)
|
|
self.m.ReplayAll()
|
|
# reset cache
|
|
lifecycle_plugin_utils.pp_class_instances = None
|
|
|
|
def test_get_plug_point_class_instances(self):
|
|
"""Tests the get_plug_point_class_instances function."""
|
|
lcp_mappings = [('A::B::C1', TestLifecycleCallout1)]
|
|
self.mock_lcp_class_map(lcp_mappings)
|
|
|
|
pp_cinstances = lifecycle_plugin_utils.get_plug_point_class_instances()
|
|
self.assertIsNotNone(pp_cinstances)
|
|
self.assertTrue(self.is_iterable(pp_cinstances),
|
|
"not iterable: %s" % pp_cinstances)
|
|
self.assertTrue(len(pp_cinstances) == 1)
|
|
self.assertEqual(TestLifecycleCallout1, pp_cinstances[0].__class__)
|
|
|
|
def test_do_pre_and_post_callouts(self):
|
|
lcp_mappings = [('A::B::C1', TestLifecycleCallout1)]
|
|
self.mock_lcp_class_map(lcp_mappings)
|
|
mc = mock.Mock()
|
|
mc.__setattr__("pre_counter_for_unit_test", 0)
|
|
mc.__setattr__("post_counter_for_unit_test", 0)
|
|
ms = mock.Mock()
|
|
ms.__setattr__("action", 'A')
|
|
lifecycle_plugin_utils.do_pre_ops(mc, ms, None, None)
|
|
self.assertEqual(1, mc.pre_counter_for_unit_test)
|
|
lifecycle_plugin_utils.do_post_ops(mc, ms, None, None)
|
|
self.assertEqual(1, mc.post_counter_for_unit_test)
|
|
|
|
return
|
|
|
|
def test_class_instantiation_and_sorting(self):
|
|
lcp_mappings = []
|
|
self.mock_lcp_class_map(lcp_mappings)
|
|
pp_cis = lifecycle_plugin_utils.get_plug_point_class_instances()
|
|
self.assertEqual(0, len(pp_cis))
|
|
|
|
# order should change with sort
|
|
lcp_mappings = [('A::B::C2', TestLifecycleCallout2),
|
|
('A::B::C1', TestLifecycleCallout1)]
|
|
self.mock_lcp_class_map(lcp_mappings)
|
|
pp_cis = lifecycle_plugin_utils.get_plug_point_class_instances()
|
|
self.assertEqual(2, len(pp_cis))
|
|
self.assertEqual(100, pp_cis[0].get_ordinal())
|
|
self.assertEqual(101, pp_cis[1].get_ordinal())
|
|
self.assertEqual(TestLifecycleCallout1, pp_cis[0].__class__)
|
|
self.assertEqual(TestLifecycleCallout2, pp_cis[1].__class__)
|
|
|
|
# order should NOT change with sort
|
|
lcp_mappings = [('A::B::C1', TestLifecycleCallout1),
|
|
('A::B::C2', TestLifecycleCallout2)]
|
|
self.mock_lcp_class_map(lcp_mappings)
|
|
pp_cis = lifecycle_plugin_utils.get_plug_point_class_instances()
|
|
self.assertEqual(2, len(pp_cis))
|
|
self.assertEqual(100, pp_cis[0].get_ordinal())
|
|
self.assertEqual(101, pp_cis[1].get_ordinal())
|
|
self.assertEqual(TestLifecycleCallout1, pp_cis[0].__class__)
|
|
self.assertEqual(TestLifecycleCallout2, pp_cis[1].__class__)
|
|
|
|
# sort failure due to exception in thrown by ordinal
|
|
lcp_mappings = [('A::B::C2', TestLifecycleCallout2),
|
|
('A::B::C3', TestLifecycleCallout3),
|
|
('A::B::C1', TestLifecycleCallout1)]
|
|
self.mock_lcp_class_map(lcp_mappings)
|
|
pp_cis = lifecycle_plugin_utils.get_plug_point_class_instances()
|
|
self.assertEqual(3, len(pp_cis))
|
|
self.assertEqual(100, pp_cis[2].get_ordinal())
|
|
self.assertEqual(101, pp_cis[0].get_ordinal())
|
|
# (can sort fail partially? If so then this test may break)
|
|
self.assertEqual(TestLifecycleCallout2, pp_cis[0].__class__)
|
|
self.assertEqual(TestLifecycleCallout3, pp_cis[1].__class__)
|
|
self.assertEqual(TestLifecycleCallout1, pp_cis[2].__class__)
|
|
|
|
return
|
|
|
|
def test_do_pre_op_failure(self):
|
|
lcp_mappings = [('A::B::C5', TestLifecycleCallout1),
|
|
('A::B::C4', TestLifecycleCallout4)]
|
|
self.mock_lcp_class_map(lcp_mappings)
|
|
mc = mock.Mock()
|
|
mc.__setattr__("pre_counter_for_unit_test", 0)
|
|
mc.__setattr__("post_counter_for_unit_test", 0)
|
|
ms = mock.Mock()
|
|
ms.__setattr__("action", 'A')
|
|
failed = False
|
|
try:
|
|
lifecycle_plugin_utils.do_pre_ops(mc, ms, None, None)
|
|
except Exception:
|
|
failed = True
|
|
self.assertTrue(failed)
|
|
self.assertEqual(1, mc.pre_counter_for_unit_test)
|
|
self.assertEqual(1, mc.post_counter_for_unit_test)
|
|
|
|
return
|
|
|
|
def test_do_post_op_failure(self):
|
|
lcp_mappings = [('A::B::C1', TestLifecycleCallout1),
|
|
('A::B::C5', TestLifecycleCallout5)]
|
|
self.mock_lcp_class_map(lcp_mappings)
|
|
mc = mock.Mock()
|
|
mc.__setattr__("pre_counter_for_unit_test", 0)
|
|
mc.__setattr__("post_counter_for_unit_test", 0)
|
|
ms = mock.Mock()
|
|
ms.__setattr__("action", 'A')
|
|
lifecycle_plugin_utils.do_post_ops(mc, ms, None, None)
|
|
self.assertEqual(1, mc.post_counter_for_unit_test)
|
|
|
|
return
|
|
|
|
def test_exercise_base_lifecycle_plugin_class(self):
|
|
lcp = lifecycle_plugin.LifecyclePlugin()
|
|
ordinal = lcp.get_ordinal()
|
|
lcp.do_pre_op(None, None, None)
|
|
lcp.do_post_op(None, None, None)
|
|
self.assertEqual(100, ordinal)
|
|
|
|
return
|
|
|
|
def is_iterable(self, obj):
|
|
# special case string
|
|
if not object:
|
|
return False
|
|
if isinstance(obj, str):
|
|
return False
|
|
|
|
# Test for iterabilityy
|
|
try:
|
|
for m in obj:
|
|
break
|
|
except TypeError:
|
|
return False
|
|
return True
|
|
|
|
|
|
class TestLifecycleCallout1(lifecycle_plugin.LifecyclePlugin):
|
|
"""Sample test class for testing pre-op and post-op work on a stack."""
|
|
|
|
def do_pre_op(self, cnxt, stack, current_stack=None, action=None):
|
|
cnxt.pre_counter_for_unit_test += 1
|
|
|
|
def do_post_op(self, cnxt, stack, current_stack=None, action=None,
|
|
is_stack_failure=False):
|
|
cnxt.post_counter_for_unit_test += 1
|
|
|
|
def get_ordinal(self):
|
|
return 100
|
|
|
|
|
|
class TestLifecycleCallout2(lifecycle_plugin.LifecyclePlugin):
|
|
"""Sample test class for testing pre-op and post-op work on a stack.
|
|
|
|
Different ordinal and increment counters by 2.
|
|
"""
|
|
|
|
def do_pre_op(self, cnxt, stack, current_stack=None, action=None):
|
|
cnxt.pre_counter_for_unit_test += 2
|
|
|
|
def do_post_op(self, cnxt, stack, current_stack=None, action=None,
|
|
is_stack_failure=False):
|
|
cnxt.post_counter_for_unit_test += 2
|
|
|
|
def get_ordinal(self):
|
|
return 101
|
|
|
|
|
|
class TestLifecycleCallout3(lifecycle_plugin.LifecyclePlugin):
|
|
"""Sample test class for testing pre-op and post-op work on a stack.
|
|
|
|
Methods raise exceptions.
|
|
"""
|
|
def do_pre_op(self, cnxt, stack, current_stack=None, action=None):
|
|
raise Exception()
|
|
|
|
def do_post_op(self, cnxt, stack, current_stack=None, action=None,
|
|
is_stack_failure=False):
|
|
raise Exception()
|
|
|
|
def get_ordinal(self):
|
|
raise Exception()
|
|
|
|
|
|
class TestLifecycleCallout4(lifecycle_plugin.LifecyclePlugin):
|
|
"""Sample test class for testing pre-op and post-op work on a stack.
|
|
|
|
do_pre_op, do_post_op both throw exception.
|
|
"""
|
|
def do_pre_op(self, cnxt, stack, current_stack=None, action=None):
|
|
raise Exception()
|
|
|
|
def do_post_op(self, cnxt, stack, current_stack=None, action=None,
|
|
is_stack_failure=False):
|
|
raise Exception()
|
|
|
|
def get_ordinal(self):
|
|
return 103
|
|
|
|
|
|
class TestLifecycleCallout5(lifecycle_plugin.LifecyclePlugin):
|
|
"""Sample test class for testing pre-op and post-op work on a stack.
|
|
|
|
do_post_op throws exception.
|
|
"""
|
|
def do_pre_op(self, cnxt, stack, current_stack=None, action=None):
|
|
cnxt.pre_counter_for_unit_test += 1
|
|
|
|
def do_post_op(self, cnxt, stack, current_stack=None, action=None,
|
|
is_stack_failure=False):
|
|
raise Exception()
|
|
|
|
def get_ordinal(self):
|
|
return 100
|