From 027aec574044004b21b749ef37d77d5390e1b4e9 Mon Sep 17 00:00:00 2001
From: Stefano Borini <sborini@enthought.com>
Date: Thu, 26 Apr 2018 11:49:03 +0100
Subject: [PATCH] Added test for the whole layer execution

---
 force_bdss/core_evaluation_driver.py          |  38 +++---
 .../tests/test_core_evaluation_driver.py      | 113 +++++++++++++++++-
 2 files changed, 135 insertions(+), 16 deletions(-)

diff --git a/force_bdss/core_evaluation_driver.py b/force_bdss/core_evaluation_driver.py
index 4b002a0..289c8c1 100644
--- a/force_bdss/core_evaluation_driver.py
+++ b/force_bdss/core_evaluation_driver.py
@@ -41,24 +41,34 @@ class CoreEvaluationDriver(BaseCoreDriver):
         mco_data_values = _get_data_values_from_mco(
             mco_model, mco_communicator)
 
-        available_data_values = mco_data_values[:]
-        for index, layer in enumerate(workflow.execution_layers):
-            log.info("Computing data layer {}".format(index))
-            ds_results = _compute_layer_results(
-                available_data_values,
-                layer,
-                "create_data_source"
-            )
-            available_data_values += ds_results
+        kpi_results = execute_workflow(workflow, mco_data_values)
+
+        mco_communicator.send_to_mco(mco_model, kpi_results)
+
 
-        log.info("Computing data layer 2")
-        kpi_results = _compute_layer_results(
+def execute_workflow(workflow, data_values):
+    """Executes the given workflow using the list of data values.
+    Returns a list of data values for the KPI results
+    """
+
+    available_data_values = data_values[:]
+    for index, layer in enumerate(workflow.execution_layers):
+        log.info("Computing data layer {}".format(index))
+        ds_results = _compute_layer_results(
             available_data_values,
-            workflow.kpi_calculators,
-            "create_kpi_calculator"
+            layer,
+            "create_data_source"
         )
+        available_data_values += ds_results
 
-        mco_communicator.send_to_mco(mco_model, kpi_results)
+    log.info("Computing KPI layer")
+    kpi_results = _compute_layer_results(
+        available_data_values,
+        workflow.kpi_calculators,
+        "create_kpi_calculator"
+    )
+
+    return kpi_results
 
 
 def _compute_layer_results(environment_data_values,
diff --git a/force_bdss/tests/test_core_evaluation_driver.py b/force_bdss/tests/test_core_evaluation_driver.py
index a6084e7..72ed3e2 100644
--- a/force_bdss/tests/test_core_evaluation_driver.py
+++ b/force_bdss/tests/test_core_evaluation_driver.py
@@ -3,6 +3,7 @@ import unittest
 import testfixtures
 import six
 
+from force_bdss.core.workflow import Workflow
 from force_bdss.tests.probe_classes.factory_registry_plugin import \
     ProbeFactoryRegistryPlugin
 from force_bdss.tests.probe_classes.mco import ProbeMCOFactory
@@ -22,8 +23,12 @@ except ImportError:
 
 from envisage.api import Application
 
-from force_bdss.core_evaluation_driver import CoreEvaluationDriver, \
-    _bind_data_values, _compute_layer_results
+from force_bdss.core_evaluation_driver import (
+    CoreEvaluationDriver,
+    execute_workflow,
+    _bind_data_values,
+    _compute_layer_results)
+
 
 
 class TestCoreEvaluationDriver(unittest.TestCase):
@@ -225,6 +230,110 @@ class TestCoreEvaluationDriver(unittest.TestCase):
         self.assertEqual(res[1].name, "three")
         self.assertEqual(res[1].value, 3)
 
+    def test_multilayer_execution(self):
+        # The multilayer peforms the following execution
+        # layer 0: in1 + in2   | in3 + in4
+        #             res1          res2
+        # layer 1:        res1 + res2
+        #                    res3
+        # layer 2:        res3 * res1
+        #                     res4
+        # kpi layer:      res4 * res2
+        #
+        # Final result should be
+        # ((in1 + in2 + in3 + in4) * (in1 + in2) * (in3 + in4)
+
+        data_values = [
+            DataValue(value=10, name="in1"),
+            DataValue(value=15, name="in2"),
+            DataValue(value=3, name="in3"),
+            DataValue(value=7, name="in4")
+        ]
+
+        def adder(model, parameters):
+
+            first = parameters[0].value
+            second = parameters[1].value
+            return [DataValue(value=(first+second))]
+
+        adder_factory = ProbeDataSourceFactory(
+            None,
+            input_slots_size=2,
+            output_slots_size=1,
+            run_function=adder)
+
+        def multiplier(model, parameters):
+            first = parameters[0].value
+            second = parameters[1].value
+            return [DataValue(value=(first*second))]
+
+        multiplier_factory = ProbeDataSourceFactory(
+            None,
+            input_slots_size=2,
+            output_slots_size=1,
+            run_function=multiplier)
+
+        multiplier_kpi_factory = ProbeKPICalculatorFactory(
+            None,
+            input_slots_size=2,
+            output_slots_size=1,
+            run_function=multiplier)
+
+        wf = Workflow(
+            execution_layers=[
+                [],
+                [],
+                []
+            ]
+        )
+        # Layer 0
+        model = adder_factory.create_model()
+        model.input_slot_maps = [
+            InputSlotMap(name="in1"),
+            InputSlotMap(name="in2")
+        ]
+        model.output_slot_names = ["res1"]
+        wf.execution_layers[0].append(model)
+
+        model = adder_factory.create_model()
+        model.input_slot_maps = [
+            InputSlotMap(name="in3"),
+            InputSlotMap(name="in4")
+        ]
+        model.output_slot_names = ["res2"]
+        wf.execution_layers[0].append(model)
+
+        # layer 1
+        model = adder_factory.create_model()
+        model.input_slot_maps = [
+            InputSlotMap(name="res1"),
+            InputSlotMap(name="res2")
+        ]
+        model.output_slot_names = ["res3"]
+        wf.execution_layers[1].append(model)
+
+        # layer 2
+        model = multiplier_factory.create_model()
+        model.input_slot_maps = [
+            InputSlotMap(name="res3"),
+            InputSlotMap(name="res1")
+        ]
+        model.output_slot_names = ["res4"]
+        wf.execution_layers[2].append(model)
+
+        # KPI layer
+        model = multiplier_kpi_factory.create_model()
+        model.input_slot_maps = [
+            InputSlotMap(name="res4"),
+            InputSlotMap(name="res2")
+        ]
+        model.output_slot_names = ["out1"]
+        wf.kpi_calculators.append(model)
+
+        kpi_results = execute_workflow(wf, data_values)
+        self.assertEqual(len(kpi_results), 1)
+        self.assertEqual(kpi_results[0].value, 8750)
+
     def test_empty_slot_name_skips_data_value(self):
         """Checks if leaving a slot name empty will skip the data value
         in the final output
-- 
GitLab