From 0bf11c591df49987de4172f3c21e7fa00ba4336a Mon Sep 17 00:00:00 2001
From: gifrerenom <lluis.gifre@cttc.es>
Date: Mon, 17 Feb 2025 11:17:22 +0000
Subject: [PATCH] NBI component:

- Added Mock NBI Dependencies service as a separate continer for testing
- Fixed unitary tests
- Fixed CI/CD pipeline
---
 .gitlab-ci.yml                                |  4 +-
 src/nbi/.gitlab-ci.yml                        |  9 ++
 src/nbi/tests/PrepareTestScenario.py          | 99 +++++++++++--------
 src/nbi/tests/test_core.py                    |  3 +-
 src/nbi/tests/test_etsi_bwm.py                |  3 +-
 src/nbi/tests/test_ietf_l2vpn.py              |  3 +-
 src/nbi/tests/test_ietf_l3vpn.py              |  3 +-
 src/nbi/tests/test_ietf_network.py            |  3 +-
 src/nbi/tests/test_tfs_api.py                 |  3 +-
 src/tests/.gitlab-ci.yml                      |  2 +
 .../mock_nbi_dependencies/.gitlab-ci.yml      | 37 +++++++
 .../tools/mock_nbi_dependencies/Config.py     | 19 ++++
 .../tools/mock_nbi_dependencies/Dockerfile    | 37 +++++++
 .../MockNbiDependencies.py                    | 48 +++++++++
 .../MockService_Dependencies.py               | 55 +++++++++++
 .../tools/mock_nbi_dependencies/README.md     | 21 ++++
 .../tools/mock_nbi_dependencies/__init__.py   | 14 +++
 .../tools/mock_nbi_dependencies/build.sh      | 21 ++++
 .../tools/mock_nbi_dependencies/deploy.sh     | 17 ++++
 .../mock-nbi-dependencies.yaml                | 76 ++++++++++++++
 .../mock_nbi_dependencies/requirements.in     | 19 ++++
 src/tests/tools/mock_nbi_dependencies/run.sh  | 19 ++++
 22 files changed, 464 insertions(+), 51 deletions(-)
 create mode 100644 src/tests/tools/mock_nbi_dependencies/.gitlab-ci.yml
 create mode 100644 src/tests/tools/mock_nbi_dependencies/Config.py
 create mode 100644 src/tests/tools/mock_nbi_dependencies/Dockerfile
 create mode 100644 src/tests/tools/mock_nbi_dependencies/MockNbiDependencies.py
 create mode 100644 src/tests/tools/mock_nbi_dependencies/MockService_Dependencies.py
 create mode 100644 src/tests/tools/mock_nbi_dependencies/README.md
 create mode 100644 src/tests/tools/mock_nbi_dependencies/__init__.py
 create mode 100755 src/tests/tools/mock_nbi_dependencies/build.sh
 create mode 100755 src/tests/tools/mock_nbi_dependencies/deploy.sh
 create mode 100644 src/tests/tools/mock_nbi_dependencies/mock-nbi-dependencies.yaml
 create mode 100644 src/tests/tools/mock_nbi_dependencies/requirements.in
 create mode 100755 src/tests/tools/mock_nbi_dependencies/run.sh

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2588fb513..d12b12939 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -55,5 +55,5 @@ include:
 #  - local: '/src/vnt_manager/.gitlab-ci.yml'
 #  - local: '/src/e2e_orchestrator/.gitlab-ci.yml'
 #
-#  # This should be last one: end-to-end integration tests
-#  - local: '/src/tests/.gitlab-ci.yml'
+  # This should be last one: end-to-end integration tests
+  - local: '/src/tests/.gitlab-ci.yml'
diff --git a/src/nbi/.gitlab-ci.yml b/src/nbi/.gitlab-ci.yml
index 2c1057f95..2aad65dc4 100644
--- a/src/nbi/.gitlab-ci.yml
+++ b/src/nbi/.gitlab-ci.yml
@@ -46,6 +46,7 @@ unit_test nbi:
   stage: unit_test
   needs:
     - build nbi
+    - build mock_nbi_dependencies
   before_script:
     - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
     - >
@@ -62,6 +63,14 @@ unit_test nbi:
       fi
   script:
     - docker pull "$CI_REGISTRY_IMAGE/$IMAGE_NAME:$IMAGE_TAG"
+    - docker pull "$CI_REGISTRY_IMAGE/mock_nbi_dependencies:test"
+    - >
+      docker run --name mock_nbi_dependencies -d
+      --network=teraflowbridge
+      --env BIND_ADDRESS=0.0.0.0
+      --env BIND_PORT=10000
+      --env LOG_LEVEL=DEBUG
+      $CI_REGISTRY_IMAGE/mock_nbi_dependencies:test
     - >
       docker run --name $IMAGE_NAME -d -v "$PWD/src/$IMAGE_NAME/tests:/opt/results" 
       --network=teraflowbridge
diff --git a/src/nbi/tests/PrepareTestScenario.py b/src/nbi/tests/PrepareTestScenario.py
index 5c4c39d5d..a9922de1b 100644
--- a/src/nbi/tests/PrepareTestScenario.py
+++ b/src/nbi/tests/PrepareTestScenario.py
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import enum, logging, os, pytest, requests, subprocess, threading, time
+import enum, logging, os, pytest, requests, time # subprocess, threading
 from typing import Any, Dict, List, Optional, Set, Union
 from socketio import Namespace
 from common.Constants import ServiceNameEnum
@@ -21,6 +21,7 @@ from common.Settings import (
     ENVVAR_SUFIX_SERVICE_PORT_HTTP, get_env_var_name
 )
 from context.client.ContextClient import ContextClient
+from device.client.DeviceClient import DeviceClient
 from nbi.service.NbiApplication import NbiApplication
 from nbi.service.health_probes.Constants import SIO_NAMESPACE as HEARTBEAT_NAMESPACE
 from nbi.service.health_probes.Namespaces import HeartbeatServerNamespace
@@ -39,54 +40,58 @@ os.environ[get_env_var_name(ServiceNameEnum.NBI,     ENVVAR_SUFIX_SERVICE_HOST
 os.environ[get_env_var_name(ServiceNameEnum.NBI,     ENVVAR_SUFIX_SERVICE_PORT_HTTP)] = str(NBI_SERVICE_PORT)
 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(MOCKSERVICE_PORT)
+os.environ[get_env_var_name(ServiceNameEnum.DEVICE,  ENVVAR_SUFIX_SERVICE_HOST     )] = str(LOCAL_HOST)
+os.environ[get_env_var_name(ServiceNameEnum.DEVICE,  ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(MOCKSERVICE_PORT)
 os.environ[get_env_var_name(ServiceNameEnum.SERVICE, ENVVAR_SUFIX_SERVICE_HOST     )] = str(LOCAL_HOST)
 os.environ[get_env_var_name(ServiceNameEnum.SERVICE, ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(MOCKSERVICE_PORT)
 os.environ[get_env_var_name(ServiceNameEnum.SLICE,   ENVVAR_SUFIX_SERVICE_HOST     )] = str(LOCAL_HOST)
 os.environ[get_env_var_name(ServiceNameEnum.SLICE,   ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(MOCKSERVICE_PORT)
 
 
-@pytest.fixture(scope='session')
-def mock_service():
-    # NOTE: Starting MockServer in a separate process to prevent
-    # issues with eventlet monkey-patched libraries.
-
-    cmd = ['python', '-m', 'nbi.tests.MockService_Dependencies']
-    custom_env = os.environ.copy()
-    mock_service_process = subprocess.Popen(
-        cmd,
-        env=custom_env,
-        stdout=subprocess.PIPE,
-        stderr=subprocess.STDOUT,
-        stdin=subprocess.DEVNULL,
-        text=True,
-        bufsize=1
-    )
-
-    mock_service_logger = logging.getLogger('MockService_Dependencies')
-    mock_service_logger.info('Started')
-
-    def stream_stdout():
-        for line in iter(mock_service_process.stdout.readline, ''):
-            mock_service_logger.info(line.strip())
-
-    stream_stdout_thread = threading.Thread(target=stream_stdout, daemon=True)
-    stream_stdout_thread.start()
-
-    yield True
-
-    # Check if process is still running
-    if mock_service_process.poll() is None:
-        mock_service_process.terminate()  # Try to terminate gracefully
-        time.sleep(2)  # Give it time to exit
-        if mock_service_process.poll() is None:
-            mock_service_process.kill()  # Force kill if still running
-
-    mock_service_logger.info('Terminated')
-    stream_stdout_thread.join()
+## MockService_Dependencies executed as a standalone container during
+# tests to prevent apparent dead locks and issues.
+#@pytest.fixture(scope='session')
+#def mock_service():
+#    # NOTE: Starting MockServer in a separate process to prevent
+#    # issues with eventlet monkey-patched libraries.
+#
+#    cmd = ['python', '-m', 'nbi.tests.MockService_Dependencies']
+#    custom_env = os.environ.copy()
+#    mock_service_process = subprocess.Popen(
+#        cmd,
+#        env=custom_env,
+#        stdout=subprocess.PIPE,
+#        stderr=subprocess.STDOUT,
+#        stdin=subprocess.DEVNULL,
+#        text=True,
+#        bufsize=1
+#    )
+#
+#    mock_service_logger = logging.getLogger('MockService_Dependencies')
+#    mock_service_logger.info('Started')
+#
+#    def stream_stdout():
+#        for line in iter(mock_service_process.stdout.readline, ''):
+#            mock_service_logger.info(line.strip())
+#
+#    stream_stdout_thread = threading.Thread(target=stream_stdout, daemon=True)
+#    stream_stdout_thread.start()
+#
+#    yield True
+#
+#    # Check if process is still running
+#    if mock_service_process.poll() is None:
+#        mock_service_process.terminate()  # Try to terminate gracefully
+#        time.sleep(2)  # Give it time to exit
+#        if mock_service_process.poll() is None:
+#            mock_service_process.kill()  # Force kill if still running
+#
+#    mock_service_logger.info('Terminated')
+#    stream_stdout_thread.join()
 
 @pytest.fixture(scope='session')
 def nbi_application(
-    mock_service                                # pylint: disable=redefined-outer-name, unused-argument
+#    mock_service                                # pylint: disable=redefined-outer-name, unused-argument
 ) -> NbiApplication:
     mock_web_server = MockWebServer()
     mock_web_server.start()
@@ -112,15 +117,23 @@ def osm_wim(
 
 @pytest.fixture(scope='session')
 def context_client(
-    mock_service                                # pylint: disable=redefined-outer-name, unused-argument
+#    mock_service                                # pylint: disable=redefined-outer-name, unused-argument
 ) -> ContextClient:
     _client = ContextClient()
     yield _client
     _client.close()
 
+@pytest.fixture(scope='session')
+def device_client(
+#    mock_service                                # pylint: disable=redefined-outer-name, unused-argument
+) -> DeviceClient:
+    _client = DeviceClient()
+    yield _client
+    _client.close()
+
 @pytest.fixture(scope='session')
 def service_client(
-    mock_service                                # pylint: disable=redefined-outer-name, unused-argument
+#    mock_service                                # pylint: disable=redefined-outer-name, unused-argument
 ) -> ServiceClient:
     _client = ServiceClient()
     yield _client
@@ -128,7 +141,7 @@ def service_client(
 
 @pytest.fixture(scope='session')
 def slice_client(
-    mock_service                                # pylint: disable=redefined-outer-name, unused-argument
+#    mock_service                                # pylint: disable=redefined-outer-name, unused-argument
 ) -> SliceClient:
     _client = SliceClient()
     yield _client
diff --git a/src/nbi/tests/test_core.py b/src/nbi/tests/test_core.py
index f41c26f5d..39db882c0 100644
--- a/src/nbi/tests/test_core.py
+++ b/src/nbi/tests/test_core.py
@@ -25,7 +25,8 @@ from .Constants import NBI_SERVICE_BASE_URL
 from .HeartbeatClientNamespace import HeartbeatClientNamespace
 from .PrepareTestScenario import ( # pylint: disable=unused-import
     # be careful, order of symbols is important here!
-    mock_service, nbi_application, do_rest_get_request
+    #mock_service,
+    nbi_application, do_rest_get_request
 )
 
 
diff --git a/src/nbi/tests/test_etsi_bwm.py b/src/nbi/tests/test_etsi_bwm.py
index 568ab2ff7..29666ffad 100644
--- a/src/nbi/tests/test_etsi_bwm.py
+++ b/src/nbi/tests/test_etsi_bwm.py
@@ -29,7 +29,8 @@ from context.client.ContextClient import ContextClient
 from nbi.service.NbiApplication import NbiApplication
 from .PrepareTestScenario import ( # pylint: disable=unused-import
     # be careful, order of symbols is important here!
-    mock_service, nbi_application, context_client,
+    #mock_service,
+    nbi_application, context_client,
     do_rest_delete_request, do_rest_get_request, do_rest_patch_request, do_rest_post_request, do_rest_put_request
 )
 
diff --git a/src/nbi/tests/test_ietf_l2vpn.py b/src/nbi/tests/test_ietf_l2vpn.py
index 37b7d60b0..f620040e1 100644
--- a/src/nbi/tests/test_ietf_l2vpn.py
+++ b/src/nbi/tests/test_ietf_l2vpn.py
@@ -28,7 +28,8 @@ from tests.tools.mock_osm.MockOSM import MockOSM
 from .OSM_Constants import SERVICE_CONNECTION_POINTS_1, SERVICE_CONNECTION_POINTS_2, SERVICE_TYPE
 from .PrepareTestScenario import ( # pylint: disable=unused-import
     # be careful, order of symbols is important here!
-    mock_service, nbi_application, osm_wim, context_client
+    #mock_service,
+    nbi_application, osm_wim, context_client
 )
 
 
diff --git a/src/nbi/tests/test_ietf_l3vpn.py b/src/nbi/tests/test_ietf_l3vpn.py
index b526611c6..c3176c25a 100644
--- a/src/nbi/tests/test_ietf_l3vpn.py
+++ b/src/nbi/tests/test_ietf_l3vpn.py
@@ -30,7 +30,8 @@ from context.client.ContextClient import ContextClient
 from nbi.service.NbiApplication import NbiApplication
 from .PrepareTestScenario import ( # pylint: disable=unused-import
     # be careful, order of symbols is important here!
-    mock_service, nbi_application, context_client,
+    #mock_service,
+    nbi_application, context_client,
     do_rest_delete_request, do_rest_get_request, do_rest_post_request
 )
 
diff --git a/src/nbi/tests/test_ietf_network.py b/src/nbi/tests/test_ietf_network.py
index 182f0ecf7..ceb61aac3 100644
--- a/src/nbi/tests/test_ietf_network.py
+++ b/src/nbi/tests/test_ietf_network.py
@@ -34,7 +34,8 @@ os.environ['IETF_NETWORK_RENDERER'] = 'PYANGBIND'
 
 from .PrepareTestScenario import ( # pylint: disable=unused-import
     # be careful, order of symbols is important here!
-    mock_service, nbi_application, context_client,
+    #mock_service,
+    nbi_application, context_client,
     do_rest_get_request
 )
 
diff --git a/src/nbi/tests/test_tfs_api.py b/src/nbi/tests/test_tfs_api.py
index d8009530f..ed5630a9b 100644
--- a/src/nbi/tests/test_tfs_api.py
+++ b/src/nbi/tests/test_tfs_api.py
@@ -39,7 +39,8 @@ from context.client.ContextClient import ContextClient
 from nbi.service.NbiApplication import NbiApplication
 from .PrepareTestScenario import ( # pylint: disable=unused-import
     # be careful, order of symbols is important here!
-    mock_service, nbi_application, context_client,
+    #mock_service,
+    nbi_application, context_client,
     do_rest_get_request
 )
 
diff --git a/src/tests/.gitlab-ci.yml b/src/tests/.gitlab-ci.yml
index ec8ab77d9..26a97416f 100644
--- a/src/tests/.gitlab-ci.yml
+++ b/src/tests/.gitlab-ci.yml
@@ -22,3 +22,5 @@ include:
 #  - local: '/src/tests/ofc24/.gitlab-ci.yml'
 #  - local: '/src/tests/eucnc24/.gitlab-ci.yml'
 #  - local: '/src/tests/ecoc24/.gitlab-ci.yml'
+
+  - local: '/src/tools/mock_nbi_dependencies/.gitlab-ci.yml'
diff --git a/src/tests/tools/mock_nbi_dependencies/.gitlab-ci.yml b/src/tests/tools/mock_nbi_dependencies/.gitlab-ci.yml
new file mode 100644
index 000000000..d84b3ade5
--- /dev/null
+++ b/src/tests/tools/mock_nbi_dependencies/.gitlab-ci.yml
@@ -0,0 +1,37 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+# Build, tag, and push the Docker image to the GitLab Docker registry
+build mock_nbi_dependencies:
+  stage: build
+  before_script:
+    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
+  script:
+    - docker buildx build -t "$CI_REGISTRY_IMAGE/mock_nbi_dependencies:test" -f ./src/tests/tools/mock_nbi_dependencies/Dockerfile .
+    - docker push "$CI_REGISTRY_IMAGE/mock_nbi_dependencies:test"
+  after_script:
+    - docker images --filter="dangling=true" --quiet | xargs -r docker rmi
+  rules:
+    - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)'
+    - if: '$CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == "develop"'
+    - changes:
+      - src/common/**/*.py
+      - proto/*.proto
+      - src/src/tests/tools/mock_nbi_dependencies/**/*.{py,in,yml,yaml}
+      - src/src/tests/tools/mock_nbi_dependencies/Dockerfile
+      - src/nbi/**/*.{py,in,yml}
+      - src/nbi/Dockerfile
+      - src/nbi/tests/*.py
+      - manifests/nbiservice.yaml
+      - .gitlab-ci.yml
diff --git a/src/tests/tools/mock_nbi_dependencies/Config.py b/src/tests/tools/mock_nbi_dependencies/Config.py
new file mode 100644
index 000000000..516a58d15
--- /dev/null
+++ b/src/tests/tools/mock_nbi_dependencies/Config.py
@@ -0,0 +1,19 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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 common.Settings import get_log_level, get_setting
+
+BIND_ADDRESS = str(get_setting('BIND_ADDRESS', default='0.0.0.0'))
+BIND_PORT    = int(get_setting('BIND_PORT',    default=10000    ))
+LOG_LEVEL    = str(get_log_level())
diff --git a/src/tests/tools/mock_nbi_dependencies/Dockerfile b/src/tests/tools/mock_nbi_dependencies/Dockerfile
new file mode 100644
index 000000000..206faa69c
--- /dev/null
+++ b/src/tests/tools/mock_nbi_dependencies/Dockerfile
@@ -0,0 +1,37 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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 python:3.9-slim
+
+# Set Python to show logs as they occur
+ENV PYTHONUNBUFFERED=0
+
+# Get generic Python packages
+RUN python3 -m pip install --upgrade pip
+RUN python3 -m pip install --upgrade setuptools wheel
+RUN python3 -m pip install --upgrade pip-tools
+
+# Create component sub-folders, and copy content
+RUN mkdir -p /var/teraflow/mock_nbi_dependencies
+WORKDIR /var/teraflow/mock_nbi_dependencies
+COPY . .
+
+# Get specific Python packages
+RUN pip-compile --quiet --output-file=requirements.txt requirements.in
+RUN python3 -m pip install -r requirements.txt
+
+RUN python3 -m pip list
+
+# Start the service
+ENTRYPOINT ["python", "MockNbiDependencies.py"]
diff --git a/src/tests/tools/mock_nbi_dependencies/MockNbiDependencies.py b/src/tests/tools/mock_nbi_dependencies/MockNbiDependencies.py
new file mode 100644
index 000000000..dd121961d
--- /dev/null
+++ b/src/tests/tools/mock_nbi_dependencies/MockNbiDependencies.py
@@ -0,0 +1,48 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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, signal, sys, threading
+from .MockService_Dependencies import MockService_Dependencies
+from .Config import BIND_ADDRESS, BIND_PORT, LOG_LEVEL
+
+logging.basicConfig(
+    level=LOG_LEVEL,
+    format='[%(asctime)s] %(levelname)s:%(name)s:%(message)s',
+)
+LOGGER = logging.getLogger(__name__)
+TERMINATE = threading.Event()
+
+def signal_handler(signal, frame): # pylint: disable=redefined-outer-name,unused-argument
+    LOGGER.warning('Terminate signal received')
+    TERMINATE.set()
+
+def main():
+    LOGGER.info('Starting...')
+    signal.signal(signal.SIGINT,  signal_handler)
+    signal.signal(signal.SIGTERM, signal_handler)
+
+    grpc_service = MockService_Dependencies(BIND_PORT, bind_address=BIND_ADDRESS)
+    grpc_service.start()
+
+    # Wait for Ctrl+C or termination signal
+    while not TERMINATE.wait(timeout=1.0): pass
+
+    LOGGER.info('Terminating...')
+    grpc_service.stop()
+
+    LOGGER.info('Bye')
+    return 0
+
+if __name__ == '__main__':
+    sys.exit(main())
diff --git a/src/tests/tools/mock_nbi_dependencies/MockService_Dependencies.py b/src/tests/tools/mock_nbi_dependencies/MockService_Dependencies.py
new file mode 100644
index 000000000..74ef6bdad
--- /dev/null
+++ b/src/tests/tools/mock_nbi_dependencies/MockService_Dependencies.py
@@ -0,0 +1,55 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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 Optional, Union
+from common.proto.context_pb2_grpc import add_ContextServiceServicer_to_server
+from common.proto.device_pb2_grpc import add_DeviceServiceServicer_to_server
+from common.proto.service_pb2_grpc import add_ServiceServiceServicer_to_server
+from common.proto.slice_pb2_grpc import add_SliceServiceServicer_to_server
+from common.tests.MockServicerImpl_Context import MockServicerImpl_Context
+from common.tests.MockServicerImpl_Device import MockServicerImpl_Device
+from common.tests.MockServicerImpl_Service import MockServicerImpl_Service
+from common.tests.MockServicerImpl_Slice import MockServicerImpl_Slice
+from common.tools.service.GenericGrpcService import GenericGrpcService
+
+
+class MockService_Dependencies(GenericGrpcService):
+    # Mock Service implementing Mock Context, Device, Service and Slice to
+    # simplify unitary tests of the NBI component.
+
+    def __init__(
+        self, bind_port : Union[str, int], bind_address : Optional[str] = None,
+        max_workers : Optional[int] = None, grace_period : Optional[int] = None,
+        enable_health_servicer : bool = True, enable_reflection : bool = False,
+        cls_name : str = 'MockService'
+    ) -> None:
+        super().__init__(
+            bind_port, bind_address=bind_address, max_workers=max_workers,
+            grace_period=grace_period, enable_health_servicer=enable_health_servicer,
+            enable_reflection=enable_reflection, cls_name=cls_name
+        )
+
+    # pylint: disable=attribute-defined-outside-init
+    def install_servicers(self):
+        self.context_servicer = MockServicerImpl_Context()
+        add_ContextServiceServicer_to_server(self.context_servicer, self.server)
+
+        self.device_servicer = MockServicerImpl_Device()
+        add_DeviceServiceServicer_to_server(self.device_servicer, self.server)
+
+        self.service_servicer = MockServicerImpl_Service()
+        add_ServiceServiceServicer_to_server(self.service_servicer, self.server)
+
+        self.slice_servicer = MockServicerImpl_Slice()
+        add_SliceServiceServicer_to_server(self.slice_servicer, self.server)
diff --git a/src/tests/tools/mock_nbi_dependencies/README.md b/src/tests/tools/mock_nbi_dependencies/README.md
new file mode 100644
index 000000000..0f3228b1c
--- /dev/null
+++ b/src/tests/tools/mock_nbi_dependencies/README.md
@@ -0,0 +1,21 @@
+# Mock NBI Dependencies
+
+This gRPC Mock NBI Dependencies server implements very basic support for the testing of the NBI component.
+
+
+## 1. Install requirements for the Mock NBI Dependencies
+__NOTE__: if you run the Mock NBI Dependencies from the PyEnv used for developing on the TeraFlowSDN
+framework and you followed the official steps in
+[Development Guide > Configure Environment > Python](https://tfs.etsi.org/documentation/latest/development_guide/#211-python),
+all the requirements are already in place. Install them only if you execute it in a separate/standalone environment.
+
+Install the required dependencies as follows:
+```bash
+pip install -r src/tests/tools/mock_nbi_dependencies/requirements.in
+```
+
+## 2. Run the Mock NBI Dependencies
+Run the Mock NBI Dependencies as follows:
+```bash
+python src/tests/tools/mock_nbi_dependencies/MockNbiDependencies.py
+```
diff --git a/src/tests/tools/mock_nbi_dependencies/__init__.py b/src/tests/tools/mock_nbi_dependencies/__init__.py
new file mode 100644
index 000000000..53d5157f7
--- /dev/null
+++ b/src/tests/tools/mock_nbi_dependencies/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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/tests/tools/mock_nbi_dependencies/build.sh b/src/tests/tools/mock_nbi_dependencies/build.sh
new file mode 100755
index 000000000..e284de000
--- /dev/null
+++ b/src/tests/tools/mock_nbi_dependencies/build.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+# Make folder containing the script the root folder for its execution
+cd $(dirname $0)
+
+docker build -t mock-nbi-dependencies:test -f Dockerfile .
+docker tag mock-nbi-dependencies:test localhost:32000/tfs/mock-nbi-dependencies:test
+docker push localhost:32000/tfs/mock-nbi-dependencies:test
diff --git a/src/tests/tools/mock_nbi_dependencies/deploy.sh b/src/tests/tools/mock_nbi_dependencies/deploy.sh
new file mode 100755
index 000000000..8e876a7d3
--- /dev/null
+++ b/src/tests/tools/mock_nbi_dependencies/deploy.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+kubectl delete namespace mocks
+kubectl --namespace mocks apply -f mock-nbi-dependencies.yaml
diff --git a/src/tests/tools/mock_nbi_dependencies/mock-nbi-dependencies.yaml b/src/tests/tools/mock_nbi_dependencies/mock-nbi-dependencies.yaml
new file mode 100644
index 000000000..770dbf742
--- /dev/null
+++ b/src/tests/tools/mock_nbi_dependencies/mock-nbi-dependencies.yaml
@@ -0,0 +1,76 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+kind: Namespace
+apiVersion: v1
+metadata:
+  name: mocks
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: mock-nbi-dependencies
+spec:
+  selector:
+    matchLabels:
+      app: mock-nbi-dependencies
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: mock-nbi-dependencies
+    spec:
+      terminationGracePeriodSeconds: 5
+      containers:
+        - name: server
+          image: localhost:32000/tfs/mock-nbi-dependencies:test
+          imagePullPolicy: IfNotPresent
+          ports:
+            - containerPort: 10000
+          env:
+            - name: BIND_ADDRESS
+              value: "0.0.0.0"
+            - name: BIND_PORT
+              value: "10000"
+            - name: LOG_LEVEL
+              value: "DEBUG"
+          readinessProbe:
+            exec:
+              command: ["/bin/grpc_health_probe", "-addr=:10000"]
+          livenessProbe:
+            exec:
+              command: ["/bin/grpc_health_probe", "-addr=:10000"]
+          resources:
+            requests:
+              cpu: 250m
+              memory: 128Mi
+            limits:
+              cpu: 700m
+              memory: 1024Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: mock-nbi-dependencies
+  labels:
+    app: mock-nbi-dependencies
+spec:
+  type: ClusterIP
+  selector:
+    app: mock-nbi-dependencies
+  ports:
+    - name: grpc
+      protocol: TCP
+      port: 10000
+      targetPort: 10000
diff --git a/src/tests/tools/mock_nbi_dependencies/requirements.in b/src/tests/tools/mock_nbi_dependencies/requirements.in
new file mode 100644
index 000000000..39d8525f2
--- /dev/null
+++ b/src/tests/tools/mock_nbi_dependencies/requirements.in
@@ -0,0 +1,19 @@
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+grpcio==1.47.*
+grpcio-health-checking==1.47.*
+grpcio-reflection==1.47.*
+grpcio-tools==1.47.*
+protobuf==3.20.*
diff --git a/src/tests/tools/mock_nbi_dependencies/run.sh b/src/tests/tools/mock_nbi_dependencies/run.sh
new file mode 100755
index 000000000..47ea5717a
--- /dev/null
+++ b/src/tests/tools/mock_nbi_dependencies/run.sh
@@ -0,0 +1,19 @@
+#!/usr/bin/env bash
+# Copyright 2022-2024 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/)
+#
+# 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.
+
+# Make folder containing the script the root folder for its execution
+cd $(dirname $0)
+
+python MockIetfActnSdnCtrl.py
-- 
GitLab