diff --git a/src/tests/ecoc24/Dockerfile b/src/tests/ecoc24/Dockerfile
index f9a616e76c682dc79c76cab3b4b5295ba229e3c9..52558e3384c0889ff47250a72ea2e28b56e17562 100644
--- a/src/tests/ecoc24/Dockerfile
+++ b/src/tests/ecoc24/Dockerfile
@@ -87,16 +87,14 @@ COPY src/tests/ecoc24/tests/. ./tests/ecoc24/tests/
 
 RUN tee ./run_tests.sh <<EOF
 #!/bin/bash
-source /var/teraflow/tfs_runtime_env_vars_e2e.sh
+# source /var/teraflow/tfs_runtime_env_vars_e2e.sh
 export PYTHONPATH=/var/teraflow
-pytest --verbose --log-level=INFO /var/teraflow/tests/ecoc24/tests/test_functional_bootstrap_opt.py --junitxml=/opt/results/report_bootstrap.xml
-pytest --verbose --log-level=INFO /var/teraflow/tests/ecoc24/tests/test_functional_bootstrap_ip.py --junitxml=/opt/results/report_bootstrap.xml
+pytest --verbose --log-level=INFO /var/teraflow/tests/ecoc24/tests/test_functional_bootstrap_opt.py --junitxml=/opt/results/report_bootstrap_opt.xml
+pytest --verbose --log-level=INFO /var/teraflow/tests/ecoc24/tests/test_functional_bootstrap_ip.py --junitxml=/opt/results/report_bootstrap_ip.xml
 sleep 5
-pytest --verbose --log-level=INFO /var/teraflow/tests/ecoc24/tests/test_functional_bootstrap_e2e.py --junitxml=/opt/results/report_bootstrap.xml
-#pytest --verbose --log-level=INFO /var/teraflow/tests/ofc24/tests/test_functional_create_service_unidir.py --junitxml=/opt/results/report_create_service_unidir.xml
-#pytest --verbose --log-level=INFO /var/teraflow/tests/ofc24/tests/test_functional_delete_service_unidir.py --junitxml=/opt/results/report_delete_service_unidir.xml
-#pytest --verbose --log-level=INFO /var/teraflow/tests/ofc24/tests/test_functional_create_service_bidir.py  --junitxml=/opt/results/report_create_service_bidir.xml
-#pytest --verbose --log-level=INFO /var/teraflow/tests/ofc24/tests/test_functional_delete_service_bidir.py  --junitxml=/opt/results/report_delete_service_bidir.xml
+pytest --verbose --log-level=INFO /var/teraflow/tests/ecoc24/tests/test_functional_bootstrap_e2e.py --junitxml=/opt/results/report_bootstrap_e2e.xml
+pytest --verbose --log-level=INFO /var/teraflow/tests/ofc24/tests/test_functional_create_service.py --junitxml=/opt/results/report_create_service.xml
+pytest --verbose --log-level=INFO /var/teraflow/tests/ofc24/tests/test_functional_delete_service.py --junitxml=/opt/results/report_delete_service.xml
 pytest --verbose --log-level=INFO /var/teraflow/tests/ofc24/tests/test_functional_cleanup.py               --junitxml=/opt/results/report_cleanup.xml
 EOF
 RUN chmod ug+x ./run_tests.sh
diff --git a/src/tests/ecoc24/tests/create_service.py b/src/tests/ecoc24/tests/create_service.py
new file mode 100644
index 0000000000000000000000000000000000000000..bc24bccd846819d07323a107a956e83718b1ebc7
--- /dev/null
+++ b/src/tests/ecoc24/tests/create_service.py
@@ -0,0 +1,27 @@
+import requests
+
+url = "http://localhost:8002/tfs-api/link/CSGW1_xe5-CSGW2_xe5"
+
+payload = {
+    "link_id": {"link_uuid": {"uuid": "CSGW1_xe5-CSGW2_xe5"}},
+    "link_endpoint_ids": [
+        {
+            "device_id": {"device_uuid": {"uuid": "CSGW1"}},
+            "endpoint_uuid": {"uuid": "PORT-xe5"}
+        },
+        {
+            "device_id": {"device_uuid": {"uuid": "CSGW2"}},
+            "endpoint_uuid": {"uuid": "PORT-xe5"}
+        }
+    ],
+    "link_type": "LINKTYPE_VIRTUAL_COPPER",
+    "attributes": {"total_capacity_gbps": 1}
+}
+headers = {
+    "cookie": "session%3Aaa82129ced5debbb=eyJjc3JmX3Rva2VuIjoiZGI1ZjY5Yjg0MDgxMjk3YmU3ZTY2MDMxZTljYzdiYTZmMWVjZjc0NCJ9.ZijdlQ.xdcOryRyoRgXCJ2XYwczsHw4yIQ; session%3A53cf1bf28136ee51=eyJjc3JmX3Rva2VuIjoiMDFlNWQwNzUyNDM3MDU1NWZhZjE3MGFiYzg4NGY2YmE3Y2M5MjM4OCJ9.ZikGzQ.KkIdiPPvqaO2pyBi7-mnlTKnmWs; session%3Ae52730446648c30a=eyJjc3JmX3Rva2VuIjoiODI4NTUwOTc4MWMxYzVjNmQ2ZDBiNGViMmU4ZDJmMzYzMzUxY2M2OSJ9.ZyOPuA.LWyhgLGjWOCb1H6wKlsG0evCV-A",
+    "Content-Type": "application/json"
+}
+
+response = requests.request("PUT", url, json=payload, headers=headers)
+
+print(response.text)
\ No newline at end of file
diff --git a/src/tests/ecoc24/tests/delete_service.py b/src/tests/ecoc24/tests/delete_service.py
new file mode 100644
index 0000000000000000000000000000000000000000..0281fb2b3a7b822516388692a43c3446e7391103
--- /dev/null
+++ b/src/tests/ecoc24/tests/delete_service.py
@@ -0,0 +1,10 @@
+import requests
+
+url = "http://localhost:8002/tfs-api/link/CSGW1_xe5-CSGW2_xe5"
+
+payload = ""
+headers = {"cookie": "session%3Aaa82129ced5debbb=eyJjc3JmX3Rva2VuIjoiZGI1ZjY5Yjg0MDgxMjk3YmU3ZTY2MDMxZTljYzdiYTZmMWVjZjc0NCJ9.ZijdlQ.xdcOryRyoRgXCJ2XYwczsHw4yIQ; session%3A53cf1bf28136ee51=eyJjc3JmX3Rva2VuIjoiMDFlNWQwNzUyNDM3MDU1NWZhZjE3MGFiYzg4NGY2YmE3Y2M5MjM4OCJ9.ZikGzQ.KkIdiPPvqaO2pyBi7-mnlTKnmWs; session%3Ae52730446648c30a=eyJjc3JmX3Rva2VuIjoiODI4NTUwOTc4MWMxYzVjNmQ2ZDBiNGViMmU4ZDJmMzYzMzUxY2M2OSJ9.ZyOPuA.LWyhgLGjWOCb1H6wKlsG0evCV-A"}
+
+response = requests.request("DELETE", url, data=payload, headers=headers)
+
+print(response.text)
\ No newline at end of file
diff --git a/src/tests/ecoc24/tests/test_functional_cleanup.py b/src/tests/ecoc24/tests/test_functional_cleanup.py
new file mode 100644
index 0000000000000000000000000000000000000000..a482c6e46559a97e3d194c6eb9dbc0a092cc39d4
--- /dev/null
+++ b/src/tests/ecoc24/tests/test_functional_cleanup.py
@@ -0,0 +1,44 @@
+# 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, os
+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 tests.Fixtures import context_client, device_client    # pylint: disable=unused-import
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+DESCRIPTOR_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'descriptors', 'topology.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/tests/ecoc24/tests/test_functional_create_service.py b/src/tests/ecoc24/tests/test_functional_create_service.py
new file mode 100644
index 0000000000000000000000000000000000000000..d4f21978c057681db82a0ddaaf46560db8915023
--- /dev/null
+++ b/src/tests/ecoc24/tests/test_functional_create_service.py
@@ -0,0 +1,74 @@
+# 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, os
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.proto.context_pb2 import ContextId, ServiceStatusEnum, ServiceTypeEnum
+from common.tools.descriptor.Loader import DescriptorLoader, check_descriptor_load_results
+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 device.client.DeviceClient import DeviceClient
+from service.client.ServiceClient import ServiceClient
+from tests.Fixtures import context_client, device_client, service_client        # pylint: disable=unused-import
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+DESCRIPTOR_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'descriptors', 'virtual_link.json')
+ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME))
+
+def test_service_creation_bidir(
+    context_client : ContextClient, # pylint: disable=redefined-outer-name
+    # device_client  : DeviceClient,  # pylint: disable=redefined-outer-name
+    # service_client : ServiceClient, # pylint: disable=redefined-outer-name
+):
+    # Load descriptors and validate the base scenario
+    # descriptor_loader = DescriptorLoader(
+    #     descriptors_file=DESCRIPTOR_FILE, context_client=context_client, device_client=device_client,
+    #     service_client=service_client
+    # )
+    # results = descriptor_loader.process()
+    # check_descriptor_load_results(results, descriptor_loader)
+
+    import create_service
+
+    # Verify the scenario has 1 service and 0 slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.service_ids) == 1
+    assert len(response.slice_ids) == 0
+
+    # Check there are no slices
+    response = context_client.ListSlices(ADMIN_CONTEXT_ID)
+    LOGGER.warning('Slices[{:d}] = {:s}'.format(len(response.slices), grpc_message_to_json_string(response)))
+    assert len(response.slices) == 0
+
+    # Check there is 1 service
+    response = context_client.ListServices(ADMIN_CONTEXT_ID)
+    LOGGER.warning('Services[{:d}] = {:s}'.format(len(response.services), grpc_message_to_json_string(response)))
+    assert len(response.services) == 1
+
+    for service in response.services:
+        service_id = service.service_id
+        assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE
+
+        response = context_client.ListConnections(service_id)
+        LOGGER.warning('  ServiceId[{:s}] => Connections[{:d}] = {:s}'.format(
+            grpc_message_to_json_string(service_id), len(response.connections), grpc_message_to_json_string(response)))
+
+        if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
+            assert len(response.connections) == 2
+        else:
+            str_service = grpc_message_to_json_string(service)
+            raise Exception('Unexpected ServiceType: {:s}'.format(str_service))
diff --git a/src/tests/ecoc24/tests/test_functional_delete_service.py b/src/tests/ecoc24/tests/test_functional_delete_service.py
new file mode 100644
index 0000000000000000000000000000000000000000..475c58e61a3b6d41fa9861840431855f347179e8
--- /dev/null
+++ b/src/tests/ecoc24/tests/test_functional_delete_service.py
@@ -0,0 +1,80 @@
+# 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
+from typing import Set, Tuple
+from common.Constants import DEFAULT_CONTEXT_NAME
+from common.proto.context_pb2 import ContextId, ServiceId, ServiceStatusEnum, ServiceTypeEnum
+from common.tools.grpc.Tools import grpc_message_to_json_string
+from common.tools.object_factory.Context import json_context_id
+from common.tools.object_factory.Service import json_service_id
+from context.client.ContextClient import ContextClient
+from service.client.ServiceClient import ServiceClient
+from tests.Fixtures import context_client, service_client   # pylint: disable=unused-import
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+ADMIN_CONTEXT_ID = ContextId(**json_context_id(DEFAULT_CONTEXT_NAME))
+
+def test_service_removal_bidir(
+    context_client : ContextClient, # pylint: disable=redefined-outer-name
+    service_client : ServiceClient, # pylint: disable=redefined-outer-name
+):
+    # Verify the scenario has 1 service and 0 slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.service_ids) == 1
+    assert len(response.slice_ids) == 0
+
+    # Check there are no slices
+    response = context_client.ListSlices(ADMIN_CONTEXT_ID)
+    LOGGER.warning('Slices[{:d}] = {:s}'.format(len(response.slices), grpc_message_to_json_string(response)))
+    assert len(response.slices) == 0
+
+    # Check there is 1 service
+    response = context_client.ListServices(ADMIN_CONTEXT_ID)
+    LOGGER.warning('Services[{:d}] = {:s}'.format(len(response.services), grpc_message_to_json_string(response)))
+    assert len(response.services) == 1
+
+    context_service_uuids : Set[Tuple[str, str]] = set()
+    for service in response.services:
+        service_id = service.service_id
+        assert service.service_status.service_status == ServiceStatusEnum.SERVICESTATUS_ACTIVE
+
+        response = context_client.ListConnections(service_id)
+        LOGGER.warning('  ServiceId[{:s}] => Connections[{:d}] = {:s}'.format(
+            grpc_message_to_json_string(service_id), len(response.connections), grpc_message_to_json_string(response)))
+
+        if service.service_type == ServiceTypeEnum.SERVICETYPE_OPTICAL_CONNECTIVITY:
+            assert len(response.connections) == 2
+            context_uuid = service_id.context_id.context_uuid.uuid
+            service_uuid = service_id.service_uuid.uuid
+            context_service_uuids.add((context_uuid, service_uuid))
+        else:
+            str_service = grpc_message_to_json_string(service)
+            raise Exception('Unexpected ServiceType: {:s}'.format(str_service))
+
+    # Identify service to delete
+    assert len(context_service_uuids) == 1
+    context_uuid, service_uuid = set(context_service_uuids).pop()
+
+    # Delete Service
+    # service_client.DeleteService(ServiceId(**json_service_id(service_uuid, json_context_id(context_uuid))))
+
+    import delete_service
+
+    # 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