diff --git a/scripts/run_tests_locally-nbi-all.sh b/scripts/run_tests_locally-nbi-all.sh
index ec2987d772bbd157eeb1795f5984a7cac5002a60..48961b0fe20ab4ac3658a6f35ce89ec659e52dc0 100755
--- a/scripts/run_tests_locally-nbi-all.sh
+++ b/scripts/run_tests_locally-nbi-all.sh
@@ -22,8 +22,14 @@ RCFILE=$PROJECTDIR/coverage/.coveragerc
 # Run unitary tests and analyze coverage of code at same time
 # helpful pytest flags: --log-level=INFO -o log_cli=true --verbose --maxfail=1 --durations=0
 
+coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
+    nbi/tests/test_etsi_bwm.py
+
 coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
     nbi/tests/test_ietf_l2vpn.py
 
+coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
+    nbi/tests/test_ietf_l3vpn.py
+
 coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
     nbi/tests/test_ietf_network.py
diff --git a/scripts/run_tests_locally-nbi-etsi-bwm.sh b/scripts/run_tests_locally-nbi-etsi-bwm.sh
new file mode 100755
index 0000000000000000000000000000000000000000..dc5f79ffa96c853671b5a4cc41d2c69fbc89f350
--- /dev/null
+++ b/scripts/run_tests_locally-nbi-etsi-bwm.sh
@@ -0,0 +1,25 @@
+#!/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.
+
+
+PROJECTDIR=`pwd`
+
+cd $PROJECTDIR/src
+RCFILE=$PROJECTDIR/coverage/.coveragerc
+
+# Run unitary tests and analyze coverage of code at same time
+# helpful pytest flags: --log-level=INFO -o log_cli=true --verbose --maxfail=1 --durations=0
+coverage run --rcfile=$RCFILE --append -m pytest --log-level=INFO --verbose \
+    nbi/tests/test_etsi_bwm.py
diff --git a/src/nbi/.gitlab-ci.yml b/src/nbi/.gitlab-ci.yml
index 8f7f4d6f45d7e4a07856aaf1d67d35d9f76a38cf..d9d790803a5cb0387d2d3447ef700154879bb615 100644
--- a/src/nbi/.gitlab-ci.yml
+++ b/src/nbi/.gitlab-ci.yml
@@ -69,6 +69,7 @@ unit_test nbi:
     - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_ietf_l2vpn.py --junitxml=/opt/results/${IMAGE_NAME}_report_ietf_l2vpn.xml"
     - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_ietf_network.py --junitxml=/opt/results/${IMAGE_NAME}_report_ietf_network.xml"
     - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_ietf_l3vpn.py --junitxml=/opt/results/${IMAGE_NAME}_report_ietf_l3vpn.xml"
+    - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_etsi_bwm.py --junitxml=/opt/results/${IMAGE_NAME}_report_etsi_bwm.xml"
     - docker exec -i $IMAGE_NAME bash -c "coverage report --include='${IMAGE_NAME}/*' --show-missing"
   coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+%)/'
   after_script:
diff --git a/src/nbi/requirements.in b/src/nbi/requirements.in
index 52094c61f2b50e99a35a8ca999c579422b7f22b7..6e3eb94404f9d12431c715080cf210a02c7c82f4 100644
--- a/src/nbi/requirements.in
+++ b/src/nbi/requirements.in
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 deepdiff==6.7.*
+deepmerge==1.1.*
 Flask==2.1.3
 Flask-HTTPAuth==4.5.0
 Flask-RESTful==0.3.9
diff --git a/src/nbi/service/rest_server/nbi_plugins/etsi_bwm/Resources.py b/src/nbi/service/rest_server/nbi_plugins/etsi_bwm/Resources.py
index 38534b754d6c1ac502b21af55375c63159c57745..3fccbbb55c8959ae0c478526d2ea24882ebfef1f 100644
--- a/src/nbi/service/rest_server/nbi_plugins/etsi_bwm/Resources.py
+++ b/src/nbi/service/rest_server/nbi_plugins/etsi_bwm/Resources.py
@@ -12,14 +12,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import copy
+import copy, deepmerge, json, logging
 from common.Constants import DEFAULT_CONTEXT_NAME
-from flask_restful import Resource, request
 from context.client.ContextClient import ContextClient
+from flask_restful import Resource, request
 from service.client.ServiceClient import ServiceClient
 from .Tools import (
     format_grpc_to_json, grpc_context_id, grpc_service_id, bwInfo_2_service, service_2_bwInfo)
 
+LOGGER = logging.getLogger(__name__)
 
 
 class _Resource(Resource):
@@ -39,7 +40,6 @@ class BwInfo(_Resource):
         bwinfo = request.get_json()
         service = bwInfo_2_service(self.client, bwinfo)
         stripped_service = copy.deepcopy(service)
-
         stripped_service.ClearField('service_endpoint_ids')
         stripped_service.ClearField('service_constraints')
         stripped_service.ClearField('service_config')
@@ -57,19 +57,30 @@ class BwInfoId(_Resource):
         return service_2_bwInfo(service)
 
     def put(self, allocationId: str):
-        json_data = request.get_json()
+        json_data = json.loads(request.get_json())
         service = bwInfo_2_service(self.client, json_data)
-        response = self.service_client.UpdateService(service)
-        return format_grpc_to_json(response)
+        self.service_client.UpdateService(service)
+        service = self.client.GetService(grpc_service_id(DEFAULT_CONTEXT_NAME, json_data['appInsId']))
+        response_bwm = service_2_bwInfo(service)
+
+        return response_bwm
 
     def patch(self, allocationId: str):
         json_data = request.get_json()
         if not 'appInsId' in json_data:
             json_data['appInsId'] = allocationId
-        service = bwInfo_2_service(self.client, json_data)
-        response = self.service_client.UpdateService(service)
-        return format_grpc_to_json(response)
+        
+        service = self.client.GetService(grpc_service_id(DEFAULT_CONTEXT_NAME, json_data['appInsId']))
+        current_bwm = service_2_bwInfo(service)
+        new_bmw = deepmerge.always_merger.merge(current_bwm, json_data)
+        
+        service = bwInfo_2_service(self.client, new_bmw)
+        self.service_client.UpdateService(service)
+
+        service = self.client.GetService(grpc_service_id(DEFAULT_CONTEXT_NAME, json_data['appInsId']))
+        response_bwm = service_2_bwInfo(service)
+
+        return response_bwm
 
     def delete(self, allocationId: str):
         self.service_client.DeleteService(grpc_service_id(DEFAULT_CONTEXT_NAME, allocationId))
-        return
diff --git a/src/nbi/service/rest_server/nbi_plugins/etsi_bwm/Tools.py b/src/nbi/service/rest_server/nbi_plugins/etsi_bwm/Tools.py
index 023d1006cd807ffeeed40d2e1e7273a580431073..a78d2819317623b9ccaaec62e808f6435c88b630 100644
--- a/src/nbi/service/rest_server/nbi_plugins/etsi_bwm/Tools.py
+++ b/src/nbi/service/rest_server/nbi_plugins/etsi_bwm/Tools.py
@@ -15,8 +15,11 @@
 import json
 import logging
 import time
+from decimal import ROUND_HALF_EVEN, Decimal
 from flask.json import jsonify
-from common.proto.context_pb2 import ContextId, Empty, EndPointId, ServiceId, ServiceTypeEnum, Service, Constraint, Constraint_SLA_Capacity, ConfigRule, ConfigRule_Custom, ConfigActionEnum
+from common.proto.context_pb2 import (
+    ContextId, Empty, EndPointId, ServiceId, ServiceTypeEnum, Service, Constraint, Constraint_SLA_Capacity,
+    ConfigRule, ConfigRule_Custom, ConfigActionEnum)
 from common.tools.grpc.Tools import grpc_message_to_json
 from common.tools.object_factory.Context import json_context_id
 from common.tools.object_factory.Service import json_service_id
@@ -27,13 +30,15 @@ LOGGER = logging.getLogger(__name__)
 def service_2_bwInfo(service: Service) -> dict:
     response = {}
     # allocationDirection = '??' # String: 00 = Downlink (towards the UE); 01 = Uplink (towards the application/session); 10 = Symmetrical
-    response['appInsId'] = service.service_id.context_id.context_uuid.uuid # String: Application instance identifier
+    response['appInsId'] = service.service_id.service_uuid.uuid # String: Application instance identifier
     for constraint in service.service_constraints:
         if constraint.WhichOneof('constraint') == 'sla_capacity':
-            response['fixedAllocation'] = str(constraint.sla_capacity.capacity_gbps*1000) # String: Size of requested fixed BW allocation in [bps]
+            # String: Size of requested fixed BW allocation in [bps]
+            fixed_allocation = Decimal(constraint.sla_capacity.capacity_gbps * 1.e9)
+            fixed_allocation = fixed_allocation.quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)
+            response['fixedAllocation'] = str(fixed_allocation)
             break
 
-
     for config_rule in service.service_config.config_rules:
         for key in ['allocationDirection', 'fixedBWPriority', 'requestType', 'sourceIp', 'sourcePort', 'dstPort', 'protocol', 'sessionFilter']:
             if config_rule.custom.resource_key == key:
@@ -42,7 +47,6 @@ def service_2_bwInfo(service: Service) -> dict:
                 else:
                     response[key] = json.loads(config_rule.custom.resource_value)
 
-    
     unixtime = time.time()
     response['timeStamp'] = { # Time stamp to indicate when the corresponding information elements are sent
         "seconds": int(unixtime),
@@ -53,7 +57,6 @@ def service_2_bwInfo(service: Service) -> dict:
 
 def bwInfo_2_service(client, bwInfo: dict) -> Service:
     service = Service()
-
     for key in ['allocationDirection', 'fixedBWPriority', 'requestType', 'timeStamp', 'sessionFilter']:
         if key not in bwInfo:
             continue
@@ -82,10 +85,6 @@ def bwInfo_2_service(client, bwInfo: dict) -> Service:
                             ep_id.endpoint_uuid.uuid = ep['uuid']
                             ep_id.device_id.device_uuid.uuid = device.device_id.device_uuid.uuid
                             service.service_endpoint_ids.append(ep_id)
-        
-        if len(service.service_endpoint_ids) < 2:
-            LOGGER.error('No endpoints matched')
-            return None
 
     service.service_type = ServiceTypeEnum.SERVICETYPE_L3NM
 
@@ -96,7 +95,7 @@ def bwInfo_2_service(client, bwInfo: dict) -> Service:
 
     if 'fixedAllocation' in bwInfo:
         capacity = Constraint_SLA_Capacity()
-        capacity.capacity_gbps = float(bwInfo['fixedAllocation'])
+        capacity.capacity_gbps = float(bwInfo['fixedAllocation']) / 1.e9
         constraint = Constraint()
         constraint.sla_capacity.CopyFrom(capacity)
         service.service_constraints.append(constraint)
diff --git a/src/nbi/service/rest_server/nbi_plugins/etsi_bwm/__init__.py b/src/nbi/service/rest_server/nbi_plugins/etsi_bwm/__init__.py
index 5525c58ad9f0def5001d9a6430ffe5fb2c5efe33..f34432d82ee302d97cb2caaf3ed1628dc6e9f005 100644
--- a/src/nbi/service/rest_server/nbi_plugins/etsi_bwm/__init__.py
+++ b/src/nbi/service/rest_server/nbi_plugins/etsi_bwm/__init__.py
@@ -15,7 +15,7 @@
 from nbi.service.rest_server.RestServer import RestServer
 from .Resources import BwInfo, BwInfoId
 
-URL_PREFIX = '/bwm/v1'
+URL_PREFIX = '/restconf/bwm/v1'
 
 # Use 'path' type since some identifiers might contain char '/' and Flask is unable to recognize them in 'string' type.
 RESOURCES = [
diff --git a/src/nbi/tests/PrepareTestScenario.py b/src/nbi/tests/PrepareTestScenario.py
index 3c1fb2739cffe5f77815bb26beddad5fc705557a..461245e09190ffe9795bc3bfcb4d21b516cc3071 100644
--- a/src/nbi/tests/PrepareTestScenario.py
+++ b/src/nbi/tests/PrepareTestScenario.py
@@ -22,6 +22,7 @@ from common.Settings import (
 from context.client.ContextClient import ContextClient
 from nbi.service.rest_server.RestServer import RestServer
 from nbi.service.rest_server.nbi_plugins.debug_api import register_debug_api
+from nbi.service.rest_server.nbi_plugins.etsi_bwm import register_etsi_bwm_api
 from nbi.service.rest_server.nbi_plugins.ietf_l2vpn import register_ietf_l2vpn
 from nbi.service.rest_server.nbi_plugins.ietf_l3vpn import register_ietf_l3vpn
 from nbi.service.rest_server.nbi_plugins.ietf_network import register_ietf_network
@@ -49,6 +50,7 @@ def mock_service():
 def nbi_service_rest(mock_service : MockService_Dependencies):  # pylint: disable=redefined-outer-name, unused-argument
     _rest_server = RestServer()
     register_debug_api(_rest_server)
+    register_etsi_bwm_api(_rest_server)
     register_ietf_l2vpn(_rest_server)
     register_ietf_l3vpn(_rest_server)
     register_ietf_network(_rest_server)
@@ -85,6 +87,7 @@ class RestRequestMethod(enum.Enum):
     GET    = 'get'
     POST   = 'post'
     PUT    = 'put'
+    PATCH  = 'patch'
     DELETE = 'delete'
 
 EXPECTED_STATUS_CODES : Set[int] = {
@@ -119,34 +122,47 @@ def do_rest_get_request(
     url : str, body : Optional[Any] = None, timeout : int = 10,
     allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES,
     logger : Optional[logging.Logger] = None
-) -> Union[Dict, List]:
+) -> Optional[Union[Dict, List]]:
     return do_rest_request(
         RestRequestMethod.GET, url, body=body, timeout=timeout, allow_redirects=allow_redirects,
         expected_status_codes=expected_status_codes, logger=logger
     )
 
-def do_rest_post_request(url : str, body : Optional[Any] = None, timeout : int = 10,
+def do_rest_post_request(
+    url : str, body : Optional[Any] = None, timeout : int = 10,
     allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES,
     logger : Optional[logging.Logger] = None
-) -> Union[Dict, List]:
+) -> Optional[Union[Dict, List]]:
     return do_rest_request(
         RestRequestMethod.POST, url, body=body, timeout=timeout, allow_redirects=allow_redirects,
         expected_status_codes=expected_status_codes, logger=logger
     )
 
-def do_rest_put_request(url : str, body : Optional[Any] = None, timeout : int = 10,
+def do_rest_put_request(
+    url : str, body : Optional[Any] = None, timeout : int = 10,
     allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES,
     logger : Optional[logging.Logger] = None
-) -> Union[Dict, List]:
+) -> Optional[Union[Dict, List]]:
     return do_rest_request(
         RestRequestMethod.PUT, url, body=body, timeout=timeout, allow_redirects=allow_redirects,
         expected_status_codes=expected_status_codes, logger=logger
     )
 
-def do_rest_delete_request(url : str, body : Optional[Any] = None, timeout : int = 10,
+def do_rest_patch_request(
+    url : str, body : Optional[Any] = None, timeout : int = 10,
     allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES,
     logger : Optional[logging.Logger] = None
-) -> Union[Dict, List]:
+) -> Optional[Union[Dict, List]]:
+    return do_rest_request(
+        RestRequestMethod.PATCH, url, body=body, timeout=timeout, allow_redirects=allow_redirects,
+        expected_status_codes=expected_status_codes, logger=logger
+    )
+
+def do_rest_delete_request(
+    url : str, body : Optional[Any] = None, timeout : int = 10,
+    allow_redirects : bool = True, expected_status_codes : Set[int] = EXPECTED_STATUS_CODES,
+    logger : Optional[logging.Logger] = None
+) -> Optional[Union[Dict, List]]:
     return do_rest_request(
         RestRequestMethod.DELETE, url, body=body, timeout=timeout, allow_redirects=allow_redirects,
         expected_status_codes=expected_status_codes, logger=logger
diff --git a/src/nbi/tests/test_etsi_bwm.py b/src/nbi/tests/test_etsi_bwm.py
new file mode 100644
index 0000000000000000000000000000000000000000..8925897a720a6afa981e9ea0cd9c0d9a5261c5cd
--- /dev/null
+++ b/src/nbi/tests/test_etsi_bwm.py
@@ -0,0 +1,240 @@
+# 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 deepdiff, json, logging, pytest
+from typing import Dict
+from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME
+from common.proto.context_pb2 import ContextId, TopologyId
+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 common.tools.object_factory.Topology import json_topology_id
+from context.client.ContextClient import ContextClient
+from nbi.service.rest_server import RestServer
+from .PrepareTestScenario import ( # pylint: disable=unused-import
+    # be careful, order of symbols is important here!
+    do_rest_delete_request, do_rest_get_request, do_rest_patch_request, do_rest_post_request, do_rest_put_request,
+    mock_service, nbi_service_rest, context_client
+)
+
+LOGGER = logging.getLogger(__name__)
+LOGGER.setLevel(logging.DEBUG)
+
+DESCRIPTOR_FILE  = 'nbi/tests/data/topology-dummy.json'
+
+JSON_ADMIN_CONTEXT_ID = json_context_id(DEFAULT_CONTEXT_NAME)
+ADMIN_CONTEXT_ID = ContextId(**JSON_ADMIN_CONTEXT_ID)
+ADMIN_TOPOLOGY_ID = TopologyId(**json_topology_id(DEFAULT_TOPOLOGY_NAME, context_id=JSON_ADMIN_CONTEXT_ID))
+BASE_URL = '/restconf/bwm/v1'
+
+@pytest.fixture(scope='session')
+def storage() -> Dict:
+    yield dict()
+
+#def compare_dicts(dict1, dict2):
+#    # Function to recursively sort dictionaries
+#    def recursively_sort(d):
+#        if isinstance(d, dict):
+#            return {k: recursively_sort(v) for k, v in sorted(d.items())}
+#        if isinstance(d, list):
+#            return [recursively_sort(item) for item in d]
+#        return d
+#
+#    # Sort dictionaries to ignore the order of fields
+#    sorted_dict1 = recursively_sort(dict1)
+#    sorted_dict2 = recursively_sort(dict2)
+#
+#    if sorted_dict1 != sorted_dict2:
+#        LOGGER.error(sorted_dict1)
+#        LOGGER.error(sorted_dict2)
+#
+#    return sorted_dict1 != sorted_dict2
+
+def check_timestamps(bwm_service):
+    assert 'timeStamp' in bwm_service
+    assert 'seconds' in bwm_service['timeStamp']
+    assert 'nanoseconds' in bwm_service['timeStamp']
+
+def test_prepare_environment(context_client : ContextClient) -> None: # pylint: disable=redefined-outer-name
+    validate_empty_scenario(context_client)
+    descriptor_loader = DescriptorLoader(descriptors_file=DESCRIPTOR_FILE, context_client=context_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.topology_ids) == 1
+    assert len(response.service_ids ) == 0
+    assert len(response.slice_ids   ) == 0
+
+def test_get_allocations_empty(nbi_service_rest : RestServer, storage : Dict): # pylint: disable=redefined-outer-name, unused-argument
+    URL = BASE_URL + '/bw_allocations'
+    retrieved_data = do_rest_get_request(URL, logger=LOGGER, expected_status_codes={200})
+    LOGGER.debug('retrieved_data={:s}'.format(json.dumps(retrieved_data, sort_keys=True)))
+    assert len(retrieved_data) == 0
+
+def test_allocation(nbi_service_rest : RestServer, storage : Dict): # pylint: disable=redefined-outer-name, unused-argument
+    URL = BASE_URL + '/bw_allocations'
+    data = {
+        "appInsId"            : "service_uuid_01",
+        "allocationDirection" : "00",
+        "fixedAllocation"     : "123000.0",
+        "fixedBWPriority"     : "SEE_DESCRIPTION",
+        "requestType"         : 0,
+        "sessionFilter"       : [{
+            "sourceIp"   : "192.168.1.2",
+            "sourcePort" : ["a"],
+            "protocol"   : "string",
+            "dstAddress" : "192.168.3.2",
+            "dstPort"    : ["b"],
+        }]
+    }
+    retrieved_data = do_rest_post_request(URL, body=data, logger=LOGGER, expected_status_codes={200})
+    LOGGER.debug('retrieved_data={:s}'.format(json.dumps(retrieved_data, sort_keys=True)))
+    storage['service_uuid_01'] = 'service_uuid_01'
+
+
+def test_get_allocations(nbi_service_rest : RestServer, storage : Dict): # pylint: disable=redefined-outer-name, unused-argument
+    assert 'service_uuid_01' in storage
+    URL = BASE_URL + '/bw_allocations'
+    retrieved_data = do_rest_get_request(URL, logger=LOGGER, expected_status_codes={200})
+    LOGGER.debug('retrieved_data={:s}'.format(json.dumps(retrieved_data, sort_keys=True)))
+    assert len(retrieved_data) == 1
+    good_result = [
+        {
+            "appInsId"            : "service_uuid_01",
+            "fixedAllocation"     : "123000.0",
+            "allocationDirection" : "00",
+            "fixedBWPriority"     : "SEE_DESCRIPTION",
+            "requestType"         : "0",
+            "sessionFilter"       : [{
+                "sourceIp"   : "192.168.1.2",
+                "sourcePort" : ["a"],
+                "protocol"   : "string",
+                "dstAddress" : "192.168.3.2",
+                "dstPort"    : ["b"],
+            }],
+        }
+    ]
+    check_timestamps(retrieved_data[0])
+    del retrieved_data[0]['timeStamp']
+    diff_data = deepdiff.DeepDiff(good_result, retrieved_data)
+    LOGGER.error('Differences:\n{:s}'.format(str(diff_data.pretty())))
+    assert len(diff_data) == 0
+
+
+def test_get_allocation(nbi_service_rest : RestServer, storage : Dict): # pylint: disable=redefined-outer-name, unused-argument
+    assert 'service_uuid_01' in storage
+    URL = BASE_URL + '/bw_allocations/service_uuid_01'
+    retrieved_data = do_rest_get_request(URL, logger=LOGGER, expected_status_codes={200})
+    LOGGER.debug('retrieved_data={:s}'.format(json.dumps(retrieved_data, sort_keys=True)))
+    good_result = {
+        "appInsId"           : "service_uuid_01",
+        "fixedAllocation"    : "123000.0",
+        "allocationDirection": "00",
+        "fixedBWPriority"    : "SEE_DESCRIPTION",
+        "requestType"        : "0",
+        "sessionFilter"      : [{
+            "sourceIp"   : "192.168.1.2",
+            "sourcePort" : ["a"],
+            "protocol"   : "string",
+            "dstAddress" : "192.168.3.2",
+            "dstPort"    : ["b"],
+        }]
+    }
+    check_timestamps(retrieved_data)
+    del retrieved_data['timeStamp']
+    diff_data = deepdiff.DeepDiff(good_result, retrieved_data)
+    LOGGER.error('Differences:\n{:s}'.format(str(diff_data.pretty())))
+    assert len(diff_data) == 0
+
+
+def test_put_allocation(nbi_service_rest : RestServer, storage : Dict): # pylint: disable=redefined-outer-name, unused-argument
+    assert 'service_uuid_01' in storage
+    URL = BASE_URL + '/bw_allocations/service_uuid_01'
+    changed_allocation = {
+        "appInsId"           : "service_uuid_01",
+        "fixedAllocation"    : "200.0",
+        "allocationDirection": "00",
+        "fixedBWPriority"    : "NOPRIORITY",
+        "requestType"        : "0",
+        "sessionFilter"      : [{
+            "sourceIp"   : "192.168.1.2",
+            "sourcePort" : ["a"],
+            "protocol"   : "string",
+            "dstAddress" : "192.168.3.2",
+            "dstPort"    : ["b"],
+        }]
+    }
+    retrieved_data = do_rest_put_request(URL, body=json.dumps(changed_allocation), logger=LOGGER, expected_status_codes={200})
+    check_timestamps(retrieved_data)
+    del retrieved_data['timeStamp']
+    diff_data = deepdiff.DeepDiff(changed_allocation, retrieved_data)
+    LOGGER.error('Differences:\n{:s}'.format(str(diff_data.pretty())))
+    assert len(diff_data) == 0
+
+
+def test_patch_allocation(nbi_service_rest : RestServer, storage : Dict): # pylint: disable=redefined-outer-name, unused-argument
+    assert 'service_uuid_01' in storage
+    URL = BASE_URL + '/bw_allocations/service_uuid_01'
+    difference = {
+        "fixedBWPriority":"FULLPRIORITY",
+    }
+    changed_allocation = {
+        "appInsId"           : "service_uuid_01",
+        "fixedAllocation"    : "200.0",
+        "allocationDirection": "00",
+        "fixedBWPriority"    : "FULLPRIORITY",
+        "requestType"        : "0",
+        "sessionFilter"      : [{
+            "sourceIp"   : "192.168.1.2",
+            "sourcePort" : ["a"],
+            "protocol"   : "string",
+            "dstAddress" : "192.168.3.2",
+            "dstPort"    : ["b"],
+        }]
+    }
+    retrieved_data = do_rest_patch_request(URL, body=difference, logger=LOGGER, expected_status_codes={200})
+    check_timestamps(retrieved_data)
+    del retrieved_data['timeStamp']
+    diff_data = deepdiff.DeepDiff(changed_allocation, retrieved_data)
+    LOGGER.error('Differences:\n{:s}'.format(str(diff_data.pretty())))
+    assert len(diff_data) == 0
+
+
+def test_delete_allocation(nbi_service_rest : RestServer, storage : Dict): # pylint: disable=redefined-outer-name, unused-argument
+    assert 'service_uuid_01' in storage
+    URL = BASE_URL + '/bw_allocations/service_uuid_01'
+    do_rest_delete_request(URL, logger=LOGGER, expected_status_codes={200})
+
+
+def test_get_allocations_empty_final(nbi_service_rest : RestServer, storage : Dict): # pylint: disable=redefined-outer-name, unused-argument
+    URL = BASE_URL + '/bw_allocations'
+    retrieved_data = do_rest_get_request(URL, logger=LOGGER, expected_status_codes={200})
+    LOGGER.debug('retrieved_data={:s}'.format(json.dumps(retrieved_data, sort_keys=True)))
+    assert len(retrieved_data) == 0
+
+
+def test_cleanup_environment(context_client : ContextClient) -> None: # pylint: disable=redefined-outer-name
+    # Verify the scenario has no services/slices
+    response = context_client.GetContext(ADMIN_CONTEXT_ID)
+    assert len(response.topology_ids) == 1
+    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)
+    descriptor_loader.validate()
+    descriptor_loader.unload()
+    validate_empty_scenario(context_client)
diff --git a/src/nbi/tests/test_ietf_network.py b/src/nbi/tests/test_ietf_network.py
index e41a88af07db0e266e80ac082a519c41c86fe523..fb39a91922ca0d76f950c5e0c8c98847547b7ac9 100644
--- a/src/nbi/tests/test_ietf_network.py
+++ b/src/nbi/tests/test_ietf_network.py
@@ -12,8 +12,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from typing import Dict
 import deepdiff, json, logging, operator
+from typing import Dict
 from common.Constants import DEFAULT_CONTEXT_NAME
 from common.proto.context_pb2 import ContextId
 from common.tools.descriptor.Loader import DescriptorLoader, check_descriptor_load_results, validate_empty_scenario