diff --git a/data/.gitignore b/data/.gitignore
index 128ac08dd932a4d32f69ad556adfde7a003caef7..6722cd96e785ac093e976a48df83409bf618b0a1 100644
--- a/data/.gitignore
+++ b/data/.gitignore
@@ -1 +1 @@
-drx30-01.xml
+*.xml
diff --git a/src/device/service/DeviceServiceServicerImpl.py b/src/device/service/DeviceServiceServicerImpl.py
index f46619874a8c5cd2127f9937b3742ba3a8c42af2..bdb7b7019fc494236cf02053c1f52b98291a40b8 100644
--- a/src/device/service/DeviceServiceServicerImpl.py
+++ b/src/device/service/DeviceServiceServicerImpl.py
@@ -1,5 +1,6 @@
+import grpc, json, logging
 from typing import Any, List, Tuple
-import grpc, logging
+from google.protobuf.json_format import MessageToDict
 from common.orm.Database import Database
 from common.orm.Factory import get_database_backend
 from common.orm.HighLevel import get_object, update_or_create_object
@@ -12,6 +13,7 @@ from context.client.ContextClient import ContextClient
 from device.proto.context_pb2 import ConfigActionEnum, Device, DeviceConfig, DeviceId, Empty
 from device.proto.device_pb2 import MonitoringSettings
 from device.proto.device_pb2_grpc import DeviceServiceServicer
+from device.service.drivers.openconfig.OpenConfigDriver import OpenConfigDriver
 from .MonitoringLoops import MonitoringLoops
 from .database.ConfigModel import (
     ConfigModel, ConfigRuleModel, ORM_ConfigActionEnum, get_config_rules, grpc_config_rules_to_raw, update_config)
@@ -22,7 +24,7 @@ from .database.DeviceModel import DeviceModel, DriverModel
 from .database.EndPointModel import EndPointModel
 from .database.KpiModel import KpiModel
 from .database.KpiSampleType import grpc_to_enum__kpi_sample_type
-from .driver_api._Driver import _Driver
+from .driver_api._Driver import _Driver, RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES
 from .driver_api.DriverInstanceCache import DriverInstanceCache
 from .driver_api.Tools import (
     check_delete_errors, check_set_errors, check_subscribe_errors, check_unsubscribe_errors)
@@ -59,11 +61,36 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
             else:
                 unexpected_config_rules.append(config_rule)
         if len(unexpected_config_rules) > 0:
+            unexpected_config_rules = MessageToDict(
+                request.device_config, including_default_value_fields=True,
+                preserving_proto_field_name=True, use_integers_for_enums=True)
+            unexpected_config_rules = unexpected_config_rules['config_rules']
+            unexpected_config_rules = list(filter(
+                lambda cr: cr['resource_key'].replace('_connect/', '') not in connection_config_rules,
+                unexpected_config_rules))
+            str_unexpected_config_rules = json.dumps(unexpected_config_rules, sort_keys=True)
             raise InvalidArgumentException(
-                'device.device_config.config_rules', str(unexpected_config_rules),
+                'device.device_config.config_rules', str_unexpected_config_rules,
                 extra_details='RPC method AddDevice only accepts connection Config Rules that should start '\
                               'with "_connect/" tag. Others should be configured after adding the device.')
 
+        if len(request.device_endpoints) > 0:
+            unexpected_endpoints = MessageToDict(
+                request.device_endpoints, including_default_value_fields=True, preserving_proto_field_name=True,
+                use_integers_for_enums=True)
+            str_unexpected_endpoints = json.dumps(unexpected_endpoints, sort_keys=True)
+            raise InvalidArgumentException(
+                'device.device_endpoints', str_unexpected_endpoints,
+                extra_details='RPC method AddDevice does not accept endpoints. Endpoints are discovered through '\
+                              'interrogation of the physical device.')
+
+        # Remove device configuration
+        json_request = MessageToDict(
+            request, including_default_value_fields=True, preserving_proto_field_name=True,
+            use_integers_for_enums=True)
+        json_request['device_config'] = {}
+        request = Device(**json_request)
+
         sync_device_from_context(device_uuid, self.context_client, self.database)
         db_device,_ = update_device_in_local_database(self.database, request)
 
@@ -76,12 +103,25 @@ class DeviceServiceServicerImpl(DeviceServiceServicer):
             settings=connection_config_rules)
         driver.Connect()
 
-        running_config_rules = driver.GetConfig()
-        running_config_rules = [(ORM_ConfigActionEnum.SET, rule[0], rule[1]) for rule in running_config_rules]
-        LOGGER.info('[AddDevice] running_config_rules = {:s}'.format(str(running_config_rules)))
-
-        context_config_rules = get_config_rules(self.database, device_uuid, 'running')
-        LOGGER.info('[AddDevice] context_config_rules = {:s}'.format(str(context_config_rules)))
+        endpoints = driver.GetConfig([RESOURCE_ENDPOINTS])
+        for _, resource_value in endpoints:
+            endpoint_uuid = resource_value.get('name')
+            endpoint_type = resource_value.get('type')
+            str_endpoint_key = key_to_str([device_uuid, endpoint_uuid])
+            update_or_create_object(
+                self.database, EndPointModel, str_endpoint_key, {
+                'device_fk'    : db_device,
+                'endpoint_uuid': endpoint_uuid,
+                'endpoint_type': endpoint_type,
+            })
+
+        running_config_rules = driver.GetConfig([RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES])
+        running_config_rules = [(ORM_ConfigActionEnum.SET, cr[0], json.dumps(cr[1])) for cr in running_config_rules]
+        #for running_config_rule in running_config_rules:
+        #    LOGGER.info('[AddDevice] running_config_rule: {:s}'.format(str(running_config_rule)))
+
+        #context_config_rules = get_config_rules(self.database, device_uuid, 'running')
+        #LOGGER.info('[AddDevice] context_config_rules = {:s}'.format(str(context_config_rules)))
 
         # TODO: Compute diff between current context config and device config. The one in device is of higher priority
         # (might happen another instance is updating config and context was not already updated)
diff --git a/src/device/service/drivers/emulated/AnyTreeTools.py b/src/device/service/driver_api/AnyTreeTools.py
similarity index 98%
rename from src/device/service/drivers/emulated/AnyTreeTools.py
rename to src/device/service/driver_api/AnyTreeTools.py
index e7817b78921e3b91fb84ca660f022c869ac88220..df61c7e030a13a3d0d758ce51a011aaa95deb49f 100644
--- a/src/device/service/drivers/emulated/AnyTreeTools.py
+++ b/src/device/service/driver_api/AnyTreeTools.py
@@ -1,8 +1,6 @@
 import anytree
 from typing import Any, List, Optional
 
-from anytree.render import Row
-
 class TreeNode(anytree.node.Node):
     def __init__(self, name, parent=None, children=None, **kwargs) -> None:
         super().__init__(name, parent=parent, children=children, **kwargs)
diff --git a/src/device/service/driver_api/_Driver.py b/src/device/service/driver_api/_Driver.py
index b79661faaf3fd773ad598ef3b20ebfaafe58bea4..909731f757af0301d5135422df8f2a14337a4ce7 100644
--- a/src/device/service/driver_api/_Driver.py
+++ b/src/device/service/driver_api/_Driver.py
@@ -1,5 +1,10 @@
 from typing import Any, Iterator, List, Optional, Tuple, Union
 
+# Special resource names
+RESOURCE_ENDPOINTS         = '__endpoints__'
+RESOURCE_INTERFACES        = '__interfaces__'
+RESOURCE_NETWORK_INSTANCES = '__network_instances__'
+
 class _Driver:
     def __init__(self, address : str, port : int, **settings) -> None:
         """ Initialize Driver.
diff --git a/src/device/service/drivers/__init__.py b/src/device/service/drivers/__init__.py
index ae0415b786af2a12ce8f33505bfc1ac774e4e463..4b3fed33ad212ac6035dc567f1559bad387d8c46 100644
--- a/src/device/service/drivers/__init__.py
+++ b/src/device/service/drivers/__init__.py
@@ -7,7 +7,7 @@ DRIVERS = [
     (EmulatedDriver, [
         {
             FilterFieldEnum.DEVICE_TYPE: DeviceTypeFilterFieldEnum.EMULATED,
-            FilterFieldEnum.DRIVER     : ORM_DeviceDriverEnum.OPENCONFIG,
+            FilterFieldEnum.DRIVER     : ORM_DeviceDriverEnum.UNDEFINED,
         }
     ]),
     (OpenConfigDriver, [
diff --git a/src/device/service/drivers/emulated/EmulatedDriver.py b/src/device/service/drivers/emulated/EmulatedDriver.py
index 3328a29dec4b56512d66860d2578a93aa2447f34..1258f20d888a1c7fdb61764892c08517b26e6e66 100644
--- a/src/device/service/drivers/emulated/EmulatedDriver.py
+++ b/src/device/service/drivers/emulated/EmulatedDriver.py
@@ -7,7 +7,7 @@ from apscheduler.jobstores.memory import MemoryJobStore
 from apscheduler.schedulers.background import BackgroundScheduler
 from common.type_checkers.Checkers import chk_float, chk_length, chk_string, chk_type
 from device.service.driver_api._Driver import _Driver
-from .AnyTreeTools import TreeNode, dump_subtree, get_subnode, set_subnode_value
+from device.service.driver_api.AnyTreeTools import TreeNode, dump_subtree, get_subnode, set_subnode_value
 
 LOGGER = logging.getLogger(__name__)
 
diff --git a/src/device/service/drivers/openconfig/OpenConfigDriver.py b/src/device/service/drivers/openconfig/OpenConfigDriver.py
index d76962a06de02668ec305191935bb9f8a41b66cd..53bfc98340fe42e5829ffe4d42226b3d204b43f2 100644
--- a/src/device/service/drivers/openconfig/OpenConfigDriver.py
+++ b/src/device/service/drivers/openconfig/OpenConfigDriver.py
@@ -1,16 +1,19 @@
-import logging, ncclient.manager, pytz, queue, threading
-import xml.dom.minidom
-from typing import Any, Iterator, List, Optional, Tuple, Union
-#import anytree, random
+import anytree, logging, pytz, queue, threading
+from anytree.importer import DictImporter
 #from datetime import datetime, timedelta
+import lxml.etree as ET
+from typing import Any, Iterator, List, Optional, Tuple, Union
 #from apscheduler.executors.pool import ThreadPoolExecutor
 #from apscheduler.job import Job
 #from apscheduler.jobstores.memory import MemoryJobStore
 #from apscheduler.schedulers.background import BackgroundScheduler
-from common.type_checkers.Checkers import chk_float, chk_length, chk_string, chk_type
+from netconf_client.connect import connect_ssh
+from netconf_client.ncclient import Manager
+from common.type_checkers.Checkers import chk_float, chk_integer, chk_length, chk_string, chk_type
 from device.service.driver_api._Driver import _Driver
-from device.service.drivers.openconfig.handlers import DEFAULT_HANDLER, HANDLERS
-#from .AnyTreeTools import TreeNode, dump_subtree, get_subnode, set_subnode_value
+from device.service.driver_api.AnyTreeTools import TreeNode, dump_subtree, get_subnode, set_subnode_value
+from device.service.drivers.openconfig.Tools import xml_pretty_print, xml_to_dict, xml_to_file
+from device.service.drivers.openconfig.templates import ALL_RESOURCES, get_filter, extract_data
 
 logging.getLogger('ncclient.transport.ssh').setLevel(logging.WARNING)
 
@@ -22,14 +25,14 @@ LOGGER = logging.getLogger(__name__)
 class OpenConfigDriver(_Driver):
     def __init__(self, address : str, port : int, **settings) -> None: # pylint: disable=super-init-not-called
         self.__address = address
-        self.__port = port
+        self.__port = int(port)
         self.__settings = settings
         self.__lock = threading.Lock()
         #self.__initial = TreeNode('.')
         #self.__running = TreeNode('.')
         self.__started = threading.Event()
         self.__terminate = threading.Event()
-        self.__netconf_manager : ncclient.manager.Manager = None
+        self.__netconf_manager : Manager = None
         #self.__scheduler = BackgroundScheduler(daemon=True) # scheduler used to emulate sampling events
         #self.__scheduler.configure(
         #    jobstores = {'default': MemoryJobStore()},
@@ -43,11 +46,10 @@ class OpenConfigDriver(_Driver):
             if self.__started.is_set(): return True
             username = self.__settings.get('username')
             password = self.__settings.get('password')
-            handler_name = self.__settings.get('handler')
-            handler = HANDLERS.get(handler_name, DEFAULT_HANDLER)
-            self.__netconf_manager = ncclient.manager.connect_ssh(
-                host=self.__address, port=self.__port, username=username, password=password, hostkey_verify=False,
-                device_params=handler)
+            timeout = int(self.__settings.get('timeout', 120))
+            session = connect_ssh(
+                host=self.__address, port=self.__port, username=username, password=password)
+            self.__netconf_manager = Manager(session, timeout=timeout)
             # Connect triggers activation of sampling events that will be scheduled based on subscriptions
             #self.__scheduler.start()
             self.__started.set()
@@ -75,29 +77,21 @@ class OpenConfigDriver(_Driver):
 
         results = []
         with self.__lock:
-            if len(resource_keys) == 0:
-                config = self.__netconf_manager.get_config(source='running').data_xml
-                with open('../data/drx30-01.xml', mode='w', encoding='UTF-8') as f:
-                    dom = xml.dom.minidom.parseString(config)
-                    f.write(dom.toprettyxml())
+            if len(resource_keys) == 0: resource_keys = ALL_RESOURCES
+            for i,resource_key in enumerate(resource_keys):
+                str_resource_name = 'resource_key[#{:d}]'.format(i)
+                try:
+                    str_filter = get_filter(resource_key)
+                    if str_filter is None: str_filter = resource_key
+                    xml_data = self.__netconf_manager.get(filter=str_filter).data_ele
+                    if isinstance(xml_data, Exception): raise xml_data
+                    results.extend(extract_data(resource_key, xml_data))
+                except Exception as e: # pylint: disable=broad-except
+                    LOGGER.exception('Exception retrieving {:s}: {:s}'.format(str_resource_name, str(resource_key)))
+                    results.append((resource_key, e)) # if validation fails, store the exception
+                    continue
         return results
 
-#            resolver = anytree.Resolver(pathattr='name')
-#            for i,resource_key in enumerate(resource_keys):
-#                str_resource_name = 'resource_key[#{:d}]'.format(i)
-#                try:
-#                    resource_path = resource_key.split('/')
-#                except Exception as e: # pylint: disable=broad-except
-#                    LOGGER.exception('Exception validating {:s}: {:s}'.format(str_resource_name, str(resource_key)))
-#                    results.append((resource_key, e)) # if validation fails, store the exception
-#                    continue
-#
-#                resource_node = get_subnode(resolver, self.__running, resource_path, default=None)
-#                # if not found, resource_node is None
-#                if resource_node is None: continue
-#                results.extend(dump_subtree(resource_node))
-#            return results
-#
 #    def GetResource(self, endpoint_uuid : str) -> Optional[str]:
 #        chk_string('endpoint_uuid', endpoint_uuid)
 #        return {
diff --git a/src/device/service/drivers/openconfig/Tools.py b/src/device/service/drivers/openconfig/Tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..230a6e3c33586c5d1771a6da2fd9dabc533e9538
--- /dev/null
+++ b/src/device/service/drivers/openconfig/Tools.py
@@ -0,0 +1,11 @@
+import xml.dom.minidom, xmltodict
+
+def xml_pretty_print(data : str):
+    return xml.dom.minidom.parseString(data).toprettyxml()
+
+def xml_to_file(data : str, file_path : str) -> None:
+    with open(file_path, mode='w', encoding='UTF-8') as f:
+        f.write(xml_pretty_print(data))
+
+def xml_to_dict(data : str):
+    return xmltodict.parse(data)
diff --git a/src/device/service/drivers/openconfig/handlers/InfineraDeviceHandler.py b/src/device/service/drivers/openconfig/handlers/InfineraDeviceHandler.py
deleted file mode 100644
index ebf0af2e41c0385591f05c67461262a1948dfb9c..0000000000000000000000000000000000000000
--- a/src/device/service/drivers/openconfig/handlers/InfineraDeviceHandler.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Handler for Infinera device specific information through YANG.
-from ncclient.xml_ import BASE_NS_1_0
-from ncclient.devices.default import DefaultDeviceHandler
-
-class InfineraDeviceHandler(DefaultDeviceHandler):
-    _EXEMPT_ERRORS = []
-
-    def get_capabilities(self):
-        return [
-            'urn:ietf:params:netconf:base:1.0',
-            'urn:ietf:params:netconf:base:1.1',
-        ]
-
-    def get_xml_base_namespace_dict(self):
-        return {None: BASE_NS_1_0}
-
-    def get_xml_extra_prefix_kwargs(self):
-        return {'nsmap': self.get_xml_base_namespace_dict()}
diff --git a/src/device/service/drivers/openconfig/handlers/__init__.py b/src/device/service/drivers/openconfig/handlers/__init__.py
deleted file mode 100644
index 109853e3b8ab30f6d84075699dacbef11acac6f6..0000000000000000000000000000000000000000
--- a/src/device/service/drivers/openconfig/handlers/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from .InfineraDeviceHandler import InfineraDeviceHandler
-
-HANDLERS = {
-    'infinera': {'handler': InfineraDeviceHandler},
-}
-
-DEFAULT_HANDLER = {'name': 'default'}
diff --git a/src/device/service/drivers/openconfig/templates/Namespace.py b/src/device/service/drivers/openconfig/templates/Namespace.py
new file mode 100644
index 0000000000000000000000000000000000000000..ff4b7c9c747b4efa872ba177e6e6a4fd7f6203b4
--- /dev/null
+++ b/src/device/service/drivers/openconfig/templates/Namespace.py
@@ -0,0 +1,23 @@
+
+NAMESPACE_NETCONF       = 'urn:ietf:params:xml:ns:netconf:base:1.0'
+
+NAMESPACE_INTERFACES             = 'http://openconfig.net/yang/interfaces'
+NAMESPACE_INTERFACES_IP          = 'http://openconfig.net/yang/interfaces/ip'
+NAMESPACE_NETWORK_INSTANCE       = 'http://openconfig.net/yang/network-instance'
+NAMESPACE_NETWORK_INSTANCE_TYPES = 'http://openconfig.net/yang/network-instance-types'
+NAMESPACE_OPENCONFIG_TYPES       = 'http://openconfig.net/yang/openconfig-types'
+NAMESPACE_PLATFORM               = 'http://openconfig.net/yang/platform'
+NAMESPACE_PLATFORM_PORT          = 'http://openconfig.net/yang/platform/port'
+NAMESPACE_VLAN                   = 'http://openconfig.net/yang/vlan'
+
+NAMESPACES = {
+    'nc'   : NAMESPACE_NETCONF,
+    'oci'  : NAMESPACE_INTERFACES,
+    'ociip': NAMESPACE_INTERFACES_IP,
+    'ocni' : NAMESPACE_NETWORK_INSTANCE,
+    'ocnit': NAMESPACE_NETWORK_INSTANCE_TYPES,
+    'ococt': NAMESPACE_OPENCONFIG_TYPES,
+    'ocp'  : NAMESPACE_PLATFORM,
+    'ocpp' : NAMESPACE_PLATFORM_PORT,
+    'ocv'  : NAMESPACE_VLAN,
+}
diff --git a/src/device/service/drivers/openconfig/templates/Tools.py b/src/device/service/drivers/openconfig/templates/Tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..01e4e666ff6c72e65d5742a4a5be437ad06f824d
--- /dev/null
+++ b/src/device/service/drivers/openconfig/templates/Tools.py
@@ -0,0 +1,12 @@
+import lxml.etree as ET
+from typing import Collection, Dict
+
+def add_value_from_tag(container : Dict, name: str, value : ET.Element, cast=None) -> None:
+    if value is None or value.text is None: return
+    value = value.text
+    if cast is not None: value = cast(value)
+    container[name] = value
+
+def add_value_from_collection(container : Dict, name: str, value : Collection) -> None:
+    if value is None or len(value) == 0: return
+    container[name] = value
diff --git a/src/device/service/drivers/openconfig/templates/__init__.py b/src/device/service/drivers/openconfig/templates/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..65d9f54e35f204f274cb9fe9c42bc41f8bfd325f
--- /dev/null
+++ b/src/device/service/drivers/openconfig/templates/__init__.py
@@ -0,0 +1,25 @@
+import lxml.etree as ET
+from device.service.driver_api._Driver import RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES
+from .Components import get_filter_components, extract_port_data
+from .Interfaces import get_filter_interfaces, extract_interface_data
+from .NetworkInstance import get_filter_network_instances, extract_network_instance_data
+
+RESOURCE_FUNCTIONS = {
+    RESOURCE_ENDPOINTS         : (get_filter_components, extract_port_data),
+    RESOURCE_INTERFACES        : (get_filter_interfaces, extract_interface_data),
+    RESOURCE_NETWORK_INSTANCES : (get_filter_network_instances, extract_network_instance_data),
+}
+
+ALL_RESOURCES = [
+    RESOURCE_ENDPOINTS,
+    RESOURCE_INTERFACES,
+    RESOURCE_NETWORK_INSTANCES,
+]
+
+def get_filter(resource_key : str, *args, **kwargs):
+    filter_function = RESOURCE_FUNCTIONS.get(resource_key)
+    return None if filter_function is None else filter_function[0](*args, **kwargs)
+
+def extract_data(resource_key : str, xml_data : ET.Element, *args, **kwargs):
+    extract_function = RESOURCE_FUNCTIONS.get(resource_key)
+    return [(resource_key, xml_data)] if extract_function is None else extract_function[1](xml_data, *args, **kwargs)
diff --git a/src/device/tests/Tools.py b/src/device/tests/Tools.py
new file mode 100644
index 0000000000000000000000000000000000000000..6c1344fb602bb523d5849227c5f052efdbba64c2
--- /dev/null
+++ b/src/device/tests/Tools.py
@@ -0,0 +1,11 @@
+from copy import deepcopy
+
+def config_rule(action, resource_key, resource_value):
+    return {'action': action, 'resource_key': resource_key, 'resource_value': resource_value}
+
+def endpoint_id(topology_id, device_id, endpoint_uuid):
+    return {'topology_id': deepcopy(topology_id), 'device_id': deepcopy(device_id),
+            'endpoint_uuid': {'uuid': endpoint_uuid}}
+
+def endpoint(topology_id, device_id, endpoint_uuid, endpoint_type):
+    return {'endpoint_id': endpoint_id(topology_id, device_id, endpoint_uuid), 'endpoint_type': endpoint_type}
diff --git a/src/device/tests/example_objects.py b/src/device/tests/example_objects.py
index b84df119fbb5de869010e0051b70fe1e50cf4376..ba382695965b28dc5fddec77775e795bb4b061c9 100644
--- a/src/device/tests/example_objects.py
+++ b/src/device/tests/example_objects.py
@@ -1,33 +1,27 @@
 from copy import deepcopy
 from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID
 from context.proto.context_pb2 import ConfigActionEnum, DeviceDriverEnum, DeviceOperationalStatusEnum
+from .Tools import config_rule
+
+DEVICE_EMU_UUID     = 'EMULARED'
+DEVICE_EMU_TYPE     = 'emulated'
+DEVICE_EMU_ADDRESS  = '127.0.0.1'
+DEVICE_EMU_PORT     = '0'
+DEVICE_EMU_DRIVERS  = [DeviceDriverEnum.DEVICEDRIVER_UNDEFINED]
 
 try:
     from ._device_credentials import (
-        DEVICE1_UUID, DEVICE1_TYPE, DEVICE1_ADDRESS, DEVICE1_PORT, DEVICE1_USERNAME, DEVICE1_PASSWORD, DEVICE1_HANDLER,
-        DEVICE1_DRIVERS)
+        DEVICE_INF_UUID, DEVICE_INF_TYPE, DEVICE_INF_ADDRESS, DEVICE_INF_PORT, DEVICE_INF_USERNAME,
+        DEVICE_INF_PASSWORD, DEVICE_INF_DRIVERS, DEVICE_INF_CONFIG_RULES)
 except ImportError:
-    DEVICE1_UUID     = 'DEV1'
-    DEVICE1_TYPE     = 'packet-router'
-    DEVICE1_ADDRESS  = '127.0.0.1'
-    DEVICE1_PORT     = '830'
-    DEVICE1_USERNAME = 'username'
-    DEVICE1_PASSWORD = 'password'
-    DEVICE1_HANDLER  = 'default'
-    DEVICE1_DRIVERS  = [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG]
-
-# Some example objects to be used by the tests
-
-# Helper methods
-def config_rule(action, resource_key, resource_value):
-    return {'action': action, 'resource_key': resource_key, 'resource_value': resource_value}
-
-def endpoint_id(topology_id, device_id, endpoint_uuid):
-    return {'topology_id': deepcopy(topology_id), 'device_id': deepcopy(device_id),
-            'endpoint_uuid': {'uuid': endpoint_uuid}}
-
-def endpoint(topology_id, device_id, endpoint_uuid, endpoint_type):
-    return {'endpoint_id': endpoint_id(topology_id, device_id, endpoint_uuid), 'endpoint_type': endpoint_type}
+    DEVICE_INF_UUID     = 'DEV2'
+    DEVICE_INF_TYPE     = 'packet-router'
+    DEVICE_INF_ADDRESS  = '127.0.0.1'
+    DEVICE_INF_PORT     = '830'
+    DEVICE_INF_USERNAME = 'username'
+    DEVICE_INF_PASSWORD = 'password'
+    DEVICE_INF_DRIVERS  = [DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG]
+    DEVICE_INF_CONFIG_RULES = []
 
 ## use "deepcopy" to prevent propagating forced changes during tests
 CONTEXT_ID = {'context_uuid': {'uuid': DEFAULT_CONTEXT_UUID}}
@@ -47,26 +41,41 @@ TOPOLOGY = {
     'link_ids': [],
 }
 
-DEVICE1_ID = {'device_uuid': {'uuid': DEVICE1_UUID}}
-DEVICE1 = {
-    'device_id': deepcopy(DEVICE1_ID),
-    'device_type': DEVICE1_TYPE,
+DEVICE_EMU_ID = {'device_uuid': {'uuid': DEVICE_EMU_UUID}}
+DEVICE_EMU = {
+    'device_id': deepcopy(DEVICE_EMU_ID),
+    'device_type': DEVICE_EMU_TYPE,
     'device_config': {'config_rules': []},
     'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED,
-    'device_drivers': DEVICE1_DRIVERS,
+    'device_drivers': DEVICE_EMU_DRIVERS,
     'device_endpoints': [],
 }
 
-DEVICE1_CONNECT_RULES = [
-    config_rule(ConfigActionEnum.CONFIGACTION_SET, '_connect/address',  DEVICE1_ADDRESS ),
-    config_rule(ConfigActionEnum.CONFIGACTION_SET, '_connect/port',     DEVICE1_PORT    ),
-    config_rule(ConfigActionEnum.CONFIGACTION_SET, '_connect/username', DEVICE1_USERNAME),
-    config_rule(ConfigActionEnum.CONFIGACTION_SET, '_connect/password', DEVICE1_PASSWORD),
-    config_rule(ConfigActionEnum.CONFIGACTION_SET, '_connect/handler',  DEVICE1_HANDLER ),
+DEVICE_EMU_CONNECT_RULES = [
+    config_rule(ConfigActionEnum.CONFIGACTION_SET, '_connect/address',  DEVICE_EMU_ADDRESS ),
+    config_rule(ConfigActionEnum.CONFIGACTION_SET, '_connect/port',     DEVICE_EMU_PORT    ),
 ]
 
-DEVICE1_CONFIG_RULES = [
+DEVICE_EMU_CONFIG_RULES = [
     config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc1/value', 'value1'),
     config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc2/value', 'value2'),
     config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc3/value', 'value3'),
 ]
+
+
+DEVICE_INF_ID = {'device_uuid': {'uuid': DEVICE_INF_UUID}}
+DEVICE_INF = {
+    'device_id': deepcopy(DEVICE_INF_ID),
+    'device_type': DEVICE_INF_TYPE,
+    'device_config': {'config_rules': []},
+    'device_operational_status': DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED,
+    'device_drivers': DEVICE_INF_DRIVERS,
+    'device_endpoints': [],
+}
+
+DEVICE_INF_CONNECT_RULES = [
+    config_rule(ConfigActionEnum.CONFIGACTION_SET, '_connect/address',  DEVICE_INF_ADDRESS ),
+    config_rule(ConfigActionEnum.CONFIGACTION_SET, '_connect/port',     DEVICE_INF_PORT    ),
+    config_rule(ConfigActionEnum.CONFIGACTION_SET, '_connect/username', DEVICE_INF_USERNAME),
+    config_rule(ConfigActionEnum.CONFIGACTION_SET, '_connect/password', DEVICE_INF_PASSWORD),
+]
diff --git a/src/device/tests/test_unitary.py b/src/device/tests/test_unitary.py
index e4132171cfa1303246570fdb7e1db4d5d04f5682..ee4a0784eea01d490dbfd8ce3b2041f2214d4519 100644
--- a/src/device/tests/test_unitary.py
+++ b/src/device/tests/test_unitary.py
@@ -24,7 +24,9 @@ from device.service.driver_api.DriverInstanceCache import DriverInstanceCache
 from device.service.drivers import DRIVERS
 from monitoring.client.monitoring_client import MonitoringClient
 from .example_objects import (
-    CONTEXT, DEVICE1, DEVICE1_CONFIG_RULES, DEVICE1_CONNECT_RULES, DEVICE1_ID, DEVICE1_UUID, TOPOLOGY, config_rule)
+    CONTEXT, TOPOLOGY, config_rule,
+    DEVICE_EMU, DEVICE_EMU_CONFIG_RULES, DEVICE_EMU_CONNECT_RULES, DEVICE_EMU_ID, DEVICE_EMU_UUID,
+    DEVICE_INF, DEVICE_INF_CONFIG_RULES, DEVICE_INF_CONNECT_RULES, DEVICE_INF_ID, DEVICE_INF_UUID)
 
 LOGGER = logging.getLogger(__name__)
 LOGGER.setLevel(logging.DEBUG)
@@ -96,7 +98,8 @@ def grpc_message_to_json_string(message):
     return str(MessageToDict(
         message, including_default_value_fields=True, preserving_proto_field_name=True, use_integers_for_enums=False))
 
-def test_device_add_configure(
+
+def test_prepare_environment(
     context_client : ContextClient,     # pylint: disable=redefined-outer-name
     device_client : DeviceClient,       # pylint: disable=redefined-outer-name
     device_service : DeviceService):    # pylint: disable=redefined-outer-name
@@ -104,11 +107,17 @@ def test_device_add_configure(
     context_client.SetContext(Context(**CONTEXT))
     context_client.SetTopology(Topology(**TOPOLOGY))
 
+
+def test_device_add_emulated_error_cases(
+    context_client : ContextClient,     # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+    device_service : DeviceService):    # pylint: disable=redefined-outer-name
+
     with pytest.raises(grpc.RpcError) as e:
-        DEVICE1_WITH_EXTRA_RULES = copy.deepcopy(DEVICE1)
-        DEVICE1_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE1_CONNECT_RULES)
-        DEVICE1_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE1_CONFIG_RULES)
-        device_client.AddDevice(Device(**DEVICE1_WITH_EXTRA_RULES))
+        DEVICE_EMU_WITH_EXTRA_RULES = copy.deepcopy(DEVICE_EMU)
+        DEVICE_EMU_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONNECT_RULES)
+        DEVICE_EMU_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONFIG_RULES)
+        device_client.AddDevice(Device(**DEVICE_EMU_WITH_EXTRA_RULES))
     assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
     msg_head = 'device.device_config.config_rules(['
     msg_tail = ']) is invalid; RPC method AddDevice only accepts connection Config Rules that should start '\
@@ -116,23 +125,46 @@ def test_device_add_configure(
     except_msg = str(e.value.details())
     assert except_msg.startswith(msg_head) and except_msg.endswith(msg_tail)
 
-    DEVICE1_WITH_CONNECT_RULES = copy.deepcopy(DEVICE1)
-    DEVICE1_WITH_CONNECT_RULES['device_config']['config_rules'].extend(DEVICE1_CONNECT_RULES)
-    device_client.AddDevice(Device(**DEVICE1_WITH_CONNECT_RULES))
-    driver : _Driver = device_service.driver_instance_cache.get(DEVICE1_UUID) # we know the driver exists now
+
+def test_device_add_emulated_correct(
+    context_client : ContextClient,     # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+    device_service : DeviceService):    # pylint: disable=redefined-outer-name
+
+    DEVICE_EMU_WITH_CONNECT_RULES = copy.deepcopy(DEVICE_EMU)
+    DEVICE_EMU_WITH_CONNECT_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONNECT_RULES)
+    device_client.AddDevice(Device(**DEVICE_EMU_WITH_CONNECT_RULES))
+    driver : _Driver = device_service.driver_instance_cache.get(DEVICE_EMU_UUID) # we know the driver exists now
     assert driver is not None
 
-    initial_config = device_client.GetInitialConfig(DeviceId(**DEVICE1_ID))
+
+def test_device_get_emulated(
+    context_client : ContextClient,     # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+    device_service : DeviceService):    # pylint: disable=redefined-outer-name
+
+    initial_config = device_client.GetInitialConfig(DeviceId(**DEVICE_EMU_ID))
     LOGGER.info('initial_config = {:s}'.format(grpc_message_to_json_string(initial_config)))
 
-    device_data = context_client.GetDevice(DeviceId(**DEVICE1_ID))
+    device_data = context_client.GetDevice(DeviceId(**DEVICE_EMU_ID))
     LOGGER.info('device_data = {:s}'.format(grpc_message_to_json_string(device_data)))
 
+
+def test_device_configure_emulated(
+    context_client : ContextClient,     # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+    device_service : DeviceService):    # pylint: disable=redefined-outer-name
+
+    driver : _Driver = device_service.driver_instance_cache.get(DEVICE_EMU_UUID) # we know the driver exists now
+    assert driver is not None
+
     driver_config = driver.GetConfig()
     LOGGER.info('driver_config = {:s}'.format(str(driver_config)))
     assert len(driver_config) == 0
 
-    device_client.ConfigureDevice(Device(**DEVICE1))
+    DEVICE_EMU_WITH_CONFIG_RULES = copy.deepcopy(DEVICE_EMU)
+    DEVICE_EMU_WITH_CONFIG_RULES['device_config']['config_rules'].extend(DEVICE_EMU_CONFIG_RULES)
+    device_client.ConfigureDevice(Device(**DEVICE_EMU_WITH_CONFIG_RULES))
 
     driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0))
     LOGGER.info('driver_config = {:s}'.format(str(driver_config)))
@@ -141,14 +173,14 @@ def test_device_add_configure(
     assert driver_config[1] == ('/dev/rsrc2/value', 'value2')
     assert driver_config[2] == ('/dev/rsrc3/value', 'value3')
 
-    DEVICE1_WITH = copy.deepcopy(DEVICE1)
-    CONFIG_RULES : List[Dict[str, Any]] = DEVICE1_WITH['device_config']['config_rules']
-    CONFIG_RULES.clear()
-    CONFIG_RULES.append(config_rule(ConfigActionEnum.CONFIGACTION_DELETE, 'dev/rsrc1/value', ''))
-    CONFIG_RULES.append(config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc10/value', 'value10'))
-    CONFIG_RULES.append(config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc11/value', 'value11'))
-    CONFIG_RULES.append(config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc12/value', 'value12'))
-    device_client.ConfigureDevice(Device(**DEVICE1_WITH))
+    DEVICE_EMU_WITH_CONFIG_RULES_2 = copy.deepcopy(DEVICE_EMU)
+    DEVICE_EMU_WITH_CONFIG_RULES_2['device_config']['config_rules'].extend([
+        config_rule(ConfigActionEnum.CONFIGACTION_DELETE, 'dev/rsrc1/value', ''),
+        config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc10/value', 'value10'),
+        config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc11/value', 'value11'),
+        config_rule(ConfigActionEnum.CONFIGACTION_SET, 'dev/rsrc12/value', 'value12'),
+    ])
+    device_client.ConfigureDevice(Device(**DEVICE_EMU_WITH_CONFIG_RULES_2))
 
     driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0))
     LOGGER.info('driver_config = {:s}'.format(str(driver_config)))
@@ -159,8 +191,7 @@ def test_device_add_configure(
     assert driver_config[3] == ('/dev/rsrc2/value', 'value2')
     assert driver_config[4] == ('/dev/rsrc3/value', 'value3')
 
-    device_data = context_client.GetDevice(DeviceId(**DEVICE1_ID))
-    #LOGGER.info('device_data = {:s}'.format(grpc_message_to_json_string(device_data)))
+    device_data = context_client.GetDevice(DeviceId(**DEVICE_EMU_ID))
     LOGGER.info('device_data.device_config.config_rules = \n{:s}'.format(
         '\n'.join([
             '{:s} {:s} = {:s}'.format(
@@ -168,219 +199,100 @@ def test_device_add_configure(
             for config_rule in device_data.device_config.config_rules
         ])))
 
-    device_client.DeleteDevice(DeviceId(**DEVICE1_ID))
-    driver : _Driver = device_service.driver_instance_cache.get(DEVICE1_UUID, {}) # we know the driver exists now
+
+def test_device_delete_emulated(
+    context_client : ContextClient,     # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+    device_service : DeviceService):    # pylint: disable=redefined-outer-name
+
+    device_client.DeleteDevice(DeviceId(**DEVICE_EMU_ID))
+    driver : _Driver = device_service.driver_instance_cache.get(DEVICE_EMU_UUID, {})
     assert driver is None
 
-    raise Exception()
-
-#def test_add_device_wrong_attributes(device_client : DeviceClient):
-#    # should fail with device uuid is empty
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        copy_device['device_id']['device_id']['uuid'] = ''
-#        device_client.AddDevice(Device(**copy_device))
-#    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-#    msg = 'device.device_id.device_id.uuid() is out of range: '\
-#          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
-#    assert e.value.details() == msg
-#
-#    # should fail with device type is empty
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        copy_device['device_type'] = ''
-#        device_client.AddDevice(Device(**copy_device))
-#    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-#    msg = 'device.device_type() is out of range: '\
-#          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
-#    assert e.value.details() == msg
-#
-#    # should fail with wrong device operational status
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        copy_device['devOperationalStatus'] = OperationalStatus.KEEP_STATE.value
-#        device_client.AddDevice(Device(**copy_device))
-#    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-#    msg = 'Method(AddDevice) does not accept OperationalStatus(KEEP_STATE). '\
-#          'Permitted values for Method(AddDevice) are OperationalStatus([\'DISABLED\', \'ENABLED\']).'
-#    assert e.value.details() == msg
-#
-#def test_add_device_wrong_endpoint(device_client : DeviceClient):
-#    # should fail with unsupported endpoint context
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        copy_device['endpointList'][0]['port_id']['topoId']['contextId']['contextUuid']['uuid'] = 'wrong-context'
-#        request = Device(**copy_device)
-#        device_client.AddDevice(request)
-#    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-#    msg = 'Context(wrong-context) in Endpoint(#0) of '\
-#          'Context(admin)/Topology(admin)/Device(DEV1) mismatches acceptable Contexts({\'admin\'}). '\
-#          'Optionally, leave field empty to use predefined Context(admin).'
-#    assert e.value.details() == msg
-#
-#    # should fail with unsupported endpoint topology
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        copy_device['endpointList'][0]['port_id']['topoId']['topoId']['uuid'] = 'wrong-topo'
-#        device_client.AddDevice(Device(**copy_device))
-#    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-#    msg = 'Context(admin)/Topology(wrong-topo) in Endpoint(#0) of '\
-#          'Context(admin)/Topology(admin)/Device(DEV1) mismatches acceptable Topologies({\'admin\'}). '\
-#          'Optionally, leave field empty to use predefined Topology(admin).'
-#    assert e.value.details() == msg
-#
-#    # should fail with wrong endpoint device
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        copy_device['endpointList'][0]['port_id']['dev_id']['device_id']['uuid'] = 'wrong-device'
-#        device_client.AddDevice(Device(**copy_device))
-#    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-#    msg = 'Context(admin)/Topology(admin)/Device(wrong-device) in Endpoint(#0) of '\
-#          'Context(admin)/Topology(admin)/Device(DEV1) mismatches acceptable Devices({\'DEV1\'}). '\
-#          'Optionally, leave field empty to use predefined Device(DEV1).'
-#    assert e.value.details() == msg
-#
-#    # should fail with endpoint port uuid is empty
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        copy_device['endpointList'][0]['port_id']['port_id']['uuid'] = ''
-#        device_client.AddDevice(Device(**copy_device))
-#    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-#    msg = 'endpoint_id[#0].port_id.uuid() is out of range: '\
-#          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
-#    assert e.value.details() == msg
-#
-#    # should fail with endpoint port type is empty
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        copy_device['endpointList'][0]['port_type'] = ''
-#        device_client.AddDevice(Device(**copy_device))
-#    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-#    msg = 'endpoint[#0].port_type() is out of range: '\
-#          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
-#    assert e.value.details() == msg
-#
-#    # should fail with duplicate port in device
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        copy_device['endpointList'][1]['port_id']['port_id']['uuid'] = 'EP2'
-#        device_client.AddDevice(Device(**copy_device))
-#    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-#    msg = 'Duplicated Context(admin)/Topology(admin)/Device(DEV1)/Port(EP2) in Endpoint(#1) of '\
-#          'Context(admin)/Topology(admin)/Device(DEV1).'
-#    assert e.value.details() == msg
-#
-#def test_add_device(device_client : DeviceClient):
-#    # should work
-#    validate_device_id(MessageToDict(
-#            device_client.AddDevice(Device(**DEVICE)),
-#            including_default_value_fields=True, preserving_proto_field_name=True,
-#            use_integers_for_enums=False))
-#
-#def test_add_device_duplicate(device_client : DeviceClient):
-#    # should fail with device already exists
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        device_client.AddDevice(Device(**DEVICE))
-#    assert e.value.code() == grpc.StatusCode.ALREADY_EXISTS
-#    msg = 'Context(admin)/Topology(admin)/Device(DEV1) already exists in the database.'
-#    assert e.value.details() == msg
-#
-#def test_delete_device_empty_uuid(device_client : DeviceClient):
-#    # should fail with device uuid is empty
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device_id = copy.deepcopy(DEVICE_ID)
-#        copy_device_id['device_id']['uuid'] = ''
-#        device_client.DeleteDevice(DeviceId(**copy_device_id))
-#    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-#    msg = 'device_id.device_id.uuid() is out of range: '\
-#          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
-#    assert e.value.details() == msg
-#
-#def test_delete_device_not_found(device_client : DeviceClient):
-#    # should fail with device not found
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device_id = copy.deepcopy(DEVICE_ID)
-#        copy_device_id['device_id']['uuid'] = 'wrong-device-id'
-#        device_client.DeleteDevice(DeviceId(**copy_device_id))
-#    assert e.value.code() == grpc.StatusCode.NOT_FOUND
-#    msg = 'Context(admin)/Topology(admin)/Device(wrong-device-id) does not exist in the database.'
-#    assert e.value.details() == msg
-#
-#def test_delete_device(device_client : DeviceClient):
-#    # should work
-#    validate_empty(MessageToDict(
-#            device_client.DeleteDevice(DeviceId(**DEVICE_ID)),
-#            including_default_value_fields=True, preserving_proto_field_name=True,
-#            use_integers_for_enums=False))
-#
-#def test_configure_device_empty_device_uuid(device_client : DeviceClient):
-#    # should fail with device uuid is empty
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        copy_device['device_id']['device_id']['uuid'] = ''
-#        device_client.ConfigureDevice(Device(**copy_device))
-#    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-#    msg = 'device.device_id.device_id.uuid() is out of range: '\
-#          'allow_empty(False) min_length(None) max_length(None) allowed_lengths(None).'
-#    assert e.value.details() == msg
-#
-#def test_configure_device_not_found(device_client : DeviceClient):
-#    # should fail with device not found
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        copy_device['device_id']['device_id']['uuid'] = 'wrong-device-id'
-#        device_client.ConfigureDevice(Device(**copy_device))
-#    assert e.value.code() == grpc.StatusCode.NOT_FOUND
-#    msg = 'Context(admin)/Topology(admin)/Device(wrong-device-id) does not exist in the database.'
-#    assert e.value.details() == msg
-#
-#def test_add_device_default_endpoint_context_topology_device(device_client : DeviceClient):
-#    # should work
-#    copy_device = copy.deepcopy(DEVICE)
-#    copy_device['endpointList'][0]['port_id']['topoId']['contextId']['contextUuid']['uuid'] = ''
-#    copy_device['endpointList'][0]['port_id']['topoId']['topoId']['uuid'] = ''
-#    copy_device['endpointList'][0]['port_id']['dev_id']['device_id']['uuid'] = ''
-#    validate_device_id(MessageToDict(
-#            device_client.AddDevice(Device(**copy_device)),
-#            including_default_value_fields=True, preserving_proto_field_name=True,
-#            use_integers_for_enums=False))
-#
-#def test_configure_device_wrong_attributes(device_client : DeviceClient):
-#    # should fail with device type is wrong
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        copy_device['device_type'] = 'wrong-type'
-#        device_client.ConfigureDevice(Device(**copy_device))
-#    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-#    msg = 'Device(DEV1) has Type(ROADM) in the database. Cannot be changed to Type(wrong-type).'
-#    assert e.value.details() == msg
-#
-#    # should fail with endpoints cannot be modified
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        device_client.ConfigureDevice(Device(**copy_device))
-#    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-#    assert e.value.details() == 'Endpoints belonging to Device(DEV1) cannot be modified.'
-#
-#    # should fail with any change detected
-#    with pytest.raises(grpc._channel._InactiveRpcError) as e:
-#        copy_device = copy.deepcopy(DEVICE)
-#        copy_device['device_config']['device_config'] = ''
-#        copy_device['devOperationalStatus'] = OperationalStatus.KEEP_STATE.value
-#        copy_device['endpointList'].clear()
-#        device_client.ConfigureDevice(Device(**copy_device))
-#    assert e.value.code() == grpc.StatusCode.ABORTED
-#    msg = 'Any change has been requested for Device(DEV1). '\
-#          'Either specify a new configuration or a new device operational status.'
-#    assert e.value.details() == msg
-#
-#def test_configure_device(device_client : DeviceClient):
-#    # should work
-#    copy_device = copy.deepcopy(DEVICE)
-#    copy_device['device_config']['device_config'] = '<new_config/>'
-#    copy_device['devOperationalStatus'] = OperationalStatus.DISABLED.value
-#    copy_device['endpointList'].clear()
-#    validate_device_id(MessageToDict(
-#            device_client.ConfigureDevice(Device(**copy_device)),
-#            including_default_value_fields=True, preserving_proto_field_name=True,
-#            use_integers_for_enums=False))
+
+def test_device_add_openconfig_error_cases(
+    context_client : ContextClient,     # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+    device_service : DeviceService):    # pylint: disable=redefined-outer-name
+
+    with pytest.raises(grpc.RpcError) as e:
+        DEVICE_INF_WITH_EXTRA_RULES = copy.deepcopy(DEVICE_INF)
+        DEVICE_INF_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE_INF_CONNECT_RULES)
+        DEVICE_INF_WITH_EXTRA_RULES['device_config']['config_rules'].extend(DEVICE_INF_CONFIG_RULES)
+        device_client.AddDevice(Device(**DEVICE_INF_WITH_EXTRA_RULES))
+    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
+    msg_head = 'device.device_config.config_rules(['
+    msg_tail = ']) is invalid; RPC method AddDevice only accepts connection Config Rules that should start '\
+               'with "_connect/" tag. Others should be configured after adding the device.'
+    except_msg = str(e.value.details())
+    assert except_msg.startswith(msg_head) and except_msg.endswith(msg_tail)
+
+
+def test_device_add_openconfig_correct(
+    context_client : ContextClient,     # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+    device_service : DeviceService):    # pylint: disable=redefined-outer-name
+
+    DEVICE_INF_WITH_CONNECT_RULES = copy.deepcopy(DEVICE_INF)
+    DEVICE_INF_WITH_CONNECT_RULES['device_config']['config_rules'].extend(DEVICE_INF_CONNECT_RULES)
+    device_client.AddDevice(Device(**DEVICE_INF_WITH_CONNECT_RULES))
+    driver : _Driver = device_service.driver_instance_cache.get(DEVICE_INF_UUID) # we know the driver exists now
+    assert driver is not None
+
+
+def test_device_get_openconfig(
+    context_client : ContextClient,     # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+    device_service : DeviceService):    # pylint: disable=redefined-outer-name
+
+    initial_config = device_client.GetInitialConfig(DeviceId(**DEVICE_INF_ID))
+    LOGGER.info('initial_config = {:s}'.format(grpc_message_to_json_string(initial_config)))
+
+    device_data = context_client.GetDevice(DeviceId(**DEVICE_INF_ID))
+    LOGGER.info('device_data = {:s}'.format(grpc_message_to_json_string(device_data)))
+
+
+def test_device_configure_openconfig(
+    context_client : ContextClient,     # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+    device_service : DeviceService):    # pylint: disable=redefined-outer-name
+
+    driver : _Driver = device_service.driver_instance_cache.get(DEVICE_INF_UUID) # we know the driver exists now
+    assert driver is not None
+
+    raise NotImplementedError()
+
+    #driver_config = driver.GetConfig()
+    #LOGGER.info('driver_config = {:s}'.format(str(driver_config)))
+    #assert len(driver_config) == 0
+
+    #DEVICE_INF_WITH_CONFIG_RULES = copy.deepcopy(DEVICE_INF)
+    #DEVICE_INF_WITH_CONFIG_RULES['device_config']['config_rules'].extend(DEVICE_INF_CONFIG_RULES)
+    #device_client.ConfigureDevice(Device(**DEVICE_INF_WITH_CONFIG_RULES))
+
+    #driver_config = sorted(driver.GetConfig(), key=operator.itemgetter(0))
+    #LOGGER.info('driver_config = {:s}'.format(str(driver_config)))
+    #assert len(driver_config) == 5
+    #assert driver_config[0] == ('/dev/rsrc10/value', 'value10')
+    #assert driver_config[1] == ('/dev/rsrc11/value', 'value11')
+    #assert driver_config[2] == ('/dev/rsrc12/value', 'value12')
+    #assert driver_config[3] == ('/dev/rsrc2/value', 'value2')
+    #assert driver_config[4] == ('/dev/rsrc3/value', 'value3')
+
+    #device_data = context_client.GetDevice(DeviceId(**DEVICE_INF_ID))
+    #LOGGER.info('device_data.device_config.config_rules = \n{:s}'.format(
+    #    '\n'.join([
+    #        '{:s} {:s} = {:s}'.format(
+    #            ConfigActionEnum.Name(config_rule.action), config_rule.resource_key, config_rule.resource_value)
+    #        for config_rule in device_data.device_config.config_rules
+    #    ])))
+
+
+def test_device_delete_openconfig(
+    context_client : ContextClient,     # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,       # pylint: disable=redefined-outer-name
+    device_service : DeviceService):    # pylint: disable=redefined-outer-name
+
+    device_client.DeleteDevice(DeviceId(**DEVICE_INF_ID))
+    driver : _Driver = device_service.driver_instance_cache.get(DEVICE_INF_UUID, {})
+    assert driver is None