Unit tests for contracts
in addition to unit tests: * in MuranoObject parent property renamed to owner * fixed ownership of temporary method arguments * more descriptive exceptions in contracts and related places Change-Id: I4ee491c5428a4a64a21ccb5b1947acac386eb78f Closes-Bug: #1337225 Partial-Bug: #1316786
This commit is contained in:
parent
803b5f83e4
commit
ac21005828
@ -47,6 +47,12 @@ class NoPackageForClassFound(Exception):
|
||||
'is not found' % name)
|
||||
|
||||
|
||||
class NoObjectFoundError(Exception):
|
||||
def __init__(self, object_id):
|
||||
super(NoObjectFoundError, self).__init__(
|
||||
'Object %s is not found in object store' % object_id)
|
||||
|
||||
|
||||
class AmbiguousMethodName(Exception):
|
||||
def __init__(self, name):
|
||||
super(AmbiguousMethodName, self).__init__(
|
||||
@ -57,3 +63,19 @@ class NoWriteAccess(Exception):
|
||||
def __init__(self, name):
|
||||
super(NoWriteAccess, self).__init__(
|
||||
'Property %s is immutable to the caller' % name)
|
||||
|
||||
|
||||
class DslContractSyntaxError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ContractViolationException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ValueIsMissingError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class DslSyntaxError(Exception):
|
||||
pass
|
||||
|
@ -189,7 +189,7 @@ class MuranoDslExecutor(object):
|
||||
value = value()
|
||||
arg_spec = arguments_scheme[name]
|
||||
parameter_values[name] = arg_spec.validate(
|
||||
value, this, self._root_context, self._object_store)
|
||||
value, this, None, self._root_context, self._object_store)
|
||||
|
||||
for name, arg_spec in arguments_scheme.iteritems():
|
||||
if name not in parameter_values:
|
||||
@ -199,7 +199,7 @@ class MuranoDslExecutor(object):
|
||||
this, this.type, context)
|
||||
parameter_values[name] = arg_spec.validate(
|
||||
helpers.evaluate(arg_spec.default, parameter_context),
|
||||
this, self._root_context, self._object_store)
|
||||
this, None, self._root_context, self._object_store)
|
||||
|
||||
return parameter_values
|
||||
|
||||
|
@ -175,17 +175,17 @@ class MuranoClass(object):
|
||||
return True
|
||||
return False
|
||||
|
||||
def new(self, parent, object_store, context, parameters=None,
|
||||
def new(self, owner, object_store, context, parameters=None,
|
||||
object_id=None, **kwargs):
|
||||
|
||||
obj = self.object_class(self, parent, object_store, context,
|
||||
obj = self.object_class(self, owner, object_store, context,
|
||||
object_id=object_id, **kwargs)
|
||||
if parameters is not None:
|
||||
argspec = inspect.getargspec(obj.initialize).args
|
||||
if '_context' in argspec:
|
||||
parameters['_context'] = context
|
||||
if '_parent' in argspec:
|
||||
parameters['_parent'] = parent
|
||||
if '_owner' in argspec:
|
||||
parameters['_owner'] = owner
|
||||
obj.initialize(**parameters)
|
||||
return obj
|
||||
|
||||
|
@ -24,12 +24,12 @@ import murano.dsl.typespec as typespec
|
||||
|
||||
|
||||
class MuranoObject(object):
|
||||
def __init__(self, murano_class, parent_obj, object_store, context,
|
||||
def __init__(self, murano_class, owner, object_store, context,
|
||||
object_id=None, known_classes=None, defaults=None, this=None):
|
||||
|
||||
if known_classes is None:
|
||||
known_classes = {}
|
||||
self.__parent_obj = parent_obj
|
||||
self.__owner = owner
|
||||
self.__object_id = object_id or murano.dsl.helpers.generate_id()
|
||||
self.__type = murano_class
|
||||
self.__properties = {}
|
||||
@ -42,7 +42,7 @@ class MuranoObject(object):
|
||||
for parent_class in murano_class.parents:
|
||||
name = parent_class.name
|
||||
if name not in known_classes:
|
||||
obj = parent_class.new(parent_obj, object_store, context,
|
||||
obj = parent_class.new(owner, object_store, context,
|
||||
None, object_id=self.__object_id,
|
||||
known_classes=known_classes,
|
||||
defaults=defaults, this=self.real_this)
|
||||
@ -75,8 +75,8 @@ class MuranoObject(object):
|
||||
return self.__type
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
return self.__parent_obj
|
||||
def owner(self):
|
||||
return self.__owner
|
||||
|
||||
@property
|
||||
def real_this(self):
|
||||
@ -145,7 +145,8 @@ class MuranoObject(object):
|
||||
default = murano.dsl.helpers.evaluate(default, child_context, 1)
|
||||
|
||||
self.__properties[key] = spec.validate(
|
||||
value, self, self.__context, self.__object_store, default)
|
||||
value, self, self, self.__context,
|
||||
self.__object_store, default)
|
||||
else:
|
||||
for parent in self.__parents.values():
|
||||
try:
|
||||
|
@ -46,9 +46,7 @@ class ObjectStore(object):
|
||||
def put(self, murano_object):
|
||||
self._store[murano_object.object_id] = murano_object
|
||||
|
||||
def load(self, value, parent, context, defaults=None):
|
||||
#tmp_store = ObjectStore(self._class_loader, self)
|
||||
|
||||
def load(self, value, owner, context, defaults=None):
|
||||
if value is None:
|
||||
return None
|
||||
if '?' not in value or 'type' not in value['?']:
|
||||
@ -62,7 +60,7 @@ class ObjectStore(object):
|
||||
if object_id in self._store:
|
||||
obj = self._store[object_id]
|
||||
else:
|
||||
obj = class_obj.new(parent, self, context=context,
|
||||
obj = class_obj.new(owner, self, context=context,
|
||||
object_id=object_id, defaults=defaults)
|
||||
self._store[object_id] = obj
|
||||
self._designer_attributes_store[object_id] = \
|
||||
@ -72,17 +70,17 @@ class ObjectStore(object):
|
||||
if '_context' in argspec:
|
||||
value['_context'] = context
|
||||
if '_parent' in argspec:
|
||||
value['_parent'] = parent
|
||||
value['_owner'] = owner
|
||||
|
||||
try:
|
||||
if parent is None:
|
||||
if owner is None:
|
||||
self._initializing = True
|
||||
obj.initialize(**value)
|
||||
if parent is None:
|
||||
if owner is None:
|
||||
self._initializing = False
|
||||
obj.initialize(**value)
|
||||
finally:
|
||||
if parent is None:
|
||||
if owner is None:
|
||||
self._initializing = False
|
||||
|
||||
if not self.initializing:
|
||||
|
@ -89,7 +89,7 @@ def _pass1_serialize(value, parent, serialized_objects,
|
||||
types.BooleanType, types.NoneType)):
|
||||
return value
|
||||
elif isinstance(value, murano_object.MuranoObject):
|
||||
if not _cmp_objects(value.parent, parent) \
|
||||
if not _cmp_objects(value.owner, parent) \
|
||||
or value.object_id in serialized_objects:
|
||||
return ObjRef(value)
|
||||
else:
|
||||
|
@ -18,6 +18,7 @@ import uuid
|
||||
|
||||
import yaql.context
|
||||
|
||||
from murano.dsl import exceptions
|
||||
import murano.dsl.helpers
|
||||
import murano.dsl.murano_object
|
||||
import murano.dsl.yaql_expression as yaql_expression
|
||||
@ -35,7 +36,7 @@ class TypeScheme(object):
|
||||
self._spec = spec
|
||||
|
||||
@staticmethod
|
||||
def prepare_context(root_context, this, object_store,
|
||||
def prepare_context(root_context, this, owner, object_store,
|
||||
namespace_resolver, default):
|
||||
def _int(value):
|
||||
value = value()
|
||||
@ -46,7 +47,8 @@ class TypeScheme(object):
|
||||
try:
|
||||
return int(value)
|
||||
except Exception:
|
||||
raise TypeError()
|
||||
raise exceptions.ContractViolationException(
|
||||
'Value {0} violates int() contract'.format(value))
|
||||
|
||||
def _string(value):
|
||||
value = value()
|
||||
@ -57,7 +59,8 @@ class TypeScheme(object):
|
||||
try:
|
||||
return unicode(value)
|
||||
except Exception:
|
||||
raise TypeError()
|
||||
raise exceptions.ContractViolationException(
|
||||
'Value {0} violates string() contract'.format(value))
|
||||
|
||||
def _bool(value):
|
||||
value = value()
|
||||
@ -74,18 +77,20 @@ class TypeScheme(object):
|
||||
return value
|
||||
|
||||
if value is None:
|
||||
raise TypeError()
|
||||
raise exceptions.ContractViolationException(
|
||||
'null value violates notNull() contract')
|
||||
return value
|
||||
|
||||
def _error():
|
||||
raise TypeError()
|
||||
raise exceptions.ContractViolationException('error() contract')
|
||||
|
||||
def _check(value, predicate):
|
||||
value = value()
|
||||
if isinstance(value, TypeScheme.ObjRef) or predicate(value):
|
||||
return value
|
||||
else:
|
||||
raise TypeError(value)
|
||||
raise exceptions.ContractViolationException(
|
||||
"Value {0} doesn't match predicate".format(value))
|
||||
|
||||
@yaql.context.EvalArg('obj', arg_type=(
|
||||
murano.dsl.murano_object.MuranoObject,
|
||||
@ -98,10 +103,16 @@ class TypeScheme(object):
|
||||
|
||||
if obj is None:
|
||||
return None
|
||||
elif obj.parent is this:
|
||||
return obj
|
||||
else:
|
||||
raise TypeError()
|
||||
|
||||
p = obj.owner
|
||||
while p is not None:
|
||||
if p is this:
|
||||
return obj
|
||||
p = p.owner
|
||||
|
||||
raise exceptions.ContractViolationException(
|
||||
'Object {0} violates owned() contract'.format(
|
||||
obj.object_id))
|
||||
|
||||
@yaql.context.EvalArg('obj', arg_type=(
|
||||
murano.dsl.murano_object.MuranoObject,
|
||||
@ -114,10 +125,15 @@ class TypeScheme(object):
|
||||
|
||||
if obj is None:
|
||||
return None
|
||||
elif obj.parent is this:
|
||||
raise TypeError()
|
||||
else:
|
||||
|
||||
try:
|
||||
_owned(obj)
|
||||
except exceptions.ContractViolationException:
|
||||
return obj
|
||||
else:
|
||||
raise exceptions.ContractViolationException(
|
||||
'Object {0} violates notOwned() contract'.format(
|
||||
obj.object_id))
|
||||
|
||||
@yaql.context.EvalArg('name', arg_type=str)
|
||||
def _class(value, name):
|
||||
@ -132,35 +148,41 @@ class TypeScheme(object):
|
||||
else:
|
||||
default_name = namespace_resolver.resolve_name(default_name)
|
||||
value = value()
|
||||
if value is NoValue:
|
||||
value = default
|
||||
if isinstance(default, types.DictionaryType):
|
||||
value = {'?': {
|
||||
'id': uuid.uuid4().hex,
|
||||
'type': default_name
|
||||
}}
|
||||
class_loader = murano.dsl.helpers.get_class_loader(root_context)
|
||||
murano_class = class_loader.get_class(name)
|
||||
if not murano_class:
|
||||
raise TypeError()
|
||||
raise exceptions.NoClassFound(
|
||||
'Class {0} cannot be found'.format(name))
|
||||
if value is None:
|
||||
return None
|
||||
if isinstance(value, murano.dsl.murano_object.MuranoObject):
|
||||
obj = value
|
||||
elif isinstance(value, types.DictionaryType):
|
||||
obj = object_store.load(value, this, root_context,
|
||||
if '?' not in value:
|
||||
new_value = {'?': {
|
||||
'id': uuid.uuid4().hex,
|
||||
'type': default_name
|
||||
}}
|
||||
new_value.update(value)
|
||||
value = new_value
|
||||
|
||||
obj = object_store.load(value, owner, root_context,
|
||||
defaults=default)
|
||||
elif isinstance(value, types.StringTypes):
|
||||
obj = object_store.get(value)
|
||||
if obj is None:
|
||||
if not object_store.initializing:
|
||||
raise TypeError('Object %s not found' % value)
|
||||
raise exceptions.NoObjectFoundError(value)
|
||||
else:
|
||||
return TypeScheme.ObjRef(value)
|
||||
else:
|
||||
raise TypeError()
|
||||
raise exceptions.ContractViolationException(
|
||||
'Value {0} cannot be represented as class {1}'.format(
|
||||
value, name))
|
||||
if not murano_class.is_compatible(obj):
|
||||
raise TypeError()
|
||||
raise exceptions.ContractViolationException(
|
||||
'Object of type {0} is not compatible with '
|
||||
'requested type {1}'.format(obj.type.name, name))
|
||||
return obj
|
||||
|
||||
@yaql.context.EvalArg('prefix', str)
|
||||
@ -187,7 +209,8 @@ class TypeScheme(object):
|
||||
if data is None or data is NoValue:
|
||||
data = {}
|
||||
if not isinstance(data, types.DictionaryType):
|
||||
raise TypeError()
|
||||
raise exceptions.ContractViolationException(
|
||||
'Supplied is not of a dictionary type')
|
||||
if not spec:
|
||||
return data
|
||||
result = {}
|
||||
@ -195,7 +218,9 @@ class TypeScheme(object):
|
||||
for key, value in spec.iteritems():
|
||||
if isinstance(key, yaql_expression.YaqlExpression):
|
||||
if yaql_key is not None:
|
||||
raise SyntaxError()
|
||||
raise exceptions.DslContractSyntaxError(
|
||||
'Dictionary contract '
|
||||
'cannot have more than one expression keys')
|
||||
else:
|
||||
yaql_key = key
|
||||
else:
|
||||
@ -232,7 +257,9 @@ class TypeScheme(object):
|
||||
shift += 1
|
||||
|
||||
if not min_length <= len(data) <= max_length:
|
||||
raise TypeError()
|
||||
raise exceptions.ContractViolationException(
|
||||
'Array length {0} is not within [{1}..{2}] range'.format(
|
||||
len(data), min_length, max_length))
|
||||
|
||||
for index, item in enumerate(data):
|
||||
spec_item = spec[-1 - shift] \
|
||||
@ -242,7 +269,8 @@ class TypeScheme(object):
|
||||
|
||||
def _map_scalar(self, data, spec):
|
||||
if data != spec:
|
||||
raise TypeError()
|
||||
raise exceptions.ContractViolationException(
|
||||
'Value {0} is not equal to {1}'.format(data, spec))
|
||||
else:
|
||||
return data
|
||||
|
||||
@ -260,7 +288,7 @@ class TypeScheme(object):
|
||||
types.NoneType)):
|
||||
return self._map_scalar(data, spec)
|
||||
|
||||
def __call__(self, data, context, this, object_store,
|
||||
def __call__(self, data, context, this, owner, object_store,
|
||||
namespace_resolver, default):
|
||||
# TODO(ativelkov, slagun): temporary fix, need a better way of handling
|
||||
# composite defaults
|
||||
@ -270,9 +298,5 @@ class TypeScheme(object):
|
||||
data = default
|
||||
|
||||
context = self.prepare_context(
|
||||
context, this, object_store, namespace_resolver,
|
||||
default)
|
||||
result = self._map(data, self._spec, context)
|
||||
if result is NoValue:
|
||||
raise TypeError('No type specified')
|
||||
return result
|
||||
context, this, owner, object_store, namespace_resolver, default)
|
||||
return self._map(data, self._spec, context)
|
||||
|
@ -12,6 +12,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from murano.dsl import exceptions
|
||||
import murano.dsl.type_scheme as type_scheme
|
||||
|
||||
|
||||
@ -33,13 +34,15 @@ class Spec(object):
|
||||
self._has_default = 'Default' in declaration
|
||||
self._usage = declaration.get('Usage') or 'In'
|
||||
if self._usage not in PropertyUsages.All:
|
||||
raise SyntaxError('Unknown type {0}. Must be one of ({1})'.format(
|
||||
self._usage, ', '.join(PropertyUsages.All)))
|
||||
raise exceptions.DslSyntaxError(
|
||||
'Unknown type {0}. Must be one of ({1})'.format(
|
||||
self._usage, ', '.join(PropertyUsages.All)))
|
||||
|
||||
def validate(self, value, this, context, object_store, default=None):
|
||||
def validate(self, value, this, owner, context,
|
||||
object_store, default=None):
|
||||
if default is None:
|
||||
default = self.default
|
||||
return self._contract(value, context, this, object_store,
|
||||
return self._contract(value, context, this, owner, object_store,
|
||||
self._namespace_resolver, default)
|
||||
|
||||
@property
|
||||
|
@ -124,11 +124,11 @@ def _get_container(context, obj, class_name):
|
||||
class_loader = helpers.get_class_loader(context)
|
||||
class_name = namespace_resolver.resolve_name(class_name)
|
||||
murano_class = class_loader.get_class(class_name)
|
||||
p = obj.parent
|
||||
p = obj.owner
|
||||
while p is not None:
|
||||
if murano_class.is_compatible(p):
|
||||
return p
|
||||
p = p.parent
|
||||
p = p.owner
|
||||
return None
|
||||
|
||||
|
||||
|
137
murano/tests/dsl/meta/ContractExamples.yaml
Normal file
137
murano/tests/dsl/meta/ContractExamples.yaml
Normal file
@ -0,0 +1,137 @@
|
||||
Name: ContractExamples
|
||||
|
||||
Properties:
|
||||
sampleClass:
|
||||
Contract: $.class(SampleClass1)
|
||||
|
||||
Methods:
|
||||
testStringContract:
|
||||
Arguments:
|
||||
arg:
|
||||
Contract: $.string()
|
||||
Body:
|
||||
Return: $arg
|
||||
|
||||
testIntContract:
|
||||
Arguments:
|
||||
arg:
|
||||
Contract: $.int()
|
||||
Body:
|
||||
Return: $arg
|
||||
|
||||
testBoolContract:
|
||||
Arguments:
|
||||
arg:
|
||||
Contract: $.bool()
|
||||
Body:
|
||||
Return: $arg
|
||||
|
||||
testClassContract:
|
||||
Arguments:
|
||||
arg:
|
||||
Contract: $.class(SampleClass2)
|
||||
Body:
|
||||
Return: $arg
|
||||
|
||||
testClassFromIdContract:
|
||||
Arguments:
|
||||
arg:
|
||||
Contract: $.class(SampleClass1)
|
||||
Body:
|
||||
Return: $arg
|
||||
|
||||
testCheckContract:
|
||||
Arguments:
|
||||
- arg1:
|
||||
Contract: $.class(SampleClass2).check($.class2Property = qwerty)
|
||||
- arg2:
|
||||
Contract: $.int().check($ > 10)
|
||||
|
||||
testOwnedContract:
|
||||
Arguments:
|
||||
- arg1:
|
||||
Contract: $.class(SampleClass1).owned()
|
||||
- arg2:
|
||||
Contract: $.class(SampleClass2).owned()
|
||||
|
||||
testNotOwnedContract:
|
||||
Arguments:
|
||||
- arg1:
|
||||
Contract: $.class(SampleClass1).notOwned()
|
||||
- arg2:
|
||||
Contract: $.class(SampleClass2).notOwned()
|
||||
|
||||
testScalarContract:
|
||||
Arguments:
|
||||
- arg1:
|
||||
Contract: 'fixed'
|
||||
- arg2:
|
||||
Contract: 456
|
||||
- arg3:
|
||||
Contract: true
|
||||
Body:
|
||||
Return: $arg1
|
||||
|
||||
testListContract:
|
||||
Arguments:
|
||||
- arg:
|
||||
Contract: [$.int()]
|
||||
Body:
|
||||
Return: $arg
|
||||
|
||||
testListWithMinLengthContract:
|
||||
Arguments:
|
||||
- arg:
|
||||
Contract: [$.int(), 3]
|
||||
Body:
|
||||
Return: $arg
|
||||
|
||||
testListWithMinMaxLengthContract:
|
||||
Arguments:
|
||||
- arg:
|
||||
Contract: [$.int(), 2, 4]
|
||||
Body:
|
||||
Return: $arg
|
||||
|
||||
testDictContract:
|
||||
Arguments:
|
||||
- arg:
|
||||
Contract:
|
||||
A: $.string()
|
||||
B: $.int()
|
||||
Body:
|
||||
Return: $arg
|
||||
|
||||
testDictExprContract:
|
||||
Arguments:
|
||||
- arg:
|
||||
Contract:
|
||||
$.int(): $.string()
|
||||
B: $.int()
|
||||
Body:
|
||||
Return: $arg
|
||||
|
||||
testDictMultiExprContract:
|
||||
Arguments:
|
||||
- arg:
|
||||
Contract:
|
||||
$.int(): $.string()
|
||||
$.string(): $.int()
|
||||
Body:
|
||||
Return: $arg
|
||||
|
||||
testNotNullContract:
|
||||
Arguments:
|
||||
- arg:
|
||||
Contract: $.notNull()
|
||||
Body:
|
||||
Return: $arg
|
||||
|
||||
testDefault:
|
||||
Arguments:
|
||||
- arg:
|
||||
Contract: $.string()
|
||||
Default: DEFAULT
|
||||
Body:
|
||||
Return: $arg
|
||||
|
292
murano/tests/dsl/test_contracts.py
Normal file
292
murano/tests/dsl/test_contracts.py
Normal file
@ -0,0 +1,292 @@
|
||||
# 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.
|
||||
|
||||
import types
|
||||
|
||||
from murano.dsl import exceptions
|
||||
from murano.dsl import murano_object
|
||||
from murano.tests.dsl.foundation import object_model as om
|
||||
from murano.tests.dsl.foundation import test_case
|
||||
|
||||
|
||||
class TestContracts(test_case.DslTestCase):
|
||||
def setUp(self):
|
||||
super(TestContracts, self).setUp()
|
||||
self._runner = self.new_runner(
|
||||
om.Object(
|
||||
'ContractExamples',
|
||||
sampleClass=om.Object(
|
||||
'SampleClass1',
|
||||
stringProperty='string1',
|
||||
classProperty=om.Object(
|
||||
'SampleClass2',
|
||||
class2Property='string2'))))
|
||||
|
||||
def test_string_contract(self):
|
||||
result = self._runner.testStringContract('qwerty')
|
||||
self.assertIsInstance(result, types.StringTypes)
|
||||
self.assertEqual(result, 'qwerty')
|
||||
|
||||
def test_string_from_number_contract(self):
|
||||
result = self._runner.testStringContract(123)
|
||||
self.assertIsInstance(result, types.StringTypes)
|
||||
self.assertEqual(result, '123')
|
||||
|
||||
def test_string_null_contract(self):
|
||||
self.assertIsNone(self._runner.testStringContract(None))
|
||||
|
||||
def test_int_contract(self):
|
||||
result = self._runner.testIntContract(123)
|
||||
self.assertIsInstance(result, int)
|
||||
self.assertEqual(result, 123)
|
||||
|
||||
def test_int_from_string_contract(self):
|
||||
result = self._runner.testIntContract('456')
|
||||
self.assertIsInstance(result, int)
|
||||
self.assertEqual(result, 456)
|
||||
|
||||
def test_int_from_string_contract_failure(self):
|
||||
self.assertRaises(exceptions.ContractViolationException,
|
||||
self._runner.testIntContract, 'nan')
|
||||
|
||||
def test_int_null_contract(self):
|
||||
self.assertIsNone(self._runner.testIntContract(None))
|
||||
|
||||
def test_bool_contract(self):
|
||||
result = self._runner.testBoolContract(True)
|
||||
self.assertIsInstance(result, bool)
|
||||
self.assertIs(result, True)
|
||||
|
||||
result = self._runner.testBoolContract(False)
|
||||
self.assertIsInstance(result, bool)
|
||||
self.assertIs(result, False)
|
||||
|
||||
def test_bool_from_int_contract(self):
|
||||
result = self._runner.testBoolContract(10)
|
||||
self.assertIsInstance(result, bool)
|
||||
self.assertIs(result, True)
|
||||
|
||||
result = self._runner.testBoolContract(0)
|
||||
self.assertIsInstance(result, bool)
|
||||
self.assertIs(result, False)
|
||||
|
||||
def test_bool_from_string_contract(self):
|
||||
result = self._runner.testBoolContract('something')
|
||||
self.assertIsInstance(result, bool)
|
||||
self.assertIs(result, True)
|
||||
|
||||
result = self._runner.testBoolContract('')
|
||||
self.assertIsInstance(result, bool)
|
||||
self.assertIs(result, False)
|
||||
|
||||
def test_bool_null_contract(self):
|
||||
self.assertIsNone(self._runner.testIntContract(None))
|
||||
|
||||
def test_class_contract(self):
|
||||
arg = om.Object('SampleClass2', class2Property='qwerty')
|
||||
result = self._runner.testClassContract(arg)
|
||||
self.assertIsInstance(result, murano_object.MuranoObject)
|
||||
|
||||
def test_class_contract_by_ref(self):
|
||||
arg = om.Object('SampleClass2', class2Property='qwerty')
|
||||
result = self._runner.testClassContract(arg)
|
||||
self.assertEqual(result.object_id, arg.id)
|
||||
|
||||
def test_class_contract_failure(self):
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self._runner.testClassContract, ['invalid type'])
|
||||
|
||||
def test_class_contract_by_ref_failure(self):
|
||||
self.assertRaises(
|
||||
exceptions.NoObjectFoundError,
|
||||
self._runner.testClassContract, 'NoSuchIdExists')
|
||||
|
||||
def test_class_contract_from_dict(self):
|
||||
self.assertEqual(
|
||||
'SampleClass2',
|
||||
self._runner.testClassContract({
|
||||
'class2Property': 'str'}).type.name)
|
||||
|
||||
def test_class_from_id_contract(self):
|
||||
object_id = self._runner.root.get_property('sampleClass').object_id
|
||||
result = self._runner.testClassFromIdContract(object_id)
|
||||
self.assertIsInstance(result, murano_object.MuranoObject)
|
||||
self.assertEqual(result.object_id, object_id)
|
||||
|
||||
def test_check_contract(self):
|
||||
arg = om.Object('SampleClass2', class2Property='qwerty')
|
||||
self.assertIsNone(self._runner.testCheckContract(arg, 100))
|
||||
|
||||
def test_check_contract_failure(self):
|
||||
invalid_arg = om.Object('SampleClass2', class2Property='not qwerty')
|
||||
self.assertRaises(exceptions.ContractViolationException,
|
||||
self._runner.testCheckContract, invalid_arg, 100)
|
||||
|
||||
def test_owned_contract(self):
|
||||
arg1 = self._runner.root.get_property('sampleClass')
|
||||
arg2 = arg1.get_property('classProperty')
|
||||
self.assertIsNone(self._runner.testOwnedContract(arg1, arg2))
|
||||
|
||||
def test_owned_contract_on_null(self):
|
||||
self.assertIsNone(self._runner.testOwnedContract(None, None))
|
||||
|
||||
def test_owned_contract_failure(self):
|
||||
arg1 = self._runner.root.get_property('sampleClass')
|
||||
arg2 = arg1.get_property('classProperty')
|
||||
invalid_arg2 = om.Object('SampleClass2', class2Property='string2')
|
||||
invalid_arg1 = om.Object(
|
||||
'SampleClass1',
|
||||
stringProperty='string1',
|
||||
classProperty=invalid_arg2)
|
||||
|
||||
self.assertRaises(exceptions.ContractViolationException,
|
||||
self._runner.testOwnedContract, invalid_arg1, arg2)
|
||||
self.assertRaises(exceptions.ContractViolationException,
|
||||
self._runner.testOwnedContract, invalid_arg2, arg1)
|
||||
|
||||
def test_not_owned_contract(self):
|
||||
arg2 = om.Object('SampleClass2', class2Property='string2')
|
||||
arg1 = om.Object(
|
||||
'SampleClass1',
|
||||
stringProperty='string1',
|
||||
classProperty=arg2)
|
||||
self.assertIsNone(self._runner.testNotOwnedContract(arg1, arg2))
|
||||
|
||||
def test_not_owned_contract_on_null(self):
|
||||
self.assertIsNone(self._runner.testNotOwnedContract(None, None))
|
||||
|
||||
def test_not_owned_contract_failure(self):
|
||||
invalid_arg1 = self._runner.root.get_property('sampleClass')
|
||||
invalid_arg2 = invalid_arg1.get_property('classProperty')
|
||||
arg2 = om.Object('SampleClass2', class2Property='string2')
|
||||
arg1 = om.Object(
|
||||
'SampleClass1',
|
||||
stringProperty='string1',
|
||||
classProperty=arg2)
|
||||
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self._runner.testNotOwnedContract, invalid_arg1, arg2)
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self._runner.testNotOwnedContract, invalid_arg2, arg1)
|
||||
|
||||
def test_scalar_contract(self):
|
||||
self.assertEqual('fixed', self._runner.testScalarContract(
|
||||
'fixed', 456, True))
|
||||
|
||||
def test_scalar_contract_failure(self):
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self._runner.testScalarContract,
|
||||
'wrong', 456, True)
|
||||
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self._runner.testScalarContract,
|
||||
'fixed', 123, True)
|
||||
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self._runner.testScalarContract,
|
||||
'fixed', 456, False)
|
||||
|
||||
def test_list_contract(self):
|
||||
self.assertEqual([3, 2, 1], self._runner.testListContract(
|
||||
['3', 2, '1']))
|
||||
|
||||
def test_list_contract_from_scalar(self):
|
||||
self.assertEqual([99], self._runner.testListContract('99'))
|
||||
|
||||
def test_list_contract_from_null(self):
|
||||
self.assertEqual([], self._runner.testListContract(None))
|
||||
|
||||
def test_list_with_min_length_contract(self):
|
||||
self.assertEqual(
|
||||
[1, 2, 3],
|
||||
self._runner.testListWithMinLengthContract([1, 2, 3]))
|
||||
self.assertEqual(
|
||||
[1, 2, 3, 4],
|
||||
self._runner.testListWithMinLengthContract([1, 2, 3, 4]))
|
||||
|
||||
def test_list_with_min_length_contract_failure(self):
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self._runner.testListWithMinLengthContract, None)
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self._runner.testListWithMinLengthContract, [1, 2])
|
||||
|
||||
def test_list_with_min_max_length_contract(self):
|
||||
self.assertEqual(
|
||||
[1, 2],
|
||||
self._runner.testListWithMinMaxLengthContract([1, 2]))
|
||||
self.assertEqual(
|
||||
[1, 2, 3, 4],
|
||||
self._runner.testListWithMinMaxLengthContract([1, 2, 3, 4]))
|
||||
|
||||
def test_list_with_min_max_length_contract_failure(self):
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self._runner.testListWithMinMaxLengthContract, [1])
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self._runner.testListWithMinMaxLengthContract, [1, 2, 3, 4, 5])
|
||||
|
||||
def test_dict_contract(self):
|
||||
self.assertEqual(
|
||||
{'A': '123', 'B': 456},
|
||||
self._runner.testDictContract({'A': '123', 'B': '456'}))
|
||||
self.assertEqual(
|
||||
{'A': '123', 'B': 456},
|
||||
self._runner.testDictContract({'A': '123', 'B': '456', 'C': 'qq'}))
|
||||
self.assertEqual(
|
||||
{'A': '123', 'B': None},
|
||||
self._runner.testDictContract({'A': '123'}))
|
||||
|
||||
def test_dict_contract_failure(self):
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self._runner.testDictContract, 'str')
|
||||
|
||||
def test_dict_expressions_contract(self):
|
||||
self.assertEqual(
|
||||
{321: 'qwerty', 99: 'val', 'B': 456},
|
||||
self._runner.testDictExprContract({
|
||||
'321': 'qwerty', '99': 'val', 'B': 456}))
|
||||
|
||||
def test_dict_expressions_contract_failure(self):
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self._runner.testDictExprContract,
|
||||
{'321': 'qwerty', 'str': 'val', 'B': 456})
|
||||
|
||||
def test_invalid_dict_expr_contract(self):
|
||||
self.assertRaises(
|
||||
exceptions.DslContractSyntaxError,
|
||||
self._runner.testDictMultiExprContract,
|
||||
{'321': 'qwerty', 'str': 'val', 'B': 456})
|
||||
|
||||
def test_not_null_contract(self):
|
||||
self.assertEqual('value', self._runner.testNotNullContract('value'))
|
||||
|
||||
def test_not_null_contract_failure(self):
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self._runner.testNotNullContract, None)
|
||||
|
||||
def test_default(self):
|
||||
self.assertEqual('value', self._runner.testDefault('value'))
|
||||
self.assertEqual('DEFAULT', self._runner.testDefault())
|
@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
|
||||
from murano.dsl import dsl_exception
|
||||
from murano.dsl import exceptions
|
||||
from murano.tests.dsl.foundation import object_model as om
|
||||
from murano.tests.dsl.foundation import test_case
|
||||
|
||||
@ -27,10 +28,11 @@ class TestExecution(test_case.DslTestCase):
|
||||
def test_load(self):
|
||||
self._load()
|
||||
|
||||
def test_not_load(self):
|
||||
def try_load():
|
||||
self.new_runner(om.Object('SampleClass1'))
|
||||
self.assertRaises(TypeError, try_load)
|
||||
def test_load_failure(self):
|
||||
self.assertRaises(
|
||||
exceptions.ContractViolationException,
|
||||
self.new_runner,
|
||||
om.Object('SampleClass1'))
|
||||
|
||||
def test_trace(self):
|
||||
runner = self._load()
|
||||
|
Loading…
Reference in New Issue
Block a user