Refactor boolean condition functions
Change-Id: I0c524b058df0266c48ade5f7c477762fa3d7483a
This commit is contained in:
parent
8262265292
commit
4090dfe926
|
@ -426,27 +426,16 @@ class Not(hot_funcs.Not):
|
|||
returns false for a condition that evaluates to true.
|
||||
"""
|
||||
|
||||
def _get_condition(self):
|
||||
try:
|
||||
if (not self.args or
|
||||
not isinstance(self.args, collections.Sequence) or
|
||||
isinstance(self.args, six.string_types)):
|
||||
raise ValueError()
|
||||
if len(self.args) != 1:
|
||||
raise ValueError()
|
||||
return self.args[0]
|
||||
except ValueError:
|
||||
msg = _('Arguments to "%s" must be of the form: '
|
||||
'[condition]')
|
||||
raise ValueError(msg % self.fn_name)
|
||||
|
||||
def result(self):
|
||||
resolved_value = function.resolve(self.condition)
|
||||
if not isinstance(resolved_value, bool):
|
||||
msg = _('The condition value should be boolean, '
|
||||
'after resolved the value is: %s')
|
||||
raise ValueError(msg % resolved_value)
|
||||
return not resolved_value
|
||||
def _check_args(self):
|
||||
msg = _('Arguments to "%s" must be of the form: '
|
||||
'[condition]') % self.fn_name
|
||||
if (not self.args or
|
||||
not isinstance(self.args, collections.Sequence) or
|
||||
isinstance(self.args, six.string_types)):
|
||||
raise ValueError(msg)
|
||||
if len(self.args) != 1:
|
||||
raise ValueError(msg)
|
||||
self.condition = self.args[0]
|
||||
|
||||
|
||||
class And(hot_funcs.And):
|
||||
|
|
|
@ -1162,7 +1162,31 @@ class If(function.Macro):
|
|||
return self.template.conditions(self.stack).is_enabled(cd_name)
|
||||
|
||||
|
||||
class Not(function.Function):
|
||||
class ConditionBoolean(function.Function):
|
||||
"""Abstract parent class of boolean condition functions."""
|
||||
|
||||
def __init__(self, stack, fn_name, args):
|
||||
super(ConditionBoolean, self).__init__(stack, fn_name, args)
|
||||
self._check_args()
|
||||
|
||||
def _check_args(self):
|
||||
if not (isinstance(self.args, collections.Sequence) and
|
||||
not isinstance(self.args, six.string_types)):
|
||||
msg = _('Arguments to "%s" must be a list of conditions')
|
||||
raise ValueError(msg % self.fn_name)
|
||||
if not self.args or len(self.args) < 2:
|
||||
msg = _('The minimum number of condition arguments to "%s" is 2.')
|
||||
raise ValueError(msg % self.fn_name)
|
||||
|
||||
def _get_condition(self, arg):
|
||||
if isinstance(arg, bool):
|
||||
return arg
|
||||
|
||||
msg = _('The condition value must be a boolean: %s')
|
||||
raise ValueError(msg % arg)
|
||||
|
||||
|
||||
class Not(ConditionBoolean):
|
||||
"""A function that acts as a NOT operator on a condition.
|
||||
|
||||
Takes the form::
|
||||
|
@ -1173,30 +1197,18 @@ class Not(function.Function):
|
|||
returns false for a condition that evaluates to true.
|
||||
"""
|
||||
|
||||
def __init__(self, stack, fn_name, args):
|
||||
super(Not, self).__init__(stack, fn_name, args)
|
||||
self.condition = self._get_condition()
|
||||
|
||||
def _get_condition(self):
|
||||
try:
|
||||
if not self.args:
|
||||
raise ValueError()
|
||||
return self.args
|
||||
except ValueError:
|
||||
msg = _('Arguments to "%s" must be of the form: '
|
||||
'condition')
|
||||
def _check_args(self):
|
||||
self.condition = self.args
|
||||
if self.args is None:
|
||||
msg = _('Argument to "%s" must be a condition')
|
||||
raise ValueError(msg % self.fn_name)
|
||||
|
||||
def result(self):
|
||||
resolved_value = function.resolve(self.condition)
|
||||
if not isinstance(resolved_value, bool):
|
||||
msg = _('The condition value should be boolean, '
|
||||
'after resolved the value is: %s')
|
||||
raise ValueError(msg % resolved_value)
|
||||
return not resolved_value
|
||||
cd = function.resolve(self.condition)
|
||||
return not self._get_condition(cd)
|
||||
|
||||
|
||||
class And(function.Function):
|
||||
class And(ConditionBoolean):
|
||||
"""A function that acts as an AND operator on conditions.
|
||||
|
||||
Takes the form::
|
||||
|
@ -1211,31 +1223,12 @@ class And(function.Function):
|
|||
of conditions that you can include is 2.
|
||||
"""
|
||||
|
||||
def __init__(self, stack, fn_name, args):
|
||||
super(And, self).__init__(stack, fn_name, args)
|
||||
if (not self.args or
|
||||
not (isinstance(self.args, collections.Sequence) and
|
||||
not isinstance(self.args, six.string_types)) or
|
||||
len(self.args) < 2):
|
||||
msg = _('Arguments to "%s" must be of the form: '
|
||||
'[{condition_1}, {condition_2}, {...}, {condition_n}], '
|
||||
'the minimum number of conditions is 2.')
|
||||
raise ValueError(msg % self.fn_name)
|
||||
|
||||
def result(self):
|
||||
for cd in self.args:
|
||||
resolved_value = function.resolve(cd)
|
||||
if not isinstance(resolved_value, bool):
|
||||
msg = _('The condition value should be boolean, '
|
||||
'after resolved the value is: %s')
|
||||
raise ValueError(msg % resolved_value)
|
||||
if not resolved_value:
|
||||
return False
|
||||
|
||||
return True
|
||||
return all(self._get_condition(cd)
|
||||
for cd in function.resolve(self.args))
|
||||
|
||||
|
||||
class Or(function.Function):
|
||||
class Or(ConditionBoolean):
|
||||
"""A function that acts as an OR operator on conditions.
|
||||
|
||||
Takes the form::
|
||||
|
@ -1250,25 +1243,6 @@ class Or(function.Function):
|
|||
number of conditions that you can include is 2.
|
||||
"""
|
||||
|
||||
def __init__(self, stack, fn_name, args):
|
||||
super(Or, self).__init__(stack, fn_name, args)
|
||||
if (not self.args or
|
||||
not (isinstance(self.args, collections.Sequence) and
|
||||
not isinstance(self.args, six.string_types)) or
|
||||
len(self.args) < 2):
|
||||
msg = _('Arguments to "%s" must be of the form: '
|
||||
'[{condition_1}, {condition_2}, {...}, {condition_n}], '
|
||||
'the minimum number of conditions is 2.')
|
||||
raise ValueError(msg % self.fn_name)
|
||||
|
||||
def result(self):
|
||||
for cd in self.args:
|
||||
resolved_value = function.resolve(cd)
|
||||
if not isinstance(resolved_value, bool):
|
||||
msg = _('The condition value should be boolean, '
|
||||
'after resolved the value is: %s')
|
||||
raise ValueError(msg % resolved_value)
|
||||
if resolved_value:
|
||||
return True
|
||||
|
||||
return False
|
||||
return any(self._get_condition(cd)
|
||||
for cd in function.resolve(self.args))
|
||||
|
|
|
@ -962,22 +962,20 @@ class TemplateTest(common.HeatTestCase):
|
|||
exc = self.assertRaises(ValueError,
|
||||
self.resolve_condition, snippet, tmpl)
|
||||
|
||||
error_msg = ('The condition value should be boolean, '
|
||||
'after resolved the value is: invalid_arg')
|
||||
error_msg = ('The condition value must be a boolean: '
|
||||
'invalid_arg')
|
||||
self.assertIn(error_msg, six.text_type(exc))
|
||||
# test invalid type
|
||||
snippet = {'Fn::Not': 'invalid'}
|
||||
exc = self.assertRaises(exception.StackValidationFailed,
|
||||
self.resolve_condition, snippet, tmpl)
|
||||
error_msg = ('.Fn::Not: Arguments to "Fn::Not" must be '
|
||||
'of the form: [condition]')
|
||||
error_msg = 'Arguments to "Fn::Not" must be '
|
||||
self.assertIn(error_msg, six.text_type(exc))
|
||||
|
||||
snippet = {'Fn::Not': ['cd1', 'cd2']}
|
||||
exc = self.assertRaises(exception.StackValidationFailed,
|
||||
self.resolve_condition, snippet, tmpl)
|
||||
error_msg = ('.Fn::Not: Arguments to "Fn::Not" must be '
|
||||
'of the form: [condition]')
|
||||
error_msg = 'Arguments to "Fn::Not" must be '
|
||||
self.assertIn(error_msg, six.text_type(exc))
|
||||
|
||||
def test_and(self):
|
||||
|
@ -1024,27 +1022,25 @@ class TemplateTest(common.HeatTestCase):
|
|||
def test_and_invalid_args(self):
|
||||
tmpl = template.Template(aws_empty_template)
|
||||
|
||||
error_msg = ('The minimum number of condition arguments to "Fn::And" '
|
||||
'is 2.')
|
||||
snippet = {'Fn::And': ['invalid_arg']}
|
||||
exc = self.assertRaises(exception.StackValidationFailed,
|
||||
self.resolve_condition, snippet, tmpl)
|
||||
|
||||
error_msg = ('.Fn::And: Arguments to "Fn::And" must be '
|
||||
'of the form: [{condition_1}, {condition_2}, {...}, '
|
||||
'{condition_n}]')
|
||||
|
||||
self.assertIn(error_msg, six.text_type(exc))
|
||||
|
||||
error_msg = 'Arguments to "Fn::And" must be'
|
||||
# test invalid type
|
||||
snippet = {'Fn::And': 'invalid'}
|
||||
exc = self.assertRaises(exception.StackValidationFailed,
|
||||
self.resolve_condition, snippet, tmpl)
|
||||
|
||||
self.assertIn(error_msg, six.text_type(exc))
|
||||
|
||||
snippet = {'Fn::And': ['cd1', True]}
|
||||
exc = self.assertRaises(ValueError,
|
||||
self.resolve_condition, snippet, tmpl)
|
||||
error_msg = ('The condition value should be boolean, '
|
||||
'after resolved the value is: cd1')
|
||||
error_msg = ('The condition value must be a boolean: '
|
||||
'cd1')
|
||||
self.assertIn(error_msg, six.text_type(exc))
|
||||
|
||||
def test_or(self):
|
||||
|
@ -1087,27 +1083,25 @@ class TemplateTest(common.HeatTestCase):
|
|||
def test_or_invalid_args(self):
|
||||
tmpl = template.Template(aws_empty_template)
|
||||
|
||||
error_msg = ('The minimum number of condition arguments to "Fn::Or" '
|
||||
'is 2.')
|
||||
snippet = {'Fn::Or': ['invalid_arg']}
|
||||
exc = self.assertRaises(exception.StackValidationFailed,
|
||||
self.resolve_condition, snippet, tmpl)
|
||||
|
||||
error_msg = ('.Fn::Or: Arguments to "Fn::Or" must be '
|
||||
'of the form: [{condition_1}, {condition_2}, {...}, '
|
||||
'{condition_n}]')
|
||||
|
||||
self.assertIn(error_msg, six.text_type(exc))
|
||||
|
||||
error_msg = 'Arguments to "Fn::Or" must be'
|
||||
# test invalid type
|
||||
snippet = {'Fn::Or': 'invalid'}
|
||||
exc = self.assertRaises(exception.StackValidationFailed,
|
||||
self.resolve_condition, snippet, tmpl)
|
||||
|
||||
self.assertIn(error_msg, six.text_type(exc))
|
||||
|
||||
snippet = {'Fn::Or': ['invalid_cd', True]}
|
||||
exc = self.assertRaises(ValueError,
|
||||
self.resolve_condition, snippet, tmpl)
|
||||
error_msg = ('The condition value should be boolean, '
|
||||
'after resolved the value is: invalid_cd')
|
||||
error_msg = ('The condition value must be a boolean: '
|
||||
'invalid_cd')
|
||||
self.assertIn(error_msg, six.text_type(exc))
|
||||
|
||||
def test_join(self):
|
||||
|
|
Loading…
Reference in New Issue