diff --git a/murano/dsl/exceptions.py b/murano/dsl/exceptions.py index be0a3e98..b1b199b1 100644 --- a/murano/dsl/exceptions.py +++ b/murano/dsl/exceptions.py @@ -126,5 +126,5 @@ class PropertyWriteError(PropertyAccessError): class UninitializedPropertyAccessError(PropertyAccessError): def __init__(self, name, murano_class): super(PropertyAccessError, self).__init__( - 'Access to private uninitialized property ' + 'Access to uninitialized property ' '%s in class %s is forbidden' % (name, murano_class.name)) diff --git a/murano/dsl/murano_object.py b/murano/dsl/murano_object.py index 1b2f93b6..26b26596 100644 --- a/murano/dsl/murano_object.py +++ b/murano/dsl/murano_object.py @@ -54,17 +54,27 @@ class MuranoObject(object): for i in xrange(2): for property_name in self.__type.properties: spec = self.__type.get_property(property_name) - if spec.usage == typespec.PropertyUsages.Runtime: - continue needs_evaluation = murano.dsl.helpers.needs_evaluation if i == 0 and needs_evaluation(spec.default) or i == 1\ and property_name in used_names: continue used_names.add(property_name) - property_value = kwargs.get(property_name, type_scheme.NoValue) - self.set_property(property_name, property_value) + if spec.usage == typespec.PropertyUsages.Runtime: + if not spec.has_default: + continue + property_value = type_scheme.NoValue + else: + property_value = kwargs.get(property_name, + type_scheme.NoValue) + try: + self.set_property(property_name, property_value) + except exceptions.ContractViolationException: + if spec.usage != typespec.PropertyUsages.Runtime: + raise + for parent in self.__parents.values(): parent.initialize(**kwargs) + self.__initialized = True @property def object_id(self): @@ -93,7 +103,7 @@ class MuranoObject(object): if caller_class is not None and caller_class.is_compatible(self): start_type, derived = caller_class, True if name in start_type.properties: - return self.cast(start_type).__properties[name] + return self.cast(start_type)._get_property_value(name) else: declared_properties = start_type.find_property(name) if len(declared_properties) == 1: @@ -101,14 +111,17 @@ class MuranoObject(object): elif len(declared_properties) > 1: raise exceptions.AmbiguousPropertyNameError(name) elif derived: - try: - return self.cast(caller_class).__properties[name] - except KeyError: - raise exceptions.UninitializedPropertyAccessError( - name, start_type) + return self.cast(caller_class)._get_property_value(name) else: raise exceptions.PropertyReadError(name, start_type) + def _get_property_value(self, name): + try: + return self.__properties[name] + except KeyError: + raise exceptions.UninitializedPropertyAccessError( + name, self.__type) + def set_property(self, name, value, caller_class=None): start_type, derived = self.__type, False if caller_class is not None and caller_class.is_compatible(self): diff --git a/murano/tests/unit/dsl/meta/PropertyInit.yaml b/murano/tests/unit/dsl/meta/PropertyInit.yaml index 006b723a..02131c55 100644 --- a/murano/tests/unit/dsl/meta/PropertyInit.yaml +++ b/murano/tests/unit/dsl/meta/PropertyInit.yaml @@ -1,11 +1,43 @@ Name: PropertyInit Properties: - runtimeProperty: + runtimePropertyWithoutDefault: Usage: Runtime Contract: $.string() + runtimePropertyWithStrictContractWithoutDefault: + Usage: Runtime + Contract: $.string().notNull() + + runtimeProperty2WithStrictContractWithoutDefault: + Usage: Runtime + Contract: $.string().notNull() + + agentListener: + Contract: $.class('io.murano.system.AgentListener') + + runtimePropertyWithStrictContractAndDefault: + Usage: Runtime + Contract: $.string().notNull() + Default: DEFAULT + Methods: - testPropertyAccess: + initialize: Body: - - Return: $this.runtimeProperty + $.runtimePropertyWithStrictContractWithoutDefault: VALUE + + testRuntimePropertyWithoutDefault: + Body: + - Return: $this.runtimePropertyWithoutDefault + + testRuntimePropertyDefault: + Body: + - Return: $this.runtimePropertyWithStrictContractAndDefault + + testRuntimePropertyWithStrictContractWithoutDefault: + Body: + - Return: $this.runtimePropertyWithStrictContractWithoutDefault + + testUninitializedRuntimeProperty: + Body: + - Return: $this.runtimeProperty2WithStrictContractWithoutDefault diff --git a/murano/tests/unit/dsl/test_property_access.py b/murano/tests/unit/dsl/test_property_access.py index 1ed9219f..aa334d18 100644 --- a/murano/tests/unit/dsl/test_property_access.py +++ b/murano/tests/unit/dsl/test_property_access.py @@ -41,7 +41,7 @@ class TestPropertyAccess(test_case.DslTestCase): exceptions.UninitializedPropertyAccessError, self._runner.testUninitializedPrivatePropertyAccess) self.assertEqual( - 'Access to private uninitialized property privateName ' + 'Access to uninitialized property privateName ' 'in class SampleClass3 is forbidden', str(e)) def test_read_of_private_property_of_other_class(self): @@ -113,8 +113,3 @@ class TestPropertyAccess(test_case.DslTestCase): exceptions.NoWriteAccessError, self._runner.on(self._multi_derived). testModifyUsageTestProperty6) - - def test_runtime_properties_skipped_on_initialize(self): - model = om.Object('PropertyInit', runtimeProperty='value') - runner = self.new_runner(model) - self.assertRaises(KeyError, runner.testPropertyAccess) diff --git a/murano/tests/unit/dsl/test_property_inititialization.py b/murano/tests/unit/dsl/test_property_inititialization.py new file mode 100644 index 00000000..ef91ea17 --- /dev/null +++ b/murano/tests/unit/dsl/test_property_inititialization.py @@ -0,0 +1,46 @@ +# Copyright (c) 2014 Mirantis, Inc. +# +# 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. + +from murano.dsl import exceptions +from murano.tests.unit.dsl.foundation import object_model as om +from murano.tests.unit.dsl.foundation import test_case + + +class TestPropertyInitialization(test_case.DslTestCase): + def setUp(self): + super(TestPropertyInitialization, self).setUp() + model = om.Object( + 'PropertyInit' + ) + self._runner = self.new_runner(model) + + def test_runtime_property_default(self): + self.assertEqual( + 'DEFAULT', + self._runner.testRuntimePropertyDefault()) + + def test_runtime_property_without_default(self): + self.assertRaises( + exceptions.UninitializedPropertyAccessError, + self._runner.testRuntimePropertyWithoutDefault) + + def test_runtime_property_with_strict_contract_without_default(self): + self.assertEqual( + 'VALUE', + self._runner.testRuntimePropertyWithStrictContractWithoutDefault()) + + def test_uninitialized_runtime_property_with_strict_contract(self): + self.assertRaises( + exceptions.UninitializedPropertyAccessError, + self._runner.testUninitializedRuntimeProperty)