From e22bc8177205f7f5744d28d8045f738cb738825b Mon Sep 17 00:00:00 2001
From: Carlos Manso <carlos.manso@cttc.es>
Date: Thu, 21 Dec 2023 10:08:46 +0100
Subject: [PATCH] Changed e2eorchestrator to e2e_orchestrator

---
 ...vice.yaml => e2e_orchestratorservice.yaml} |  18 +-
 my_deploy.sh                                  |   6 +-
 .../.gitlab-ci.yml                            |   0
 .../Config.py                                 |   0
 .../Dockerfile                                |  12 +-
 .../__init__.py                               |   0
 .../client/E2EOrchestratorClient.py           |   0
 .../client/__init__.py                        |   0
 .../requirements.in                           |   0
 .../service/E2EOrchestratorService.py         |   0
 .../E2EOrchestratorServiceServicerImpl.py     |   0
 .../service/__init__.py                       |   0
 .../service/__main__.py                       |   0
 src/e2e_orchestrator/tests/__init__.py        |  14 +
 src/e2e_orchestrator/tests/deploy_specs.sh    | 154 +++++++++++
 .../tests/descriptors_emulated.json           | 250 ++++++++++++++++++
 .../tests/functional_tests/Fixtures.py        |  39 +++
 .../tests/functional_tests/Objects.py         |  60 +++++
 .../tests/functional_tests/__init__.py        |  14 +
 .../test_functional_bootstrap.py              |  71 +++++
 .../test_functional_cleanup.py                |  44 +++
 .../test_functional_compute_path.py           |  61 +++++
 src/e2e_orchestrator/tests/redeploy.sh        |  18 ++
 .../tests/run_test_01_bootstrap.sh            |  17 ++
 .../tests/run_test_02_compute_path.sh         |  17 ++
 .../tests/run_test_03_cleanup.sh              |  17 ++
 src/e2e_orchestrator/tests/run_tests.sh       |  20 ++
 src/tests/Fixtures.py                         |   2 +-
 .../tests/test_functional_compute_path.py     |   2 +-
 29 files changed, 816 insertions(+), 20 deletions(-)
 rename manifests/{e2eorchestratorservice.yaml => e2e_orchestratorservice.yaml} (85%)
 rename src/{e2eorchestrator => e2e_orchestrator}/.gitlab-ci.yml (100%)
 rename src/{e2eorchestrator => e2e_orchestrator}/Config.py (100%)
 rename src/{e2eorchestrator => e2e_orchestrator}/Dockerfile (86%)
 rename src/{e2eorchestrator => e2e_orchestrator}/__init__.py (100%)
 rename src/{e2eorchestrator => e2e_orchestrator}/client/E2EOrchestratorClient.py (100%)
 rename src/{e2eorchestrator => e2e_orchestrator}/client/__init__.py (100%)
 rename src/{e2eorchestrator => e2e_orchestrator}/requirements.in (100%)
 rename src/{e2eorchestrator => e2e_orchestrator}/service/E2EOrchestratorService.py (100%)
 rename src/{e2eorchestrator => e2e_orchestrator}/service/E2EOrchestratorServiceServicerImpl.py (100%)
 rename src/{e2eorchestrator => e2e_orchestrator}/service/__init__.py (100%)
 rename src/{e2eorchestrator => e2e_orchestrator}/service/__main__.py (100%)
 create mode 100644 src/e2e_orchestrator/tests/__init__.py
 create mode 100755 src/e2e_orchestrator/tests/deploy_specs.sh
 create mode 100644 src/e2e_orchestrator/tests/descriptors_emulated.json
 create mode 100644 src/e2e_orchestrator/tests/functional_tests/Fixtures.py
 create mode 100644 src/e2e_orchestrator/tests/functional_tests/Objects.py
 create mode 100644 src/e2e_orchestrator/tests/functional_tests/__init__.py
 create mode 100644 src/e2e_orchestrator/tests/functional_tests/test_functional_bootstrap.py
 create mode 100644 src/e2e_orchestrator/tests/functional_tests/test_functional_cleanup.py
 create mode 100644 src/e2e_orchestrator/tests/functional_tests/test_functional_compute_path.py
 create mode 100755 src/e2e_orchestrator/tests/redeploy.sh
 create mode 100755 src/e2e_orchestrator/tests/run_test_01_bootstrap.sh
 create mode 100755 src/e2e_orchestrator/tests/run_test_02_compute_path.sh
 create mode 100755 src/e2e_orchestrator/tests/run_test_03_cleanup.sh
 create mode 100755 src/e2e_orchestrator/tests/run_tests.sh

diff --git a/manifests/e2eorchestratorservice.yaml b/manifests/e2e_orchestratorservice.yaml
similarity index 85%
rename from manifests/e2eorchestratorservice.yaml
rename to manifests/e2e_orchestratorservice.yaml
index acefd44b9..13717b7fa 100644
--- a/manifests/e2eorchestratorservice.yaml
+++ b/manifests/e2e_orchestratorservice.yaml
@@ -15,20 +15,20 @@
 apiVersion: apps/v1
 kind: Deployment
 metadata:
-  name: e2eorchestratorservice
+  name: e2e-orchestratorservice
 spec:
   selector:
     matchLabels:
-      app: e2eorchestratorservice
+      app: e2e-orchestratorservice
   template:
     metadata:
       labels:
-        app: e2eorchestratorservice
+        app: e2e-orchestratorservice
     spec:
       terminationGracePeriodSeconds: 5
       containers:
       - name: server
-        image: labs.etsi.org:5050/tfs/controller/e2eorchestrator:latest
+        image: labs.etsi.org:5050/tfs/controller/e2e_orchestrator:latest
         imagePullPolicy: Always
         ports:
         - containerPort: 10050
@@ -58,13 +58,13 @@ spec:
 apiVersion: v1
 kind: Service
 metadata:
-  name: e2eorchestratorservice
+  name: e2e-orchestratorservice
   labels:
-    app: e2eorchestratorservice
+    app: e2e-orchestratorservice
 spec:
   type: ClusterIP
   selector:
-    app: e2eorchestratorservice
+    app: e2e-orchestratorservice
   ports:
   - name: grpc
     port: 10050
@@ -76,12 +76,12 @@ spec:
 apiVersion: autoscaling/v2
 kind: HorizontalPodAutoscaler
 metadata:
-  name: e2eorchestratorservice-hpa
+  name: e2e-orchestratorservice-hpa
 spec:
   scaleTargetRef:
     apiVersion: apps/v1
     kind: Deployment
-    name: e2eorchestratorservice
+    name: e2e-orchestratorservice
   minReplicas: 1
   maxReplicas: 20
   metrics:
diff --git a/my_deploy.sh b/my_deploy.sh
index 73eb85fb5..0fcb51f90 100755
--- a/my_deploy.sh
+++ b/my_deploy.sh
@@ -44,7 +44,7 @@ export TFS_COMPONENTS="context device pathcomp service slice nbi webui load_gene
 #export TFS_COMPONENTS="${TFS_COMPONENTS} forecaster"
 
 # Uncomment to activate E2E Orchestrator
-#export TFS_COMPONENTS="${TFS_COMPONENTS} e2eorchestrator"
+#export TFS_COMPONENTS="${TFS_COMPONENTS} e2e_orchestrator"
 
 # Set the tag you want to use for your images.
 export TFS_IMAGE_TAG="dev"
@@ -93,7 +93,7 @@ export CRDB_DATABASE="tfs"
 export CRDB_DEPLOY_MODE="single"
 
 # Disable flag for dropping database, if it exists.
-export CRDB_DROP_DATABASE_IF_EXISTS="YES"
+export CRDB_DROP_DATABASE_IF_EXISTS=""
 
 # Disable flag for re-deploying CockroachDB from scratch.
 export CRDB_REDEPLOY=""
@@ -141,7 +141,7 @@ export QDB_TABLE_MONITORING_KPIS="tfs_monitoring_kpis"
 export QDB_TABLE_SLICE_GROUPS="tfs_slice_groups"
 
 # Disable flag for dropping tables if they exist.
-export QDB_DROP_TABLES_IF_EXIST="YES"
+export QDB_DROP_TABLES_IF_EXIST=""
 
 # Disable flag for re-deploying QuestDB from scratch.
 export QDB_REDEPLOY=""
diff --git a/src/e2eorchestrator/.gitlab-ci.yml b/src/e2e_orchestrator/.gitlab-ci.yml
similarity index 100%
rename from src/e2eorchestrator/.gitlab-ci.yml
rename to src/e2e_orchestrator/.gitlab-ci.yml
diff --git a/src/e2eorchestrator/Config.py b/src/e2e_orchestrator/Config.py
similarity index 100%
rename from src/e2eorchestrator/Config.py
rename to src/e2e_orchestrator/Config.py
diff --git a/src/e2eorchestrator/Dockerfile b/src/e2e_orchestrator/Dockerfile
similarity index 86%
rename from src/e2eorchestrator/Dockerfile
rename to src/e2e_orchestrator/Dockerfile
index 52bd806f5..85b7f1666 100644
--- a/src/e2eorchestrator/Dockerfile
+++ b/src/e2e_orchestrator/Dockerfile
@@ -67,18 +67,18 @@ RUN rm *.proto
 RUN find . -type f -exec sed -i -E 's/(import\ .*)_pb2/from . \1_pb2/g' {} \;
 
 # Create module sub-folders
-RUN mkdir -p /home/teraflow/controller/e2eorchestrator
+RUN mkdir -p /home/teraflow/controller/e2e_orchestrator
 WORKDIR /home/teraflow/controller
 
 # Get Python packages per module
-COPY --chown=teraflow:teraflow ./src/e2eorchestrator/requirements.in e2eorchestrator/requirements.in
+COPY --chown=teraflow:teraflow ./src/e2e_orchestrator/requirements.in e2e_orchestrator/requirements.in
 # consider common and specific requirements to avoid inconsistencies with dependencies
-RUN pip-compile --quiet --output-file=e2eorchestrator/requirements.txt e2eorchestrator/requirements.in common_requirements.in
-RUN python3 -m pip install -r e2eorchestrator/requirements.txt
+RUN pip-compile --quiet --output-file=e2e_orchestrator/requirements.txt e2e_orchestrator/requirements.in common_requirements.in
+RUN python3 -m pip install -r e2e_orchestrator/requirements.txt
 
 # Add component files into working directory
 COPY --chown=teraflow:teraflow ./src/context/. context
-COPY --chown=teraflow:teraflow ./src/e2eorchestrator/. e2eorchestrator
+COPY --chown=teraflow:teraflow ./src/e2e_orchestrator/. e2e_orchestrator
 
 # Start the service
-ENTRYPOINT ["python", "-m", "e2eorchestrator.service"]
+ENTRYPOINT ["python", "-m", "e2e_orchestrator.service"]
diff --git a/src/e2eorchestrator/__init__.py b/src/e2e_orchestrator/__init__.py
similarity index 100%
rename from src/e2eorchestrator/__init__.py
rename to src/e2e_orchestrator/__init__.py
diff --git a/src/e2eorchestrator/client/E2EOrchestratorClient.py b/src/e2e_orchestrator/client/E2EOrchestratorClient.py
similarity index 100%
rename from src/e2eorchestrator/client/E2EOrchestratorClient.py
rename to src/e2e_orchestrator/client/E2EOrchestratorClient.py
diff --git a/src/e2eorchestrator/client/__init__.py b/src/e2e_orchestrator/client/__init__.py
similarity index 100%
rename from src/e2eorchestrator/client/__init__.py
rename to src/e2e_orchestrator/client/__init__.py
diff --git a/src/e2eorchestrator/requirements.in b/src/e2e_orchestrator/requirements.in
similarity index 100%
rename from src/e2eorchestrator/requirements.in
rename to src/e2e_orchestrator/requirements.in
diff --git a/src/e2eorchestrator/service/E2EOrchestratorService.py b/src/e2e_orchestrator/service/E2EOrchestratorService.py
similarity index 100%
rename from src/e2eorchestrator/service/E2EOrchestratorService.py
rename to src/e2e_orchestrator/service/E2EOrchestratorService.py
diff --git a/src/e2eorchestrator/service/E2EOrchestratorServiceServicerImpl.py b/src/e2e_orchestrator/service/E2EOrchestratorServiceServicerImpl.py
similarity index 100%
rename from src/e2eorchestrator/service/E2EOrchestratorServiceServicerImpl.py
rename to src/e2e_orchestrator/service/E2EOrchestratorServiceServicerImpl.py
diff --git a/src/e2eorchestrator/service/__init__.py b/src/e2e_orchestrator/service/__init__.py
similarity index 100%
rename from src/e2eorchestrator/service/__init__.py
rename to src/e2e_orchestrator/service/__init__.py
diff --git a/src/e2eorchestrator/service/__main__.py b/src/e2e_orchestrator/service/__main__.py
similarity index 100%
rename from src/e2eorchestrator/service/__main__.py
rename to src/e2e_orchestrator/service/__main__.py
diff --git a/src/e2e_orchestrator/tests/__init__.py b/src/e2e_orchestrator/tests/__init__.py
new file mode 100644
index 000000000..1549d9811
--- /dev/null
+++ b/src/e2e_orchestrator/tests/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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/e2e_orchestrator/tests/deploy_specs.sh b/src/e2e_orchestrator/tests/deploy_specs.sh
new file mode 100755
index 000000000..67aed976a
--- /dev/null
+++ b/src/e2e_orchestrator/tests/deploy_specs.sh
@@ -0,0 +1,154 @@
+#!/bin/bash
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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.
+
+
+# ----- TeraFlowSDN ------------------------------------------------------------
+
+# Set the URL of the internal MicroK8s Docker registry where the images will be uploaded to.
+export TFS_REGISTRY_IMAGES="http://localhost:32000/tfs/"
+
+# Set the list of components, separated by spaces, you want to build images for, and deploy.
+#export TFS_COMPONENTS="context device pathcomp service slice nbi webui load_generator"
+export TFS_COMPONENTS="context device pathcomp service slice nbi webui"
+
+# Uncomment to activate Monitoring
+# export TFS_COMPONENTS="${TFS_COMPONENTS} monitoring"
+
+# Uncomment to activate ZTP and Policy Manager
+#export TFS_COMPONENTS="${TFS_COMPONENTS} ztp policy"
+# export TFS_COMPONENTS="${TFS_COMPONENTS} ztp"
+
+# Uncomment to activate Optical CyberSecurity
+#export TFS_COMPONENTS="${TFS_COMPONENTS} dbscanserving opticalattackmitigator opticalattackdetector opticalattackmanager"
+
+# Uncomment to activate L3 CyberSecurity
+#export TFS_COMPONENTS="${TFS_COMPONENTS} l3_attackmitigator l3_centralizedattackdetector"
+
+# Uncomment to activate TE
+#export TFS_COMPONENTS="${TFS_COMPONENTS} te"
+
+# Uncomment to activate E2E_Orchestrator
+export TFS_COMPONENTS="${TFS_COMPONENTS} e2e_orchestrator"
+
+
+
+# Set the tag you want to use for your images.
+export TFS_IMAGE_TAG="dev"
+
+# Set the name of the Kubernetes namespace to deploy TFS to.
+export TFS_K8S_NAMESPACE="tfs"
+
+# Set additional manifest files to be applied after the deployment
+export TFS_EXTRA_MANIFESTS="manifests/nginx_ingress_http.yaml"
+
+# Uncomment to monitor performance of components
+export TFS_EXTRA_MANIFESTS="${TFS_EXTRA_MANIFESTS} manifests/servicemonitors.yaml"
+
+# Uncomment when deploying Optical CyberSecurity
+#export TFS_EXTRA_MANIFESTS="${TFS_EXTRA_MANIFESTS} manifests/cachingservice.yaml"
+
+# Set the new Grafana admin password
+export TFS_GRAFANA_PASSWORD="admin123+"
+
+# Disable skip-build flag to rebuild the Docker images.
+export TFS_SKIP_BUILD=""
+
+
+# ----- CockroachDB ------------------------------------------------------------
+
+# Set the namespace where CockroackDB will be deployed.
+export CRDB_NAMESPACE="crdb"
+
+# Set the external port CockroackDB Postgre SQL interface will be exposed to.
+export CRDB_EXT_PORT_SQL="26257"
+
+# Set the external port CockroackDB HTTP Mgmt GUI interface will be exposed to.
+export CRDB_EXT_PORT_HTTP="8081"
+
+# Set the database username to be used by Context.
+export CRDB_USERNAME="tfs"
+
+# Set the database user's password to be used by Context.
+export CRDB_PASSWORD="tfs123"
+
+# Set the database name to be used by Context.
+export CRDB_DATABASE="tfs"
+
+# Set CockroachDB installation mode to 'single'. This option is convenient for development and testing.
+# See ./deploy/all.sh or ./deploy/crdb.sh for additional details
+export CRDB_DEPLOY_MODE="single"
+
+# Disable flag for dropping database, if it exists.
+export CRDB_DROP_DATABASE_IF_EXISTS="YES"
+
+# Disable flag for re-deploying CockroachDB from scratch.
+export CRDB_REDEPLOY=""
+
+
+# ----- NATS -------------------------------------------------------------------
+
+# Set the namespace where NATS will be deployed.
+export NATS_NAMESPACE="nats"
+
+# Set the external port NATS Client interface will be exposed to.
+export NATS_EXT_PORT_CLIENT="4222"
+
+# Set the external port NATS HTTP Mgmt GUI interface will be exposed to.
+export NATS_EXT_PORT_HTTP="8222"
+
+# Disable flag for re-deploying NATS from scratch.
+export NATS_REDEPLOY=""
+
+
+# ----- QuestDB ----------------------------------------------------------------
+
+# Set the namespace where QuestDB will be deployed.
+export QDB_NAMESPACE="qdb"
+
+# Set the external port QuestDB Postgre SQL interface will be exposed to.
+export QDB_EXT_PORT_SQL="8812"
+
+# Set the external port QuestDB Influx Line Protocol interface will be exposed to.
+export QDB_EXT_PORT_ILP="9009"
+
+# Set the external port QuestDB HTTP Mgmt GUI interface will be exposed to.
+export QDB_EXT_PORT_HTTP="9000"
+
+# Set the database username to be used for QuestDB.
+export QDB_USERNAME="admin"
+
+# Set the database user's password to be used for QuestDB.
+export QDB_PASSWORD="quest"
+
+# Set the table name to be used by Monitoring for KPIs.
+export QDB_TABLE_MONITORING_KPIS="tfs_monitoring_kpis"
+
+# Set the table name to be used by Slice for plotting groups.
+export QDB_TABLE_SLICE_GROUPS="tfs_slice_groups"
+
+# Disable flag for dropping tables if they exist.
+export QDB_DROP_TABLES_IF_EXIST="YES"
+
+# Disable flag for re-deploying QuestDB from scratch.
+export QDB_REDEPLOY=""
+
+
+# ----- K8s Observability ------------------------------------------------------
+
+# Set the external port Prometheus Mgmt HTTP GUI interface will be exposed to.
+export PROM_EXT_PORT_HTTP="9090"
+
+# Set the external port Grafana HTTP Dashboards will be exposed to.
+export GRAF_EXT_PORT_HTTP="3000"
diff --git a/src/e2e_orchestrator/tests/descriptors_emulated.json b/src/e2e_orchestrator/tests/descriptors_emulated.json
new file mode 100644
index 000000000..a2918ace9
--- /dev/null
+++ b/src/e2e_orchestrator/tests/descriptors_emulated.json
@@ -0,0 +1,250 @@
+{
+    "contexts": [
+        {
+            "context_id": {"context_uuid": {"uuid": "admin"}},
+            "topology_ids": [], "service_ids": []
+        }
+    ],
+    "topologies": [
+        {
+            "topology_id": {
+                "context_id": {"context_uuid": {"uuid": "admin"}},
+                "topology_uuid": {"uuid": "admin"}
+            },
+            "device_ids": [
+                {"device_uuid": {"uuid": "R1"}},
+                {"device_uuid": {"uuid": "R2"}},
+                {"device_uuid": {"uuid": "T1"}},
+                {"device_uuid": {"uuid": "T2"}},
+                {"device_uuid": {"uuid": "M1"}},
+                {"device_uuid": {"uuid": "M2"}}
+            ],
+            "link_ids": [
+                {"link_uuid": {"uuid": "R1==T1"}},
+                {"link_uuid": {"uuid": "T1==R1"}},
+                {"link_uuid": {"uuid": "R2==T2"}},
+                {"link_uuid": {"uuid": "T2==R2"}},
+
+                {"link_uuid": {"uuid": "T1==M1"}},
+                {"link_uuid": {"uuid": "M1==T1"}},
+                {"link_uuid": {"uuid": "T2==M2"}},
+                {"link_uuid": {"uuid": "M2==T2"}},
+
+                {"link_uuid": {"uuid": "M1==M2"}},
+                {"link_uuid": {"uuid": "M2==M1"}}
+
+
+            ]
+        }
+    ],
+    "devices": [
+        {
+            "device_id": {"device_uuid": {"uuid": "R1"}}, "device_type": "emu-packet-router", "device_drivers": [0],
+            "device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
+                    {"sample_types": [], "type": "copper", "uuid": "1/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/4"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/4"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/4"}
+                ]}}}
+            ]}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "R2"}}, "device_type": "emu-packet-router", "device_drivers": [0],
+            "device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
+                    {"sample_types": [], "type": "copper", "uuid": "1/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/4"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/4"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/4"}
+                ]}}}
+            ]}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "T1"}}, "device_type": "emu-optical-transponder", "device_drivers": [0],
+            "device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
+                    {"sample_types": [], "type": "copper", "uuid": "1/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/4"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/4"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/4"}
+                ]}}}
+            ]}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "T2"}}, "device_type": "emu-optical-transponder", "device_drivers": [0],
+            "device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
+                    {"sample_types": [], "type": "copper", "uuid": "1/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/4"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/4"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/4"}
+                ]}}}
+            ]}
+        },
+
+        {
+            "device_id": {"device_uuid": {"uuid": "M1"}}, "device_type": "emu-optical-roadm", "device_drivers": [0],
+            "device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
+                    {"sample_types": [], "type": "copper", "uuid": "1/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/4"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/4"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/4"}
+                ]}}}
+            ]}
+        },
+
+
+        {
+            "device_id": {"device_uuid": {"uuid": "M2"}}, "device_type": "emu-optical-roadm", "device_drivers": [0],
+            "device_endpoints": [], "device_operational_status": 1, "device_config": {"config_rules": [
+                {"action": 1, "custom": {"resource_key": "_connect/address", "resource_value": "127.0.0.1"}},
+                {"action": 1, "custom": {"resource_key": "_connect/port", "resource_value": "0"}},
+                {"action": 1, "custom": {"resource_key": "_connect/settings", "resource_value": {"endpoints": [
+                    {"sample_types": [], "type": "copper", "uuid": "1/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "1/4"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "2/4"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/1"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/2"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/3"},
+                    {"sample_types": [], "type": "copper", "uuid": "3/4"}
+                ]}}}
+            ]}
+        }
+
+
+    ],
+    "links": [
+        {
+            "link_id": {"link_uuid": {"uuid": "R1==T1"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "1/1"}},
+                {"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1/1"}}
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "T1==R1"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "1/1"}},
+                {"device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "1/1"}}
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "R2==T2"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "1/2"}},
+                {"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "1/2"}}
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "T2==R2"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "1/2"}},
+                {"device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "1/2"}}
+            ]
+        },
+
+
+        {
+            "link_id": {"link_uuid": {"uuid": "T1==M1"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "2/1"}},
+                {"device_id": {"device_uuid": {"uuid": "M1"}}, "endpoint_uuid": {"uuid": "2/1"}}
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "M1==T1"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "M1"}}, "endpoint_uuid": {"uuid": "2/1"}},
+                {"device_id": {"device_uuid": {"uuid": "T1"}}, "endpoint_uuid": {"uuid": "2/1"}}
+            ]
+        },
+
+        {
+            "link_id": {"link_uuid": {"uuid": "T2==M2"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "2/2"}},
+                {"device_id": {"device_uuid": {"uuid": "M2"}}, "endpoint_uuid": {"uuid": "2/2"}}
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "M2==T2"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "M2"}}, "endpoint_uuid": {"uuid": "2/2"}},
+                {"device_id": {"device_uuid": {"uuid": "T2"}}, "endpoint_uuid": {"uuid": "2/2"}}
+            ]
+        },
+
+        {
+            "link_id": {"link_uuid": {"uuid": "M1==M2"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "M1"}}, "endpoint_uuid": {"uuid": "3/1"}},
+                {"device_id": {"device_uuid": {"uuid": "M2"}}, "endpoint_uuid": {"uuid": "3/1"}}
+            ]
+        },
+        {
+            "link_id": {"link_uuid": {"uuid": "M2==M1"}},
+            "link_endpoint_ids": [
+                {"device_id": {"device_uuid": {"uuid": "M2"}}, "endpoint_uuid": {"uuid": "3/1"}},
+                {"device_id": {"device_uuid": {"uuid": "M1"}}, "endpoint_uuid": {"uuid": "3/1"}}
+            ]
+        }
+
+    ]
+}
\ No newline at end of file
diff --git a/src/e2e_orchestrator/tests/functional_tests/Fixtures.py b/src/e2e_orchestrator/tests/functional_tests/Fixtures.py
new file mode 100644
index 000000000..0f7b4b0d4
--- /dev/null
+++ b/src/e2e_orchestrator/tests/functional_tests/Fixtures.py
@@ -0,0 +1,39 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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 pytest
+from context.client.ContextClient import ContextClient
+from device.client.DeviceClient import DeviceClient
+from monitoring.client.MonitoringClient import MonitoringClient
+from e2e_orchestrator.client.E2EOrchestratorClient import E2EOrchestratorClient
+from service.client.ServiceClient import ServiceClient
+
+
+@pytest.fixture(scope='session')
+def context_client():
+    _client = ContextClient()
+    yield _client
+    _client.close()
+
+@pytest.fixture(scope='session')
+def device_client():
+    _client = DeviceClient()
+    yield _client
+    _client.close()
+
+@pytest.fixture(scope='session')
+def e2eorchestrator_client():
+    _client = E2EOrchestratorClient()
+    yield _client
+    _client.close()
diff --git a/src/e2e_orchestrator/tests/functional_tests/Objects.py b/src/e2e_orchestrator/tests/functional_tests/Objects.py
new file mode 100644
index 000000000..1748efec9
--- /dev/null
+++ b/src/e2e_orchestrator/tests/functional_tests/Objects.py
@@ -0,0 +1,60 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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 os
+from typing import Dict, List, Tuple
+from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME
+from common.tools.object_factory.Context import json_context, json_context_id
+from common.tools.object_factory.Device import (
+    json_device_connect_rules, json_device_emulated_connect_rules, json_device_emulated_packet_router_disabled,
+    json_device_connect_rules, json_device_id, json_device_p4_disabled,
+    json_device_emulated_tapi_disabled, json_device_id, json_device_packetrouter_disabled, json_device_tapi_disabled)
+from common.tools.object_factory.Service import (
+    get_service_uuid, json_service_l3nm_planned,json_service_p4_planned)
+from common.tools.object_factory.ConfigRule import (
+    json_config_rule_set, json_config_rule_delete)
+from common.tools.object_factory.EndPoint import json_endpoint, json_endpoint_ids, json_endpoints, json_endpoint_id
+from common.tools.object_factory.EndPoint import json_endpoint_descriptor
+
+
+
+DEVICE_R1_UUID             = 'R1'
+DEVICE_R2_UUID             = 'R2'
+
+DEVICE_R1_ID               = json_device_id(DEVICE_R1_UUID)
+DEVICE_R1_ENDPOINT_DEFS    = [json_endpoint_descriptor('2/2', 'port')]
+DEVICE_R2_ID               = json_device_id(DEVICE_R2_UUID)
+DEVICE_R2_ENDPOINT_DEFS    = [json_endpoint_descriptor('2/2', 'port')]
+
+DEVICE_R1_ENDPOINTS        = json_endpoints(DEVICE_R1_ID, DEVICE_R1_ENDPOINT_DEFS)
+DEVICE_R2_ENDPOINTS        = json_endpoints(DEVICE_R2_ID, DEVICE_R2_ENDPOINT_DEFS)
+
+
+DEVICE_R1_ENDPOINT_IDS     = json_endpoint_ids(DEVICE_R1_ID, DEVICE_R1_ENDPOINT_DEFS)
+ENDPOINT_ID_R1             = DEVICE_R1_ENDPOINTS[0]['endpoint_id']
+DEVICE_R2_ENDPOINT_IDS     = json_endpoint_ids(DEVICE_R2_ID, DEVICE_R2_ENDPOINT_DEFS)
+ENDPOINT_ID_R2             = DEVICE_R2_ENDPOINTS[0]['endpoint_id']
+
+
+# ----- Service ----------------------------------------------------------------------------------------------------------
+
+
+SERVICE_R1_R2_UUID          = get_service_uuid(ENDPOINT_ID_R1, ENDPOINT_ID_R2)
+SERVICE_R1_R2               = json_service_p4_planned(SERVICE_R1_R2_UUID)
+SERVICE_R1_R2_ENDPOINT_IDS  = [DEVICE_R1_ENDPOINT_IDS[0], DEVICE_R2_ENDPOINT_IDS[0]]
+
+
+SERVICES = [
+    (SERVICE_R1_R2, SERVICE_R1_R2_ENDPOINT_IDS)
+]
diff --git a/src/e2e_orchestrator/tests/functional_tests/__init__.py b/src/e2e_orchestrator/tests/functional_tests/__init__.py
new file mode 100644
index 000000000..1549d9811
--- /dev/null
+++ b/src/e2e_orchestrator/tests/functional_tests/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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/e2e_orchestrator/tests/functional_tests/test_functional_bootstrap.py b/src/e2e_orchestrator/tests/functional_tests/test_functional_bootstrap.py
new file mode 100644
index 000000000..d0e85e4e3
--- /dev/null
+++ b/src/e2e_orchestrator/tests/functional_tests/test_functional_bootstrap.py
@@ -0,0 +1,71 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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, time
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.proto.context_pb2 import ContextId, DeviceOperationalStatusEnum, Empty
+from common.proto.monitoring_pb2 import KpiDescriptorList
+from common.tools.descriptor.Loader import DescriptorLoader, check_descriptor_load_results, validate_empty_scenario
+from common.tools.object_factory.Context import json_context_id
+from context.client.ContextClient import ContextClient
+from device.client.DeviceClient import DeviceClient
+from monitoring.client.MonitoringClient import MonitoringClient
+from .Fixtures import context_client, device_client # pylint: disable=unused-import
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+DESCRIPTOR_FILE = 'src/e2e_orchestrator/tests/descriptors_emulated.json'
+ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME))
+
+def test_scenario_bootstrap(
+    context_client : ContextClient, # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,   # pylint: disable=redefined-outer-name
+) -> None:
+    validate_empty_scenario(context_client)
+
+    descriptor_loader = DescriptorLoader(
+        descriptors_file=DESCRIPTOR_FILE, context_client=context_client, device_client=device_client)
+    results = descriptor_loader.process()
+    check_descriptor_load_results(results, descriptor_loader)
+    descriptor_loader.validate()
+
+    # Verify the scenario has no services/slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.service_ids) == 0
+    assert len(response.slice_ids) == 0
+
+def test_scenario_devices_enabled(
+    context_client : ContextClient,         # pylint: disable=redefined-outer-name
+) -> None:
+    """
+    This test validates that the devices are enabled.
+    """
+    DEVICE_OP_STATUS_ENABLED = DeviceOperationalStatusEnum.DEVICEOPERATIONALSTATUS_ENABLED
+
+    num_devices = -1
+    num_devices_enabled, num_retry = 0, 0
+    while (num_devices != num_devices_enabled) and (num_retry < 1):
+        time.sleep(1.0)
+        response = context_client.ListDevices(Empty())
+        num_devices = len(response.devices)
+        num_devices_enabled = 0
+        for device in response.devices:
+            if device.device_operational_status != DEVICE_OP_STATUS_ENABLED: continue
+            num_devices_enabled += 1
+        LOGGER.info('Num Devices enabled: {:d}/{:d}'.format(num_devices_enabled, num_devices))
+        num_retry += 1
+    assert num_devices_enabled == num_devices
+
+
diff --git a/src/e2e_orchestrator/tests/functional_tests/test_functional_cleanup.py b/src/e2e_orchestrator/tests/functional_tests/test_functional_cleanup.py
new file mode 100644
index 000000000..9c88b3b38
--- /dev/null
+++ b/src/e2e_orchestrator/tests/functional_tests/test_functional_cleanup.py
@@ -0,0 +1,44 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.proto.context_pb2 import ContextId
+from common.tools.descriptor.Loader import DescriptorLoader, validate_empty_scenario
+from common.tools.object_factory.Context import json_context_id
+from context.client.ContextClient import ContextClient
+from device.client.DeviceClient import DeviceClient
+from .Fixtures import context_client, device_client    # pylint: disable=unused-import
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+DESCRIPTOR_FILE = 'src/e2e_orchestrator/tests/descriptors_emulated.json'
+ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME))
+
+def test_scenario_cleanup(
+    context_client : ContextClient, # pylint: disable=redefined-outer-name
+    device_client : DeviceClient,   # pylint: disable=redefined-outer-name
+) -> None:
+    # Verify the scenario has no services/slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.service_ids) == 0
+    assert len(response.slice_ids) == 0
+
+    # Load descriptors and validate the base scenario
+    descriptor_loader = DescriptorLoader(
+        descriptors_file=DESCRIPTOR_FILE, context_client=context_client, device_client=device_client)
+    descriptor_loader.validate()
+    descriptor_loader.unload()
+    validate_empty_scenario(context_client)
diff --git a/src/e2e_orchestrator/tests/functional_tests/test_functional_compute_path.py b/src/e2e_orchestrator/tests/functional_tests/test_functional_compute_path.py
new file mode 100644
index 000000000..91a928e6a
--- /dev/null
+++ b/src/e2e_orchestrator/tests/functional_tests/test_functional_compute_path.py
@@ -0,0 +1,61 @@
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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, random
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.proto.context_pb2 import ContextId, Empty, ServiceTypeEnum, Service
+from common.proto.e2eorchestrator_pb2 import E2EOrchestratorRequest
+from common.proto.kpi_sample_types_pb2 import KpiSampleType
+from common.tools.descriptor.Loader import DescriptorLoader
+from common.tools.grpc.Tools import grpc_message_to_json_string
+from common.tools.object_factory.Context import json_context_id
+from context.client.ContextClient import ContextClient
+from service.client.ServiceClient import ServiceClient
+from .Fixtures import context_client, device_client, e2eorchestrator_client # pylint: disable=unused-import
+from e2e_orchestrator.client.E2EOrchestratorClient import E2EOrchestratorClient
+from .Objects import SERVICES
+import copy
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+DESCRIPTOR_FILE = 'src/e2e_orchestrator/tests/descriptors_emulated.json'
+ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME))
+
+
+def test_orchestration(context_client : ContextClient, e2eorchestrator_client : E2EOrchestratorClient): # pylint: disable=redefined-outer-name
+    # Load descriptors and validate the base scenario
+    descriptor_loader = DescriptorLoader(descriptors_file=DESCRIPTOR_FILE, context_client=context_client)
+    descriptor_loader.validate()
+
+    # Verify the scenario has no services/slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.service_ids) == 0
+    assert len(response.slice_ids) == 0
+
+
+
+    # ----- Compute E2E path ---------------------------------------------------------------
+    for service, endpoints in SERVICES:
+        service_uuid = service['service_id']['service_uuid']['uuid']
+        print('Creating Service {:s}'.format(service_uuid))
+        service_p4 = copy.deepcopy(service)
+        service_p4['service_endpoint_ids'].extend(endpoints)
+
+        request = E2EOrchestratorRequest()
+        request.service.MergeFrom(Service(**service_p4))
+        reply = e2eorchestrator_client.Compute(request)
+        LOGGER.info(reply)
+        assert len(reply.connections) == 6
+
diff --git a/src/e2e_orchestrator/tests/redeploy.sh b/src/e2e_orchestrator/tests/redeploy.sh
new file mode 100755
index 000000000..bd995709b
--- /dev/null
+++ b/src/e2e_orchestrator/tests/redeploy.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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.
+
+source src/e2e_orchestrator/tests/deploy_specs.sh
+./deploy/all.sh
+source tfs_runtime_env_vars.sh
diff --git a/src/e2e_orchestrator/tests/run_test_01_bootstrap.sh b/src/e2e_orchestrator/tests/run_test_01_bootstrap.sh
new file mode 100755
index 000000000..e875cf9ae
--- /dev/null
+++ b/src/e2e_orchestrator/tests/run_test_01_bootstrap.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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.
+
+source tfs_runtime_env_vars.sh
+pytest --verbose --log-level=INFO src/e2e_orchestrator/tests/functional_tests/test_functional_bootstrap.py
diff --git a/src/e2e_orchestrator/tests/run_test_02_compute_path.sh b/src/e2e_orchestrator/tests/run_test_02_compute_path.sh
new file mode 100755
index 000000000..be61e70e4
--- /dev/null
+++ b/src/e2e_orchestrator/tests/run_test_02_compute_path.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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.
+
+source tfs_runtime_env_vars.sh
+pytest --verbose --log-level=INFO src/e2e_orchestrator/tests/functional_tests/test_functional_compute_path.py 
diff --git a/src/e2e_orchestrator/tests/run_test_03_cleanup.sh b/src/e2e_orchestrator/tests/run_test_03_cleanup.sh
new file mode 100755
index 000000000..78ed3e1d1
--- /dev/null
+++ b/src/e2e_orchestrator/tests/run_test_03_cleanup.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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.
+
+source tfs_runtime_env_vars.sh
+pytest --verbose --log-level=INFO src/e2e_orchestrator/tests/functional_tests/test_functional_cleanup.py
diff --git a/src/e2e_orchestrator/tests/run_tests.sh b/src/e2e_orchestrator/tests/run_tests.sh
new file mode 100755
index 000000000..9f19bb438
--- /dev/null
+++ b/src/e2e_orchestrator/tests/run_tests.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (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.
+
+# Run functional tests
+source tfs_runtime_env_vars.sh
+pytest --verbose --log-level=INFO src/e2e_orchestrator/tests/functional_tests/test_functional_bootstrap.py
+pytest --verbose --log-level=INFO src/e2e_orchestrator/tests/functional_tests/test_functional_compute_path.py
+pytest --verbose --log-level=INFO src/e2e_orchestrator/tests/functional_tests/test_functional_cleanup.py
diff --git a/src/tests/Fixtures.py b/src/tests/Fixtures.py
index 78a470b54..62ad13f49 100644
--- a/src/tests/Fixtures.py
+++ b/src/tests/Fixtures.py
@@ -16,7 +16,7 @@ import pytest
 from context.client.ContextClient import ContextClient
 from device.client.DeviceClient import DeviceClient
 from monitoring.client.MonitoringClient import MonitoringClient
-from e2eorchestrator.client.E2EOrchestratorClient import E2EOrchestratorClient
+from e2e_orchestrator.client.E2EOrchestratorClient import E2EOrchestratorClient
 from service.client.ServiceClient import ServiceClient
 
 
diff --git a/src/tests/e2e_orchestrator/tests/test_functional_compute_path.py b/src/tests/e2e_orchestrator/tests/test_functional_compute_path.py
index 6d7282de8..cbbf71038 100644
--- a/src/tests/e2e_orchestrator/tests/test_functional_compute_path.py
+++ b/src/tests/e2e_orchestrator/tests/test_functional_compute_path.py
@@ -23,7 +23,7 @@ from common.tools.object_factory.Context import json_context_id
 from context.client.ContextClient import ContextClient
 from service.client.ServiceClient import ServiceClient
 from tests.Fixtures import service_client, context_client, e2eorchestrator_client                   # pylint: disable=unused-import
-from e2eorchestrator.client.E2EOrchestratorClient import E2EOrchestratorClient
+from e2e_orchestrator.client.E2EOrchestratorClient import E2EOrchestratorClient
 from .Objects import SERVICES
 import copy
 
-- 
GitLab