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:
Stan Lagun 2014-07-03 14:24:41 +04:00
parent 803b5f83e4
commit ac21005828
12 changed files with 546 additions and 67 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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:

View File

@ -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:

View File

@ -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)

View File

@ -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

View File

@ -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

View 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

View 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())

View File

@ -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()