move the library to ONF

Change-Id: I383437e2934ce04cc1a7dc332134f7308991776f
diff --git a/tests/servers/dmi/dmi_server.py b/tests/servers/dmi/dmi_server.py
new file mode 100644
index 0000000..31e0f55
--- /dev/null
+++ b/tests/servers/dmi/dmi_server.py
@@ -0,0 +1,148 @@
+# Copyright 2020-present Open Networking Foundation
+# Original copyright 2020-present ADTRAN, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+from concurrent import futures
+import grpc
+
+import dmi.hw_events_mgmt_service_pb2
+import dmi.hw_events_mgmt_service_pb2_grpc
+import dmi.hw_management_service_pb2
+import dmi.hw_management_service_pb2_grpc
+import dmi.hw_metrics_mgmt_service_pb2
+import dmi.hw_metrics_mgmt_service_pb2_grpc
+import dmi.sw_management_service_pb2
+import dmi.sw_management_service_pb2_grpc
+import dmi.commons_pb2
+import dmi.sw_image_pb2
+
+
+class DmiEventsManagementServiceServicer(dmi.hw_events_mgmt_service_pb2_grpc.NativeEventsManagementServiceServicer):
+
+    def ListEvents(self, request, context):
+        return dmi.hw_events_mgmt_service_pb2.ListEventsResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def UpdateEventsConfiguration(self, request, context):
+        return dmi.hw_events_mgmt_service_pb2.EventsConfigurationResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def StreamEvents(self, request, context):
+        for _ in range(0, 1):
+            yield dmi.hw_events_mgmt_service_pb2.Event(event_id=dmi.hw_events_mgmt_service_pb2.EVENT_NAME_UNDEFINED)
+
+
+class DmiHwManagementServiceServicer(dmi.hw_management_service_pb2_grpc.NativeHWManagementServiceServicer):
+
+    def StartManagingDevice(self, request, context):
+        for _ in range(0, 1):
+            yield dmi.hw_management_service_pb2.StartManagingDeviceResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def StopManagingDevice(self, request, context):
+        return dmi.hw_management_service_pb2.StopManagingDeviceResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def GetManagedDevices(self, request, context):
+        return dmi.hw_management_service_pb2.ManagedDevicesResponse()
+
+    def GetPhysicalInventory(self, request, context):
+        for _ in range(0, 1):
+            yield dmi.hw_management_service_pb2.PhysicalInventoryResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def GetHWComponentInfo(self, request, context):
+        for _ in range(0, 1):
+            yield dmi.hw_management_service_pb2.HWComponentInfoGetResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def SetHWComponentInfo(self, request, context):
+        return dmi.hw_management_service_pb2.HWComponentInfoSetResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def SetLoggingEndpoint(self, request, context):
+        return dmi.hw_management_service_pb2.SetRemoteEndpointResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def GetLoggingEndpoint(self, request, context):
+        return dmi.hw_management_service_pb2.GetLoggingEndpointResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def SetMsgBusEndpoint(self, request, context):
+        return dmi.hw_management_service_pb2.SetRemoteEndpointResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def GetMsgBusEndpoint(self, request, context):
+        return dmi.hw_management_service_pb2.GetMsgBusEndpointResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def GetLoggableEntities(self, request, context):
+        return dmi.hw_management_service_pb2.GetLogLevelResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def SetLogLevel(self, request, context):
+        return dmi.hw_management_service_pb2.SetLogLevelResponse()
+
+    def GetLogLevel(self, request, context):
+        return dmi.hw_management_service_pb2.GetLogLevelResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def HeartbeatCheck(self, request, context):
+        return dmi.hw_management_service_pb2.Heartbeat(heartbeat_signature=0)
+
+    def RebootDevice(self, request, context):
+        return dmi.hw_management_service_pb2.RebootDeviceResponse(status=dmi.commons_pb2.OK_STATUS)
+
+
+class DmiMetricsManagementServiceServicer(dmi.hw_metrics_mgmt_service_pb2_grpc.NativeMetricsManagementServiceServicer):
+
+    def ListMetrics(self, request, context):
+        return dmi.hw_metrics_mgmt_service_pb2.ListMetricsResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def UpdateMetricsConfiguration(self, request, context):
+        return dmi.hw_metrics_mgmt_service_pb2.MetricsConfigurationResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def GetMetric(self, request, context):
+        return dmi.hw_metrics_mgmt_service_pb2.GetMetricResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def StreamMetrics(self, request, context):
+        for _ in range(0, 1):
+            yield dmi.hw_metrics_mgmt_service_pb2.Metric(metric_id=dmi.hw_metrics_mgmt_service_pb2.METRIC_NAME_UNDEFINED)
+
+
+class DmiSoftwareManagementServiceServicer(dmi.sw_management_service_pb2_grpc.NativeSoftwareManagementServiceServicer):
+
+    def GetSoftwareVersion(self, request, context):
+        return dmi.sw_management_service_pb2.GetSoftwareVersionInformationResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def DownloadImage(self, request, context):
+        for _ in range(0, 1):
+            yield dmi.sw_image_pb2.ImageStatus(status=dmi.commons_pb2.OK_STATUS)
+
+    def ActivateImage(self, request, context):
+        for _ in range(0, 1):
+            yield dmi.sw_image_pb2.ImageStatus(status=dmi.commons_pb2.OK_STATUS)
+
+    def RevertToStandbyImage(self, request, context):
+        for _ in range(0, 1):
+            yield dmi.sw_image_pb2.ImageStatus(status=dmi.commons_pb2.OK_STATUS)
+
+    def UpdateStartupConfiguration(self, request, context):
+        for _ in range(0, 1):
+            yield dmi.sw_management_service_pb2.ConfigResponse(status=dmi.commons_pb2.OK_STATUS)
+
+    def GetStartupConfigurationInfo(self, request, context):
+        return dmi.sw_management_service_pb2.StartupConfigInfoResponse(status=dmi.commons_pb2.OK_STATUS)
+
+
+def serve():
+    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+
+    dmi.hw_events_mgmt_service_pb2_grpc.add_NativeEventsManagementServiceServicer_to_server(DmiEventsManagementServiceServicer(), server)
+    dmi.hw_management_service_pb2_grpc.add_NativeHWManagementServiceServicer_to_server(DmiHwManagementServiceServicer(), server)
+    dmi.hw_metrics_mgmt_service_pb2_grpc.add_NativeMetricsManagementServiceServicer_to_server(DmiMetricsManagementServiceServicer(), server)
+    dmi.sw_management_service_pb2_grpc.add_NativeSoftwareManagementServiceServicer_to_server(DmiSoftwareManagementServiceServicer(), server)
+
+    server.add_insecure_port('127.0.01:50051')
+    server.start()
+    server.wait_for_termination()
+
+
+if __name__ == '__main__':
+    serve()
diff --git a/tests/test.robot b/tests/test.robot
new file mode 100644
index 0000000..1e0894c
--- /dev/null
+++ b/tests/test.robot
@@ -0,0 +1,172 @@
+# Copyright 2020-present Open Networking Foundation
+# Original copyright 2020-present ADTRAN, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+
+*** Settings ***
+Documentation    Library test suite for the grpc_robot library. To run the test suite, the fake device manager from
+...    _./servers/dmi_ must have been started beforehand with command _python3 dmi_server.py_.
+Library    OperatingSystem    WITH NAME    os
+Library    String
+Library    Collections
+Variables    ./variables.py
+
+*** Test Cases ***
+Library import
+    [Documentation]    Checks if the grpc_robot libraries can be imported.
+    Import Library    grpc_robot.Dmi    WITH NAME    dmi
+    Import Library    grpc_robot.Collections
+    Import Library    grpc_robot.DmiTools    WITH NAME    dtools
+    Import Library    grpc_robot.VolthaTools    WITH NAME    vtools
+
+library_versions
+    [Documentation]    Checks if the library returns the installed library and device-management-interface versions.
+    [Template]    version_check
+    grpc-robot    dmi.Library Version Get
+    device-management-interface    dmi.Dmi Version Get
+
+keywords
+    [Documentation]    Checks if the keyword name exists in the library's keyword list.
+    Keyword Should Exist    dmi.connection_close
+    Keyword Should Exist    dmi.connection_open
+    Keyword Should Exist    dmi.connection_parameters_get
+    Keyword Should Exist    dmi.connection_parameters_set
+    Keyword Should Exist    dmi.hw_event_mgmt_service_list_events
+    Keyword Should Exist    dmi.hw_event_mgmt_service_update_events_configuration
+    Keyword Should Exist    dmi.hw_management_service_get_hw_component_info
+    Keyword Should Exist    dmi.hw_management_service_get_logging_endpoint
+    Keyword Should Exist    dmi.hw_management_service_get_managed_devices
+    Keyword Should Exist    dmi.hw_management_service_get_msg_bus_endpoint
+    Keyword Should Exist    dmi.hw_management_service_get_physical_inventory
+    Keyword Should Exist    dmi.hw_management_service_set_hw_component_info
+    Keyword Should Exist    dmi.hw_management_service_set_logging_endpoint
+    Keyword Should Exist    dmi.hw_management_service_set_msg_bus_endpoint
+    Keyword Should Exist    dmi.hw_management_service_start_managing_device
+    Keyword Should Exist    dmi.hw_management_service_stop_managing_device
+    Keyword Should Exist    dmi.hw_management_service_get_loggable_entities
+    Keyword Should Exist    dmi.hw_management_service_set_log_level
+    Keyword Should Exist    dmi.hw_management_service_get_log_level
+    Keyword Should Exist    dmi.hw_metrics_mgmt_service_get_metric
+    Keyword Should Exist    dmi.hw_metrics_mgmt_service_list_metrics
+    Keyword Should Exist    dmi.hw_metrics_mgmt_service_update_metrics_configuration
+    Keyword Should Exist    dmi.sw_management_service_activate_image
+    Keyword Should Exist    dmi.sw_management_service_download_image
+    Keyword Should Exist    dmi.sw_management_service_revert_to_standby_image
+    Keyword Should Exist    dmi.sw_management_service_get_software_version
+    Keyword Should Exist    dmi.sw_management_service_update_startup_configuration
+    Keyword Should Exist    dmi.sw_management_service_get_startup_configuration_info
+    Keyword Should Exist    dtools.hw_metrics_mgmt_decode_metric
+    Keyword Should Exist    dtools.hw_events_mgmt_decode_event
+    Keyword Should Exist    vtools.events_decode_event
+    Keyword Should Exist    vtools.tech_profile_decode_resource_instance
+
+dmi
+    [Documentation]    Checks the RPC keywords whether or not they handle their input and output correctly and uses the
+    ...    fake device manager for that. The fake device manager returns _OK_STATUS_ for each RPC. The variables
+    ...    _${keywords_to_skip}_ and _${params}_ are defined in the variables file _./variables.py_.
+    [Setup]    dmi.Connection Open    host=127.0.0.1    port=50051
+    ${keywords}    Run Keyword    dmi.Get Keyword Names
+    FOR    ${keyword}    IN    @{keywords}
+        Continue For Loop If    '${keyword}' in ${keywords_to_skip}
+        ${status}    ${params}    Run Keyword And Ignore Error    Get From Dictionary     ${param_dicts}    ${keyword}
+        Run Keyword If    '${status}' == 'FAIL'    Log    no parameters available for keyword '${keyword}'    WARN
+        Continue For Loop If    '${status}' == 'FAIL'
+        Run Keyword If    ${params} == ${NONE}    ${keyword}    ELSE    ${keyword}    ${params}
+    END
+    [Teardown]    dmi.Connection Close
+
+connection_params
+    [Documentation]    Checks the connection parameter settings.
+    ${new_timeout}    Set Variable    100
+    ${settings_before}    dmi.Connection Parameters Get
+    ${settings_while_set}    dmi.Connection Parameters Set    timeout=${new_timeout}
+    ${settings_after}    dmi.Connection Parameters Get
+    Should Be Equal    ${settings_before}    ${settings_while_set}
+    Should Be Equal As Integers     ${settings_after}[timeout]    ${new_timeout}
+
+enum_and_default_values
+    [Documentation]    Checks the optional parameters _return_enum_integer_ and _return_defaults_ of the RPC keywords to
+    ...    control their output. Check keyword documentation for the meaning of the parameters.
+    ...    *Note*: The fake device manager must be running for this test case.
+    [Setup]    dmi.Connection Open    host=127.0.0.1    port=50051
+    ${params}   Get From Dictionary    ${param_dicts}    hw_management_service_get_log_level
+    ${return}   hw_management_service_get_log_level     ${params}
+    Should Be Equal As Strings    ${return}[status]    OK_STATUS
+    Dictionary Should Not Contain Key     ${return}    reason
+    ${return}   hw_management_service_get_log_level     ${params}    return_enum_integer=true
+    Should Be Equal As Integers    ${return}[status]    1
+    Dictionary Should Not Contain Key     ${return}    reason
+    ${return}   hw_management_service_get_log_level     ${params}    return_enum_integer=${TRUE}
+    Should Be Equal As Integers    ${return}[status]    1
+    Dictionary Should Not Contain Key     ${return}    reason
+    ${return}   hw_management_service_get_log_level     ${params}    return_defaults=true
+    Should Be Equal As Strings    ${return}[status]    OK_STATUS
+    Should Be Equal As Strings    ${return}[reason]    UNDEFINED_REASON
+    ${return}   hw_management_service_get_log_level     ${params}    return_defaults=${TRUE}
+    Should Be Equal As Strings    ${return}[status]    OK_STATUS
+    Should Be Equal As Strings    ${return}[reason]    UNDEFINED_REASON
+    ${return}   hw_management_service_get_log_level     ${params}    return_enum_integer=true    return_defaults=true
+    Should Be Equal As Integers    ${return}[status]    1
+    Should Be Equal As Integers    ${return}[reason]    0
+    [Teardown]    dmi.Connection Close
+
+tools
+    [Documentation]    Checks some functions from the tools library which shall support the tester with general functionality.
+    ${dict_1}    Create Dictionary    name=abc    type=123
+    ${dict_2}    Create Dictionary    name=def    type=456
+    ${list}    Create List    ${dict_1}    ${dict_2}
+    ${return_dict}    grpc_robot.Collections.List Get Dict By Value    ${list}    name    def
+    Should Be Equal    ${return_dict}[type]    456
+
+dmi_tools
+    [Documentation]    Checks functions from the DMI tools library with decoding Kafka messages. The variables
+    ...    _kafka_metric_messages_ and _kafka_event_messages_ are defined in the variables file.
+    FOR    ${kafka}    IN    @{kafka_metric_messages}
+        ${metric}    dtools.Hw Metrics Mgmt Decode Metric    ${kafka}[message]
+        Should Be Equal    ${metric}[metric_metadata][device_uuid][uuid]    4c411df2-22e6-58d2-b1bb-545a0263d18d
+        Should Be Equal    ${metric}[metric_id]    ${kafka}[metric]
+    END
+    FOR    ${kafka}    IN    @{kafka_event_messages}
+        ${event}    dtools.Hw Events Mgmt Decode Event    ${kafka}[message]
+        Should Be Equal    ${event}[event_metadata][device_uuid][uuid]    84f46fde-89fa-5a2f-be4a-6d18abe6e953
+        Should Be Equal    ${event}[event_id]    ${kafka}[event]
+    END
+
+voltha_tools
+    [Documentation]    Checks functions from the Voltha tools library with decoding Kafka messages. The variables
+    ...    _kafka_voltha_events_messages_ and _voltha_resource_instances_ are defined in the variables file.
+    FOR    ${kafka}    IN    @{kafka_voltha_events_messages}
+        ${event}    vtools.Events Decode Event    ${kafka}[message]    return_defaults=true
+        Should Be Equal    ${event}[header][id]    Voltha.openolt..1613491472935896440
+        Should Be Equal    ${event}[kpi_event2][type]    slice
+        ${event}    vtools.Events Decode Event    ${kafka}[message]
+        Dictionary Should Not Contain Key    ${event}[kpi_event2]    type
+    END
+    FOR    ${input}    IN    @{voltha_resource_instances}
+        ${instance}    vtools.Tech Profile Decode Resource Instance    ${input}    return_defaults=true
+        Should Be Equal    ${instance}[tp_id]    ${64}
+    END
+
+*** Keywords ***
+version_check
+    [Documentation]    Determines the version of the installed package and compares it with the returned version of the
+    ...    corresponding keyword.
+    [Arguments]    ${package_name}     ${kw_name}
+    ${pip show}    os.Run    python3 -m pip show ${package_name} | grep Version
+    ${pip show}    Split To Lines    ${pip show}
+    FOR    ${line}    IN    @{pip show}
+         ${is_version}    Evaluate    '${line}'.startswith('Version')
+         Continue For Loop If    not ${is_version}
+         ${pip_version}    Evaluate    '${line}'.split(':')[-1].strip()
+    END
+    ${lib_version}    Run Keyword    ${kw_name}
+    Should Be Equal    ${pip_version}    ${lib_version}
diff --git a/tests/variables.py b/tests/variables.py
new file mode 100644
index 0000000..15fd619
--- /dev/null
+++ b/tests/variables.py
@@ -0,0 +1,245 @@
+# Copyright 2020-present Open Networking Foundation
+# Original copyright 2020-present ADTRAN, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+
+keywords_to_skip = [
+    'connection_open',
+    'connection_close',
+    'connection_parameters_get',
+    'connection_parameters_set',
+    'get_keyword_names',
+    'library_version_get',
+    'dmi_version_get'
+]
+
+param_dicts = {
+    'hw_event_mgmt_service_list_events': {'uuid': {'uuid': '1234-3456-5678'}},
+    'hw_event_mgmt_service_update_events_configuration': {'device_uuid': {'uuid': '1234-3456-5678'}},
+    'hw_event_mgmt_service_stream_events': None,
+    'hw_management_service_start_managing_device': {'name': 'otti', 'uri': {'uri': '1.2.3.4'}},
+    'hw_management_service_stop_managing_device': {'name': 'otti'},
+    'hw_management_service_get_managed_devices': None,
+    'hw_management_service_get_physical_inventory': {'device_uuid': {'uuid': '1234-3456-5678'}},
+    'hw_management_service_get_hw_component_info': {'device_uuid': {'uuid': '1234-3456-5678'}},
+    'hw_management_service_set_hw_component_info': {'device_uuid': {'uuid': '1234-3456-5678'}},
+    'hw_management_service_set_logging_endpoint': {'device_uuid': {'uuid': '1234-3456-5678'}},
+    'hw_management_service_get_logging_endpoint': {'uuid': {'uuid': '1234-3456-5678'}},
+    'hw_management_service_set_msg_bus_endpoint': {'msgbus_endpoint': '1234-3456-5678'},
+    'hw_management_service_get_msg_bus_endpoint': None,
+    'hw_management_service_get_loggable_entities': {'device_uuid': {'uuid': '1234-3456-5678'}},
+    'hw_management_service_set_log_level': {'device_uuid': {'uuid': '1234-3456-5678'}},
+    'hw_management_service_get_log_level': {'device_uuid': {'uuid': '1234-3456-5678'}},
+    'hw_management_service_heartbeat_check': None,
+    'hw_management_service_reboot_device': {'device_uuid': {'uuid': '1234-3456-5678'}},
+    'hw_metrics_mgmt_service_list_metrics': {'uuid': {'uuid': '1234-3456-5678'}},
+    'hw_metrics_mgmt_service_update_metrics_configuration': {'device_uuid': {'uuid': '1234-3456-5678'}},
+    'hw_metrics_mgmt_service_get_metric': {'meta_data': {'device_uuid': {'uuid': '1234-3456-5678'}}},
+    'hw_metrics_mgmt_service_stream_metrics': None,
+    'sw_management_service_get_software_version': {'uuid': {'uuid': '1234-3456-5678'}},
+    'sw_management_service_download_image': {'device_uuid': {'uuid': '1234-3456-5678'}},
+    'sw_management_service_activate_image': {'uuid': {'uuid': '1234-3456-5678'}},
+    'sw_management_service_revert_to_standby_image': {'uuid': {'uuid': '1234-3456-5678'}},
+    'sw_management_service_update_startup_configuration': {'device_uuid': {'uuid': '1234-3456-5678'}},
+    'sw_management_service_get_startup_configuration_info': {'device_uuid': {'uuid': '1234-3456-5678'}},
+}
+
+kafka_metric_messages = [
+    {
+        'message': b"\x08e\x12Y\n&\n$4c411df2-22e6-58d2-b1bb-545a0263d18d\x12&\n$96f716bd-9e72-5c39-9a79-58bb3821df19"
+                   b"\x1a\x07cpu 0/1\x1a9\x08\x07\x10\x01\x18\t(\x012\x07percent:\x06\x08\xde\x96\x84\xfd\x05@\x88'J\x1b"
+                   b"METRIC_CPU_USAGE_PERCENTAGE",
+        'metric': 'METRIC_CPU_USAGE_PERCENTAGE'
+    },
+    {
+        'message': b"\x08\xaf\x02\x12f\n&\n$4c411df2-22e6-58d2-b1bb-545a0263d18d\x12&\n$f14853c0-51e8-5f5a-8983-e8dc9c060f5d"
+                   b"\x1a\x14storage-resource 0/1\x1a:\x08_\x10\x01\x18\t(\x012\x07percent:\x06\x08\xe3\x96\x84\xfd\x05@\x88'"
+                   b"J\x1cMETRIC_DISK_USAGE_PERCENTAGE",
+        'metric': 'METRIC_DISK_USAGE_PERCENTAGE'
+    },
+    {
+        'message': b"\x08\xf6\x03\x12b\n&\n$4c411df2-22e6-58d2-b1bb-545a0263d18d\x12&\n$81ba5a6b-b8b9-582e-9cea-a512ed6bd8ad"
+                   b"\x1a\x10power-supply 0/1\x1a;\x082\x10\x01\x18\t(\x012\x07percent:\x06\x08\xe7\x96\x84\xfd\x05@\x88'J\x1d"
+                   b"METRIC_POWER_USAGE_PERCENTAGE",
+        'metric': 'METRIC_POWER_USAGE_PERCENTAGE'
+    },
+    {
+        'message': b"\x08\xf6\x03\x12b\n&\n$4c411df2-22e6-58d2-b1bb-545a0263d18d\x12&\n$760d33cd-ad0d-541b-8014-272af0cfbff8"
+                   b"\x1a\x10power-supply 0/2\x1a;\x082\x10\x01\x18\t(\x012\x07percent:\x06\x08\xe7\x96\x84\xfd\x05@\x88'J\x1d"
+                   b"METRIC_POWER_USAGE_PERCENTAGE",
+        'metric': 'METRIC_POWER_USAGE_PERCENTAGE'
+    },
+    {
+        'message': b"\x08\x01\x12e\n&\n$4c411df2-22e6-58d2-b1bb-545a0263d18d\x12&\n$0f3a8a29-2b79-560a-a034-2255e0c85920"
+                   b"\x1a\x13pluggable-fan 0/1/1\x1a+\x08\xc0%\x10\n\x18\t(\x012\x03rpm:\x06\x08\xeb\x96\x84\xfd\x05@\x88'J\x10"
+                   b"METRIC_FAN_SPEED",
+        'metric': 'METRIC_FAN_SPEED'
+    },
+    {
+        'message': b"\x08\x01\x12e\n&\n$4c411df2-22e6-58d2-b1bb-545a0263d18d\x12&\n$80d0e158-efc0-59ea-808d-e273d1c46099"
+                   b"\x1a\x13pluggable-fan 0/1/2\x1a+\x08\xe5&\x10\n\x18\t(\x012\x03rpm:\x06\x08\xeb\x96\x84\xfd\x05@\x88'J\x10"
+                   b"METRIC_FAN_SPEED",
+        'metric': 'METRIC_FAN_SPEED'
+    },
+    {
+        'message': b"\x08\x01\x12e\n&\n$4c411df2-22e6-58d2-b1bb-545a0263d18d\x12&\n$15d3103a-36b2-5774-ae06-d2d59a2ab6e7"
+                   b"\x1a\x13pluggable-fan 0/1/3\x1a+\x08\xc8$\x10\n\x18\t(\x012\x03rpm:\x06\x08\xeb\x96\x84\xfd\x05@\x88'J\x10"
+                   b"METRIC_FAN_SPEED",
+        'metric': 'METRIC_FAN_SPEED'
+    },
+    {
+        'message': b"\x08\xd8\x04\x12a\n&\n$4c411df2-22e6-58d2-b1bb-545a0263d18d\x12&\n$dc8c95f1-6b84-5e6d-b645-c76b02b7551b"
+                   b"\x1a\x0ftemperature 0/1\x1aB\x085\x10\x08\x18\t(\x012\x0edegree Celsius:\x06\x08\xf0\x96\x84\xfd\x05@\x88'"
+                   b"J\x1dMETRIC_INNER_SURROUNDING_TEMP",
+        'metric': 'METRIC_INNER_SURROUNDING_TEMP'
+    },
+]
+
+kafka_event_messages = [
+    {
+        'message': b'\na\n&\n$84f46fde-89fa-5a2f-be4a-6d18abe6e953\x12&\n$368c6f41-564c-5821-8e15-721f818387fc\x1a\x0f'
+                    b'temperature 0/1\x10\xf7\x03\x1a\x06\x08\x80\x82\xcd\xfe\x05"\x10\n\x02\x10\x00\x12\n\n\x08\n\x02'
+                    b'\x10A\x12\x02\x10\x01',
+        'event': 'EVENT_HW_DEVICE_TEMPERATURE_ABOVE_CRITICAL_RECOVERED'
+    },
+    {
+        'message': b'\na\n&\n$84f46fde-89fa-5a2f-be4a-6d18abe6e953\x12&\n$368c6f41-564c-5821-8e15-721f818387fc\x1a\x0f'
+                    b'temperature 0/1\x10\xf8\x03\x1a\x06\x08\x80\x82\xcd\xfe\x05"\x00',
+        'event': 'EVENT_HW_DEVICE_TEMPERATURE_ABOVE_FATAL_RECOVERED'
+    },
+    {
+        'message': b'\na\n&\n$84f46fde-89fa-5a2f-be4a-6d18abe6e953\x12&\n$368c6f41-564c-5821-8e15-721f818387fc\x1a\x0f'
+                    b'temperature 0/1\x10\xf5\x03\x1a\x06\x08\xfe\xac\xdd\xfe\x05"\x10\n\x02\x10\x03\x12\n\n\x08\n\x02'
+                    b'\x10\x02\x12\x02\x10\x01*\xcf\x01The system temperature of the physical entity '
+                    b'\'temperature 0/1\' has risen above power reduction active-threshold of 2 degree Celsius. Unit '
+                    b'operates out of specification. Correct service cannot be guaranteed.',
+        'event': 'EVENT_HW_DEVICE_TEMPERATURE_ABOVE_CRITICAL'
+    },
+    {
+        'message': b'\na\n&\n$84f46fde-89fa-5a2f-be4a-6d18abe6e953\x12&\n$368c6f41-564c-5821-8e15-721f818387fc\x1a\x0f'
+                    b'temperature 0/1\x10\xf6\x03\x1a\x06\x08\xfe\xac\xdd\xfe\x05"\x00*\x86\x01The system temperature '
+                    b'of the physical entity \'temperature 0/1\' has risen above thermal shutdown active-threshold '
+                    b'of 2 degree Celsius.',
+        'event': 'EVENT_HW_DEVICE_TEMPERATURE_ABOVE_FATAL'
+    },
+    {
+        'message': b'\na\n&\n$84f46fde-89fa-5a2f-be4a-6d18abe6e953\x12&\n$368c6f41-564c-5821-8e15-721f818387fc\x1a\x0f'
+                    b'temperature 0/1\x10\xf7\x03\x1a\x06\x08\xfe\xac\xdd\xfe\x05"\x10\n\x02\x10\x00\x12\n\n\x08\n\x02'
+                    b'\x10\x02\x12\x02\x10\x01',
+        'event': 'EVENT_HW_DEVICE_TEMPERATURE_ABOVE_CRITICAL_RECOVERED'
+    },
+    {
+        'message': b'\na\n&\n$84f46fde-89fa-5a2f-be4a-6d18abe6e953\x12&\n$368c6f41-564c-5821-8e15-721f818387fc\x1a\x0f'
+                    b'temperature 0/1\x10\xf5\x03\x1a\x06\x08\xfe\xac\xdd\xfe\x05"\x10\n\x02\x10\x03\x12\n\n\x08\n\x02'
+                    b'\x10\x02\x12\x02\x10\x01*\xcf\x01The system temperature of the physical entity '
+                    b'\'temperature 0/1\' has risen above power reduction active-threshold of 2 degree Celsius. Unit '
+                    b'operates out of specification. Correct service cannot be guaranteed.',
+        'event': 'EVENT_HW_DEVICE_TEMPERATURE_ABOVE_CRITICAL'
+    },
+    {
+        'message': b'\na\n&\n$84f46fde-89fa-5a2f-be4a-6d18abe6e953\x12&\n$368c6f41-564c-5821-8e15-721f818387fc\x1a\x0f'
+                    b'temperature 0/1\x10\xf7\x03\x1a\x06\x08\xfe\xac\xdd\xfe\x05"\x10\n\x02\x10\x00\x12\n\n\x08\n\x02'
+                    b'\x10\x02\x12\x02\x10\x01',
+        'event': 'EVENT_HW_DEVICE_TEMPERATURE_ABOVE_CRITICAL_RECOVERED'
+    },
+    {
+        'message': b'\na\n&\n$84f46fde-89fa-5a2f-be4a-6d18abe6e953\x12&\n$368c6f41-564c-5821-8e15-721f818387fc\x1a\x0f'
+                    b'temperature 0/1\x10\xf5\x03\x1a\x06\x08\xfe\xac\xdd\xfe\x05"\x10\n\x02\x10\x03\x12\n\n\x08\n\x02'
+                    b'\x10\x02\x12\x02\x10\x01*\xcf\x01The system temperature of the physical entity '
+                    b'\'temperature 0/1\' has risen above power reduction active-threshold of 2 degree Celsius. Unit '
+                    b'operates out of specification. Correct service cannot be guaranteed.',
+        'event': 'EVENT_HW_DEVICE_TEMPERATURE_ABOVE_CRITICAL'
+    },
+]
+
+kafka_voltha_events_messages = [
+    {
+        'message': b'\nL\n#Voltha.openolt..1613491472935896440\x10\x02\x18\x04 \x02*\x030.12\x0c\x08\x90\xda\xaf\x81\x06\x10\x97\xb2\xa2\xbe\x03:\x0c\x08'
+                   b'\x90\xda\xaf\x81\x06\x10\x86\xd3\xa2\xbe\x03"\xc2\x02\x11@w,\xf2Ed\xb6C\x1a\xb6\x02\n\x93\x01\n\x08NNIStats\x119w,\xf2Ed\xb6C*$a3281'
+                   b'32d-ad87-4edf-976e-ad1a364144012-\n\x05oltid\x12$a328132d-ad87-4edf-976e-ad1a364144012\x15\n\ndevicetype\x12\x07openolt2\x12\n\tport'
+                   b'label\x12\x05nni-0\x12\x15\n\x0eTxMcastPackets\x15\x00\x80\xccD\x12\x15\n\x0eTxBcastPackets\x15\x00\x80\xccD\x12\x0e\n\x07RxBytes\x15'
+                   b'\x00p\xaaH\x12\x10\n\tRxPackets\x15\x00p\xaaE\x12\x15\n\x0eRxMcastPackets\x15\x00\x80\xccD\x12\x15\n\x0eRxBcastPackets\x15\x00\x80\xcc'
+                   b'D\x12\x0e\n\x07TxBytes\x15\x00p\xaaH\x12\x10\n\tTxPackets\x15\x00p\xaaE',
+        'timestamp': -1,
+        'topic': 'voltha.events'
+    },
+    {
+        'message': b'\nJ\n#Voltha.openolt..1613491472935896440\x10\x02 \x02*\x030.12\x0c\x08\x90\xda\xaf\x81\x06\x10\xdf\xba\xa6\xbe\x03:\x0c\x08\x90\xda'
+                   b'\xaf\x81\x06\x10\xb8\xcf\xa6\xbe\x03"\xc2\x02\x11?x,\xf2Ed\xb6C\x1a\xb6\x02\n\x93\x01\n\x08PONStats\x11=x,\xf2Ed\xb6C*$a328132d-ad87'
+                   b'-4edf-976e-ad1a364144012-\n\x05oltid\x12$a328132d-ad87-4edf-976e-ad1a364144012\x15\n\ndevicetype\x12\x07openolt2\x12\n\tportlabel\x12'
+                   b'\x05pon-0\x12\x0e\n\x07TxBytes\x15\x00\xd0\xa6H\x12\x10\n\tTxPackets\x15\x00\xd0\xa6E\x12\x15\n\x0eTxMcastPackets\x15\x00 \xc8D\x12'
+                   b'\x15\n\x0eTxBcastPackets\x15\x00 \xc8D\x12\x0e\n\x07RxBytes\x15\x00\xd0\xa6H\x12\x10\n\tRxPackets\x15\x00\xd0\xa6E\x12\x15\n\x0eRxMc'
+                   b'astPackets\x15\x00 \xc8D\x12\x15\n\x0eRxBcastPackets\x15\x00 \xc8D',
+        'timestamp': -1,
+        'topic': 'voltha.events'
+    },
+    {
+        'message': b'\nJ\n#Voltha.openolt..1613491472935896440\x10\x02 \x02*\x030.12\x0c\x08\xb8\xab\xb8\x81\x06\x10\x80\x8f\xc8\xb4\x02:\x0c\x08\xb8\xab'
+                   b'\xb8\x81\x06\x10\xae\xa1\xc8\xb4\x02"\xc2\x02\x119e\xfc\x9e\xc6d\xb6C\x1a\xb6\x02\n\x93\x01\n\x08PONStats\x118e\xfc\x9e\xc6d\xb6C*$4'
+                   b'fce7729-d898-43af-a12a-d143fea0abea2\x15\n\ndevicetype\x12\x07openolt2\x12\n\tportlabel\x12\x05pon-02-\n\x05oltid\x12$4fce7729-d898-'
+                   b'43af-a12a-d143fea0abea\x12\x10\n\tRxPackets\x15\x00\xc0\x06E\x12\x15\n\x0eRxMcastPackets\x15\x00\x80!D\x12\x15\n\x0eRxBcastPackets'
+                   b'\x15\x00\x80!D\x12\x0e\n\x07TxBytes\x15\x00\xc0\x06H\x12\x10\n\tTxPackets\x15\x00\xc0\x06E\x12\x15\n\x0eTxMcastPackets\x15\x00\x80!D'
+                   b'\x12\x15\n\x0eTxBcastPackets\x15\x00\x80!D\x12\x0e\n\x07RxBytes\x15\x00\xc0\x06H',
+        'timestamp': -1,
+        'topic': 'voltha.events'
+    },
+    {
+        'message': b'\nD\n#Voltha.openolt..1613491472935896440\x10\x02 \x02*\x030.12\x06\x08\xad\xe3\xba\x87\x06:\x0c\x08\xad\xe3\xba\x87\x06\x10\xd9'
+                   b'\xc9\xc8\x8f\x01"\xc2\x02\x11\x00\x00@k\xac;\xd8A\x1a\xb6\x02\n\x93\x01\n\x08PONStats\x11\x00\x00@k\xac;\xd8A*$65950aaf-b40f-4697'
+                   b'-b5c3-8deb50fedd5d2-\n\x05oltid\x12$65950aaf-b40f-4697-b5c3-8deb50fedd5d2\x15\n\ndevicetype\x12\x07openolt2\x12\n\tportlabel\x12'
+                   b'\x05pon-0\x12\x10\n\tTxPackets\x15\x00\x00\x8bC\x12\x15\n\x0eTxMcastPackets\x15\x00\x00\xa6B\x12\x15\n\x0eTxBcastPackets\x15\x00'
+                   b'\x00\xa6B\x12\x0e\n\x07RxBytes\x15\x00\x00\x8bF\x12\x10\n\tRxPackets\x15\x00\x00\x8bC\x12\x15\n\x0eRxMcastPackets\x15\x00\x00\xa6'
+                   b'B\x12\x15\n\x0eRxBcastPackets\x15\x00\x00\xa6B\x12\x0e\n\x07TxBytes\x15\x00\x00\x8bF',
+        'timestamp': -1,
+        'topic': 'voltha.events'
+    }
+]
+
+voltha_resource_instances = [
+        b"\x08\x40\x12\x07\x58\x47\x53\x2d\x50\x4f\x4e\x1a\x42\x6f\x6c\x74\x2d\x7b\x39\x35\x36\x31\x37\x31\x32\x62\x2d\x35\x33\x32\x33\x2d\x34\x64\x64"
+        b"\x63\x2d\x38\x36\x62\x34\x2d\x64\x35\x31\x62\x62\x34\x61\x65\x30\x37\x33\x39\x7d\x2f\x70\x6f\x6e\x2d\x7b\x31\x7d\x2f\x6f\x6e\x75\x2d\x7b\x32"
+        b"\x7d\x2f\x75\x6e\x69\x2d\x7b\x30\x7d\x20\x81\x08\x2a\x10\x88\x08\x89\x08\x8a\x08\x8b\x08\x8c\x08\x8d\x08\x8e\x08\x8f\x08",
+        b"\x08\x40\x12\x07\x58\x47\x53\x2d\x50\x4f\x4e\x1a\x42\x6f\x6c\x74\x2d\x7b\x35\x66\x35\x39\x61\x32\x32\x63\x2d\x37\x63\x37\x65\x2d\x34\x65\x30"
+        b"\x63\x2d\x39\x38\x30\x65\x2d\x37\x34\x66\x31\x35\x33\x62\x33\x32\x33\x38\x31\x7d\x2f\x70\x6f\x6e\x2d\x7b\x30\x7d\x2f\x6f\x6e\x75\x2d\x7b\x31"
+        b"\x7d\x2f\x75\x6e\x69\x2d\x7b\x30\x7d\x20\x81\x08\x2a\x10\x88\x08\x89\x08\x8a\x08\x8b\x08\x8c\x08\x8d\x08\x8e\x08\x8f\x08",
+        b"\x08\x40\x12\x07\x58\x47\x53\x2d\x50\x4f\x4e\x1a\x42\x6f\x6c\x74\x2d\x7b\x35\x66\x35\x39\x61\x32\x32\x63\x2d\x37\x63\x37\x65\x2d\x34\x65\x30"
+        b"\x63\x2d\x39\x38\x30\x65\x2d\x37\x34\x66\x31\x35\x33\x62\x33\x32\x33\x38\x31\x7d\x2f\x70\x6f\x6e\x2d\x7b\x30\x7d\x2f\x6f\x6e\x75\x2d\x7b\x32"
+        b"\x7d\x2f\x75\x6e\x69\x2d\x7b\x30\x7d\x20\x80\x08\x2a\x10\x80\x08\x81\x08\x82\x08\x83\x08\x84\x08\x85\x08\x86\x08\x87\x08",
+        b"\x08\x40\x12\x07\x58\x47\x53\x2d\x50\x4f\x4e\x1a\x42\x6f\x6c\x74\x2d\x7b\x35\x66\x35\x39\x61\x32\x32\x63\x2d\x37\x63\x37\x65\x2d\x34\x65\x30"
+        b"\x63\x2d\x39\x38\x30\x65\x2d\x37\x34\x66\x31\x35\x33\x62\x33\x32\x33\x38\x31\x7d\x2f\x70\x6f\x6e\x2d\x7b\x31\x7d\x2f\x6f\x6e\x75\x2d\x7b\x31"
+        b"\x7d\x2f\x75\x6e\x69\x2d\x7b\x30\x7d\x20\x81\x08\x2a\x10\x88\x08\x89\x08\x8a\x08\x8b\x08\x8c\x08\x8d\x08\x8e\x08\x8f\x08",
+        b"\x08\x40\x12\x07\x58\x47\x53\x2d\x50\x4f\x4e\x1a\x42\x6f\x6c\x74\x2d\x7b\x35\x66\x35\x39\x61\x32\x32\x63\x2d\x37\x63\x37\x65\x2d\x34\x65\x30"
+        b"\x63\x2d\x39\x38\x30\x65\x2d\x37\x34\x66\x31\x35\x33\x62\x33\x32\x33\x38\x31\x7d\x2f\x70\x6f\x6e\x2d\x7b\x31\x7d\x2f\x6f\x6e\x75\x2d\x7b\x32"
+        b"\x7d\x2f\x75\x6e\x69\x2d\x7b\x30\x7d\x20\x80\x08\x2a\x10\x80\x08\x81\x08\x82\x08\x83\x08\x84\x08\x85\x08\x86\x08\x87\x08",
+        b"\x08\x40\x12\x07\x58\x47\x53\x2d\x50\x4f\x4e\x1a\x42\x6f\x6c\x74\x2d\x7b\x38\x34\x62\x35\x64\x35\x61\x39\x2d\x33\x34\x64\x66\x2d\x34\x61\x33"
+        b"\x37\x2d\x62\x66\x37\x64\x2d\x63\x37\x37\x61\x34\x65\x33\x34\x33\x61\x37\x64\x7d\x2f\x70\x6f\x6e\x2d\x7b\x30\x7d\x2f\x6f\x6e\x75\x2d\x7b\x31"
+        b"\x7d\x2f\x75\x6e\x69\x2d\x7b\x30\x7d\x20\x81\x08\x2a\x10\x88\x08\x89\x08\x8a\x08\x8b\x08\x8c\x08\x8d\x08\x8e\x08\x8f\x08",
+        b"\x08\x40\x12\x07\x58\x47\x53\x2d\x50\x4f\x4e\x1a\x42\x6f\x6c\x74\x2d\x7b\x38\x34\x62\x35\x64\x35\x61\x39\x2d\x33\x34\x64\x66\x2d\x34\x61\x33"
+        b"\x37\x2d\x62\x66\x37\x64\x2d\x63\x37\x37\x61\x34\x65\x33\x34\x33\x61\x37\x64\x7d\x2f\x70\x6f\x6e\x2d\x7b\x30\x7d\x2f\x6f\x6e\x75\x2d\x7b\x32"
+        b"\x7d\x2f\x75\x6e\x69\x2d\x7b\x30\x7d\x20\x80\x08\x2a\x10\x80\x08\x81\x08\x82\x08\x83\x08\x84\x08\x85\x08\x86\x08\x87\x08",
+        b"\x08\x40\x12\x07\x58\x47\x53\x2d\x50\x4f\x4e\x1a\x42\x6f\x6c\x74\x2d\x7b\x38\x34\x62\x35\x64\x35\x61\x39\x2d\x33\x34\x64\x66\x2d\x34\x61\x33"
+        b"\x37\x2d\x62\x66\x37\x64\x2d\x63\x37\x37\x61\x34\x65\x33\x34\x33\x61\x37\x64\x7d\x2f\x70\x6f\x6e\x2d\x7b\x31\x7d\x2f\x6f\x6e\x75\x2d\x7b\x31"
+        b"\x7d\x2f\x75\x6e\x69\x2d\x7b\x30\x7d\x20\x80\x08\x2a\x10\x80\x08\x81\x08\x82\x08\x83\x08\x84\x08\x85\x08\x86\x08\x87\x08",
+        b"\x08\x40\x12\x07\x58\x47\x53\x2d\x50\x4f\x4e\x1a\x42\x6f\x6c\x74\x2d\x7b\x38\x34\x62\x35\x64\x35\x61\x39\x2d\x33\x34\x64\x66\x2d\x34\x61\x33"
+        b"\x37\x2d\x62\x66\x37\x64\x2d\x63\x37\x37\x61\x34\x65\x33\x34\x33\x61\x37\x64\x7d\x2f\x70\x6f\x6e\x2d\x7b\x31\x7d\x2f\x6f\x6e\x75\x2d\x7b\x32"
+        b"\x7d\x2f\x75\x6e\x69\x2d\x7b\x30\x7d\x20\x81\x08\x2a\x10\x88\x08\x89\x08\x8a\x08\x8b\x08\x8c\x08\x8d\x08\x8e\x08\x8f\x08",
+        b"\x08\x40\x12\x07\x58\x47\x53\x2d\x50\x4f\x4e\x1a\x42\x6f\x6c\x74\x2d\x7b\x61\x61\x34\x36\x63\x62\x63\x61\x2d\x39\x31\x64\x37\x2d\x34\x36\x64"
+        b"\x65\x2d\x61\x61\x30\x65\x2d\x61\x32\x65\x33\x64\x32\x36\x61\x61\x66\x36\x32\x7d\x2f\x70\x6f\x6e\x2d\x7b\x30\x7d\x2f\x6f\x6e\x75\x2d\x7b\x31"
+        b"\x7d\x2f\x75\x6e\x69\x2d\x7b\x30\x7d\x20\x80\x08\x2a\x10\x80\x08\x81\x08\x82\x08\x83\x08\x84\x08\x85\x08\x86\x08\x87\x08",
+        "\x08\x40\x12\x07\x58\x47\x53\x2d\x50\x4f\x4e\x1a\x42\x6f\x6c\x74\x2d\x7b\x61\x61\x34\x36\x63\x62\x63\x61\x2d\x39\x31\x64\x37\x2d\x34\x36\x64"
+        "\x65\x2d\x61\x61\x30\x65\x2d\x61\x32\x65\x33\x64\x32\x36\x61\x61\x66\x36\x32\x7d\x2f\x70\x6f\x6e\x2d\x7b\x30\x7d\x2f\x6f\x6e\x75\x2d\x7b\x31"
+        "\x7d\x2f\x75\x6e\x69\x2d\x7b\x30\x7d\x20\x80\x08\x2a\x10\x80\x08\x81\x08\x82\x08\x83\x08\x84\x08\x85\x08\x86\x08\x87\x08",
+        "\\x08\\x40\\x12\\x07\\x58\\x47\\x53\\x2d\\x50\\x4f\\x4e\\x1a\\x42\\x6f\\x6c\\x74\\x2d\\x7b\\x61\\x61\\x34\\x36\\x63\\x62\\x63\\x61\\x2d\\x39"
+        "\\x31\\x64\\x37\\x2d\\x34\\x36\\x64\\x65\\x2d\\x61\\x61\\x30\\x65\\x2d\\x61\\x32\\x65\\x33\\x64\\x32\\x36\\x61\\x61\\x66\\x36\\x32\\x7d\\x2f"
+        "\\x70\\x6f\\x6e\\x2d\\x7b\\x30\\x7d\\x2f\\x6f\\x6e\\x75\\x2d\\x7b\\x31\\x7d\\x2f\\x75\\x6e\\x69\\x2d\\x7b\\x30\\x7d\\x20\\x80\\x08\\x2a\\x10"
+        "\\x80\\x08\\x81\\x08\\x82\\x08\\x83\\x08\\x84\\x08\\x85\\x08\\x86\\x08\\x87\\x08"
+    ]