Beispiel #1
0
 def test_transform(self, input_filter_string, input_reading_block,
                    expected_return):
     jqfilter_instance = JQFilter()
     with patch.object(pyjq, "all",
                       return_value=expected_return) as mock_pyjq:
         ret = jqfilter_instance.transform(input_filter_string,
                                           input_reading_block)
         assert ret == expected_return
     mock_pyjq.assert_called_once_with(input_reading_block,
                                       input_filter_string)
Beispiel #2
0
 def test_transform_exceptions(self, input_filter_string,
                               input_reading_block, expected_error,
                               expected_log):
     jqfilter_instance = JQFilter()
     with patch.object(pyjq, "all",
                       side_effect=expected_error) as mock_pyjq:
         with patch.object(jqfilter_instance._logger, "error") as log:
             with pytest.raises(expected_error):
                 jqfilter_instance.transform(input_filter_string,
                                             input_reading_block)
     mock_pyjq.assert_called_once_with(input_reading_block,
                                       input_filter_string)
     log.assert_called_once_with(expected_log, '')
Beispiel #3
0
    def _send_data_block(self, stream_id):
        """ Sends a block of data to the destination using the configured plugin
        Args:
        Returns:
        Raises:
        Todo:
        """
        data_sent = False
        SendingProcess._logger.debug("{0} - ".format("_send_data_block"))
        try:
            last_object_id = self._last_object_id_read(stream_id)
            data_to_send = self._load_data_into_memory(last_object_id)
            if data_to_send:
                if self._config_from_manager['applyFilter']["value"].upper() == "TRUE":
                    jqfilter = JQFilter()

                    # Steps needed to proper format the data generated by the JQFilter to the one expected by the SP
                    data_to_send_2 = jqfilter.transform(data_to_send, self._config_from_manager['filterRule']["value"])
                    data_to_send_3 = json.dumps(data_to_send_2)
                    del data_to_send_2

                    data_to_send_4 = eval(data_to_send_3)
                    del data_to_send_3

                    data_to_send = data_to_send_4[0]
                    del data_to_send_4

                data_sent, new_last_object_id, num_sent = self._plugin.plugin_send(self._plugin_handle, data_to_send, stream_id)
                if data_sent:
                    # Updates reached position, statistics and logs the operation within the Storage Layer
                    self._last_object_id_update(new_last_object_id, stream_id)
                    self._update_statistics(num_sent, stream_id)
                    loop = asyncio.get_event_loop()
                    loop.run_until_complete(self._audit.information(self._AUDIT_CODE, {"sentRows": num_sent}))
        except Exception:
            _message = _MESSAGES_LIST["e000006"]
            SendingProcess._logger.error(_message)
            raise
        return data_sent
Beispiel #4
0
 async def _task_fetch_data(self):
     """ Read data from the Storage Layer into a memory structure"""
     try:
         last_object_id = await self._last_object_id_read()
         self._memory_buffer_fetch_idx = 0
         sleep_time = self.TASK_FETCH_SLEEP
         sleep_num_increments = 1
         while self._task_fetch_data_run:
             slept = False
             if self._memory_buffer_fetch_idx < self._config['memory_buffer_size']:
                 # Checks if there is enough space to load a new block of data
                 if self._memory_buffer[self._memory_buffer_fetch_idx] is None:
                     try:
                         data_to_send = await self._load_data_into_memory(last_object_id)
                     except Exception as ex:
                         _message = _MESSAGES_LIST["e000028"].format(ex)
                         SendingProcess._logger.error(_message)
                         await self._audit.failure(self._AUDIT_CODE, {"error - on _task_fetch_data": _message})
                         data_to_send = False
                         slept = True
                         await asyncio.sleep(sleep_time)
                     if data_to_send:
                         # Handles the JQFilter functionality
                         if self._config_from_manager['applyFilter']["value"].upper() == "TRUE":
                             jqfilter = JQFilter()
                             # Steps needed to proper format the data generated by the JQFilter
                             # to the one expected by the SP
                             data_to_send_2 = jqfilter.transform(data_to_send,
                                                                 self._config_from_manager['filterRule']["value"])
                             data_to_send_3 = json.dumps(data_to_send_2)
                             del data_to_send_2
                             data_to_send_4 = eval(data_to_send_3)
                             del data_to_send_3
                             data_to_send = data_to_send_4[0]
                             del data_to_send_4
                         # Loads the block of data into the in memory buffer
                         self._memory_buffer[self._memory_buffer_fetch_idx] = data_to_send
                         last_position = len(data_to_send) - 1
                         last_object_id = data_to_send[last_position]['id']
                         self._memory_buffer_fetch_idx += 1
                         self._task_fetch_data_sem.release()
                         self.performance_track("task _task_fetch_data")
                     else:
                         # There is no more data to load
                         slept = True
                         await asyncio.sleep(sleep_time)
                 else:
                     # There is no more space in the in memory buffer
                     await self._task_send_data_sem.acquire()
             else:
                 self._memory_buffer_fetch_idx = 0
             # Handles the sleep time, it is doubled every time up to a limit
             if slept:
                 sleep_num_increments += 1
                 sleep_time *= 2
                 if sleep_num_increments > self.TASK_SLEEP_MAX_INCREMENTS:
                     sleep_time = self.TASK_FETCH_SLEEP
                     sleep_num_increments = 1
     except Exception as ex:
         _message = _MESSAGES_LIST["e000028"].format(ex)
         SendingProcess._logger.error(_message)
         await self._audit.failure(self._AUDIT_CODE, {"error - on _task_fetch_data": _message})
         raise
Beispiel #5
0
class TestJQFilter:
    """
    JQ Filter Tests
      - Test that north plugins can load and apply JQ filter
      - Test that correct results are returned after applying JQ filter
    """
    _name = "JQFilter"
    # TODO: How to eliminate manual intervention as below when tests will run unattended at CI?
    _core_management_port = pytest.test_env.core_mgmt_port
    _core_management_host = "localhost"

    _storage_client = StorageClient("localhost", _core_management_port)
    _readings = ReadingsStorageClient("localhost", _core_management_port)
    _cfg_manager = ConfigurationManager(_storage_client)

    # Configuration related to JQ Filter
    _CONFIG_CATEGORY_NAME ="JQ_FILTER"
    _CONFIG_CATEGORY_DESCRIPTION = "JQ configuration"
    _DEFAULT_FILTER_CONFIG = {
        "applyFilter": {
            "description": "Whether to apply filter before processing the data",
            "type": "boolean",
            "default": "False"
        },
        "filterRule": {
            "description": "JQ formatted filter to apply (applicable if applyFilter is True)",
            "type": "string",
            "default": ".[]"
        }
    }
    _first_read_id = None
    _raw_data = None
    _jqfilter = JQFilter()

    @classmethod
    def set_configuration(cls):
        """" set the default configuration for plugin
        :return:
            Configuration information that will be set for any north plugin
        """
        event_loop = asyncio.get_event_loop()
        event_loop.run_until_complete(cls._cfg_manager.create_category(cls._CONFIG_CATEGORY_NAME,
                                                                       cls._DEFAULT_FILTER_CONFIG,
                                                                       cls._CONFIG_CATEGORY_DESCRIPTION))
        return event_loop.run_until_complete(cls._cfg_manager.get_category_all_items(cls._CONFIG_CATEGORY_NAME))

    @classmethod
    @pytest.fixture(scope="class", autouse=True)
    def init_test(cls):
        """Setup and Cleanup method, executed once for the entire test class"""
        cls.set_configuration()
        cls._first_read_id = cls._insert_readings_data()
        cls._insert_readings_data()
        payload = PayloadBuilder()\
            .WHERE(['id', '>=', cls._first_read_id]) \
            .ORDER_BY(['id', 'ASC']) \
            .payload()
        readings = cls._readings.query(payload)
        cls._raw_data = readings['rows']

        yield
        # Delete all test data from readings and configuration
        cls._storage_client.delete_from_tbl("readings", {})
        payload = PayloadBuilder().WHERE(["key", "=", cls._CONFIG_CATEGORY_NAME]).payload()
        cls._storage_client.delete_from_tbl("configuration", payload)

    @classmethod
    def _insert_readings_data(cls):
        """Insert reads in readings table
        args:

        :return:
            The id of inserted row

        """
        readings = []

        read = dict()
        read["asset_code"] = "TEST_JQ"
        read["read_key"] = str(uuid.uuid4())
        read['reading'] = dict()
        read['reading']['rate'] = random.randint(1, 100)
        ts = str(datetime.now(tz=timezone.utc))
        read["user_ts"] = ts

        readings.append(read)

        payload = dict()
        payload['readings'] = readings

        cls._readings.append(json.dumps(payload))

        payload = PayloadBuilder().AGGREGATE(["max", "id"]).payload()
        result = cls._storage_client.query_tbl_with_payload("readings", payload)
        return int(result["rows"][0]["max_id"])

    async def test_default_filter_configuration(self):
        """Test that filter is not applied when testing with default configuration"""
        apply_filter = await self._cfg_manager.get_category_item_value_entry(self._CONFIG_CATEGORY_NAME, 'applyFilter')
        jq_rule = await self._cfg_manager.get_category_item_value_entry(self._CONFIG_CATEGORY_NAME, 'filterRule')
        if apply_filter.upper() == "TRUE":
            transformed_data = self._jqfilter.transform(self._raw_data, jq_rule)
            assert transformed_data is None
        else:
            assert True

    async def test_default_filterRule(self):
        """Test that filter is applied and returns readings block unaltered with default configuration of filterRule"""
        await self._cfg_manager.set_category_item_value_entry(self._CONFIG_CATEGORY_NAME, 'applyFilter', "True")
        apply_filter = await self._cfg_manager.get_category_item_value_entry(self._CONFIG_CATEGORY_NAME, 'applyFilter')
        jq_rule = await self._cfg_manager.get_category_item_value_entry(self._CONFIG_CATEGORY_NAME, 'filterRule')
        if apply_filter.upper() == "TRUE":
            transformed_data = self._jqfilter.transform(self._raw_data, jq_rule)
            assert transformed_data == self._raw_data
        else:
            assert False

    async def test_custom_filter_configuration(self):
        """Test with supplied filterRule"""
        await self._cfg_manager.set_category_item_value_entry(self._CONFIG_CATEGORY_NAME, 'applyFilter', "True")
        await self._cfg_manager.set_category_item_value_entry(self._CONFIG_CATEGORY_NAME,
                                                              'filterRule', ".[0]|{Measurement_id: .id}")
        apply_filter = await self._cfg_manager.get_category_item_value_entry(self._CONFIG_CATEGORY_NAME, 'applyFilter')
        jq_rule = await self._cfg_manager.get_category_item_value_entry(self._CONFIG_CATEGORY_NAME, 'filterRule')
        transformed_data = self._jqfilter.transform(self._raw_data, jq_rule)
        if apply_filter.upper() == "TRUE":
            assert transformed_data == [{"Measurement_id": self._first_read_id}]
        else:
            assert False

    async def test_invalid_filter_configuration(self):
        """Test with invalid filterRule"""
        await self._cfg_manager.set_category_item_value_entry(self._CONFIG_CATEGORY_NAME, 'filterRule', "|")
        jq_rule = await self._cfg_manager.get_category_item_value_entry(self._CONFIG_CATEGORY_NAME, 'filterRule')
        with pytest.raises(ValueError) as ex:
            self._jqfilter.transform(self._raw_data, jq_rule)
        assert "jq: error: syntax error, unexpected '|'" in str(ex)
Beispiel #6
0
 def test_init(self):
     with patch.object(logger, "setup") as log:
         jqfilter_instance = JQFilter()
     assert isinstance(jqfilter_instance, JQFilter)
     log.assert_called_once_with("JQFilter")