Enable new translation mechanism
Disable old translation mechanism and enable new one. Integrate it with Properties class and correct tests. Change-Id: I953a52e9b165d3ea4fb2fc57ceea8083c7f8f30c Closes-bug: #1620859changes/22/420022/17
parent
157ede1949
commit
e159868d2f
|
@ -24,6 +24,7 @@ from heat.engine import function
|
|||
from heat.engine.hot import parameters as hot_param
|
||||
from heat.engine import parameters
|
||||
from heat.engine import support
|
||||
from heat.engine import translation as trans
|
||||
|
||||
SCHEMA_KEYS = (
|
||||
REQUIRED, IMPLEMENTED, DEFAULT, TYPE, SCHEMA,
|
||||
|
@ -280,14 +281,16 @@ class Property(object):
|
|||
raise ValueError(_('Value must be a string'))
|
||||
return value
|
||||
|
||||
def _get_children(self, child_values, keys=None, validate=False):
|
||||
def _get_children(self, child_values, keys=None, validate=False,
|
||||
translation=None):
|
||||
if self.schema.schema is not None:
|
||||
if keys is None:
|
||||
keys = list(self.schema.schema)
|
||||
schemata = dict((k, self.schema.schema[k]) for k in keys)
|
||||
properties = Properties(schemata, dict(child_values),
|
||||
context=self.context,
|
||||
parent_name=self.path)
|
||||
parent_name=self.path,
|
||||
translation=translation)
|
||||
if validate:
|
||||
properties.validate()
|
||||
|
||||
|
@ -295,7 +298,7 @@ class Property(object):
|
|||
else:
|
||||
return child_values
|
||||
|
||||
def _get_map(self, value, validate=False):
|
||||
def _get_map(self, value, validate=False, translation=None):
|
||||
if value is None:
|
||||
value = self.default() if self.has_default() else {}
|
||||
if not isinstance(value, collections.Mapping):
|
||||
|
@ -310,9 +313,10 @@ class Property(object):
|
|||
raise TypeError(_('"%s" is not a map') % value)
|
||||
|
||||
return dict(self._get_children(six.iteritems(value),
|
||||
validate=validate))
|
||||
validate=validate,
|
||||
translation=translation))
|
||||
|
||||
def _get_list(self, value, validate=False):
|
||||
def _get_list(self, value, validate=False, translation=None):
|
||||
if value is None:
|
||||
value = self.has_default() and self.default() or []
|
||||
if self.schema.allow_conversion and isinstance(value,
|
||||
|
@ -324,7 +328,8 @@ class Property(object):
|
|||
|
||||
return [v[1] for v in self._get_children(enumerate(value),
|
||||
range(len(value)),
|
||||
validate)]
|
||||
validate=validate,
|
||||
translation=translation)]
|
||||
|
||||
def _get_bool(self, value):
|
||||
"""Get value for boolean property.
|
||||
|
@ -344,7 +349,8 @@ class Property(object):
|
|||
|
||||
raise TypeError(_('"%s" is not a valid boolean') % value)
|
||||
|
||||
def get_value(self, value, validate=False, template=None):
|
||||
def get_value(self, value, validate=False, template=None,
|
||||
translation=None):
|
||||
"""Get value from raw value and sanitize according to data type."""
|
||||
|
||||
t = self.type()
|
||||
|
@ -355,9 +361,9 @@ class Property(object):
|
|||
elif t == Schema.NUMBER:
|
||||
_value = self._get_number(value)
|
||||
elif t == Schema.MAP:
|
||||
_value = self._get_map(value, validate)
|
||||
_value = self._get_map(value, validate, translation)
|
||||
elif t == Schema.LIST:
|
||||
_value = self._get_list(value, validate)
|
||||
_value = self._get_list(value, validate, translation)
|
||||
elif t == Schema.BOOLEAN:
|
||||
_value = self._get_bool(value)
|
||||
elif t == Schema.ANY:
|
||||
|
@ -373,7 +379,7 @@ class Property(object):
|
|||
class Properties(collections.Mapping):
|
||||
|
||||
def __init__(self, schema, data, resolver=lambda d: d, parent_name=None,
|
||||
context=None, section=None):
|
||||
context=None, section=None, translation=None):
|
||||
self.props = dict((k, Property(s, k, context, path=parent_name))
|
||||
for k, s in schema.items())
|
||||
self.resolve = resolver
|
||||
|
@ -381,6 +387,11 @@ class Properties(collections.Mapping):
|
|||
self.error_prefix = [section] if section is not None else []
|
||||
self.parent_name = parent_name
|
||||
self.context = context
|
||||
self.translation = (trans.Translation(properties=self)
|
||||
if translation is None else translation)
|
||||
|
||||
def update_translation(self, rules, client_resolve=True):
|
||||
self.translation.set_rules(rules, client_resolve=client_resolve)
|
||||
|
||||
@staticmethod
|
||||
def schema_from_params(params_snippet):
|
||||
|
@ -402,6 +413,9 @@ class Properties(collections.Mapping):
|
|||
raise exception.StackValidationFailed(message=msg)
|
||||
|
||||
for (key, prop) in self.props.items():
|
||||
if (self.translation.is_deleted(prop.path) or
|
||||
self.translation.is_replaced(prop.path)):
|
||||
continue
|
||||
if with_value:
|
||||
try:
|
||||
self._get_property_value(key,
|
||||
|
@ -446,6 +460,9 @@ class Properties(collections.Mapping):
|
|||
raise KeyError(_('Invalid Property %s') % key)
|
||||
|
||||
prop = self.props[key]
|
||||
if (self.translation.is_deleted(prop.path) or
|
||||
self.translation.is_replaced(prop.path)):
|
||||
return
|
||||
if key in self.data:
|
||||
try:
|
||||
unresolved_value = self.data[key]
|
||||
|
@ -454,7 +471,14 @@ class Properties(collections.Mapping):
|
|||
validate = False
|
||||
|
||||
value = self.resolve(unresolved_value)
|
||||
return prop.get_value(value, validate, template=template)
|
||||
|
||||
if self.translation.has_translation(prop.path):
|
||||
value = self.translation.translate(prop.path,
|
||||
value,
|
||||
self.data)
|
||||
|
||||
return prop.get_value(value, validate, template=template,
|
||||
translation=self.translation)
|
||||
# Children can raise StackValidationFailed with unique path which
|
||||
# is necessary for further use in StackValidationFailed exception.
|
||||
# So we need to handle this exception in this method.
|
||||
|
@ -471,10 +495,17 @@ class Properties(collections.Mapping):
|
|||
raise KeyError(_('Invalid Property %s') % key)
|
||||
|
||||
prop = self.props[key]
|
||||
if key in self.data:
|
||||
if not self.translation.is_deleted(prop.path) and key in self.data:
|
||||
return self.get_user_value(key, validate, template=template)
|
||||
elif self.translation.has_translation(prop.path):
|
||||
value = self.translation.translate(prop.path, prop_data=self.data,
|
||||
validate=validate,
|
||||
template=template)
|
||||
if value is not None or prop.has_default():
|
||||
return prop.get_value(value)
|
||||
elif prop.has_default():
|
||||
return prop.get_value(None, validate, template=template)
|
||||
return prop.get_value(None, validate, template=template,
|
||||
translation=self.translation)
|
||||
elif prop.required():
|
||||
raise ValueError(_('Property %s not assigned') % key)
|
||||
|
||||
|
|
|
@ -219,8 +219,7 @@ class Resource(status.ResourceStatus):
|
|||
self.t = definition
|
||||
# Only translate in cases where resource_validate is True
|
||||
# ex. for template-validate
|
||||
self.reparse(translate=self.stack.resource_validate,
|
||||
client_resolve=False)
|
||||
self.reparse(client_resolve=False)
|
||||
self.update_policy = self.t.update_policy(self.update_policy_schema,
|
||||
self.context)
|
||||
self._update_allowed_properties = self.calc_update_allowed(
|
||||
|
@ -372,7 +371,7 @@ class Resource(status.ResourceStatus):
|
|||
{'status': self.COMPLETE, 'replaced_by': self.replaced_by})
|
||||
return new_rs.id
|
||||
|
||||
def reparse(self, translate=True, client_resolve=True):
|
||||
def reparse(self, client_resolve=True):
|
||||
"""Reparse the resource properties.
|
||||
|
||||
Optional translate flag for property translation and
|
||||
|
@ -381,8 +380,7 @@ class Resource(status.ResourceStatus):
|
|||
"""
|
||||
self.properties = self.t.properties(self.properties_schema,
|
||||
self.context)
|
||||
if translate:
|
||||
self.translate_properties(self.properties, client_resolve)
|
||||
self.translate_properties(self.properties, client_resolve)
|
||||
|
||||
def calc_update_allowed(self, props):
|
||||
update_allowed_set = set(self.update_allowed_properties)
|
||||
|
@ -1081,28 +1079,18 @@ class Resource(status.ResourceStatus):
|
|||
|
||||
def translation_rules(self, properties):
|
||||
"""Return specified rules for resource."""
|
||||
return []
|
||||
|
||||
def translate_properties(self, properties,
|
||||
client_resolve=True):
|
||||
"""Translates properties with resource specific rules.
|
||||
"""Set resource specific rules for properties translation.
|
||||
|
||||
The properties parameter is a properties object and the
|
||||
optional client_resolve flag is to specify whether to
|
||||
do 'RESOLVE' translation with client lookup.
|
||||
"""
|
||||
rules = self.translation_rules(properties) or []
|
||||
for rule in rules:
|
||||
try:
|
||||
rule.execute_rule(client_resolve)
|
||||
except exception.ResourcePropertyConflict as ex:
|
||||
path = [self.stack.t.RESOURCES, self.name,
|
||||
self.stack.t.get_section_name(
|
||||
self.stack.t.RES_PROPERTIES)]
|
||||
raise exception.StackValidationFailed(
|
||||
error='Property error',
|
||||
path=path,
|
||||
message=ex.message
|
||||
)
|
||||
properties.update_translation(rules, client_resolve=client_resolve)
|
||||
|
||||
def cancel_grace_period(self):
|
||||
if self.status != self.IN_PROGRESS:
|
||||
|
@ -1279,6 +1267,7 @@ class Resource(status.ResourceStatus):
|
|||
|
||||
# Regenerate the schema, else validation would fail
|
||||
self.regenerate_info_schema(after)
|
||||
after.set_translation_rules(self.translation_rules(self.properties))
|
||||
after_props = after.properties(self.properties_schema,
|
||||
self.context)
|
||||
self.translate_properties(after_props)
|
||||
|
@ -1717,6 +1706,7 @@ class Resource(status.ResourceStatus):
|
|||
# so use the stored frozen_definition instead
|
||||
self.properties = self.frozen_definition().properties(
|
||||
self.properties_schema, self.context)
|
||||
self.translate_properties(self.properties)
|
||||
|
||||
with self._action_recorder(action):
|
||||
if self.abandon_in_progress:
|
||||
|
|
|
@ -36,10 +36,9 @@ class NoneResource(resource.Resource):
|
|||
prev_resource, check_init_complete=True):
|
||||
return False
|
||||
|
||||
def reparse(self, translate=True, client_resolve=True):
|
||||
def reparse(self, client_resolve=True):
|
||||
self.properties = properties.Properties(schema={}, data={})
|
||||
if translate:
|
||||
self.translate_properties(self.properties, client_resolve)
|
||||
self.translate_properties(self.properties, client_resolve)
|
||||
|
||||
def handle_create(self):
|
||||
self.resource_id_set(six.text_type(uuid.uuid4()))
|
||||
|
|
|
@ -138,6 +138,8 @@ class ResourceDefinition(object):
|
|||
function.Function))
|
||||
self._hash ^= _hash_data(condition)
|
||||
|
||||
self.set_translation_rules()
|
||||
|
||||
def freeze(self, **overrides):
|
||||
"""Return a frozen resource definition, with all functions resolved.
|
||||
|
||||
|
@ -238,15 +240,22 @@ class ResourceDefinition(object):
|
|||
filter(None, (get_resource(dep) for dep in explicit_depends)),
|
||||
prop_deps, metadata_deps)
|
||||
|
||||
def set_translation_rules(self, rules=None, client_resolve=True):
|
||||
"""Helper method to update properties with translation rules."""
|
||||
self._rules = rules or []
|
||||
self._client_resolve = client_resolve
|
||||
|
||||
def properties(self, schema, context=None):
|
||||
"""Return a Properties object representing the resource properties.
|
||||
|
||||
The Properties object is constructed from the given schema, and may
|
||||
require a context to validate constraints.
|
||||
"""
|
||||
return properties.Properties(schema, self._properties or {},
|
||||
function.resolve, context=context,
|
||||
section='Properties')
|
||||
props = properties.Properties(schema, self._properties or {},
|
||||
function.resolve, context=context,
|
||||
section='Properties')
|
||||
props.update_translation(self._rules, self._client_resolve)
|
||||
return props
|
||||
|
||||
def deletion_policy(self):
|
||||
"""Return the deletion policy for the resource.
|
||||
|
@ -261,9 +270,11 @@ class ResourceDefinition(object):
|
|||
The Properties object is constructed from the given schema, and may
|
||||
require a context to validate constraints.
|
||||
"""
|
||||
return properties.Properties(schema, self._update_policy or {},
|
||||
function.resolve, context=context,
|
||||
section='UpdatePolicy')
|
||||
props = properties.Properties(schema, self._update_policy or {},
|
||||
function.resolve, context=context,
|
||||
section='UpdatePolicy')
|
||||
props.update_translation(self._rules, self._client_resolve)
|
||||
return props
|
||||
|
||||
def metadata(self):
|
||||
"""Return the resource metadata."""
|
||||
|
|
|
@ -21,7 +21,6 @@ from heat.common.i18n import _
|
|||
from heat.engine.cfn import functions as cfn_funcs
|
||||
from heat.engine import function
|
||||
from heat.engine.hot import functions as hot_funcs
|
||||
from heat.engine import properties
|
||||
|
||||
|
||||
@functools.total_ordering
|
||||
|
@ -101,9 +100,6 @@ class TranslationRule(object):
|
|||
'rules is: %(rules)s.') % {
|
||||
'rule': self.rule,
|
||||
'rules': ', '.join(self.RULE_KEYS)})
|
||||
if not isinstance(self.properties, properties.Properties):
|
||||
raise ValueError(_('Properties must be Properties type. '
|
||||
'Found %s.') % type(self.properties))
|
||||
|
||||
if (not isinstance(self.translation_path, list) or
|
||||
len(self.translation_path) == 0):
|
||||
|
@ -167,41 +163,7 @@ class TranslationRule(object):
|
|||
client_resolve=client_resolve)
|
||||
|
||||
def _prepare_data(self, data, path, props):
|
||||
def get_props(props, key):
|
||||
props = props.get(key)
|
||||
if props.schema.schema is not None:
|
||||
keys = list(props.schema.schema)
|
||||
schemata = dict((k, props.schema.schema[k])
|
||||
for k in keys)
|
||||
props = dict((k, properties.Property(s, k))
|
||||
for k, s in schemata.items())
|
||||
if set(props.keys()) == set('*'):
|
||||
return get_props(props, '*')
|
||||
return props
|
||||
|
||||
if not path:
|
||||
return
|
||||
current_key = path[0]
|
||||
if data.get(current_key) is None:
|
||||
if (self.rule in (TranslationRule.DELETE,
|
||||
TranslationRule.RESOLVE) or
|
||||
(self.rule == TranslationRule.REPLACE and
|
||||
self.value_name is not None)):
|
||||
return
|
||||
data_type = props.get(current_key).type()
|
||||
if data_type == properties.Schema.LIST:
|
||||
data[current_key] = []
|
||||
if data_type == properties.Schema.MAP:
|
||||
data[current_key] = {}
|
||||
return
|
||||
data[current_key] = self._resolve_param(data.get(current_key))
|
||||
if isinstance(data[current_key], list):
|
||||
for item in data[current_key]:
|
||||
self._prepare_data(item, path[1:],
|
||||
get_props(props, current_key))
|
||||
elif isinstance(data[current_key], dict):
|
||||
self._prepare_data(data[current_key], path[1:],
|
||||
get_props(props, current_key))
|
||||
pass
|
||||
|
||||
def _exec_action(self, key, data, value=None, value_key=None,
|
||||
value_data=None, client_resolve=True):
|
||||
|
@ -454,7 +416,8 @@ class Translation(object):
|
|||
return (self.is_active and
|
||||
(key in self._rules or key in self.resolved_translations))
|
||||
|
||||
def translate(self, key, prop_value=None, prop_data=None):
|
||||
def translate(self, key, prop_value=None, prop_data=None, validate=False,
|
||||
template=None):
|
||||
if key in self.resolved_translations:
|
||||
return self.resolved_translations[key]
|
||||
|
||||
|
@ -468,10 +431,12 @@ class Translation(object):
|
|||
result = None
|
||||
|
||||
if rule.rule == TranslationRule.REPLACE:
|
||||
result = self.replace(key, rule, result, prop_data)
|
||||
result = self.replace(key, rule, result, prop_data, validate,
|
||||
template)
|
||||
|
||||
if rule.rule == TranslationRule.ADD:
|
||||
result = self.add(key, rule, result, prop_data)
|
||||
result = self.add(key, rule, result, prop_data, validate,
|
||||
template)
|
||||
|
||||
if rule.rule == TranslationRule.RESOLVE:
|
||||
resolved_value = resolve_and_find(result,
|
||||
|
@ -484,7 +449,8 @@ class Translation(object):
|
|||
|
||||
return result
|
||||
|
||||
def add(self, key, add_rule, prop_value=None, prop_data=None):
|
||||
def add(self, key, add_rule, prop_value=None, prop_data=None,
|
||||
validate=False, template=None):
|
||||
value_path = add_rule.get_value_absolute_path()
|
||||
if prop_value is None:
|
||||
prop_value = []
|
||||
|
@ -504,7 +470,9 @@ class Translation(object):
|
|||
self.is_active = False
|
||||
value = get_value(value_path,
|
||||
prop_data if add_rule.value_name else
|
||||
self.properties)
|
||||
self.properties,
|
||||
validate,
|
||||
template)
|
||||
self.is_active = True
|
||||
if value is not None:
|
||||
translation_value.extend(value if isinstance(value, list)
|
||||
|
@ -514,7 +482,8 @@ class Translation(object):
|
|||
self.resolved_translations[key] = translation_value
|
||||
return translation_value
|
||||
|
||||
def replace(self, key, replace_rule, prop_value=None, prop_data=None):
|
||||
def replace(self, key, replace_rule, prop_value=None, prop_data=None,
|
||||
validate=False, template=None):
|
||||
value = None
|
||||
value_path = replace_rule.get_value_absolute_path(full_value_name=True)
|
||||
short_path = replace_rule.get_value_absolute_path()
|
||||
|
@ -530,7 +499,7 @@ class Translation(object):
|
|||
subpath = value_path
|
||||
props = prop_data if replace_rule.value_name else self.properties
|
||||
self.is_active = False
|
||||
value = get_value(subpath, props)
|
||||
value = get_value(subpath, props, validate, template)
|
||||
self.is_active = True
|
||||
|
||||
if self.has_translation(prop_path):
|
||||
|
@ -554,12 +523,15 @@ class Translation(object):
|
|||
return result
|
||||
|
||||
|
||||
def get_value(path, props):
|
||||
def get_value(path, props, validate=False, template=None):
|
||||
if not props:
|
||||
return None
|
||||
|
||||
key = path[0]
|
||||
prop = props.get(key)
|
||||
if isinstance(props, dict):
|
||||
prop = props.get(key)
|
||||
else:
|
||||
prop = props._get_property_value(key, validate, template)
|
||||
if len(path[1:]) == 0:
|
||||
return prop
|
||||
elif prop is None:
|
||||
|
|
|
@ -1089,17 +1089,16 @@ class CinderVolumeTest(vt_base.BaseVolumeTest):
|
|||
def test_cinder_create_with_image_and_imageRef(self):
|
||||
stack_name = 'test_create_with_image_and_imageRef'
|
||||
combinations = {'imageRef': 'image-456', 'image': 'image-123'}
|
||||
err_msg = ("Property error: resources.volume2.properties: Cannot "
|
||||
"define the following properties at the same time: "
|
||||
"['image', 'imageRef'].")
|
||||
err_msg = ("Cannot define the following properties at the same time: "
|
||||
"image, imageRef")
|
||||
self.stub_ImageConstraint_validate()
|
||||
stack = utils.parse_stack(self.t, stack_name=stack_name)
|
||||
vp = stack.t['Resources']['volume2']['Properties']
|
||||
vp.pop('size')
|
||||
vp.update(combinations)
|
||||
ex = self.assertRaises(exception.StackValidationFailed,
|
||||
stack.get, 'volume2')
|
||||
self.assertEqual(err_msg, six.text_type(ex))
|
||||
rsrc = stack.get('volume2')
|
||||
ex = self.assertRaises(exception.StackValidationFailed, rsrc.validate)
|
||||
self.assertIn(err_msg, six.text_type(ex))
|
||||
|
||||
def test_cinder_create_with_image_and_size(self):
|
||||
stack_name = 'test_create_with_image_and_size'
|
||||
|
|
|
@ -339,7 +339,7 @@ resources:
|
|||
count: 15
|
||||
wait_before: 5
|
||||
wait_after: 5
|
||||
pause_before: 5
|
||||
pause_before: true
|
||||
timeout: 42
|
||||
concurrency: 5
|
||||
"""
|
||||
|
@ -769,13 +769,12 @@ class TestMistralWorkflow(common.HeatTestCase):
|
|||
|
||||
rsrc_defns = stack.t.resource_definitions(stack)['workflow']
|
||||
|
||||
workflow_rsrc = workflow.Workflow('workflow', rsrc_defns, stack)
|
||||
ex = self.assertRaises(exception.StackValidationFailed,
|
||||
workflow.Workflow, 'workflow', rsrc_defns,
|
||||
stack)
|
||||
error_msg = ("Property error: resources.workflow.properties: Cannot "
|
||||
"define the following properties at the same time: "
|
||||
"['retry', 'policies'].")
|
||||
self.assertEqual(error_msg, six.text_type(ex))
|
||||
workflow_rsrc.validate)
|
||||
error_msg = ("Cannot define the following properties at "
|
||||
"the same time: tasks.retry, tasks.policies.retry")
|
||||
self.assertIn(error_msg, six.text_type(ex))
|
||||
|
||||
def validate_json_inputs(self, actual_input, expected_input):
|
||||
actual_json_input = jsonutils.loads(actual_input)
|
||||
|
@ -837,11 +836,12 @@ class TestMistralWorkflow(common.HeatTestCase):
|
|||
rsrc_defns = stack.t.resource_definitions(stack)['workflow']
|
||||
wf = workflow.Workflow('workflow', rsrc_defns, stack)
|
||||
|
||||
self.assertEqual([{'name': 'check_dat_thing',
|
||||
'action': 'nova.servers_list',
|
||||
'retry': {'delay': 5, 'count': 15},
|
||||
'wait_before': 5,
|
||||
'wait_after': 5,
|
||||
'pause_before': 5,
|
||||
'timeout': 42,
|
||||
'concurrency': 5}], wf.properties.data['tasks'])
|
||||
result = {k: v for k, v in wf.properties['tasks'][0].items() if v}
|
||||
self.assertEqual({'name': 'check_dat_thing',
|
||||
'action': 'nova.servers_list',
|
||||
'retry': {'delay': 5, 'count': 15},
|
||||
'wait_before': 5,
|
||||
'wait_after': 5,
|
||||
'pause_before': True,
|
||||
'timeout': 42,
|
||||
'concurrency': 5}, result)
|
||||
|
|
|
@ -362,7 +362,7 @@ class PoolTest(common.HeatTestCase):
|
|||
'subnet',
|
||||
'sub9999',
|
||||
cmd_resource=None,
|
||||
).AndReturn('sub9999')
|
||||
).MultipleTimes().AndReturn('sub9999')
|
||||
neutronclient.Client.create_vip(stvipvsn
|
||||
).AndReturn({'vip': {'id': 'xyz'}})
|
||||
else:
|
||||
|
@ -386,11 +386,7 @@ class PoolTest(common.HeatTestCase):
|
|||
self.m.VerifyAll()
|
||||
|
||||
def test_create_with_vip_subnet(self):
|
||||
rsrc = self.create_pool(with_vip_subnet=True)
|
||||
self.m.ReplayAll()
|
||||
scheduler.TaskRunner(rsrc.create)()
|
||||
self.assertEqual((rsrc.CREATE, rsrc.COMPLETE), rsrc.state)
|
||||
self.m.VerifyAll()
|
||||
self._test_create(with_vip_subnet=True)
|
||||
|
||||
def test_create_pending(self):
|
||||
snippet = template_format.parse(pool_template)
|
||||
|
|
|
@ -429,7 +429,7 @@ class NeutronPortTest(common.HeatTestCase):
|
|||
create_kwargs = props.copy()
|
||||
create_kwargs['admin_state_up'] = True
|
||||
|
||||
self.find_mock.side_effect = [net1] * 7 + [net2] * 2
|
||||
self.find_mock.side_effect = [net1] * 8 + [net2] * 2 + [net1]
|
||||
self.create_mock.return_value = {'port': {
|
||||
"status": "ACTIVE",
|
||||
"id": "fc68ea2c-b60b-4b4f-bd82-94ec81110766"
|
||||
|
@ -457,23 +457,23 @@ class NeutronPortTest(common.HeatTestCase):
|
|||
self.assertEqual((port.CREATE, port.COMPLETE), port.state)
|
||||
self.create_mock.assert_called_once_with({'port': create_kwargs})
|
||||
|
||||
# Switch from network_id=ID to network=ID (no replace and no upate)
|
||||
# Switch from network_id=ID to network=ID (no replace)
|
||||
new_props = props.copy()
|
||||
new_props['network'] = new_props.pop('network_id')
|
||||
update_snippet = rsrc_defn.ResourceDefinition(port.name, port.type(),
|
||||
new_props)
|
||||
|
||||
scheduler.TaskRunner(port.update, update_snippet)()
|
||||
self.assertEqual((port.CREATE, port.COMPLETE), port.state)
|
||||
self.assertEqual((port.UPDATE, port.COMPLETE), port.state)
|
||||
self.assertEqual(0, self.update_mock.call_count)
|
||||
|
||||
# Switch from network=ID to network=NAME (no replace and no update)
|
||||
# Switch from network=ID to network=NAME (no replace)
|
||||
new_props['network'] = 'net1234'
|
||||
update_snippet = rsrc_defn.ResourceDefinition(port.name, port.type(),
|
||||
new_props)
|
||||
|
||||
scheduler.TaskRunner(port.update, update_snippet)()
|
||||
self.assertEqual((port.CREATE, port.COMPLETE), port.state)
|
||||
self.assertEqual((port.UPDATE, port.COMPLETE), port.state)
|
||||
self.assertEqual(0, self.update_mock.call_count)
|
||||
|
||||
# Switch to a different network (replace)
|
||||
|
@ -482,7 +482,7 @@ class NeutronPortTest(common.HeatTestCase):
|
|||
new_props)
|
||||
updater = scheduler.TaskRunner(port.update, update_snippet)
|
||||
self.assertRaises(resource.UpdateReplace, updater)
|
||||
self.assertEqual(9, self.find_mock.call_count)
|
||||
self.assertEqual(11, self.find_mock.call_count)
|
||||
|
||||
def test_get_port_attributes(self):
|
||||
t = template_format.parse(neutron_port_template)
|
||||
|
|
|
@ -485,14 +485,14 @@ class NeutronRouterTest(common.HeatTestCase):
|
|||
'router',
|
||||
'3e46229d-8fce-4733-819a-b5fe630550f8',
|
||||
cmd_resource=None,
|
||||
).AndReturn('3e46229d-8fce-4733-819a-b5fe630550f8')
|
||||
).MultipleTimes().AndReturn('3e46229d-8fce-4733-819a-b5fe630550f8')
|
||||
router_key = 'router'
|
||||
neutronV20.find_resourceid_by_name_or_id(
|
||||
mox.IsA(neutronclient.Client),
|
||||
'subnet',
|
||||
'91e47a57-7508-46fe-afc9-fc454e8580e1',
|
||||
cmd_resource=None,
|
||||
).AndReturn('91e47a57-7508-46fe-afc9-fc454e8580e1')
|
||||
).MultipleTimes().AndReturn('91e47a57-7508-46fe-afc9-fc454e8580e1')
|
||||
subnet_key = 'subnet'
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
@ -724,7 +724,7 @@ class NeutronRouterTest(common.HeatTestCase):
|
|||
'network',
|
||||
'public',
|
||||
cmd_resource=None,
|
||||
).AndReturn('fc68ea2c-b60b-4b4f-bd82-94ec81110766')
|
||||
).MultipleTimes().AndReturn('fc68ea2c-b60b-4b4f-bd82-94ec81110766')
|
||||
neutronV20.find_resourceid_by_name_or_id(
|
||||
mox.IsA(neutronclient.Client),
|
||||
'subnet',
|
||||
|
@ -884,24 +884,12 @@ class NeutronRouterTest(common.HeatTestCase):
|
|||
'other_public',
|
||||
cmd_resource=None,
|
||||
).AndReturn('91e47a57-7508-46fe-afc9-fc454e8580e1')
|
||||
neutronV20.find_resourceid_by_name_or_id(
|
||||
mox.IsA(neutronclient.Client),
|
||||
'network',
|
||||
'fc68ea2c-b60b-4b4f-bd82-94ec81110766',
|
||||
cmd_resource=None,
|
||||
).AndReturn('fc68ea2c-b60b-4b4f-bd82-94ec81110766')
|
||||
neutronV20.find_resourceid_by_name_or_id(
|
||||
mox.IsA(neutronclient.Client),
|
||||
'subnet',
|
||||
'sub1234',
|
||||
cmd_resource=None,
|
||||
).AndReturn('sub1234')
|
||||
neutronV20.find_resourceid_by_name_or_id(
|
||||
mox.IsA(neutronclient.Client),
|
||||
'network',
|
||||
'91e47a57-7508-46fe-afc9-fc454e8580e1',
|
||||
cmd_resource=None,
|
||||
).AndReturn('91e47a57-7508-46fe-afc9-fc454e8580e1')
|
||||
neutronclient.Client.update_router(
|
||||
'3e46229d-8fce-4733-819a-b5fe630550f8',
|
||||
{'router': {
|
||||
|
@ -913,7 +901,7 @@ class NeutronRouterTest(common.HeatTestCase):
|
|||
).AndReturn(None)
|
||||
|
||||
neutronclient.Client.show_router(
|
||||
'3e46229d-8fce-4733-819a-b5fe630550f8').AndReturn({
|
||||
'3e46229d-8fce-4733-819a-b5fe630550f8').MultipleTimes().AndReturn({
|
||||
"router": {
|
||||
"status": "ACTIVE",
|
||||
"external_gateway_info": {
|
||||
|
|
|
@ -134,18 +134,18 @@ class VPNServiceTest(common.HeatTestCase):
|
|||
def create_vpnservice(self, resolve_neutron=True, resolve_router=True):
|
||||
self.stub_SubnetConstraint_validate()
|
||||
self.stub_RouterConstraint_validate()
|
||||
neutronV20.find_resourceid_by_name_or_id(
|
||||
mox.IsA(neutronclient.Client),
|
||||
'subnet',
|
||||
'sub123',
|
||||
cmd_resource=None,
|
||||
).AndReturn('sub123')
|
||||
neutronV20.find_resourceid_by_name_or_id(
|
||||
mox.IsA(neutronclient.Client),
|
||||
'router',
|
||||
'rou123',
|
||||
cmd_resource=None,
|
||||
).AndReturn('rou123')
|
||||
).MultipleTimes().AndReturn('rou123')
|
||||
neutronV20.find_resourceid_by_name_or_id(
|
||||
mox.IsA(neutronclient.Client),
|
||||
'subnet',
|
||||
'sub123',
|
||||
cmd_resource=None,
|
||||
).MultipleTimes().AndReturn('sub123')
|
||||
if resolve_neutron:
|
||||
snippet = template_format.parse(vpnservice_template)
|
||||
else:
|
||||
|
|
|
@ -255,9 +255,13 @@ class ServersTest(common.HeatTestCase):
|
|||
|
||||
def _setup_test_stack(self, stack_name, test_templ=wp_template):
|
||||
t = template_format.parse(test_templ)
|
||||
files = {}
|
||||
if test_templ == ns_template:
|
||||
files = {'a_file': 'stub'}
|
||||
templ = template.Template(t,
|
||||
env=environment.Environment(
|
||||
{'key_name': 'test'}))
|
||||
{'key_name': 'test'}),
|
||||
files=files)
|
||||
stack = parser.Stack(utils.dummy_context(), stack_name, templ,
|
||||
stack_id=uuidutils.generate_uuid(),
|
||||
stack_user_project_id='8888')
|
||||
|
@ -549,38 +553,39 @@ class ServersTest(common.HeatTestCase):
|
|||
(tmpl, stack) = self._setup_test_stack(stack_name)
|
||||
mock_image = self.patchobject(glance.GlanceClientPlugin,
|
||||
'find_image_by_name_or_id')
|
||||
mock_image.side_effect = [
|
||||
self.stub_KeypairConstraint_validate()
|
||||
mock_image.side_effect = (
|
||||
glance.client_exception.EntityMatchNotFound(
|
||||
entity='image', args={'name': 'Slackware'})]
|
||||
entity='image', args={'name': 'Slackware'}))
|
||||
# Init a server with non exist image name
|
||||
tmpl['Resources']['WebServer']['Properties']['image'] = 'Slackware'
|
||||
resource_defns = tmpl.resource_definitions(stack)
|
||||
server = servers.Server('WebServer',
|
||||
resource_defns['WebServer'], stack)
|
||||
|
||||
error = self.assertRaises(glance.client_exception.EntityMatchNotFound,
|
||||
error = self.assertRaises(exception.ResourceFailure,
|
||||
scheduler.TaskRunner(server.create))
|
||||
self.assertEqual("No image matching {'name': 'Slackware'}.",
|
||||
six.text_type(error))
|
||||
self.assertIn("No image matching {'name': 'Slackware'}.",
|
||||
six.text_type(error))
|
||||
|
||||
def test_server_duplicate_image_name_err(self):
|
||||
stack_name = 'img_dup_err'
|
||||
(tmpl, stack) = self._setup_test_stack(stack_name)
|
||||
mock_image = self.patchobject(glance.GlanceClientPlugin,
|
||||
'find_image_by_name_or_id')
|
||||
mock_image.side_effect = [
|
||||
self.stub_KeypairConstraint_validate()
|
||||
mock_image.side_effect = (
|
||||
glance.client_exception.EntityUniqueMatchNotFound(
|
||||
entity='image', args='CentOS 5.2')]
|
||||
entity='image', args='CentOS 5.2'))
|
||||
tmpl['Resources']['WebServer']['Properties']['image'] = 'CentOS 5.2'
|
||||
resource_defns = tmpl.resource_definitions(stack)
|
||||
server = servers.Server('WebServer',
|
||||
resource_defns['WebServer'], stack)
|
||||
|
||||
error = self.assertRaises(
|
||||
glance.client_exception.EntityUniqueMatchNotFound,
|
||||
scheduler.TaskRunner(server.create))
|
||||
self.assertEqual('No image unique match found for CentOS 5.2.',
|
||||
six.text_type(error))
|
||||
error = self.assertRaises(exception.ResourceFailure,
|
||||
scheduler.TaskRunner(server.create))
|
||||
self.assertIn('No image unique match found for CentOS 5.2.',
|
||||
six.text_type(error))
|
||||
|
||||
def test_server_create_unexpected_status(self):
|
||||
# NOTE(pshchelo) checking is done only on check_create_complete
|
||||
|
@ -1237,6 +1242,7 @@ class ServersTest(common.HeatTestCase):
|
|||
def test_server_validate_with_networks(self):
|
||||
stack_name = 'srv_net'
|
||||
(tmpl, stack) = self._setup_test_stack(stack_name)
|
||||
self.stub_KeypairConstraint_validate()
|
||||
|
||||
network_name = 'public'
|
||||
# create a server with 'uuid' and 'network' properties
|
||||
|
@ -1245,15 +1251,14 @@ class ServersTest(common.HeatTestCase):
|
|||
'network': network_name}])
|
||||
|
||||
resource_defns = tmpl.resource_definitions(stack)
|
||||
server = servers.Server('server_validate_with_networks',
|
||||
resource_defns['WebServer'], stack)
|
||||
self.stub_NetworkConstraint_validate()
|
||||
ex = self.assertRaises(exception.StackValidationFailed,
|
||||
servers.Server,
|
||||
'server_validate_with_networks',
|
||||
resource_defns['WebServer'], stack)
|
||||
server.validate)
|
||||
|
||||
self.assertIn("Property error: "
|
||||
"Resources.server_validate_with_networks.Properties: "
|
||||
"Cannot define the following properties at the same "
|
||||
"time: ['network', 'uuid'].",
|
||||
self.assertIn("Cannot define the following properties at "
|
||||
"the same time: networks.network, networks.uuid",
|
||||
six.text_type(ex))
|
||||
|
||||
def test_server_validate_with_network_empty_ref(self):
|
||||
|
@ -2466,20 +2471,20 @@ class ServersTest(common.HeatTestCase):
|
|||
(tmpl, stack) = self._setup_test_stack(stack_name,
|
||||
test_templ=ns_template)
|
||||
|
||||
side_effect = [neutron.exceptions.NotFound(),
|
||||
neutron.exceptions.NeutronClientNoUniqueMatch()]
|
||||
resolver = self.patchobject(neutron.NeutronClientPlugin,
|
||||
'find_resourceid_by_name_or_id')
|
||||
|
||||
self.patchobject(neutron.NeutronClientPlugin,
|
||||
'find_resourceid_by_name_or_id',
|
||||
side_effect=side_effect)
|
||||
resource_defns = tmpl.resource_definitions(stack)
|
||||
server = servers.Server('server',
|
||||
resource_defns['server'], stack)
|
||||
|
||||
self.assertRaises(neutron.exceptions.NotFound,
|
||||
scheduler.TaskRunner(server.create))
|
||||
self.assertRaises(neutron.exceptions.NeutronClientNoUniqueMatch,
|
||||
scheduler.TaskRunner(server.create))
|
||||
resolver.side_effect = neutron.exceptions.NotFound()
|
||||
server.reparse()
|
||||
self.assertRaises(ValueError, server.properties.get, 'networks')
|
||||
resolver.side_effect = neutron.exceptions.NeutronClientNoUniqueMatch()
|
||||
ex = self.assertRaises(exception.ResourceFailure,
|
||||
scheduler.TaskRunner(server.create))
|
||||
self.assertIn('use an ID to be more specific.', six.text_type(ex))
|
||||
|
||||
def test_server_without_ip_address(self):
|
||||
return_server = self.fc.servers.list()[3]
|
||||
|
@ -2785,22 +2790,23 @@ class ServersTest(common.HeatTestCase):
|
|||
resource_defns = tmpl.resource_definitions(stack)
|
||||
self.server = servers.Server('server',
|
||||
resource_defns['server'], stack)
|
||||
self.server.translate_properties(self.server.properties, True)
|
||||
self.assertEqual(2, self.server.t._properties[
|
||||
'block_device_mapping_v2'][0]['image'])
|
||||
self.server.translate_properties(self.server.properties)
|
||||
self.assertEqual('2',
|
||||
self.server.properties['block_device_mapping_v2'][
|
||||
0]['image'])
|
||||
|
||||
def test_block_device_mapping_v2_image_prop_conflict(self):
|
||||
test_templ = bdm_v2_template + "\n image: F17-x86_64-gold"
|
||||
(tmpl, stack) = self._setup_test_stack('mapping',
|
||||
test_templ=test_templ)
|
||||
resource_defns = tmpl.resource_definitions(stack)
|
||||
msg = ("Property error: resources.server.properties: Cannot define "
|
||||
"the following properties at the same time: "
|
||||
"['image', 'image_id'].")
|
||||
msg = ("Cannot define the following "
|
||||
"properties at the same time: block_device_mapping_v2.image, "
|
||||
"block_device_mapping_v2.image_id")
|
||||
server = servers.Server('server', resource_defns['server'], stack)
|
||||
exc = self.assertRaises(exception.StackValidationFailed,
|
||||
servers.Server, 'server',
|
||||
resource_defns['server'], stack)
|
||||
self.assertEqual(msg, six.text_type(exc))
|
||||
server.validate)
|
||||
self.assertIn(msg, six.text_type(exc))
|
||||
|
||||
@mock.patch.object(nova.NovaClientPlugin, '_create')
|
||||
def test_validate_with_both_blk_dev_map_and_blk_dev_map_v2(self,
|
||||
|
@ -3700,9 +3706,11 @@ class ServersTest(common.HeatTestCase):
|
|||
|
||||
# update
|
||||
updater = scheduler.TaskRunner(server.update, update_template)
|
||||
err = self.assertRaises(glance.client_exception.EntityMatchNotFound,
|
||||
err = self.assertRaises(exception.ResourceFailure,
|
||||
updater)
|
||||
self.assertEqual('No image matching Update Image.',
|
||||
self.assertEqual("StackValidationFailed: resources.my_server: "
|
||||
"Property error: Properties.image: Error validating "
|
||||
"value '1': No image matching Update Image.",
|
||||
six.text_type(err))
|
||||
|
||||
def test_server_snapshot(self):
|
||||
|
|
|
@ -198,7 +198,7 @@ class ResourceTest(common.HeatTestCase):
|
|||
stack.resource_validate = False
|
||||
mock_db_get.return_value = mock.Mock()
|
||||
self.assertEqual(1, len(stack.resources))
|
||||
self.assertEqual(1, mock_translate.call_count)
|
||||
self.assertEqual(2, mock_translate.call_count)
|
||||
self.assertEqual(1, mock_load.call_count)
|
||||
self.assertEqual(0, mock_resolve.call_count)
|
||||
|
||||
|
|
|
@ -27,6 +27,10 @@ from heat.tests import common
|
|||
|
||||
class TestTranslationRule(common.HeatTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestTranslationRule, self).setUp()
|
||||
self.props = mock.Mock(spec=properties.Properties)
|
||||
|
||||
def test_translation_rule(self):
|
||||
for r in translation.TranslationRule.RULE_KEYS:
|
||||
props = properties.Properties({}, {})
|
||||
|
@ -81,12 +85,6 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
|
||||
def test_invalid_translation_rule(self):
|
||||
props = properties.Properties({}, {})
|
||||
exc = self.assertRaises(ValueError,
|
||||
translation.TranslationRule,
|
||||
'proppy', mock.ANY,
|
||||
mock.ANY)
|
||||
self.assertEqual('Properties must be Properties type. '
|
||||
'Found %s.' % str, six.text_type(exc))
|
||||
|
||||
exc = self.assertRaises(ValueError,
|
||||
translation.TranslationRule,
|
||||
|
@ -169,13 +167,8 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
translation.TranslationRule.ADD,
|
||||
['far'],
|
||||
[{'red': props.get('bar')}])
|
||||
rule.execute_rule()
|
||||
|
||||
self.assertIn({'red': 'dak'}, props.get('far'))
|
||||
|
||||
# check for new translation
|
||||
tran = translation.Translation(properties.Properties(schema,
|
||||
copy.copy(data)))
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
|
||||
self.assertTrue(tran.has_translation('far'))
|
||||
|
@ -211,12 +204,8 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
translation.TranslationRule.ADD,
|
||||
['far'],
|
||||
[{'red': props.get('bar')}])
|
||||
rule.execute_rule()
|
||||
|
||||
self.assertEqual([{'red': 'dak'}], props.get('far'))
|
||||
# check for new translation
|
||||
tran = translation.Translation(properties.Properties(schema,
|
||||
copy.copy(data)))
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
|
||||
self.assertTrue(tran.has_translation('far'))
|
||||
|
@ -249,13 +238,8 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
translation.TranslationRule.ADD,
|
||||
['far'],
|
||||
[props.get('bar')])
|
||||
exc = self.assertRaises(ValueError, rule.execute_rule)
|
||||
|
||||
self.assertEqual('Add rule must be used only for lists.',
|
||||
six.text_type(exc))
|
||||
# check for new translation
|
||||
tran = translation.Translation(properties.Properties(schema,
|
||||
copy.copy(data)))
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
|
||||
self.assertTrue(tran.has_translation('far'))
|
||||
|
@ -289,11 +273,7 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
translation.TranslationRule.REPLACE,
|
||||
['far', 'red'],
|
||||
props.get('bar'))
|
||||
rule.execute_rule()
|
||||
|
||||
self.assertEqual({'red': 'dak'}, props.get('far'))
|
||||
|
||||
# check for new translation
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
|
||||
|
@ -326,11 +306,7 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
translation.TranslationRule.REPLACE,
|
||||
['far', 'red'],
|
||||
props.get('bar'))
|
||||
rule.execute_rule()
|
||||
|
||||
self.assertEqual({'red': 'dak'}, props.get('far'))
|
||||
|
||||
# check for new translation
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
|
||||
|
@ -368,11 +344,7 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
translation.TranslationRule.REPLACE,
|
||||
['far', 'red'],
|
||||
props.get('bar'))
|
||||
rule.execute_rule()
|
||||
|
||||
self.assertEqual([{'red': 'dak'}, {'red': 'dak'}], props.get('far'))
|
||||
|
||||
# check for new translation
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
|
||||
|
@ -410,18 +382,12 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
['far', 'red'],
|
||||
None,
|
||||
'blue')
|
||||
rule.execute_rule()
|
||||
|
||||
self.assertEqual([{'red': 'white', 'blue': None},
|
||||
{'blue': None, 'red': 'roses'}],
|
||||
props.get('far'))
|
||||
|
||||
# check for new translation
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
|
||||
self.assertTrue(tran.has_translation('far.0.red'))
|
||||
result = tran.translate('far.0.red', data['far'][0]['red'],
|
||||
result = tran.translate('far.0.red', data['far'][0].get('red'),
|
||||
data['far'][0])
|
||||
self.assertEqual('white', result)
|
||||
self.assertEqual('white', tran.resolved_translations['far.0.red'])
|
||||
|
@ -448,12 +414,7 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
translation.TranslationRule.REPLACE,
|
||||
['bar'],
|
||||
props.get('far'))
|
||||
rule.execute_rule()
|
||||
|
||||
self.assertEqual('one', props.get('bar'))
|
||||
self.assertEqual('one', props.get('far'))
|
||||
|
||||
# check for new translation
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
|
||||
|
@ -477,13 +438,7 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
translation.TranslationRule.REPLACE,
|
||||
['bar'],
|
||||
value_path=['far'])
|
||||
ex = self.assertRaises(exception.ResourcePropertyConflict,
|
||||
rule.execute_rule)
|
||||
self.assertEqual("Cannot define the following properties at the "
|
||||
"same time: ['bar', 'far'].",
|
||||
six.text_type(ex))
|
||||
|
||||
# check for new translation
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
|
||||
|
@ -506,12 +461,7 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
translation.TranslationRule.REPLACE,
|
||||
['bar'],
|
||||
value_path=['far'])
|
||||
rule.execute_rule()
|
||||
|
||||
self.assertEqual('one', props.get('bar'))
|
||||
self.assertIsNone(props.get('far'))
|
||||
|
||||
# check for new translation
|
||||
props = properties.Properties(schema, {'far': 'one'})
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
|
@ -537,8 +487,7 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
translation.TranslationRule.REPLACE,
|
||||
['bar'],
|
||||
props.get('far'))
|
||||
rule.execute_rule()
|
||||
|
||||
props.update_translation([rule])
|
||||
exc = self.assertRaises(exception.StackValidationFailed,
|
||||
props.validate)
|
||||
self.assertEqual("Property error: bar: Value 'one' is not an integer",
|
||||
|
@ -572,27 +521,12 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
translation.TranslationRule.DELETE,
|
||||
['far', 'red'])
|
||||
|
||||
# check for new translation (before old translation, because old style
|
||||
# change data)
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
self.assertTrue(tran.has_translation('far.red'))
|
||||
self.assertIsNone(tran.translate('far.red'))
|
||||
self.assertIsNone(tran.resolved_translations['far.red'])
|
||||
|
||||
rule.execute_rule()
|
||||
|
||||
self.assertEqual([{'check': None, 'red': None},
|
||||
{'check': None, 'red': None}], props.get('far'))
|
||||
|
||||
# check if no data translation still is correct
|
||||
props = properties.Properties(schema, {'far': [{'check': 'yep'}]})
|
||||
rule = translation.TranslationRule(
|
||||
props,
|
||||
translation.TranslationRule.DELETE,
|
||||
['far', 'red'])
|
||||
self.assertIsNone(rule.execute_rule())
|
||||
|
||||
def test_delete_rule_other(self):
|
||||
schema = {
|
||||
'far': properties.Schema(properties.Schema.STRING)
|
||||
|
@ -607,18 +541,12 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
translation.TranslationRule.DELETE,
|
||||
['far'])
|
||||
|
||||
# check for new translation (before old translation, because old style
|
||||
# change data)
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
self.assertTrue(tran.has_translation('far'))
|
||||
self.assertIsNone(tran.translate('far'))
|
||||
self.assertIsNone(tran.resolved_translations['far'])
|
||||
|
||||
rule.execute_rule()
|
||||
|
||||
self.assertIsNone(props.get('far'))
|
||||
|
||||
def _test_resolve_rule(self, is_list=False):
|
||||
class FakeClientPlugin(object):
|
||||
def find_name_id(self, entity=None,
|
||||
|
@ -662,8 +590,6 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
finder='find_name_id'
|
||||
)
|
||||
|
||||
# check for new translation (before old translation, because old style
|
||||
# change data)
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
self.assertTrue(tran.has_translation('far.red'))
|
||||
|
@ -671,10 +597,6 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
self.assertEqual('yellow', result)
|
||||
self.assertEqual('yellow', tran.resolved_translations['far.0.red'])
|
||||
|
||||
rule.execute_rule()
|
||||
self.assertEqual([{'red': 'yellow'}, {'red': 'yellow'}],
|
||||
props.get('far'))
|
||||
|
||||
def test_resolve_rule_list_with_function(self):
|
||||
client_plugin, schema = self._test_resolve_rule(is_list=True)
|
||||
join_func = cfn_funcs.Join(None,
|
||||
|
@ -693,8 +615,6 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
finder='find_name_id'
|
||||
)
|
||||
|
||||
# check for new translation (before old translation, because old style
|
||||
# change data)
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
self.assertTrue(tran.has_translation('far.red'))
|
||||
|
@ -702,10 +622,6 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
self.assertEqual('yellow', result)
|
||||
self.assertEqual('yellow', tran.resolved_translations['far.0.red'])
|
||||
|
||||
rule.execute_rule()
|
||||
self.assertEqual([{'red': 'yellow'}, {'red': 'yellow'}],
|
||||
props.get('far'))
|
||||
|
||||
def test_resolve_rule_list_with_ref(self):
|
||||
client_plugin, schema = self._test_resolve_rule(is_list=True)
|
||||
|
||||
|
@ -734,8 +650,6 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
finder='find_name_id'
|
||||
)
|
||||
|
||||
# check for new translation (before old translation, because old style
|
||||
# change data)
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
self.assertTrue(tran.has_translation('far.red'))
|
||||
|
@ -743,9 +657,6 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
self.assertEqual('yellow', result)
|
||||
self.assertEqual('yellow', tran.resolved_translations['far.0.red'])
|
||||
|
||||
rule.execute_rule()
|
||||
self.assertEqual(data, props.data)
|
||||
|
||||
def test_resolve_rule_list_strings(self):
|
||||
client_plugin, schema = self._test_resolve_rule()
|
||||
data = {'far': ['one', 'rose']}
|
||||
|
@ -763,8 +674,6 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
client_plugin=client_plugin,
|
||||
finder='find_name_id')
|
||||
|
||||
# check for new translation (before old translation, because old style
|
||||
# change data)
|
||||
tran = translation.Translation(props)
|
||||
tran.set_rules([rule])
|
||||
self.assertTrue(tran.has_translation('far'))
|
||||
|
@ -772,26 +681,6 @@ class TestTranslationRule(common.HeatTestCase):
|
|||
self.assertEqual(['yellow', 'pink'], result)
|
||||
self.assertEqual(['yellow', 'pink'], tran.resolved_translations['far'])
|
||||
|
||||
rule.execute_rule()
|
||||
self.assertEqual(['yellow', 'pink'], props.get('far'))
|
||||
|
||||
def test_resolve_rule_list_empty(self):
|
||||
client_plugin, schema = self._test_resolve_rule(is_list=True)
|
||||
data = {
|
||||
'far': [],
|
||||
}
|
||||
props = properties.Properties(schema, data)
|
||||
|
||||
rule = translation.TranslationRule(
|
||||
props,
|
||||
translation.TranslationRule.RESOLVE,
|
||||
['far', 'red'],
|
||||
client_plugin=client_plugin,
|
||||