Code refactoring and improvements for MuranoPL testing mini-framework
* Stack-traces of caught exceptions are no longer printed in Python 2.6 * No more warning on Exception.message being deprecated * Loaded YAML files are cached instead of being re-read for each test greatly increasing performance without side effects because class-loader is still new on each test * object_model helper objects can be used as a test method arguments * Path to core library classes was relative to the test. That prevented grouping tests into sub-folders * Preserve original stack-trace for Python exceptions thrown by the engine * Ability to delete (clear) traces (produced by calls to trace(...) in MuranoPL code) * Code refactoring Change-Id: Ifab8460d3a188c6e05edd682a302e2a8a6dd0425
This commit is contained in:
@@ -59,16 +59,17 @@ class MuranoClassLoader(object):
|
|||||||
namespaces = data.get('Namespaces', {})
|
namespaces = data.get('Namespaces', {})
|
||||||
ns_resolver = namespace_resolver.NamespaceResolver(namespaces)
|
ns_resolver = namespace_resolver.NamespaceResolver(namespaces)
|
||||||
|
|
||||||
class_parents = data.get('Extends')
|
parent_class_names = data.get('Extends')
|
||||||
if class_parents:
|
parent_classes = []
|
||||||
if not isinstance(class_parents, types.ListType):
|
if parent_class_names:
|
||||||
class_parents = [class_parents]
|
if not isinstance(parent_class_names, types.ListType):
|
||||||
for i, parent_name in enumerate(class_parents):
|
parent_class_names = [parent_class_names]
|
||||||
|
for parent_name in parent_class_names:
|
||||||
full_name = ns_resolver.resolve_name(parent_name)
|
full_name = ns_resolver.resolve_name(parent_name)
|
||||||
class_parents[i] = self.get_class(full_name)
|
parent_classes.append(self.get_class(full_name))
|
||||||
|
|
||||||
type_obj = murano_class.MuranoClass(self, ns_resolver, name,
|
type_obj = murano_class.MuranoClass(self, ns_resolver, name,
|
||||||
package, class_parents)
|
package, parent_classes)
|
||||||
|
|
||||||
properties = data.get('Properties', {})
|
properties = data.get('Properties', {})
|
||||||
for property_name, property_spec in properties.iteritems():
|
for property_name, property_spec in properties.iteritems():
|
||||||
|
@@ -12,6 +12,8 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
import murano.dsl.yaql_functions as yaql_functions
|
import murano.dsl.yaql_functions as yaql_functions
|
||||||
|
|
||||||
|
|
||||||
@@ -55,8 +57,10 @@ class MuranoPlException(Exception):
|
|||||||
exception_type.__name__)]
|
exception_type.__name__)]
|
||||||
|
|
||||||
result = MuranoPlException(
|
result = MuranoPlException(
|
||||||
names, exception.message, stacktrace)
|
names, str(exception), stacktrace)
|
||||||
|
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||||
result.original_exception = exception
|
result.original_exception = exception
|
||||||
|
result.original_traceback = exc_traceback
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _format_name(self):
|
def _format_name(self):
|
||||||
|
@@ -25,10 +25,18 @@ class Object(object):
|
|||||||
}
|
}
|
||||||
self.data.update(kwargs)
|
self.data.update(kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self):
|
||||||
|
return self.data['?']['id']
|
||||||
|
|
||||||
|
|
||||||
class Ref(object):
|
class Ref(object):
|
||||||
def __init__(self, obj):
|
def __init__(self, obj):
|
||||||
self.id = obj.data['?']['id']
|
self._id = obj.id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self):
|
||||||
|
return self._id
|
||||||
|
|
||||||
|
|
||||||
def build_model(root):
|
def build_model(root):
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
import types
|
import types
|
||||||
|
|
||||||
from murano.dsl import dsl_exception
|
from murano.dsl import dsl_exception
|
||||||
@@ -29,15 +30,13 @@ class Runner(object):
|
|||||||
self._runner = runner
|
self._runner = runner
|
||||||
if isinstance(obj, types.StringTypes):
|
if isinstance(obj, types.StringTypes):
|
||||||
self._object_id = obj
|
self._object_id = obj
|
||||||
elif isinstance(obj, object_model.Object):
|
elif isinstance(obj, (object_model.Object, object_model.Ref)):
|
||||||
self._object_id = obj.data['?']['id']
|
self._object_id = obj.id
|
||||||
elif isinstance(obj, murano_object.MuranoObject):
|
elif isinstance(obj, murano_object.MuranoObject):
|
||||||
self._object_id = obj.object_id
|
self._object_id = obj.object_id
|
||||||
elif isinstance(obj, object_model.Ref):
|
|
||||||
self._object_id = obj.id
|
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
'obj should be object ID string, MuranoObject or one of '
|
'obj must be object ID string, MuranoObject or one of '
|
||||||
'object_model helper classes (Object, Ref)')
|
'object_model helper classes (Object, Ref)')
|
||||||
self._preserve_exception = False
|
self._preserve_exception = False
|
||||||
|
|
||||||
@@ -58,32 +57,46 @@ class Runner(object):
|
|||||||
|
|
||||||
self.executor = executor.MuranoDslExecutor(
|
self.executor = executor.MuranoDslExecutor(
|
||||||
class_loader, environment.Environment())
|
class_loader, environment.Environment())
|
||||||
self.root = self.executor.load(model)
|
self._root = self.executor.load(model)
|
||||||
|
|
||||||
def _execute(self, name, object_id, *args, **kwargs):
|
def _execute(self, name, object_id, *args, **kwargs):
|
||||||
obj = self.executor.object_store.get(object_id)
|
obj = self.executor.object_store.get(object_id)
|
||||||
try:
|
try:
|
||||||
return obj.type.invoke(
|
final_args = []
|
||||||
name, self.executor, obj,
|
for arg in args:
|
||||||
tuple(list(args) + kwargs.items()))
|
if isinstance(arg, object_model.Object):
|
||||||
|
arg = object_model.build_model(arg)
|
||||||
|
final_args.append(arg)
|
||||||
|
for name, arg in kwargs.iteritems():
|
||||||
|
if isinstance(arg, object_model.Object):
|
||||||
|
arg = object_model.build_model(arg)
|
||||||
|
final_args.append({name: arg})
|
||||||
|
return obj.type.invoke(name, self.executor, obj, tuple(final_args))
|
||||||
except dsl_exception.MuranoPlException as e:
|
except dsl_exception.MuranoPlException as e:
|
||||||
if not self.preserve_exception:
|
if not self.preserve_exception:
|
||||||
original_exception = getattr(e, 'original_exception', None)
|
original_exception = getattr(e, 'original_exception', None)
|
||||||
if not isinstance(original_exception,
|
if original_exception and not isinstance(
|
||||||
dsl_exception.MuranoPlException):
|
original_exception, dsl_exception.MuranoPlException):
|
||||||
raise original_exception
|
exc_traceback = getattr(
|
||||||
|
e, 'original_traceback', None) or sys.exc_info()[2]
|
||||||
|
raise type(original_exception), original_exception, \
|
||||||
|
exc_traceback
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def __getattr__(self, item):
|
def __getattr__(self, item):
|
||||||
if item.startswith('test'):
|
if item.startswith('test'):
|
||||||
return getattr(Runner.DslObjectWrapper(self.root, self), item)
|
return getattr(Runner.DslObjectWrapper(self._root, self), item)
|
||||||
|
|
||||||
def on(self, obj):
|
def on(self, obj):
|
||||||
return Runner.DslObjectWrapper(obj, self)
|
return Runner.DslObjectWrapper(obj, self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def model(self):
|
def root(self):
|
||||||
return results_serializer.serialize(self.root, self.executor)
|
return self._root
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serialized_model(self):
|
||||||
|
return results_serializer.serialize(self._root, self.executor)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def preserve_exception(self):
|
def preserve_exception(self):
|
||||||
|
@@ -28,14 +28,17 @@ class DslTestCase(base.MuranoTestCase):
|
|||||||
super(DslTestCase, self).setUp()
|
super(DslTestCase, self).setUp()
|
||||||
directory = os.path.join(os.path.dirname(
|
directory = os.path.join(os.path.dirname(
|
||||||
inspect.getfile(self.__class__)), 'meta')
|
inspect.getfile(self.__class__)), 'meta')
|
||||||
|
root_meta_directory = os.path.join(
|
||||||
|
os.path.dirname(__file__), '../../../../meta')
|
||||||
sys_class_loader = test_class_loader.TestClassLoader(
|
sys_class_loader = test_class_loader.TestClassLoader(
|
||||||
os.path.join(directory, '../../../../meta/io.murano/Classes'),
|
os.path.join(root_meta_directory, 'io.murano/Classes'),
|
||||||
'murano.io')
|
'murano.io')
|
||||||
self._class_loader = test_class_loader.TestClassLoader(
|
self._class_loader = test_class_loader.TestClassLoader(
|
||||||
directory, 'tests', sys_class_loader)
|
directory, 'tests', sys_class_loader)
|
||||||
self.register_function(
|
self.register_function(
|
||||||
lambda data: self._traces.append(data()), 'trace')
|
lambda data: self._traces.append(data()), 'trace')
|
||||||
self._traces = []
|
self._traces = []
|
||||||
|
eventlet.debug.hub_exceptions(False)
|
||||||
|
|
||||||
def new_runner(self, model):
|
def new_runner(self, model):
|
||||||
return runner.Runner(model, self.class_loader)
|
return runner.Runner(model, self.class_loader)
|
||||||
@@ -44,13 +47,13 @@ class DslTestCase(base.MuranoTestCase):
|
|||||||
def traces(self):
|
def traces(self):
|
||||||
return self._traces
|
return self._traces
|
||||||
|
|
||||||
|
@traces.deleter
|
||||||
|
def traces(self):
|
||||||
|
self._traces = []
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def class_loader(self):
|
def class_loader(self):
|
||||||
return self._class_loader
|
return self._class_loader
|
||||||
|
|
||||||
def register_function(self, func, name):
|
def register_function(self, func, name):
|
||||||
self.class_loader.register_function(func, name)
|
self.class_loader.register_function(func, name)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setUpClass(cls):
|
|
||||||
eventlet.debug.hub_exceptions(False)
|
|
||||||
|
@@ -26,12 +26,18 @@ from murano.engine import yaql_yaml_loader
|
|||||||
|
|
||||||
|
|
||||||
class TestClassLoader(class_loader.MuranoClassLoader):
|
class TestClassLoader(class_loader.MuranoClassLoader):
|
||||||
|
_classes_cache = {}
|
||||||
|
|
||||||
def __init__(self, directory, package_name, parent_loader=None):
|
def __init__(self, directory, package_name, parent_loader=None):
|
||||||
self._classes = {}
|
|
||||||
self._package = murano_package.MuranoPackage()
|
self._package = murano_package.MuranoPackage()
|
||||||
self._package.name = package_name
|
self._package.name = package_name
|
||||||
self._parent = parent_loader
|
self._parent = parent_loader
|
||||||
self._build_index(directory)
|
if directory in TestClassLoader._classes_cache:
|
||||||
|
self._classes = TestClassLoader._classes_cache[directory]
|
||||||
|
else:
|
||||||
|
self._classes = {}
|
||||||
|
self._build_index(directory)
|
||||||
|
TestClassLoader._classes_cache[directory] = self._classes
|
||||||
self._functions = {}
|
self._functions = {}
|
||||||
super(TestClassLoader, self).__init__()
|
super(TestClassLoader, self).__init__()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user