Commit c7e957fb authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

NBI Component - ETSI BMW:

- Cosmetic cleanup in unitary test data
- Multiple bug fixes
- Fixed unitary tests
- Added new Python requirement
parent 8729a0dd
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+8 −2
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import copy, json, logging
import copy, deepmerge, json, logging
from common.Constants import DEFAULT_CONTEXT_NAME
from context.client.ContextClient import ContextClient
from flask_restful import Resource, request
@@ -69,8 +69,14 @@ class BwInfoId(_Resource):
        json_data = request.get_json()
        if not 'appInsId' in json_data:
            json_data['appInsId'] = allocationId
        service = bwInfo_2_service(self.client, json_data)
        
        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)

+9 −3
Original line number Diff line number Diff line
@@ -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
@@ -30,7 +33,10 @@ def service_2_bwInfo(service: Service) -> dict:
    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:
@@ -89,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)
+117 −101
Original line number Diff line number Diff line
@@ -12,8 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import deepdiff, json, logging, pytest
from typing import Dict
import json, logging, pytest
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
@@ -21,8 +21,11 @@ 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 do_rest_delete_request, do_rest_post_request, do_rest_get_request, do_rest_put_request, do_rest_patch_request, mock_service, nbi_service_rest, context_client

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)
@@ -38,24 +41,24 @@ BASE_URL = '/restconf/bwm/v1'
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 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
@@ -71,7 +74,7 @@ def test_prepare_environment(context_client : ContextClient) -> None: # pylint:

    # Verify the scenario has no services/slices
    response = context_client.GetContext(ADMIN_CONTEXT_ID)
    assert len(response.topology_ids) == 3
    assert len(response.topology_ids) == 1
    assert len(response.service_ids ) == 0
    assert len(response.slice_ids   ) == 0

@@ -81,23 +84,21 @@ def test_get_allocations_empty(nbi_service_rest : RestServer, storage : Dict): #
    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):
def test_allocation(nbi_service_rest : RestServer, storage : Dict): # pylint: disable=redefined-outer-name, unused-argument
    URL = BASE_URL + '/bw_allocations'
    data = {
        "allocationDirection":"string",
        "appInsId"            : "service_uuid_01",
        "allocationDirection" : "00",
        "fixedAllocation"     : "123000.0",
        "fixedBWPriority"     : "SEE_DESCRIPTION",
        "requestType"         : 0,
        "sessionFilter":[
            {
        "sessionFilter"       : [{
            "sourceIp"   : "192.168.1.2",
            "sourcePort" : ["a"],
            "protocol"   : "string",
            "dstAddress" : "192.168.3.2",
            "dstPort"    : ["b"],
                "protocol":"string",
                "sourceIp":"192.168.1.2",
                "sourcePort":["a"]
            }
        ]
        }]
    }
    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)))
@@ -114,22 +115,23 @@ def test_get_allocations(nbi_service_rest : RestServer, storage : Dict): # pylin
        {
            "appInsId"            : "service_uuid_01",
            "fixedAllocation"     : "123000.0",
            "allocationDirection":"string",
            "allocationDirection" : "00",
            "fixedBWPriority"     : "SEE_DESCRIPTION",
            "requestType"         : "0",
            "sessionFilter":[
                {
            "sessionFilter"       : [{
                "sourceIp"   : "192.168.1.2",
                "sourcePort" : ["a"],
                "protocol"   : "string",
                "dstAddress" : "192.168.3.2",
                "dstPort"    : ["b"],
                    "protocol":"string",
                    "sourceIp":"192.168.1.2",
                    "sourcePort":["a"]
                }
            ],
            }],
        }
    ]
    compare_dicts(retrieved_data, good_result)
    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
@@ -140,22 +142,22 @@ def test_get_allocation(nbi_service_rest : RestServer, storage : Dict): # pylint
    good_result = {
        "appInsId"           : "service_uuid_01",
        "fixedAllocation"    : "123000.0",
        "allocationDirection":"string",
        "allocationDirection": "00",
        "fixedBWPriority"    : "SEE_DESCRIPTION",
        "requestType"        : "0",
        "sessionFilter":[
            {
        "sessionFilter"      : [{
            "sourceIp"   : "192.168.1.2",
            "sourcePort" : ["a"],
            "protocol"   : "string",
            "dstAddress" : "192.168.3.2",
            "dstPort"    : ["b"],
                "protocol":"string",
                "sourceIp":"192.168.1.2",
                "sourcePort":["a"]
            }
        ]
        }]
    }
    
    compare_dicts(retrieved_data, good_result)
    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
@@ -164,22 +166,23 @@ def test_put_allocation(nbi_service_rest : RestServer, storage : Dict): # pylint
    changed_allocation = {
        "appInsId"           : "service_uuid_01",
        "fixedAllocation"    : "200.0",
        "allocationDirection":"parriba",
        "allocationDirection": "00",
        "fixedBWPriority"    : "NOPRIORITY",
        "requestType"        : "0",
        "sessionFilter":[
            {
        "sessionFilter"      : [{
            "sourceIp"   : "192.168.1.2",
            "sourcePort" : ["a"],
            "protocol"   : "string",
            "dstAddress" : "192.168.3.2",
            "dstPort"    : ["b"],
                "protocol":"string",
                "sourceIp":"192.168.1.2",
                "sourcePort":["a"]
            }
        ]
        }]
    }
    retrieved_data = do_rest_put_request(URL, body=json.dumps(changed_allocation), logger=LOGGER, expected_status_codes={200})
    compare_dicts(retrieved_data, changed_allocation)
    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
@@ -191,24 +194,23 @@ def test_patch_allocation(nbi_service_rest : RestServer, storage : Dict): # pyli
    changed_allocation = {
        "appInsId"           : "service_uuid_01",
        "fixedAllocation"    : "200.0",
        "allocationDirection":"parriba",
        "allocationDirection": "00",
        "fixedBWPriority"    : "FULLPRIORITY",
        "requestType"        : "0",
        "sessionFilter":[
            {
        "sessionFilter"      : [{
            "sourceIp"   : "192.168.1.2",
            "sourcePort" : ["a"],
            "protocol"   : "string",
            "dstAddress" : "192.168.3.2",
            "dstPort"    : ["b"],
                "protocol":"string",
                "sourceIp":"192.168.1.2",
                "sourcePort":["a"]
        }]
    }
        ]
    }

    retrieved_data = do_rest_patch_request(URL, body=changed_allocation, logger=LOGGER, expected_status_codes={200})
    compare_dicts(retrieved_data, changed_allocation)
    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
@@ -222,3 +224,17 @@ def test_get_allocations_empty_final(nbi_service_rest : RestServer, storage : Di
    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)
+1 −1
Original line number Diff line number Diff line
@@ -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
+1 −1

File changed.

Contains only whitespace changes.

Loading