Convert parser tests that need nested stacks to unit tests
Part of blueprint decouple-nested Change-Id: Id64d88104ac11601beac95cf5792f814cad388c8
This commit is contained in:
@@ -27,7 +27,6 @@ from heat.common import context
|
|||||||
from heat.common import exception
|
from heat.common import exception
|
||||||
from heat.common import heat_keystoneclient as hkc
|
from heat.common import heat_keystoneclient as hkc
|
||||||
from heat.common import template_format
|
from heat.common import template_format
|
||||||
from heat.common import urlfetch
|
|
||||||
import heat.db.api as db_api
|
import heat.db.api as db_api
|
||||||
from heat.engine.cfn import functions as cfn_funcs
|
from heat.engine.cfn import functions as cfn_funcs
|
||||||
from heat.engine.cfn import template as cfn_t
|
from heat.engine.cfn import template as cfn_t
|
||||||
@@ -1047,75 +1046,71 @@ class StackTest(common.HeatTestCase):
|
|||||||
status_reason='blarg')
|
status_reason='blarg')
|
||||||
self.assertEqual(1, stack.total_resources())
|
self.assertEqual(1, stack.total_resources())
|
||||||
|
|
||||||
def _setup_nested(self, name):
|
|
||||||
nested_tpl = ('{"HeatTemplateFormatVersion" : "2012-12-12",'
|
|
||||||
'"Resources":{'
|
|
||||||
'"A": {"Type": "GenericResourceType"},'
|
|
||||||
'"B": {"Type": "GenericResourceType"}}}')
|
|
||||||
tpl = {'HeatTemplateFormatVersion': "2012-12-12",
|
|
||||||
'Resources':
|
|
||||||
{'A': {'Type': 'AWS::CloudFormation::Stack',
|
|
||||||
'Properties':
|
|
||||||
{'TemplateURL': 'http://server.test/nested.json'}},
|
|
||||||
'B': {'Type': 'GenericResourceType'}}}
|
|
||||||
self.m.StubOutWithMock(urlfetch, 'get')
|
|
||||||
urlfetch.get('http://server.test/nested.json').AndReturn(nested_tpl)
|
|
||||||
self.m.ReplayAll()
|
|
||||||
self.stack = parser.Stack(self.ctx, 'test_stack', parser.Template(tpl),
|
|
||||||
status_reason=name)
|
|
||||||
self.stack.store()
|
|
||||||
self.stack.create()
|
|
||||||
|
|
||||||
def test_total_resources_nested(self):
|
def test_total_resources_nested(self):
|
||||||
self._setup_nested('zyzzyx')
|
tpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
||||||
self.assertEqual(4, self.stack.total_resources())
|
'Resources':
|
||||||
self.assertIsNotNone(self.stack['A'].nested())
|
{'A': {'Type': 'GenericResourceType'}}}
|
||||||
self.assertEqual(
|
stack = parser.Stack(self.ctx, 'test_stack', parser.Template(tpl),
|
||||||
2, self.stack['A'].nested().total_resources())
|
status_reason='blarg')
|
||||||
self.assertEqual(
|
|
||||||
4,
|
stack['A'].nested = mock.Mock()
|
||||||
self.stack['A'].nested().root_stack.total_resources())
|
stack['A'].nested.return_value.total_resources.return_value = 3
|
||||||
|
self.assertEqual(4, stack.total_resources())
|
||||||
|
|
||||||
def test_iter_resources(self):
|
def test_iter_resources(self):
|
||||||
self._setup_nested('iter_resources')
|
tpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
||||||
nested_stack = self.stack['A'].nested()
|
'Resources':
|
||||||
resource_generator = self.stack.iter_resources()
|
{'A': {'Type': 'GenericResourceType'},
|
||||||
|
'B': {'Type': 'GenericResourceType'}}}
|
||||||
|
stack = parser.Stack(self.ctx, 'test_stack', parser.Template(tpl),
|
||||||
|
status_reason='blarg')
|
||||||
|
|
||||||
|
def get_more(nested_depth=0):
|
||||||
|
yield 'X'
|
||||||
|
yield 'Y'
|
||||||
|
yield 'Z'
|
||||||
|
|
||||||
|
stack['A'].nested = mock.MagicMock()
|
||||||
|
stack['A'].nested.return_value.iter_resources.side_effect = get_more
|
||||||
|
|
||||||
|
resource_generator = stack.iter_resources()
|
||||||
self.assertIsNot(resource_generator, list)
|
self.assertIsNot(resource_generator, list)
|
||||||
|
|
||||||
first_level_resources = list(resource_generator)
|
first_level_resources = list(resource_generator)
|
||||||
self.assertEqual(2, len(first_level_resources))
|
self.assertEqual(2, len(first_level_resources))
|
||||||
self.assertIn(self.stack['A'], first_level_resources)
|
all_resources = list(stack.iter_resources(1))
|
||||||
self.assertIn(self.stack['B'], first_level_resources)
|
self.assertEqual(5, len(all_resources))
|
||||||
|
|
||||||
all_resources = list(self.stack.iter_resources(1))
|
def test_root_stack_no_parent(self):
|
||||||
self.assertIn(self.stack['A'], first_level_resources)
|
tpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
||||||
self.assertIn(self.stack['B'], first_level_resources)
|
'Resources':
|
||||||
self.assertIn(nested_stack['A'], all_resources)
|
{'A': {'Type': 'GenericResourceType'}}}
|
||||||
self.assertIn(nested_stack['B'], all_resources)
|
stack = parser.Stack(self.ctx, 'test_stack', parser.Template(tpl),
|
||||||
|
status_reason='blarg')
|
||||||
|
|
||||||
def test_root_stack(self):
|
self.assertEqual(stack, stack.root_stack)
|
||||||
self._setup_nested('toor')
|
|
||||||
self.assertEqual(self.stack, self.stack.root_stack)
|
|
||||||
self.assertIsNotNone(self.stack['A'].nested())
|
|
||||||
self.assertEqual(
|
|
||||||
self.stack, self.stack['A'].nested().root_stack)
|
|
||||||
|
|
||||||
def test_nested_stack_abandon(self):
|
def test_root_stack_parent_no_stack(self):
|
||||||
self._setup_nested('nestedstack')
|
tpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
||||||
ret = self.stack.prepare_abandon()
|
'Resources':
|
||||||
self.assertIsNotNone(self.stack['A'].nested())
|
{'A': {'Type': 'GenericResourceType'}}}
|
||||||
self.assertEqual(
|
stack = parser.Stack(self.ctx, 'test_stack', parser.Template(tpl),
|
||||||
self.stack, self.stack['A'].nested().root_stack)
|
status_reason='blarg')
|
||||||
|
|
||||||
keys = ['name', 'id', 'action', 'status', 'template', 'resources',
|
stack.parent_resource = mock.Mock()
|
||||||
'project_id', 'stack_user_project_id', 'environment']
|
stack.parent_resource.stack = None
|
||||||
|
self.assertEqual(stack, stack.root_stack)
|
||||||
|
|
||||||
self.assertEqual(len(keys), len(ret))
|
def test_root_stack_with_parent(self):
|
||||||
nested_stack_data = ret['resources']['A']
|
tpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
||||||
self.assertEqual(len(keys), len(nested_stack_data))
|
'Resources':
|
||||||
for key in keys:
|
{'A': {'Type': 'GenericResourceType'}}}
|
||||||
self.assertIn(key, ret)
|
stack = parser.Stack(self.ctx, 'test_stack', parser.Template(tpl),
|
||||||
self.assertIn(key, nested_stack_data)
|
status_reason='blarg')
|
||||||
|
|
||||||
|
stack.parent_resource = mock.Mock()
|
||||||
|
stack.parent_resource.stack.root_stack = 'test value'
|
||||||
|
self.assertEqual('test value', stack.root_stack)
|
||||||
|
|
||||||
def test_load_parent_resource(self):
|
def test_load_parent_resource(self):
|
||||||
self.stack = parser.Stack(self.ctx, 'load_parent_resource',
|
self.stack = parser.Stack(self.ctx, 'load_parent_resource',
|
||||||
@@ -1851,12 +1846,17 @@ class StackTest(common.HeatTestCase):
|
|||||||
self.m.VerifyAll()
|
self.m.VerifyAll()
|
||||||
|
|
||||||
def _get_stack_to_check(self, name):
|
def _get_stack_to_check(self, name):
|
||||||
|
tpl = {"HeatTemplateFormatVersion": "2012-12-12",
|
||||||
|
"Resources": {
|
||||||
|
"A": {"Type": "GenericResourceType"},
|
||||||
|
"B": {"Type": "GenericResourceType"}}}
|
||||||
|
self.stack = parser.Stack(self.ctx, name, parser.Template(tpl),
|
||||||
|
status_reason=name)
|
||||||
|
self.stack.store()
|
||||||
|
|
||||||
def _mock_check(res):
|
def _mock_check(res):
|
||||||
res.handle_check = mock.Mock()
|
res.handle_check = mock.Mock()
|
||||||
if hasattr(res, 'nested'):
|
|
||||||
[_mock_check(r) for r in res.nested().resources.values()]
|
|
||||||
|
|
||||||
self._setup_nested(name)
|
|
||||||
[_mock_check(res) for res in self.stack.resources.values()]
|
[_mock_check(res) for res in self.stack.resources.values()]
|
||||||
return self.stack
|
return self.stack
|
||||||
|
|
||||||
@@ -1870,18 +1870,6 @@ class StackTest(common.HeatTestCase):
|
|||||||
for res in stack.resources.values()]
|
for res in stack.resources.values()]
|
||||||
self.assertNotIn('not fully supported', stack.status_reason)
|
self.assertNotIn('not fully supported', stack.status_reason)
|
||||||
|
|
||||||
def test_check_nested_stack(self):
|
|
||||||
def _mock_check(res):
|
|
||||||
res.handle_check = mock.Mock()
|
|
||||||
|
|
||||||
self._setup_nested('check-nested-stack')
|
|
||||||
nested = self.stack['A'].nested()
|
|
||||||
[_mock_check(res) for res in nested.resources.values()]
|
|
||||||
self.stack.check()
|
|
||||||
|
|
||||||
[self.assertTrue(res.handle_check.called)
|
|
||||||
for res in nested.resources.values()]
|
|
||||||
|
|
||||||
def test_check_not_supported(self):
|
def test_check_not_supported(self):
|
||||||
stack = self._get_stack_to_check('check-not-supported')
|
stack = self._get_stack_to_check('check-not-supported')
|
||||||
del stack['B'].handle_check
|
del stack['B'].handle_check
|
||||||
|
|||||||
@@ -189,6 +189,14 @@ class StackResourceTest(common.HeatTestCase):
|
|||||||
preview = self.parent_resource.preview()
|
preview = self.parent_resource.preview()
|
||||||
self.assertIsInstance(preview, stack_resource.StackResource)
|
self.assertIsInstance(preview, stack_resource.StackResource)
|
||||||
|
|
||||||
|
def test_nested_stack_abandon(self):
|
||||||
|
nest = mock.MagicMock()
|
||||||
|
self.parent_resource.nested = nest
|
||||||
|
nest.return_value.prepare_abandon.return_value = {'X': 'Y'}
|
||||||
|
ret = self.parent_resource.prepare_abandon()
|
||||||
|
nest.return_value.prepare_abandon.assert_called_once_with()
|
||||||
|
self.assertEqual({'X': 'Y'}, ret)
|
||||||
|
|
||||||
def test_implementation_signature(self):
|
def test_implementation_signature(self):
|
||||||
self.parent_resource.child_template = mock.Mock(
|
self.parent_resource.child_template = mock.Mock(
|
||||||
return_value=self.simple_template)
|
return_value=self.simple_template)
|
||||||
|
|||||||
@@ -420,3 +420,56 @@ Outputs:
|
|||||||
self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
|
self.assert_resource_is_a_stack(stack_identifier, 'the_nested')
|
||||||
stack = self.client.stacks.get(stack_identifier)
|
stack = self.client.stacks.get(stack_identifier)
|
||||||
self.assertEqual('goopie', self._stack_output(stack, 'value'))
|
self.assertEqual('goopie', self._stack_output(stack, 'value'))
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateResourceCheckTest(test.HeatIntegrationTest):
|
||||||
|
"""Prove that we can do template resource check."""
|
||||||
|
|
||||||
|
main_template = '''
|
||||||
|
HeatTemplateFormatVersion: '2012-12-12'
|
||||||
|
Resources:
|
||||||
|
the_nested:
|
||||||
|
Type: the.yaml
|
||||||
|
Properties:
|
||||||
|
one: my_name
|
||||||
|
Outputs:
|
||||||
|
identifier:
|
||||||
|
Value: {Ref: the_nested}
|
||||||
|
value:
|
||||||
|
Value: {'Fn::GetAtt': [the_nested, the_str]}
|
||||||
|
'''
|
||||||
|
|
||||||
|
nested_templ = '''
|
||||||
|
HeatTemplateFormatVersion: '2012-12-12'
|
||||||
|
Parameters:
|
||||||
|
one:
|
||||||
|
Default: foo
|
||||||
|
Type: String
|
||||||
|
Resources:
|
||||||
|
RealRandom:
|
||||||
|
Type: OS::Heat::RandomString
|
||||||
|
Properties:
|
||||||
|
salt: {Ref: one}
|
||||||
|
Outputs:
|
||||||
|
the_str:
|
||||||
|
Value: {'Fn::GetAtt': [RealRandom, value]}
|
||||||
|
'''
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TemplateResourceCheckTest, self).setUp()
|
||||||
|
self.client = self.orchestration_client
|
||||||
|
|
||||||
|
def test_check(self):
|
||||||
|
stack_name = self._stack_rand_name()
|
||||||
|
self.client.stacks.create(
|
||||||
|
stack_name=stack_name,
|
||||||
|
template=self.main_template,
|
||||||
|
files={'the.yaml': self.nested_templ},
|
||||||
|
disable_rollback=True,
|
||||||
|
)
|
||||||
|
stack = self.client.stacks.get(stack_name)
|
||||||
|
stack_identifier = '%s/%s' % (stack_name, stack.id)
|
||||||
|
self._wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
|
||||||
|
|
||||||
|
self.client.actions.check(stack_id=stack_identifier)
|
||||||
|
self._wait_for_stack_status(stack_identifier, 'CHECK_COMPLETE')
|
||||||
|
|||||||
Reference in New Issue
Block a user