From 1d77cb00ae8f577885de32f01f4740f865853863 Mon Sep 17 00:00:00 2001
From: Fotis Soldatos <fsoldatos@ubitech.eu>
Date: Tue, 26 Jul 2022 13:10:40 +0300
Subject: [PATCH] feat(policy): add Device domain model

---
 .../java/eu/teraflow/policy/Serializer.java   | 178 ++++++++
 .../teraflow/policy/context/model/Device.java |  83 ++++
 .../policy/context/model/DeviceConfig.java    |  39 ++
 .../context/model/DeviceDriverEnum.java       |  26 ++
 .../model/DeviceOperationalStatus.java        |  23 +
 .../policy/context/model/EndPoint.java        |  66 +++
 .../eu/teraflow/policy/SerializerTest.java    | 412 ++++++++++++++++++
 7 files changed, 827 insertions(+)
 create mode 100644 src/policy/src/main/java/eu/teraflow/policy/context/model/Device.java
 create mode 100644 src/policy/src/main/java/eu/teraflow/policy/context/model/DeviceConfig.java
 create mode 100644 src/policy/src/main/java/eu/teraflow/policy/context/model/DeviceDriverEnum.java
 create mode 100644 src/policy/src/main/java/eu/teraflow/policy/context/model/DeviceOperationalStatus.java
 create mode 100644 src/policy/src/main/java/eu/teraflow/policy/context/model/EndPoint.java

diff --git a/src/policy/src/main/java/eu/teraflow/policy/Serializer.java b/src/policy/src/main/java/eu/teraflow/policy/Serializer.java
index f794d8baf..997085212 100644
--- a/src/policy/src/main/java/eu/teraflow/policy/Serializer.java
+++ b/src/policy/src/main/java/eu/teraflow/policy/Serializer.java
@@ -22,6 +22,7 @@ import context.ContextOuterClass.ConfigRule_ACL;
 import context.ContextOuterClass.ConfigRule_Custom;
 import context.ContextOuterClass.ContextId;
 import context.ContextOuterClass.DeviceId;
+import context.ContextOuterClass.DeviceOperationalStatusEnum;
 import context.ContextOuterClass.Uuid;
 import eu.teraflow.policy.acl.AclAction;
 import eu.teraflow.policy.acl.AclEntry;
@@ -51,6 +52,11 @@ import eu.teraflow.policy.context.model.ConstraintTypeSlaAvailability;
 import eu.teraflow.policy.context.model.ConstraintTypeSlaCapacity;
 import eu.teraflow.policy.context.model.ConstraintTypeSlaIsolationLevel;
 import eu.teraflow.policy.context.model.ConstraintTypeSlaLatency;
+import eu.teraflow.policy.context.model.Device;
+import eu.teraflow.policy.context.model.DeviceConfig;
+import eu.teraflow.policy.context.model.DeviceDriverEnum;
+import eu.teraflow.policy.context.model.DeviceOperationalStatus;
+import eu.teraflow.policy.context.model.EndPoint;
 import eu.teraflow.policy.context.model.EndPointId;
 import eu.teraflow.policy.context.model.Event;
 import eu.teraflow.policy.context.model.EventTypeEnum;
@@ -1952,6 +1958,178 @@ public class Serializer {
                 sliceId);
     }
 
+    public ContextOuterClass.DeviceConfig serialize(DeviceConfig deviceConfig) {
+        final var builder = ContextOuterClass.DeviceConfig.newBuilder();
+
+        final var serializedConfigRules =
+                deviceConfig.getConfigRules().stream().map(this::serialize).collect(Collectors.toList());
+        builder.addAllConfigRules(serializedConfigRules);
+
+        return builder.build();
+    }
+
+    public DeviceConfig deserialize(ContextOuterClass.DeviceConfig deviceConfig) {
+        final var configRules =
+                deviceConfig.getConfigRulesList().stream()
+                        .map(this::deserialize)
+                        .collect(Collectors.toList());
+
+        return new DeviceConfig(configRules);
+    }
+
+    public ContextOuterClass.DeviceOperationalStatusEnum serialize(DeviceOperationalStatus opStatus) {
+        switch (opStatus) {
+            case ENABLED:
+                return DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED;
+            case DISABLED:
+                return DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED;
+            case UNDEFINED:
+            default:
+                return DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_UNDEFINED;
+        }
+    }
+
+    public DeviceOperationalStatus deserialize(
+            ContextOuterClass.DeviceOperationalStatusEnum opStatus) {
+        switch (opStatus) {
+            case DEVICEOPERATIONALSTATUS_ENABLED:
+                return DeviceOperationalStatus.ENABLED;
+            case DEVICEOPERATIONALSTATUS_DISABLED:
+                return DeviceOperationalStatus.DISABLED;
+            case DEVICEOPERATIONALSTATUS_UNDEFINED:
+            case UNRECOGNIZED:
+            default:
+                return DeviceOperationalStatus.UNDEFINED;
+        }
+    }
+
+    public ContextOuterClass.DeviceDriverEnum serialize(DeviceDriverEnum deviceDriverEnum) {
+        switch (deviceDriverEnum) {
+            case OPENCONFIG:
+                return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG;
+            case TRANSPORT_API:
+                return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API;
+            case P4:
+                return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_P4;
+            case IETF_NETWORK_TOPOLOGY:
+                return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY;
+            case ONF_TR_352:
+                return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352;
+            case UNDEFINED:
+            default:
+                return ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_UNDEFINED;
+        }
+    }
+
+    public DeviceDriverEnum deserialize(
+            ContextOuterClass.DeviceDriverEnum serializedDeviceDriverEnum) {
+        switch (serializedDeviceDriverEnum) {
+            case DEVICEDRIVER_OPENCONFIG:
+                return DeviceDriverEnum.OPENCONFIG;
+            case DEVICEDRIVER_TRANSPORT_API:
+                return DeviceDriverEnum.TRANSPORT_API;
+            case DEVICEDRIVER_P4:
+                return DeviceDriverEnum.P4;
+            case DEVICEDRIVER_IETF_NETWORK_TOPOLOGY:
+                return DeviceDriverEnum.IETF_NETWORK_TOPOLOGY;
+            case DEVICEDRIVER_ONF_TR_352:
+                return DeviceDriverEnum.ONF_TR_352;
+            case DEVICEDRIVER_UNDEFINED:
+            case UNRECOGNIZED:
+            default:
+                return DeviceDriverEnum.UNDEFINED;
+        }
+    }
+
+    public ContextOuterClass.EndPoint serialize(EndPoint endPoint) {
+        final var builder = ContextOuterClass.EndPoint.newBuilder();
+
+        final var endPointId = endPoint.getEndPointId();
+        final var endPointType = endPoint.getEndPointType();
+        final var kpiSampleTypes = endPoint.getKpiSampleTypes();
+        final var endPointLocation = endPoint.getEndPointLocation();
+
+        final var serializedEndPointId = serialize(endPointId);
+        final var serializedKpiSampleTypes =
+                kpiSampleTypes.stream().map(this::serialize).collect(Collectors.toList());
+        final var serializedEndPointLocation = serialize(endPointLocation);
+
+        builder.setEndpointId(serializedEndPointId);
+        builder.setEndpointType(endPointType);
+        builder.addAllKpiSampleTypes(serializedKpiSampleTypes);
+        builder.setEndpointLocation(serializedEndPointLocation);
+
+        return builder.build();
+    }
+
+    public EndPoint deserialize(ContextOuterClass.EndPoint serializedEndPoint) {
+        final var serializedEndPointId = serializedEndPoint.getEndpointId();
+        final var endPointType = serializedEndPoint.getEndpointType();
+        final var serializedKpiSampleTypes = serializedEndPoint.getKpiSampleTypesList();
+        final var serializedEndPointLocation = serializedEndPoint.getEndpointLocation();
+
+        final var endPointId = deserialize(serializedEndPointId);
+        final var kpiSampleTypes =
+                serializedKpiSampleTypes.stream().map(this::deserialize).collect(Collectors.toList());
+        final var endPointLocation = deserialize(serializedEndPointLocation);
+
+        return new EndPoint(endPointId, endPointType, kpiSampleTypes, endPointLocation);
+    }
+
+    public ContextOuterClass.Device serialize(Device device) {
+        final var builder = ContextOuterClass.Device.newBuilder();
+
+        final var deviceIdUuid = serializeUuid(device.getDeviceId());
+        final var deviceId = DeviceId.newBuilder().setDeviceUuid(deviceIdUuid);
+        final var deviceType = device.getDeviceType();
+        final var deviceConfig = device.getDeviceConfig();
+        final var deviceOperationalStatus = device.getDeviceOperationalStatus();
+        final var deviceDrivers = device.getDeviceDrivers();
+        final var deviceEndPoints = device.getEndPoints();
+
+        final var serializedDeviceConfig = serialize(deviceConfig);
+        final var serializedDeviceOperationalStatus = serialize(deviceOperationalStatus);
+        final var serializedDeviceDrivers =
+                deviceDrivers.stream().map(this::serialize).collect(Collectors.toList());
+        final var serializedDeviceEndPoints =
+                deviceEndPoints.stream().map(this::serialize).collect(Collectors.toList());
+
+        builder.setDeviceId(deviceId);
+        builder.setDeviceType(deviceType);
+        builder.setDeviceConfig(serializedDeviceConfig);
+        builder.setDeviceOperationalStatus(serializedDeviceOperationalStatus);
+        builder.addAllDeviceDrivers(serializedDeviceDrivers);
+        builder.addAllDeviceEndpoints(serializedDeviceEndPoints);
+
+        return builder.build();
+    }
+
+    public Device deserialize(ContextOuterClass.Device device) {
+
+        final var serializedDeviceId = device.getDeviceId();
+        final var deviceType = device.getDeviceType();
+        final var serializedDeviceConfig = device.getDeviceConfig();
+        final var serializedDeviceOperationalStatus = device.getDeviceOperationalStatus();
+        final var serializedDeviceDrivers = device.getDeviceDriversList();
+        final var serializedDeviceEndPoints = device.getDeviceEndpointsList();
+
+        final var deviceId = deserialize(serializedDeviceId);
+        final var deviceConfig = deserialize(serializedDeviceConfig);
+        final var deviceOperationalStatus = deserialize(serializedDeviceOperationalStatus);
+        final var deviceDrivers =
+                serializedDeviceDrivers.stream().map(this::deserialize).collect(Collectors.toList());
+        final var deviceEndPoints =
+                serializedDeviceEndPoints.stream().map(this::deserialize).collect(Collectors.toList());
+
+        return new Device(
+                deviceId,
+                deviceType,
+                deviceConfig,
+                deviceOperationalStatus,
+                deviceDrivers,
+                deviceEndPoints);
+    }
+
     public Uuid serializeUuid(String uuid) {
         return Uuid.newBuilder().setUuid(uuid).build();
     }
diff --git a/src/policy/src/main/java/eu/teraflow/policy/context/model/Device.java b/src/policy/src/main/java/eu/teraflow/policy/context/model/Device.java
new file mode 100644
index 000000000..b00fd235c
--- /dev/null
+++ b/src/policy/src/main/java/eu/teraflow/policy/context/model/Device.java
@@ -0,0 +1,83 @@
+/*
+* Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
+*
+* 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
+* limitations under the License.
+*/
+
+package eu.teraflow.policy.context.model;
+
+import eu.teraflow.policy.common.Util;
+import java.util.List;
+
+public class Device {
+
+    private final String deviceId;
+    private final String deviceType;
+    private DeviceConfig deviceConfig;
+    private DeviceOperationalStatus deviceOperationalStatus;
+    private List<DeviceDriverEnum> deviceDrivers;
+    private List<EndPoint> endPoints;
+
+    public Device(
+            String deviceId,
+            String deviceType,
+            DeviceConfig deviceConfig,
+            DeviceOperationalStatus deviceOperationalStatus,
+            List<DeviceDriverEnum> deviceDrivers,
+            List<EndPoint> endPoints) {
+
+        this.deviceId = deviceId;
+        this.deviceType = deviceType;
+        this.deviceConfig = deviceConfig;
+        this.deviceOperationalStatus = deviceOperationalStatus;
+        this.deviceDrivers = deviceDrivers;
+        this.endPoints = endPoints;
+    }
+
+    public String getDeviceId() {
+        return deviceId;
+    }
+
+    public String getDeviceType() {
+        return deviceType;
+    }
+
+    public DeviceConfig getDeviceConfig() {
+        return deviceConfig;
+    }
+
+    public DeviceOperationalStatus getDeviceOperationalStatus() {
+        return deviceOperationalStatus;
+    }
+
+    public List<DeviceDriverEnum> getDeviceDrivers() {
+        return deviceDrivers;
+    }
+
+    public List<EndPoint> getEndPoints() {
+        return endPoints;
+    }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "%s:{deviceId:\"%s\", deviceType:\"%s\", %s, deviceOperationalStatus=\"%s\", [%s], [%s]}",
+                getClass().getSimpleName(),
+                deviceId,
+                deviceType,
+                deviceConfig,
+                deviceOperationalStatus.toString(),
+                Util.toString(deviceDrivers),
+                Util.toString(endPoints));
+    }
+}
diff --git a/src/policy/src/main/java/eu/teraflow/policy/context/model/DeviceConfig.java b/src/policy/src/main/java/eu/teraflow/policy/context/model/DeviceConfig.java
new file mode 100644
index 000000000..e6fa702dd
--- /dev/null
+++ b/src/policy/src/main/java/eu/teraflow/policy/context/model/DeviceConfig.java
@@ -0,0 +1,39 @@
+/*
+* Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
+*
+* 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
+* limitations under the License.
+*/
+
+package eu.teraflow.policy.context.model;
+
+import eu.teraflow.policy.common.Util;
+import java.util.List;
+
+public class DeviceConfig {
+
+    private final List<ConfigRule> configRules;
+
+    public DeviceConfig(List<ConfigRule> configRules) {
+
+        this.configRules = configRules;
+    }
+
+    public List<ConfigRule> getConfigRules() {
+        return configRules;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s:{[%s]}", getClass().getSimpleName(), Util.toString(configRules));
+    }
+}
diff --git a/src/policy/src/main/java/eu/teraflow/policy/context/model/DeviceDriverEnum.java b/src/policy/src/main/java/eu/teraflow/policy/context/model/DeviceDriverEnum.java
new file mode 100644
index 000000000..c98fc1fce
--- /dev/null
+++ b/src/policy/src/main/java/eu/teraflow/policy/context/model/DeviceDriverEnum.java
@@ -0,0 +1,26 @@
+/*
+* Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
+*
+* 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
+* limitations under the License.
+*/
+
+package eu.teraflow.policy.context.model;
+
+public enum DeviceDriverEnum {
+    UNDEFINED,
+    OPENCONFIG,
+    TRANSPORT_API,
+    P4,
+    IETF_NETWORK_TOPOLOGY,
+    ONF_TR_352
+}
diff --git a/src/policy/src/main/java/eu/teraflow/policy/context/model/DeviceOperationalStatus.java b/src/policy/src/main/java/eu/teraflow/policy/context/model/DeviceOperationalStatus.java
new file mode 100644
index 000000000..2efe9052e
--- /dev/null
+++ b/src/policy/src/main/java/eu/teraflow/policy/context/model/DeviceOperationalStatus.java
@@ -0,0 +1,23 @@
+/*
+* Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
+*
+* 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
+* limitations under the License.
+*/
+
+package eu.teraflow.policy.context.model;
+
+public enum DeviceOperationalStatus {
+    UNDEFINED,
+    DISABLED,
+    ENABLED
+}
diff --git a/src/policy/src/main/java/eu/teraflow/policy/context/model/EndPoint.java b/src/policy/src/main/java/eu/teraflow/policy/context/model/EndPoint.java
new file mode 100644
index 000000000..a657b5921
--- /dev/null
+++ b/src/policy/src/main/java/eu/teraflow/policy/context/model/EndPoint.java
@@ -0,0 +1,66 @@
+/*
+* Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
+*
+* 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
+* limitations under the License.
+*/
+
+package eu.teraflow.policy.context.model;
+
+import eu.teraflow.policy.common.Util;
+import eu.teraflow.policy.kpi_sample_types.model.KpiSampleType;
+import java.util.List;
+
+public class EndPoint {
+    private final EndPointId endPointId;
+    private final String endPointType;
+    private final List<KpiSampleType> kpiSampleTypes;
+    private final Location endPointLocation;
+
+    public EndPoint(
+            EndPointId endPointId,
+            String endPointType,
+            List<KpiSampleType> kpiSampleTypes,
+            Location endPointLocation) {
+        this.endPointId = endPointId;
+        this.endPointType = endPointType;
+        this.kpiSampleTypes = kpiSampleTypes;
+        this.endPointLocation = endPointLocation;
+    }
+
+    public EndPointId getEndPointId() {
+        return endPointId;
+    }
+
+    public String getEndPointType() {
+        return endPointType;
+    }
+
+    public List<KpiSampleType> getKpiSampleTypes() {
+        return kpiSampleTypes;
+    }
+
+    public Location getEndPointLocation() {
+        return endPointLocation;
+    }
+
+    @Override
+    public String toString() {
+        return String.format(
+                "%s:{%s, endPointType:\"%s\", [%s], %s}",
+                getClass().getSimpleName(),
+                endPointId,
+                endPointType,
+                Util.toString(kpiSampleTypes),
+                endPointLocation);
+    }
+}
diff --git a/src/policy/src/test/java/eu/teraflow/policy/SerializerTest.java b/src/policy/src/test/java/eu/teraflow/policy/SerializerTest.java
index 49aa004be..e8c582013 100644
--- a/src/policy/src/test/java/eu/teraflow/policy/SerializerTest.java
+++ b/src/policy/src/test/java/eu/teraflow/policy/SerializerTest.java
@@ -23,6 +23,7 @@ import acl.Acl;
 import context.ContextOuterClass;
 import context.ContextOuterClass.ContextId;
 import context.ContextOuterClass.DeviceId;
+import context.ContextOuterClass.DeviceOperationalStatusEnum;
 import context.ContextOuterClass.Uuid;
 import eu.teraflow.policy.acl.AclAction;
 import eu.teraflow.policy.acl.AclEntry;
@@ -52,6 +53,11 @@ import eu.teraflow.policy.context.model.ConstraintTypeSlaAvailability;
 import eu.teraflow.policy.context.model.ConstraintTypeSlaCapacity;
 import eu.teraflow.policy.context.model.ConstraintTypeSlaIsolationLevel;
 import eu.teraflow.policy.context.model.ConstraintTypeSlaLatency;
+import eu.teraflow.policy.context.model.Device;
+import eu.teraflow.policy.context.model.DeviceConfig;
+import eu.teraflow.policy.context.model.DeviceDriverEnum;
+import eu.teraflow.policy.context.model.DeviceOperationalStatus;
+import eu.teraflow.policy.context.model.EndPoint;
 import eu.teraflow.policy.context.model.EndPointId;
 import eu.teraflow.policy.context.model.Event;
 import eu.teraflow.policy.context.model.EventTypeEnum;
@@ -3169,6 +3175,412 @@ class SerializerTest {
         assertThat(kpiDescriptor).usingRecursiveComparison().isEqualTo(expectedKpiDescriptor);
     }
 
+    @Test
+    void shouldSerializeDeviceConfig() {
+        final var expectedConfigRuleCustomA =
+                ContextOuterClass.ConfigRule_Custom.newBuilder()
+                        .setResourceKey("resourceKeyA")
+                        .setResourceValue("resourceValueA")
+                        .build();
+
+        final var configRuleCustomA = new ConfigRuleCustom("resourceKeyA", "resourceValueA");
+
+        final var expectedConfigRuleCustomB =
+                ContextOuterClass.ConfigRule_Custom.newBuilder()
+                        .setResourceKey("resourceKeyB")
+                        .setResourceValue("resourceValueB")
+                        .build();
+
+        final var configRuleCustomB = new ConfigRuleCustom("resourceKeyB", "resourceValueB");
+
+        final var expectedConfigRuleA =
+                ContextOuterClass.ConfigRule.newBuilder()
+                        .setAction(ContextOuterClass.ConfigActionEnum.CONFIGACTION_SET)
+                        .setCustom(expectedConfigRuleCustomA)
+                        .build();
+        final var expectedConfigRuleB =
+                ContextOuterClass.ConfigRule.newBuilder()
+                        .setAction(ContextOuterClass.ConfigActionEnum.CONFIGACTION_DELETE)
+                        .setCustom(expectedConfigRuleCustomB)
+                        .build();
+
+        final var expectedDeviceConfig =
+                ContextOuterClass.DeviceConfig.newBuilder()
+                        .addAllConfigRules(List.of(expectedConfigRuleA, expectedConfigRuleB))
+                        .build();
+
+        final var configRuleTypeA = new ConfigRuleTypeCustom(configRuleCustomA);
+        final var configRuleTypeB = new ConfigRuleTypeCustom(configRuleCustomB);
+
+        final var configRuleA = new ConfigRule(ConfigActionEnum.SET, configRuleTypeA);
+        final var configRuleB = new ConfigRule(ConfigActionEnum.DELETE, configRuleTypeB);
+
+        final var deviceConfig = new DeviceConfig(List.of(configRuleA, configRuleB));
+        final var serializedDeviceConfig = serializer.serialize(deviceConfig);
+
+        assertThat(serializedDeviceConfig).isEqualTo(expectedDeviceConfig);
+    }
+
+    @Test
+    void shouldDeserializeDeviceConfig() {
+        final var expectedConfigRuleCustomA = new ConfigRuleCustom("resourceKeyA", "resourceValueA");
+        final var expectedConfigRuleCustomB = new ConfigRuleCustom("resourceKeyB", "resourceValueB");
+
+        final var expectedConfigRuleTypeA = new ConfigRuleTypeCustom(expectedConfigRuleCustomA);
+        final var expectedConfigRuleTypeB = new ConfigRuleTypeCustom(expectedConfigRuleCustomB);
+
+        final var expectedConfigRuleA = new ConfigRule(ConfigActionEnum.SET, expectedConfigRuleTypeA);
+        final var expectedConfigRuleB =
+                new ConfigRule(ConfigActionEnum.DELETE, expectedConfigRuleTypeB);
+
+        final var expectedDeviceConfig =
+                new DeviceConfig(List.of(expectedConfigRuleA, expectedConfigRuleB));
+
+        final var configRuleCustomA =
+                ContextOuterClass.ConfigRule_Custom.newBuilder()
+                        .setResourceKey("resourceKeyA")
+                        .setResourceValue("resourceValueA")
+                        .build();
+
+        final var configRuleCustomB =
+                ContextOuterClass.ConfigRule_Custom.newBuilder()
+                        .setResourceKey("resourceKeyB")
+                        .setResourceValue("resourceValueB")
+                        .build();
+
+        final var configRuleA =
+                ContextOuterClass.ConfigRule.newBuilder()
+                        .setAction(ContextOuterClass.ConfigActionEnum.CONFIGACTION_SET)
+                        .setCustom(configRuleCustomA)
+                        .build();
+        final var configRuleB =
+                ContextOuterClass.ConfigRule.newBuilder()
+                        .setAction(ContextOuterClass.ConfigActionEnum.CONFIGACTION_DELETE)
+                        .setCustom(configRuleCustomB)
+                        .build();
+        final var serializedDeviceConfig =
+                ContextOuterClass.DeviceConfig.newBuilder()
+                        .addAllConfigRules(List.of(configRuleA, configRuleB))
+                        .build();
+        final var deviceConfig = serializer.deserialize(serializedDeviceConfig);
+
+        assertThat(deviceConfig).usingRecursiveComparison().isEqualTo(expectedDeviceConfig);
+    }
+
+    private static Stream<Arguments> provideOperationalStatusEnum() {
+        return Stream.of(
+                Arguments.of(
+                        DeviceOperationalStatus.ENABLED,
+                        DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED),
+                Arguments.of(
+                        DeviceOperationalStatus.DISABLED,
+                        DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED),
+                Arguments.of(
+                        DeviceOperationalStatus.UNDEFINED,
+                        DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_UNDEFINED));
+    }
+
+    @ParameterizedTest
+    @MethodSource("provideOperationalStatusEnum")
+    void shouldSerializeOperationalStatusEnum(
+            DeviceOperationalStatus opStatus,
+            ContextOuterClass.DeviceOperationalStatusEnum expectedOpStatus) {
+        final var serializedOpStatus = serializer.serialize(opStatus);
+        assertThat(serializedOpStatus.getNumber()).isEqualTo(expectedOpStatus.getNumber());
+    }
+
+    @ParameterizedTest
+    @MethodSource("provideOperationalStatusEnum")
+    void shouldDeserializeOperationalStatusEnum(
+            DeviceOperationalStatus expectedOpStatus,
+            ContextOuterClass.DeviceOperationalStatusEnum serializedOpStatus) {
+        final var operationalStatus = serializer.deserialize(serializedOpStatus);
+        assertThat(operationalStatus).isEqualTo(expectedOpStatus);
+    }
+
+    private static Stream<Arguments> provideDeviceDriverEnum() {
+        return Stream.of(
+                Arguments.of(
+                        DeviceDriverEnum.OPENCONFIG,
+                        ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG),
+                Arguments.of(
+                        DeviceDriverEnum.TRANSPORT_API,
+                        ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API),
+                Arguments.of(DeviceDriverEnum.P4, ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_P4),
+                Arguments.of(
+                        DeviceDriverEnum.IETF_NETWORK_TOPOLOGY,
+                        ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY),
+                Arguments.of(
+                        DeviceDriverEnum.ONF_TR_352,
+                        ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352),
+                Arguments.of(
+                        DeviceDriverEnum.UNDEFINED, ContextOuterClass.DeviceDriverEnum.DEVICEDRIVER_UNDEFINED));
+    }
+
+    @ParameterizedTest
+    @MethodSource("provideDeviceDriverEnum")
+    void shouldSerializeDeviceDriverEnum(
+            DeviceDriverEnum deviceDriverEnum,
+            ContextOuterClass.DeviceDriverEnum expectedDeviceDriverEnum) {
+        final var serializedDeviceDriverEnum = serializer.serialize(deviceDriverEnum);
+
+        assertThat(serializedDeviceDriverEnum.getNumber())
+                .isEqualTo(expectedDeviceDriverEnum.getNumber());
+    }
+
+    @ParameterizedTest
+    @MethodSource("provideDeviceDriverEnum")
+    void shouldDeserializeDeviceDriverEnum(
+            DeviceDriverEnum expectedDeviceDriverEnum,
+            ContextOuterClass.DeviceDriverEnum serializedDeviceDriverEnum) {
+        final var deviceDriverEnum = serializer.deserialize(serializedDeviceDriverEnum);
+
+        assertThat(deviceDriverEnum).isEqualTo(expectedDeviceDriverEnum);
+    }
+
+    @Test
+    void shouldSerializeEndPoint() {
+        final var expectedTopologyId = new TopologyId("contextId", "id");
+        final var expectedDeviceId = "expectedDeviceId";
+        final var expectedId = "expectedId";
+        final var endPointId = new EndPointId(expectedTopologyId, expectedDeviceId, expectedId);
+        final var endPointType = "endPointType";
+        final var kpiSampleTypes =
+                List.of(KpiSampleType.BYTES_RECEIVED, KpiSampleType.BYTES_TRANSMITTED);
+
+        final var locationTypeRegion = new LocationTypeRegion("ATH");
+        final var location = new Location(locationTypeRegion);
+
+        final var endPoint = new EndPoint(endPointId, endPointType, kpiSampleTypes, location);
+
+        final var serializedEndPointId = serializer.serialize(endPointId);
+        final var serializedKpiSampleTypes =
+                kpiSampleTypes.stream()
+                        .map(kpiSampleType -> serializer.serialize(kpiSampleType))
+                        .collect(Collectors.toList());
+        final var serializedLocation = serializer.serialize(location);
+
+        final var expectedEndPoint =
+                ContextOuterClass.EndPoint.newBuilder()
+                        .setEndpointId(serializedEndPointId)
+                        .setEndpointType(endPointType)
+                        .addAllKpiSampleTypes(serializedKpiSampleTypes)
+                        .setEndpointLocation(serializedLocation)
+                        .build();
+
+        final var serializedEndPoint = serializer.serialize(endPoint);
+
+        assertThat(serializedEndPoint).usingRecursiveComparison().isEqualTo(expectedEndPoint);
+    }
+
+    @Test
+    void shouldDeserializeEndPoint() {
+        final var expectedTopologyId = new TopologyId("contextId", "id");
+        final var expectedDeviceId = "expectedDeviceId";
+        final var expectedId = "expectedId";
+        final var expectedEndPointId = new EndPointId(expectedTopologyId, expectedDeviceId, expectedId);
+        final var expectedEndPointType = "expectedEndPointType";
+        final var expectedKpiSampleTypes =
+                List.of(KpiSampleType.BYTES_RECEIVED, KpiSampleType.BYTES_TRANSMITTED);
+
+        final var expectedLocationTypeRegion = new LocationTypeRegion("ATH");
+        final var expectedLocation = new Location(expectedLocationTypeRegion);
+
+        final var expectedEndPoint =
+                new EndPoint(
+                        expectedEndPointId, expectedEndPointType, expectedKpiSampleTypes, expectedLocation);
+
+        final var serializedEndPointId = serializer.serialize(expectedEndPointId);
+        final var serializedKpiSampleTypes =
+                expectedKpiSampleTypes.stream()
+                        .map(kpiSampleType -> serializer.serialize(kpiSampleType))
+                        .collect(Collectors.toList());
+        final var serializedLocation = serializer.serialize(expectedLocation);
+
+        final var serializedEndPoint =
+                ContextOuterClass.EndPoint.newBuilder()
+                        .setEndpointId(serializedEndPointId)
+                        .setEndpointType(expectedEndPointType)
+                        .addAllKpiSampleTypes(serializedKpiSampleTypes)
+                        .setEndpointLocation(serializedLocation)
+                        .build();
+
+        final var endPoint = serializer.deserialize(serializedEndPoint);
+
+        assertThat(endPoint).usingRecursiveComparison().isEqualTo(expectedEndPoint);
+    }
+
+    @Test
+    void shouldSerializeDevice() {
+        final var expectedConfigRuleCustomA =
+                ContextOuterClass.ConfigRule_Custom.newBuilder()
+                        .setResourceKey("resourceKeyA")
+                        .setResourceValue("resourceValueA")
+                        .build();
+        final var configRuleCustomA = new ConfigRuleCustom("resourceKeyA", "resourceValueA");
+
+        final var expectedConfigRule =
+                ContextOuterClass.ConfigRule.newBuilder()
+                        .setAction(ContextOuterClass.ConfigActionEnum.CONFIGACTION_SET)
+                        .setCustom(expectedConfigRuleCustomA)
+                        .build();
+
+        final var configRuleTypeA = new ConfigRuleTypeCustom(configRuleCustomA);
+        final var deviceConfig =
+                new DeviceConfig(List.of(new ConfigRule(ConfigActionEnum.SET, configRuleTypeA)));
+
+        final var deviceDrivers = List.of(DeviceDriverEnum.IETF_NETWORK_TOPOLOGY, DeviceDriverEnum.P4);
+
+        final var expectedTopologyIdA = new TopologyId("contextIdA", "idA");
+        final var expectedDeviceIdA = "expectedDeviceIdA";
+        final var expectedIdA = "expectedIdA";
+        final var endPointIdA = new EndPointId(expectedTopologyIdA, expectedDeviceIdA, expectedIdA);
+
+        final var endPointTypeA = "endPointTypeA";
+        final var kpiSampleTypesA =
+                List.of(KpiSampleType.BYTES_RECEIVED, KpiSampleType.BYTES_TRANSMITTED);
+        final var locationTypeRegionA = new LocationTypeRegion("ATH");
+        final var locationA = new Location(locationTypeRegionA);
+        final var endPointA = new EndPoint(endPointIdA, endPointTypeA, kpiSampleTypesA, locationA);
+
+        final var expectedTopologyIdB = new TopologyId("contextIdB", "idB");
+        final var expectedDeviceIdB = "expectedDeviceIdB";
+        final var expectedIdB = "expectedIdB";
+        final var endPointIdB = new EndPointId(expectedTopologyIdB, expectedDeviceIdB, expectedIdB);
+
+        final var endPointTypeB = "endPointTypeB";
+        final var kpiSampleTypesB =
+                List.of(KpiSampleType.BYTES_RECEIVED, KpiSampleType.BYTES_TRANSMITTED);
+        final var locationTypeRegionB = new LocationTypeRegion("ATH");
+        final var locationB = new Location(locationTypeRegionB);
+        final var endPointB = new EndPoint(endPointIdB, endPointTypeB, kpiSampleTypesB, locationB);
+
+        final var endPoints = List.of(endPointA, endPointB);
+
+        final var expectedDeviceConfig =
+                ContextOuterClass.DeviceConfig.newBuilder().addConfigRules(expectedConfigRule).build();
+
+        final var serializedDeviceId = serializer.serializeDeviceId("deviceId");
+        final var serializedDrivers =
+                deviceDrivers.stream()
+                        .map(deviceDriverEnum -> serializer.serialize(deviceDriverEnum))
+                        .collect(Collectors.toList());
+
+        final var serializedEndPoints =
+                endPoints.stream()
+                        .map(endPoint -> serializer.serialize(endPoint))
+                        .collect(Collectors.toList());
+
+        final var deviceBuilder = ContextOuterClass.Device.newBuilder();
+
+        deviceBuilder.setDeviceId(serializedDeviceId);
+        deviceBuilder.setDeviceType("deviceType");
+        deviceBuilder.setDeviceConfig(expectedDeviceConfig);
+        deviceBuilder.setDeviceOperationalStatus(serializer.serialize(DeviceOperationalStatus.ENABLED));
+        deviceBuilder.addAllDeviceDrivers(serializedDrivers);
+        deviceBuilder.addAllDeviceEndpoints(serializedEndPoints);
+
+        final var expectedDevice = deviceBuilder.build();
+
+        final var device =
+                new Device(
+                        "deviceId",
+                        "deviceType",
+                        deviceConfig,
+                        DeviceOperationalStatus.ENABLED,
+                        deviceDrivers,
+                        endPoints);
+        final var serializedDevice = serializer.serialize(device);
+
+        assertThat(serializedDevice).isEqualTo(expectedDevice);
+    }
+
+    @Test
+    void shouldDeserializeDevice() {
+        final var configRuleCustom = new ConfigRuleCustom("resourceKeyA", "resourceValueA");
+        final var expectedConfigRuleCustom =
+                ContextOuterClass.ConfigRule_Custom.newBuilder()
+                        .setResourceKey("resourceKeyA")
+                        .setResourceValue("resourceValueA")
+                        .build();
+        final var configRuleType = new ConfigRuleTypeCustom(configRuleCustom);
+
+        final var expectedConfig =
+                new DeviceConfig(List.of(new ConfigRule(ConfigActionEnum.DELETE, configRuleType)));
+
+        final var deviceDrivers = List.of(DeviceDriverEnum.IETF_NETWORK_TOPOLOGY, DeviceDriverEnum.P4);
+
+        final var expectedTopologyIdA = new TopologyId("contextIdA", "idA");
+        final var expectedDeviceIdA = "expectedDeviceIdA";
+        final var expectedIdA = "expectedIdA";
+        final var endPointIdA = new EndPointId(expectedTopologyIdA, expectedDeviceIdA, expectedIdA);
+
+        final var endPointTypeA = "endPointTypeA";
+        final var kpiSampleTypesA =
+                List.of(KpiSampleType.BYTES_RECEIVED, KpiSampleType.BYTES_TRANSMITTED);
+        final var locationTypeRegionA = new LocationTypeRegion("ATH");
+        final var locationA = new Location(locationTypeRegionA);
+        final var endPointA = new EndPoint(endPointIdA, endPointTypeA, kpiSampleTypesA, locationA);
+
+        final var expectedTopologyIdB = new TopologyId("contextIdB", "idB");
+        final var expectedDeviceIdB = "expectedDeviceIdB";
+        final var expectedIdB = "expectedIdB";
+        final var endPointIdB = new EndPointId(expectedTopologyIdB, expectedDeviceIdB, expectedIdB);
+
+        final var endPointTypeB = "endPointTypeB";
+        final var kpiSampleTypesB =
+                List.of(KpiSampleType.BYTES_RECEIVED, KpiSampleType.BYTES_TRANSMITTED);
+        final var locationTypeRegionB = new LocationTypeRegion("ATH");
+        final var locationB = new Location(locationTypeRegionB);
+        final var endPointB = new EndPoint(endPointIdB, endPointTypeB, kpiSampleTypesB, locationB);
+
+        final var endPoints = List.of(endPointA, endPointB);
+
+        final var expectedDevice =
+                new Device(
+                        "deviceId",
+                        "deviceType",
+                        expectedConfig,
+                        DeviceOperationalStatus.ENABLED,
+                        deviceDrivers,
+                        endPoints);
+
+        final var configRule =
+                ContextOuterClass.ConfigRule.newBuilder()
+                        .setAction(ContextOuterClass.ConfigActionEnum.CONFIGACTION_DELETE)
+                        .setCustom(expectedConfigRuleCustom)
+                        .build();
+        final var deviceConfig =
+                ContextOuterClass.DeviceConfig.newBuilder().addConfigRules(configRule).build();
+
+        final var serializedDeviceId = serializer.serializeDeviceId("deviceId");
+        final var serializedDeviceOperationalStatus =
+                serializer.serialize(DeviceOperationalStatus.ENABLED);
+
+        final var serializedDrivers =
+                deviceDrivers.stream()
+                        .map(deviceDriverEnum -> serializer.serialize(deviceDriverEnum))
+                        .collect(Collectors.toList());
+
+        final var serializedEndPoints =
+                endPoints.stream()
+                        .map(endPoint -> serializer.serialize(endPoint))
+                        .collect(Collectors.toList());
+
+        final var deviceBuilder = ContextOuterClass.Device.newBuilder();
+        deviceBuilder.setDeviceId(serializedDeviceId);
+        deviceBuilder.setDeviceType("deviceType");
+        deviceBuilder.setDeviceConfig(deviceConfig);
+        deviceBuilder.setDeviceOperationalStatus(serializedDeviceOperationalStatus);
+        deviceBuilder.addAllDeviceDrivers(serializedDrivers);
+        deviceBuilder.addAllDeviceEndpoints(serializedEndPoints);
+
+        final var serializedDevice = deviceBuilder.build();
+        final var device = serializer.deserialize(serializedDevice);
+
+        assertThat(device).usingRecursiveComparison().isEqualTo(expectedDevice);
+    }
+
     @Test
     void shouldSerializeUuid() {
         final var expectedUuid = "uuid";
-- 
GitLab