diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1f6ceec4475f0354e59706f8c13ba02704bc53a1..b315409e5229df19dc4dddc7683e0f9927ba874f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,7 +4,8 @@ stages:
   - test
   - dependencies
   - deploy
-  - integration_test
+  - integration
+  - functional
 
 # include the individual .gitlab-ci.yml of each micro-service
 include: 
@@ -13,4 +14,5 @@ include:
   - local: '/src/context/.gitlab-ci.yml'
   - local: '/src/device/.gitlab-ci.yml'
   - local: '/src/service/.gitlab-ci.yml'
-  - local: '/src/integration_tester/.gitlab-ci.yml'
+  - local: '/src/tester_integration/.gitlab-ci.yml'
+  - local: '/src/tester_functional/.gitlab-ci.yml'
diff --git a/run_integration_tests.sh b/run_in_kubernetes.sh
similarity index 100%
rename from run_integration_tests.sh
rename to run_in_kubernetes.sh
diff --git a/run_local_tests.sh b/run_local_tests.sh
new file mode 100755
index 0000000000000000000000000000000000000000..59aef4c79f8e179e432db74b37cfc9cc01a201b2
--- /dev/null
+++ b/run_local_tests.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+cd $(dirname $0)/src
+RCFILE=~/teraflow/controller/coverage/.coveragerc
+COVERAGEFILE=~/teraflow/controller/coverage/.coverage
+
+# Run unitary tests and analyze coverage of code at same time
+
+# First destroy old coverage file
+rm -f $COVERAGEFILE
+
+coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
+    common/database/tests/test_unitary.py \
+    common/database/tests/test_engine_inmemory.py
+
+coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
+    context/tests/test_unitary.py
+
+coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
+    device/tests/test_unitary.py
+
+coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
+    service/tests/test_unitary.py
+
+# Run integration tests and analyze coverage of code at same time
+export DB_ENGINE='redis'
+export REDIS_SERVICE_HOST='10.1.7.194'
+export REDIS_SERVICE_PORT='31789'
+export REDIS_DATABASE_ID='0'
+coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
+    common/database/tests/test_engine_redis.py \
+    tester_integration/test_context_device_service.py
diff --git a/run_unitary_tests.sh b/run_unitary_tests.sh
deleted file mode 100755
index 766d9029232b8fb5db94cfb2a5507fb8270d4494..0000000000000000000000000000000000000000
--- a/run_unitary_tests.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/bin/bash
-
-cd $(dirname $0)/src
-RCFILE=~/teraflow/controller/coverage/.coveragerc
-
-# Run unitary tests and analyze coverage of code at same time
-coverage run --rcfile=$RCFILE -m pytest --log-level=DEBUG --verbose \
-    common/database/tests/test_unitary.py \
-    common/database/tests/test_engine_inmemory.py \
-    context/tests/test_unitary.py \
-    device/tests/test_unitary.py \
-    service/tests/test_unitary.py
-
-## Run integration tests and analyze coverage of code at same time
-#coverage run --rcfile=$RCFILE --append -m pytest --log-level=WARN --verbose \
-#    common/database/tests/test_integration_redis.py \
-#    device/tests/test_integration.py
diff --git a/src/common/database/api/context/service/Constraint.py b/src/common/database/api/context/service/Constraint.py
index 327c2dc8ba9df6aae4aac23cf959bc5d5f8d6d13..866f98c1761ba399a3d27fc440524515626a019d 100644
--- a/src/common/database/api/context/service/Constraint.py
+++ b/src/common/database/api/context/service/Constraint.py
@@ -57,7 +57,6 @@ class Constraint(_Entity):
 
     def dump(self) -> Dict:
         attributes = self.attributes.get()
-        return {
-            'constraint_type': self.constraint_type,
-            'constraint_value': attributes.get('constraint_value', None),
-        }
+        result = self.dump_id()
+        result.update({'constraint_value': attributes.get('constraint_value', None)})
+        return result
diff --git a/src/common/tools/service/ServiceCheckers.py b/src/common/tools/service/ServiceCheckers.py
index 8026533bf9875d15a0a734ff7a063745e6d304c9..d8bafd1c03db0b1b330633062456752da7cd93c9 100644
--- a/src/common/tools/service/ServiceCheckers.py
+++ b/src/common/tools/service/ServiceCheckers.py
@@ -3,15 +3,27 @@ from common.database.api.Database import Database
 from common.exceptions.ServiceException import ServiceException
 
 def check_service_exists(database : Database, context_id : str, service_id : str):
-    db_context = database.context(context_id).create()
+    if not database.contexts.contains(context_id):
+        msg = 'Context({}) does not exist in the database.'
+        msg = msg.format(context_id)
+        raise ServiceException(grpc.StatusCode.NOT_FOUND, msg)
+
+    db_context = database.context(context_id)
     if db_context.services.contains(service_id): return
+
     msg = 'Context({})/Service({}) does not exist in the database.'
     msg = msg.format(context_id, service_id)
     raise ServiceException(grpc.StatusCode.NOT_FOUND, msg)
 
 def check_service_not_exists(database : Database, context_id : str, service_id : str):
-    db_context = database.context(context_id).create()
+    if not database.contexts.contains(context_id):
+        msg = 'Context({}) does not exist in the database.'
+        msg = msg.format(context_id)
+        raise ServiceException(grpc.StatusCode.NOT_FOUND, msg)
+
+    db_context = database.context(context_id)
     if not db_context.services.contains(service_id): return
+
     msg = 'Context({})/Service({}) already exists in the database.'
     msg = msg.format(context_id, service_id)
     raise ServiceException(grpc.StatusCode.ALREADY_EXISTS, msg)
diff --git a/src/context/tests/test_unitary.py b/src/context/tests/test_unitary.py
index c82f62d202b96bcf9ec787e7124a6825bfbc33e1..4827488a77846cc50d08c54e4bf06f5a6ba4c51c 100644
--- a/src/context/tests/test_unitary.py
+++ b/src/context/tests/test_unitary.py
@@ -2,38 +2,28 @@ import copy, grpc, logging, pytest
 from google.protobuf.json_format import MessageToDict
 from common.database.Factory import get_database, DatabaseEngineEnum
 from common.database.api.Database import Database
+from common.database.api.context.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
 from common.database.tests.script import populate_example
-from common.tests.Assertions import validate_empty, validate_link_id, validate_topology
+from common.tests.Assertions import validate_empty, validate_link_id, validate_topology, validate_topology_has_devices, validate_topology_has_links, validate_topology_is_empty
 from context.client.ContextClient import ContextClient
 from context.proto.context_pb2 import Empty, Link, LinkId
 from context.service.ContextService import ContextService
 from context.Config import GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD
 
-port = 10000 + GRPC_SERVICE_PORT # avoid first 1024 privileged ports to avoid evelating permissions for tests
+port = 10000 + GRPC_SERVICE_PORT # avoid privileged ports
 
 LOGGER = logging.getLogger(__name__)
 LOGGER.setLevel(logging.DEBUG)
 
+# use "copy.deepcopy" to prevent propagating forced changes during tests
+CONTEXT_ID = {'contextUuid': {'uuid': DEFAULT_CONTEXT_ID}}
+TOPOLOGY_ID = {'contextId': copy.deepcopy(CONTEXT_ID), 'topoId': {'uuid': DEFAULT_TOPOLOGY_ID}}
 LINK_ID = {'link_id': {'uuid': 'DEV1/EP2 ==> DEV2/EP1'}}
 LINK = {
     'link_id': {'link_id': {'uuid': 'DEV1/EP2 ==> DEV2/EP1'}},
     'endpointList' : [
-        {
-            'topoId': {
-                'contextId': {'contextUuid': {'uuid': 'admin'}},
-                'topoId': {'uuid': 'admin'}
-            },
-            'dev_id': {'device_id': {'uuid': 'DEV1'}},
-            'port_id': {'uuid' : 'EP2'}
-        },
-        {
-            'topoId': {
-                'contextId': {'contextUuid': {'uuid': 'admin'}},
-                'topoId': {'uuid': 'admin'}
-            },
-            'dev_id': {'device_id': {'uuid': 'DEV2'}},
-            'port_id': {'uuid' : 'EP1'}
-        },
+        {'topoId': copy.deepcopy(TOPOLOGY_ID), 'dev_id': {'device_id': {'uuid': 'DEV1'}}, 'port_id': {'uuid' : 'EP2'}},
+        {'topoId': copy.deepcopy(TOPOLOGY_ID), 'dev_id': {'device_id': {'uuid': 'DEV2'}}, 'port_id': {'uuid' : 'EP1'}},
     ]
 }
 
@@ -59,7 +49,7 @@ def context_client(context_service):
 def test_get_topology_empty(context_client : ContextClient, context_database : Database):
     # should work
     context_database.clear_all()
-    validate_topology(MessageToDict(
+    validate_topology_is_empty(MessageToDict(
         context_client.GetTopology(Empty()),
         including_default_value_fields=True, preserving_proto_field_name=True,
         use_integers_for_enums=False))
@@ -67,10 +57,13 @@ def test_get_topology_empty(context_client : ContextClient, context_database : D
 def test_get_topology_completed(context_client : ContextClient, context_database : Database):
     # should work
     populate_example(context_database, add_services=False)
-    validate_topology(MessageToDict(
+    topology = MessageToDict(
         context_client.GetTopology(Empty()),
         including_default_value_fields=True, preserving_proto_field_name=True,
-        use_integers_for_enums=False))
+        use_integers_for_enums=False)
+    validate_topology(topology)
+    validate_topology_has_devices(topology)
+    validate_topology_has_links(topology)
 
 def test_delete_link_empty_uuid(context_client : ContextClient):
     # should fail with link not found
@@ -227,7 +220,10 @@ def test_add_link_default_endpoint_context_topology(context_client : ContextClie
 
 def test_get_topology_completed_2(context_client : ContextClient):
     # should work
-    validate_topology(MessageToDict(
+    topology = MessageToDict(
         context_client.GetTopology(Empty()),
         including_default_value_fields=True, preserving_proto_field_name=True,
-        use_integers_for_enums=False))
+        use_integers_for_enums=False)
+    validate_topology(topology)
+    validate_topology_has_devices(topology)
+    validate_topology_has_links(topology)
diff --git a/src/device/tests/test_unitary.py b/src/device/tests/test_unitary.py
index 773da58bcbb18b2c6a91416a365fa5bf18a98c04..95eb0a1af27433ddd85d100160cd122aebc60b8a 100644
--- a/src/device/tests/test_unitary.py
+++ b/src/device/tests/test_unitary.py
@@ -1,6 +1,7 @@
 import copy, grpc, logging, pytest
 from google.protobuf.json_format import MessageToDict
 from common.database.Factory import get_database, DatabaseEngineEnum
+from common.database.api.context.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
 from common.database.api.context.topology.device.OperationalStatus import OperationalStatus
 from common.tests.Assertions import validate_device_id, validate_empty
 from device.client.DeviceClient import DeviceClient
@@ -8,47 +9,31 @@ from device.proto.context_pb2 import Device, DeviceId
 from device.service.DeviceService import DeviceService
 from device.Config import GRPC_SERVICE_PORT, GRPC_MAX_WORKERS, GRPC_GRACE_PERIOD
 
+port = 10000 + GRPC_SERVICE_PORT # avoid privileged ports
+
 LOGGER = logging.getLogger(__name__)
 LOGGER.setLevel(logging.DEBUG)
 
+# use "copy.deepcopy" to prevent propagating forced changes during tests
+CONTEXT_ID = {'contextUuid': {'uuid': DEFAULT_CONTEXT_ID}}
+TOPOLOGY_ID = {'contextId': copy.deepcopy(CONTEXT_ID), 'topoId': {'uuid': DEFAULT_TOPOLOGY_ID}}
 DEVICE_ID = {'device_id': {'uuid': 'DEV1'}}
 DEVICE = {
-    'device_id': {'device_id': {'uuid': 'DEV1'}},
+    'device_id': copy.deepcopy(DEVICE_ID),
     'device_type': 'ROADM',
     'device_config': {'device_config': '<config/>'},
     'devOperationalStatus': OperationalStatus.ENABLED.value,
     'endpointList' : [
         {
-            'port_id': {
-                'topoId': {
-                    'contextId': {'contextUuid': {'uuid': 'admin'}},
-                    'topoId': {'uuid': 'admin'}
-                },
-                'dev_id': {'device_id': {'uuid': 'DEV1'}},
-                'port_id': {'uuid' : 'EP2'}
-            },
+            'port_id': {'topoId': copy.deepcopy(TOPOLOGY_ID), 'dev_id': copy.deepcopy(DEVICE_ID), 'port_id': {'uuid' : 'EP2'}},
             'port_type': 'WDM'
         },
         {
-            'port_id': {
-                'topoId': {
-                    'contextId': {'contextUuid': {'uuid': 'admin'}},
-                    'topoId': {'uuid': 'admin'}
-                },
-                'dev_id': {'device_id': {'uuid': 'DEV1'}},
-                'port_id': {'uuid' : 'EP3'}
-            },
+            'port_id': {'topoId': copy.deepcopy(TOPOLOGY_ID), 'dev_id': copy.deepcopy(DEVICE_ID), 'port_id': {'uuid' : 'EP3'}},
             'port_type': 'WDM'
         },
         {
-            'port_id': {
-                'topoId': {
-                    'contextId': {'contextUuid': {'uuid': 'admin'}},
-                    'topoId': {'uuid': 'admin'}
-                },
-                'dev_id': {'device_id': {'uuid': 'DEV1'}},
-                'port_id': {'uuid' : 'EP4'}
-            },
+            'port_id': {'topoId': copy.deepcopy(TOPOLOGY_ID), 'dev_id': copy.deepcopy(DEVICE_ID), 'port_id': {'uuid' : 'EP4'}},
             'port_type': 'WDM'
         },
     ]
@@ -62,14 +47,14 @@ def device_database():
 @pytest.fixture(scope='session')
 def device_service(device_database):
     _service = DeviceService(
-        device_database, port=GRPC_SERVICE_PORT, max_workers=GRPC_MAX_WORKERS, grace_period=GRPC_GRACE_PERIOD)
+        device_database, port=port, max_workers=GRPC_MAX_WORKERS, grace_period=GRPC_GRACE_PERIOD)
     _service.start()
     yield _service
     _service.stop()
 
 @pytest.fixture(scope='session')
 def device_client(device_service):
-    _client = DeviceClient(address='127.0.0.1', port=GRPC_SERVICE_PORT)
+    _client = DeviceClient(address='127.0.0.1', port=port)
     yield _client
     _client.close()
 
diff --git a/src/integration_tester/definitions.py b/src/integration_tester/definitions.py
deleted file mode 100644
index 768b84cd2498f5cf7dda636d77a330c02d9837c7..0000000000000000000000000000000000000000
--- a/src/integration_tester/definitions.py
+++ /dev/null
@@ -1,148 +0,0 @@
-from common.database.api.context.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
-from common.database.api.context.service.ServiceState import ServiceState
-from common.database.api.context.service.ServiceType import ServiceType
-from common.database.api.context.topology.device.OperationalStatus import OperationalStatus
-
-CONTEXT_ID = {'contextUuid': {'uuid': DEFAULT_CONTEXT_ID}}
-
-TOPOLOGY_ID = {'contextId': CONTEXT_ID, 'topoId': {'uuid': DEFAULT_TOPOLOGY_ID}}
-
-DEVICE_ID_DEV1 = {'device_id': {'uuid': 'dev1'}}
-DEVICE_DEV1 = {
-    'device_id': DEVICE_ID_DEV1, 'device_type': 'ROADM', 'device_config': {'device_config': '<config/>'},
-    'devOperationalStatus': OperationalStatus.ENABLED.value,
-    'endpointList' : [
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV1, 'port_id': {'uuid' : 'port2'}}, 'port_type': 'WDM'},
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV1, 'port_id': {'uuid' : 'port3'}}, 'port_type': 'WDM'},
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV1, 'port_id': {'uuid' : 'port101'}}, 'port_type': 'OCH'},
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV1, 'port_id': {'uuid' : 'port102'}}, 'port_type': 'OCH'},
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV1, 'port_id': {'uuid' : 'port103'}}, 'port_type': 'OCH'},
-    ]
-}
-
-DEVICE_ID_DEV2 = {'device_id': {'uuid': 'dev2'}}
-DEVICE_DEV2 = {
-    'device_id': DEVICE_ID_DEV2, 'device_type': 'ROADM', 'device_config': {'device_config': '<config/>'},
-    'devOperationalStatus': OperationalStatus.ENABLED.value,
-    'endpointList' : [
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV2, 'port_id': {'uuid' : 'port1'}}, 'port_type': 'WDM'},
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV2, 'port_id': {'uuid' : 'port3'}}, 'port_type': 'WDM'},
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV2, 'port_id': {'uuid' : 'port101'}}, 'port_type': 'OCH'},
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV2, 'port_id': {'uuid' : 'port102'}}, 'port_type': 'OCH'},
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV2, 'port_id': {'uuid' : 'port103'}}, 'port_type': 'OCH'},
-    ]
-}
-
-DEVICE_ID_DEV3 = {'device_id': {'uuid': 'dev3'}}
-DEVICE_DEV3 = {
-    'device_id': DEVICE_ID_DEV3,
-    'device_type': 'ROADM',
-    'device_config': {'device_config': '<config/>'},
-    'devOperationalStatus': OperationalStatus.ENABLED.value,
-    'endpointList' : [
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV3, 'port_id': {'uuid' : 'port1'}}, 'port_type': 'WDM'},
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV3, 'port_id': {'uuid' : 'port2'}}, 'port_type': 'WDM'},
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV3, 'port_id': {'uuid' : 'port101'}}, 'port_type': 'OCH'},
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV3, 'port_id': {'uuid' : 'port102'}}, 'port_type': 'OCH'},
-        {'port_id': {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV3, 'port_id': {'uuid' : 'port103'}}, 'port_type': 'OCH'},
-    ]
-}
-
-LINK_ID_DEV1_DEV2 = {'link_id': {'uuid': 'dev1/port2 ==> dev2/port1'}}
-LINK_DEV1_DEV2 = {
-    'link_id': LINK_ID_DEV1_DEV2,
-    'endpointList' : [
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV1, 'port_id': {'uuid' : 'port2'}},
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV2, 'port_id': {'uuid' : 'port1'}},
-    ]
-}
-
-LINK_ID_DEV1_DEV3 = {'link_id': {'uuid': 'dev1/port3 ==> dev3/port1'}}
-LINK_DEV1_DEV3 = {
-    'link_id': LINK_ID_DEV1_DEV3,
-    'endpointList' : [
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV1, 'port_id': {'uuid' : 'port3'}},
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV3, 'port_id': {'uuid' : 'port1'}},
-    ]
-}
-
-LINK_ID_DEV2_DEV1 = {'link_id': {'uuid': 'dev2/port1 ==> dev1/port2'}}
-LINK_DEV2_DEV1 = {
-    'link_id': LINK_ID_DEV2_DEV1,
-    'endpointList' : [
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV2, 'port_id': {'uuid' : 'port1'}},
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV1, 'port_id': {'uuid' : 'port2'}},
-    ]
-}
-
-LINK_ID_DEV2_DEV3 = {'link_id': {'uuid': 'dev2/port3 ==> dev3/port2'}}
-LINK_DEV2_DEV3 = {
-    'link_id': LINK_ID_DEV2_DEV3,
-    'endpointList' : [
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV2, 'port_id': {'uuid' : 'port3'}},
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV3, 'port_id': {'uuid' : 'port2'}},
-    ]
-}
-
-LINK_ID_DEV3_DEV1 = {'link_id': {'uuid': 'dev3/port1 ==> dev1/port3'}}
-LINK_DEV3_DEV1 = {
-    'link_id': LINK_ID_DEV3_DEV1,
-    'endpointList' : [
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV3, 'port_id': {'uuid' : 'port1'}},
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV1, 'port_id': {'uuid' : 'port3'}},
-    ]
-}
-
-LINK_ID_DEV3_DEV2 = {'link_id': {'uuid': 'dev3/port2 ==> dev2/port3'}}
-LINK_DEV3_DEV2 = {
-    'link_id': LINK_ID_DEV3_DEV2,
-    'endpointList' : [
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV3, 'port_id': {'uuid' : 'port2'}},
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV2, 'port_id': {'uuid' : 'port3'}},
-    ]
-}
-
-SERVICE_ID_SVC1 = {'contextId': CONTEXT_ID, 'cs_id': {'uuid': 'svc1'}}
-SERVICE_SVC1 = {
-    'cs_id': SERVICE_ID_SVC1, 'serviceType': ServiceType.L3NM.value, 'serviceConfig': {'serviceConfig': '<config/>'},
-    'serviceState': {'serviceState': ServiceState.PLANNED.value},
-    'constraint': [
-        {'constraint_type': 'latency_ms', 'constraint_value': '100'},
-        {'constraint_type': 'hops', 'constraint_value': '5'},
-    ],
-    'endpointList' : [
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV1, 'port_id': {'uuid' : 'port101'}},
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV2, 'port_id': {'uuid' : 'port101'}},
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV3, 'port_id': {'uuid' : 'port101'}},
-    ]
-}
-
-SERVICE_ID_SVC2 = {'contextId': CONTEXT_ID, 'cs_id': {'uuid': 'svc2'}}
-SERVICE_SVC2 = {
-    'cs_id': SERVICE_ID_SVC2, 'serviceType': ServiceType.L3NM.value, 'serviceConfig': {'serviceConfig': '<config/>'},
-    'serviceState': {'serviceState': ServiceState.PLANNED.value},
-    'constraint': [
-        {'constraint_type': 'latency_ms', 'constraint_value': '100'},
-        {'constraint_type': 'hops', 'constraint_value': '5'},
-    ],
-    'endpointList' : [
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV1, 'port_id': {'uuid' : 'port102'}},
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV2, 'port_id': {'uuid' : 'port102'}},
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV3, 'port_id': {'uuid' : 'port102'}},
-    ]
-}
-
-SERVICE_ID_SVC3 = {'contextId': CONTEXT_ID, 'cs_id': {'uuid': 'svc3'}}
-SERVICE_SVC3 = {
-    'cs_id': SERVICE_ID_SVC3, 'serviceType': ServiceType.L3NM.value, 'serviceConfig': {'serviceConfig': '<config/>'},
-    'serviceState': {'serviceState': ServiceState.PLANNED.value},
-    'constraint': [
-        {'constraint_type': 'latency_ms', 'constraint_value': '100'},
-        {'constraint_type': 'hops', 'constraint_value': '5'},
-    ],
-    'endpointList' : [
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV1, 'port_id': {'uuid' : 'port103'}},
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV2, 'port_id': {'uuid' : 'port103'}},
-        {'topoId': TOPOLOGY_ID, 'dev_id': DEVICE_ID_DEV3, 'port_id': {'uuid' : 'port103'}},
-    ]
-}
diff --git a/src/service/tests/test_unitary.py b/src/service/tests/test_unitary.py
index 800de71dac6e6ad9072d081c849095361ed1ffb1..48d56af038b226caa2ffe6a73b71509f4c011ad1 100644
--- a/src/service/tests/test_unitary.py
+++ b/src/service/tests/test_unitary.py
@@ -2,6 +2,7 @@ import copy, grpc, logging, pytest
 from google.protobuf.json_format import MessageToDict
 from common.database.Factory import get_database, DatabaseEngineEnum
 from common.database.api.Database import Database
+from common.database.api.context.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
 from common.database.tests.script import populate_example
 from common.tests.Assertions import validate_empty, validate_service, validate_service_id, \
     validate_service_list_is_empty, validate_service_list_is_not_empty
@@ -11,15 +12,17 @@ from service.proto.context_pb2 import Empty
 from service.proto.service_pb2 import Service, ServiceId, ServiceStateEnum, ServiceType
 from service.service.ServiceService import ServiceService
 
+port = 10000 + GRPC_SERVICE_PORT # avoid privileged ports
+
 LOGGER = logging.getLogger(__name__)
 LOGGER.setLevel(logging.DEBUG)
 
-SERVICE_ID = {
-    'contextId': {'contextUuid': {'uuid': 'admin'}},
-    'cs_id': {'uuid': 'DEV1'},
-}
+# use "copy.deepcopy" to prevent propagating forced changes during tests
+CONTEXT_ID = {'contextUuid': {'uuid': DEFAULT_CONTEXT_ID}}
+TOPOLOGY_ID = {'contextId': copy.deepcopy(CONTEXT_ID), 'topoId': {'uuid': DEFAULT_TOPOLOGY_ID}}
+SERVICE_ID = {'contextId': copy.deepcopy(CONTEXT_ID), 'cs_id': {'uuid': 'DEV1'}}
 SERVICE = {
-    'cs_id': SERVICE_ID,
+    'cs_id': copy.deepcopy(SERVICE_ID),
     'serviceType': ServiceType.L3NM,
     'serviceConfig': {'serviceConfig': '<config/>'},
     'serviceState': {'serviceState': ServiceStateEnum.PLANNED},
@@ -28,30 +31,9 @@ SERVICE = {
         {'constraint_type': 'hops', 'constraint_value': '5'},
     ],
     'endpointList' : [
-        {
-            'topoId': {
-                'contextId': {'contextUuid': {'uuid': 'admin'}},
-                'topoId': {'uuid': 'admin'}
-            },
-            'dev_id': {'device_id': {'uuid': 'DEV1'}},
-            'port_id': {'uuid' : 'EP5'}
-        },
-        {
-            'topoId': {
-                'contextId': {'contextUuid': {'uuid': 'admin'}},
-                'topoId': {'uuid': 'admin'}
-            },
-            'dev_id': {'device_id': {'uuid': 'DEV2'}},
-            'port_id': {'uuid' : 'EP5'}
-        },
-        {
-            'topoId': {
-                'contextId': {'contextUuid': {'uuid': 'admin'}},
-                'topoId': {'uuid': 'admin'}
-            },
-            'dev_id': {'device_id': {'uuid': 'DEV3'}},
-            'port_id': {'uuid' : 'EP5'}
-        },
+        {'topoId': copy.deepcopy(TOPOLOGY_ID), 'dev_id': {'device_id': {'uuid': 'DEV1'}}, 'port_id': {'uuid' : 'EP5'}},
+        {'topoId': copy.deepcopy(TOPOLOGY_ID), 'dev_id': {'device_id': {'uuid': 'DEV2'}}, 'port_id': {'uuid' : 'EP5'}},
+        {'topoId': copy.deepcopy(TOPOLOGY_ID), 'dev_id': {'device_id': {'uuid': 'DEV3'}}, 'port_id': {'uuid' : 'EP5'}},
     ]
 }
 
@@ -64,14 +46,14 @@ def database():
 @pytest.fixture(scope='session')
 def service_service(database):
     _service = ServiceService(
-        database, port=GRPC_SERVICE_PORT, max_workers=GRPC_MAX_WORKERS, grace_period=GRPC_GRACE_PERIOD)
+        database, port=port, max_workers=GRPC_MAX_WORKERS, grace_period=GRPC_GRACE_PERIOD)
     _service.start()
     yield _service
     _service.stop()
 
 @pytest.fixture(scope='session')
 def service_client(service_service):
-    _client = ServiceClient(address='127.0.0.1', port=GRPC_SERVICE_PORT)
+    _client = ServiceClient(address='127.0.0.1', port=port)
     yield _client
     _client.close()
 
@@ -92,6 +74,15 @@ def test_create_service_wrong_service_attributes(service_client : ServiceClient)
     msg = 'service.cs_id.contextId.contextUuid.uuid() string is empty.'
     assert e.value.details() == msg
 
+    # should fail with service context does not exist
+    with pytest.raises(grpc._channel._InactiveRpcError) as e:
+        copy_service = copy.deepcopy(SERVICE)
+        copy_service['cs_id']['contextId']['contextUuid']['uuid'] = 'wrong-context'
+        service_client.CreateService(Service(**copy_service))
+    assert e.value.code() == grpc.StatusCode.NOT_FOUND
+    msg = 'Context(wrong-context) does not exist in the database.'
+    assert e.value.details() == msg
+
     # should fail with wrong service id
     with pytest.raises(grpc._channel._InactiveRpcError) as e:
         copy_service = copy.deepcopy(SERVICE)
@@ -155,11 +146,12 @@ def test_create_service_wrong_constraint(service_client : ServiceClient):
     msg = 'Duplicated ConstraintType(latency_ms) in Constraint(#1) of Context(admin)/Service(DEV1).'
     assert e.value.details() == msg
 
-def test_create_service_wrong_endpoint(service_client : ServiceClient):
+def test_create_service_wrong_endpoint(service_client : ServiceClient, database : Database):
     # should fail with wrong endpoint context
     with pytest.raises(grpc._channel._InactiveRpcError) as e:
         copy_service = copy.deepcopy(SERVICE)
         copy_service['endpointList'][0]['topoId']['contextId']['contextUuid']['uuid'] = 'wrong-context'
+        print(copy_service)
         service_client.CreateService(Service(**copy_service))
     assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
     msg = ' '.join([
@@ -169,7 +161,7 @@ def test_create_service_wrong_endpoint(service_client : ServiceClient):
     ])
     assert e.value.details() == msg
 
-    # should fail with endpoint topology not found
+    # should fail with wrong endpoint topology
     with pytest.raises(grpc._channel._InactiveRpcError) as e:
         copy_service = copy.deepcopy(SERVICE)
         copy_service['endpointList'][0]['topoId']['topoId']['uuid'] = 'wrong-topo'
@@ -234,6 +226,15 @@ def test_create_service_wrong_endpoint(service_client : ServiceClient):
     assert e.value.details() == msg
 
 def test_get_service_does_not_exist(service_client : ServiceClient):
+    # should fail with service context does not exist
+    with pytest.raises(grpc._channel._InactiveRpcError) as e:
+        copy_service_id = copy.deepcopy(SERVICE_ID)
+        copy_service_id['contextId']['contextUuid']['uuid'] = 'wrong-context'
+        service_client.GetServiceById(ServiceId(**copy_service_id))
+    assert e.value.code() == grpc.StatusCode.NOT_FOUND
+    msg = 'Context(wrong-context) does not exist in the database.'
+    assert e.value.details() == msg
+
     # should fail with service does not exist
     with pytest.raises(grpc._channel._InactiveRpcError) as e:
         service_client.GetServiceById(ServiceId(**SERVICE_ID))
@@ -298,7 +299,25 @@ def test_update_service(service_client : ServiceClient):
         use_integers_for_enums=False))
 
 def test_delete_service_wrong_service_id(service_client : ServiceClient):
-    # should fail with wrong service id / context
+    # should fail with service context is empty
+    with pytest.raises(grpc._channel._InactiveRpcError) as e:
+        copy_service_id = copy.deepcopy(SERVICE_ID)
+        copy_service_id['contextId']['contextUuid']['uuid'] = ''
+        service_client.DeleteService(ServiceId(**copy_service_id))
+    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
+    msg = 'service_id.contextId.contextUuid.uuid() string is empty.'
+    assert e.value.details() == msg
+
+    # should fail with service context does not exist
+    with pytest.raises(grpc._channel._InactiveRpcError) as e:
+        copy_service_id = copy.deepcopy(SERVICE_ID)
+        copy_service_id['contextId']['contextUuid']['uuid'] = 'wrong-context'
+        service_client.DeleteService(ServiceId(**copy_service_id))
+    assert e.value.code() == grpc.StatusCode.NOT_FOUND
+    msg = 'Context(wrong-context) does not exist in the database.'
+    assert e.value.details() == msg
+
+    # should fail with service id is empty
     with pytest.raises(grpc._channel._InactiveRpcError) as e:
         copy_service_id = copy.deepcopy(SERVICE_ID)
         copy_service_id['cs_id']['uuid'] = ''
@@ -307,12 +326,13 @@ def test_delete_service_wrong_service_id(service_client : ServiceClient):
     msg = 'service_id.cs_id.uuid() string is empty.'
     assert e.value.details() == msg
 
+    # should fail with service id is empty
     with pytest.raises(grpc._channel._InactiveRpcError) as e:
         copy_service_id = copy.deepcopy(SERVICE_ID)
-        copy_service_id['contextId']['contextUuid']['uuid'] = ''
+        copy_service_id['cs_id']['uuid'] = 'wrong-service'
         service_client.DeleteService(ServiceId(**copy_service_id))
-    assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT
-    msg = 'service_id.contextId.contextUuid.uuid() string is empty.'
+    assert e.value.code() == grpc.StatusCode.NOT_FOUND
+    msg = 'Context(admin)/Service(wrong-service) does not exist in the database.'
     assert e.value.details() == msg
 
 def test_delete_service(service_client : ServiceClient):
diff --git a/src/integration_tester/.gitlab-ci.yml b/src/tester_functional/.gitlab-ci.yml
similarity index 81%
rename from src/integration_tester/.gitlab-ci.yml
rename to src/tester_functional/.gitlab-ci.yml
index 045b235d3aea7a7e56deedc3e60bf0dcab4dca13..d90552d2d14b4bdcf271764ee34c7ef6d8d964b8 100644
--- a/src/integration_tester/.gitlab-ci.yml
+++ b/src/tester_functional/.gitlab-ci.yml
@@ -1,7 +1,7 @@
 # Build, tag, and push the Docker images to the GitLab Docker registry
-build integration_tester:
+build tester_functional:
   variables:
-    IMAGE_NAME: 'integration_tester' # name of the microservice
+    IMAGE_NAME: 'tester_functional' # name of the microservice
     IMAGE_TAG: 'latest' # tag of the container image (production, development, etc)
   stage: build
   before_script:
@@ -20,13 +20,13 @@ build integration_tester:
       - .gitlab-ci.yml
 
 # Pull, execute, and run unitary tests for the Docker image from the GitLab registry
-test integration_tester:
+test tester_functional:
   variables:
-    IMAGE_NAME: 'integration_tester' # name of the microservice
+    IMAGE_NAME: 'tester_functional' # name of the microservice
     IMAGE_TAG: 'latest' # tag of the container image (production, development, etc)
   stage: test
   needs:
-    - build integration_tester
+    - build tester_functional
   before_script:
     - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
   script:
@@ -40,15 +40,15 @@ test integration_tester:
       - src/$IMAGE_NAME/**
       - .gitlab-ci.yml
 
-# Run integration tests in Kubernetes Cluster
-integration_test integration_tester:
+# Run functional tests in Kubernetes Cluster
+functional tester_functional:
   variables:
-    IMAGE_NAME: 'integration_tester' # name of the microservice
+    IMAGE_NAME: 'tester_functional' # name of the microservice
     IMAGE_TAG: 'latest' # tag of the container image (production, development, etc)
-  stage: integration_test
+  stage: functional
   needs:
-    - build integration_tester
-    - test integration_tester
+    - build tester_functional
+    - test tester_functional
     - deploy context
     - deploy device
     - deploy service
diff --git a/src/tester_functional/Dockerfile b/src/tester_functional/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..36883f30bf76fbee7094ee9c5dbe626c6fdec071
--- /dev/null
+++ b/src/tester_functional/Dockerfile
@@ -0,0 +1,35 @@
+FROM python:3-slim
+
+# Install dependencies
+RUN apt-get --yes --quiet --quiet update && \
+    apt-get --yes --quiet --quiet install wget g++ && \
+    rm -rf /var/lib/apt/lists/*
+
+# Set Python to show logs as they occur
+ENV PYTHONUNBUFFERED=0
+
+# Get generic Python packages
+RUN python3 -m pip install --upgrade pip setuptools wheel pip-tools
+
+# Set working directory
+WORKDIR /var/teraflow
+
+# Create module sub-folders
+RUN mkdir -p /var/teraflow/tester_functional
+
+# Get Python packages per module
+COPY tester_functional/requirements.in tester_functional/requirements.in
+RUN pip-compile --output-file=tester_functional/requirements.txt tester_functional/requirements.in
+RUN python3 -m pip install -r tester_functional/requirements.in
+
+# Add files into working directory
+COPY common/. common
+COPY context/. context
+COPY device/. device
+COPY service/. service
+COPY tester_functional/. tester_functional
+
+# Run integration tester
+ENTRYPOINT ["pytest", "-v", "--log-level=DEBUG", \
+            "tester_functional/test_context_device_service.py" \
+]
diff --git a/src/integration_tester/__init__.py b/src/tester_functional/__init__.py
similarity index 100%
rename from src/integration_tester/__init__.py
rename to src/tester_functional/__init__.py
diff --git a/src/tester_functional/definitions.py b/src/tester_functional/definitions.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b38e74bc9d25199e4f192dbb3f093ec033fe80b
--- /dev/null
+++ b/src/tester_functional/definitions.py
@@ -0,0 +1,165 @@
+import copy
+from common.database.api.context.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
+from common.database.api.context.service.ServiceState import ServiceState
+from common.database.api.context.service.ServiceType import ServiceType
+from common.database.api.context.topology.device.OperationalStatus import OperationalStatus
+
+# use "copy.deepcopy" to prevent propagating forced changes during tests
+dc = copy.deepcopy
+
+CONTEXT_ID = {'contextUuid': {'uuid': DEFAULT_CONTEXT_ID}}
+
+TOPOLOGY_ID = {'contextId': dc(CONTEXT_ID), 'topoId': {'uuid': DEFAULT_TOPOLOGY_ID}}
+
+DEVICE_ID_DEV1 = {'device_id': {'uuid': 'dev1'}}
+DEVICE_DEV1 = {
+    'device_id': dc(DEVICE_ID_DEV1), 'device_type': 'ROADM', 'device_config': {'device_config': '<config/>'},
+    'devOperationalStatus': OperationalStatus.ENABLED.value,
+    'endpointList' : [
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port2'}},
+         'port_type': 'WDM'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port3'}},
+         'port_type': 'WDM'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port101'}},
+         'port_type': 'OCH'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port102'}},
+         'port_type': 'OCH'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port103'}},
+         'port_type': 'OCH'},
+    ]
+}
+
+DEVICE_ID_DEV2 = {'device_id': {'uuid': 'dev2'}}
+DEVICE_DEV2 = {
+    'device_id': dc(DEVICE_ID_DEV2), 'device_type': 'ROADM', 'device_config': {'device_config': '<config/>'},
+    'devOperationalStatus': OperationalStatus.ENABLED.value,
+    'endpointList' : [
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port1'}},
+         'port_type': 'WDM'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port3'}},
+         'port_type': 'WDM'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port101'}},
+         'port_type': 'OCH'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port102'}},
+         'port_type': 'OCH'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port103'}},
+         'port_type': 'OCH'},
+    ]
+}
+
+DEVICE_ID_DEV3 = {'device_id': {'uuid': 'dev3'}}
+DEVICE_DEV3 = {
+    'device_id': dc(DEVICE_ID_DEV3), 'device_type': 'ROADM', 'device_config': {'device_config': '<config/>'},
+    'devOperationalStatus': OperationalStatus.ENABLED.value,
+    'endpointList' : [
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port1'}},
+         'port_type': 'WDM'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port2'}},
+         'port_type': 'WDM'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port101'}},
+         'port_type': 'OCH'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port102'}},
+         'port_type': 'OCH'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port103'}},
+         'port_type': 'OCH'},
+    ]
+}
+
+LINK_ID_DEV1_DEV2 = {'link_id': {'uuid': 'dev1/port2 ==> dev2/port1'}}
+LINK_DEV1_DEV2 = {
+    'link_id': dc(LINK_ID_DEV1_DEV2),
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port2'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port1'}},
+    ]
+}
+
+LINK_ID_DEV1_DEV3 = {'link_id': {'uuid': 'dev1/port3 ==> dev3/port1'}}
+LINK_DEV1_DEV3 = {
+    'link_id': dc(LINK_ID_DEV1_DEV3),
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port3'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port1'}},
+    ]
+}
+
+LINK_ID_DEV2_DEV1 = {'link_id': {'uuid': 'dev2/port1 ==> dev1/port2'}}
+LINK_DEV2_DEV1 = {
+    'link_id': dc(LINK_ID_DEV2_DEV1),
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port1'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port2'}},
+    ]
+}
+
+LINK_ID_DEV2_DEV3 = {'link_id': {'uuid': 'dev2/port3 ==> dev3/port2'}}
+LINK_DEV2_DEV3 = {
+    'link_id': dc(LINK_ID_DEV2_DEV3),
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port3'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port2'}},
+    ]
+}
+
+LINK_ID_DEV3_DEV1 = {'link_id': {'uuid': 'dev3/port1 ==> dev1/port3'}}
+LINK_DEV3_DEV1 = {
+    'link_id': dc(LINK_ID_DEV3_DEV1),
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port1'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port3'}},
+    ]
+}
+
+LINK_ID_DEV3_DEV2 = {'link_id': {'uuid': 'dev3/port2 ==> dev2/port3'}}
+LINK_DEV3_DEV2 = {
+    'link_id': dc(LINK_ID_DEV3_DEV2),
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port2'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port3'}},
+    ]
+}
+
+SERVICE_ID_SVC1 = {'contextId': dc(CONTEXT_ID), 'cs_id': {'uuid': 'svc1'}}
+SERVICE_SVC1 = {
+    'cs_id': dc(SERVICE_ID_SVC1), 'serviceType': ServiceType.L3NM.value,
+    'serviceConfig': {'serviceConfig': '<config/>'}, 'serviceState': {'serviceState': ServiceState.PLANNED.value},
+    'constraint': [
+        {'constraint_type': 'latency_ms', 'constraint_value': '100'},
+        {'constraint_type': 'hops', 'constraint_value': '5'},
+    ],
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port101'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port101'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port101'}},
+    ]
+}
+
+SERVICE_ID_SVC2 = {'contextId': dc(CONTEXT_ID), 'cs_id': {'uuid': 'svc2'}}
+SERVICE_SVC2 = {
+    'cs_id': dc(SERVICE_ID_SVC2), 'serviceType': ServiceType.L3NM.value,
+    'serviceConfig': {'serviceConfig': '<config/>'}, 'serviceState': {'serviceState': ServiceState.PLANNED.value},
+    'constraint': [
+        {'constraint_type': 'latency_ms', 'constraint_value': '100'},
+        {'constraint_type': 'hops', 'constraint_value': '5'},
+    ],
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port102'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port102'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port102'}},
+    ]
+}
+
+SERVICE_ID_SVC3 = {'contextId': dc(CONTEXT_ID), 'cs_id': {'uuid': 'svc3'}}
+SERVICE_SVC3 = {
+    'cs_id': dc(SERVICE_ID_SVC3), 'serviceType': ServiceType.L3NM.value,
+    'serviceConfig': {'serviceConfig': '<config/>'}, 'serviceState': {'serviceState': ServiceState.PLANNED.value},
+    'constraint': [
+        {'constraint_type': 'latency_ms', 'constraint_value': '100'},
+        {'constraint_type': 'hops', 'constraint_value': '5'},
+    ],
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port103'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port103'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port103'}},
+    ]
+}
diff --git a/src/integration_tester/requirements.in b/src/tester_functional/requirements.in
similarity index 100%
rename from src/integration_tester/requirements.in
rename to src/tester_functional/requirements.in
diff --git a/src/integration_tester/test_context_device_service.py b/src/tester_functional/test_context_device_service.py
similarity index 93%
rename from src/integration_tester/test_context_device_service.py
rename to src/tester_functional/test_context_device_service.py
index 4f3cf4cfe4db6df6df8afd9c3e581a356abb873b..d1b228b0dffc40b681314ebe66879534b85ed699 100644
--- a/src/integration_tester/test_context_device_service.py
+++ b/src/tester_functional/test_context_device_service.py
@@ -8,10 +8,10 @@ from common.tests.Assertions import validate_device_id, validate_link_id, valida
 from context.client.ContextClient import ContextClient
 from context.proto.context_pb2 import Device, Empty, Link
 from device.client.DeviceClient import DeviceClient
-from integration_tester.definitions import DEVICE_DEV1, DEVICE_DEV2, DEVICE_DEV3
-from integration_tester.definitions import LINK_DEV1_DEV2, LINK_DEV1_DEV3, LINK_DEV2_DEV1, LINK_DEV2_DEV3, \
+from tester_functional.definitions import DEVICE_DEV1, DEVICE_DEV2, DEVICE_DEV3
+from tester_functional.definitions import LINK_DEV1_DEV2, LINK_DEV1_DEV3, LINK_DEV2_DEV1, LINK_DEV2_DEV3, \
     LINK_DEV3_DEV1, LINK_DEV3_DEV2
-from integration_tester.definitions import SERVICE_SVC1, SERVICE_SVC2, SERVICE_SVC3
+from tester_functional.definitions import SERVICE_SVC1, SERVICE_SVC2, SERVICE_SVC3
 from service.client.ServiceClient import ServiceClient
 from service.proto.service_pb2 import Service
 
diff --git a/src/tester_integration/.gitlab-ci.yml b/src/tester_integration/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..460fa4414f7b70e0b96146e621b20c773b4184ed
--- /dev/null
+++ b/src/tester_integration/.gitlab-ci.yml
@@ -0,0 +1,52 @@
+# Build, tag, and push the Docker images to the GitLab Docker registry
+build tester_integration:
+  variables:
+    IMAGE_NAME: 'tester_integration' # name of the microservice
+    IMAGE_NAME_TEST: 'tester_integration-test' # name of the microservice
+    IMAGE_TAG: 'latest' # tag of the container image (production, development, etc)
+  stage: build
+  before_script:
+    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
+  script:
+    - docker build -t "$IMAGE_NAME:$IMAGE_TAG" -f ./src/$IMAGE_NAME/Dockerfile ./src/
+    - docker tag "$IMAGE_NAME:$IMAGE_TAG" "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
+    - docker push "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
+  rules:
+    - changes:
+      - src/common/**
+      - src/context/**
+      - src/device/**
+      - src/service/**
+      - src/$IMAGE_NAME/**
+      - .gitlab-ci.yml
+
+# Pull, execute, and run unitary tests for the Docker image from the GitLab registry
+test tester_integration:
+  variables:
+    IMAGE_NAME: 'tester_integration' # name of the microservice
+    IMAGE_NAME_TEST: 'tester_integration-test' # name of the microservice
+    IMAGE_TAG: 'latest' # tag of the container image (production, development, etc)
+  stage: test
+  needs:
+    - build tester_integration
+  before_script:
+    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
+    - if docker network list | grep teraflowbridge; then echo "teraflowbridge is already created"; else docker network create -d bridge teraflowbridge; fi  
+  script:
+    - docker pull "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
+    - docker run -d -p 6379:6379 --name redis --network=teraflowbridge "redis:6.2"
+    - docker ps -a
+    - sleep 5
+    - docker ps -a
+    - docker run -d --name $IMAGE_NAME --network=teraflowbridge --env "DB_ENGINE=redis" --env "REDIS_SERVICE_HOST=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' redis)" --env "REDIS_SERVICE_PORT=6379" --env "REDIS_DATABASE_ID=0" "$IMAGE_NAME:$IMAGE_TAG" bash -c "pytest --log-level=INFO --verbose common/database/tests/test_engine_redis.py tester_integration/test_context_device_service.py"
+  after_script:
+    - docker stop $IMAGE_NAME redis
+    - docker rm $IMAGE_NAME redis
+  rules:
+    - changes:
+      - src/common/**
+      - src/context/**
+      - src/device/**
+      - src/service/**
+      - src/$IMAGE_NAME/**
+      - .gitlab-ci.yml
diff --git a/src/integration_tester/Dockerfile b/src/tester_integration/Dockerfile
similarity index 63%
rename from src/integration_tester/Dockerfile
rename to src/tester_integration/Dockerfile
index 5c833b1202f8a571cdd86081f550fe19d59280b8..31ab8884b62814d43fbadaf624754e10681c8e7c 100644
--- a/src/integration_tester/Dockerfile
+++ b/src/tester_integration/Dockerfile
@@ -15,21 +15,21 @@ RUN python3 -m pip install --upgrade pip setuptools wheel pip-tools
 WORKDIR /var/teraflow
 
 # Create module sub-folders
-RUN mkdir -p /var/teraflow/integration_tester
+RUN mkdir -p /var/teraflow/tester_integration
 
 # Get Python packages per module
-COPY integration_tester/requirements.in integration_tester/requirements.in
-RUN pip-compile --output-file=integration_tester/requirements.txt integration_tester/requirements.in
-RUN python3 -m pip install -r integration_tester/requirements.in
+COPY tester_integration/requirements.in tester_integration/requirements.in
+RUN pip-compile --output-file=tester_integration/requirements.txt tester_integration/requirements.in
+RUN python3 -m pip install -r tester_integration/requirements.in
 
 # Add files into working directory
 COPY common/. common
 COPY context/. context
 COPY device/. device
 COPY service/. service
-COPY integration_tester/. integration_tester
+COPY tester_integration/. tester_integration
 
 # Run integration tester
 ENTRYPOINT ["pytest", "-v", "--log-level=DEBUG", \
-            "integration_tester/test_context_device_service.py" \
+            "tester_integration/test_context_device_service.py" \
 ]
diff --git a/src/tester_integration/__init__.py b/src/tester_integration/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/tester_integration/definitions.py b/src/tester_integration/definitions.py
new file mode 100644
index 0000000000000000000000000000000000000000..2b38e74bc9d25199e4f192dbb3f093ec033fe80b
--- /dev/null
+++ b/src/tester_integration/definitions.py
@@ -0,0 +1,165 @@
+import copy
+from common.database.api.context.Constants import DEFAULT_CONTEXT_ID, DEFAULT_TOPOLOGY_ID
+from common.database.api.context.service.ServiceState import ServiceState
+from common.database.api.context.service.ServiceType import ServiceType
+from common.database.api.context.topology.device.OperationalStatus import OperationalStatus
+
+# use "copy.deepcopy" to prevent propagating forced changes during tests
+dc = copy.deepcopy
+
+CONTEXT_ID = {'contextUuid': {'uuid': DEFAULT_CONTEXT_ID}}
+
+TOPOLOGY_ID = {'contextId': dc(CONTEXT_ID), 'topoId': {'uuid': DEFAULT_TOPOLOGY_ID}}
+
+DEVICE_ID_DEV1 = {'device_id': {'uuid': 'dev1'}}
+DEVICE_DEV1 = {
+    'device_id': dc(DEVICE_ID_DEV1), 'device_type': 'ROADM', 'device_config': {'device_config': '<config/>'},
+    'devOperationalStatus': OperationalStatus.ENABLED.value,
+    'endpointList' : [
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port2'}},
+         'port_type': 'WDM'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port3'}},
+         'port_type': 'WDM'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port101'}},
+         'port_type': 'OCH'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port102'}},
+         'port_type': 'OCH'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port103'}},
+         'port_type': 'OCH'},
+    ]
+}
+
+DEVICE_ID_DEV2 = {'device_id': {'uuid': 'dev2'}}
+DEVICE_DEV2 = {
+    'device_id': dc(DEVICE_ID_DEV2), 'device_type': 'ROADM', 'device_config': {'device_config': '<config/>'},
+    'devOperationalStatus': OperationalStatus.ENABLED.value,
+    'endpointList' : [
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port1'}},
+         'port_type': 'WDM'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port3'}},
+         'port_type': 'WDM'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port101'}},
+         'port_type': 'OCH'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port102'}},
+         'port_type': 'OCH'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port103'}},
+         'port_type': 'OCH'},
+    ]
+}
+
+DEVICE_ID_DEV3 = {'device_id': {'uuid': 'dev3'}}
+DEVICE_DEV3 = {
+    'device_id': dc(DEVICE_ID_DEV3), 'device_type': 'ROADM', 'device_config': {'device_config': '<config/>'},
+    'devOperationalStatus': OperationalStatus.ENABLED.value,
+    'endpointList' : [
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port1'}},
+         'port_type': 'WDM'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port2'}},
+         'port_type': 'WDM'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port101'}},
+         'port_type': 'OCH'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port102'}},
+         'port_type': 'OCH'},
+        {'port_id': {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port103'}},
+         'port_type': 'OCH'},
+    ]
+}
+
+LINK_ID_DEV1_DEV2 = {'link_id': {'uuid': 'dev1/port2 ==> dev2/port1'}}
+LINK_DEV1_DEV2 = {
+    'link_id': dc(LINK_ID_DEV1_DEV2),
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port2'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port1'}},
+    ]
+}
+
+LINK_ID_DEV1_DEV3 = {'link_id': {'uuid': 'dev1/port3 ==> dev3/port1'}}
+LINK_DEV1_DEV3 = {
+    'link_id': dc(LINK_ID_DEV1_DEV3),
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port3'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port1'}},
+    ]
+}
+
+LINK_ID_DEV2_DEV1 = {'link_id': {'uuid': 'dev2/port1 ==> dev1/port2'}}
+LINK_DEV2_DEV1 = {
+    'link_id': dc(LINK_ID_DEV2_DEV1),
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port1'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port2'}},
+    ]
+}
+
+LINK_ID_DEV2_DEV3 = {'link_id': {'uuid': 'dev2/port3 ==> dev3/port2'}}
+LINK_DEV2_DEV3 = {
+    'link_id': dc(LINK_ID_DEV2_DEV3),
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port3'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port2'}},
+    ]
+}
+
+LINK_ID_DEV3_DEV1 = {'link_id': {'uuid': 'dev3/port1 ==> dev1/port3'}}
+LINK_DEV3_DEV1 = {
+    'link_id': dc(LINK_ID_DEV3_DEV1),
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port1'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port3'}},
+    ]
+}
+
+LINK_ID_DEV3_DEV2 = {'link_id': {'uuid': 'dev3/port2 ==> dev2/port3'}}
+LINK_DEV3_DEV2 = {
+    'link_id': dc(LINK_ID_DEV3_DEV2),
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port2'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port3'}},
+    ]
+}
+
+SERVICE_ID_SVC1 = {'contextId': dc(CONTEXT_ID), 'cs_id': {'uuid': 'svc1'}}
+SERVICE_SVC1 = {
+    'cs_id': dc(SERVICE_ID_SVC1), 'serviceType': ServiceType.L3NM.value,
+    'serviceConfig': {'serviceConfig': '<config/>'}, 'serviceState': {'serviceState': ServiceState.PLANNED.value},
+    'constraint': [
+        {'constraint_type': 'latency_ms', 'constraint_value': '100'},
+        {'constraint_type': 'hops', 'constraint_value': '5'},
+    ],
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port101'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port101'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port101'}},
+    ]
+}
+
+SERVICE_ID_SVC2 = {'contextId': dc(CONTEXT_ID), 'cs_id': {'uuid': 'svc2'}}
+SERVICE_SVC2 = {
+    'cs_id': dc(SERVICE_ID_SVC2), 'serviceType': ServiceType.L3NM.value,
+    'serviceConfig': {'serviceConfig': '<config/>'}, 'serviceState': {'serviceState': ServiceState.PLANNED.value},
+    'constraint': [
+        {'constraint_type': 'latency_ms', 'constraint_value': '100'},
+        {'constraint_type': 'hops', 'constraint_value': '5'},
+    ],
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port102'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port102'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port102'}},
+    ]
+}
+
+SERVICE_ID_SVC3 = {'contextId': dc(CONTEXT_ID), 'cs_id': {'uuid': 'svc3'}}
+SERVICE_SVC3 = {
+    'cs_id': dc(SERVICE_ID_SVC3), 'serviceType': ServiceType.L3NM.value,
+    'serviceConfig': {'serviceConfig': '<config/>'}, 'serviceState': {'serviceState': ServiceState.PLANNED.value},
+    'constraint': [
+        {'constraint_type': 'latency_ms', 'constraint_value': '100'},
+        {'constraint_type': 'hops', 'constraint_value': '5'},
+    ],
+    'endpointList' : [
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV1), 'port_id': {'uuid' : 'port103'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV2), 'port_id': {'uuid' : 'port103'}},
+        {'topoId': dc(TOPOLOGY_ID), 'dev_id': dc(DEVICE_ID_DEV3), 'port_id': {'uuid' : 'port103'}},
+    ]
+}
diff --git a/src/tester_integration/requirements.in b/src/tester_integration/requirements.in
new file mode 100644
index 0000000000000000000000000000000000000000..25abdad1b5767117956a88b816399635348884c7
--- /dev/null
+++ b/src/tester_integration/requirements.in
@@ -0,0 +1,6 @@
+grpcio-health-checking
+grpcio
+prometheus-client
+pytest
+pytest-benchmark
+redis
diff --git a/src/tester_integration/test_context_device_service.py b/src/tester_integration/test_context_device_service.py
new file mode 100644
index 0000000000000000000000000000000000000000..2d128800c2e714de242de328c2d00a6134c378d7
--- /dev/null
+++ b/src/tester_integration/test_context_device_service.py
@@ -0,0 +1,138 @@
+import logging, pytest
+from google.protobuf.json_format import MessageToDict
+from common.database.Factory import get_database, DatabaseEngineEnum
+from common.database.api.Database import Database
+from common.tests.Assertions import validate_device_id, validate_link_id, validate_service_id, \
+    validate_service_list_is_not_empty, validate_topology_has_devices, validate_topology_has_links, \
+    validate_topology_is_empty
+from context.Config import GRPC_SERVICE_PORT as GRPC_CONTEXT_SERVICE_PORT, \
+    GRPC_MAX_WORKERS as GRPC_CONTEXT_MAX_WORKERS, GRPC_GRACE_PERIOD as GRPC_CONTEXT_GRACE_PERIOD
+from context.client.ContextClient import ContextClient
+from context.proto.context_pb2 import Device, Empty, Link
+from context.service.ContextService import ContextService
+from device.Config import GRPC_SERVICE_PORT as GRPC_DEVICE_SERVICE_PORT, \
+    GRPC_MAX_WORKERS as GRPC_DEVICE_MAX_WORKERS, GRPC_GRACE_PERIOD as GRPC_DEVICE_GRACE_PERIOD
+from device.client.DeviceClient import DeviceClient
+from device.service.DeviceService import DeviceService
+from service.service.ServiceService import ServiceService
+from tester_integration.definitions import DEVICE_DEV1, DEVICE_DEV2, DEVICE_DEV3
+from tester_integration.definitions import LINK_DEV1_DEV2, LINK_DEV1_DEV3, LINK_DEV2_DEV1, LINK_DEV2_DEV3, \
+    LINK_DEV3_DEV1, LINK_DEV3_DEV2
+from tester_integration.definitions import SERVICE_SVC1, SERVICE_SVC2, SERVICE_SVC3
+from service.Config import GRPC_SERVICE_PORT as GRPC_SERVICE_SERVICE_PORT, \
+    GRPC_MAX_WORKERS as GRPC_SERVICE_MAX_WORKERS, GRPC_GRACE_PERIOD as GRPC_SERVICE_GRACE_PERIOD
+from service.client.ServiceClient import ServiceClient
+from service.proto.service_pb2 import Service
+
+PORT_CONTEXT = 10000 + GRPC_CONTEXT_SERVICE_PORT # avoid privileged ports
+PORT_DEVICE  = 10000 + GRPC_DEVICE_SERVICE_PORT  # avoid privileged ports
+PORT_SERVICE = 10000 + GRPC_SERVICE_SERVICE_PORT # avoid privileged ports
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+@pytest.fixture(scope='session')
+def redis_database():
+    _database = get_database(engine=DatabaseEngineEnum.REDIS, REDIS_DATABASE_ID=0)
+    return _database
+
+@pytest.fixture(scope='session')
+def context_service(redis_database : Database):
+    context_database = get_database(engine=DatabaseEngineEnum.REDIS, REDIS_DATABASE_ID=0)
+    _service = ContextService(
+        context_database, port=PORT_CONTEXT, max_workers=GRPC_CONTEXT_MAX_WORKERS,
+        grace_period=GRPC_CONTEXT_GRACE_PERIOD)
+    _service.start()
+    yield _service
+    _service.stop()
+
+@pytest.fixture(scope='session')
+def context_client(context_service):
+    _client = ContextClient(address='127.0.0.1', port=PORT_CONTEXT)
+    yield _client
+    _client.close()
+
+@pytest.fixture(scope='session')
+def device_service(redis_database : Database):
+    device_database = get_database(engine=DatabaseEngineEnum.REDIS, REDIS_DATABASE_ID=0)
+    _service = DeviceService(
+        device_database, port=PORT_DEVICE, max_workers=GRPC_DEVICE_MAX_WORKERS,
+        grace_period=GRPC_DEVICE_GRACE_PERIOD)
+    _service.start()
+    yield _service
+    _service.stop()
+
+@pytest.fixture(scope='session')
+def device_client(device_service):
+    _client = DeviceClient(address='127.0.0.1', port=PORT_DEVICE)
+    yield _client
+    _client.close()
+
+@pytest.fixture(scope='session')
+def service_service(redis_database : Database):
+    service_database = get_database(engine=DatabaseEngineEnum.REDIS, REDIS_DATABASE_ID=0)
+    _service = ServiceService(
+        service_database, port=PORT_SERVICE, max_workers=GRPC_SERVICE_MAX_WORKERS,
+        grace_period=GRPC_SERVICE_GRACE_PERIOD)
+    _service.start()
+    yield _service
+    _service.stop()
+
+@pytest.fixture(scope='session')
+def service_client(service_service):
+    _client = ServiceClient(address='127.0.0.1', port=PORT_SERVICE)
+    yield _client
+    _client.close()
+
+def test_clean_database(redis_database : Database):
+    # should work
+    redis_database.clear_all()
+
+def test_get_topology_empty(context_client : ContextClient):
+    # should work
+    validate_topology_is_empty(MessageToDict(
+        context_client.GetTopology(Empty()),
+        including_default_value_fields=True, preserving_proto_field_name=True,
+        use_integers_for_enums=False))
+
+def test_add_devices(context_client : ContextClient, device_client : DeviceClient):
+    # should work
+    for device in [DEVICE_DEV1, DEVICE_DEV2, DEVICE_DEV3]:
+        validate_device_id(MessageToDict(
+            device_client.AddDevice(Device(**device)),
+            including_default_value_fields=True, preserving_proto_field_name=True,
+            use_integers_for_enums=False))
+
+    # should work
+    validate_topology_has_devices(MessageToDict(
+        context_client.GetTopology(Empty()),
+        including_default_value_fields=True, preserving_proto_field_name=True,
+        use_integers_for_enums=False))
+
+def test_add_links(context_client : ContextClient):
+    # should work
+    for link in [LINK_DEV1_DEV2, LINK_DEV1_DEV3, LINK_DEV2_DEV1, LINK_DEV2_DEV3, LINK_DEV3_DEV1, LINK_DEV3_DEV2]:
+        validate_link_id(MessageToDict(
+            context_client.AddLink(Link(**link)),
+            including_default_value_fields=True, preserving_proto_field_name=True,
+            use_integers_for_enums=False))
+
+    # should work
+    validate_topology_has_links(MessageToDict(
+        context_client.GetTopology(Empty()),
+        including_default_value_fields=True, preserving_proto_field_name=True,
+        use_integers_for_enums=False))
+
+def test_add_services(service_client : ServiceClient):
+    # should work
+    for service in [SERVICE_SVC1, SERVICE_SVC2, SERVICE_SVC3]:
+        validate_service_id(MessageToDict(
+            service_client.CreateService(Service(**service)),
+            including_default_value_fields=True, preserving_proto_field_name=True,
+            use_integers_for_enums=False))
+
+    # should work
+    validate_service_list_is_not_empty(MessageToDict(
+        service_client.GetServiceList(Empty()),
+        including_default_value_fields=True, preserving_proto_field_name=True,
+        use_integers_for_enums=False))