Correct list_join function
Heat supports 'list_join' function to join one or more lists of strings in Liberty release. But when we resolve the function, we pop some arguments, this introduced errors if resolve the snippet again when updating a resource. This patch correct the behavior of 'list_join' function, also refactor some codes for the functions of Kilo/Liberty. Change-Id: Ia67a0171261ca1a864fe11f7d61c3bf5ef801040 Closes-Bug: #1513060
This commit is contained in:
parent
ba532e6530
commit
db11ae6d42
|
@ -303,7 +303,7 @@ class Join(function.Function):
|
|||
fmt_data = {'fn_name': self.fn_name,
|
||||
'example': example}
|
||||
|
||||
if isinstance(self.args, (six.string_types, collections.Mapping)):
|
||||
if not isinstance(self.args, list):
|
||||
raise TypeError(_('Incorrect arguments to "%(fn_name)s" '
|
||||
'should be: %(example)s') % fmt_data)
|
||||
|
||||
|
@ -331,7 +331,8 @@ class Join(function.Function):
|
|||
return ''
|
||||
if not isinstance(s, six.string_types):
|
||||
raise TypeError(
|
||||
_('Items to join must be strings %s') % (repr(s)[:200]))
|
||||
_('Items to join must be strings not %s'
|
||||
) % (repr(s)[:200]))
|
||||
return s
|
||||
|
||||
return delim.join(ensure_string(s) for s in strings)
|
||||
|
|
|
@ -357,7 +357,7 @@ class Join(cfn_funcs.Join):
|
|||
|
||||
|
||||
class JoinMultiple(function.Function):
|
||||
"""A function for joining strings.
|
||||
"""A function for joining one or more lists of strings.
|
||||
|
||||
Takes the form::
|
||||
|
||||
|
@ -376,31 +376,31 @@ class JoinMultiple(function.Function):
|
|||
fmt_data = {'fn_name': fn_name,
|
||||
'example': example}
|
||||
|
||||
if isinstance(args, (six.string_types, collections.Mapping)):
|
||||
if not isinstance(args, list):
|
||||
raise TypeError(_('Incorrect arguments to "%(fn_name)s" '
|
||||
'should be: %(example)s') % fmt_data)
|
||||
|
||||
try:
|
||||
self._delim = args.pop(0)
|
||||
self._joinlist = args.pop(0)
|
||||
except IndexError:
|
||||
self._delim = args[0]
|
||||
self._joinlists = args[1:]
|
||||
if len(self._joinlists) < 1:
|
||||
raise ValueError
|
||||
except (IndexError, ValueError):
|
||||
raise ValueError(_('Incorrect arguments to "%(fn_name)s" '
|
||||
'should be: %(example)s') % fmt_data)
|
||||
# Optionally allow additional lists, which are appended
|
||||
for l in args:
|
||||
try:
|
||||
self._joinlist += l
|
||||
except (AttributeError, TypeError):
|
||||
raise TypeError(_('Incorrect arguments to "%(fn_name)s" '
|
||||
'should be: %(example)s') % fmt_data)
|
||||
|
||||
def result(self):
|
||||
strings = function.resolve(self._joinlist)
|
||||
if strings is None:
|
||||
strings = []
|
||||
if (isinstance(strings, six.string_types) or
|
||||
not isinstance(strings, collections.Sequence)):
|
||||
raise TypeError(_('"%s" must operate on a list') % self.fn_name)
|
||||
r_joinlists = function.resolve(self._joinlists)
|
||||
|
||||
strings = []
|
||||
for jl in r_joinlists:
|
||||
if jl:
|
||||
if (isinstance(jl, six.string_types) or
|
||||
not isinstance(jl, collections.Sequence)):
|
||||
raise TypeError(_('"%s" must operate on '
|
||||
'a list') % self.fn_name)
|
||||
|
||||
strings += jl
|
||||
|
||||
delim = function.resolve(self._delim)
|
||||
if not isinstance(delim, six.string_types):
|
||||
|
@ -421,9 +421,7 @@ class JoinMultiple(function.Function):
|
|||
msg = _('Items to join must be string, map or list. '
|
||||
'%s failed json serialization'
|
||||
) % (repr(s)[:200])
|
||||
else:
|
||||
msg = _('Items to join must be string, map or list not %s'
|
||||
) % (repr(s)[:200])
|
||||
|
||||
raise TypeError(msg)
|
||||
|
||||
return delim.join(ensure_string(s) for s in strings)
|
||||
|
|
|
@ -496,6 +496,17 @@ class HOTemplateTest(common.HeatTestCase):
|
|||
stack = parser.Stack(utils.dummy_context(), 'test_stack', tmpl)
|
||||
snippet = {'list_join': ["\n", {'get_attr': ['rg', 'name']}]}
|
||||
self.assertEqual('', self.resolve(snippet, tmpl, stack))
|
||||
# test list_join for liberty template
|
||||
hot_tpl['heat_template_version'] = '2015-10-15'
|
||||
tmpl = template.Template(hot_tpl)
|
||||
stack = parser.Stack(utils.dummy_context(), 'test_stack', tmpl)
|
||||
snippet = {'list_join': ["\n", {'get_attr': ['rg', 'name']}]}
|
||||
self.assertEqual('', self.resolve(snippet, tmpl, stack))
|
||||
# test list join again and update to multiple lists
|
||||
snippet = {'list_join': ["\n",
|
||||
{'get_attr': ['rg', 'name']},
|
||||
{'get_attr': ['rg', 'name']}]}
|
||||
self.assertEqual('', self.resolve(snippet, tmpl, stack))
|
||||
|
||||
def test_str_replace(self):
|
||||
"""Test str_replace function."""
|
||||
|
@ -669,25 +680,41 @@ class HOTemplateTest(common.HeatTestCase):
|
|||
tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
self.assertEqual(snippet_resolved, self.resolve(snippet, tmpl))
|
||||
|
||||
def test_list_join_empty_list(self):
|
||||
snippet = {'list_join': [',', []]}
|
||||
snippet_resolved = ''
|
||||
k_tmpl = template.Template(hot_kilo_tpl_empty)
|
||||
self.assertEqual(snippet_resolved, self.resolve(snippet, k_tmpl))
|
||||
l_tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
self.assertEqual(snippet_resolved, self.resolve(snippet, l_tmpl))
|
||||
|
||||
def test_join_json(self):
|
||||
snippet = {'list_join': [',', [{'foo': 'json'}, {'foo2': 'json2'}]]}
|
||||
snippet_resolved = '{"foo": "json"},{"foo2": "json2"}'
|
||||
tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
self.assertEqual(snippet_resolved, self.resolve(snippet, tmpl))
|
||||
l_tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
self.assertEqual(snippet_resolved, self.resolve(snippet, l_tmpl))
|
||||
# old versions before liberty don't support to join json
|
||||
k_tmpl = template.Template(hot_kilo_tpl_empty)
|
||||
exc = self.assertRaises(TypeError, self.resolve, snippet, k_tmpl)
|
||||
self.assertEqual("Items to join must be strings not {'foo': 'json'}",
|
||||
six.text_type(exc))
|
||||
|
||||
def test_join_type_fail(self):
|
||||
def test_join_object_type_fail(self):
|
||||
not_serializable = object
|
||||
snippet = {'list_join': [',', [not_serializable]]}
|
||||
tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
exc = self.assertRaises(TypeError, self.resolve, snippet, tmpl)
|
||||
l_tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
exc = self.assertRaises(TypeError, self.resolve, snippet, l_tmpl)
|
||||
self.assertIn('Items to join must be string, map or list not',
|
||||
six.text_type(exc))
|
||||
k_tmpl = template.Template(hot_kilo_tpl_empty)
|
||||
exc = self.assertRaises(TypeError, self.resolve, snippet, k_tmpl)
|
||||
self.assertIn("Items to join must be strings", six.text_type(exc))
|
||||
|
||||
def test_join_json_fail(self):
|
||||
not_serializable = object
|
||||
snippet = {'list_join': [',', [{'foo': not_serializable}]]}
|
||||
tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
exc = self.assertRaises(TypeError, self.resolve, snippet, tmpl)
|
||||
l_tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
exc = self.assertRaises(TypeError, self.resolve, snippet, l_tmpl)
|
||||
self.assertIn('Items to join must be string, map or list',
|
||||
six.text_type(exc))
|
||||
self.assertIn("failed json serialization",
|
||||
|
@ -695,22 +722,39 @@ class HOTemplateTest(common.HeatTestCase):
|
|||
|
||||
def test_join_invalid(self):
|
||||
snippet = {'list_join': 'bad'}
|
||||
tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
exc = self.assertRaises(TypeError, self.resolve, snippet, tmpl)
|
||||
l_tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
exc = self.assertRaises(TypeError, self.resolve, snippet, l_tmpl)
|
||||
self.assertIn('Incorrect arguments', six.text_type(exc))
|
||||
|
||||
k_tmpl = template.Template(hot_kilo_tpl_empty)
|
||||
exc1 = self.assertRaises(TypeError, self.resolve, snippet, k_tmpl)
|
||||
self.assertIn('Incorrect arguments', six.text_type(exc1))
|
||||
|
||||
def test_join_int_invalid(self):
|
||||
snippet = {'list_join': 5}
|
||||
l_tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
exc = self.assertRaises(TypeError, self.resolve, snippet, l_tmpl)
|
||||
self.assertIn('Incorrect arguments', six.text_type(exc))
|
||||
|
||||
k_tmpl = template.Template(hot_kilo_tpl_empty)
|
||||
exc1 = self.assertRaises(TypeError, self.resolve, snippet, k_tmpl)
|
||||
self.assertIn('Incorrect arguments', six.text_type(exc1))
|
||||
|
||||
def test_join_invalid_value(self):
|
||||
snippet = {'list_join': [',']}
|
||||
tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
|
||||
exc = self.assertRaises(ValueError, self.resolve, snippet, tmpl)
|
||||
l_tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
exc = self.assertRaises(ValueError, self.resolve, snippet, l_tmpl)
|
||||
self.assertIn('Incorrect arguments', six.text_type(exc))
|
||||
|
||||
k_tmpl = template.Template(hot_kilo_tpl_empty)
|
||||
exc1 = self.assertRaises(ValueError, self.resolve, snippet, k_tmpl)
|
||||
self.assertIn('Incorrect arguments', six.text_type(exc1))
|
||||
|
||||
def test_join_invalid_multiple(self):
|
||||
snippet = {'list_join': [',', 'bad', ['foo']]}
|
||||
tmpl = template.Template(hot_liberty_tpl_empty)
|
||||
exc = self.assertRaises(TypeError, self.resolve, snippet, tmpl)
|
||||
self.assertIn('Incorrect arguments', six.text_type(exc))
|
||||
self.assertIn('must operate on a list', six.text_type(exc))
|
||||
|
||||
def test_merge(self):
|
||||
snippet = {'map_merge': [{'f1': 'b1', 'f2': 'b2'}, {'f1': 'b2'}]}
|
||||
|
|
Loading…
Reference in New Issue