diff --git a/scripts/run_tests_locally-context.sh b/scripts/run_tests_locally-context.sh
index 61f8cee916374b228ca1bcee8810bd299837a2f5..5b6c53aa8a137c3ba3ca75d061a83e0c9810a6b4 100755
--- a/scripts/run_tests_locally-context.sh
+++ b/scripts/run_tests_locally-context.sh
@@ -44,8 +44,9 @@ export PYTHONPATH=/home/tfs/tfs-ctrl/src
 #coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose --maxfail=1 \
 #    context/tests/test_unitary.py
 
-# --log-level=INFO -o log_cli=true
-pytest --verbose --maxfail=1 --durations=0 \
-    context/tests/test_unitary.py
+# --log-level=INFO -o log_cli=true --durations=0
+pytest --verbose --maxfail=1 \
+    context/tests/test_unitary.py \
+    context/tests/test_hasher.py
 
 #kubectl --namespace $TFS_K8S_NAMESPACE delete service redis-tests
diff --git a/src/context/requirements.in b/src/context/requirements.in
index 6c68d692d6745e93f23fac8ca04be492a262365f..f5d5ccbe2cf5d8f85649f85f00f6c9fa9b21cfc4 100644
--- a/src/context/requirements.in
+++ b/src/context/requirements.in
@@ -1,8 +1,10 @@
 Flask==2.1.3
 Flask-RESTful==0.3.9
 psycopg2-binary==2.9.3
+pytest-depends==1.0.1
 redis==4.1.2
 requests==2.27.1
 SQLAlchemy==1.4.40
 sqlalchemy-cockroachdb==1.4.3
 SQLAlchemy-Utils==0.38.3
+prettytable==3.5.0
diff --git a/src/context/service/ChangeFeedExample.py b/src/context/service/ChangeFeedExample.py
new file mode 100644
index 0000000000000000000000000000000000000000..2bd46b546f1194ea8a109ee08a9d5c2907f3001d
--- /dev/null
+++ b/src/context/service/ChangeFeedExample.py
@@ -0,0 +1,34 @@
+# 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.
+
+
+    @safe_and_metered_rpc_method(METRICS, LOGGER)
+    def GetContextEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ContextEvent]:
+        pass
+        #for message in self.messagebroker.consume({TOPIC_CONTEXT}, consume_timeout=CONSUME_TIMEOUT):
+        #    yield ContextEvent(**json.loads(message.content))
+        #cf = ChangeFeedClient()
+        #ready = cf.initialize()
+        #if not ready: raise OperationFailedException('Initialize ChangeFeed')
+        #for timestamp, _, primary_key, is_delete, after in cf.get_changes('context'):
+        #    if is_delete:
+        #        event_type = EventTypeEnum.EVENTTYPE_REMOVE
+        #    else:
+        #        is_create = (timestamp - after.get('created_at')) < 1.0
+        #        event_type = EventTypeEnum.EVENTTYPE_CREATE if is_create else EventTypeEnum.EVENTTYPE_UPDATE
+        #    event = {
+        #        'event': {'timestamp': {'timestamp': timestamp}, 'event_type': event_type},
+        #        'context_id': json_context_id(primary_key[0]),
+        #    }
+        #    yield ContextEvent(**event)
diff --git a/src/context/service/Constants.py b/src/context/service/Constants.py
index 9d7c886c725d22308f33dc274234ad17f595633d..25790fe2925cc18003cd3d7df057e9c2923803fb 100644
--- a/src/context/service/Constants.py
+++ b/src/context/service/Constants.py
@@ -14,12 +14,16 @@
 
 TOPIC_CONNECTION = 'connection'
 TOPIC_CONTEXT    = 'context'
-TOPIC_TOPOLOGY   = 'topology'
 TOPIC_DEVICE     = 'device'
 TOPIC_LINK       = 'link'
+TOPIC_POLICY     = 'policy'
 TOPIC_SERVICE    = 'service'
 TOPIC_SLICE      = 'slice'
+TOPIC_TOPOLOGY   = 'topology'
 
-TOPICS = {TOPIC_CONNECTION, TOPIC_CONTEXT, TOPIC_TOPOLOGY, TOPIC_DEVICE, TOPIC_LINK, TOPIC_SERVICE, TOPIC_SLICE}
+TOPICS = {
+    TOPIC_CONNECTION, TOPIC_CONTEXT, TOPIC_DEVICE, TOPIC_LINK,
+    TOPIC_POLICY, TOPIC_SERVICE, TOPIC_SLICE, TOPIC_TOPOLOGY
+}
 
 CONSUME_TIMEOUT = 0.5 # seconds
diff --git a/src/context/service/ContextServiceServicerImpl.py b/src/context/service/ContextServiceServicerImpl.py
index 2661f25c12a5797a1bf11ec51551569a36c5c50f..5075d8889fd217623a76955ba0a786a8f5366c01 100644
--- a/src/context/service/ContextServiceServicerImpl.py
+++ b/src/context/service/ContextServiceServicerImpl.py
@@ -16,8 +16,8 @@
 import grpc, json, logging, operator, sqlalchemy, threading, time, uuid
 from sqlalchemy.orm import Session, contains_eager, selectinload, sessionmaker
 from sqlalchemy.dialects.postgresql import UUID, insert
-from sqlalchemy_cockroachdb import run_transaction
 from typing import Dict, Iterator, List, Optional, Set, Tuple, Union
+
 from common.message_broker.MessageBroker import MessageBroker
 #from common.orm.backend.Tools import key_to_str
 from common.proto.context_pb2 import (
@@ -37,6 +37,10 @@ from common.tools.object_factory.Context import json_context_id
 from common.rpc_method_wrapper.Decorator import create_metrics, safe_and_metered_rpc_method
 from common.rpc_method_wrapper.ServiceExceptions import (
     InvalidArgumentException, NotFoundException, OperationFailedException)
+from context.service.database.methods.Context import context_delete, context_get, context_list_ids, context_list_objs, context_set
+from context.service.database.methods.Device import device_delete, device_get, device_list_ids, device_list_objs, device_set
+from context.service.database.methods.Link import link_delete, link_get, link_list_ids, link_list_objs, link_set
+from context.service.database.methods.Topology import topology_delete, topology_get, topology_list_ids, topology_list_objs, topology_set
 #from common.tools.grpc.Tools import grpc_message_to_json, grpc_message_to_json_string
 #from context.service.Database import Database
 #from context.service.database.ConfigModel import (
@@ -44,24 +48,24 @@ from common.rpc_method_wrapper.ServiceExceptions import (
 #from context.service.database.ConnectionModel import ConnectionModel, set_path
 #from context.service.database.ConstraintModel import (
 #    ConstraintModel, ConstraintsModel, Union_ConstraintModel, CONSTRAINT_PARSERS, set_constraints)
-from context.service.database.ContextModel import ContextModel
-from context.service.database.DeviceModel import (
-    DeviceModel, grpc_to_enum__device_operational_status, grpc_to_enum__device_driver)
-from context.service.database.EndPointModel import EndPointModel, grpc_to_enum__kpi_sample_type
+#from context.service.database.models.ContextModel import ContextModel
+#from context.service.database.models.DeviceModel import (
+#    DeviceModel, grpc_to_enum__device_operational_status, grpc_to_enum__device_driver)
+#from context.service.database.models.EndPointModel import EndPointModel, grpc_to_enum__kpi_sample_type
 #from context.service.database.EndPointModel import EndPointModel, set_kpi_sample_types
 #from context.service.database.Events import notify_event
 #from context.service.database.LinkModel import LinkModel
 #from context.service.database.PolicyRuleModel import PolicyRuleModel
-from context.service.database.RelationModels import TopologyDeviceModel
+#from context.service.database.RelationModels import TopologyDeviceModel
 #    ConnectionSubServiceModel, LinkEndPointModel, ServiceEndPointModel, SliceEndPointModel, SliceServiceModel,
 #    SliceSubSliceModel, TopologyLinkModel)
 #from context.service.database.ServiceModel import (
 #    ServiceModel, grpc_to_enum__service_status, grpc_to_enum__service_type)
 #from context.service.database.SliceModel import SliceModel, grpc_to_enum__slice_status
-from context.service.database.TopologyModel import TopologyModel
-#from .Constants import (
-#    CONSUME_TIMEOUT, TOPIC_CONNECTION, TOPIC_CONTEXT, TOPIC_DEVICE, TOPIC_LINK, TOPIC_SERVICE, TOPIC_SLICE,
-#    TOPIC_TOPOLOGY)
+#from context.service.database.TopologyModel import TopologyModel
+from .Constants import (
+    CONSUME_TIMEOUT, TOPIC_CONNECTION, TOPIC_CONTEXT, TOPIC_DEVICE, TOPIC_LINK, TOPIC_POLICY, TOPIC_SERVICE,
+    TOPIC_SLICE, TOPIC_TOPOLOGY)
 #from .ChangeFeedClient import ChangeFeedClient
 
 LOGGER = logging.getLogger(__name__)
@@ -84,508 +88,148 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer
     def __init__(self, db_engine : sqlalchemy.engine.Engine, messagebroker : MessageBroker) -> None:
         LOGGER.debug('Creating Servicer...')
         self.db_engine = db_engine
-        #self.lock = threading.Lock()
-        #session = sessionmaker(bind=db_engine, expire_on_commit=False)
-        #self.session = session
-        #self.database = Database(session)
         self.messagebroker = messagebroker
         LOGGER.debug('Servicer Created')
 
+    def _get_metrics(self): return METRICS
+
+
     # ----- Context ----------------------------------------------------------------------------------------------------
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def ListContextIds(self, request : Empty, context : grpc.ServicerContext) -> ContextIdList:
-        def callback(session : Session) -> List[Dict]:
-            obj_list : List[ContextModel] = session.query(ContextModel).all()
-            #.options(selectinload(ContextModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
-            return [obj.dump_id() for obj in obj_list]
-        return ContextIdList(context_ids=run_transaction(sessionmaker(bind=self.db_engine), callback))
+        return context_list_ids(self.db_engine)
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def ListContexts(self, request : Empty, context : grpc.ServicerContext) -> ContextList:
-        def callback(session : Session) -> List[Dict]:
-            obj_list : List[ContextModel] = session.query(ContextModel).all()
-            #.options(selectinload(ContextModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
-            return [obj.dump() for obj in obj_list]
-        return ContextList(contexts=run_transaction(sessionmaker(bind=self.db_engine), callback))
+        return context_list_objs(self.db_engine)
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def GetContext(self, request : ContextId, context : grpc.ServicerContext) -> Context:
-        context_uuid = request.context_uuid.uuid
-        def callback(session : Session) -> Optional[Dict]:
-            obj : Optional[ContextModel] = session.query(ContextModel)\
-                .filter_by(context_uuid=context_uuid).one_or_none()
-            return None if obj is None else obj.dump()
-        obj = run_transaction(sessionmaker(bind=self.db_engine), callback)
-        if obj is None: raise NotFoundException(ContextModel.__name__.replace('Model', ''), context_uuid)
-        return Context(**obj)
+        return context_get(self.db_engine, request)
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def SetContext(self, request : Context, context : grpc.ServicerContext) -> ContextId:
-        context_uuid = request.context_id.context_uuid.uuid
-        context_name = request.name
-
-        for i, topology_id in enumerate(request.topology_ids):
-            topology_context_uuid = topology_id.context_id.context_uuid.uuid
-            if topology_context_uuid != context_uuid:
-                raise InvalidArgumentException(
-                    'request.topology_ids[{:d}].context_id.context_uuid.uuid'.format(i), topology_context_uuid,
-                    ['should be == {:s}({:s})'.format('request.context_id.context_uuid.uuid', context_uuid)])
-
-        for i, service_id in enumerate(request.service_ids):
-            service_context_uuid = service_id.context_id.context_uuid.uuid
-            if service_context_uuid != context_uuid:
-                raise InvalidArgumentException(
-                    'request.service_ids[{:d}].context_id.context_uuid.uuid'.format(i), service_context_uuid,
-                    ['should be == {:s}({:s})'.format('request.context_id.context_uuid.uuid', context_uuid)])
-
-        for i, slice_id in enumerate(request.slice_ids):
-            slice_context_uuid = slice_id.context_id.context_uuid.uuid
-            if slice_context_uuid != context_uuid:
-                raise InvalidArgumentException(
-                    'request.slice_ids[{:d}].context_id.context_uuid.uuid'.format(i), slice_context_uuid,
-                    ['should be == {:s}({:s})'.format('request.context_id.context_uuid.uuid', context_uuid)])
-
-        def callback(session : Session) -> Tuple[Optional[Dict], bool]:
-            obj : Optional[ContextModel] = session.query(ContextModel).with_for_update()\
-                .filter_by(context_uuid=context_uuid).one_or_none()
-            is_update = obj is not None
-            if is_update:
-                obj.context_name = context_name
-                session.merge(obj)
-            else:
-                session.add(ContextModel(context_uuid=context_uuid, context_name=context_name, created_at=time.time()))
-            obj : Optional[ContextModel] = session.query(ContextModel)\
-                .filter_by(context_uuid=context_uuid).one_or_none()
-            return (None if obj is None else obj.dump_id()), is_update
-
-        obj_id,updated = run_transaction(sessionmaker(bind=self.db_engine), callback)
-        if obj_id is None: raise NotFoundException(ContextModel.__name__.replace('Model', ''), context_uuid)
-
+        updated = context_set(self.db_engine, request)
         #event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE
-        #notify_event(self.messagebroker, TOPIC_CONTEXT, event_type, {'context_id': obj_id})
-        return ContextId(**obj_id)
+        #notify_event(self.messagebroker, TOPIC_CONTEXT, event_type, {'context_id': request.context_id})
+        return request.context_id
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def RemoveContext(self, request : ContextId, context : grpc.ServicerContext) -> Empty:
-        context_uuid = request.context_uuid.uuid
-
-        def callback(session : Session) -> bool:
-            num_deleted = session.query(ContextModel).filter_by(context_uuid=context_uuid).delete()
-            return num_deleted > 0
-
-        deleted = run_transaction(sessionmaker(bind=self.db_engine), callback)
+        deleted = context_delete(self.db_engine, request)
         #if deleted:
         #    notify_event(self.messagebroker, TOPIC_CONTEXT, EventTypeEnum.EVENTTYPE_REMOVE, {'context_id': request})
         return Empty()
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def GetContextEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ContextEvent]:
-        pass
-        #for message in self.messagebroker.consume({TOPIC_CONTEXT}, consume_timeout=CONSUME_TIMEOUT):
-        #    yield ContextEvent(**json.loads(message.content))
-        #cf = ChangeFeedClient()
-        #ready = cf.initialize()
-        #if not ready: raise OperationFailedException('Initialize ChangeFeed')
-        #for timestamp, _, primary_key, is_delete, after in cf.get_changes('context'):
-        #    if is_delete:
-        #        event_type = EventTypeEnum.EVENTTYPE_REMOVE
-        #    else:
-        #        is_create = (timestamp - after.get('created_at')) < 1.0
-        #        event_type = EventTypeEnum.EVENTTYPE_CREATE if is_create else EventTypeEnum.EVENTTYPE_UPDATE
-        #    event = {
-        #        'event': {'timestamp': {'timestamp': timestamp}, 'event_type': event_type},
-        #        'context_id': json_context_id(primary_key[0]),
-        #    }
-        #    yield ContextEvent(**event)
+        for message in self.messagebroker.consume({TOPIC_CONTEXT}, consume_timeout=CONSUME_TIMEOUT):
+            yield ContextEvent(**json.loads(message.content))
+
 
     # ----- Topology ---------------------------------------------------------------------------------------------------
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def ListTopologyIds(self, request : ContextId, context : grpc.ServicerContext) -> TopologyIdList:
-        context_uuid = request.context_uuid.uuid
-        def callback(session : Session) -> List[Dict]:
-            obj_list : List[TopologyModel] = session.query(TopologyModel).filter_by(context_uuid=context_uuid).all()
-            #.options(selectinload(ContextModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
-            return [obj.dump_id() for obj in obj_list]
-        return TopologyIdList(topology_ids=run_transaction(sessionmaker(bind=self.db_engine), callback))
+        return topology_list_ids(self.db_engine, request)
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def ListTopologies(self, request : ContextId, context : grpc.ServicerContext) -> TopologyList:
-        context_uuid = request.context_uuid.uuid
-        def callback(session : Session) -> List[Dict]:
-            obj_list : List[TopologyModel] = session.query(TopologyModel).filter_by(context_uuid=context_uuid).all()
-            #.options(selectinload(ContextModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
-            return [obj.dump() for obj in obj_list]
-        return TopologyList(topologies=run_transaction(sessionmaker(bind=self.db_engine), callback))
+        return topology_list_objs(self.db_engine, request)
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def GetTopology(self, request : TopologyId, context : grpc.ServicerContext) -> Topology:
-        context_uuid = request.context_id.context_uuid.uuid
-        topology_uuid = request.topology_uuid.uuid
-
-        def callback(session : Session) -> Optional[Dict]:
-            obj : Optional[TopologyModel] = session.query(TopologyModel)\
-                .filter_by(context_uuid=context_uuid, topology_uuid=topology_uuid).one_or_none()
-            return None if obj is None else obj.dump()
-        obj = run_transaction(sessionmaker(bind=self.db_engine), callback)
-        if obj is None:
-            obj_uuid = '{:s}/{:s}'.format(context_uuid, topology_uuid)
-            raise NotFoundException(TopologyModel.__name__.replace('Model', ''), obj_uuid)
-        return Topology(**obj)
+        return topology_get(self.db_engine, request)
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def SetTopology(self, request : Topology, context : grpc.ServicerContext) -> TopologyId:
-        context_uuid = request.topology_id.context_id.context_uuid.uuid
-        topology_uuid = request.topology_id.topology_uuid.uuid
-        topology_name = request.name
-
-        devices_to_add : List[str] = [
-            {'context_uuid': context_uuid, 'topology_uuid': topology_uuid, 'device_uuid': device_id.device_uuid.uuid}
-            for device_id in request.device_ids
-        ]
-        links_to_add : List[str] = [
-            {'context_uuid': context_uuid, 'topology_uuid': topology_uuid, 'link_uuid': link_id.link_uuid.uuid}
-            for link_id in request.link_ids
-        ]
-        print('devices_to_add', devices_to_add)
-
-        def callback(session : Session) -> Tuple[Optional[Dict], bool]:
-            topology_data = [{
-                'context_uuid' : context_uuid,
-                'topology_uuid': topology_uuid,
-                'topology_name': topology_name,
-                'created_at'   : time.time(),
-            }]
-            stmt = insert(TopologyModel).values(topology_data)
-            stmt = stmt.on_conflict_do_update(
-                index_elements=[TopologyModel.context_uuid, TopologyModel.topology_uuid],
-                set_=dict(topology_name = stmt.excluded.topology_name)
-            )
-            session.execute(stmt)
-
-            if len(devices_to_add) > 0:
-                session.execute(insert(TopologyDeviceModel).values(devices_to_add).on_conflict_do_nothing(
-                    index_elements=[
-                        TopologyDeviceModel.context_uuid, TopologyDeviceModel.topology_uuid,
-                        TopologyDeviceModel.device_uuid
-                    ]
-                ))
-
-            #if len(link_to_add) > 0:
-            #    session.execute(insert(TopologyLinkModel).values(link_to_add).on_conflict_do_nothing(
-            #        index_elements=[
-            #            TopologyLinkModel.context_uuid, TopologyLinkModel.topology_uuid,
-            #            TopologyLinkModel.link_uuid
-            #        ]
-            #    ))
-
-            is_update = True
-            obj : Optional[TopologyModel] = session.query(TopologyModel)\
-                .filter_by(context_uuid=context_uuid, topology_uuid=topology_uuid).one_or_none()
-            return (None if obj is None else obj.dump_id()), is_update
-
-        obj_id,updated = run_transaction(sessionmaker(bind=self.db_engine), callback)
-        if obj_id is None: raise NotFoundException(ContextModel.__name__.replace('Model', ''), context_uuid)
-
+        updated = topology_set(self.db_engine, request)
         #event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE
-        #notify_event(self.messagebroker, TOPIC_TOPOLOGY, event_type, {'topology_id': obj_id})
-        return TopologyId(**obj_id)
+        #notify_event(self.messagebroker, TOPIC_TOPOLOGY, event_type, {'topology_id': request.topology_id})
+        return request.topology_id
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def RemoveTopology(self, request : TopologyId, context : grpc.ServicerContext) -> Empty:
-        context_uuid = request.context_id.context_uuid.uuid
-        topology_uuid = request.topology_uuid.uuid
-
-        def callback(session : Session) -> bool:
-            num_deleted = session.query(TopologyModel)\
-                .filter_by(context_uuid=context_uuid, topology_uuid=topology_uuid).delete()
-            return num_deleted > 0
-
-        deleted = run_transaction(sessionmaker(bind=self.db_engine), callback)
+        deleted = topology_delete(self.db_engine, request)
         #if deleted:
         #    notify_event(self.messagebroker, TOPIC_TOPOLOGY, EventTypeEnum.EVENTTYPE_REMOVE, {'topology_id': request})
         return Empty()
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def GetTopologyEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[TopologyEvent]:
-        pass
-        #for message in self.messagebroker.consume({TOPIC_TOPOLOGY}, consume_timeout=CONSUME_TIMEOUT):
-        #    yield TopologyEvent(**json.loads(message.content))
+        for message in self.messagebroker.consume({TOPIC_TOPOLOGY}, consume_timeout=CONSUME_TIMEOUT):
+            yield TopologyEvent(**json.loads(message.content))
+
 
     # ----- Device -----------------------------------------------------------------------------------------------------
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def ListDeviceIds(self, request : Empty, context : grpc.ServicerContext) -> DeviceIdList:
-        def callback(session : Session) -> List[Dict]:
-            obj_list : List[DeviceModel] = session.query(DeviceModel).all()
-            #.options(selectinload(DeviceModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
-            return [obj.dump_id() for obj in obj_list]
-        return DeviceIdList(device_ids=run_transaction(sessionmaker(bind=self.db_engine), callback))
+        return device_list_ids(self.db_engine)
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def ListDevices(self, request : Empty, context : grpc.ServicerContext) -> DeviceList:
-        def callback(session : Session) -> List[Dict]:
-            obj_list : List[DeviceModel] = session.query(DeviceModel).all()
-            #.options(selectinload(DeviceModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
-            return [obj.dump() for obj in obj_list]
-        return DeviceList(devices=run_transaction(sessionmaker(bind=self.db_engine), callback))
+        return device_list_objs(self.db_engine)
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def GetDevice(self, request : ContextId, context : grpc.ServicerContext) -> Device:
-        device_uuid = request.device_uuid.uuid
-        def callback(session : Session) -> Optional[Dict]:
-            obj : Optional[DeviceModel] = session.query(DeviceModel)\
-                .filter_by(device_uuid=device_uuid).one_or_none()
-            return None if obj is None else obj.dump()
-        obj = run_transaction(sessionmaker(bind=self.db_engine), callback)
-        if obj is None: raise NotFoundException(DeviceModel.__name__.replace('Model', ''), device_uuid)
-        return Device(**obj)
+        return device_get(self.db_engine, request)
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
     def SetDevice(self, request : Device, context : grpc.ServicerContext) -> DeviceId:
-        device_uuid = request.device_id.device_uuid.uuid
-        device_name = request.name
-        device_type = request.device_type
-        oper_status = grpc_to_enum__device_operational_status(request.device_operational_status)
-        device_drivers = [grpc_to_enum__device_driver(d) for d in request.device_drivers]
-
-        related_topology_uuids : Set[Tuple[str, str]] = set()
-        endpoints_data : List[Dict] = list()
-        for i, endpoint in enumerate(request.device_endpoints):
-            endpoint_device_uuid = endpoint.endpoint_id.device_id.device_uuid.uuid
-            if len(endpoint_device_uuid) == 0: endpoint_device_uuid = device_uuid
-            if device_uuid != endpoint_device_uuid:
-                raise InvalidArgumentException(
-                    'request.device_endpoints[{:d}].device_id.device_uuid.uuid'.format(i), endpoint_device_uuid,
-                    ['should be == {:s}({:s})'.format('request.device_id.device_uuid.uuid', device_uuid)])
-
-            endpoint_context_uuid = endpoint.endpoint_id.topology_id.context_id.context_uuid.uuid
-            endpoint_topology_uuid = endpoint.endpoint_id.topology_id.topology_uuid.uuid
-
-            kpi_sample_types = [grpc_to_enum__kpi_sample_type(kst) for kst in endpoint.kpi_sample_types]
+        updated = device_set(self.db_engine, request)
+        #event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE
+        #notify_event(self.messagebroker, TOPIC_DEVICE, event_type, {'device_id': request.device_id})
+        return request.device_id
 
-            endpoints_data.append({
-                'context_uuid'    : endpoint_context_uuid,
-                'topology_uuid'   : endpoint_topology_uuid,
-                'device_uuid'     : endpoint_device_uuid,
-                'endpoint_uuid'   : endpoint.endpoint_id.endpoint_uuid.uuid,
-                'endpoint_type'   : endpoint.endpoint_type,
-                'kpi_sample_types': kpi_sample_types,
-            })
+    @safe_and_metered_rpc_method(METRICS, LOGGER)
+    def RemoveDevice(self, request : DeviceId, context : grpc.ServicerContext) -> Empty:
+        deleted = device_delete(self.db_engine, request)
+        #if deleted:
+        #    notify_event(self.messagebroker, TOPIC_DEVICE, EventTypeEnum.EVENTTYPE_REMOVE, {'device_id': request})
+        return Empty()
 
-            if len(endpoint_context_uuid) > 0 and len(endpoint_topology_uuid) > 0:
-                related_topology_uuids.add({
-                    'context_uuid': endpoint_context_uuid,
-                    'topology_uuid': endpoint_topology_uuid,
-                    'device_uuid': endpoint_device_uuid,
-                })
+    @safe_and_metered_rpc_method(METRICS, LOGGER)
+    def GetDeviceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[DeviceEvent]:
+        for message in self.messagebroker.consume({TOPIC_DEVICE}, consume_timeout=CONSUME_TIMEOUT):
+            yield DeviceEvent(**json.loads(message.content))
 
-        def callback(session : Session) -> Tuple[Optional[Dict], bool]:
-            obj : Optional[DeviceModel] = session.query(DeviceModel).with_for_update()\
-                .filter_by(device_uuid=device_uuid).one_or_none()
-            is_update = obj is not None
-            if is_update:
-                obj.device_name = device_name
-                obj.device_type = device_type
-                obj.device_operational_status = oper_status
-                obj.device_drivers = device_drivers
-                session.merge(obj)
-            else:
-                session.add(DeviceModel(
-                    device_uuid=device_uuid, device_name=device_name, device_type=device_type,
-                    device_operational_status=oper_status, device_drivers=device_drivers, created_at=time.time()))
-            obj : Optional[DeviceModel] = session.query(DeviceModel)\
-                .filter_by(device_uuid=device_uuid).one_or_none()
 
-            stmt = insert(EndPointModel).values(endpoints_data)
-            stmt = stmt.on_conflict_do_update(
-                index_elements=[
-                    EndPointModel.context_uuid, EndPointModel.topology_uuid, EndPointModel.device_uuid,
-                    EndPointModel.endpoint_uuid
-                ],
-                set_=dict(
-                    endpoint_type = stmt.excluded.endpoint_type,
-                    kpi_sample_types = stmt.excluded.kpi_sample_types,
-                )
-            )
-            session.execute(stmt)
+    # ----- Link -------------------------------------------------------------------------------------------------------
 
-            session.execute(insert(TopologyDeviceModel).values(list(related_topology_uuids)).on_conflict_do_nothing(
-                index_elements=[
-                    TopologyDeviceModel.context_uuid, TopologyDeviceModel.topology_uuid,
-                    TopologyDeviceModel.device_uuid
-                ]
-            ))
+    @safe_and_metered_rpc_method(METRICS, LOGGER)
+    def ListLinkIds(self, request : Empty, context : grpc.ServicerContext) -> LinkIdList:
+        return link_list_ids(self.db_engine)
 
-            return (None if obj is None else obj.dump_id()), is_update
+    @safe_and_metered_rpc_method(METRICS, LOGGER)
+    def ListLinks(self, request : Empty, context : grpc.ServicerContext) -> LinkList:
+        return link_list_objs(self.db_engine)
 
-        obj_id,updated = run_transaction(sessionmaker(bind=self.db_engine), callback)
-        if obj_id is None: raise NotFoundException(DeviceModel.__name__.replace('Model', ''), device_uuid)
+    @safe_and_metered_rpc_method(METRICS, LOGGER)
+    def GetLink(self, request : LinkId, context : grpc.ServicerContext) -> Link:
+        return link_get(self.db_engine, request)
 
+    @safe_and_metered_rpc_method(METRICS, LOGGER)
+    def SetLink(self, request : Link, context : grpc.ServicerContext) -> LinkId:
+        updated = link_set(self.db_engine, request)
         #event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE
-        #notify_event(self.messagebroker, TOPIC_DEVICE, event_type, {'device_id': obj_id})
-        return DeviceId(**obj_id)
-
-#        with self.session() as session:
-#            config_rules = grpc_config_rules_to_raw(request.device_config.config_rules)
-#            running_config_result = self.update_config(session, device_uuid, 'device', config_rules)
-#            db_running_config = running_config_result[0][0]
-#            config_uuid = db_running_config.config_uuid
-#            running_config_rules = update_config(
-#                self.database, device_uuid, 'device', request.device_config.config_rules)
-#            db_running_config = running_config_rules[0][0]
-#
-#            new_obj = DeviceModel(**{
-#                'device_uuid'               : device_uuid,
-#                'device_type'               : request.device_type,
-#                'device_operational_status' : grpc_to_enum__device_operational_status(request.device_operational_status),
-#                'device_config_uuid'        : config_uuid,
-#            })
-#            result: Tuple[DeviceModel, bool] = self.database.create_or_update(new_obj)
-#            db_device, updated = result
-#
-#            self.set_drivers(db_device, request.device_drivers)
-#
-#
+        #notify_event(self.messagebroker, TOPIC_LINK, event_type, {'link_id': request.link_id})
+        return request.link_id
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
-    def RemoveDevice(self, request : DeviceId, context : grpc.ServicerContext) -> Empty:
-        device_uuid = request.device_uuid.uuid
-        def callback(session : Session) -> bool:
-            session.query(TopologyDeviceModel).filter_by(device_uuid=device_uuid).delete()
-            num_deleted = session.query(DeviceModel).filter_by(device_uuid=device_uuid).delete()
-            #db_device = session.query(DeviceModel).filter_by(device_uuid=device_uuid).one_or_none()
-            #session.query(ConfigRuleModel).filter_by(config_uuid=db_device.device_config_uuid).delete()
-            #session.query(ConfigModel).filter_by(config_uuid=db_device.device_config_uuid).delete()
-            #session.query(DeviceModel).filter_by(device_uuid=device_uuid).delete()
-            return num_deleted > 0
-        deleted = run_transaction(sessionmaker(bind=self.db_engine), callback)
+    def RemoveLink(self, request : LinkId, context : grpc.ServicerContext) -> Empty:
+        deleted = link_delete(self.db_engine, request)
         #if deleted:
-        #    notify_event(self.messagebroker, TOPIC_DEVICE, EventTypeEnum.EVENTTYPE_REMOVE, {'device_id': request})
+        #    notify_event(self.messagebroker, TOPIC_LINK, event_type, {'link_id': dict_link_id})
         return Empty()
 
     @safe_and_metered_rpc_method(METRICS, LOGGER)
-    def GetDeviceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[DeviceEvent]:
-        pass
-        #for message in self.messagebroker.consume({TOPIC_DEVICE}, consume_timeout=CONSUME_TIMEOUT):
-        #    yield DeviceEvent(**json.loads(message.content))
+    def GetLinkEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[LinkEvent]:
+        for message in self.messagebroker.consume({TOPIC_LINK}, consume_timeout=CONSUME_TIMEOUT):
+            yield LinkEvent(**json.loads(message.content))
 
 
-#    # ----- Link -------------------------------------------------------------------------------------------------------
-#
-#    @safe_and_metered_rpc_method(METRICS, LOGGER)
-#    def ListLinkIds(self, request : Empty, context : grpc.ServicerContext) -> LinkIdList:
-#        with self.session() as session:
-#            result = session.query(LinkModel).all()
-#            return LinkIdList(link_ids=[db_link.dump_id() for db_link in result])
-#
-#
-#    @safe_and_metered_rpc_method(METRICS, LOGGER)
-#    def ListLinks(self, request : Empty, context : grpc.ServicerContext) -> LinkList:
-#        with self.session() as session:
-#            link_list = LinkList()
-#
-#            db_links = session.query(LinkModel).all()
-#
-#            for db_link in db_links:
-#                link_uuid = db_link.link_uuid
-#                filt = {'link_uuid': link_uuid}
-#                link_endpoints = session.query(LinkEndPointModel).filter_by(**filt).all()
-#                if link_endpoints:
-#                    eps = []
-#                    for lep in link_endpoints:
-#                        filt = {'endpoint_uuid': lep.endpoint_uuid}
-#                        eps.append(session.query(EndPointModel).filter_by(**filt).one())
-#                    link_list.links.append(Link(**db_link.dump(eps)))
-#
-#            return link_list
-#
-#    @safe_and_metered_rpc_method(METRICS, LOGGER)
-#    def GetLink(self, request : LinkId, context : grpc.ServicerContext) -> Link:
-#        link_uuid = request.link_uuid.uuid
-#        with self.session() as session:
-#            result = session.query(LinkModel).filter(LinkModel.link_uuid == link_uuid).one_or_none()
-#            if not result:
-#                raise NotFoundException(LinkModel.__name__.replace('Model', ''), link_uuid)
-#
-#            filt = {'link_uuid': link_uuid}
-#            link_endpoints = session.query(LinkEndPointModel).filter_by(**filt).all()
-#            if link_endpoints:
-#                eps = []
-#                for lep in link_endpoints:
-#                    filt = {'endpoint_uuid': lep.endpoint_uuid}
-#                    eps.append(session.query(EndPointModel).filter_by(**filt).one())
-#                return Link(**result.dump(eps))
-#
-#            rd = result.dump()
-#            rt = Link(**rd)
-#
-#            return rt
-#
-#
-#
-#    @safe_and_metered_rpc_method(METRICS, LOGGER)
-#    def SetLink(self, request : Link, context : grpc.ServicerContext) -> LinkId:
-#        link_uuid = request.link_id.link_uuid.uuid
-#
-#        new_link = LinkModel(**{
-#            'link_uuid': link_uuid
-#        })
-#        result: Tuple[LinkModel, bool] = self.database.create_or_update(new_link)
-#        db_link, updated = result
-#
-#        for endpoint_id in request.link_endpoint_ids:
-#            endpoint_uuid                  = endpoint_id.endpoint_uuid.uuid
-#            endpoint_device_uuid           = endpoint_id.device_id.device_uuid.uuid
-#            endpoint_topology_uuid         = endpoint_id.topology_id.topology_uuid.uuid
-#            endpoint_topology_context_uuid = endpoint_id.topology_id.context_id.context_uuid.uuid
-#
-#
-#            db_topology = None
-#            if len(endpoint_topology_context_uuid) > 0 and len(endpoint_topology_uuid) > 0:
-#                db_topology: TopologyModel = self.database.get_object(TopologyModel, endpoint_topology_uuid)
-#                # check device is in topology
-#                self.database.get_object(TopologyDeviceModel, endpoint_device_uuid)
-#
-#
-#            link_endpoint = LinkEndPointModel(link_uuid=link_uuid, endpoint_uuid=endpoint_uuid)
-#            result: Tuple[LinkEndPointModel, bool] = self.database.create_or_update(link_endpoint)
-#
-#            if db_topology is not None:
-#                topology_link = TopologyLinkModel(topology_uuid=endpoint_topology_uuid, link_uuid=link_uuid)
-#                result: Tuple[TopologyLinkModel, bool] = self.database.create_or_update(topology_link)
-#
-#        event_type = EventTypeEnum.EVENTTYPE_UPDATE if updated else EventTypeEnum.EVENTTYPE_CREATE
-#        dict_link_id = db_link.dump_id()
-#        notify_event(self.messagebroker, TOPIC_LINK, event_type, {'link_id': dict_link_id})
-#        return LinkId(**dict_link_id)
-#
-#    @safe_and_metered_rpc_method(METRICS, LOGGER)
-#    def RemoveLink(self, request : LinkId, context : grpc.ServicerContext) -> Empty:
-#        with self.session() as session:
-#            link_uuid = request.link_uuid.uuid
-#
-#            session.query(TopologyLinkModel).filter_by(link_uuid=link_uuid).delete()
-#            session.query(LinkEndPointModel).filter_by(link_uuid=link_uuid).delete()
-#
-#            result = session.query(LinkModel).filter_by(link_uuid=link_uuid).one_or_none()
-#            if not result:
-#                return Empty()
-#            dict_link_id = result.dump_id()
-#
-#            session.query(LinkModel).filter_by(link_uuid=link_uuid).delete()
-#            session.commit()
-#            event_type = EventTypeEnum.EVENTTYPE_REMOVE
-#            notify_event(self.messagebroker, TOPIC_LINK, event_type, {'link_id': dict_link_id})
-#            return Empty()
-#
-##    @safe_and_metered_rpc_method(METRICS, LOGGER)
-##    def GetLinkEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[LinkEvent]:
-##        for message in self.messagebroker.consume({TOPIC_LINK}, consume_timeout=CONSUME_TIMEOUT):
-##            yield LinkEvent(**json.loads(message.content))
-#
-#
 #    # ----- Service ----------------------------------------------------------------------------------------------------
 #
 #    @safe_and_metered_rpc_method(METRICS, LOGGER)
@@ -810,13 +454,13 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer
 #            event_type = EventTypeEnum.EVENTTYPE_REMOVE
 #            notify_event(self.messagebroker, TOPIC_SERVICE, event_type, {'service_id': dict_service_id})
 #            return Empty()
-#
-##    @safe_and_metered_rpc_method(METRICS, LOGGER)
-##    def GetServiceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ServiceEvent]:
-##        for message in self.messagebroker.consume({TOPIC_SERVICE}, consume_timeout=CONSUME_TIMEOUT):
-##            yield ServiceEvent(**json.loads(message.content))
-#
-#
+
+    @safe_and_metered_rpc_method(METRICS, LOGGER)
+    def GetServiceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ServiceEvent]:
+        for message in self.messagebroker.consume({TOPIC_SERVICE}, consume_timeout=CONSUME_TIMEOUT):
+            yield ServiceEvent(**json.loads(message.content))
+
+
 #    # ----- Slice ----------------------------------------------------------------------------------------------------
 #
 #    @safe_and_metered_rpc_method(METRICS, LOGGER)
@@ -993,13 +637,13 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer
 #            event_type = EventTypeEnum.EVENTTYPE_REMOVE
 #            notify_event(self.messagebroker, TOPIC_SLICE, event_type, {'slice_id': dict_slice_id})
 #            return Empty()
-#
-##    @safe_and_metered_rpc_method(METRICS, LOGGER)
-##    def GetSliceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[SliceEvent]:
-##        for message in self.messagebroker.consume({TOPIC_SLICE}, consume_timeout=CONSUME_TIMEOUT):
-##            yield SliceEvent(**json.loads(message.content))
-#
-#
+
+    @safe_and_metered_rpc_method(METRICS, LOGGER)
+    def GetSliceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[SliceEvent]:
+        for message in self.messagebroker.consume({TOPIC_SLICE}, consume_timeout=CONSUME_TIMEOUT):
+            yield SliceEvent(**json.loads(message.content))
+
+
 #    # ----- Connection -------------------------------------------------------------------------------------------------
 #
 #    @safe_and_metered_rpc_method(METRICS, LOGGER)
@@ -1082,13 +726,13 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer
 #            event_type = EventTypeEnum.EVENTTYPE_REMOVE
 #            notify_event(self.messagebroker, TOPIC_CONNECTION, event_type, {'connection_id': dict_connection_id})
 #            return Empty()
-#
-##    @safe_and_metered_rpc_method(METRICS, LOGGER)
-##    def GetConnectionEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ConnectionEvent]:
-##        for message in self.messagebroker.consume({TOPIC_CONNECTION}, consume_timeout=CONSUME_TIMEOUT):
-##            yield ConnectionEvent(**json.loads(message.content))
-#
-#
+
+    @safe_and_metered_rpc_method(METRICS, LOGGER)
+    def GetConnectionEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ConnectionEvent]:
+        for message in self.messagebroker.consume({TOPIC_CONNECTION}, consume_timeout=CONSUME_TIMEOUT):
+            yield ConnectionEvent(**json.loads(message.content))
+
+
 #    # ----- Policy -----------------------------------------------------------------------------------------------------
 #
 #    @safe_and_metered_rpc_method(METRICS, LOGGER)
@@ -1140,4 +784,3 @@ class ContextServiceServicerImpl(ContextServiceServicer, ContextPolicyServiceSer
 #            #event_type = EventTypeEnum.EVENTTYPE_REMOVE
 #            #notify_event(self.messagebroker, TOPIC_POLICY, event_type, {"policy_id": dict_policy_id})
 #            return Empty()
-#
\ No newline at end of file
diff --git a/src/context/service/Database.py b/src/context/service/Database.py
index 03598a97fb5df6b1cb6951449d8df2d3a360e0ff..edb903a104070f407e2511a1b947a38ad4d7ed34 100644
--- a/src/context/service/Database.py
+++ b/src/context/service/Database.py
@@ -2,7 +2,7 @@ import logging
 from sqlalchemy import MetaData
 from sqlalchemy.orm import Session #, joinedload
 from typing import Tuple #, List
-from context.service.database._Base import _Base
+from context.service.database.models._Base import _Base
 #from common.orm.backend.Tools import key_to_str
 from common.rpc_method_wrapper.ServiceExceptions import NotFoundException
 
diff --git a/src/context/service/Engine.py b/src/context/service/Engine.py
index ec4702f271ecec2659f7c227e9540db8a1c03e26..151f33751b0a04657d01ab4b8369f1dd6cc4b2c5 100644
--- a/src/context/service/Engine.py
+++ b/src/context/service/Engine.py
@@ -18,6 +18,7 @@ from common.Settings import get_setting
 LOGGER = logging.getLogger(__name__)
 
 APP_NAME = 'tfs'
+ECHO = False # true: dump SQL commands and transactions executed
 
 class Engine:
     @staticmethod
@@ -26,7 +27,7 @@ class Engine:
 
         try:
             engine = sqlalchemy.create_engine(
-                crdb_uri, connect_args={'application_name': APP_NAME}, echo=True, future=True)
+                crdb_uri, connect_args={'application_name': APP_NAME}, echo=ECHO, future=True)
         except: # pylint: disable=bare-except
             LOGGER.exception('Failed to connect to database: {:s}'.format(crdb_uri))
             return None
diff --git a/src/context/service/database/Events.py b/src/context/service/Events.py
similarity index 100%
rename from src/context/service/database/Events.py
rename to src/context/service/Events.py
diff --git a/src/context/service/_old_code/_test_restapi.py b/src/context/service/_old_code/_test_restapi.py
new file mode 100644
index 0000000000000000000000000000000000000000..82a8bca4005eb1ff575293a473c7cebeb5f69a76
--- /dev/null
+++ b/src/context/service/_old_code/_test_restapi.py
@@ -0,0 +1,31 @@
+# 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.
+
+import logging
+#from context.service._old_code.Populate import populate
+#from context.service.rest_server.RestServer import RestServer
+#from context.service.rest_server.Resources import RESOURCES
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+#def do_rest_request(url : str):
+#    base_url = get_service_baseurl_http(ServiceNameEnum.CONTEXT)
+#    request_url = 'http://{:s}:{:s}{:s}{:s}'.format(str(LOCAL_HOST), str(HTTP_PORT), str(base_url), url)
+#    LOGGER.warning('Request: GET {:s}'.format(str(request_url)))
+#    reply = requests.get(request_url)
+#    LOGGER.warning('Reply: {:s}'.format(str(reply.text)))
+#    assert reply.status_code == 200, 'Reply failed with code {}'.format(reply.status_code)
+#    return reply.json()
+
diff --git a/src/context/service/_old_code/test_unitary.py b/src/context/service/_old_code/test_unitary.py
index 04e054aad022a916d443feac8916b7eb436cafe2..5a0dcb9c18f4693a40fc3b48ed0297f5902e5d79 100644
--- a/src/context/service/_old_code/test_unitary.py
+++ b/src/context/service/_old_code/test_unitary.py
@@ -34,7 +34,7 @@ from common.type_checkers.Assertions import (
     validate_topology_ids)
 from context.client.ContextClient import ContextClient
 from context.client.EventsCollector import EventsCollector
-from context.service.database.Tools import (
+from context.service.database.tools.Tools import (
     FASTHASHER_DATA_ACCEPTED_FORMAT, FASTHASHER_ITEM_ACCEPTED_FORMAT, fast_hasher)
 from context.service.grpc_server.ContextService import ContextService
 from context.service._old_code.Populate import populate
@@ -43,7 +43,7 @@ from context.service.rest_server.Resources import RESOURCES
 from requests import Session
 from sqlalchemy import create_engine
 from sqlalchemy.orm import sessionmaker
-from context.service.database._Base import Base
+from context.service.database.models._Base import Base
 
 from .Objects import (
     CONNECTION_R1_R3, CONNECTION_R1_R3_ID, CONNECTION_R1_R3_UUID, CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID,
diff --git a/src/context/service/database/ConfigModel.py b/src/context/service/database/ConfigModel.py
deleted file mode 100644
index d36622e765b6011c0ac49ef382888438e9139979..0000000000000000000000000000000000000000
--- a/src/context/service/database/ConfigModel.py
+++ /dev/null
@@ -1,278 +0,0 @@
-# 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.
-import enum
-import functools, logging, operator
-from typing import Dict, List, Optional, Tuple, Union
-from common.orm.backend.Tools import key_to_str
-from common.proto.context_pb2 import ConfigActionEnum
-from common.tools.grpc.Tools import grpc_message_to_json_string
-from sqlalchemy import Column, ForeignKey, INTEGER, CheckConstraint, Enum, String
-from sqlalchemy.dialects.postgresql import UUID, ARRAY
-from context.service.database._Base import _Base
-from sqlalchemy.orm import relationship
-from context.service.Database import Database
-
-
-import functools, json, logging, operator
-from enum import Enum
-from typing import Dict, List, Optional, Tuple, Type, Union
-from common.orm.Database import Database
-from common.orm.HighLevel import get_object, get_or_create_object, update_or_create_object
-from common.orm.backend.Tools import key_to_str
-from common.orm.fields.EnumeratedField import EnumeratedField
-from common.orm.fields.ForeignKeyField import ForeignKeyField
-from common.orm.fields.IntegerField import IntegerField
-from common.orm.fields.PrimaryKeyField import PrimaryKeyField
-from common.orm.fields.StringField import StringField
-from common.orm.model.Model import Model
-from common.proto.context_pb2 import ConfigActionEnum, ConfigRule
-from common.tools.grpc.Tools import grpc_message_to_json_string
-#from .EndPointModel import EndPointModel, get_endpoint
-from .Tools import fast_hasher, grpc_to_enum, remove_dict_key
-
-LOGGER = logging.getLogger(__name__)
-
-class ORM_ConfigActionEnum(enum.Enum):
-    UNDEFINED = ConfigActionEnum.CONFIGACTION_UNDEFINED
-    SET       = ConfigActionEnum.CONFIGACTION_SET
-    DELETE    = ConfigActionEnum.CONFIGACTION_DELETE
-
-grpc_to_enum__config_action = functools.partial(
-    grpc_to_enum, ConfigActionEnum, ORM_ConfigActionEnum)
-
-class ConfigModel(Base): # pylint: disable=abstract-method
-    __tablename__ = 'Config'
-    config_uuid = Column(UUID(as_uuid=False), primary_key=True)
-
-    # Relationships
-    config_rule = relationship("ConfigRuleModel",  cascade="all,delete", back_populates="config", lazy='joined')
-
-    def dump(self) -> List[Dict]:
-        config_rules = []
-        for a in self.config_rule:
-            asdf = a.dump()
-            config_rules.append(asdf)
-        return [remove_dict_key(config_rule, 'position') for config_rule in config_rules]
-
-    @staticmethod
-    def main_pk_name():
-        return 'config_uuid'
-
-class ConfigRuleModel(Base): # pylint: disable=abstract-method
-    __tablename__ = 'ConfigRule'
-    config_rule_uuid = Column(UUID(as_uuid=False), primary_key=True)
-    config_uuid = Column(UUID(as_uuid=False), ForeignKey("Config.config_uuid", ondelete='CASCADE'), primary_key=True)
-
-    action = Column(Enum(ORM_ConfigActionEnum, create_constraint=True, native_enum=True), nullable=False)
-    position = Column(INTEGER, nullable=False)
-    key = Column(String, nullable=False)
-    value = Column(String, nullable=False)
-
-    __table_args__ = (
-        CheckConstraint(position >= 0, name='check_position_value'),
-        {}
-    )
-
-    # Relationships
-    config = relationship("ConfigModel", passive_deletes=True, back_populates="config_rule")
-class ConfigRuleCustomModel(Model): # pylint: disable=abstract-method
-    key = StringField(required=True, allow_empty=False)
-    value = StringField(required=True, allow_empty=False)
-
-    def dump(self) -> Dict: # pylint: disable=arguments-differ
-        return {'custom': {'resource_key': self.key, 'resource_value': self.value}}
-
-class ConfigRuleAclModel(Model): # pylint: disable=abstract-method
-    # TODO: improve definition of fields in ConfigRuleAclModel
-    # To simplify, endpoint encoded as JSON-string directly; otherwise causes circular dependencies
-    #endpoint_fk = ForeignKeyField(EndPointModel)
-    endpoint_id = StringField(required=True, allow_empty=False)
-    # To simplify, ACL rule is encoded as a JSON-string directly
-    acl_data = StringField(required=True, allow_empty=False)
-
-    def dump(self) -> Dict: # pylint: disable=arguments-differ
-        #json_endpoint_id = EndPointModel(self.database, self.endpoint_fk).dump_id()
-        json_endpoint_id = json.loads(self.endpoint_id)
-        json_acl_rule_set = json.loads(self.acl_data)
-        return {'acl': {'endpoint_id': json_endpoint_id, 'rule_set': json_acl_rule_set}}
-
-# enum values should match name of field in ConfigRuleModel
-class ConfigRuleKindEnum(Enum):
-    CUSTOM = 'custom'
-    ACL    = 'acl'
-
-Union_SpecificConfigRule = Union[
-    ConfigRuleCustomModel, ConfigRuleAclModel
-]
-
-class ConfigRuleModel(Model): # pylint: disable=abstract-method
-    pk = PrimaryKeyField()
-    config_fk = ForeignKeyField(ConfigModel)
-    kind = EnumeratedField(ConfigRuleKindEnum)
-    position = IntegerField(min_value=0, required=True)
-    action = EnumeratedField(ORM_ConfigActionEnum, required=True)
-    config_rule_custom_fk = ForeignKeyField(ConfigRuleCustomModel, required=False)
-    config_rule_acl_fk    = ForeignKeyField(ConfigRuleAclModel, required=False)
-
-    def delete(self) -> None:
-        field_name = 'config_rule_{:s}_fk'.format(str(self.kind.value))
-        specific_fk_value : Optional[ForeignKeyField] = getattr(self, field_name, None)
-        if specific_fk_value is None:
-            raise Exception('Unable to find config_rule key for field_name({:s})'.format(field_name))
-        specific_fk_class = getattr(ConfigRuleModel, field_name, None)
-        foreign_model_class : Model = specific_fk_class.foreign_model
-        super().delete()
-        get_object(self.database, foreign_model_class, str(specific_fk_value)).delete()
-
-    def dump(self, include_position=True) -> Dict: # pylint: disable=arguments-differ
-        field_name = 'config_rule_{:s}_fk'.format(str(self.kind.value))
-        specific_fk_value : Optional[ForeignKeyField] = getattr(self, field_name, None)
-        if specific_fk_value is None:
-            raise Exception('Unable to find config_rule key for field_name({:s})'.format(field_name))
-        specific_fk_class = getattr(ConfigRuleModel, field_name, None)
-        foreign_model_class : Model = specific_fk_class.foreign_model
-        config_rule : Union_SpecificConfigRule = get_object(self.database, foreign_model_class, str(specific_fk_value))
-        result = config_rule.dump()
-        result['action'] = self.action.value
-        if include_position: result['position'] = self.position
-        return result
-
-    @staticmethod
-    def main_pk_name():
-        return 'config_rule_uuid'
-
-def set_config_rule(
-    database : Database, db_config : ConfigModel, position : int, resource_key : str, resource_value : str,
-): # -> Tuple[ConfigRuleModel, bool]:
-
-    str_rule_key_hash = fast_hasher(resource_key)
-    str_config_rule_key = key_to_str([db_config.config_uuid, str_rule_key_hash], separator=':')
-
-    data = {'config_fk': db_config, 'position': position, 'action': ORM_ConfigActionEnum.SET, 'key': resource_key,
-            'value': resource_value}
-    to_add = ConfigRuleModel(**data)
-
-    result = database.create_or_update(to_add)
-    return result
-Tuple_ConfigRuleSpecs = Tuple[Type, str, Dict, ConfigRuleKindEnum]
-
-def parse_config_rule_custom(database : Database, grpc_config_rule) -> Tuple_ConfigRuleSpecs:
-    config_rule_class = ConfigRuleCustomModel
-    str_config_rule_id = grpc_config_rule.custom.resource_key
-    config_rule_data = {
-        'key'  : grpc_config_rule.custom.resource_key,
-        'value': grpc_config_rule.custom.resource_value,
-    }
-    return config_rule_class, str_config_rule_id, config_rule_data, ConfigRuleKindEnum.CUSTOM
-
-def parse_config_rule_acl(database : Database, grpc_config_rule) -> Tuple_ConfigRuleSpecs:
-    config_rule_class = ConfigRuleAclModel
-    grpc_endpoint_id = grpc_config_rule.acl.endpoint_id
-    grpc_rule_set = grpc_config_rule.acl.rule_set
-    device_uuid = grpc_endpoint_id.device_id.device_uuid.uuid
-    endpoint_uuid = grpc_endpoint_id.endpoint_uuid.uuid
-    str_endpoint_key = '/'.join([device_uuid, endpoint_uuid])
-    #str_endpoint_key, db_endpoint = get_endpoint(database, grpc_endpoint_id)
-    str_config_rule_id = ':'.join([str_endpoint_key, grpc_rule_set.name])
-    config_rule_data = {
-        #'endpoint_fk': db_endpoint,
-        'endpoint_id': grpc_message_to_json_string(grpc_endpoint_id),
-        'acl_data': grpc_message_to_json_string(grpc_rule_set),
-    }
-    return config_rule_class, str_config_rule_id, config_rule_data, ConfigRuleKindEnum.ACL
-
-CONFIGRULE_PARSERS = {
-    'custom': parse_config_rule_custom,
-    'acl'   : parse_config_rule_acl,
-}
-
-Union_ConfigRuleModel = Union[
-    ConfigRuleCustomModel, ConfigRuleAclModel,
-]
-
-def set_config_rule(
-    database : Database, db_config : ConfigModel, grpc_config_rule : ConfigRule, position : int
-) -> Tuple[Union_ConfigRuleModel, bool]:
-    grpc_config_rule_kind = str(grpc_config_rule.WhichOneof('config_rule'))
-    parser = CONFIGRULE_PARSERS.get(grpc_config_rule_kind)
-    if parser is None:
-        raise NotImplementedError('ConfigRule of kind {:s} is not implemented: {:s}'.format(
-            grpc_config_rule_kind, grpc_message_to_json_string(grpc_config_rule)))
-
-    # create specific ConfigRule
-    config_rule_class, str_config_rule_id, config_rule_data, config_rule_kind = parser(database, grpc_config_rule)
-    str_config_rule_key_hash = fast_hasher(':'.join([config_rule_kind.value, str_config_rule_id]))
-    str_config_rule_key = key_to_str([db_config.pk, str_config_rule_key_hash], separator=':')
-    result : Tuple[Union_ConfigRuleModel, bool] = update_or_create_object(
-        database, config_rule_class, str_config_rule_key, config_rule_data)
-    db_specific_config_rule, updated = result
-
-    # create generic ConfigRule
-    config_rule_fk_field_name = 'config_rule_{:s}_fk'.format(config_rule_kind.value)
-    config_rule_data = {
-        'config_fk': db_config, 'kind': config_rule_kind, 'position': position,
-        'action': ORM_ConfigActionEnum.SET,
-        config_rule_fk_field_name: db_specific_config_rule
-    }
-    result : Tuple[ConfigRuleModel, bool] = update_or_create_object(
-        database, ConfigRuleModel, str_config_rule_key, config_rule_data)
-    db_config_rule, updated = result
-
-    return db_config_rule, updated
-
-def delete_config_rule(
-    database : Database, db_config : ConfigModel, grpc_config_rule : ConfigRule
-) -> None:
-    grpc_config_rule_kind = str(grpc_config_rule.WhichOneof('config_rule'))
-    parser = CONFIGRULE_PARSERS.get(grpc_config_rule_kind)
-    if parser is None:
-        raise NotImplementedError('ConfigRule of kind {:s} is not implemented: {:s}'.format(
-            grpc_config_rule_kind, grpc_message_to_json_string(grpc_config_rule)))
-
-    # delete generic config rules; self deletes specific config rule
-    _, str_config_rule_id, _, config_rule_kind = parser(database, grpc_config_rule)
-    str_config_rule_key_hash = fast_hasher(':'.join([config_rule_kind.value, str_config_rule_id]))
-    str_config_rule_key = key_to_str([db_config.pk, str_config_rule_key_hash], separator=':')
-    db_config_rule : Optional[ConfigRuleModel] = get_object(
-        database, ConfigRuleModel, str_config_rule_key, raise_if_not_found=False)
-    if db_config_rule is None: return
-    db_config_rule.delete()
-
-def update_config(
-    database : Database, db_parent_pk : str, config_name : str, grpc_config_rules
-) -> List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]]:
-
-    str_config_key = key_to_str([config_name, db_parent_pk], separator=':')
-    result : Tuple[ConfigModel, bool] = get_or_create_object(database, ConfigModel, str_config_key)
-    db_config, created = result
-
-    db_objects = [(db_config, created)]
-
-    for position,grpc_config_rule in enumerate(grpc_config_rules):
-        action = grpc_to_enum__config_action(grpc_config_rule.action)
-
-        if action == ORM_ConfigActionEnum.SET:
-            result : Tuple[ConfigRuleModel, bool] = set_config_rule(
-                database, db_config, grpc_config_rule, position)
-            db_config_rule, updated = result
-            db_objects.append((db_config_rule, updated))
-        elif action == ORM_ConfigActionEnum.DELETE:
-            delete_config_rule(database, db_config, grpc_config_rule)
-        else:
-            msg = 'Unsupported Action({:s}) for ConfigRule({:s})'
-            str_action = str(ConfigActionEnum.Name(action))
-            str_config_rule = grpc_message_to_json_string(grpc_config_rule)
-            raise AttributeError(msg.format(str_action, str_config_rule))
-
-    return db_objects
diff --git a/src/context/service/database/DeviceModel.py b/src/context/service/database/DeviceModel.py
deleted file mode 100644
index 5c9e27e06ded6a4a3d31a0d356fd8621cd930dc2..0000000000000000000000000000000000000000
--- a/src/context/service/database/DeviceModel.py
+++ /dev/null
@@ -1,198 +0,0 @@
-# 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.
-
-import enum
-import functools, logging
-#import uuid
-from typing import Dict #, List
-#from common.orm.Database import Database
-#from common.orm.backend.Tools import key_to_str
-from common.proto.context_pb2 import DeviceDriverEnum, DeviceOperationalStatusEnum
-from sqlalchemy import Column, Float, ForeignKey, String, Enum
-from sqlalchemy.dialects.postgresql import UUID, ARRAY
-from sqlalchemy.orm import relationship
-from context.service.database._Base import _Base
-from .Tools import grpc_to_enum
-
-LOGGER = logging.getLogger(__name__)
-
-class ORM_DeviceDriverEnum(enum.Enum):
-    UNDEFINED             = DeviceDriverEnum.DEVICEDRIVER_UNDEFINED
-    OPENCONFIG            = DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG
-    TRANSPORT_API         = DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API
-    P4                    = DeviceDriverEnum.DEVICEDRIVER_P4
-    IETF_NETWORK_TOPOLOGY = DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY
-    ONF_TR_352            = DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352
-    XR                    = DeviceDriverEnum.DEVICEDRIVER_XR
-
-grpc_to_enum__device_driver = functools.partial(
-    grpc_to_enum, DeviceDriverEnum, ORM_DeviceDriverEnum)
-
-class ORM_DeviceOperationalStatusEnum(enum.Enum):
-    UNDEFINED = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_UNDEFINED
-    DISABLED  = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED
-    ENABLED   = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
-
-grpc_to_enum__device_operational_status = functools.partial(
-    grpc_to_enum, DeviceOperationalStatusEnum, ORM_DeviceOperationalStatusEnum)
-
-class DeviceModel(_Base):
-    __tablename__ = 'device'
-    device_uuid = Column(UUID(as_uuid=False), primary_key=True)
-    device_name = Column(String(), nullable=False)
-    device_type = Column(String(), nullable=False)
-    #device_config_uuid = Column(UUID(as_uuid=False), ForeignKey('config.config_uuid', ondelete='CASCADE'))
-    device_operational_status = Column(Enum(ORM_DeviceOperationalStatusEnum))
-    device_drivers = Column(ARRAY(Enum(ORM_DeviceDriverEnum), dimensions=1))
-    created_at = Column(Float)
-
-    # Relationships
-    topology_device = relationship('TopologyDeviceModel', back_populates='devices')
-    #device_config = relationship("ConfigModel", passive_deletes=True, lazy="joined")
-    endpoints = relationship('EndPointModel', passive_deletes=True, back_populates='device')
-
-    def dump_id(self) -> Dict:
-        return {'device_uuid': {'uuid': self.device_uuid}}
-
-    def dump(self) -> Dict:
-        return {
-            'device_id'                : self.dump_id(),
-            'name'                     : self.device_name,
-            'device_type'              : self.device_type,
-            'device_operational_status': self.device_operational_status.value,
-            'device_drivers'           : [d.value for d in self.device_drivers],
-            #'device_config'            : {'config_rules': self.device_config.dump()},
-            #'device_endpoints'         : [ep.dump() for ep in self.endpoints],
-        }
-
-#def set_drivers(database : Database, db_device : DeviceModel, grpc_device_drivers):
-#    db_device_pk = db_device.device_uuid
-#    for driver in grpc_device_drivers:
-#        orm_driver = grpc_to_enum__device_driver(driver)
-#        str_device_driver_key = key_to_str([db_device_pk, orm_driver.name])
-#        db_device_driver = DriverModel(database, str_device_driver_key)
-#        db_device_driver.device_fk = db_device
-#        db_device_driver.driver = orm_driver
-#        db_device_driver.save()
-
-#    def set_kpi_sample_types(self, db_endpoint: EndPointModel, grpc_endpoint_kpi_sample_types):
-#        db_endpoint_pk = db_endpoint.endpoint_uuid
-#        for kpi_sample_type in grpc_endpoint_kpi_sample_types:
-#            orm_kpi_sample_type = grpc_to_enum__kpi_sample_type(kpi_sample_type)
-#            # str_endpoint_kpi_sample_type_key = key_to_str([db_endpoint_pk, orm_kpi_sample_type.name])
-#            data = {'endpoint_uuid': db_endpoint_pk,
-#                    'kpi_sample_type': orm_kpi_sample_type.name,
-#                    'kpi_uuid': str(uuid.uuid4())}
-#            db_endpoint_kpi_sample_type = KpiSampleTypeModel(**data)
-#            self.database.create(db_endpoint_kpi_sample_type)
-
-#    def set_drivers(self, db_device: DeviceModel, grpc_device_drivers):
-#        db_device_pk = db_device.device_uuid
-#        for driver in grpc_device_drivers:
-#            orm_driver = grpc_to_enum__device_driver(driver)
-#            str_device_driver_key = key_to_str([db_device_pk, orm_driver.name])
-#            driver_config = {
-#                # "driver_uuid": str(uuid.uuid4()),
-#                "device_uuid": db_device_pk,
-#                "driver": orm_driver.name
-#            }
-#            db_device_driver = DriverModel(**driver_config)
-#            db_device_driver.device_fk = db_device
-#            db_device_driver.driver = orm_driver
-#
-#            self.database.create_or_update(db_device_driver)
-
-#    def update_config(
-#            self, session, db_parent_pk: str, config_name: str,
-#            raw_config_rules: List[Tuple[ORM_ConfigActionEnum, str, str]]
-#    ) -> List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]]:
-#
-#        created = False
-#
-#        db_config = session.query(ConfigModel).filter_by(**{ConfigModel.main_pk_name(): db_parent_pk}).one_or_none()
-#        if not db_config:
-#            db_config = ConfigModel()
-#            setattr(db_config, ConfigModel.main_pk_name(), db_parent_pk)
-#            session.add(db_config)
-#            session.commit()
-#            created = True
-#
-#        LOGGER.info('UPDATED-CONFIG: {}'.format(db_config.dump()))
-#
-#        db_objects: List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]] = [(db_config, created)]
-#
-#        for position, (action, resource_key, resource_value) in enumerate(raw_config_rules):
-#            if action == ORM_ConfigActionEnum.SET:
-#                result : Tuple[ConfigRuleModel, bool] = self.set_config_rule(
-#                    db_config, position, resource_key, resource_value)
-#                db_config_rule, updated = result
-#                db_objects.append((db_config_rule, updated))
-#            elif action == ORM_ConfigActionEnum.DELETE:
-#                self.delete_config_rule(db_config, resource_key)
-#            else:
-#                msg = 'Unsupported action({:s}) for resource_key({:s})/resource_value({:s})'
-#                raise AttributeError(
-#                    msg.format(str(ConfigActionEnum.Name(action)), str(resource_key), str(resource_value)))
-#
-#        return db_objects
-#
-#    def set_config_rule(self, db_config: ConfigModel, position: int, resource_key: str, resource_value: str,
-#    ):  # -> Tuple[ConfigRuleModel, bool]:
-#
-#        from src.context.service.database.Tools import fast_hasher
-#        str_rule_key_hash = fast_hasher(resource_key)
-#        str_config_rule_key = key_to_str([db_config.config_uuid, str_rule_key_hash], separator=':')
-#        pk = str(uuid.uuid5(uuid.UUID('9566448d-e950-425e-b2ae-7ead656c7e47'), str_config_rule_key))
-#        data = {'config_rule_uuid': pk, 'config_uuid': db_config.config_uuid, 'position': position,
-#                'action': ORM_ConfigActionEnum.SET, 'key': resource_key, 'value': resource_value}
-#        to_add = ConfigRuleModel(**data)
-#
-#        result, updated = self.database.create_or_update(to_add)
-#        return result, updated
-#
-#    def delete_config_rule(
-#            self, db_config: ConfigModel, resource_key: str
-#    ) -> None:
-#
-#        from src.context.service.database.Tools import fast_hasher
-#        str_rule_key_hash = fast_hasher(resource_key)
-#        str_config_rule_key = key_to_str([db_config.pk, str_rule_key_hash], separator=':')
-#
-#        db_config_rule = self.database.get_object(ConfigRuleModel, str_config_rule_key, raise_if_not_found=False)
-#
-#        if db_config_rule is None:
-#            return
-#        db_config_rule.delete()
-#
-#    def delete_all_config_rules(self, db_config: ConfigModel) -> None:
-#
-#        db_config_rule_pks = db_config.references(ConfigRuleModel)
-#        for pk, _ in db_config_rule_pks: ConfigRuleModel(self.database, pk).delete()
-#
-#        """
-#        for position, (action, resource_key, resource_value) in enumerate(raw_config_rules):
-#            if action == ORM_ConfigActionEnum.SET:
-#                result: Tuple[ConfigRuleModel, bool] = set_config_rule(
-#                    database, db_config, position, resource_key, resource_value)
-#                db_config_rule, updated = result
-#                db_objects.append((db_config_rule, updated))
-#            elif action == ORM_ConfigActionEnum.DELETE:
-#                delete_config_rule(database, db_config, resource_key)
-#            else:
-#                msg = 'Unsupported action({:s}) for resource_key({:s})/resource_value({:s})'
-#                raise AttributeError(
-#                    msg.format(str(ConfigActionEnum.Name(action)), str(resource_key), str(resource_value)))
-#
-#        return db_objects
-#        """
diff --git a/src/context/service/database/LinkModel.py b/src/context/service/database/LinkModel.py
deleted file mode 100644
index 6b768d1b7ba8e4eca5e35ec774d40f2d66aeac63..0000000000000000000000000000000000000000
--- a/src/context/service/database/LinkModel.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# 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.
-
-import logging, operator
-from typing import Dict, List
-from sqlalchemy import Column, ForeignKey
-from sqlalchemy.dialects.postgresql import UUID
-from context.service.database._Base import Base
-from sqlalchemy.orm import relationship
-
-LOGGER = logging.getLogger(__name__)
-
-class LinkModel(Base):
-    __tablename__ = 'Link'
-    link_uuid = Column(UUID(as_uuid=False), primary_key=True, unique=True)
-
-    @staticmethod
-    def main_pk_name():
-        return 'link_uuid'
-
-    def dump_id(self) -> Dict:
-        return {'link_uuid': {'uuid': self.link_uuid}}
-
-    def dump_endpoint_ids(self) -> List[Dict]:
-        return [endpoint.dump_id() for endpoint in self.endpoints]
-
-    def dump(self, endpoints=None) -> Dict:
-        result = {
-                'link_id': self.dump_id()
-            }
-        if endpoints:
-            result['link_endpoint_ids'] = []
-            for endpoint in endpoints:
-                dump = endpoint.dump_id()
-                LOGGER.info(dump)
-                result['link_endpoint_ids'].append(dump)
-
-            LOGGER.info(result['link_endpoint_ids'])
-
-        LOGGER.info(result)
-        return result
diff --git a/src/context/service/database/methods/Context.py b/src/context/service/database/methods/Context.py
new file mode 100644
index 0000000000000000000000000000000000000000..8f1c2ee23ef853d450343cf4fdedd320b5a12bac
--- /dev/null
+++ b/src/context/service/database/methods/Context.py
@@ -0,0 +1,95 @@
+# 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.
+
+import time
+from sqlalchemy.dialects.postgresql import insert
+from sqlalchemy.engine import Engine
+from sqlalchemy.orm import Session, sessionmaker
+from sqlalchemy_cockroachdb import run_transaction
+from typing import Dict, List, Optional
+from common.proto.context_pb2 import Context, ContextId, ContextIdList, ContextList
+from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentException, NotFoundException
+from context.service.database.models.ContextModel import ContextModel
+
+def context_list_ids(db_engine : Engine) -> ContextIdList:
+    def callback(session : Session) -> List[Dict]:
+        obj_list : List[ContextModel] = session.query(ContextModel).all()
+        #.options(selectinload(ContextModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
+        return [obj.dump_id() for obj in obj_list]
+    return ContextIdList(context_ids=run_transaction(sessionmaker(bind=db_engine), callback))
+
+def context_list_objs(db_engine : Engine) -> ContextList:
+    def callback(session : Session) -> List[Dict]:
+        obj_list : List[ContextModel] = session.query(ContextModel).all()
+        #.options(selectinload(ContextModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
+        return [obj.dump() for obj in obj_list]
+    return ContextList(contexts=run_transaction(sessionmaker(bind=db_engine), callback))
+
+def context_get(db_engine : Engine, request : ContextId) -> Context:
+    context_uuid = request.context_uuid.uuid
+    def callback(session : Session) -> Optional[Dict]:
+        obj : Optional[ContextModel] = session.query(ContextModel)\
+            .filter_by(context_uuid=context_uuid).one_or_none()
+        return None if obj is None else obj.dump()
+    obj = run_transaction(sessionmaker(bind=db_engine), callback)
+    if obj is None: raise NotFoundException('Context', context_uuid)
+    return Context(**obj)
+
+def context_set(db_engine : Engine, request : Context) -> bool:
+    context_uuid = request.context_id.context_uuid.uuid
+    context_name = request.name
+
+    for i, topology_id in enumerate(request.topology_ids):
+        topology_context_uuid = topology_id.context_id.context_uuid.uuid
+        if topology_context_uuid != context_uuid:
+            raise InvalidArgumentException(
+                'request.topology_ids[{:d}].context_id.context_uuid.uuid'.format(i), topology_context_uuid,
+                ['should be == {:s}({:s})'.format('request.context_id.context_uuid.uuid', context_uuid)])
+
+    for i, service_id in enumerate(request.service_ids):
+        service_context_uuid = service_id.context_id.context_uuid.uuid
+        if service_context_uuid != context_uuid:
+            raise InvalidArgumentException(
+                'request.service_ids[{:d}].context_id.context_uuid.uuid'.format(i), service_context_uuid,
+                ['should be == {:s}({:s})'.format('request.context_id.context_uuid.uuid', context_uuid)])
+
+    for i, slice_id in enumerate(request.slice_ids):
+        slice_context_uuid = slice_id.context_id.context_uuid.uuid
+        if slice_context_uuid != context_uuid:
+            raise InvalidArgumentException(
+                'request.slice_ids[{:d}].context_id.context_uuid.uuid'.format(i), slice_context_uuid,
+                ['should be == {:s}({:s})'.format('request.context_id.context_uuid.uuid', context_uuid)])
+
+    def callback(session : Session) -> None:
+        context_data = [{
+            'context_uuid': context_uuid,
+            'context_name': context_name,
+            'created_at'  : time.time(),
+        }]
+        stmt = insert(ContextModel).values(context_data)
+        stmt = stmt.on_conflict_do_update(
+            index_elements=[ContextModel.context_uuid],
+            set_=dict(context_name = stmt.excluded.context_name)
+        )
+        session.execute(stmt)
+
+    run_transaction(sessionmaker(bind=db_engine), callback)
+    return False # TODO: improve and check if created/updated
+
+def context_delete(db_engine : Engine, request : ContextId) -> bool:
+    context_uuid = request.context_uuid.uuid
+    def callback(session : Session) -> bool:
+        num_deleted = session.query(ContextModel).filter_by(context_uuid=context_uuid).delete()
+        return num_deleted > 0
+    return run_transaction(sessionmaker(bind=db_engine), callback)
diff --git a/src/context/service/database/methods/Device.py b/src/context/service/database/methods/Device.py
new file mode 100644
index 0000000000000000000000000000000000000000..e7dc3dadb224fafbeb8b459f4ac5a1a70f844874
--- /dev/null
+++ b/src/context/service/database/methods/Device.py
@@ -0,0 +1,296 @@
+# 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.
+
+import time
+from sqlalchemy import delete
+from sqlalchemy.dialects.postgresql import insert
+from sqlalchemy.engine import Engine
+from sqlalchemy.orm import Session, sessionmaker
+from sqlalchemy_cockroachdb import run_transaction
+from typing import Dict, List, Optional, Set, Tuple
+from common.proto.context_pb2 import Device, DeviceId, DeviceIdList, DeviceList
+from common.rpc_method_wrapper.ServiceExceptions import InvalidArgumentException, NotFoundException
+from common.tools.grpc.Tools import grpc_message_to_json_string
+from context.service.database.models.ConfigRuleModel import ConfigRuleKindEnum, ConfigRuleModel
+from context.service.database.models.DeviceModel import DeviceModel
+from context.service.database.models.EndPointModel import EndPointModel
+from context.service.database.models.RelationModels import TopologyDeviceModel
+from context.service.database.models.enums.ConfigAction import grpc_to_enum__config_action
+from context.service.database.models.enums.DeviceDriver import grpc_to_enum__device_driver
+from context.service.database.models.enums.DeviceOperationalStatus import grpc_to_enum__device_operational_status
+from context.service.database.models.enums.KpiSampleType import grpc_to_enum__kpi_sample_type
+
+def device_list_ids(db_engine : Engine) -> DeviceIdList:
+    def callback(session : Session) -> List[Dict]:
+        obj_list : List[DeviceModel] = session.query(DeviceModel).all()
+        #.options(selectinload(DeviceModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
+        return [obj.dump_id() for obj in obj_list]
+    return DeviceIdList(device_ids=run_transaction(sessionmaker(bind=db_engine), callback))
+
+def device_list_objs(db_engine : Engine) -> DeviceList:
+    def callback(session : Session) -> List[Dict]:
+        obj_list : List[DeviceModel] = session.query(DeviceModel).all()
+        #.options(selectinload(DeviceModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
+        return [obj.dump() for obj in obj_list]
+    return DeviceList(devices=run_transaction(sessionmaker(bind=db_engine), callback))
+
+def device_get(db_engine : Engine, request : DeviceId) -> Device:
+    device_uuid = request.device_uuid.uuid
+    def callback(session : Session) -> Optional[Dict]:
+        obj : Optional[DeviceModel] = session.query(DeviceModel)\
+            .filter_by(device_uuid=device_uuid).one_or_none()
+        return None if obj is None else obj.dump()
+    obj = run_transaction(sessionmaker(bind=db_engine), callback)
+    if obj is None: raise NotFoundException('Device', device_uuid)
+    return Device(**obj)
+
+def device_set(db_engine : Engine, request : Device) -> bool:
+    device_uuid = request.device_id.device_uuid.uuid
+    device_name = request.name
+    device_type = request.device_type
+    oper_status = grpc_to_enum__device_operational_status(request.device_operational_status)
+    device_drivers = [grpc_to_enum__device_driver(d) for d in request.device_drivers]
+
+    topology_keys : Set[Tuple[str, str]] = set()
+    related_topologies : List[Dict] = list()
+    endpoints_data : List[Dict] = list()
+    for i, endpoint in enumerate(request.device_endpoints):
+        endpoint_device_uuid = endpoint.endpoint_id.device_id.device_uuid.uuid
+        if len(endpoint_device_uuid) == 0: endpoint_device_uuid = device_uuid
+        if device_uuid != endpoint_device_uuid:
+            raise InvalidArgumentException(
+                'request.device_endpoints[{:d}].device_id.device_uuid.uuid'.format(i), endpoint_device_uuid,
+                ['should be == {:s}({:s})'.format('request.device_id.device_uuid.uuid', device_uuid)])
+
+        endpoint_context_uuid = endpoint.endpoint_id.topology_id.context_id.context_uuid.uuid
+        endpoint_topology_uuid = endpoint.endpoint_id.topology_id.topology_uuid.uuid
+
+        kpi_sample_types = [grpc_to_enum__kpi_sample_type(kst) for kst in endpoint.kpi_sample_types]
+
+        endpoints_data.append({
+            'context_uuid'    : endpoint_context_uuid,
+            'topology_uuid'   : endpoint_topology_uuid,
+            'device_uuid'     : endpoint_device_uuid,
+            'endpoint_uuid'   : endpoint.endpoint_id.endpoint_uuid.uuid,
+            'endpoint_type'   : endpoint.endpoint_type,
+            'kpi_sample_types': kpi_sample_types,
+        })
+
+        if len(endpoint_context_uuid) > 0 and len(endpoint_topology_uuid) > 0:
+            topology_key = (endpoint_context_uuid, endpoint_topology_uuid)
+            if topology_key not in topology_keys:
+                related_topologies.append({
+                    'context_uuid': endpoint_context_uuid,
+                    'topology_uuid': endpoint_topology_uuid,
+                    'device_uuid': endpoint_device_uuid,
+                })
+                topology_keys.add(topology_key)
+
+    config_rules : List[Dict] = list()
+    for position,config_rule in enumerate(request.device_config.config_rules):
+        str_kind = config_rule.WhichOneof('config_rule')
+        config_rules.append({
+            'device_uuid': device_uuid,
+            'kind'       : ConfigRuleKindEnum._member_map_.get(str_kind.upper()), # pylint: disable=no-member
+            'action'     : grpc_to_enum__config_action(config_rule.action),
+            'position'   : position,
+            'data'       : grpc_message_to_json_string(getattr(config_rule, str_kind, {})),
+        })
+
+    def callback(session : Session) -> None:
+        obj : Optional[DeviceModel] = session.query(DeviceModel).with_for_update()\
+            .filter_by(device_uuid=device_uuid).one_or_none()
+        is_update = obj is not None
+        if is_update:
+            obj.device_name = device_name
+            obj.device_type = device_type
+            obj.device_operational_status = oper_status
+            obj.device_drivers = device_drivers
+            session.merge(obj)
+        else:
+            session.add(DeviceModel(
+                device_uuid=device_uuid, device_name=device_name, device_type=device_type,
+                device_operational_status=oper_status, device_drivers=device_drivers, created_at=time.time()))
+        obj : Optional[DeviceModel] = session.query(DeviceModel)\
+            .filter_by(device_uuid=device_uuid).one_or_none()
+
+        stmt = insert(EndPointModel).values(endpoints_data)
+        stmt = stmt.on_conflict_do_update(
+            index_elements=[
+                EndPointModel.context_uuid, EndPointModel.topology_uuid, EndPointModel.device_uuid,
+                EndPointModel.endpoint_uuid
+            ],
+            set_=dict(
+                endpoint_type = stmt.excluded.endpoint_type,
+                kpi_sample_types = stmt.excluded.kpi_sample_types,
+            )
+        )
+        session.execute(stmt)
+
+        session.execute(insert(TopologyDeviceModel).values(related_topologies).on_conflict_do_nothing(
+            index_elements=[
+                TopologyDeviceModel.context_uuid, TopologyDeviceModel.topology_uuid,
+                TopologyDeviceModel.device_uuid
+            ]
+        ))
+
+        session.execute(delete(ConfigRuleModel).where(ConfigRuleModel.device_uuid == device_uuid))
+        session.execute(insert(ConfigRuleModel).values(config_rules))
+
+    run_transaction(sessionmaker(bind=db_engine), callback)
+    return False # TODO: improve and check if created/updated
+
+def device_delete(db_engine : Engine, request : DeviceId) -> bool:
+    device_uuid = request.device_uuid.uuid
+    def callback(session : Session) -> bool:
+        session.query(TopologyDeviceModel).filter_by(device_uuid=device_uuid).delete()
+        num_deleted = session.query(DeviceModel).filter_by(device_uuid=device_uuid).delete()
+        #db_device = session.query(DeviceModel).filter_by(device_uuid=device_uuid).one_or_none()
+        #session.query(ConfigRuleModel).filter_by(config_uuid=db_device.device_config_uuid).delete()
+        #session.query(ConfigModel).filter_by(config_uuid=db_device.device_config_uuid).delete()
+        #session.query(DeviceModel).filter_by(device_uuid=device_uuid).delete()
+        return num_deleted > 0
+    return run_transaction(sessionmaker(bind=db_engine), callback)
+
+
+
+
+#Union_SpecificConfigRule = Union[
+#    ConfigRuleCustomModel, ConfigRuleAclModel
+#]
+#
+#def set_config_rule(
+#    database : Database, db_config : ConfigModel, position : int, resource_key : str, resource_value : str,
+#): # -> Tuple[ConfigRuleModel, bool]:
+#
+#    str_rule_key_hash = fast_hasher(resource_key)
+#    str_config_rule_key = key_to_str([db_config.config_uuid, str_rule_key_hash], separator=':')
+#
+#    data = {'config_fk': db_config, 'position': position, 'action': ORM_ConfigActionEnum.SET, 'key': resource_key,
+#            'value': resource_value}
+#    to_add = ConfigRuleModel(**data)
+#
+#    result = database.create_or_update(to_add)
+#    return result
+#Tuple_ConfigRuleSpecs = Tuple[Type, str, Dict, ConfigRuleKindEnum]
+#
+#def parse_config_rule_custom(database : Database, grpc_config_rule) -> Tuple_ConfigRuleSpecs:
+#    config_rule_class = ConfigRuleCustomModel
+#    str_config_rule_id = grpc_config_rule.custom.resource_key
+#    config_rule_data = {
+#        'key'  : grpc_config_rule.custom.resource_key,
+#        'value': grpc_config_rule.custom.resource_value,
+#    }
+#    return config_rule_class, str_config_rule_id, config_rule_data, ConfigRuleKindEnum.CUSTOM
+#
+#def parse_config_rule_acl(database : Database, grpc_config_rule) -> Tuple_ConfigRuleSpecs:
+#    config_rule_class = ConfigRuleAclModel
+#    grpc_endpoint_id = grpc_config_rule.acl.endpoint_id
+#    grpc_rule_set = grpc_config_rule.acl.rule_set
+#    device_uuid = grpc_endpoint_id.device_id.device_uuid.uuid
+#    endpoint_uuid = grpc_endpoint_id.endpoint_uuid.uuid
+#    str_endpoint_key = '/'.join([device_uuid, endpoint_uuid])
+#    #str_endpoint_key, db_endpoint = get_endpoint(database, grpc_endpoint_id)
+#    str_config_rule_id = ':'.join([str_endpoint_key, grpc_rule_set.name])
+#    config_rule_data = {
+#        #'endpoint_fk': db_endpoint,
+#        'endpoint_id': grpc_message_to_json_string(grpc_endpoint_id),
+#        'acl_data': grpc_message_to_json_string(grpc_rule_set),
+#    }
+#    return config_rule_class, str_config_rule_id, config_rule_data, ConfigRuleKindEnum.ACL
+#
+#CONFIGRULE_PARSERS = {
+#    'custom': parse_config_rule_custom,
+#    'acl'   : parse_config_rule_acl,
+#}
+#
+#Union_ConfigRuleModel = Union[
+#    ConfigRuleCustomModel, ConfigRuleAclModel,
+#]
+#
+#def set_config_rule(
+#    database : Database, db_config : ConfigModel, grpc_config_rule : ConfigRule, position : int
+#) -> Tuple[Union_ConfigRuleModel, bool]:
+#    grpc_config_rule_kind = str(grpc_config_rule.WhichOneof('config_rule'))
+#    parser = CONFIGRULE_PARSERS.get(grpc_config_rule_kind)
+#    if parser is None:
+#        raise NotImplementedError('ConfigRule of kind {:s} is not implemented: {:s}'.format(
+#            grpc_config_rule_kind, grpc_message_to_json_string(grpc_config_rule)))
+#
+#    # create specific ConfigRule
+#    config_rule_class, str_config_rule_id, config_rule_data, config_rule_kind = parser(database, grpc_config_rule)
+#    str_config_rule_key_hash = fast_hasher(':'.join([config_rule_kind.value, str_config_rule_id]))
+#    str_config_rule_key = key_to_str([db_config.pk, str_config_rule_key_hash], separator=':')
+#    result : Tuple[Union_ConfigRuleModel, bool] = update_or_create_object(
+#        database, config_rule_class, str_config_rule_key, config_rule_data)
+#    db_specific_config_rule, updated = result
+#
+#    # create generic ConfigRule
+#    config_rule_fk_field_name = 'config_rule_{:s}_fk'.format(config_rule_kind.value)
+#    config_rule_data = {
+#        'config_fk': db_config, 'kind': config_rule_kind, 'position': position,
+#        'action': ORM_ConfigActionEnum.SET,
+#        config_rule_fk_field_name: db_specific_config_rule
+#    }
+#    result : Tuple[ConfigRuleModel, bool] = update_or_create_object(
+#        database, ConfigRuleModel, str_config_rule_key, config_rule_data)
+#    db_config_rule, updated = result
+#
+#    return db_config_rule, updated
+#
+#def delete_config_rule(
+#    database : Database, db_config : ConfigModel, grpc_config_rule : ConfigRule
+#) -> None:
+#    grpc_config_rule_kind = str(grpc_config_rule.WhichOneof('config_rule'))
+#    parser = CONFIGRULE_PARSERS.get(grpc_config_rule_kind)
+#    if parser is None:
+#        raise NotImplementedError('ConfigRule of kind {:s} is not implemented: {:s}'.format(
+#            grpc_config_rule_kind, grpc_message_to_json_string(grpc_config_rule)))
+#
+#    # delete generic config rules; self deletes specific config rule
+#    _, str_config_rule_id, _, config_rule_kind = parser(database, grpc_config_rule)
+#    str_config_rule_key_hash = fast_hasher(':'.join([config_rule_kind.value, str_config_rule_id]))
+#    str_config_rule_key = key_to_str([db_config.pk, str_config_rule_key_hash], separator=':')
+#    db_config_rule : Optional[ConfigRuleModel] = get_object(
+#        database, ConfigRuleModel, str_config_rule_key, raise_if_not_found=False)
+#    if db_config_rule is None: return
+#    db_config_rule.delete()
+#
+#def update_config(
+#    database : Database, db_parent_pk : str, config_name : str, grpc_config_rules
+#) -> List[Tuple[Union[ConfigModel, ConfigRuleModel], bool]]:
+#
+#    str_config_key = key_to_str([config_name, db_parent_pk], separator=':')
+#    result : Tuple[ConfigModel, bool] = get_or_create_object(database, ConfigModel, str_config_key)
+#    db_config, created = result
+#
+#    db_objects = [(db_config, created)]
+#
+#    for position,grpc_config_rule in enumerate(grpc_config_rules):
+#        action = grpc_to_enum__config_action(grpc_config_rule.action)
+#
+#        if action == ORM_ConfigActionEnum.SET:
+#            result : Tuple[ConfigRuleModel, bool] = set_config_rule(
+#                database, db_config, grpc_config_rule, position)
+#            db_config_rule, updated = result
+#            db_objects.append((db_config_rule, updated))
+#        elif action == ORM_ConfigActionEnum.DELETE:
+#            delete_config_rule(database, db_config, grpc_config_rule)
+#        else:
+#            msg = 'Unsupported Action({:s}) for ConfigRule({:s})'
+#            str_action = str(ConfigActionEnum.Name(action))
+#            str_config_rule = grpc_message_to_json_string(grpc_config_rule)
+#            raise AttributeError(msg.format(str_action, str_config_rule))
+#
+#    return db_objects
diff --git a/src/context/service/database/methods/Link.py b/src/context/service/database/methods/Link.py
new file mode 100644
index 0000000000000000000000000000000000000000..b98578c226e7b5810c15bf3d783038d6975a334c
--- /dev/null
+++ b/src/context/service/database/methods/Link.py
@@ -0,0 +1,120 @@
+# 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.
+
+import time
+from sqlalchemy.dialects.postgresql import insert
+from sqlalchemy.engine import Engine
+from sqlalchemy.orm import Session, sessionmaker
+from sqlalchemy_cockroachdb import run_transaction
+from typing import Dict, List, Optional, Set, Tuple
+from common.proto.context_pb2 import Link, LinkId, LinkIdList, LinkList
+from common.rpc_method_wrapper.ServiceExceptions import NotFoundException
+from context.service.database.models.LinkModel import LinkModel
+from context.service.database.models.RelationModels import LinkEndPointModel, TopologyLinkModel
+
+def link_list_ids(db_engine : Engine) -> LinkIdList:
+    def callback(session : Session) -> List[Dict]:
+        obj_list : List[LinkModel] = session.query(LinkModel).all()
+        #.options(selectinload(LinkModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
+        return [obj.dump_id() for obj in obj_list]
+    return LinkIdList(link_ids=run_transaction(sessionmaker(bind=db_engine), callback))
+
+def link_list_objs(db_engine : Engine) -> LinkList:
+    def callback(session : Session) -> List[Dict]:
+        obj_list : List[LinkModel] = session.query(LinkModel).all()
+        #.options(selectinload(LinkModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
+        return [obj.dump() for obj in obj_list]
+    return LinkList(links=run_transaction(sessionmaker(bind=db_engine), callback))
+
+def link_get(db_engine : Engine, request : LinkId) -> Link:
+    link_uuid = request.link_uuid.uuid
+    def callback(session : Session) -> Optional[Dict]:
+        obj : Optional[LinkModel] = session.query(LinkModel)\
+            .filter_by(link_uuid=link_uuid).one_or_none()
+        return None if obj is None else obj.dump()
+    obj = run_transaction(sessionmaker(bind=db_engine), callback)
+    if obj is None: raise NotFoundException('Link', link_uuid)
+    return Link(**obj)
+
+def link_set(db_engine : Engine, request : Link) -> bool:
+    link_uuid = request.link_id.link_uuid.uuid
+    link_name = request.name
+
+    topology_keys : Set[Tuple[str, str]] = set()
+    related_topologies : List[Dict] = list()
+    link_endpoints_data : List[Dict] = list()
+    for endpoint_id in request.link_endpoint_ids:
+        context_uuid  = endpoint_id.topology_id.context_id.context_uuid.uuid
+        topology_uuid = endpoint_id.topology_id.topology_uuid.uuid
+        device_uuid   = endpoint_id.device_id.device_uuid.uuid
+        endpoint_uuid = endpoint_id.endpoint_uuid.uuid
+
+        link_endpoints_data.append({
+            'link_uuid'    : link_uuid,
+            'context_uuid' : context_uuid,
+            'topology_uuid': topology_uuid,
+            'device_uuid'  : device_uuid,
+            'endpoint_uuid': endpoint_uuid,
+        })
+
+        if len(context_uuid) > 0 and len(topology_uuid) > 0:
+            topology_key = (context_uuid, topology_uuid)
+            if topology_key not in topology_keys:
+                related_topologies.append({
+                    'context_uuid': context_uuid,
+                    'topology_uuid': topology_uuid,
+                    'link_uuid': link_uuid,
+                })
+                topology_keys.add(topology_key)
+
+    def callback(session : Session) -> None:
+        obj : Optional[LinkModel] = session.query(LinkModel).with_for_update()\
+            .filter_by(link_uuid=link_uuid).one_or_none()
+        is_update = obj is not None
+        if is_update:
+            obj.link_name = link_name
+            session.merge(obj)
+        else:
+            session.add(LinkModel(link_uuid=link_uuid, link_name=link_name, created_at=time.time()))
+        obj : Optional[LinkModel] = session.query(LinkModel)\
+            .filter_by(link_uuid=link_uuid).one_or_none()
+
+        stmt = insert(LinkEndPointModel).values(link_endpoints_data)
+        stmt = stmt.on_conflict_do_nothing(
+            index_elements=[
+                LinkEndPointModel.link_uuid, LinkEndPointModel.context_uuid, LinkEndPointModel.topology_uuid,
+                LinkEndPointModel.device_uuid, LinkEndPointModel.endpoint_uuid
+            ],
+        )
+        session.execute(stmt)
+
+        session.execute(insert(TopologyLinkModel).values(related_topologies).on_conflict_do_nothing(
+            index_elements=[
+                TopologyLinkModel.context_uuid, TopologyLinkModel.topology_uuid,
+                TopologyLinkModel.link_uuid
+            ]
+        ))
+    run_transaction(sessionmaker(bind=db_engine), callback)
+    return False # TODO: improve and check if created/updated
+
+def link_delete(db_engine : Engine, request : LinkId) -> bool:
+    link_uuid = request.link_uuid.uuid
+    def callback(session : Session) -> bool:
+        session.query(TopologyLinkModel).filter_by(link_uuid=link_uuid).delete()
+        session.query(LinkEndPointModel).filter_by(link_uuid=link_uuid).delete()
+        num_deleted = session.query(LinkModel).filter_by(link_uuid=link_uuid).delete()
+        #db_link = session.query(LinkModel).filter_by(link_uuid=link_uuid).one_or_none()
+        #session.query(LinkModel).filter_by(link_uuid=link_uuid).delete()
+        return num_deleted > 0
+    return run_transaction(sessionmaker(bind=db_engine), callback)
diff --git a/src/context/service/database/methods/Topology.py b/src/context/service/database/methods/Topology.py
new file mode 100644
index 0000000000000000000000000000000000000000..f9449e0c39050544ae9f5bba6b9f73e6913cde42
--- /dev/null
+++ b/src/context/service/database/methods/Topology.py
@@ -0,0 +1,123 @@
+# 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.
+
+import time
+from sqlalchemy.dialects.postgresql import insert
+from sqlalchemy.engine import Engine
+from sqlalchemy.orm import Session, sessionmaker
+from sqlalchemy_cockroachdb import run_transaction
+from typing import Dict, List, Optional, Set
+from common.proto.context_pb2 import ContextId, Topology, TopologyId, TopologyIdList, TopologyList
+from common.rpc_method_wrapper.ServiceExceptions import NotFoundException
+from context.service.database.models.RelationModels import TopologyDeviceModel
+from context.service.database.models.TopologyModel import TopologyModel
+
+def topology_list_ids(db_engine : Engine, request : ContextId) -> TopologyIdList:
+    context_uuid = request.context_uuid.uuid
+    def callback(session : Session) -> List[Dict]:
+        obj_list : List[TopologyModel] = session.query(TopologyModel).filter_by(context_uuid=context_uuid).all()
+        #.options(selectinload(ContextModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
+        return [obj.dump_id() for obj in obj_list]
+    return TopologyIdList(topology_ids=run_transaction(sessionmaker(bind=db_engine), callback))
+
+def topology_list_objs(db_engine : Engine, request : ContextId) -> TopologyList:
+    context_uuid = request.context_uuid.uuid
+    def callback(session : Session) -> List[Dict]:
+        obj_list : List[TopologyModel] = session.query(TopologyModel).filter_by(context_uuid=context_uuid).all()
+        #.options(selectinload(ContextModel.topology)).filter_by(context_uuid=context_uuid).one_or_none()
+        return [obj.dump() for obj in obj_list]
+    return TopologyList(topologies=run_transaction(sessionmaker(bind=db_engine), callback))
+
+def topology_get(db_engine : Engine, request : TopologyId) -> Topology:
+    context_uuid = request.context_id.context_uuid.uuid
+    topology_uuid = request.topology_uuid.uuid
+
+    def callback(session : Session) -> Optional[Dict]:
+        obj : Optional[TopologyModel] = session.query(TopologyModel)\
+            .filter_by(context_uuid=context_uuid, topology_uuid=topology_uuid).one_or_none()
+        return None if obj is None else obj.dump()
+    obj = run_transaction(sessionmaker(bind=db_engine), callback)
+    if obj is None:
+        obj_uuid = '{:s}/{:s}'.format(context_uuid, topology_uuid)
+        raise NotFoundException('Topology', obj_uuid)
+    return Topology(**obj)
+
+def topology_set(db_engine : Engine, request : Topology) -> bool:
+    context_uuid = request.topology_id.context_id.context_uuid.uuid
+    topology_uuid = request.topology_id.topology_uuid.uuid
+    topology_name = request.name
+
+    device_uuids : Set[str] = set()
+    devices_to_add : List[Dict] = list()
+    for device_id in request.device_ids:
+        device_uuid = device_id.device_uuid.uuid
+        if device_uuid in device_uuids: continue
+        devices_to_add.append({
+            'context_uuid': context_uuid, 'topology_uuid': topology_uuid, 'device_uuid': device_uuid
+        })
+        device_uuids.add(device_uuid)
+
+    link_uuids : Set[str] = set()
+    links_to_add : List[Dict] = list()
+    for link_id in request.link_ids:
+        link_uuid = link_id.link_uuid.uuid
+        if link_uuid in link_uuids: continue
+        links_to_add.append({
+            'context_uuid': context_uuid, 'topology_uuid': topology_uuid, 'link_uuid': link_uuid
+        })
+        link_uuids.add(link_uuid)
+
+    def callback(session : Session) -> None:
+        topology_data = [{
+            'context_uuid' : context_uuid,
+            'topology_uuid': topology_uuid,
+            'topology_name': topology_name,
+            'created_at'   : time.time(),
+        }]
+        stmt = insert(TopologyModel).values(topology_data)
+        stmt = stmt.on_conflict_do_update(
+            index_elements=[TopologyModel.context_uuid, TopologyModel.topology_uuid],
+            set_=dict(topology_name = stmt.excluded.topology_name)
+        )
+        session.execute(stmt)
+
+        if len(devices_to_add) > 0:
+            session.execute(insert(TopologyDeviceModel).values(devices_to_add).on_conflict_do_nothing(
+                index_elements=[
+                    TopologyDeviceModel.context_uuid, TopologyDeviceModel.topology_uuid,
+                    TopologyDeviceModel.device_uuid
+                ]
+            ))
+
+        #if len(link_to_add) > 0:
+        #    session.execute(insert(TopologyLinkModel).values(links_to_add).on_conflict_do_nothing(
+        #        index_elements=[
+        #            TopologyLinkModel.context_uuid, TopologyLinkModel.topology_uuid,
+        #            TopologyLinkModel.link_uuid
+        #        ]
+        #    ))
+
+    run_transaction(sessionmaker(bind=db_engine), callback)
+    return False # TODO: improve and check if created/updated
+
+def topology_delete(db_engine : Engine, request : TopologyId) -> bool:
+    context_uuid = request.context_id.context_uuid.uuid
+    topology_uuid = request.topology_uuid.uuid
+
+    def callback(session : Session) -> bool:
+        num_deleted = session.query(TopologyModel)\
+            .filter_by(context_uuid=context_uuid, topology_uuid=topology_uuid).delete()
+        return num_deleted > 0
+
+    return run_transaction(sessionmaker(bind=db_engine), callback)
diff --git a/src/context/service/database/methods/__init__.py b/src/context/service/database/methods/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9953c820575d42fa88351cc8de022d880ba96e6a
--- /dev/null
+++ b/src/context/service/database/methods/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/src/context/service/database/models/ConfigRuleModel.py b/src/context/service/database/models/ConfigRuleModel.py
new file mode 100644
index 0000000000000000000000000000000000000000..d5a37eed2cfac39ebb4b72906e1e70249e22b365
--- /dev/null
+++ b/src/context/service/database/models/ConfigRuleModel.py
@@ -0,0 +1,44 @@
+# 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.
+
+import enum, json
+from sqlalchemy import Column, ForeignKey, INTEGER, CheckConstraint, Enum, String, text
+from sqlalchemy.dialects.postgresql import UUID
+from sqlalchemy.orm import relationship
+from typing import Dict
+from .enums.ConfigAction import ORM_ConfigActionEnum
+from ._Base import _Base
+
+# enum values should match name of field in ConfigRuleModel
+class ConfigRuleKindEnum(enum.Enum):
+    CUSTOM = 'custom'
+    ACL    = 'acl'
+
+class ConfigRuleModel(_Base):
+    __tablename__ = 'config_rule'
+    device_uuid = Column(UUID(as_uuid=False), ForeignKey('device.device_uuid', ondelete='CASCADE'), primary_key=True)
+    rule_uuid = Column(UUID(as_uuid=False), primary_key=True, server_default=text('uuid_generate_v4()'))
+    kind = Column(Enum(ConfigRuleKindEnum))
+    action = Column(Enum(ORM_ConfigActionEnum))
+    position = Column(INTEGER, nullable=False)
+    data = Column(String, nullable=False)
+
+    __table_args__ = (
+        CheckConstraint(position >= 0, name='check_position_value'),
+    )
+
+    device = relationship('DeviceModel', back_populates='config_rules')
+
+    def dump(self) -> Dict:
+        return {self.kind.value: json.loads(self.data)}
diff --git a/src/context/service/database/ConnectionModel.py b/src/context/service/database/models/ConnectionModel.py
similarity index 97%
rename from src/context/service/database/ConnectionModel.py
rename to src/context/service/database/models/ConnectionModel.py
index e780ccb681101919dd7065ab6424dcb9033f521b..546fb7a80ee42a524e8950c8d5d3363a09ee6710 100644
--- a/src/context/service/database/ConnectionModel.py
+++ b/src/context/service/database/models/ConnectionModel.py
@@ -24,19 +24,21 @@ from common.orm.HighLevel import get_object, get_or_create_object, get_related_o
 from common.proto.context_pb2 import EndPointId
 from .EndPointModel import EndPointModel
 from .ServiceModel import ServiceModel
-from .Tools import remove_dict_key
 
+def remove_dict_key(dictionary : Dict, key : str):
+    dictionary.pop(key, None)
+    return dictionary
 
 from sqlalchemy import Column, Enum, ForeignKey, Integer, CheckConstraint
 from typing import Dict, List
 from common.orm.HighLevel import get_related_objects
 from common.proto.context_pb2 import ServiceStatusEnum, ServiceTypeEnum
-from .ConfigModel import ConfigModel
+from .ConfigRuleModel import ConfigModel
 from .ConstraintModel import ConstraintsModel
-from .ContextModel import ContextModel
+from .models.ContextModel import ContextModel
 from .Tools import grpc_to_enum
 from sqlalchemy.dialects.postgresql import UUID
-from context.service.database._Base import Base
+from context.service.database.models._Base import Base
 import enum
 LOGGER = logging.getLogger(__name__)
 
diff --git a/src/context/service/database/ConstraintModel.py b/src/context/service/database/models/ConstraintModel.py
similarity index 98%
rename from src/context/service/database/ConstraintModel.py
rename to src/context/service/database/models/ConstraintModel.py
index 30d9003009f2f804a168a3b709bb15565dae96ed..d616c3a7fe86adfccd37faa39fef737a4e21dfeb 100644
--- a/src/context/service/database/ConstraintModel.py
+++ b/src/context/service/database/models/ConstraintModel.py
@@ -19,14 +19,17 @@ from common.orm.backend.Tools import key_to_str
 from common.proto.context_pb2 import Constraint
 from common.tools.grpc.Tools import grpc_message_to_json_string
 from .EndPointModel import EndPointModel
-from .Tools import fast_hasher, remove_dict_key
+from .Tools import fast_hasher
 from sqlalchemy import Column, ForeignKey, String, Float, CheckConstraint, Integer, Boolean, Enum
 from sqlalchemy.dialects.postgresql import UUID
-from context.service.database._Base import Base
+from context.service.database.models._Base import Base
 import enum
 
 LOGGER = logging.getLogger(__name__)
 
+def remove_dict_key(dictionary : Dict, key : str):
+    dictionary.pop(key, None)
+    return dictionary
 
 class ConstraintsModel(Base): # pylint: disable=abstract-method
     __tablename__ = 'Constraints'
diff --git a/src/context/service/database/ContextModel.py b/src/context/service/database/models/ContextModel.py
similarity index 86%
rename from src/context/service/database/ContextModel.py
rename to src/context/service/database/models/ContextModel.py
index ae8cf995f67cba1708e1bad6d941ef2c976eb67c..a5ddeb59686356e211192fc18390df8cc54834bc 100644
--- a/src/context/service/database/ContextModel.py
+++ b/src/context/service/database/models/ContextModel.py
@@ -24,9 +24,9 @@ class ContextModel(_Base):
     context_name = Column(String(), nullable=False)
     created_at   = Column(Float)
 
-    topology = relationship('TopologyModel', back_populates='context')
-    #service  = relationship('ServiceModel', back_populates='context')
-    #slice    = relationship('SliceModel', back_populates='context')
+    topologies = relationship('TopologyModel', back_populates='context')
+    #services  = relationship('ServiceModel', back_populates='context')
+    #slices    = relationship('SliceModel', back_populates='context')
 
     def dump_id(self) -> Dict:
         return {'context_uuid': {'uuid': self.context_uuid}}
@@ -38,7 +38,7 @@ class ContextModel(_Base):
         return {
             'context_id'  : self.dump_id(),
             'name'        : self.context_name,
-            'topology_ids': [obj.dump_id() for obj in self.topology],
-            #'service_ids' : [obj.dump_id() for obj in self.service ],
-            #'slice_ids'   : [obj.dump_id() for obj in self.slice   ],
+            'topology_ids': [obj.dump_id() for obj in self.topologies],
+            #'service_ids' : [obj.dump_id() for obj in self.services ],
+            #'slice_ids'   : [obj.dump_id() for obj in self.slices   ],
         }
diff --git a/src/context/service/database/models/DeviceModel.py b/src/context/service/database/models/DeviceModel.py
new file mode 100644
index 0000000000000000000000000000000000000000..fb585348216a294f4e92d92fb1d10dac4c9cb57d
--- /dev/null
+++ b/src/context/service/database/models/DeviceModel.py
@@ -0,0 +1,52 @@
+# 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.
+
+import operator
+from typing import Dict
+from sqlalchemy import Column, Float, String, Enum
+from sqlalchemy.dialects.postgresql import UUID, ARRAY
+from sqlalchemy.orm import relationship
+from ._Base import _Base
+from .enums.DeviceDriver import ORM_DeviceDriverEnum
+from .enums.DeviceOperationalStatus import ORM_DeviceOperationalStatusEnum
+
+class DeviceModel(_Base):
+    __tablename__ = 'device'
+    device_uuid = Column(UUID(as_uuid=False), primary_key=True)
+    device_name = Column(String, nullable=False)
+    device_type = Column(String, nullable=False)
+    device_operational_status = Column(Enum(ORM_DeviceOperationalStatusEnum))
+    device_drivers = Column(ARRAY(Enum(ORM_DeviceDriverEnum), dimensions=1))
+    created_at = Column(Float)
+
+    topology_devices = relationship('TopologyDeviceModel', back_populates='device')
+    config_rules     = relationship('ConfigRuleModel', passive_deletes=True, back_populates='device', lazy='joined')
+    endpoints        = relationship('EndPointModel', passive_deletes=True, back_populates='device', lazy='joined')
+
+    def dump_id(self) -> Dict:
+        return {'device_uuid': {'uuid': self.device_uuid}}
+
+    def dump(self) -> Dict:
+        return {
+            'device_id'                : self.dump_id(),
+            'name'                     : self.device_name,
+            'device_type'              : self.device_type,
+            'device_operational_status': self.device_operational_status.value,
+            'device_drivers'           : [driver.value for driver in self.device_drivers],
+            'device_config'            : {'config_rules': [
+                config_rule.dump()
+                for config_rule in sorted(self.config_rules, key=operator.attrgetter('position'))
+            ]},
+            'device_endpoints'         : [endpoint.dump() for endpoint in self.endpoints],
+        }
diff --git a/src/context/service/database/EndPointModel.py b/src/context/service/database/models/EndPointModel.py
similarity index 82%
rename from src/context/service/database/EndPointModel.py
rename to src/context/service/database/models/EndPointModel.py
index a8d3c2c699db8f54024508edc376c519509f0c03..b7e4c9fe38d59bc6fab02f8cfa7338eb1ce16c41 100644
--- a/src/context/service/database/EndPointModel.py
+++ b/src/context/service/database/models/EndPointModel.py
@@ -12,24 +12,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import enum, functools
 from typing import Dict
 from sqlalchemy import Column, String, Enum, ForeignKeyConstraint
 from sqlalchemy.dialects.postgresql import ARRAY, UUID
 from sqlalchemy.orm import relationship
-from common.proto.kpi_sample_types_pb2 import KpiSampleType
+from .enums.KpiSampleType import ORM_KpiSampleTypeEnum
 from ._Base import _Base
-from .Tools import grpc_to_enum
-
-class ORM_KpiSampleTypeEnum(enum.Enum):
-    UNKNOWN             = KpiSampleType.KPISAMPLETYPE_UNKNOWN
-    PACKETS_TRANSMITTED = KpiSampleType.KPISAMPLETYPE_PACKETS_TRANSMITTED
-    PACKETS_RECEIVED    = KpiSampleType.KPISAMPLETYPE_PACKETS_RECEIVED
-    BYTES_TRANSMITTED   = KpiSampleType.KPISAMPLETYPE_BYTES_TRANSMITTED
-    BYTES_RECEIVED      = KpiSampleType.KPISAMPLETYPE_BYTES_RECEIVED
-
-grpc_to_enum__kpi_sample_type = functools.partial(
-    grpc_to_enum, KpiSampleType, ORM_KpiSampleTypeEnum)
 
 class EndPointModel(_Base):
     __tablename__ = 'endpoint'
@@ -51,8 +39,9 @@ class EndPointModel(_Base):
             ondelete='CASCADE'),
     )
 
-    topology = relationship('TopologyModel', back_populates='endpoints')
-    device   = relationship('DeviceModel', back_populates='endpoints')
+    topology       = relationship('TopologyModel',     back_populates='endpoints')
+    device         = relationship('DeviceModel',       back_populates='endpoints')
+    link_endpoints = relationship('LinkEndPointModel', back_populates='endpoint')
 
     def dump_id(self) -> Dict:
         result = {
diff --git a/src/context/service/database/models/LinkModel.py b/src/context/service/database/models/LinkModel.py
new file mode 100644
index 0000000000000000000000000000000000000000..df173f52726f0f9d28fd350c17abed83bea0b876
--- /dev/null
+++ b/src/context/service/database/models/LinkModel.py
@@ -0,0 +1,41 @@
+# 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.
+
+from typing import Dict
+from sqlalchemy import Column, Float, String
+from sqlalchemy.dialects.postgresql import UUID
+from sqlalchemy.orm import relationship
+from ._Base import _Base
+
+class LinkModel(_Base):
+    __tablename__ = 'link'
+    link_uuid  = Column(UUID(as_uuid=False), primary_key=True)
+    link_name  = Column(String, nullable=False)
+    created_at = Column(Float)
+
+    topology_links = relationship('TopologyLinkModel', back_populates='link')
+    link_endpoints = relationship('LinkEndPointModel', back_populates='link') #, lazy='joined')
+
+    def dump_id(self) -> Dict:
+        return {'link_uuid': {'uuid': self.link_uuid}}
+
+    def dump(self) -> Dict:
+        return {
+            'link_id'          : self.dump_id(),
+            'name'             : self.link_name,
+            'link_endpoint_ids': [
+                link_endpoint.endpoint.dump_id()
+                for link_endpoint in self.link_endpoints
+            ],
+        }
diff --git a/src/context/service/database/PolicyRuleModel.py b/src/context/service/database/models/PolicyRuleModel.py
similarity index 100%
rename from src/context/service/database/PolicyRuleModel.py
rename to src/context/service/database/models/PolicyRuleModel.py
diff --git a/src/context/service/database/RelationModels.py b/src/context/service/database/models/RelationModels.py
similarity index 57%
rename from src/context/service/database/RelationModels.py
rename to src/context/service/database/models/RelationModels.py
index bcf85d005d6e0c11cb77ea567b1bf28fa47bdc1a..6cc4ff86cf061efd516a2bad59e0ad0e5965c796 100644
--- a/src/context/service/database/RelationModels.py
+++ b/src/context/service/database/models/RelationModels.py
@@ -16,7 +16,7 @@ import logging
 from sqlalchemy import Column, ForeignKey, ForeignKeyConstraint
 from sqlalchemy.dialects.postgresql import UUID
 from sqlalchemy.orm import relationship
-from context.service.database._Base import _Base
+from context.service.database.models._Base import _Base
 
 LOGGER = logging.getLogger(__name__)
 
@@ -24,27 +24,43 @@ LOGGER = logging.getLogger(__name__)
 #     pk = PrimaryKeyField()
 #     connection_fk = ForeignKeyField(ConnectionModel)
 #     sub_service_fk = ForeignKeyField(ServiceModel)
-#
-#class LinkEndPointModel(Base):
-#    __tablename__ = 'LinkEndPoint'
-#    # uuid = Column(UUID(as_uuid=False), primary_key=True, unique=True)
+
+
 #    link_uuid = Column(UUID(as_uuid=False), ForeignKey("Link.link_uuid"))
 #    endpoint_uuid = Column(UUID(as_uuid=False), ForeignKey("EndPoint.endpoint_uuid"), primary_key=True)
-#
-#    @staticmethod
-#    def main_pk_name():
-#        return 'endpoint_uuid'
-#
+
+class LinkEndPointModel(_Base):
+    __tablename__ = 'link_endpoint'
+    link_uuid     = Column(UUID(as_uuid=False), primary_key=True)
+    context_uuid  = Column(UUID(as_uuid=False), primary_key=True)
+    topology_uuid = Column(UUID(as_uuid=False), primary_key=True)
+    device_uuid   = Column(UUID(as_uuid=False), primary_key=True)
+    endpoint_uuid = Column(UUID(as_uuid=False), primary_key=True)
+
+    link     = relationship('LinkModel',     back_populates='link_endpoints', lazy='joined')
+    endpoint = relationship('EndPointModel', back_populates='link_endpoints', lazy='joined')
+
+    __table_args__ = (
+        ForeignKeyConstraint(
+            ['link_uuid'],
+            ['link.link_uuid'],
+            ondelete='CASCADE'),
+        ForeignKeyConstraint(
+            ['context_uuid', 'topology_uuid', 'device_uuid', 'endpoint_uuid'],
+            ['endpoint.context_uuid', 'endpoint.topology_uuid', 'endpoint.device_uuid', 'endpoint.endpoint_uuid'],
+            ondelete='CASCADE'),
+    )
+
 # class ServiceEndPointModel(Model):
 #     pk = PrimaryKeyField()
 #     service_fk = ForeignKeyField(ServiceModel)
 #     endpoint_fk = ForeignKeyField(EndPointModel)
-#
+
 # class SliceEndPointModel(Model):
 #     pk = PrimaryKeyField()
 #     slice_fk = ForeignKeyField(SliceModel)
 #     endpoint_fk = ForeignKeyField(EndPointModel)
-#
+
 # class SliceServiceModel(Model):
 #     pk = PrimaryKeyField()
 #     slice_fk = ForeignKeyField(SliceModel)
@@ -54,7 +70,7 @@ LOGGER = logging.getLogger(__name__)
 #     link_uuid = Column(UUID(as_uuid=False), ForeignKey("Link.link_uuid"))
 #     endpoint_uuid = Column(UUID(as_uuid=False), ForeignKey("EndPoint.endpoint_uuid"))
 #del)
-#
+
 # class SliceSubSliceModel(Model):
 #     pk = PrimaryKeyField()
 #     slice_fk = ForeignKeyField(SliceModel)
@@ -66,8 +82,8 @@ class TopologyDeviceModel(_Base):
     topology_uuid = Column(UUID(as_uuid=False), primary_key=True)
     device_uuid   = Column(UUID(as_uuid=False), primary_key=True)
 
-    topologies = relationship('TopologyModel', back_populates='topology_device')
-    devices    = relationship('DeviceModel', back_populates='topology_device')
+    topology = relationship('TopologyModel', back_populates='topology_devices', lazy='joined')
+    device   = relationship('DeviceModel',   back_populates='topology_devices', lazy='joined')
 
     __table_args__ = (
         ForeignKeyConstraint(
@@ -80,7 +96,22 @@ class TopologyDeviceModel(_Base):
             ondelete='CASCADE'),
     )
 
-#class TopologyLinkModel(Base):
-#    __tablename__ = 'TopologyLink'
-#    topology_uuid = Column(UUID(as_uuid=False), ForeignKey("Topology.topology_uuid"))
-#    link_uuid = Column(UUID(as_uuid=False), ForeignKey("Link.link_uuid"), primary_key=True)
+class TopologyLinkModel(_Base):
+    __tablename__ = 'topology_link'
+    context_uuid  = Column(UUID(as_uuid=False), primary_key=True)
+    topology_uuid = Column(UUID(as_uuid=False), primary_key=True)
+    link_uuid     = Column(UUID(as_uuid=False), primary_key=True)
+
+    topology = relationship('TopologyModel', back_populates='topology_links', lazy='joined')
+    link     = relationship('LinkModel',     back_populates='topology_links', lazy='joined')
+
+    __table_args__ = (
+        ForeignKeyConstraint(
+            ['context_uuid', 'topology_uuid'],
+            ['topology.context_uuid', 'topology.topology_uuid'],
+            ondelete='CASCADE'),
+        ForeignKeyConstraint(
+            ['link_uuid'],
+            ['link.link_uuid'],
+            ondelete='CASCADE'),
+    )
diff --git a/src/context/service/database/ServiceModel.py b/src/context/service/database/models/ServiceModel.py
similarity index 97%
rename from src/context/service/database/ServiceModel.py
rename to src/context/service/database/models/ServiceModel.py
index 20e10ddd5a9ecb5b62e22c4c082b3b3144a5a509..c06baca32c785e47fe295699d3cdd2026c0c389b 100644
--- a/src/context/service/database/ServiceModel.py
+++ b/src/context/service/database/models/ServiceModel.py
@@ -17,12 +17,12 @@ from sqlalchemy import Column, Enum, ForeignKey
 from typing import Dict, List
 from common.orm.HighLevel import get_related_objects
 from common.proto.context_pb2 import ServiceStatusEnum, ServiceTypeEnum
-from .ConfigModel import ConfigModel
+from .ConfigRuleModel import ConfigModel
 from .ConstraintModel import ConstraintsModel
-from .ContextModel import ContextModel
+from .models.ContextModel import ContextModel
 from .Tools import grpc_to_enum
 from sqlalchemy.dialects.postgresql import UUID
-from context.service.database._Base import Base
+from context.service.database.models._Base import Base
 import enum
 LOGGER = logging.getLogger(__name__)
 
diff --git a/src/context/service/database/SliceModel.py b/src/context/service/database/models/SliceModel.py
similarity index 98%
rename from src/context/service/database/SliceModel.py
rename to src/context/service/database/models/SliceModel.py
index 74bb60b401f656fdcfec8b0466019f87a8f1b41e..2b03e61222cd8d36836bdacd921d0f0f359827b0 100644
--- a/src/context/service/database/SliceModel.py
+++ b/src/context/service/database/models/SliceModel.py
@@ -22,9 +22,9 @@ from common.orm.fields.StringField import StringField
 from common.orm.model.Model import Model
 from common.orm.HighLevel import get_related_objects
 from common.proto.context_pb2 import SliceStatusEnum
-from .ConfigModel import ConfigModel
+from .ConfigRuleModel import ConfigModel
 from .ConstraintModel import ConstraintsModel
-from .ContextModel import ContextModel
+from .models.ContextModel import ContextModel
 from .Tools import grpc_to_enum
 
 LOGGER = logging.getLogger(__name__)
diff --git a/src/context/service/database/TopologyModel.py b/src/context/service/database/models/TopologyModel.py
similarity index 77%
rename from src/context/service/database/TopologyModel.py
rename to src/context/service/database/models/TopologyModel.py
index 57fe1b3475aa643eba881324f0fc3c05dad74578..95f7a63502a68e8b92b70a29c7b71cf229f108bf 100644
--- a/src/context/service/database/TopologyModel.py
+++ b/src/context/service/database/models/TopologyModel.py
@@ -26,10 +26,10 @@ class TopologyModel(_Base):
     created_at   = Column(Float)
 
     # Relationships
-    context         = relationship('ContextModel', back_populates='topology')
-    topology_device = relationship('TopologyDeviceModel', back_populates='topologies')
-    #topology_link   = relationship('TopologyLinkModel', back_populates='topology')
-    endpoints       = relationship('EndPointModel', back_populates='topology')
+    context          = relationship('ContextModel', back_populates='topologies')
+    topology_devices = relationship('TopologyDeviceModel', back_populates='topology')
+    topology_links   = relationship('TopologyLinkModel', back_populates='topology')
+    endpoints        = relationship('EndPointModel', back_populates='topology')
 
     def dump_id(self) -> Dict:
         return {
@@ -41,6 +41,6 @@ class TopologyModel(_Base):
         return {
             'topology_id': self.dump_id(),
             'name'       : self.topology_name,
-            'device_ids' : [{'device_uuid': {'uuid': td.device_uuid}} for td in self.topology_device],
-            #'link_ids'   : [{'link_uuid'  : {'uuid': td.link_uuid  }} for td in self.topology_link  ],
+            'device_ids' : [{'device_uuid': {'uuid': td.device_uuid}} for td in self.topology_devices],
+            'link_ids'   : [{'link_uuid'  : {'uuid': td.link_uuid  }} for td in self.topology_links  ],
         }
diff --git a/src/context/service/database/_Base.py b/src/context/service/database/models/_Base.py
similarity index 100%
rename from src/context/service/database/_Base.py
rename to src/context/service/database/models/_Base.py
diff --git a/src/context/service/database/models/__init__.py b/src/context/service/database/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9953c820575d42fa88351cc8de022d880ba96e6a
--- /dev/null
+++ b/src/context/service/database/models/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/src/context/service/database/models/enums/ConfigAction.py b/src/context/service/database/models/enums/ConfigAction.py
new file mode 100644
index 0000000000000000000000000000000000000000..6bbcdea99c02823e982d19d1ad8d12c77f17dbdb
--- /dev/null
+++ b/src/context/service/database/models/enums/ConfigAction.py
@@ -0,0 +1,25 @@
+# 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.
+
+import enum, functools
+from common.proto.context_pb2 import ConfigActionEnum
+from ._GrpcToEnum import grpc_to_enum
+
+class ORM_ConfigActionEnum(enum.Enum):
+    UNDEFINED = ConfigActionEnum.CONFIGACTION_UNDEFINED
+    SET       = ConfigActionEnum.CONFIGACTION_SET
+    DELETE    = ConfigActionEnum.CONFIGACTION_DELETE
+
+grpc_to_enum__config_action = functools.partial(
+    grpc_to_enum, ConfigActionEnum, ORM_ConfigActionEnum)
diff --git a/src/context/service/database/models/enums/DeviceDriver.py b/src/context/service/database/models/enums/DeviceDriver.py
new file mode 100644
index 0000000000000000000000000000000000000000..21338ddb8dc0de111e889a7041a65a6fa0219cfd
--- /dev/null
+++ b/src/context/service/database/models/enums/DeviceDriver.py
@@ -0,0 +1,29 @@
+# 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.
+
+import enum, functools
+from common.proto.context_pb2 import DeviceDriverEnum
+from ._GrpcToEnum import grpc_to_enum
+
+class ORM_DeviceDriverEnum(enum.Enum):
+    UNDEFINED             = DeviceDriverEnum.DEVICEDRIVER_UNDEFINED
+    OPENCONFIG            = DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG
+    TRANSPORT_API         = DeviceDriverEnum.DEVICEDRIVER_TRANSPORT_API
+    P4                    = DeviceDriverEnum.DEVICEDRIVER_P4
+    IETF_NETWORK_TOPOLOGY = DeviceDriverEnum.DEVICEDRIVER_IETF_NETWORK_TOPOLOGY
+    ONF_TR_352            = DeviceDriverEnum.DEVICEDRIVER_ONF_TR_352
+    XR                    = DeviceDriverEnum.DEVICEDRIVER_XR
+
+grpc_to_enum__device_driver = functools.partial(
+    grpc_to_enum, DeviceDriverEnum, ORM_DeviceDriverEnum)
diff --git a/src/context/service/database/models/enums/DeviceOperationalStatus.py b/src/context/service/database/models/enums/DeviceOperationalStatus.py
new file mode 100644
index 0000000000000000000000000000000000000000..2bfe60779101a7021a40c00c6ee91cf28e2304ca
--- /dev/null
+++ b/src/context/service/database/models/enums/DeviceOperationalStatus.py
@@ -0,0 +1,25 @@
+# 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.
+
+import enum, functools
+from common.proto.context_pb2 import DeviceOperationalStatusEnum
+from ._GrpcToEnum import grpc_to_enum
+
+class ORM_DeviceOperationalStatusEnum(enum.Enum):
+    UNDEFINED = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_UNDEFINED
+    DISABLED  = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED
+    ENABLED   = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
+
+grpc_to_enum__device_operational_status = functools.partial(
+    grpc_to_enum, DeviceOperationalStatusEnum, ORM_DeviceOperationalStatusEnum)
diff --git a/src/context/service/database/models/enums/KpiSampleType.py b/src/context/service/database/models/enums/KpiSampleType.py
new file mode 100644
index 0000000000000000000000000000000000000000..4126e90b2373a1d720b6a35e8e122be10d3d74e5
--- /dev/null
+++ b/src/context/service/database/models/enums/KpiSampleType.py
@@ -0,0 +1,27 @@
+# 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.
+
+import enum, functools
+from common.proto.kpi_sample_types_pb2 import KpiSampleType
+from ._GrpcToEnum import grpc_to_enum
+
+class ORM_KpiSampleTypeEnum(enum.Enum):
+    UNKNOWN             = KpiSampleType.KPISAMPLETYPE_UNKNOWN
+    PACKETS_TRANSMITTED = KpiSampleType.KPISAMPLETYPE_PACKETS_TRANSMITTED
+    PACKETS_RECEIVED    = KpiSampleType.KPISAMPLETYPE_PACKETS_RECEIVED
+    BYTES_TRANSMITTED   = KpiSampleType.KPISAMPLETYPE_BYTES_TRANSMITTED
+    BYTES_RECEIVED      = KpiSampleType.KPISAMPLETYPE_BYTES_RECEIVED
+
+grpc_to_enum__kpi_sample_type = functools.partial(
+    grpc_to_enum, KpiSampleType, ORM_KpiSampleTypeEnum)
diff --git a/src/context/service/database/models/enums/_GrpcToEnum.py b/src/context/service/database/models/enums/_GrpcToEnum.py
new file mode 100644
index 0000000000000000000000000000000000000000..df70399f98692adf12d1baabd6af25007b6e524f
--- /dev/null
+++ b/src/context/service/database/models/enums/_GrpcToEnum.py
@@ -0,0 +1,32 @@
+# 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.
+
+import re
+from enum import Enum
+
+# Enumeration classes are redundant with gRPC classes, but gRPC does not provide a programmatical method to retrieve
+# the values it expects from strings containing the desired value symbol or its integer value, so a kind of mapping is
+# required. Besides, ORM Models expect Enum classes in EnumeratedFields; we create specific and conveniently defined
+# Enum classes to serve both purposes.
+
+def grpc_to_enum(grpc_enum_class, orm_enum_class : Enum, grpc_enum_value):
+    grpc_enum_name = grpc_enum_class.Name(grpc_enum_value)
+    grpc_enum_prefix = orm_enum_class.__name__.upper()
+    #grpc_enum_prefix = re.sub(r'^ORM_(.+)$', r'\1', grpc_enum_prefix)
+    #grpc_enum_prefix = re.sub(r'^(.+)ENUM$', r'\1', grpc_enum_prefix)
+    #grpc_enum_prefix = grpc_enum_prefix + '_'
+    grpc_enum_prefix = re.sub(r'^ORM_(.+)ENUM$', r'\1_', grpc_enum_prefix)
+    orm_enum_name = grpc_enum_name.replace(grpc_enum_prefix, '')
+    orm_enum_value = orm_enum_class._member_map_.get(orm_enum_name)
+    return orm_enum_value
diff --git a/src/context/service/database/models/enums/__init__.py b/src/context/service/database/models/enums/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9953c820575d42fa88351cc8de022d880ba96e6a
--- /dev/null
+++ b/src/context/service/database/models/enums/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/src/context/service/database/Tools.py b/src/context/service/database/tools/FastHasher.py
similarity index 63%
rename from src/context/service/database/Tools.py
rename to src/context/service/database/tools/FastHasher.py
index 44a5aa2647c79daa0d69c9b6a2d617d9bcb2f476..6632a1c794ed3be8533486614993bbe7a88650cb 100644
--- a/src/context/service/database/Tools.py
+++ b/src/context/service/database/tools/FastHasher.py
@@ -12,31 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import hashlib, re
-from enum import Enum
-from typing import Dict, List, Tuple, Union
-import logging
-# Convenient helper function to remove dictionary items in dict/list/set comprehensions.
-LOGGER = logging.getLogger(__name__)
-
-def remove_dict_key(dictionary : Dict, key : str):
-    dictionary.pop(key, None)
-    return dictionary
-
-# Enumeration classes are redundant with gRPC classes, but gRPC does not provide a programmatical method to retrieve
-# the values it expects from strings containing the desired value symbol or its integer value, so a kind of mapping is
-# required. Besides, ORM Models expect Enum classes in EnumeratedFields; we create specific and conveniently defined
-# Enum classes to serve both purposes.
-
-def grpc_to_enum(grpc_enum_class, orm_enum_class : Enum, grpc_enum_value):
-    grpc_enum_name = grpc_enum_class.Name(grpc_enum_value)
-    grpc_enum_prefix = orm_enum_class.__name__.upper()
-    grpc_enum_prefix = re.sub(r'^ORM_(.+)$', r'\1', grpc_enum_prefix)
-    grpc_enum_prefix = re.sub(r'^(.+)ENUM$', r'\1', grpc_enum_prefix)
-    grpc_enum_prefix = grpc_enum_prefix + '_'
-    orm_enum_name = grpc_enum_name.replace(grpc_enum_prefix, '')
-    orm_enum_value = orm_enum_class._member_map_.get(orm_enum_name) # pylint: disable=protected-access
-    return orm_enum_value
+import hashlib
+from typing import List, Tuple, Union
 
 # For some models, it is convenient to produce a string hash for fast comparisons of existence or modification. Method
 # fast_hasher computes configurable length (between 1 and 64 byte) hashes and retrieves them in hex representation.
diff --git a/src/context/service/database/tools/__init__.py b/src/context/service/database/tools/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9953c820575d42fa88351cc8de022d880ba96e6a
--- /dev/null
+++ b/src/context/service/database/tools/__init__.py
@@ -0,0 +1,13 @@
+# 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.
diff --git a/src/context/tests/_test_connection.py b/src/context/tests/_test_connection.py
new file mode 100644
index 0000000000000000000000000000000000000000..b6060df68bddb610fa0540c0ddab30cbf4f005c2
--- /dev/null
+++ b/src/context/tests/_test_connection.py
@@ -0,0 +1,280 @@
+# 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.
+
+import copy, grpc, pytest
+from typing import Tuple
+from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID
+from common.proto.context_pb2 import (
+    Connection, ConnectionEvent, ConnectionId, Context, ContextEvent, ContextId, Device, DeviceEvent, DeviceId,
+    EventTypeEnum, Service, ServiceEvent, ServiceId, Topology, TopologyEvent, TopologyId)
+from context.client.ContextClient import ContextClient
+from context.client.EventsCollector import EventsCollector
+from .Objects import (
+    CONNECTION_R1_R3, CONNECTION_R1_R3_ID, CONNECTION_R1_R3_UUID, CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID,
+    DEVICE_R1_UUID, DEVICE_R2, DEVICE_R2_ID, DEVICE_R2_UUID, DEVICE_R3, DEVICE_R3_ID, DEVICE_R3_UUID, SERVICE_R1_R2,
+    SERVICE_R1_R2_ID, SERVICE_R1_R2_UUID, SERVICE_R1_R3, SERVICE_R1_R3_ID, SERVICE_R1_R3_UUID, SERVICE_R2_R3,
+    SERVICE_R2_R3_ID, SERVICE_R2_R3_UUID, TOPOLOGY, TOPOLOGY_ID)
+
+def grpc_connection(
+    context_client_grpc : ContextClient,                # pylint: disable=redefined-outer-name
+    context_db_mb : Tuple[Database, MessageBroker]):    # pylint: disable=redefined-outer-name
+    Session = context_db_mb[0]
+
+    database = Database(Session)
+
+    # ----- Clean the database -----------------------------------------------------------------------------------------
+    database.clear()
+
+    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
+    events_collector = EventsCollector(context_client_grpc)
+    events_collector.start()
+
+    # ----- Prepare dependencies for the test and capture related events -----------------------------------------------
+    response = context_client_grpc.SetContext(Context(**CONTEXT))
+    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    response = context_client_grpc.SetDevice(Device(**DEVICE_R1))
+    assert response.device_uuid.uuid == DEVICE_R1_UUID
+
+    response = context_client_grpc.SetDevice(Device(**DEVICE_R2))
+    assert response.device_uuid.uuid == DEVICE_R2_UUID
+
+    response = context_client_grpc.SetDevice(Device(**DEVICE_R3))
+    assert response.device_uuid.uuid == DEVICE_R3_UUID
+
+    response = context_client_grpc.SetService(Service(**SERVICE_R1_R2))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.service_uuid.uuid == SERVICE_R1_R2_UUID
+
+    CONTEXT_WITH_SERVICE = copy.deepcopy(CONTEXT)
+    CONTEXT_WITH_SERVICE['service_ids'].append(SERVICE_R1_R2_ID)
+    response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_SERVICE))
+    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    response = context_client_grpc.SetService(Service(**SERVICE_R2_R3))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.service_uuid.uuid == SERVICE_R2_R3_UUID
+
+    CONTEXT_WITH_SERVICE = copy.deepcopy(CONTEXT)
+    CONTEXT_WITH_SERVICE['service_ids'].append(SERVICE_R2_R3_ID)
+    response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_SERVICE))
+    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    response = context_client_grpc.SetService(Service(**SERVICE_R1_R3))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.service_uuid.uuid == SERVICE_R1_R3_UUID
+
+    CONTEXT_WITH_SERVICE = copy.deepcopy(CONTEXT)
+    CONTEXT_WITH_SERVICE['service_ids'].append(SERVICE_R1_R3_ID)
+    response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_SERVICE))
+    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    events = events_collector.get_events(block=True, count=11)
+
+    assert isinstance(events[0], ContextEvent)
+    assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert events[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    assert isinstance(events[1], TopologyEvent)
+    assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    assert isinstance(events[2], DeviceEvent)
+    assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert events[2].device_id.device_uuid.uuid == DEVICE_R1_UUID
+
+    assert isinstance(events[3], DeviceEvent)
+    assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert events[3].device_id.device_uuid.uuid == DEVICE_R2_UUID
+
+    assert isinstance(events[4], DeviceEvent)
+    assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert events[4].device_id.device_uuid.uuid == DEVICE_R3_UUID
+
+    assert isinstance(events[5], ServiceEvent)
+    assert events[5].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert events[5].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert events[5].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
+
+    assert isinstance(events[6], ContextEvent)
+    assert events[6].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    assert events[6].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    assert isinstance(events[7], ServiceEvent)
+    assert events[7].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert events[7].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert events[7].service_id.service_uuid.uuid == SERVICE_R2_R3_UUID
+
+    assert isinstance(events[8], ContextEvent)
+    assert events[8].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    assert events[8].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    assert isinstance(events[9], ServiceEvent)
+    assert events[9].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert events[9].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert events[9].service_id.service_uuid.uuid == SERVICE_R1_R3_UUID
+
+    assert isinstance(events[10], ContextEvent)
+    assert events[10].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    assert events[10].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Get when the object does not exist -------------------------------------------------------------------------
+    with pytest.raises(grpc.RpcError) as e:
+        context_client_grpc.GetConnection(ConnectionId(**CONNECTION_R1_R3_ID))
+    assert e.value.code() == grpc.StatusCode.NOT_FOUND
+    assert e.value.details() == 'Connection({:s}) not found'.format(CONNECTION_R1_R3_UUID)
+
+    # ----- List when the object does not exist ------------------------------------------------------------------------
+    response = context_client_grpc.ListConnectionIds(ServiceId(**SERVICE_R1_R3_ID))
+    assert len(response.connection_ids) == 0
+
+    response = context_client_grpc.ListConnections(ServiceId(**SERVICE_R1_R3_ID))
+    assert len(response.connections) == 0
+
+    # ----- Dump state of database before create the object ------------------------------------------------------------
+    db_entries = context_database.dump()
+    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
+    for db_entry in db_entries:
+        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
+    LOGGER.info('-----------------------------------------------------------')
+    assert len(db_entries) == 187
+
+    # ----- Create the object ------------------------------------------------------------------------------------------
+    with pytest.raises(grpc.RpcError) as e:
+        WRONG_CONNECTION = copy.deepcopy(CONNECTION_R1_R3)
+        WRONG_CONNECTION['path_hops_endpoint_ids'][0]\
+            ['topology_id']['context_id']['context_uuid']['uuid'] = 'wrong-context-uuid'
+        context_client_grpc.SetConnection(Connection(**WRONG_CONNECTION))
+    assert e.value.code() == grpc.StatusCode.NOT_FOUND
+    # TODO: should we check that all endpoints belong to same topology?
+    # TODO: should we check that endpoints form links over the topology?
+    msg = 'EndPoint({:s}/{:s}:wrong-context-uuid/{:s}) not found'.format(
+        DEVICE_R1_UUID, WRONG_CONNECTION['path_hops_endpoint_ids'][0]['endpoint_uuid']['uuid'], DEFAULT_TOPOLOGY_UUID)
+    assert e.value.details() == msg
+
+    response = context_client_grpc.SetConnection(Connection(**CONNECTION_R1_R3))
+    assert response.connection_uuid.uuid == CONNECTION_R1_R3_UUID
+
+    # ----- Check create event -----------------------------------------------------------------------------------------
+    event = events_collector.get_event(block=True)
+    assert isinstance(event, ConnectionEvent)
+    assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert event.connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID
+
+    # ----- Update the object ------------------------------------------------------------------------------------------
+    response = context_client_grpc.SetConnection(Connection(**CONNECTION_R1_R3))
+    assert response.connection_uuid.uuid == CONNECTION_R1_R3_UUID
+
+    # ----- Check update event -----------------------------------------------------------------------------------------
+    event = events_collector.get_event(block=True)
+    assert isinstance(event, ConnectionEvent)
+    assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    assert event.connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID
+
+    # ----- Dump state of database after create/update the object ------------------------------------------------------
+    db_entries = context_database.dump()
+    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
+    for db_entry in db_entries:
+        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
+    LOGGER.info('-----------------------------------------------------------')
+    assert len(db_entries) == 203
+
+    # ----- Get when the object exists ---------------------------------------------------------------------------------
+    response = context_client_grpc.GetConnection(ConnectionId(**CONNECTION_R1_R3_ID))
+    assert response.connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID
+    assert response.service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.service_id.service_uuid.uuid == SERVICE_R1_R3_UUID
+    assert len(response.path_hops_endpoint_ids) == 6
+    assert len(response.sub_service_ids) == 2
+
+    # ----- List when the object exists --------------------------------------------------------------------------------
+    response = context_client_grpc.ListConnectionIds(ServiceId(**SERVICE_R1_R3_ID))
+    assert len(response.connection_ids) == 1
+    assert response.connection_ids[0].connection_uuid.uuid == CONNECTION_R1_R3_UUID
+
+    response = context_client_grpc.ListConnections(ServiceId(**SERVICE_R1_R3_ID))
+    assert len(response.connections) == 1
+    assert response.connections[0].connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID
+    assert len(response.connections[0].path_hops_endpoint_ids) == 6
+    assert len(response.connections[0].sub_service_ids) == 2
+
+    # ----- Remove the object ------------------------------------------------------------------------------------------
+    context_client_grpc.RemoveConnection(ConnectionId(**CONNECTION_R1_R3_ID))
+    context_client_grpc.RemoveService(ServiceId(**SERVICE_R1_R3_ID))
+    context_client_grpc.RemoveService(ServiceId(**SERVICE_R2_R3_ID))
+    context_client_grpc.RemoveService(ServiceId(**SERVICE_R1_R2_ID))
+    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R1_ID))
+    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R2_ID))
+    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R3_ID))
+    context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID))
+    context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID))
+
+    # ----- Check remove event -----------------------------------------------------------------------------------------
+    events = events_collector.get_events(block=True, count=9)
+
+    assert isinstance(events[0], ConnectionEvent)
+    assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[0].connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID
+
+    assert isinstance(events[1], ServiceEvent)
+    assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[1].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert events[1].service_id.service_uuid.uuid == SERVICE_R1_R3_UUID
+
+    assert isinstance(events[2], ServiceEvent)
+    assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[2].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert events[2].service_id.service_uuid.uuid == SERVICE_R2_R3_UUID
+
+    assert isinstance(events[3], ServiceEvent)
+    assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[3].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert events[3].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
+
+    assert isinstance(events[4], DeviceEvent)
+    assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[4].device_id.device_uuid.uuid == DEVICE_R1_UUID
+
+    assert isinstance(events[5], DeviceEvent)
+    assert events[5].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[5].device_id.device_uuid.uuid == DEVICE_R2_UUID
+
+    assert isinstance(events[6], DeviceEvent)
+    assert events[6].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[6].device_id.device_uuid.uuid == DEVICE_R3_UUID
+
+    assert isinstance(events[7], TopologyEvent)
+    assert events[7].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[7].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert events[7].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    assert isinstance(events[8], ContextEvent)
+    assert events[8].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[8].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
+    events_collector.stop()
+
+    # ----- Dump state of database after remove the object -------------------------------------------------------------
+    db_entries = context_database.dump()
+    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
+    for db_entry in db_entries:
+        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
+    LOGGER.info('-----------------------------------------------------------')
+    assert len(db_entries) == 0
diff --git a/src/context/tests/_test_context.py b/src/context/tests/_test_context.py
new file mode 100644
index 0000000000000000000000000000000000000000..ef67d39d79a8fb175ba7da8ca093f39262dd2390
--- /dev/null
+++ b/src/context/tests/_test_context.py
@@ -0,0 +1,160 @@
+# 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.
+
+import copy, grpc, pytest, uuid
+from common.Constants import DEFAULT_CONTEXT_UUID
+from common.proto.context_pb2 import Context, ContextId, Empty
+from common.tools.object_factory.Context import json_context_id
+from common.tools.object_factory.Service import json_service_id
+from common.tools.object_factory.Slice import json_slice_id
+from common.tools.object_factory.Topology import json_topology_id
+from context.client.ContextClient import ContextClient
+#from context.client.EventsCollector import EventsCollector
+from .Objects import CONTEXT, CONTEXT_ID
+
+def grpc_context(context_client_grpc : ContextClient) -> None:
+
+    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
+    #events_collector = EventsCollector(
+    #    context_client_grpc, log_events_received=True,
+    #    activate_context_collector = True, activate_topology_collector = False, activate_device_collector = False,
+    #    activate_link_collector = False, activate_service_collector = False, activate_slice_collector = False,
+    #    activate_connection_collector = False)
+    #events_collector.start()
+
+    # ----- Get when the object does not exist -------------------------------------------------------------------------
+    with pytest.raises(grpc.RpcError) as e:
+        context_client_grpc.GetContext(ContextId(**CONTEXT_ID))
+    assert e.value.code() == grpc.StatusCode.NOT_FOUND
+    assert e.value.details() == 'Context({:s}) not found'.format(DEFAULT_CONTEXT_UUID)
+
+    # ----- List when the object does not exist ------------------------------------------------------------------------
+    response = context_client_grpc.ListContextIds(Empty())
+    assert len(response.context_ids) == 0
+
+    response = context_client_grpc.ListContexts(Empty())
+    assert len(response.contexts) == 0
+
+    # ----- Create the object ------------------------------------------------------------------------------------------
+    response = context_client_grpc.SetContext(Context(**CONTEXT))
+    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    wrong_context_uuid = str(uuid.uuid4())
+    wrong_context_id = json_context_id(wrong_context_uuid)
+    with pytest.raises(grpc.RpcError) as e:
+        WRONG_CONTEXT = copy.deepcopy(CONTEXT)
+        WRONG_CONTEXT['topology_ids'].append(json_topology_id(str(uuid.uuid4()), context_id=wrong_context_id))
+        context_client_grpc.SetContext(Context(**WRONG_CONTEXT))
+    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
+    msg = 'request.topology_ids[0].context_id.context_uuid.uuid({}) is invalid; '\
+          'should be == request.context_id.context_uuid.uuid({})'.format(wrong_context_uuid, DEFAULT_CONTEXT_UUID)
+    assert e.value.details() == msg
+
+    with pytest.raises(grpc.RpcError) as e:
+        WRONG_CONTEXT = copy.deepcopy(CONTEXT)
+        WRONG_CONTEXT['service_ids'].append(json_service_id(str(uuid.uuid4()), context_id=wrong_context_id))
+        context_client_grpc.SetContext(Context(**WRONG_CONTEXT))
+    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
+    msg = 'request.service_ids[0].context_id.context_uuid.uuid({}) is invalid; '\
+          'should be == request.context_id.context_uuid.uuid({})'.format(wrong_context_uuid, DEFAULT_CONTEXT_UUID)
+    assert e.value.details() == msg
+
+    with pytest.raises(grpc.RpcError) as e:
+        WRONG_CONTEXT = copy.deepcopy(CONTEXT)
+        WRONG_CONTEXT['slice_ids'].append(json_slice_id(str(uuid.uuid4()), context_id=wrong_context_id))
+        context_client_grpc.SetContext(Context(**WRONG_CONTEXT))
+    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
+    msg = 'request.slice_ids[0].context_id.context_uuid.uuid({}) is invalid; '\
+          'should be == request.context_id.context_uuid.uuid({})'.format(wrong_context_uuid, DEFAULT_CONTEXT_UUID)
+    assert e.value.details() == msg
+
+    # ----- Check create event -----------------------------------------------------------------------------------------
+    #event = events_collector.get_event(block=True, timeout=10.0)
+    #assert isinstance(event, ContextEvent)
+    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    #assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Get when the object exists ---------------------------------------------------------------------------------
+    response = context_client_grpc.GetContext(ContextId(**CONTEXT_ID))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.name == ''
+    assert len(response.topology_ids) == 0
+    assert len(response.service_ids) == 0
+    assert len(response.slice_ids) == 0
+
+    # ----- List when the object exists --------------------------------------------------------------------------------
+    response = context_client_grpc.ListContextIds(Empty())
+    assert len(response.context_ids) == 1
+    assert response.context_ids[0].context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    response = context_client_grpc.ListContexts(Empty())
+    assert len(response.contexts) == 1
+    assert response.contexts[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.contexts[0].name == ''
+    assert len(response.contexts[0].topology_ids) == 0
+    assert len(response.contexts[0].service_ids) == 0
+    assert len(response.contexts[0].slice_ids) == 0
+
+    # ----- Update the object ------------------------------------------------------------------------------------------
+    new_context_name = 'new'
+    CONTEXT_WITH_NAME = copy.deepcopy(CONTEXT)
+    CONTEXT_WITH_NAME['name'] = new_context_name
+    response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_NAME))
+    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Check update event -----------------------------------------------------------------------------------------
+    #event = events_collector.get_event(block=True, timeout=10.0)
+    #assert isinstance(event, ContextEvent)
+    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    #assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Get when the object is modified ----------------------------------------------------------------------------
+    response = context_client_grpc.GetContext(ContextId(**CONTEXT_ID))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.name == new_context_name
+    assert len(response.topology_ids) == 0
+    assert len(response.service_ids) == 0
+    assert len(response.slice_ids) == 0
+
+    # ----- List when the object is modified ---------------------------------------------------------------------------
+    response = context_client_grpc.ListContextIds(Empty())
+    assert len(response.context_ids) == 1
+    assert response.context_ids[0].context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    response = context_client_grpc.ListContexts(Empty())
+    assert len(response.contexts) == 1
+    assert response.contexts[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.contexts[0].name == new_context_name
+    assert len(response.contexts[0].topology_ids) == 0
+    assert len(response.contexts[0].service_ids) == 0
+    assert len(response.contexts[0].slice_ids) == 0
+
+    # ----- Remove the object ------------------------------------------------------------------------------------------
+    context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID))
+
+    # ----- Check remove event -----------------------------------------------------------------------------------------
+    #event = events_collector.get_event(block=True, timeout=10.0)
+    #assert isinstance(event, ContextEvent)
+    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    #assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- List after deleting the object -----------------------------------------------------------------------------
+    response = context_client_grpc.ListContextIds(Empty())
+    assert len(response.context_ids) == 0
+
+    response = context_client_grpc.ListContexts(Empty())
+    assert len(response.contexts) == 0
+
+    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
+    #events_collector.stop()
diff --git a/src/context/tests/_test_device.py b/src/context/tests/_test_device.py
new file mode 100644
index 0000000000000000000000000000000000000000..20760a9612cf57739dda44736e184bccebbc776f
--- /dev/null
+++ b/src/context/tests/_test_device.py
@@ -0,0 +1,199 @@
+# 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.
+
+import copy, grpc, pytest
+from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID
+from common.proto.context_pb2 import (
+    Context, ContextId, Device, DeviceDriverEnum, DeviceId, DeviceOperationalStatusEnum, Empty, Topology, TopologyId)
+from context.client.ContextClient import ContextClient
+#from context.client.EventsCollector import EventsCollector
+from .Objects import CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID, DEVICE_R1_UUID, TOPOLOGY, TOPOLOGY_ID
+
+def grpc_device(context_client_grpc : ContextClient) -> None:
+
+    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
+    #events_collector = EventsCollector(
+    #    context_client_grpc, log_events_received=True,
+    #    activate_context_collector = False, activate_topology_collector = False, activate_device_collector = True,
+    #    activate_link_collector = False, activate_service_collector = False, activate_slice_collector = False,
+    #    activate_connection_collector = False)
+    #events_collector.start()
+
+    # ----- Prepare dependencies for the test and capture related events -----------------------------------------------
+    response = context_client_grpc.SetContext(Context(**CONTEXT))
+    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    #events = events_collector.get_events(block=True, count=2)
+    #assert isinstance(events[0], ContextEvent)
+    #assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    #assert events[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    #assert isinstance(events[1], TopologyEvent)
+    #assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    #assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    #assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    # ----- Get when the object does not exist -------------------------------------------------------------------------
+    with pytest.raises(grpc.RpcError) as e:
+        context_client_grpc.GetDevice(DeviceId(**DEVICE_R1_ID))
+    assert e.value.code() == grpc.StatusCode.NOT_FOUND
+    assert e.value.details() == 'Device({:s}) not found'.format(DEVICE_R1_UUID)
+
+    # ----- List when the object does not exist ------------------------------------------------------------------------
+    response = context_client_grpc.ListDeviceIds(Empty())
+    assert len(response.device_ids) == 0
+
+    response = context_client_grpc.ListDevices(Empty())
+    assert len(response.devices) == 0
+
+    # ----- Create the object ------------------------------------------------------------------------------------------
+    with pytest.raises(grpc.RpcError) as e:
+        WRONG_DEVICE = copy.deepcopy(DEVICE_R1)
+        WRONG_DEVICE_UUID = '3f03c76d-31fb-47f5-9c1d-bc6b6bfa2d08'
+        WRONG_DEVICE['device_endpoints'][0]['endpoint_id']['device_id']['device_uuid']['uuid'] = WRONG_DEVICE_UUID
+        context_client_grpc.SetDevice(Device(**WRONG_DEVICE))
+    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
+    msg = 'request.device_endpoints[0].device_id.device_uuid.uuid({}) is invalid; '\
+          'should be == request.device_id.device_uuid.uuid({})'.format(WRONG_DEVICE_UUID, DEVICE_R1_UUID)
+    assert e.value.details() == msg
+
+    response = context_client_grpc.SetDevice(Device(**DEVICE_R1))
+    assert response.device_uuid.uuid == DEVICE_R1_UUID
+
+    # ----- Check create event -----------------------------------------------------------------------------------------
+    # event = events_collector.get_event(block=True)
+    # assert isinstance(event, DeviceEvent)
+    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    # assert event.device_id.device_uuid.uuid == DEVICE_R1_UUID
+
+    # ----- Get when the object exists ---------------------------------------------------------------------------------
+    response = context_client_grpc.GetDevice(DeviceId(**DEVICE_R1_ID))
+    assert response.device_id.device_uuid.uuid == DEVICE_R1_UUID
+    assert response.name == ''
+    assert response.device_type == 'packet-router'
+    assert len(response.device_config.config_rules) == 3
+    assert response.device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED
+    assert len(response.device_drivers) == 1
+    assert DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG in response.device_drivers
+    assert len(response.device_endpoints) == 3
+
+    # ----- List when the object exists --------------------------------------------------------------------------------
+    response = context_client_grpc.ListDeviceIds(Empty())
+    assert len(response.device_ids) == 1
+    assert response.device_ids[0].device_uuid.uuid == DEVICE_R1_UUID
+
+    response = context_client_grpc.ListDevices(Empty())
+    assert len(response.devices) == 1
+    assert response.devices[0].device_id.device_uuid.uuid == DEVICE_R1_UUID
+    assert response.devices[0].name == ''
+    assert response.devices[0].device_type == 'packet-router'
+    assert len(response.devices[0].device_config.config_rules) == 3
+    assert response.devices[0].device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED
+    assert len(response.devices[0].device_drivers) == 1
+    assert DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG in response.devices[0].device_drivers
+    assert len(response.devices[0].device_endpoints) == 3
+
+    # ----- Update the object ------------------------------------------------------------------------------------------
+    new_device_name = 'r1'
+    new_device_driver = DeviceDriverEnum.DEVICEDRIVER_UNDEFINED
+    DEVICE_UPDATED = copy.deepcopy(DEVICE_R1)
+    DEVICE_UPDATED['name'] = new_device_name
+    DEVICE_UPDATED['device_operational_status'] = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
+    DEVICE_UPDATED['device_drivers'].append(new_device_driver)
+    response = context_client_grpc.SetDevice(Device(**DEVICE_UPDATED))
+    assert response.device_uuid.uuid == DEVICE_R1_UUID
+
+    # ----- Check update event -----------------------------------------------------------------------------------------
+    # event = events_collector.get_event(block=True)
+    # assert isinstance(event, DeviceEvent)
+    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    # assert event.device_id.device_uuid.uuid == DEVICE_R1_UUID
+
+    # ----- Get when the object is modified ----------------------------------------------------------------------------
+    response = context_client_grpc.GetDevice(DeviceId(**DEVICE_R1_ID))
+    assert response.device_id.device_uuid.uuid == DEVICE_R1_UUID
+    assert response.name == new_device_name
+    assert response.device_type == 'packet-router'
+    assert len(response.device_config.config_rules) == 3
+    assert response.device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
+    assert len(response.device_drivers) == 2
+    assert DeviceDriverEnum.DEVICEDRIVER_UNDEFINED in response.device_drivers
+    assert DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG in response.device_drivers
+    assert len(response.device_endpoints) == 3
+
+    # ----- List when the object is modified ---------------------------------------------------------------------------
+    response = context_client_grpc.ListDeviceIds(Empty())
+    assert len(response.device_ids) == 1
+    assert response.device_ids[0].device_uuid.uuid == DEVICE_R1_UUID
+
+    response = context_client_grpc.ListDevices(Empty())
+    assert len(response.devices) == 1
+    assert response.devices[0].device_id.device_uuid.uuid == DEVICE_R1_UUID
+    assert response.devices[0].name == new_device_name
+    assert response.devices[0].device_type == 'packet-router'
+    assert len(response.devices[0].device_config.config_rules) == 3
+    assert response.devices[0].device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
+    assert len(response.devices[0].device_drivers) == 2
+    assert DeviceDriverEnum.DEVICEDRIVER_UNDEFINED in response.devices[0].device_drivers
+    assert DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG in response.devices[0].device_drivers
+    assert len(response.devices[0].device_endpoints) == 3
+
+    # ----- Create object relation -------------------------------------------------------------------------------------
+    TOPOLOGY_WITH_DEVICE = copy.deepcopy(TOPOLOGY)
+    TOPOLOGY_WITH_DEVICE['device_ids'].append(DEVICE_R1_ID)
+    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY_WITH_DEVICE))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    # ----- Check update event -----------------------------------------------------------------------------------------
+    # event = events_collector.get_event(block=True)
+    # assert isinstance(event, TopologyEvent)
+    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    # assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    # assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    # ----- Check relation was created ---------------------------------------------------------------------------------
+    response = context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID))
+    assert response.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+    assert len(response.device_ids) == 1
+    assert response.device_ids[0].device_uuid.uuid == DEVICE_R1_UUID
+    assert len(response.link_ids) == 0
+
+    # ----- Remove the object ------------------------------------------------------------------------------------------
+    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R1_ID))
+    context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID))
+    context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID))
+
+    # ----- Check remove event -----------------------------------------------------------------------------------------
+    # events = events_collector.get_events(block=True, count=3)
+
+    # assert isinstance(events[0], DeviceEvent)
+    # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    # assert events[0].device_id.device_uuid.uuid == DEVICE_R1_UUID
+
+    # assert isinstance(events[1], TopologyEvent)
+    # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    # assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    # assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    # assert isinstance(events[2], ContextEvent)
+    # assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    # assert events[2].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
+    #events_collector.stop()
diff --git a/src/context/tests/_test_link.py b/src/context/tests/_test_link.py
new file mode 100644
index 0000000000000000000000000000000000000000..d493f23d7d64e29ae4fbfc987bd09fb4d54c3aac
--- /dev/null
+++ b/src/context/tests/_test_link.py
@@ -0,0 +1,189 @@
+# 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.
+
+import copy, grpc, pytest
+from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID
+from common.proto.context_pb2 import Context, ContextId, Device, DeviceId, Empty, Link, LinkId, Topology, TopologyId
+from context.client.ContextClient import ContextClient
+#from context.client.EventsCollector import EventsCollector
+from .Objects import (
+    CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID, DEVICE_R1_UUID, DEVICE_R2, DEVICE_R2_ID, DEVICE_R2_UUID, LINK_R1_R2,
+    LINK_R1_R2_ID, LINK_R1_R2_UUID, TOPOLOGY, TOPOLOGY_ID)
+
+def grpc_link(context_client_grpc: ContextClient) -> None:
+
+    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
+    #events_collector = EventsCollector(
+    #    context_client_grpc, log_events_received=True,
+    #    activate_context_collector = False, activate_topology_collector = False, activate_device_collector = False,
+    #    activate_link_collector = True, activate_service_collector = False, activate_slice_collector = False,
+    #    activate_connection_collector = False)
+    #events_collector.start()
+
+    # ----- Prepare dependencies for the test and capture related events -----------------------------------------------
+    response = context_client_grpc.SetContext(Context(**CONTEXT))
+    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    response = context_client_grpc.SetDevice(Device(**DEVICE_R1))
+    assert response.device_uuid.uuid == DEVICE_R1_UUID
+
+    response = context_client_grpc.SetDevice(Device(**DEVICE_R2))
+    assert response.device_uuid.uuid == DEVICE_R2_UUID
+
+    # events = events_collector.get_events(block=True, count=4)
+    # assert isinstance(events[0], ContextEvent)
+    # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    # assert events[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    # assert isinstance(events[1], TopologyEvent)
+    # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    # assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    # assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+    # assert isinstance(events[2], DeviceEvent)
+    # assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    # assert events[2].device_id.device_uuid.uuid == DEVICE_R1_UUID
+    # assert isinstance(events[3], DeviceEvent)
+    # assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    # assert events[3].device_id.device_uuid.uuid == DEVICE_R2_UUID
+
+    # ----- Get when the object does not exist -------------------------------------------------------------------------
+    with pytest.raises(grpc.RpcError) as e:
+        context_client_grpc.GetLink(LinkId(**LINK_R1_R2_ID))
+    assert e.value.code() == grpc.StatusCode.NOT_FOUND
+    assert e.value.details() == 'Link({:s}) not found'.format(LINK_R1_R2_UUID)
+
+    # ----- List when the object does not exist ------------------------------------------------------------------------
+    response = context_client_grpc.ListLinkIds(Empty())
+    assert len(response.link_ids) == 0
+
+    response = context_client_grpc.ListLinks(Empty())
+    assert len(response.links) == 0
+
+    # ----- Create the object ------------------------------------------------------------------------------------------
+    response = context_client_grpc.SetLink(Link(**LINK_R1_R2))
+    assert response.link_uuid.uuid == LINK_R1_R2_UUID
+
+    # ----- Check create event -----------------------------------------------------------------------------------------
+    # event = events_collector.get_event(block=True)
+    # assert isinstance(event, LinkEvent)
+    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    # assert event.link_id.link_uuid.uuid == LINK_R1_R2_UUID
+
+    # ----- Get when the object exists ---------------------------------------------------------------------------------
+    response = context_client_grpc.GetLink(LinkId(**LINK_R1_R2_ID))
+    assert response.link_id.link_uuid.uuid == LINK_R1_R2_UUID
+    assert response.name == ''
+    assert len(response.link_endpoint_ids) == 2
+
+    # ----- List when the object exists --------------------------------------------------------------------------------
+    response = context_client_grpc.ListLinkIds(Empty())
+    assert len(response.link_ids) == 1
+    assert response.link_ids[0].link_uuid.uuid == LINK_R1_R2_UUID
+
+    response = context_client_grpc.ListLinks(Empty())
+    assert len(response.links) == 1
+    assert response.links[0].link_id.link_uuid.uuid == LINK_R1_R2_UUID
+    assert response.links[0].name == ''
+    assert len(response.links[0].link_endpoint_ids) == 2
+
+    # ----- Update the object ------------------------------------------------------------------------------------------
+    new_link_name = 'l1'
+    LINK_UPDATED = copy.deepcopy(LINK_R1_R2)
+    LINK_UPDATED['name'] = new_link_name
+    response = context_client_grpc.SetLink(Link(**LINK_UPDATED))
+    assert response.link_uuid.uuid == LINK_R1_R2_UUID
+
+    # ----- Check update event -----------------------------------------------------------------------------------------
+    # event = events_collector.get_event(block=True)
+    # assert isinstance(event, LinkEvent)
+    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    # assert event.link_id.link_uuid.uuid == LINK_R1_R2_UUID
+
+    # ----- Get when the object is modified ----------------------------------------------------------------------------
+    response = context_client_grpc.GetLink(LinkId(**LINK_R1_R2_ID))
+    assert response.link_id.link_uuid.uuid == LINK_R1_R2_UUID
+    assert response.name == new_link_name
+    assert len(response.link_endpoint_ids) == 2
+
+    # ----- List when the object is modified ---------------------------------------------------------------------------
+    response = context_client_grpc.ListLinkIds(Empty())
+    assert len(response.link_ids) == 1
+    assert response.link_ids[0].link_uuid.uuid == LINK_R1_R2_UUID
+
+    response = context_client_grpc.ListLinks(Empty())
+    assert len(response.links) == 1
+    assert response.links[0].link_id.link_uuid.uuid == LINK_R1_R2_UUID
+    assert response.links[0].name == new_link_name
+    assert len(response.links[0].link_endpoint_ids) == 2
+
+    # ----- Create object relation -------------------------------------------------------------------------------------
+    TOPOLOGY_WITH_LINK = copy.deepcopy(TOPOLOGY)
+    TOPOLOGY_WITH_LINK['link_ids'].append(LINK_R1_R2_ID)
+    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY_WITH_LINK))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    # ----- Check update event -----------------------------------------------------------------------------------------
+    # event = events_collector.get_event(block=True)
+    # assert isinstance(event, TopologyEvent)
+    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    # assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    # assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    # ----- Check relation was created ---------------------------------------------------------------------------------
+    response = context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID))
+    assert response.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+    assert len(response.device_ids) == 2
+    assert response.device_ids[0].device_uuid.uuid in {DEVICE_R1_UUID, DEVICE_R2_UUID}
+    assert response.device_ids[1].device_uuid.uuid in {DEVICE_R1_UUID, DEVICE_R2_UUID}
+    assert len(response.link_ids) == 1
+    assert response.link_ids[0].link_uuid.uuid == LINK_R1_R2_UUID
+
+    # ----- Remove the object ------------------------------------------------------------------------------------------
+    #context_client_grpc.RemoveLink(LinkId(**LINK_R1_R2_ID))
+    #context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R1_ID))
+    #context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R2_ID))
+    #context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID))
+    #context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID))
+
+    # ----- Check remove event -----------------------------------------------------------------------------------------
+    # events = events_collector.get_events(block=True, count=5)
+    #
+    # assert isinstance(events[0], LinkEvent)
+    # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    # assert events[0].link_id.link_uuid.uuid == LINK_R1_R2_UUID
+    #
+    # assert isinstance(events[1], DeviceEvent)
+    # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    # assert events[1].device_id.device_uuid.uuid == DEVICE_R1_UUID
+    #
+    # assert isinstance(events[2], DeviceEvent)
+    # assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    # assert events[2].device_id.device_uuid.uuid == DEVICE_R2_UUID
+    #
+    # assert isinstance(events[3], TopologyEvent)
+    # assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    # assert events[3].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    # assert events[3].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+    #
+    # assert isinstance(events[4], ContextEvent)
+    # assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    # assert events[4].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
+    #events_collector.stop()
diff --git a/src/context/tests/_test_policy.py b/src/context/tests/_test_policy.py
new file mode 100644
index 0000000000000000000000000000000000000000..e416575f774bc6fdc3bcc3c7c5e003dba994e639
--- /dev/null
+++ b/src/context/tests/_test_policy.py
@@ -0,0 +1,114 @@
+# 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.
+
+import grpc, pytest
+from typing import Tuple
+from common.proto.context_pb2 import Empty
+from common.proto.policy_pb2 import PolicyRuleId, PolicyRule
+from context.client.ContextClient import ContextClient
+#from context.client.EventsCollector import EventsCollector
+from .Objects import POLICY_RULE, POLICY_RULE_ID, POLICY_RULE_UUID
+
+def grpc_policy(
+    context_client_grpc : ContextClient,                # pylint: disable=redefined-outer-name
+    context_db_mb : Tuple[Database, MessageBroker]):    # pylint: disable=redefined-outer-name
+    context_database = context_db_mb[0]
+
+    # ----- Clean the database -----------------------------------------------------------------------------------------
+    context_database.clear_all()
+
+    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
+    #events_collector = EventsCollector(context_client_grpc)
+    #events_collector.start()
+
+    # ----- Get when the object does not exist -------------------------------------------------------------------------
+    POLICY_ID = 'no-uuid'
+    DEFAULT_POLICY_ID = {'uuid': {'uuid': POLICY_ID}}
+
+    with pytest.raises(grpc.RpcError) as e:
+        context_client_grpc.GetPolicyRule(PolicyRuleId(**DEFAULT_POLICY_ID))
+
+    assert e.value.code() == grpc.StatusCode.NOT_FOUND
+    assert e.value.details() == 'PolicyRule({:s}) not found'.format(POLICY_ID)
+
+    # ----- List when the object does not exist ------------------------------------------------------------------------
+    response = context_client_grpc.ListPolicyRuleIds(Empty())
+    assert len(response.policyRuleIdList) == 0
+
+    response = context_client_grpc.ListPolicyRules(Empty())
+    assert len(response.policyRules) == 0
+
+    # ----- Dump state of database before create the object ------------------------------------------------------------
+    db_entries = context_database.dump()
+    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
+    for db_entry in db_entries:
+        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry))  # pragma: no cover
+    LOGGER.info('-----------------------------------------------------------')
+    assert len(db_entries) == 0
+
+    # ----- Create the object ------------------------------------------------------------------------------------------
+    response = context_client_grpc.SetPolicyRule(PolicyRule(**POLICY_RULE))
+    assert response.uuid.uuid == POLICY_RULE_UUID
+
+    # ----- Check create event -----------------------------------------------------------------------------------------
+    # events = events_collector.get_events(block=True, count=1)
+    # assert isinstance(events[0], PolicyEvent)
+    # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    # assert events[0].policy_id.uuid.uuid == POLICY_RULE_UUID
+
+    # ----- Update the object ------------------------------------------------------------------------------------------
+    response = context_client_grpc.SetPolicyRule(PolicyRule(**POLICY_RULE))
+    assert response.uuid.uuid == POLICY_RULE_UUID
+
+    # ----- Dump state of database after create/update the object ------------------------------------------------------
+    db_entries = context_database.dump()
+    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
+    for db_entry in db_entries:
+        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
+    LOGGER.info('-----------------------------------------------------------')
+    assert len(db_entries) == 2
+
+    # ----- Get when the object exists ---------------------------------------------------------------------------------
+    response = context_client_grpc.GetPolicyRule(PolicyRuleId(**POLICY_RULE_ID))
+    assert response.device.policyRuleBasic.policyRuleId.uuid.uuid == POLICY_RULE_UUID
+
+    # ----- List when the object exists --------------------------------------------------------------------------------
+    response = context_client_grpc.ListPolicyRuleIds(Empty())
+    assert len(response.policyRuleIdList) == 1
+    assert response.policyRuleIdList[0].uuid.uuid == POLICY_RULE_UUID
+
+    response = context_client_grpc.ListPolicyRules(Empty())
+    assert len(response.policyRules) == 1
+
+    # ----- Remove the object ------------------------------------------------------------------------------------------
+    context_client_grpc.RemovePolicyRule(PolicyRuleId(**POLICY_RULE_ID))
+
+    # ----- Check remove event -----------------------------------------------------------------------------------------
+    # events = events_collector.get_events(block=True, count=2)
+
+    # assert isinstance(events[0], PolicyEvent)
+    # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    # assert events[0].policy_id.uuid.uuid == POLICY_RULE_UUID
+
+
+    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
+    # events_collector.stop()
+
+    # ----- Dump state of database after remove the object -------------------------------------------------------------
+    db_entries = context_database.dump()
+    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
+    for db_entry in db_entries:
+        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
+    LOGGER.info('-----------------------------------------------------------')
+    assert len(db_entries) == 0
diff --git a/src/context/tests/_test_service.py b/src/context/tests/_test_service.py
new file mode 100644
index 0000000000000000000000000000000000000000..88ece2ba90be93e133ed6699024e399a92045a7b
--- /dev/null
+++ b/src/context/tests/_test_service.py
@@ -0,0 +1,214 @@
+# 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.
+
+import copy, grpc, pytest
+from typing import Tuple
+from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID
+from common.proto.context_pb2 import (
+    Context, ContextEvent, ContextId, Device, DeviceEvent, DeviceId, EventTypeEnum, Service, ServiceEvent, ServiceId,
+    ServiceStatusEnum, ServiceTypeEnum, Topology, TopologyEvent, TopologyId)
+from context.client.ContextClient import ContextClient
+from context.client.EventsCollector import EventsCollector
+from .Objects import (
+    CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID, DEVICE_R1_UUID, DEVICE_R2, DEVICE_R2_ID, DEVICE_R2_UUID,
+    SERVICE_R1_R2, SERVICE_R1_R2_ID, SERVICE_R1_R2_UUID, TOPOLOGY, TOPOLOGY_ID)
+
+def grpc_service(
+    context_client_grpc : ContextClient,                # pylint: disable=redefined-outer-name
+    context_db_mb : Tuple[Database, MessageBroker]):    # pylint: disable=redefined-outer-name
+    Session = context_db_mb[0]
+    # ----- Clean the database -----------------------------------------------------------------------------------------
+    database = Database(Session)
+    database.clear()
+
+    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
+    events_collector = EventsCollector(context_client_grpc)
+    events_collector.start()
+
+    # ----- Prepare dependencies for the test and capture related events -----------------------------------------------
+    response = context_client_grpc.SetContext(Context(**CONTEXT))
+    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    response = context_client_grpc.SetDevice(Device(**DEVICE_R1))
+    assert response.device_uuid.uuid == DEVICE_R1_UUID
+
+    response = context_client_grpc.SetDevice(Device(**DEVICE_R2))
+    assert response.device_uuid.uuid == DEVICE_R2_UUID
+    # events = events_collector.get_events(block=True, count=4)
+    #
+    # assert isinstance(events[0], ContextEvent)
+    # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    # assert events[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    #
+    # assert isinstance(events[1], TopologyEvent)
+    # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    # assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    # assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+    #
+    # assert isinstance(events[2], DeviceEvent)
+    # assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    # assert events[2].device_id.device_uuid.uuid == DEVICE_R1_UUID
+    #
+    # assert isinstance(events[3], DeviceEvent)
+    # assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    # assert events[3].device_id.device_uuid.uuid == DEVICE_R2_UUID
+    LOGGER.info('----------------')
+
+    # ----- Get when the object does not exist -------------------------------------------------------------------------
+    with pytest.raises(grpc.RpcError) as e:
+        context_client_grpc.GetService(ServiceId(**SERVICE_R1_R2_ID))
+    assert e.value.code() == grpc.StatusCode.NOT_FOUND
+    assert e.value.details() == 'Service({:s}) not found'.format(SERVICE_R1_R2_UUID)
+    LOGGER.info('----------------')
+
+    # ----- List when the object does not exist ------------------------------------------------------------------------
+    response = context_client_grpc.ListServiceIds(ContextId(**CONTEXT_ID))
+    assert len(response.service_ids) == 0
+    LOGGER.info('----------------')
+
+    response = context_client_grpc.ListServices(ContextId(**CONTEXT_ID))
+    assert len(response.services) == 0
+    LOGGER.info('----------------')
+
+    # ----- Dump state of database before create the object ------------------------------------------------------------
+    db_entries = database.dump_all()
+    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
+    for db_entry in db_entries:
+        LOGGER.info(db_entry)
+    LOGGER.info('-----------------------------------------------------------')
+    assert len(db_entries) == 80
+
+    # ----- Create the object ------------------------------------------------------------------------------------------
+    with pytest.raises(grpc.RpcError) as e:
+        WRONG_SERVICE = copy.deepcopy(SERVICE_R1_R2)
+        WRONG_SERVICE['service_endpoint_ids'][0]\
+            ['topology_id']['context_id']['context_uuid']['uuid'] = 'ca1ea172-728f-441d-972c-feeae8c9bffc'
+        context_client_grpc.SetService(Service(**WRONG_SERVICE))
+    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
+    msg = 'request.service_endpoint_ids[0].topology_id.context_id.context_uuid.uuid(ca1ea172-728f-441d-972c-feeae8c9bffc) is invalid; '\
+          'should be == request.service_id.context_id.context_uuid.uuid({:s})'.format(DEFAULT_CONTEXT_UUID)
+    assert e.value.details() == msg
+
+    response = context_client_grpc.SetService(Service(**SERVICE_R1_R2))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.service_uuid.uuid == SERVICE_R1_R2_UUID
+
+    CONTEXT_WITH_SERVICE = copy.deepcopy(CONTEXT)
+    CONTEXT_WITH_SERVICE['service_ids'].append(SERVICE_R1_R2_ID)
+    response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_SERVICE))
+    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Check create event -----------------------------------------------------------------------------------------
+    events = events_collector.get_events(block=True, count=2)
+
+    assert isinstance(events[0], ServiceEvent)
+    assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    assert events[0].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert events[0].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
+
+    assert isinstance(events[1], ContextEvent)
+    assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    assert events[1].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Update the object ------------------------------------------------------------------------------------------
+    response = context_client_grpc.SetService(Service(**SERVICE_R1_R2))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.service_uuid.uuid == SERVICE_R1_R2_UUID
+
+    # ----- Check update event -----------------------------------------------------------------------------------------
+    event = events_collector.get_event(block=True)
+    assert isinstance(event, ServiceEvent)
+    assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    assert event.service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert event.service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
+
+    # ----- Dump state of database after create/update the object ------------------------------------------------------
+    db_entries = context_database.dump()
+    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
+    for db_entry in db_entries:
+        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
+    LOGGER.info('-----------------------------------------------------------')
+    assert len(db_entries) == 108
+
+    # ----- Get when the object exists ---------------------------------------------------------------------------------
+    response = context_client_grpc.GetService(ServiceId(**SERVICE_R1_R2_ID))
+    assert response.service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
+    assert response.service_type == ServiceTypeEnum.SERVICETYPE_L3NM
+    assert len(response.service_endpoint_ids) == 2
+    assert len(response.service_constraints) == 2
+    assert response.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_PLANNED
+    assert len(response.service_config.config_rules) == 3
+
+    # ----- List when the object exists --------------------------------------------------------------------------------
+    response = context_client_grpc.ListServiceIds(ContextId(**CONTEXT_ID))
+    assert len(response.service_ids) == 1
+    assert response.service_ids[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.service_ids[0].service_uuid.uuid == SERVICE_R1_R2_UUID
+
+    response = context_client_grpc.ListServices(ContextId(**CONTEXT_ID))
+    assert len(response.services) == 1
+    assert response.services[0].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.services[0].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
+    assert response.services[0].service_type == ServiceTypeEnum.SERVICETYPE_L3NM
+    assert len(response.services[0].service_endpoint_ids) == 2
+    assert len(response.services[0].service_constraints) == 2
+    assert response.services[0].service_status.service_status == ServiceStatusEnum.SERVICESTATUS_PLANNED
+    assert len(response.services[0].service_config.config_rules) == 3
+
+    # ----- Remove the object ------------------------------------------------------------------------------------------
+    context_client_grpc.RemoveService(ServiceId(**SERVICE_R1_R2_ID))
+    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R1_ID))
+    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R2_ID))
+    context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID))
+    context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID))
+
+    # ----- Check remove event -----------------------------------------------------------------------------------------
+    events = events_collector.get_events(block=True, count=5)
+
+    assert isinstance(events[0], ServiceEvent)
+    assert events[0].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert events[0].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
+
+    assert isinstance(events[1], DeviceEvent)
+    assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[1].device_id.device_uuid.uuid == DEVICE_R1_UUID
+
+    assert isinstance(events[2], DeviceEvent)
+    assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[2].device_id.device_uuid.uuid == DEVICE_R2_UUID
+
+    assert isinstance(events[3], TopologyEvent)
+    assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[3].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert events[3].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    assert isinstance(events[4], ContextEvent)
+    assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    assert events[4].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
+    events_collector.stop()
+
+    # ----- Dump state of database after remove the object -------------------------------------------------------------
+    db_entries = context_database.dump()
+    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
+    for db_entry in db_entries:
+        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
+    LOGGER.info('-----------------------------------------------------------')
+    assert len(db_entries) == 0
diff --git a/src/context/tests/_test_slice.py b/src/context/tests/_test_slice.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/context/tests/_test_topology.py b/src/context/tests/_test_topology.py
new file mode 100644
index 0000000000000000000000000000000000000000..9774d972fc78c0688766ed4b8ad6ff68038a1c89
--- /dev/null
+++ b/src/context/tests/_test_topology.py
@@ -0,0 +1,166 @@
+# 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.
+
+import copy, grpc, pytest
+from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID
+from common.proto.context_pb2 import Context, ContextId, Topology, TopologyId
+from context.client.ContextClient import ContextClient
+#from context.client.EventsCollector import EventsCollector
+from .Objects import CONTEXT, CONTEXT_ID, TOPOLOGY, TOPOLOGY_ID
+
+def grpc_topology(context_client_grpc : ContextClient) -> None:
+
+    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
+    #events_collector = EventsCollector(
+    #    context_client_grpc, log_events_received=True,
+    #    activate_context_collector = False, activate_topology_collector = True, activate_device_collector = False,
+    #    activate_link_collector = False, activate_service_collector = False, activate_slice_collector = False,
+    #    activate_connection_collector = False)
+    #events_collector.start()
+
+    # ----- Prepare dependencies for the test and capture related events -----------------------------------------------
+    response = context_client_grpc.SetContext(Context(**CONTEXT))
+    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    # event = events_collector.get_event(block=True)
+    # assert isinstance(event, ContextEvent)
+    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    # assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Get when the object does not exist -------------------------------------------------------------------------
+    with pytest.raises(grpc.RpcError) as e:
+        context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID))
+    assert e.value.code() == grpc.StatusCode.NOT_FOUND
+    assert e.value.details() == 'Topology({:s}/{:s}) not found'.format(DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID)
+
+    # ----- List when the object does not exist ------------------------------------------------------------------------
+    response = context_client_grpc.ListTopologyIds(ContextId(**CONTEXT_ID))
+    assert len(response.topology_ids) == 0
+
+    response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID))
+    assert len(response.topologies) == 0
+
+    # ----- Create the object ------------------------------------------------------------------------------------------
+    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    #CONTEXT_WITH_TOPOLOGY = copy.deepcopy(CONTEXT)
+    #CONTEXT_WITH_TOPOLOGY['topology_ids'].append(TOPOLOGY_ID)
+    #response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_TOPOLOGY))
+    #assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Check create event -----------------------------------------------------------------------------------------
+    #events = events_collector.get_events(block=True, count=2)
+    #assert isinstance(events[0], TopologyEvent)
+    #assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
+    #assert events[0].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    #assert events[0].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+    #assert isinstance(events[1], ContextEvent)
+    #assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    #assert events[1].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Get when the object exists ---------------------------------------------------------------------------------
+    response = context_client_grpc.GetContext(ContextId(**CONTEXT_ID))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.name == ''
+    assert len(response.topology_ids) == 1
+    assert response.topology_ids[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_ids[0].topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+    assert len(response.service_ids) == 0
+    assert len(response.slice_ids) == 0
+
+    response = context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID))
+    assert response.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+    assert response.name == ''
+    assert len(response.device_ids) == 0
+    assert len(response.link_ids) == 0
+
+    # ----- List when the object exists --------------------------------------------------------------------------------
+    response = context_client_grpc.ListTopologyIds(ContextId(**CONTEXT_ID))
+    assert len(response.topology_ids) == 1
+    assert response.topology_ids[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_ids[0].topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID))
+    assert len(response.topologies) == 1
+    assert response.topologies[0].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topologies[0].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+    assert response.topologies[0].name == ''
+    assert len(response.topologies[0].device_ids) == 0
+    assert len(response.topologies[0].link_ids) == 0
+
+    # ----- Update the object ------------------------------------------------------------------------------------------
+    new_topology_name = 'new'
+    TOPOLOGY_WITH_NAME = copy.deepcopy(TOPOLOGY)
+    TOPOLOGY_WITH_NAME['name'] = new_topology_name
+    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY_WITH_NAME))
+    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    # ----- Check update event -----------------------------------------------------------------------------------------
+    #event = events_collector.get_event(block=True)
+    #assert isinstance(event, TopologyEvent)
+    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
+    #assert event.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    #assert event.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    # ----- Get when the object is modified ----------------------------------------------------------------------------
+    response = context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID))
+    assert response.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+    assert response.name == new_topology_name
+    assert len(response.device_ids) == 0
+    assert len(response.link_ids) == 0
+
+    # ----- List when the object is modified ---------------------------------------------------------------------------
+    response = context_client_grpc.ListTopologyIds(ContextId(**CONTEXT_ID))
+    assert len(response.topology_ids) == 1
+    assert response.topology_ids[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topology_ids[0].topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID))
+    assert len(response.topologies) == 1
+    assert response.topologies[0].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    assert response.topologies[0].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+    assert response.topologies[0].name == new_topology_name
+    assert len(response.topologies[0].device_ids) == 0
+    assert len(response.topologies[0].link_ids) == 0
+
+    # ----- Remove the object ------------------------------------------------------------------------------------------
+    context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID))
+
+    # ----- Check remove event -----------------------------------------------------------------------------------------
+    #event = events_collector.get_event(block=True)
+    #assert isinstance(event, TopologyEvent)
+    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    #assert event.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+    #assert event.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
+
+    # ----- List after deleting the object -----------------------------------------------------------------------------
+    response = context_client_grpc.ListTopologyIds(ContextId(**CONTEXT_ID))
+    assert len(response.topology_ids) == 0
+
+    response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID))
+    assert len(response.topologies) == 0
+
+    # ----- Clean dependencies used in the test and capture related events ---------------------------------------------
+    context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID))
+    #event = events_collector.get_event(block=True)
+    #assert isinstance(event, ContextEvent)
+    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
+    #assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
+
+    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
+    #events_collector.stop()
diff --git a/src/context/tests/conftest.py b/src/context/tests/conftest.py
new file mode 100644
index 0000000000000000000000000000000000000000..cf56ed9af2798a42191266e58f373422a3374257
--- /dev/null
+++ b/src/context/tests/conftest.py
@@ -0,0 +1,153 @@
+# 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.
+
+import json, os, pytest, sqlalchemy
+from _pytest.config import Config
+from _pytest.terminal import TerminalReporter
+from prettytable import PrettyTable
+from typing import Any, Dict, List, Tuple
+from common.Constants import ServiceNameEnum
+from common.Settings import (
+    ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, ENVVAR_SUFIX_SERVICE_PORT_HTTP, get_env_var_name,
+    get_service_port_grpc, get_service_port_http)
+from common.message_broker.Factory import get_messagebroker_backend, BackendEnum as MessageBrokerBackendEnum
+from common.message_broker.MessageBroker import MessageBroker
+from context.client.ContextClient import ContextClient
+from context.service.ContextService import ContextService
+from context.service.Database import Database
+from context.service.Engine import Engine
+from context.service.database.models._Base import rebuild_database
+#from context.service._old_code.Populate import populate
+#from context.service.rest_server.RestServer import RestServer
+#from context.service.rest_server.Resources import RESOURCES
+
+
+LOCAL_HOST = '127.0.0.1'
+GRPC_PORT = 10000 + int(get_service_port_grpc(ServiceNameEnum.CONTEXT))   # avoid privileged ports
+HTTP_PORT = 10000 + int(get_service_port_http(ServiceNameEnum.CONTEXT))   # avoid privileged ports
+
+os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_HOST     )] = str(LOCAL_HOST)
+os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(GRPC_PORT)
+os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_HTTP)] = str(HTTP_PORT)
+
+#DEFAULT_REDIS_SERVICE_HOST = LOCAL_HOST
+#DEFAULT_REDIS_SERVICE_PORT = 6379
+#DEFAULT_REDIS_DATABASE_ID  = 0
+
+#REDIS_CONFIG = {
+#    'REDIS_SERVICE_HOST': os.environ.get('REDIS_SERVICE_HOST', DEFAULT_REDIS_SERVICE_HOST),
+#    'REDIS_SERVICE_PORT': os.environ.get('REDIS_SERVICE_PORT', DEFAULT_REDIS_SERVICE_PORT),
+#    'REDIS_DATABASE_ID' : os.environ.get('REDIS_DATABASE_ID',  DEFAULT_REDIS_DATABASE_ID ),
+#}
+
+#SCENARIOS = [
+#    ('db:cockroach_mb:inmemory', None, {}, None, {}),
+#    ('all_inmemory', DatabaseBackendEnum.INMEMORY, {},           MessageBrokerBackendEnum.INMEMORY, {}          )
+#    ('all_redis',    DatabaseBackendEnum.REDIS,    REDIS_CONFIG, MessageBrokerBackendEnum.REDIS,    REDIS_CONFIG),
+#]
+
+#@pytest.fixture(scope='session', ids=[str(scenario[0]) for scenario in SCENARIOS], params=SCENARIOS)
+@pytest.fixture(scope='session')
+def context_db_mb(request) -> Tuple[sqlalchemy.engine.Engine, MessageBroker]:   # pylint: disable=unused-argument
+    #name,db_session,mb_backend,mb_settings = request.param
+    #msg = 'Running scenario {:s} db_session={:s}, mb_backend={:s}, mb_settings={:s}...'
+    #LOGGER.info(msg.format(str(name), str(db_session), str(mb_backend.value), str(mb_settings)))
+
+    _db_engine = Engine.get_engine()
+    Engine.drop_database(_db_engine)
+    Engine.create_database(_db_engine)
+    rebuild_database(_db_engine)
+
+    _msg_broker = MessageBroker(get_messagebroker_backend(backend=MessageBrokerBackendEnum.INMEMORY))
+    yield _db_engine, _msg_broker
+    _msg_broker.terminate()
+
+RAW_METRICS = None
+
+@pytest.fixture(scope='session')
+def context_service_grpc(context_db_mb : Tuple[Database, MessageBroker]): # pylint: disable=redefined-outer-name
+    global RAW_METRICS # pylint: disable=global-statement
+    _service = ContextService(context_db_mb[0], context_db_mb[1])
+    RAW_METRICS = _service.context_servicer._get_metrics()
+    _service.start()
+    yield _service
+    _service.stop()
+
+#@pytest.fixture(scope='session')
+#def context_service_rest(context_db_mb : Tuple[Database, MessageBroker]): # pylint: disable=redefined-outer-name
+#    database = context_db_mb[0]
+#    _rest_server = RestServer()
+#    for endpoint_name, resource_class, resource_url in RESOURCES:
+#        _rest_server.add_resource(resource_class, resource_url, endpoint=endpoint_name, resource_class_args=(database,))
+#    _rest_server.start()
+#    time.sleep(1) # bring time for the server to start
+#    yield _rest_server
+#    _rest_server.shutdown()
+#    _rest_server.join()
+
+@pytest.fixture(scope='session')
+def context_client_grpc(
+    context_service_grpc : ContextService   # pylint: disable=redefined-outer-name,unused-argument
+):
+    _client = ContextClient()
+    yield _client
+    _client.close()
+
+@pytest.hookimpl(hookwrapper=True)
+def pytest_terminal_summary(
+    terminalreporter : TerminalReporter, exitstatus : int, config : Config  # pylint: disable=unused-argument
+):
+    yield
+
+    method_to_metric_fields : Dict[str, Dict[str, Dict[str, Any]]]= dict()
+    for raw_metric_name,raw_metric_data in RAW_METRICS.items():
+        if '_COUNTER_' in raw_metric_name:
+            method_name,metric_name = raw_metric_name.split('_COUNTER_')
+        elif '_HISTOGRAM_' in raw_metric_name:
+            method_name,metric_name = raw_metric_name.split('_HISTOGRAM_')
+        else:
+            raise Exception('Unsupported metric: {:s}'.format(raw_metric_name))
+        metric_data = method_to_metric_fields.setdefault(method_name, dict()).setdefault(metric_name, dict())
+        for field_name,labels,value,_,_ in raw_metric_data._child_samples():
+            if len(labels) > 0: field_name = '{:s}:{:s}'.format(field_name, json.dumps(labels, sort_keys=True))
+            metric_data[field_name] = value
+    #print('method_to_metric_fields', method_to_metric_fields)
+
+    def sort_stats_key(item : List) -> float:
+        str_duration = str(item[0])
+        if str_duration == '---': return 0.0
+        return float(str_duration.replace(' ms', ''))
+
+    field_names = ['Method', 'Started', 'Completed', 'Failed', 'avg(Duration)']
+    pt_stats = PrettyTable(field_names=field_names, sortby='avg(Duration)', sort_key=sort_stats_key, reversesort=True)
+    for f in ['Method']: pt_stats.align[f] = 'l'
+    for f in ['Started', 'Completed', 'Failed', 'avg(Duration)']: pt_stats.align[f] = 'r'
+
+    for method_name,metrics in method_to_metric_fields.items():
+        counter_started_value = int(metrics['STARTED']['_total'])
+        if counter_started_value == 0:
+            #pt_stats.add_row([method_name, '---', '---', '---', '---'])
+            continue
+        counter_completed_value = int(metrics['COMPLETED']['_total'])
+        counter_failed_value = int(metrics['FAILED']['_total'])
+        duration_count_value = float(metrics['DURATION']['_count'])
+        duration_sum_value = float(metrics['DURATION']['_sum'])
+        duration_avg_value = duration_sum_value/duration_count_value
+        pt_stats.add_row([
+            method_name, str(counter_started_value), str(counter_completed_value), str(counter_failed_value),
+            '{:.3f} ms'.format(1000.0 * duration_avg_value),
+        ])
+    print('')
+    print('Performance Results:')
+    print(pt_stats.get_string())
diff --git a/src/context/tests/test_hasher.py b/src/context/tests/test_hasher.py
new file mode 100644
index 0000000000000000000000000000000000000000..f9a52f5d0222160ea434bc326e49e8a0f80ea622
--- /dev/null
+++ b/src/context/tests/test_hasher.py
@@ -0,0 +1,47 @@
+# 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.
+
+import logging, pytest
+from context.service.database.tools.FastHasher import (
+    FASTHASHER_DATA_ACCEPTED_FORMAT, FASTHASHER_ITEM_ACCEPTED_FORMAT, fast_hasher)
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+
+# ----- Test misc. Context internal tools ------------------------------------------------------------------------------
+
+def test_tools_fast_string_hasher():
+    with pytest.raises(TypeError) as e:
+        fast_hasher(27)
+    assert str(e.value) == "data(27) must be " + FASTHASHER_DATA_ACCEPTED_FORMAT + ", found <class 'int'>"
+
+    with pytest.raises(TypeError) as e:
+        fast_hasher({27})
+    assert str(e.value) == "data({27}) must be " + FASTHASHER_DATA_ACCEPTED_FORMAT + ", found <class 'set'>"
+
+    with pytest.raises(TypeError) as e:
+        fast_hasher({'27'})
+    assert str(e.value) == "data({'27'}) must be " + FASTHASHER_DATA_ACCEPTED_FORMAT + ", found <class 'set'>"
+
+    with pytest.raises(TypeError) as e:
+        fast_hasher([27])
+    assert str(e.value) == "data[0](27) must be " + FASTHASHER_ITEM_ACCEPTED_FORMAT + ", found <class 'int'>"
+
+    fast_hasher('hello-world')
+    fast_hasher('hello-world'.encode('UTF-8'))
+    fast_hasher(['hello', 'world'])
+    fast_hasher(('hello', 'world'))
+    fast_hasher(['hello'.encode('UTF-8'), 'world'.encode('UTF-8')])
+    fast_hasher(('hello'.encode('UTF-8'), 'world'.encode('UTF-8')))
diff --git a/src/context/tests/test_unitary.py b/src/context/tests/test_unitary.py
index c85042d2cd71285c98015a3a8872cf59d4cf7683..6845036bd6daa6ac1c595bca388ef0ff53f98f56 100644
--- a/src/context/tests/test_unitary.py
+++ b/src/context/tests/test_unitary.py
@@ -12,1348 +12,44 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# pylint: disable=too-many-lines
-import copy, grpc, logging, os, pytest, requests, sqlalchemy, time, urllib, uuid
-from typing import Tuple
-from common.Constants import DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID, ServiceNameEnum
-from common.Settings import (
-    ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, ENVVAR_SUFIX_SERVICE_PORT_HTTP, get_env_var_name,
-    get_service_baseurl_http, get_service_port_grpc, get_service_port_http)
-from context.service.Database import Database
-from common.message_broker.Factory import get_messagebroker_backend, BackendEnum as MessageBrokerBackendEnum
-from common.message_broker.MessageBroker import MessageBroker
-from common.proto.context_pb2 import (
-    Connection, ConnectionEvent, ConnectionId, Context, ContextEvent, ContextId, Device, DeviceDriverEnum, DeviceEvent, DeviceId,
-    DeviceOperationalStatusEnum, Empty, EventTypeEnum, Link, LinkEvent, LinkId, Service, ServiceEvent, ServiceId,
-    ServiceStatusEnum, ServiceTypeEnum, Topology, TopologyEvent, TopologyId)
-from common.proto.policy_pb2 import (PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule)
-from common.tools.object_factory.Context import json_context, json_context_id
-from common.tools.object_factory.Service import json_service_id
-from common.tools.object_factory.Slice import json_slice_id
-from common.tools.object_factory.Topology import json_topology_id
-from common.type_checkers.Assertions import (
-    validate_connection, validate_connection_ids, validate_connections, validate_context, validate_context_ids,
-    validate_contexts, validate_device, validate_device_ids, validate_devices, validate_link, validate_link_ids,
-    validate_links, validate_service, validate_service_ids, validate_services, validate_topologies, validate_topology,
-    validate_topology_ids)
+import pytest
 from context.client.ContextClient import ContextClient
-from context.client.EventsCollector import EventsCollector
-from context.service.database.Tools import (
-    FASTHASHER_DATA_ACCEPTED_FORMAT, FASTHASHER_ITEM_ACCEPTED_FORMAT, fast_hasher)
-from context.service.ContextService import ContextService
-#from context.service._old_code.Populate import populate
-#from context.service.rest_server.RestServer import RestServer
-#from context.service.rest_server.Resources import RESOURCES
-from requests import Session
-from sqlalchemy import create_engine
-from sqlalchemy.orm import sessionmaker
-from context.service.database._Base import _Base
-from common.Settings import get_setting
-from context.service.Engine import Engine
-from context.service.database._Base import rebuild_database
-
-from .Objects import (
-    CONNECTION_R1_R3, CONNECTION_R1_R3_ID, CONNECTION_R1_R3_UUID, CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID,
-    DEVICE_R1_UUID, DEVICE_R2, DEVICE_R2_ID, DEVICE_R2_UUID, DEVICE_R3, DEVICE_R3_ID, DEVICE_R3_UUID, LINK_R1_R2,
-    LINK_R1_R2_ID, LINK_R1_R2_UUID, SERVICE_R1_R2, SERVICE_R1_R2_ID, SERVICE_R1_R2_UUID, SERVICE_R1_R3,
-    SERVICE_R1_R3_ID, SERVICE_R1_R3_UUID, SERVICE_R2_R3, SERVICE_R2_R3_ID, SERVICE_R2_R3_UUID, TOPOLOGY, TOPOLOGY_ID,
-    POLICY_RULE, POLICY_RULE_ID, POLICY_RULE_UUID)
-
-LOGGER = logging.getLogger(__name__)
-LOGGER.setLevel(logging.DEBUG)
-
-LOCAL_HOST = '127.0.0.1'
-GRPC_PORT = 10000 + int(get_service_port_grpc(ServiceNameEnum.CONTEXT))   # avoid privileged ports
-HTTP_PORT = 10000 + int(get_service_port_http(ServiceNameEnum.CONTEXT))   # avoid privileged ports
-
-os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_HOST     )] = str(LOCAL_HOST)
-os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(GRPC_PORT)
-os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_HTTP)] = str(HTTP_PORT)
-
-#DEFAULT_REDIS_SERVICE_HOST = LOCAL_HOST
-#DEFAULT_REDIS_SERVICE_PORT = 6379
-#DEFAULT_REDIS_DATABASE_ID  = 0
-
-#REDIS_CONFIG = {
-#    'REDIS_SERVICE_HOST': os.environ.get('REDIS_SERVICE_HOST', DEFAULT_REDIS_SERVICE_HOST),
-#    'REDIS_SERVICE_PORT': os.environ.get('REDIS_SERVICE_PORT', DEFAULT_REDIS_SERVICE_PORT),
-#    'REDIS_DATABASE_ID' : os.environ.get('REDIS_DATABASE_ID',  DEFAULT_REDIS_DATABASE_ID ),
-#}
-
-#SCENARIOS = [
-#    ('db:cockroach_mb:inmemory', None, {}, None, {}),
-#    ('all_inmemory', DatabaseBackendEnum.INMEMORY, {},           MessageBrokerBackendEnum.INMEMORY, {}          )
-#    ('all_redis',    DatabaseBackendEnum.REDIS,    REDIS_CONFIG, MessageBrokerBackendEnum.REDIS,    REDIS_CONFIG),
-#]
-
-#@pytest.fixture(scope='session', ids=[str(scenario[0]) for scenario in SCENARIOS], params=SCENARIOS)
-@pytest.fixture(scope='session')
-def context_db_mb(request) -> Tuple[Session, MessageBroker]:
-    #name,db_session,mb_backend,mb_settings = request.param
-    #msg = 'Running scenario {:s} db_session={:s}, mb_backend={:s}, mb_settings={:s}...'
-    #LOGGER.info(msg.format(str(name), str(db_session), str(mb_backend.value), str(mb_settings)))
-
-    _db_engine = Engine.get_engine()
-    Engine.drop_database(_db_engine)
-    Engine.create_database(_db_engine)
-    rebuild_database(_db_engine)
-
-    _msg_broker = MessageBroker(get_messagebroker_backend(backend=MessageBrokerBackendEnum.INMEMORY))
-    yield _db_engine, _msg_broker
-    _msg_broker.terminate()
-
-@pytest.fixture(scope='session')
-def context_service_grpc(context_db_mb : Tuple[Database, MessageBroker]): # pylint: disable=redefined-outer-name
-    _service = ContextService(context_db_mb[0], context_db_mb[1])
-    _service.start()
-    yield _service
-    _service.stop()
-
-#@pytest.fixture(scope='session')
-#def context_service_rest(context_db_mb : Tuple[Database, MessageBroker]): # pylint: disable=redefined-outer-name
-#    database = context_db_mb[0]
-#    _rest_server = RestServer()
-#    for endpoint_name, resource_class, resource_url in RESOURCES:
-#        _rest_server.add_resource(resource_class, resource_url, endpoint=endpoint_name, resource_class_args=(database,))
-#    _rest_server.start()
-#    time.sleep(1) # bring time for the server to start
-#    yield _rest_server
-#    _rest_server.shutdown()
-#    _rest_server.join()
-
-@pytest.fixture(scope='session')
-def context_client_grpc(context_service_grpc : ContextService): # pylint: disable=redefined-outer-name
-    _client = ContextClient()
-    yield _client
-    _client.close()
-
-#def do_rest_request(url : str):
-#    base_url = get_service_baseurl_http(ServiceNameEnum.CONTEXT)
-#    request_url = 'http://{:s}:{:s}{:s}{:s}'.format(str(LOCAL_HOST), str(HTTP_PORT), str(base_url), url)
-#    LOGGER.warning('Request: GET {:s}'.format(str(request_url)))
-#    reply = requests.get(request_url)
-#    LOGGER.warning('Reply: {:s}'.format(str(reply.text)))
-#    assert reply.status_code == 200, 'Reply failed with code {}'.format(reply.status_code)
-#    return reply.json()
-
-# pylint: disable=redefined-outer-name, unused-argument
-def test_grpc_initialize(context_client_grpc : ContextClient) -> None:
-    # dummy method used to initialize fixtures, database, message broker, etc.
-    pass
-
-# ----- Test gRPC methods ----------------------------------------------------------------------------------------------
-
-def test_grpc_context(context_client_grpc : ContextClient) -> None: # pylint: disable=redefined-outer-name
-
-    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
-    #events_collector = EventsCollector(
-    #    context_client_grpc, log_events_received=True,
-    #    activate_context_collector = True, activate_topology_collector = False, activate_device_collector = False,
-    #    activate_link_collector = False, activate_service_collector = False, activate_slice_collector = False,
-    #    activate_connection_collector = False)
-    #events_collector.start()
-
-    # ----- Get when the object does not exist -------------------------------------------------------------------------
-    with pytest.raises(grpc.RpcError) as e:
-        context_client_grpc.GetContext(ContextId(**CONTEXT_ID))
-    assert e.value.code() == grpc.StatusCode.NOT_FOUND
-    assert e.value.details() == 'Context({:s}) not found'.format(DEFAULT_CONTEXT_UUID)
-
-    # ----- List when the object does not exist ------------------------------------------------------------------------
-    response = context_client_grpc.ListContextIds(Empty())
-    assert len(response.context_ids) == 0
-
-    response = context_client_grpc.ListContexts(Empty())
-    assert len(response.contexts) == 0
-
-    # ----- Create the object ------------------------------------------------------------------------------------------
-    response = context_client_grpc.SetContext(Context(**CONTEXT))
-    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    wrong_context_uuid = str(uuid.uuid4())
-    wrong_context_id = json_context_id(wrong_context_uuid)
-    with pytest.raises(grpc.RpcError) as e:
-        WRONG_CONTEXT = copy.deepcopy(CONTEXT)
-        WRONG_CONTEXT['topology_ids'].append(json_topology_id(str(uuid.uuid4()), context_id=wrong_context_id))
-        context_client_grpc.SetContext(Context(**WRONG_CONTEXT))
-    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-    msg = 'request.topology_ids[0].context_id.context_uuid.uuid({}) is invalid; '\
-          'should be == request.context_id.context_uuid.uuid({})'.format(wrong_context_uuid, DEFAULT_CONTEXT_UUID)
-    assert e.value.details() == msg
-
-    with pytest.raises(grpc.RpcError) as e:
-        WRONG_CONTEXT = copy.deepcopy(CONTEXT)
-        WRONG_CONTEXT['service_ids'].append(json_service_id(str(uuid.uuid4()), context_id=wrong_context_id))
-        context_client_grpc.SetContext(Context(**WRONG_CONTEXT))
-    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-    msg = 'request.service_ids[0].context_id.context_uuid.uuid({}) is invalid; '\
-          'should be == request.context_id.context_uuid.uuid({})'.format(wrong_context_uuid, DEFAULT_CONTEXT_UUID)
-    assert e.value.details() == msg
-
-    with pytest.raises(grpc.RpcError) as e:
-        WRONG_CONTEXT = copy.deepcopy(CONTEXT)
-        WRONG_CONTEXT['slice_ids'].append(json_slice_id(str(uuid.uuid4()), context_id=wrong_context_id))
-        context_client_grpc.SetContext(Context(**WRONG_CONTEXT))
-    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-    msg = 'request.slice_ids[0].context_id.context_uuid.uuid({}) is invalid; '\
-          'should be == request.context_id.context_uuid.uuid({})'.format(wrong_context_uuid, DEFAULT_CONTEXT_UUID)
-    assert e.value.details() == msg
-
-    # ----- Check create event -----------------------------------------------------------------------------------------
-    #event = events_collector.get_event(block=True, timeout=10.0)
-    #assert isinstance(event, ContextEvent)
-    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    #assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Get when the object exists ---------------------------------------------------------------------------------
-    response = context_client_grpc.GetContext(ContextId(**CONTEXT_ID))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.name == ''
-    assert len(response.topology_ids) == 0
-    assert len(response.service_ids) == 0
-    assert len(response.slice_ids) == 0
-
-    # ----- List when the object exists --------------------------------------------------------------------------------
-    response = context_client_grpc.ListContextIds(Empty())
-    assert len(response.context_ids) == 1
-    assert response.context_ids[0].context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    response = context_client_grpc.ListContexts(Empty())
-    assert len(response.contexts) == 1
-    assert response.contexts[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.contexts[0].name == ''
-    assert len(response.contexts[0].topology_ids) == 0
-    assert len(response.contexts[0].service_ids) == 0
-    assert len(response.contexts[0].slice_ids) == 0
-
-    # ----- Update the object ------------------------------------------------------------------------------------------
-    new_context_name = 'new'
-    CONTEXT_WITH_NAME = copy.deepcopy(CONTEXT)
-    CONTEXT_WITH_NAME['name'] = new_context_name
-    response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_NAME))
-    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Check update event -----------------------------------------------------------------------------------------
-    #event = events_collector.get_event(block=True, timeout=10.0)
-    #assert isinstance(event, ContextEvent)
-    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    #assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Get when the object is modified ----------------------------------------------------------------------------
-    response = context_client_grpc.GetContext(ContextId(**CONTEXT_ID))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.name == new_context_name
-    assert len(response.topology_ids) == 0
-    assert len(response.service_ids) == 0
-    assert len(response.slice_ids) == 0
-
-    # ----- List when the object is modified ---------------------------------------------------------------------------
-    response = context_client_grpc.ListContextIds(Empty())
-    assert len(response.context_ids) == 1
-    assert response.context_ids[0].context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    response = context_client_grpc.ListContexts(Empty())
-    assert len(response.contexts) == 1
-    assert response.contexts[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.contexts[0].name == new_context_name
-    assert len(response.contexts[0].topology_ids) == 0
-    assert len(response.contexts[0].service_ids) == 0
-    assert len(response.contexts[0].slice_ids) == 0
-
-    # ----- Remove the object ------------------------------------------------------------------------------------------
-    context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID))
-
-    # ----- Check remove event -----------------------------------------------------------------------------------------
-    #event = events_collector.get_event(block=True, timeout=10.0)
-    #assert isinstance(event, ContextEvent)
-    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    #assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- List after deleting the object -----------------------------------------------------------------------------
-    response = context_client_grpc.ListContextIds(Empty())
-    assert len(response.context_ids) == 0
-
-    response = context_client_grpc.ListContexts(Empty())
-    assert len(response.contexts) == 0
-
-    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
-    #events_collector.stop()
-
-
-def test_grpc_topology(context_client_grpc : ContextClient) -> None:    # pylint: disable=redefined-outer-name
-
-    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
-    #events_collector = EventsCollector(
-    #    context_client_grpc, log_events_received=True,
-    #    activate_context_collector = False, activate_topology_collector = True, activate_device_collector = False,
-    #    activate_link_collector = False, activate_service_collector = False, activate_slice_collector = False,
-    #    activate_connection_collector = False)
-    #events_collector.start()
-
-    # ----- Prepare dependencies for the test and capture related events -----------------------------------------------
-    response = context_client_grpc.SetContext(Context(**CONTEXT))
-    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    # event = events_collector.get_event(block=True)
-    # assert isinstance(event, ContextEvent)
-    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Get when the object does not exist -------------------------------------------------------------------------
-    with pytest.raises(grpc.RpcError) as e:
-        context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID))
-    assert e.value.code() == grpc.StatusCode.NOT_FOUND
-    assert e.value.details() == 'Topology({:s}/{:s}) not found'.format(DEFAULT_CONTEXT_UUID, DEFAULT_TOPOLOGY_UUID)
-
-    # ----- List when the object does not exist ------------------------------------------------------------------------
-    response = context_client_grpc.ListTopologyIds(ContextId(**CONTEXT_ID))
-    assert len(response.topology_ids) == 0
-
-    response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID))
-    assert len(response.topologies) == 0
-
-    # ----- Create the object ------------------------------------------------------------------------------------------
-    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    #CONTEXT_WITH_TOPOLOGY = copy.deepcopy(CONTEXT)
-    #CONTEXT_WITH_TOPOLOGY['topology_ids'].append(TOPOLOGY_ID)
-    #response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_TOPOLOGY))
-    #assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Check create event -----------------------------------------------------------------------------------------
-    #events = events_collector.get_events(block=True, count=2)
-    #assert isinstance(events[0], TopologyEvent)
-    #assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    #assert events[0].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    #assert events[0].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-    #assert isinstance(events[1], ContextEvent)
-    #assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    #assert events[1].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Get when the object exists ---------------------------------------------------------------------------------
-    response = context_client_grpc.GetContext(ContextId(**CONTEXT_ID))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.name == ''
-    assert len(response.topology_ids) == 1
-    assert response.topology_ids[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_ids[0].topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-    assert len(response.service_ids) == 0
-    assert len(response.slice_ids) == 0
-
-    response = context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID))
-    assert response.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-    assert response.name == ''
-    assert len(response.device_ids) == 0
-    assert len(response.link_ids) == 0
-
-    # ----- List when the object exists --------------------------------------------------------------------------------
-    response = context_client_grpc.ListTopologyIds(ContextId(**CONTEXT_ID))
-    assert len(response.topology_ids) == 1
-    assert response.topology_ids[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_ids[0].topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID))
-    assert len(response.topologies) == 1
-    assert response.topologies[0].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topologies[0].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-    assert response.topologies[0].name == ''
-    assert len(response.topologies[0].device_ids) == 0
-    assert len(response.topologies[0].link_ids) == 0
-
-    # ----- Update the object ------------------------------------------------------------------------------------------
-    new_topology_name = 'new'
-    TOPOLOGY_WITH_NAME = copy.deepcopy(TOPOLOGY)
-    TOPOLOGY_WITH_NAME['name'] = new_topology_name
-    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY_WITH_NAME))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    # ----- Check update event -----------------------------------------------------------------------------------------
-    #event = events_collector.get_event(block=True)
-    #assert isinstance(event, TopologyEvent)
-    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    #assert event.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    #assert event.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    # ----- Get when the object is modified ----------------------------------------------------------------------------
-    response = context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID))
-    assert response.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-    assert response.name == new_topology_name
-    assert len(response.device_ids) == 0
-    assert len(response.link_ids) == 0
-
-    # ----- List when the object is modified ---------------------------------------------------------------------------
-    response = context_client_grpc.ListTopologyIds(ContextId(**CONTEXT_ID))
-    assert len(response.topology_ids) == 1
-    assert response.topology_ids[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_ids[0].topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID))
-    assert len(response.topologies) == 1
-    assert response.topologies[0].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topologies[0].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-    assert response.topologies[0].name == new_topology_name
-    assert len(response.topologies[0].device_ids) == 0
-    assert len(response.topologies[0].link_ids) == 0
-
-    # ----- Remove the object ------------------------------------------------------------------------------------------
-    context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID))
-
-    # ----- Check remove event -----------------------------------------------------------------------------------------
-    #event = events_collector.get_event(block=True)
-    #assert isinstance(event, TopologyEvent)
-    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    #assert event.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    #assert event.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    # ----- List after deleting the object -----------------------------------------------------------------------------
-    response = context_client_grpc.ListTopologyIds(ContextId(**CONTEXT_ID))
-    assert len(response.topology_ids) == 0
-
-    response = context_client_grpc.ListTopologies(ContextId(**CONTEXT_ID))
-    assert len(response.topologies) == 0
-
-    # ----- Clean dependencies used in the test and capture related events ---------------------------------------------
-    context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID))
-    #event = events_collector.get_event(block=True)
-    #assert isinstance(event, ContextEvent)
-    #assert event.event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    #assert event.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
-    #events_collector.stop()
-
-def test_grpc_device(context_client_grpc : ContextClient) -> None:  # pylint: disable=redefined-outer-name
-
-    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
-    #events_collector = EventsCollector(
-    #    context_client_grpc, log_events_received=True,
-    #    activate_context_collector = False, activate_topology_collector = False, activate_device_collector = True,
-    #    activate_link_collector = False, activate_service_collector = False, activate_slice_collector = False,
-    #    activate_connection_collector = False)
-    #events_collector.start()
-
-    # ----- Prepare dependencies for the test and capture related events -----------------------------------------------
-    response = context_client_grpc.SetContext(Context(**CONTEXT))
-    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    #events = events_collector.get_events(block=True, count=2)
-    #assert isinstance(events[0], ContextEvent)
-    #assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    #assert events[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    #assert isinstance(events[1], TopologyEvent)
-    #assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    #assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    #assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    # ----- Get when the object does not exist -------------------------------------------------------------------------
-    with pytest.raises(grpc.RpcError) as e:
-        context_client_grpc.GetDevice(DeviceId(**DEVICE_R1_ID))
-    assert e.value.code() == grpc.StatusCode.NOT_FOUND
-    assert e.value.details() == 'Device({:s}) not found'.format(DEVICE_R1_UUID)
-
-    # ----- List when the object does not exist ------------------------------------------------------------------------
-    response = context_client_grpc.ListDeviceIds(Empty())
-    assert len(response.device_ids) == 0
-
-    response = context_client_grpc.ListDevices(Empty())
-    assert len(response.devices) == 0
-
-    # ----- Create the object ------------------------------------------------------------------------------------------
-    with pytest.raises(grpc.RpcError) as e:
-        WRONG_DEVICE = copy.deepcopy(DEVICE_R1)
-        WRONG_DEVICE_UUID = '3f03c76d-31fb-47f5-9c1d-bc6b6bfa2d08'
-        WRONG_DEVICE['device_endpoints'][0]['endpoint_id']['device_id']['device_uuid']['uuid'] = WRONG_DEVICE_UUID
-        context_client_grpc.SetDevice(Device(**WRONG_DEVICE))
-    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-    msg = 'request.device_endpoints[0].device_id.device_uuid.uuid({}) is invalid; '\
-          'should be == request.device_id.device_uuid.uuid({})'.format(WRONG_DEVICE_UUID, DEVICE_R1_UUID)
-    assert e.value.details() == msg
-
-    response = context_client_grpc.SetDevice(Device(**DEVICE_R1))
-    assert response.device_uuid.uuid == DEVICE_R1_UUID
-
-    # ----- Check create event -----------------------------------------------------------------------------------------
-    # event = events_collector.get_event(block=True)
-    # assert isinstance(event, DeviceEvent)
-    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert event.device_id.device_uuid.uuid == DEVICE_R1_UUID
-
-    # ----- Get when the object exists ---------------------------------------------------------------------------------
-    response = context_client_grpc.GetDevice(DeviceId(**DEVICE_R1_ID))
-    assert response.device_id.device_uuid.uuid == DEVICE_R1_UUID
-    assert response.name == ''
-    assert response.device_type == 'packet-router'
-    #assert len(response.device_config.config_rules) == 3
-    assert response.device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED
-    assert len(response.device_drivers) == 1
-    assert DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG in response.device_drivers
-    #assert len(response.device_endpoints) == 3
-
-    # ----- List when the object exists --------------------------------------------------------------------------------
-    response = context_client_grpc.ListDeviceIds(Empty())
-    assert len(response.device_ids) == 1
-    assert response.device_ids[0].device_uuid.uuid == DEVICE_R1_UUID
-
-    response = context_client_grpc.ListDevices(Empty())
-    assert len(response.devices) == 1
-    assert response.devices[0].device_id.device_uuid.uuid == DEVICE_R1_UUID
-    assert response.devices[0].name == ''
-    assert response.devices[0].device_type == 'packet-router'
-    #assert len(response.devices[0].device_config.config_rules) == 3
-    assert response.devices[0].device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_DISABLED
-    assert len(response.devices[0].device_drivers) == 1
-    assert DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG in response.devices[0].device_drivers
-    #assert len(response.devices[0].device_endpoints) == 3
-
-    # ----- Update the object ------------------------------------------------------------------------------------------
-    new_device_name = 'r1'
-    new_device_driver = DeviceDriverEnum.DEVICEDRIVER_UNDEFINED
-    DEVICE_UPDATED = copy.deepcopy(DEVICE_R1)
-    DEVICE_UPDATED['name'] = new_device_name
-    DEVICE_UPDATED['device_operational_status'] = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
-    DEVICE_UPDATED['device_drivers'].append(new_device_driver)
-    response = context_client_grpc.SetDevice(Device(**DEVICE_UPDATED))
-    assert response.device_uuid.uuid == DEVICE_R1_UUID
-
-    # ----- Check update event -----------------------------------------------------------------------------------------
-    # event = events_collector.get_event(block=True)
-    # assert isinstance(event, DeviceEvent)
-    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    # assert event.device_id.device_uuid.uuid == DEVICE_R1_UUID
-
-    # ----- Get when the object is modified ----------------------------------------------------------------------------
-    response = context_client_grpc.GetDevice(DeviceId(**DEVICE_R1_ID))
-    assert response.device_id.device_uuid.uuid == DEVICE_R1_UUID
-    assert response.name == 'r1'
-    assert response.device_type == 'packet-router'
-    #assert len(response.device_config.config_rules) == 3
-    assert response.device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
-    assert len(response.device_drivers) == 2
-    assert DeviceDriverEnum.DEVICEDRIVER_UNDEFINED in response.device_drivers
-    assert DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG in response.device_drivers
-    #assert len(response.device_endpoints) == 3
-
-    # ----- List when the object is modified ---------------------------------------------------------------------------
-    response = context_client_grpc.ListDeviceIds(Empty())
-    assert len(response.device_ids) == 1
-    assert response.device_ids[0].device_uuid.uuid == DEVICE_R1_UUID
-
-    response = context_client_grpc.ListDevices(Empty())
-    assert len(response.devices) == 1
-    assert response.devices[0].device_id.device_uuid.uuid == DEVICE_R1_UUID
-    assert response.devices[0].name == 'r1'
-    assert response.devices[0].device_type == 'packet-router'
-    #assert len(response.devices[0].device_config.config_rules) == 3
-    assert response.devices[0].device_operational_status == DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
-    assert len(response.devices[0].device_drivers) == 2
-    assert DeviceDriverEnum.DEVICEDRIVER_UNDEFINED in response.devices[0].device_drivers
-    assert DeviceDriverEnum.DEVICEDRIVER_OPENCONFIG in response.devices[0].device_drivers
-    #assert len(response.devices[0].device_endpoints) == 3
-
-    # ----- Create object relation -------------------------------------------------------------------------------------
-    TOPOLOGY_WITH_DEVICE = copy.deepcopy(TOPOLOGY)
-    TOPOLOGY_WITH_DEVICE['device_ids'].append(DEVICE_R1_ID)
-    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY_WITH_DEVICE))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    # ----- Check update event -----------------------------------------------------------------------------------------
-    # event = events_collector.get_event(block=True)
-    # assert isinstance(event, TopologyEvent)
-    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    # assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    # assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    # ----- Check relation was created ---------------------------------------------------------------------------------
-    response = context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID))
-    assert response.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-    assert len(response.device_ids) == 1
-    assert response.device_ids[0].device_uuid.uuid == DEVICE_R1_UUID
-    assert len(response.link_ids) == 0
-
-    # ----- Remove the object ------------------------------------------------------------------------------------------
-    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R1_ID))
-    context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID))
-    context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID))
-
-    # ----- Check remove event -----------------------------------------------------------------------------------------
-    # events = events_collector.get_events(block=True, count=3)
-
-    # assert isinstance(events[0], DeviceEvent)
-    # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    # assert events[0].device_id.device_uuid.uuid == DEVICE_R1_UUID
-
-    # assert isinstance(events[1], TopologyEvent)
-    # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    # assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    # assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    # assert isinstance(events[2], ContextEvent)
-    # assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    # assert events[2].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
-    # events_collector.stop()
-
-
-"""
-def test_grpc_link(
-    context_client_grpc: ContextClient,             # pylint: disable=redefined-outer-name
-    context_db_mb: Tuple[Session, MessageBroker]):   # pylint: disable=redefined-outer-name
-    session = context_db_mb[0]
-
-    database = Database(session)
-
-    # ----- Clean the database -----------------------------------------------------------------------------------------
-    database.clear()
-
-    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
-    events_collector = EventsCollector(context_client_grpc)
-    events_collector.start()
-
-    # ----- Prepare dependencies for the test and capture related events -----------------------------------------------
-    response = context_client_grpc.SetContext(Context(**CONTEXT))
-    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    response = context_client_grpc.SetDevice(Device(**DEVICE_R1))
-    assert response.device_uuid.uuid == DEVICE_R1_UUID
-
-    response = context_client_grpc.SetDevice(Device(**DEVICE_R2))
-    assert response.device_uuid.uuid == DEVICE_R2_UUID
-    # events = events_collector.get_events(block=True, count=4)
-
-    # assert isinstance(events[0], ContextEvent)
-    # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert events[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    #
-    # assert isinstance(events[1], TopologyEvent)
-    # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    # assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-    #
-    # assert isinstance(events[2], DeviceEvent)
-    # assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert events[2].device_id.device_uuid.uuid == DEVICE_R1_UUID
-    #
-    # assert isinstance(events[3], DeviceEvent)
-    # assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert events[3].device_id.device_uuid.uuid == DEVICE_R2_UUID
-
-    # ----- Get when the object does not exist -------------------------------------------------------------------------
-    with pytest.raises(grpc.RpcError) as e:
-        context_client_grpc.GetLink(LinkId(**LINK_R1_R2_ID))
-    assert e.value.code() == grpc.StatusCode.NOT_FOUND
-    assert e.value.details() == 'Link({:s}) not found'.format(LINK_R1_R2_UUID)
-
-    # ----- List when the object does not exist ------------------------------------------------------------------------
-    response = context_client_grpc.ListLinkIds(Empty())
-    assert len(response.link_ids) == 0
-
-    response = context_client_grpc.ListLinks(Empty())
-    assert len(response.links) == 0
-
-    # ----- Dump state of database before create the object ------------------------------------------------------------
-    db_entries = database.dump_all()
-    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
-    for db_entry in db_entries:
-        LOGGER.info(db_entry)
-    LOGGER.info('-----------------------------------------------------------')
-    assert len(db_entries) == 80
-
-    # ----- Create the object ------------------------------------------------------------------------------------------
-    response = context_client_grpc.SetLink(Link(**LINK_R1_R2))
-    assert response.link_uuid.uuid == LINK_R1_R2_UUID
-
-    # ----- Check create event -----------------------------------------------------------------------------------------
-    # event = events_collector.get_event(block=True)
-    # assert isinstance(event, LinkEvent)
-    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert event.link_id.link_uuid.uuid == LINK_R1_R2_UUID
-
-    # ----- Update the object ------------------------------------------------------------------------------------------
-    response = context_client_grpc.SetLink(Link(**LINK_R1_R2))
-    assert response.link_uuid.uuid == LINK_R1_R2_UUID
-    # ----- Check update event -----------------------------------------------------------------------------------------
-    # event = events_collector.get_event(block=True)
-    # assert isinstance(event, LinkEvent)
-    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    # assert event.link_id.link_uuid.uuid == LINK_R1_R2_UUID
-
-    # ----- Dump state of database after create/update the object ------------------------------------------------------
-    db_entries = database.dump_all()
-    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
-    for db_entry in db_entries:
-        LOGGER.info(db_entry)
-    LOGGER.info('-----------------------------------------------------------')
-    assert len(db_entries) == 88
-
-    # ----- Get when the object exists ---------------------------------------------------------------------------------
-    response = context_client_grpc.GetLink(LinkId(**LINK_R1_R2_ID))
-    assert response.link_id.link_uuid.uuid == LINK_R1_R2_UUID
-    assert len(response.link_endpoint_ids) == 2
-
-    # ----- List when the object exists --------------------------------------------------------------------------------
-    response = context_client_grpc.ListLinkIds(Empty())
-    assert len(response.link_ids) == 1
-    assert response.link_ids[0].link_uuid.uuid == LINK_R1_R2_UUID
-
-    response = context_client_grpc.ListLinks(Empty())
-    assert len(response.links) == 1
-    assert response.links[0].link_id.link_uuid.uuid == LINK_R1_R2_UUID
-
-    assert len(response.links[0].link_endpoint_ids) == 2
-
-    # ----- Create object relation -------------------------------------------------------------------------------------
-    TOPOLOGY_WITH_LINK = copy.deepcopy(TOPOLOGY)
-    TOPOLOGY_WITH_LINK['link_ids'].append(LINK_R1_R2_ID)
-    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY_WITH_LINK))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    # ----- Check update event -----------------------------------------------------------------------------------------
-    # event = events_collector.get_event(block=True)
-    # assert isinstance(event, TopologyEvent)
-    # assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    # assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    # assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    # ----- Check relation was created ---------------------------------------------------------------------------------
-    response = context_client_grpc.GetTopology(TopologyId(**TOPOLOGY_ID))
-    assert response.topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-    assert len(response.device_ids) == 2
-    # assert response.device_ids[0].device_uuid.uuid == DEVICE_R1_UUID
-    # assert response.device_ids[1].device_uuid.uuid == DEVICE_R2_UUID
-    assert len(response.link_ids) == 1
-    assert response.link_ids[0].link_uuid.uuid == LINK_R1_R2_UUID
-
-    db_entries = database.dump_all()
-    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
-    for db_entry in db_entries:
-        LOGGER.info(db_entry)
-    LOGGER.info('-----------------------------------------------------------')
-    assert len(db_entries) == 88
-
-    # ----- Remove the object ------------------------------------------------------------------------------------------
-    context_client_grpc.RemoveLink(LinkId(**LINK_R1_R2_ID))
-    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R1_ID))
-    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R2_ID))
-    context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID))
-    context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID))
-
-    # ----- Check remove event -----------------------------------------------------------------------------------------
-    # events = events_collector.get_events(block=True, count=5)
-    #
-    # assert isinstance(events[0], LinkEvent)
-    # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    # assert events[0].link_id.link_uuid.uuid == LINK_R1_R2_UUID
-    #
-    # assert isinstance(events[1], DeviceEvent)
-    # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    # assert events[1].device_id.device_uuid.uuid == DEVICE_R1_UUID
-    #
-    # assert isinstance(events[2], DeviceEvent)
-    # assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    # assert events[2].device_id.device_uuid.uuid == DEVICE_R2_UUID
-    #
-    # assert isinstance(events[3], TopologyEvent)
-    # assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    # assert events[3].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    # assert events[3].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-    #
-    # assert isinstance(events[4], ContextEvent)
-    # assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    # assert events[4].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
-    events_collector.stop()
-
-    # ----- Dump state of database after remove the object -------------------------------------------------------------
-    db_entries = database.dump_all()
-    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
-    for db_entry in db_entries:
-        LOGGER.info(db_entry)
-    LOGGER.info('-----------------------------------------------------------')
-    assert len(db_entries) == 0
-"""
-
-"""
-def test_grpc_service(
-    context_client_grpc : ContextClient,                # pylint: disable=redefined-outer-name
-    context_db_mb : Tuple[Database, MessageBroker]):    # pylint: disable=redefined-outer-name
-    Session = context_db_mb[0]
-    # ----- Clean the database -----------------------------------------------------------------------------------------
-    database = Database(Session)
-    database.clear()
-
-    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
-    events_collector = EventsCollector(context_client_grpc)
-    events_collector.start()
-
-    # ----- Prepare dependencies for the test and capture related events -----------------------------------------------
-    response = context_client_grpc.SetContext(Context(**CONTEXT))
-    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    response = context_client_grpc.SetDevice(Device(**DEVICE_R1))
-    assert response.device_uuid.uuid == DEVICE_R1_UUID
-
-    response = context_client_grpc.SetDevice(Device(**DEVICE_R2))
-    assert response.device_uuid.uuid == DEVICE_R2_UUID
-    # events = events_collector.get_events(block=True, count=4)
-    #
-    # assert isinstance(events[0], ContextEvent)
-    # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert events[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    #
-    # assert isinstance(events[1], TopologyEvent)
-    # assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    # assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-    #
-    # assert isinstance(events[2], DeviceEvent)
-    # assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert events[2].device_id.device_uuid.uuid == DEVICE_R1_UUID
-    #
-    # assert isinstance(events[3], DeviceEvent)
-    # assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert events[3].device_id.device_uuid.uuid == DEVICE_R2_UUID
-    LOGGER.info('----------------')
-
-    # ----- Get when the object does not exist -------------------------------------------------------------------------
-    with pytest.raises(grpc.RpcError) as e:
-        context_client_grpc.GetService(ServiceId(**SERVICE_R1_R2_ID))
-    assert e.value.code() == grpc.StatusCode.NOT_FOUND
-    assert e.value.details() == 'Service({:s}) not found'.format(SERVICE_R1_R2_UUID)
-    LOGGER.info('----------------')
-
-    # ----- List when the object does not exist ------------------------------------------------------------------------
-    response = context_client_grpc.ListServiceIds(ContextId(**CONTEXT_ID))
-    assert len(response.service_ids) == 0
-    LOGGER.info('----------------')
-
-    response = context_client_grpc.ListServices(ContextId(**CONTEXT_ID))
-    assert len(response.services) == 0
-    LOGGER.info('----------------')
-
-    # ----- Dump state of database before create the object ------------------------------------------------------------
-    db_entries = database.dump_all()
-    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
-    for db_entry in db_entries:
-        LOGGER.info(db_entry)
-    LOGGER.info('-----------------------------------------------------------')
-    assert len(db_entries) == 80
-
-    # ----- Create the object ------------------------------------------------------------------------------------------
-    with pytest.raises(grpc.RpcError) as e:
-        WRONG_SERVICE = copy.deepcopy(SERVICE_R1_R2)
-        WRONG_SERVICE['service_endpoint_ids'][0]\
-            ['topology_id']['context_id']['context_uuid']['uuid'] = 'ca1ea172-728f-441d-972c-feeae8c9bffc'
-        context_client_grpc.SetService(Service(**WRONG_SERVICE))
-    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-    msg = 'request.service_endpoint_ids[0].topology_id.context_id.context_uuid.uuid(ca1ea172-728f-441d-972c-feeae8c9bffc) is invalid; '\
-          'should be == request.service_id.context_id.context_uuid.uuid({:s})'.format(DEFAULT_CONTEXT_UUID)
-    assert e.value.details() == msg
-
-    response = context_client_grpc.SetService(Service(**SERVICE_R1_R2))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.service_uuid.uuid == SERVICE_R1_R2_UUID
-
-    CONTEXT_WITH_SERVICE = copy.deepcopy(CONTEXT)
-    CONTEXT_WITH_SERVICE['service_ids'].append(SERVICE_R1_R2_ID)
-    response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_SERVICE))
-    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Check create event -----------------------------------------------------------------------------------------
-    events = events_collector.get_events(block=True, count=2)
-
-    assert isinstance(events[0], ServiceEvent)
-    assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    assert events[0].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert events[0].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
-
-    assert isinstance(events[1], ContextEvent)
-    assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    assert events[1].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Update the object ------------------------------------------------------------------------------------------
-    response = context_client_grpc.SetService(Service(**SERVICE_R1_R2))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.service_uuid.uuid == SERVICE_R1_R2_UUID
-
-    # ----- Check update event -----------------------------------------------------------------------------------------
-    event = events_collector.get_event(block=True)
-    assert isinstance(event, ServiceEvent)
-    assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    assert event.service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert event.service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
-
-    # ----- Dump state of database after create/update the object ------------------------------------------------------
-    db_entries = context_database.dump()
-    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
-    for db_entry in db_entries:
-        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
-    LOGGER.info('-----------------------------------------------------------')
-    assert len(db_entries) == 108
-
-    # ----- Get when the object exists ---------------------------------------------------------------------------------
-    response = context_client_grpc.GetService(ServiceId(**SERVICE_R1_R2_ID))
-    assert response.service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
-    assert response.service_type == ServiceTypeEnum.SERVICETYPE_L3NM
-    assert len(response.service_endpoint_ids) == 2
-    assert len(response.service_constraints) == 2
-    assert response.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_PLANNED
-    assert len(response.service_config.config_rules) == 3
-
-    # ----- List when the object exists --------------------------------------------------------------------------------
-    response = context_client_grpc.ListServiceIds(ContextId(**CONTEXT_ID))
-    assert len(response.service_ids) == 1
-    assert response.service_ids[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.service_ids[0].service_uuid.uuid == SERVICE_R1_R2_UUID
-
-    response = context_client_grpc.ListServices(ContextId(**CONTEXT_ID))
-    assert len(response.services) == 1
-    assert response.services[0].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.services[0].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
-    assert response.services[0].service_type == ServiceTypeEnum.SERVICETYPE_L3NM
-    assert len(response.services[0].service_endpoint_ids) == 2
-    assert len(response.services[0].service_constraints) == 2
-    assert response.services[0].service_status.service_status == ServiceStatusEnum.SERVICESTATUS_PLANNED
-    assert len(response.services[0].service_config.config_rules) == 3
-
-    # ----- Remove the object ------------------------------------------------------------------------------------------
-    context_client_grpc.RemoveService(ServiceId(**SERVICE_R1_R2_ID))
-    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R1_ID))
-    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R2_ID))
-    context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID))
-    context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID))
-
-    # ----- Check remove event -----------------------------------------------------------------------------------------
-    events = events_collector.get_events(block=True, count=5)
-
-    assert isinstance(events[0], ServiceEvent)
-    assert events[0].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert events[0].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
-
-    assert isinstance(events[1], DeviceEvent)
-    assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    assert events[1].device_id.device_uuid.uuid == DEVICE_R1_UUID
-
-    assert isinstance(events[2], DeviceEvent)
-    assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    assert events[2].device_id.device_uuid.uuid == DEVICE_R2_UUID
-
-    assert isinstance(events[3], TopologyEvent)
-    assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    assert events[3].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert events[3].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    assert isinstance(events[4], ContextEvent)
-    assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    assert events[4].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
-    events_collector.stop()
-
-    # ----- Dump state of database after remove the object -------------------------------------------------------------
-    db_entries = context_database.dump()
-    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
-    for db_entry in db_entries:
-        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
-    LOGGER.info('-----------------------------------------------------------')
-    assert len(db_entries) == 0
-"""
-
-"""
-def test_grpc_connection(
-    context_client_grpc : ContextClient,                # pylint: disable=redefined-outer-name
-    context_db_mb : Tuple[Database, MessageBroker]):    # pylint: disable=redefined-outer-name
-    Session = context_db_mb[0]
-
-    database = Database(Session)
-
-    # ----- Clean the database -----------------------------------------------------------------------------------------
-    database.clear()
-
-    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
-    events_collector = EventsCollector(context_client_grpc)
-    events_collector.start()
-
-    # ----- Prepare dependencies for the test and capture related events -----------------------------------------------
-    response = context_client_grpc.SetContext(Context(**CONTEXT))
-    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    response = context_client_grpc.SetTopology(Topology(**TOPOLOGY))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    response = context_client_grpc.SetDevice(Device(**DEVICE_R1))
-    assert response.device_uuid.uuid == DEVICE_R1_UUID
-
-    response = context_client_grpc.SetDevice(Device(**DEVICE_R2))
-    assert response.device_uuid.uuid == DEVICE_R2_UUID
-
-    response = context_client_grpc.SetDevice(Device(**DEVICE_R3))
-    assert response.device_uuid.uuid == DEVICE_R3_UUID
-
-    response = context_client_grpc.SetService(Service(**SERVICE_R1_R2))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.service_uuid.uuid == SERVICE_R1_R2_UUID
-
-    CONTEXT_WITH_SERVICE = copy.deepcopy(CONTEXT)
-    CONTEXT_WITH_SERVICE['service_ids'].append(SERVICE_R1_R2_ID)
-    response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_SERVICE))
-    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    response = context_client_grpc.SetService(Service(**SERVICE_R2_R3))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.service_uuid.uuid == SERVICE_R2_R3_UUID
-
-    CONTEXT_WITH_SERVICE = copy.deepcopy(CONTEXT)
-    CONTEXT_WITH_SERVICE['service_ids'].append(SERVICE_R2_R3_ID)
-    response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_SERVICE))
-    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    response = context_client_grpc.SetService(Service(**SERVICE_R1_R3))
-    assert response.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.service_uuid.uuid == SERVICE_R1_R3_UUID
-
-    CONTEXT_WITH_SERVICE = copy.deepcopy(CONTEXT)
-    CONTEXT_WITH_SERVICE['service_ids'].append(SERVICE_R1_R3_ID)
-    response = context_client_grpc.SetContext(Context(**CONTEXT_WITH_SERVICE))
-    assert response.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    events = events_collector.get_events(block=True, count=11)
-
-    assert isinstance(events[0], ContextEvent)
-    assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    assert events[0].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    assert isinstance(events[1], TopologyEvent)
-    assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    assert events[1].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert events[1].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    assert isinstance(events[2], DeviceEvent)
-    assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    assert events[2].device_id.device_uuid.uuid == DEVICE_R1_UUID
-
-    assert isinstance(events[3], DeviceEvent)
-    assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    assert events[3].device_id.device_uuid.uuid == DEVICE_R2_UUID
-
-    assert isinstance(events[4], DeviceEvent)
-    assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    assert events[4].device_id.device_uuid.uuid == DEVICE_R3_UUID
-
-    assert isinstance(events[5], ServiceEvent)
-    assert events[5].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    assert events[5].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert events[5].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
-
-    assert isinstance(events[6], ContextEvent)
-    assert events[6].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    assert events[6].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    assert isinstance(events[7], ServiceEvent)
-    assert events[7].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    assert events[7].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert events[7].service_id.service_uuid.uuid == SERVICE_R2_R3_UUID
-
-    assert isinstance(events[8], ContextEvent)
-    assert events[8].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    assert events[8].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    assert isinstance(events[9], ServiceEvent)
-    assert events[9].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    assert events[9].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert events[9].service_id.service_uuid.uuid == SERVICE_R1_R3_UUID
-
-    assert isinstance(events[10], ContextEvent)
-    assert events[10].event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    assert events[10].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Get when the object does not exist -------------------------------------------------------------------------
-    with pytest.raises(grpc.RpcError) as e:
-        context_client_grpc.GetConnection(ConnectionId(**CONNECTION_R1_R3_ID))
-    assert e.value.code() == grpc.StatusCode.NOT_FOUND
-    assert e.value.details() == 'Connection({:s}) not found'.format(CONNECTION_R1_R3_UUID)
-
-    # ----- List when the object does not exist ------------------------------------------------------------------------
-    response = context_client_grpc.ListConnectionIds(ServiceId(**SERVICE_R1_R3_ID))
-    assert len(response.connection_ids) == 0
-
-    response = context_client_grpc.ListConnections(ServiceId(**SERVICE_R1_R3_ID))
-    assert len(response.connections) == 0
-
-    # ----- Dump state of database before create the object ------------------------------------------------------------
-    db_entries = context_database.dump()
-    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
-    for db_entry in db_entries:
-        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
-    LOGGER.info('-----------------------------------------------------------')
-    assert len(db_entries) == 187
-
-    # ----- Create the object ------------------------------------------------------------------------------------------
-    with pytest.raises(grpc.RpcError) as e:
-        WRONG_CONNECTION = copy.deepcopy(CONNECTION_R1_R3)
-        WRONG_CONNECTION['path_hops_endpoint_ids'][0]\
-            ['topology_id']['context_id']['context_uuid']['uuid'] = 'wrong-context-uuid'
-        context_client_grpc.SetConnection(Connection(**WRONG_CONNECTION))
-    assert e.value.code() == grpc.StatusCode.NOT_FOUND
-    # TODO: should we check that all endpoints belong to same topology?
-    # TODO: should we check that endpoints form links over the topology?
-    msg = 'EndPoint({:s}/{:s}:wrong-context-uuid/{:s}) not found'.format(
-        DEVICE_R1_UUID, WRONG_CONNECTION['path_hops_endpoint_ids'][0]['endpoint_uuid']['uuid'], DEFAULT_TOPOLOGY_UUID)
-    assert e.value.details() == msg
-
-    response = context_client_grpc.SetConnection(Connection(**CONNECTION_R1_R3))
-    assert response.connection_uuid.uuid == CONNECTION_R1_R3_UUID
-
-    # ----- Check create event -----------------------------------------------------------------------------------------
-    event = events_collector.get_event(block=True)
-    assert isinstance(event, ConnectionEvent)
-    assert event.event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    assert event.connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID
-
-    # ----- Update the object ------------------------------------------------------------------------------------------
-    response = context_client_grpc.SetConnection(Connection(**CONNECTION_R1_R3))
-    assert response.connection_uuid.uuid == CONNECTION_R1_R3_UUID
-
-    # ----- Check update event -----------------------------------------------------------------------------------------
-    event = events_collector.get_event(block=True)
-    assert isinstance(event, ConnectionEvent)
-    assert event.event.event_type == EventTypeEnum.EVENTTYPE_UPDATE
-    assert event.connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID
-
-    # ----- Dump state of database after create/update the object ------------------------------------------------------
-    db_entries = context_database.dump()
-    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
-    for db_entry in db_entries:
-        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
-    LOGGER.info('-----------------------------------------------------------')
-    assert len(db_entries) == 203
-
-    # ----- Get when the object exists ---------------------------------------------------------------------------------
-    response = context_client_grpc.GetConnection(ConnectionId(**CONNECTION_R1_R3_ID))
-    assert response.connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID
-    assert response.service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert response.service_id.service_uuid.uuid == SERVICE_R1_R3_UUID
-    assert len(response.path_hops_endpoint_ids) == 6
-    assert len(response.sub_service_ids) == 2
-
-    # ----- List when the object exists --------------------------------------------------------------------------------
-    response = context_client_grpc.ListConnectionIds(ServiceId(**SERVICE_R1_R3_ID))
-    assert len(response.connection_ids) == 1
-    assert response.connection_ids[0].connection_uuid.uuid == CONNECTION_R1_R3_UUID
-
-    response = context_client_grpc.ListConnections(ServiceId(**SERVICE_R1_R3_ID))
-    assert len(response.connections) == 1
-    assert response.connections[0].connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID
-    assert len(response.connections[0].path_hops_endpoint_ids) == 6
-    assert len(response.connections[0].sub_service_ids) == 2
-
-    # ----- Remove the object ------------------------------------------------------------------------------------------
-    context_client_grpc.RemoveConnection(ConnectionId(**CONNECTION_R1_R3_ID))
-    context_client_grpc.RemoveService(ServiceId(**SERVICE_R1_R3_ID))
-    context_client_grpc.RemoveService(ServiceId(**SERVICE_R2_R3_ID))
-    context_client_grpc.RemoveService(ServiceId(**SERVICE_R1_R2_ID))
-    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R1_ID))
-    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R2_ID))
-    context_client_grpc.RemoveDevice(DeviceId(**DEVICE_R3_ID))
-    context_client_grpc.RemoveTopology(TopologyId(**TOPOLOGY_ID))
-    context_client_grpc.RemoveContext(ContextId(**CONTEXT_ID))
-
-    # ----- Check remove event -----------------------------------------------------------------------------------------
-    events = events_collector.get_events(block=True, count=9)
-
-    assert isinstance(events[0], ConnectionEvent)
-    assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    assert events[0].connection_id.connection_uuid.uuid == CONNECTION_R1_R3_UUID
-
-    assert isinstance(events[1], ServiceEvent)
-    assert events[1].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    assert events[1].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert events[1].service_id.service_uuid.uuid == SERVICE_R1_R3_UUID
-
-    assert isinstance(events[2], ServiceEvent)
-    assert events[2].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    assert events[2].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert events[2].service_id.service_uuid.uuid == SERVICE_R2_R3_UUID
-
-    assert isinstance(events[3], ServiceEvent)
-    assert events[3].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    assert events[3].service_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert events[3].service_id.service_uuid.uuid == SERVICE_R1_R2_UUID
-
-    assert isinstance(events[4], DeviceEvent)
-    assert events[4].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    assert events[4].device_id.device_uuid.uuid == DEVICE_R1_UUID
-
-    assert isinstance(events[5], DeviceEvent)
-    assert events[5].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    assert events[5].device_id.device_uuid.uuid == DEVICE_R2_UUID
-
-    assert isinstance(events[6], DeviceEvent)
-    assert events[6].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    assert events[6].device_id.device_uuid.uuid == DEVICE_R3_UUID
-
-    assert isinstance(events[7], TopologyEvent)
-    assert events[7].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    assert events[7].topology_id.context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-    assert events[7].topology_id.topology_uuid.uuid == DEFAULT_TOPOLOGY_UUID
-
-    assert isinstance(events[8], ContextEvent)
-    assert events[8].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    assert events[8].context_id.context_uuid.uuid == DEFAULT_CONTEXT_UUID
-
-    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
-    events_collector.stop()
-
-    # ----- Dump state of database after remove the object -------------------------------------------------------------
-    db_entries = context_database.dump()
-    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
-    for db_entry in db_entries:
-        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
-    LOGGER.info('-----------------------------------------------------------')
-    assert len(db_entries) == 0
-
-
-def test_grpc_policy(
-    context_client_grpc : ContextClient,                # pylint: disable=redefined-outer-name
-    context_db_mb : Tuple[Database, MessageBroker]):    # pylint: disable=redefined-outer-name
-    context_database = context_db_mb[0]
-
-    # ----- Clean the database -----------------------------------------------------------------------------------------
-    context_database.clear_all()
-
-    # ----- Initialize the EventsCollector -----------------------------------------------------------------------------
-    #events_collector = EventsCollector(context_client_grpc)
-    #events_collector.start()
-
-    # ----- Get when the object does not exist -------------------------------------------------------------------------
-    POLICY_ID = 'no-uuid'
-    DEFAULT_POLICY_ID = {'uuid': {'uuid': POLICY_ID}}
-
-    with pytest.raises(grpc.RpcError) as e:
-        context_client_grpc.GetPolicyRule(PolicyRuleId(**DEFAULT_POLICY_ID))
-
-    assert e.value.code() == grpc.StatusCode.NOT_FOUND
-    assert e.value.details() == 'PolicyRule({:s}) not found'.format(POLICY_ID)
-
-    # ----- List when the object does not exist ------------------------------------------------------------------------
-    response = context_client_grpc.ListPolicyRuleIds(Empty())
-    assert len(response.policyRuleIdList) == 0
-
-    response = context_client_grpc.ListPolicyRules(Empty())
-    assert len(response.policyRules) == 0
-
-    # ----- Dump state of database before create the object ------------------------------------------------------------
-    db_entries = context_database.dump()
-    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
-    for db_entry in db_entries:
-        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry))  # pragma: no cover
-    LOGGER.info('-----------------------------------------------------------')
-    assert len(db_entries) == 0
-
-    # ----- Create the object ------------------------------------------------------------------------------------------
-    response = context_client_grpc.SetPolicyRule(PolicyRule(**POLICY_RULE))
-    assert response.uuid.uuid == POLICY_RULE_UUID
-
-    # ----- Check create event -----------------------------------------------------------------------------------------
-    # events = events_collector.get_events(block=True, count=1)
-    # assert isinstance(events[0], PolicyEvent)
-    # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_CREATE
-    # assert events[0].policy_id.uuid.uuid == POLICY_RULE_UUID
-
-    # ----- Update the object ------------------------------------------------------------------------------------------
-    response = context_client_grpc.SetPolicyRule(PolicyRule(**POLICY_RULE))
-    assert response.uuid.uuid == POLICY_RULE_UUID
-
-    # ----- Dump state of database after create/update the object ------------------------------------------------------
-    db_entries = context_database.dump()
-    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
-    for db_entry in db_entries:
-        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
-    LOGGER.info('-----------------------------------------------------------')
-    assert len(db_entries) == 2
-
-    # ----- Get when the object exists ---------------------------------------------------------------------------------
-    response = context_client_grpc.GetPolicyRule(PolicyRuleId(**POLICY_RULE_ID))
-    assert response.device.policyRuleBasic.policyRuleId.uuid.uuid == POLICY_RULE_UUID
-
-    # ----- List when the object exists --------------------------------------------------------------------------------
-    response = context_client_grpc.ListPolicyRuleIds(Empty())
-    assert len(response.policyRuleIdList) == 1
-    assert response.policyRuleIdList[0].uuid.uuid == POLICY_RULE_UUID
-
-    response = context_client_grpc.ListPolicyRules(Empty())
-    assert len(response.policyRules) == 1
-
-    # ----- Remove the object ------------------------------------------------------------------------------------------
-    context_client_grpc.RemovePolicyRule(PolicyRuleId(**POLICY_RULE_ID))
-
-    # ----- Check remove event -----------------------------------------------------------------------------------------
-    # events = events_collector.get_events(block=True, count=2)
-
-    # assert isinstance(events[0], PolicyEvent)
-    # assert events[0].event.event_type == EventTypeEnum.EVENTTYPE_REMOVE
-    # assert events[0].policy_id.uuid.uuid == POLICY_RULE_UUID
-
-
-    # ----- Stop the EventsCollector -----------------------------------------------------------------------------------
-    # events_collector.stop()
-
-    # ----- Dump state of database after remove the object -------------------------------------------------------------
-    db_entries = context_database.dump()
-    LOGGER.info('----- Database Dump [{:3d} entries] -------------------------'.format(len(db_entries)))
-    for db_entry in db_entries:
-        LOGGER.info('  [{:>4s}] {:40s} :: {:s}'.format(*db_entry)) # pragma: no cover
-    LOGGER.info('-----------------------------------------------------------')
-    assert len(db_entries) == 0
-
-
-
-# ----- Test misc. Context internal tools ------------------------------------------------------------------------------
-
-def test_tools_fast_string_hasher():
-    with pytest.raises(TypeError) as e:
-        fast_hasher(27)
-    assert str(e.value) == "data(27) must be " + FASTHASHER_DATA_ACCEPTED_FORMAT + ", found <class 'int'>"
-
-    with pytest.raises(TypeError) as e:
-        fast_hasher({27})
-    assert str(e.value) == "data({27}) must be " + FASTHASHER_DATA_ACCEPTED_FORMAT + ", found <class 'set'>"
-
-    with pytest.raises(TypeError) as e:
-        fast_hasher({'27'})
-    assert str(e.value) == "data({'27'}) must be " + FASTHASHER_DATA_ACCEPTED_FORMAT + ", found <class 'set'>"
-
-    with pytest.raises(TypeError) as e:
-        fast_hasher([27])
-    assert str(e.value) == "data[0](27) must be " + FASTHASHER_ITEM_ACCEPTED_FORMAT + ", found <class 'int'>"
-
-    fast_hasher('hello-world')
-    fast_hasher('hello-world'.encode('UTF-8'))
-    fast_hasher(['hello', 'world'])
-    fast_hasher(('hello', 'world'))
-    fast_hasher(['hello'.encode('UTF-8'), 'world'.encode('UTF-8')])
-    fast_hasher(('hello'.encode('UTF-8'), 'world'.encode('UTF-8')))
-"""
\ No newline at end of file
+from ._test_context import grpc_context
+from ._test_topology import grpc_topology
+from ._test_device import grpc_device
+from ._test_link import grpc_link
+#from ._test_service import grpc_service
+#from ._test_slice import grpc_slice
+#from ._test_connection import grpc_connection
+#from ._test_policy import grpc_policy
+
+def test_grpc_context(context_client_grpc : ContextClient) -> None:
+    grpc_context(context_client_grpc)
+
+@pytest.mark.depends(on=['test_grpc_context'])
+def test_grpc_topology(context_client_grpc : ContextClient) -> None:
+    grpc_topology(context_client_grpc)
+
+@pytest.mark.depends(on=['test_grpc_topology'])
+def test_grpc_device(context_client_grpc : ContextClient) -> None:
+    grpc_device(context_client_grpc)
+
+@pytest.mark.depends(on=['test_grpc_device'])
+def test_grpc_link(context_client_grpc : ContextClient) -> None:
+    grpc_link(context_client_grpc)
+
+#@pytest.mark.depends(on=['test_grpc_link'])
+#def test_grpc_service(context_client_grpc : ContextClient) -> None:
+#    grpc_service(context_client_grpc)
+
+#@pytest.mark.depends(on=['test_grpc_service'])
+#def test_grpc_slice(context_client_grpc : ContextClient) -> None:
+#    grpc_slice(context_client_grpc)
+
+#@pytest.mark.depends(on=['test_grpc_slice'])
+#def test_grpc_connection(context_client_grpc : ContextClient) -> None:
+#    grpc_connection(context_client_grpc)
+
+#@pytest.mark.depends(on=['test_grpc_connection'])
+#def test_grpc_policy(context_client_grpc : ContextClient) -> None:
+#    grpc_policy(context_client_grpc)