Skip to content
Snippets Groups Projects
Commit 1a3cd214 authored by Stefano Borini's avatar Stefano Borini
Browse files

First verifier implementation

parent e98a5611
No related branches found
No related tags found
1 merge request!139Introduce Verifier to check if a model can run and if not, report the errors.
import unittest
from force_bdss.core.execution_layer import ExecutionLayer
from force_bdss.core.input_slot_info import InputSlotInfo
from force_bdss.core.output_slot_info import OutputSlotInfo
from force_bdss.core.verifier import verify_workflow
from force_bdss.core.workflow import Workflow
from force_bdss.tests.dummy_classes.extension_plugin import \
DummyExtensionPlugin
class TestVerifier(unittest.TestCase):
def setUp(self):
self.plugin = DummyExtensionPlugin()
self.workflow = Workflow()
def test_empty_workflow(self):
wf = self.workflow
errors = verify_workflow(wf)
self.assertEqual(len(errors), 2)
self.assertEqual(errors[0].subject, wf)
self.assertIn("no MCO", errors[0].error)
self.assertEqual(errors[1].subject, wf)
self.assertIn("no execution layers", errors[1].error)
def test_no_mco_parameters(self):
wf = self.workflow
wf.mco = self.plugin.mco_factories[0].create_model()
errors = verify_workflow(wf)
self.assertEqual(len(errors), 2)
self.assertEqual(errors[0].subject, wf.mco)
self.assertIn("no defined parameters", errors[0].error)
def test_parameters_empty_names(self):
wf = self.workflow
mco_factory = self.plugin.mco_factories[0]
wf.mco = mco_factory.create_model()
parameter_factory = mco_factory.parameter_factories()[0]
wf.mco.parameters.append(parameter_factory.create_model())
errors = verify_workflow(wf)
self.assertEqual(len(errors), 3)
self.assertEqual(errors[0].subject, wf.mco.parameters[0])
self.assertIn("empty name", errors[0].error)
self.assertEqual(errors[1].subject, wf.mco.parameters[0])
self.assertIn("empty type", errors[1].error)
def test_data_sources(self):
wf = self.workflow
mco_factory = self.plugin.mco_factories[0]
wf.mco = mco_factory.create_model()
parameter_factory = mco_factory.parameter_factories()[0]
wf.mco.parameters.append(parameter_factory.create_model())
wf.mco.parameters[0].name = "name"
wf.mco.parameters[0].type = "type"
layer = ExecutionLayer()
wf.execution_layers.append(layer)
ds_factory = self.plugin.data_source_factories[0]
ds_model = ds_factory.create_model()
layer.data_sources.append(ds_model)
errors = verify_workflow(wf)
self.assertEqual(errors[0].subject, ds_model)
self.assertIn("Missing input slot name assignment", errors[0].error)
ds_model.input_slot_info.append(
InputSlotInfo(name="name")
)
errors = verify_workflow(wf)
self.assertEqual(errors[0].subject, ds_model)
self.assertIn("Missing output slot name assignment", errors[0].error)
ds_model.output_slot_info.append(
OutputSlotInfo(name="name")
)
errors = verify_workflow(wf)
self.assertEqual(len(errors), 0)
ds_model.input_slot_info[0].name = ''
errors = verify_workflow(wf)
self.assertEqual(len(errors), 1)
self.assertIn("Undefined name for input parameter", errors[0].error)
ds_model.output_slot_info[0].name = ''
errors = verify_workflow(wf)
self.assertEqual(len(errors), 2)
self.assertIn("Undefined name for output parameter", errors[1].error)
import logging
from traits.api import HasStrictTraits, Str, Any
logger = logging.getLogger(__name__)
class VerifierError(HasStrictTraits):
subject = Any()
error = Str()
def verify_workflow(workflow):
"""Verifies if the workflow can be executed, and specifies where the
error occurs and why.
"""
result = []
result.extend(_check_mco(workflow))
result.extend(_check_execution_layers(workflow))
return result
def _check_mco(workflow):
errors = []
if workflow.mco is None:
errors.append(
VerifierError(
subject=workflow,
error="Workflow has no MCO"
)
)
return errors
mco = workflow.mco
if len(mco.parameters) == 0:
errors.append(VerifierError(subject=mco,
error="MCO has no defined parameters"))
for param in mco.parameters:
if len(param.name.strip()) == 0:
errors.append(VerifierError(subject=param,
error="Parameter has empty name"))
if len(param.type.strip()) == 0:
errors.append(VerifierError(subject=param,
error="Parameter has empty type"))
return errors
def _check_execution_layers(workflow):
errors = []
layers = workflow.execution_layers
if len(layers) == 0:
errors.append(
VerifierError(
subject=workflow,
error="Workflow has no execution layers"
)
)
return errors
for layer in layers:
if len(layer.data_sources) == 0:
errors.append(VerifierError(subject=layer,
error="Layer has no data sources"))
for ds in layer.data_sources:
errors.extend(_check_data_source(ds))
return errors
def _check_data_source(data_source_model):
errors = []
factory = data_source_model.factory
try:
data_source = factory.create_data_source()
except Exception:
logger.exception("Unable to create data source from factory"
" '{}', plugin '{}'. This might indicate a "
"programming error".format(factory.id,
factory.plugin.id))
raise
try:
input_slots, output_slots = data_source.slots(data_source_model)
except Exception:
logger.exception(
"Unable to retrieve slot information from data source"
" created by factory '{}', plugin '{}'. This might "
"indicate a programming error.".format(
data_source.factory.id,
data_source.factory.plugin.id))
raise
if len(input_slots) != len(data_source_model.input_slot_info):
errors.append(VerifierError(
subject=data_source_model,
error="Missing input slot name assignment"))
for idx, info in enumerate(data_source_model.input_slot_info):
if len(info.name.strip()) == 0:
errors.append(VerifierError(
subject=data_source_model,
error="Undefined name for input parameter {}".format(idx)))
if len(output_slots) != len(data_source_model.output_slot_info):
errors.append(VerifierError(
subject=data_source_model,
error="Missing output slot name assignment"))
for idx, info in enumerate(data_source_model.output_slot_info):
if len(info.name.strip()) == 0:
errors.append(VerifierError(
subject=data_source_model,
error="Undefined name for output parameter {}".format(idx)))
return errors
from force_bdss.core.slot import Slot
from force_bdss.data_sources.base_data_source import BaseDataSource from force_bdss.data_sources.base_data_source import BaseDataSource
from force_bdss.data_sources.base_data_source_factory import \ from force_bdss.data_sources.base_data_source_factory import \
BaseDataSourceFactory BaseDataSourceFactory
...@@ -9,7 +10,11 @@ class DummyDataSource(BaseDataSource): ...@@ -9,7 +10,11 @@ class DummyDataSource(BaseDataSource):
pass pass
def slots(self, model): def slots(self, model):
return (), () return (
Slot(type="TYPE1"),
), (
Slot(type="TYPE2"),
)
class DummyDataSourceModel(BaseDataSourceModel): class DummyDataSourceModel(BaseDataSourceModel):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment