def test_initialization(self):
        slotmap = InputSlotInfo()

        self.assertEqual(slotmap.source, "Environment")
        self.assertEqual(slotmap.name, "")
        with self.assertRaises(TraitError):
            slotmap.name = "000"
Esempio n. 2
0
    def setUp(self):
        self.registry = ProbeFactoryRegistry()
        self.plugin = self.registry.plugin

        self.data_values = [
            DataValue(name="foo"),
            DataValue(name="bar"),
            DataValue(name="baz"),
        ]

        self.slot_map = (InputSlotInfo(name="baz"), InputSlotInfo(name="bar"))

        self.slots = (Slot(), Slot())
Esempio n. 3
0
    def test_data_source_run_error(self):

        data_values = [DataValue(name="foo")]
        self.layer.data_sources[0].input_slot_info = [
            InputSlotInfo(name="foo")
        ]

        factory = self.registry.data_source_factories[0]
        factory.raises_on_data_source_run = True

        with testfixtures.LogCapture() as capture:
            with self.assertRaises(Exception):
                self.layer.execute_layer(data_values)
            capture.check(
                (
                    "force_bdss.core.execution_layer",
                    "INFO",
                    "Evaluating for Data Source test_data_source",
                ),
                ("force_bdss.core.execution_layer", "INFO", "Passed values:"),
                (
                    "force_bdss.core.execution_layer",
                    "INFO",
                    "0:  foo = None (AVERAGE)",
                ),
                (
                    "force_bdss.core.execution_layer",
                    "ERROR",
                    "Evaluation could not be performed. "
                    "Run method raised exception.",
                ),
            )
Esempio n. 4
0
    def test_error_for_non_data_source(self):

        data_values = [DataValue(name="foo")]
        self.layer.data_sources[0].input_slot_info = [
            InputSlotInfo(name="foo")
        ]
        self.layer.data_sources[0].output_slot_info = [
            OutputSlotInfo(name="one")
        ]

        def probe_run(self, *args, **kwargs):
            return ["hello"]

        factory = self.registry.data_source_factories[0]
        factory.run_function = probe_run

        with testfixtures.LogCapture():
            with self.assertRaisesRegex(
                    RuntimeError,
                    "The result list returned by DataSource "
                    "test_data_source"
                    " contains an entry that is not a DataValue."
                    " An entry of type <.* 'str'> was instead found"
                    " in position 0."
                    r" Fix the DataSource.run\(\) method to"
                    " return the appropriate entity.",
            ):
                self.layer.execute_layer(data_values)
Esempio n. 5
0
    def from_json(cls, factory, json_data):
        """ Instantiate an BaseMCOModel object from a `json_data`
        dictionary and the generating `factory` object.

        Parameters
        ----------
        factory: IDataSourceFactory
            Generating factory object
        json_data: dict
            Dictionary with a DataSourceModel serialized data

        Returns
        ----------
        layer: BaseDataSourceModel
            BaseDataSourceModel instance with attributes values from
            the `json_data` dict
        """
        data = deepcopy(json_data)

        input_slots = [InputSlotInfo(**d) for d in data["input_slot_info"]]
        data["input_slot_info"] = input_slots

        output_slots = [OutputSlotInfo(**d) for d in data["output_slot_info"]]
        data["output_slot_info"] = output_slots

        data_source = factory.create_model(data)
        return data_source
    def test_getstate(self):
        model = DummyDataSourceModel(self.mock_factory)
        self.assertDictEqual(
            model.__getstate__(),
            {
                "id": "id",
                "model_data": {
                    "input_slot_info": [],
                    "output_slot_info": []
                },
            },
        )

        model.input_slot_info = [
            InputSlotInfo(name="foo"),
            InputSlotInfo(name="bar"),
        ]
        model.output_slot_info = [
            OutputSlotInfo(name="baz"),
            OutputSlotInfo(name="quux"),
        ]

        self.assertDictEqual(
            model.__getstate__(),
            {
                "id": "id",
                "model_data": {
                    "input_slot_info": [
                        {
                            "source": "Environment",
                            "name": "foo"
                        },
                        {
                            "source": "Environment",
                            "name": "bar"
                        },
                    ],
                    "output_slot_info": [{
                        "name": "baz"
                    }, {
                        "name": "quux"
                    }],
                },
            },
        )
    def test_traits_to_dict(self):
        wf = self.sample_workflow()
        exec_layer = wf.execution_layers[0]
        exec_layer.data_sources[0].input_slot_info = [InputSlotInfo()]

        datastore_list = exec_layer.__getstate__()
        new_slotdata = datastore_list["data_sources"][0]["model_data"][
            "input_slot_info"]
        self.assertNotIn("__traits_version__", new_slotdata)
Esempio n. 8
0
    def test_execute_layer_results(self):

        data_values = [
            DataValue(name="foo"),
            DataValue(name="bar"),
            DataValue(name="baz"),
            DataValue(name="quux"),
        ]

        def run(self, *args, **kwargs):
            return [DataValue(value=1), DataValue(value=2), DataValue(value=3)]

        ds_factory = self.registry.data_source_factories[0]
        ds_factory.input_slots_size = 2
        ds_factory.output_slots_size = 3
        ds_factory.run_function = run
        evaluator_model = ds_factory.create_model()

        evaluator_model.input_slot_info = [
            InputSlotInfo(name="foo"),
            InputSlotInfo(name="quux"),
        ]
        evaluator_model.output_slot_info = [
            OutputSlotInfo(name="one"),
            OutputSlotInfo(name=""),
            OutputSlotInfo(name="three"),
        ]

        self.layer.data_sources = [evaluator_model]
        res = self.layer.execute_layer(data_values)
        self.assertEqual(len(res), 2)
        self.assertEqual(res[0].name, "one")
        self.assertEqual(res[0].value, 1)
        self.assertEqual(res[1].name, "three")
        self.assertEqual(res[1].value, 3)

        with mock.patch(
                "force_bdss.data_sources.base_data_source.BaseDataSource._run",
                return_value=run(None)) as mock_run:
            # mock_run.side_effect = [1, 2]
            self.layer.execute_layer(data_values)
        mock_run.assert_called_once()
Esempio n. 9
0
    def test_data_sources(self):
        wf = self.workflow
        mco_factory = self.plugin.mco_factories[0]
        wf.mco_model = mco_factory.create_model()
        parameter_factory = mco_factory.parameter_factories[0]
        wf.mco_model.parameters.append(parameter_factory.create_model())
        wf.mco_model.parameters[0].name = "name"
        wf.mco_model.parameters[0].type = "type"
        wf.mco_model.kpis.append(KPISpecification(name='name'))

        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(
            "The number of input slots (1 values) returned by "
            "'Dummy data source' does not match the number "
            "of user-defined names specified (0 values). This "
            "is either a plugin error or a file error.", errors[0].local_error)

        ds_model.input_slot_info.append(InputSlotInfo(name="name"))

        errors = verify_workflow(wf)
        self.assertEqual(errors[0].subject, ds_model)
        self.assertIn(
            "The number of output slots (1 values) returned by "
            "'Dummy data source' does not match the number "
            "of user-defined names specified (0 values). This "
            "is either a plugin error or a file error.", errors[0].local_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("Input slot is not named", errors[0].local_error)

        ds_model.output_slot_info[0].name = ''
        errors = verify_workflow(wf)
        self.assertEqual(len(errors), 3)
        self.assertIn("All output variables have undefined names",
                      errors[1].local_error)
        self.assertIn("An output variable has an undefined name",
                      errors[2].local_error)
Esempio n. 10
0
    def test_error_for_output_slots(self):
        data_values = [DataValue(name="foo")]
        self.layer.data_sources[0].input_slot_info = [
            InputSlotInfo(name="foo")
        ]

        def probe_run(self, *args, **kwargs):
            return ["too", "many", "data", "values"]

        factory = self.registry.data_source_factories[0]
        factory.run_function = probe_run

        with testfixtures.LogCapture():
            with self.assertRaisesRegex(
                    RuntimeError,
                    r"The number of data values \(4 values\) returned"
                    " by 'test_data_source' does not match the number"
                    r" of output slots it specifies \(1 values\)."
                    " This is likely a plugin error.",
            ):
                self.layer.execute_layer(data_values)
Esempio n. 11
0
    def test_error_for_incorrect_return_type(self):

        data_values = [DataValue(name="foo")]
        self.layer.data_sources[0].input_slot_info = [
            InputSlotInfo(name="foo")
        ]

        def probe_run(self, *args, **kwargs):
            return "hello"

        factory = self.registry.data_source_factories[0]
        factory.run_function = probe_run

        with testfixtures.LogCapture():
            with self.assertRaisesRegex(
                    RuntimeError,
                    "The run method of data source "
                    "test_data_source must return a list. It "
                    r"returned instead <.* 'str'>. Fix the run\(\)"
                    " method to return the appropriate entity.",
            ):
                self.layer.execute_layer(data_values)
Esempio n. 12
0
    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
        # layer 3:        res4 * res2
        #                     out1
        # Final result should be
        # out1 = ((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(
            self.plugin,
            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(
            self.plugin,
            input_slots_size=2,
            output_slots_size=1,
            run_function=multiplier,
        )

        mco_factory = ProbeMCOFactory(self.plugin)
        mco_model = mco_factory.create_model()
        parameter_factory = mco_factory.parameter_factories[0]

        mco_model.parameters = [
            parameter_factory.create_model({"name": "in1"}),
            parameter_factory.create_model({"name": "in2"}),
            parameter_factory.create_model({"name": "in3"}),
            parameter_factory.create_model({"name": "in4"}),
        ]
        mco_model.kpis = [KPISpecification(name="out1")]

        wf = Workflow(
            mco_model=mco_model,
            execution_layers=[
                ExecutionLayer(),
                ExecutionLayer(),
                ExecutionLayer(),
                ExecutionLayer(),
            ],
        )
        # Layer 0
        model = adder_factory.create_model()
        model.input_slot_info = [
            InputSlotInfo(name="in1"),
            InputSlotInfo(name="in2"),
        ]
        model.output_slot_info = [OutputSlotInfo(name="res1")]
        wf.execution_layers[0].data_sources.append(model)

        model = adder_factory.create_model()
        model.input_slot_info = [
            InputSlotInfo(name="in3"),
            InputSlotInfo(name="in4"),
        ]
        model.output_slot_info = [OutputSlotInfo(name="res2")]
        wf.execution_layers[0].data_sources.append(model)

        # layer 1
        model = adder_factory.create_model()
        model.input_slot_info = [
            InputSlotInfo(name="res1"),
            InputSlotInfo(name="res2"),
        ]
        model.output_slot_info = [OutputSlotInfo(name="res3")]
        wf.execution_layers[1].data_sources.append(model)

        # layer 2
        model = multiplier_factory.create_model()
        model.input_slot_info = [
            InputSlotInfo(name="res3"),
            InputSlotInfo(name="res1"),
        ]
        model.output_slot_info = [OutputSlotInfo(name="res4")]
        wf.execution_layers[2].data_sources.append(model)

        # layer 3
        model = multiplier_factory.create_model()
        model.input_slot_info = [
            InputSlotInfo(name="res4"),
            InputSlotInfo(name="res2"),
        ]
        model.output_slot_info = [OutputSlotInfo(name="out1")]
        wf.execution_layers[3].data_sources.append(model)

        kpi_results = wf.execute(data_values)
        self.assertEqual(1, len(kpi_results))
        self.assertEqual(8750, kpi_results[0].value)
Esempio n. 13
0
    def test_kpi_specification_adherence(self):
        # Often the user may only wish to treat a subset of DataSource
        # output slots as KPIs. This test makes sure they get what they
        # ask for!

        # keep input DataValues constant
        data_values = [
            DataValue(value=99, name="in1"),
            DataValue(value=1, name="in2"),
        ]

        # dummy addition DataSource(a, b) that also returns its inputs
        # [a, b, a+b]
        def adder(model, parameters):
            first = parameters[0].value
            second = parameters[1].value
            return [
                DataValue(value=first),
                DataValue(value=second),
                DataValue(value=(first + second)),
            ]

        adder_factory = ProbeDataSourceFactory(
            self.plugin,
            input_slots_size=2,
            output_slots_size=3,
            run_function=adder,
        )

        mco_factory = ProbeMCOFactory(self.plugin)
        parameter_factory = mco_factory.parameter_factories[0]
        mco_model = mco_factory.create_model()

        # DataSourceModel stats constant throughout
        model = adder_factory.create_model()
        model.input_slot_info = [
            InputSlotInfo(name="in1"),
            InputSlotInfo(name="in2"),
        ]
        model.output_slot_info = [
            OutputSlotInfo(name="out1"),
            OutputSlotInfo(name="out2"),
            OutputSlotInfo(name="out3"),
        ]

        # test Parameter and KPI spec that follows DataSource slots
        # exactly
        mco_model.parameters = [
            parameter_factory.create_model({"name": "in1"}),
            parameter_factory.create_model({"name": "in2"}),
        ]
        mco_model.kpis = [
            KPISpecification(name="out1"),
            KPISpecification(name="out2"),
            KPISpecification(name="out3"),
        ]
        # need to make a new workflow for each KPISpecification
        wf = Workflow(mco_model=mco_model, execution_layers=[ExecutionLayer()])
        wf.execution_layers[0].data_sources.append(model)
        kpi_results = wf.execute(data_values)
        self.assertEqual(len(kpi_results), 3)
        self.assertEqual(kpi_results[0].value, 99)
        self.assertEqual(kpi_results[1].value, 1)
        self.assertEqual(kpi_results[2].value, 100)
        self.assertEqual(kpi_results[0].name, "out1")
        self.assertEqual(kpi_results[1].name, "out2")
        self.assertEqual(kpi_results[2].name, "out3")

        # now test all possible combinations of KPISpecification, including
        # those with KPIs repeated, and empty KPI specification
        import itertools

        out_options = [("out1", 99), ("out2", 1), ("out3", 100)]
        for num_outputs in range(len(out_options) + 2, 0, -1):
            for spec in itertools.permutations(out_options, r=num_outputs):
                mco_model.kpis = [
                    KPISpecification(name=opt[0]) for opt in spec
                ]

                wf = Workflow(
                    mco_model=mco_model, execution_layers=[ExecutionLayer()]
                )
                wf.execution_layers[0].data_sources.append(model)
                kpi_results = wf.execute(data_values)
                self.assertEqual(len(kpi_results), num_outputs)

                for i in range(num_outputs):
                    self.assertEqual(kpi_results[i].name, spec[i][0])
                    self.assertEqual(kpi_results[i].value, spec[i][1])