From b91ce702042f9b83e8a9726ddde124b2f2cedbba Mon Sep 17 00:00:00 2001 From: hajipour Date: Thu, 18 Jan 2024 15:54:00 +0100 Subject: [PATCH 01/10] NBI component - Debug API> - Fixed unitary tests (WIP) --- src/common/tests/MockServicerImpl_Context.py | 86 ++++- src/common/type_checkers/Assertions.py | 16 +- src/nbi/tests/test_debug_api.py | 326 ++++++++++--------- 3 files changed, 264 insertions(+), 164 deletions(-) diff --git a/src/common/tests/MockServicerImpl_Context.py b/src/common/tests/MockServicerImpl_Context.py index 98a216850..6e749e17c 100644 --- a/src/common/tests/MockServicerImpl_Context.py +++ b/src/common/tests/MockServicerImpl_Context.py @@ -25,12 +25,18 @@ from common.proto.context_pb2 import ( Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList) from common.proto.context_pb2_grpc import ContextServiceServicer +from common.proto.policy_pb2 import ( + PolicyRule, + PolicyRuleId, + PolicyRuleIdList, + PolicyRuleList, +) from common.tools.grpc.Tools import grpc_message_to_json, grpc_message_to_json_string from common.tools.object_factory.Device import json_device_id from common.tools.object_factory.Link import json_link_id from .InMemoryObjectDatabase import InMemoryObjectDatabase from .MockMessageBroker import ( - TOPIC_CONNECTION, TOPIC_CONTEXT, TOPIC_DEVICE, TOPIC_LINK, TOPIC_SERVICE, TOPIC_SLICE, TOPIC_TOPOLOGY, + TOPIC_CONNECTION, TOPIC_CONTEXT, TOPIC_DEVICE, TOPIC_LINK, TOPIC_SERVICE, TOPIC_SLICE, TOPIC_TOPOLOGY, TOPIC_POLICY, MockMessageBroker, notify_event) LOGGER = logging.getLogger(__name__) @@ -615,3 +621,81 @@ class MockServicerImpl_Context(ContextServiceServicer): def GetConnectionEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[ConnectionEvent]: LOGGER.debug('[GetConnectionEvents] request={:s}'.format(grpc_message_to_json_string(request))) for message in self.msg_broker.consume({TOPIC_CONNECTION}): yield ConnectionEvent(**json.loads(message.content)) + + def ListPolicyRuleIds(self, request: Empty, context: grpc.ServicerContext): + LOGGER.debug( + "[ListPolicyRuleIds] request={:s}".format( + grpc_message_to_json_string(request) + ) + ) + reply = PolicyRuleIdList( + policyRuleIdList=[ + getattr( + policy_rule, policy_rule.WhichOneof("policy_rule") + ).policyRuleBasic.policyRuleId + for policy_rule in self.obj_db.get_entries("policy") + ] + ) + LOGGER.debug( + "[ListPolicyRuleIds] reply={:s}".format(grpc_message_to_json_string(reply)) + ) + return reply + + def ListPolicyRules(self, request: Empty, context: grpc.ServicerContext): + LOGGER.debug( + "[ListPolicyRules] request={:s}".format( + grpc_message_to_json_string(request) + ) + ) + reply = PolicyRuleList(policyRules=self.obj_db.get_entries("policy")) + LOGGER.debug( + "[ListPolicyRules] reply={:s}".format(grpc_message_to_json_string(reply)) + ) + return reply + + def GetPolicyRule(self, request: PolicyRuleId, context: grpc.ServicerContext): + LOGGER.debug( + "[GetPolicyRule] request={:s}".format(grpc_message_to_json_string(request)) + ) + reply = self.obj_db.get_entry("policy_rule", request.uuid.uuid, context) + LOGGER.debug( + "[GetPolicyRule] reply={:s}".format(grpc_message_to_json_string(reply)) + ) + return reply + + def SetPolicyRule(self, request: PolicyRule, context: grpc.ServicerContext): + LOGGER.debug( + "[SetPolicyRule] request={:s}".format(grpc_message_to_json_string(request)) + ) + policy_type = request.WhichOneof("policy_rule") + reply, _ = self._set( + request, + "policy", + getattr(request, policy_type).policyRuleBasic.policyRuleId.uuid.uuid, + f"{policy_type}.policyRuleBasic.policyRuleId", + TOPIC_POLICY, + ) + LOGGER.debug( + "[SetPolicyRule] reply={:s}".format(grpc_message_to_json_string(reply)) + ) + return reply + + def RemovePolicyRule(self, request: PolicyRuleId, context: grpc.ServicerContext): + LOGGER.debug( + "[RemovePolicyRule] request={:s}".format( + grpc_message_to_json_string(request) + ) + ) + policy_type = request.WhichOneof("policy_rule") + reply = self._del( + request, + "policy", + getattr(request, policy_type).policyRuleBasic.policyRuleId.uuid.uuid, + f"{policy_type}.policyRuleBasic.policyRuleId", + TOPIC_CONTEXT, + context, + ) + LOGGER.debug( + "[RemovePolicyRule] reply={:s}".format(grpc_message_to_json_string(reply)) + ) + return reply \ No newline at end of file diff --git a/src/common/type_checkers/Assertions.py b/src/common/type_checkers/Assertions.py index 286ae179d..98987f234 100644 --- a/src/common/type_checkers/Assertions.py +++ b/src/common/type_checkers/Assertions.py @@ -192,6 +192,15 @@ def validate_connection_id(message): assert 'connection_uuid' in message validate_uuid(message['connection_uuid']) +def validate_slice_id(message, context_uuid = None): + assert isinstance(message, dict) + assert len(message.keys()) == 2 + assert 'context_id' in message + validate_context_id(message['context_id']) + if context_uuid is not None: assert message['context_id']['context_uuid']['uuid'] == context_uuid + assert 'slice_uuid' in message + validate_uuid(message['slice_uuid']) + # ----- Lists of Identifiers ------------------------------------------------------------------------------------------- @@ -242,7 +251,9 @@ def validate_connection_ids(message): def validate_context(message): assert isinstance(message, dict) - assert len(message.keys()) == 3 + assert len(message.keys()) == 5 + assert 'name' in message + assert isinstance(message['name'], str) assert 'context_id' in message validate_context_id(message['context_id']) context_uuid = message['context_id']['context_uuid']['uuid'] @@ -252,6 +263,9 @@ def validate_context(message): assert 'topology_ids' in message assert isinstance(message['topology_ids'], list) for topology_id in message['topology_ids']: validate_topology_id(topology_id, context_uuid=context_uuid) + assert 'slice_ids' in message + assert isinstance(message['slice_ids'], list) + for slice_id in message['slice_ids']: validate_slice_id(slice_id, context_uuid=context_uuid) def validate_service_state(message): assert isinstance(message, dict) diff --git a/src/nbi/tests/test_debug_api.py b/src/nbi/tests/test_debug_api.py index e28499261..ed788f469 100644 --- a/src/nbi/tests/test_debug_api.py +++ b/src/nbi/tests/test_debug_api.py @@ -13,6 +13,7 @@ # limitations under the License. import logging, os, pytest, time, urllib +import pprint from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME, ServiceNameEnum from common.proto.context_pb2 import Connection, Context, Device, Link, Service, Slice, Topology from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule @@ -25,17 +26,35 @@ from common.type_checkers.Assertions import ( validate_contexts, validate_device, validate_device_ids, validate_devices, validate_link, validate_link_ids, validate_links, validate_service, validate_service_ids, validate_services, validate_topologies, validate_topology, validate_topology_ids) -from context.client.ContextClient import ContextClient -from nbi.tests.PrepareTestScenario import do_rest_get_request +from nbi.tests.PrepareTestScenario import do_rest_get_request, context_client, nbi_service_rest +from ..service.rest_server.RestServer import RestServer from .MockService_Dependencies import MockService_Dependencies -from .Objects import ( - CONNECTION_R1_R3, CONNECTION_R1_R3_ID, CONNECTION_R1_R3_UUID, CONTEXT, CONTEXT_ID, DEVICE_R1, DEVICE_R1_ID, - DEVICE_R1_UUID, DEVICE_R2, DEVICE_R2_ID, DEVICE_R2_UUID, DEVICE_R3, DEVICE_R3_ID, DEVICE_R3_UUID, LINK_R1_R2, - LINK_R1_R2_ID, LINK_R1_R2_UUID, SERVICE_R1_R2, SERVICE_R1_R2_ID, SERVICE_R1_R2_UUID, SERVICE_R1_R3, - SERVICE_R1_R3_ID, SERVICE_R1_R3_UUID, SERVICE_R2_R3, SERVICE_R2_R3_ID, SERVICE_R2_R3_UUID, SLICE_R1_R3, TOPOLOGY, - TOPOLOGY_ID, POLICY_RULE, POLICY_RULE_ID, POLICY_RULE_UUID +from context.tests.Objects import ( + CONNECTION_R1_R3, CONTEXT, DEVICE_R1, DEVICE_R2, DEVICE_R3, LINK_R1_R2, LINK_R1_R3, LINK_R2_R3, SERVICE_R1_R2, SERVICE_R1_R3, + SERVICE_R2_R3, SLICE_R1_R3, TOPOLOGY ) - +from ..service.rest_server.nbi_plugins.debug_api import URL_PREFIX +# from context.client.ContextClient import ContextClient +# from ..service.rest_server.nbi_plugins.debug_api import RESOURCES + +# connection_r1_r3_uuid = '' +# policyrule_uuid = '' +# slice_r1_r3_uuid = '' +# service_r1_r2_uuid = '' +# service_r1_r3_uuid = '' +# link_r1_r2_uuid = '' +# device_r1_uuid = '' + +def pytest_namespace(): + return { + 'connection_r1_r3_uuid' : '', + 'policyrule_uuid' : '', + 'slice_r1_r3_uuid' : '', + 'service_r1_r2_uuid' : '', + 'service_r1_r3_uuid' : '', + 'link_r1_r2_uuid' : '', + 'device_r1_uuid' : '', + } @pytest.fixture(scope='session') def mock_service(): @@ -61,160 +80,143 @@ os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_HOST os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(GRPC_PORT) os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_HTTP)] = str(HTTP_PORT) -@pytest.fixture(scope='session') -def context_service_grpc(): - _service = ContextService(context_s_mb[0], context_s_mb[1]) - _service.start() - yield _service - _service.stop() - -@pytest.fixture(scope='session') -def context_service_rest(): - database = context_db_mb[0] - _rest_server = RestServer() - for endpoint_name, resource_class, resource_url in RESOURCES: - _rest_server.add_resource(resource_class, resource_url, endpoint=endpoint_name, resource_class_args=(database,)) - _rest_server.start() - time.sleep(1) # bring time for the server to start - yield _rest_server - _rest_server.shutdown() - _rest_server.join() - -@pytest.fixture(scope='session') -def context_client_grpc(context_service_grpc : ContextService): # pylint: disable=redefined-outer-name - _client = ContextClient() - yield _client - _client.close() - -def test_populate_database(): - client = ContextClient(host=LOCAL_HOST, port=GRPC_PORT) - client.SetContext(Context(**CONTEXT)) - client.SetTopology(Topology(**TOPOLOGY)) - client.SetDevice(Device(**DEVICE_R1)) - client.SetDevice(Device(**DEVICE_R2)) - client.SetDevice(Device(**DEVICE_R3)) - client.SetLink(Link(**LINK_R1_R2)) - client.SetLink(Link(**LINK_R1_R3)) - client.SetLink(Link(**LINK_R2_R3)) - client.SetService(Service(**SERVICE_R1_R2)) - client.SetService(Service(**SERVICE_R1_R3)) - client.SetService(Service(**SERVICE_R2_R3)) - client.SetSlice(Slice(**SLICE_R1_R3)) - client.SetConnection(Connection(**CONNECTION_R1_R3)) - -def test_rest_get_context_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_get_request('/context_ids') +def test_populate_database(context_client): + set_context_response = context_client.SetContext(Context(**CONTEXT)) + pytest.connection_r1_r3_uuid = set_context_response.context_uuid.uuid + context_client.SetTopology(Topology(**TOPOLOGY)) + set_device_r1_response = context_client.SetDevice(Device(**DEVICE_R1)) + pytest.device_r1_uuid = set_device_r1_response.device_uuid.uuid + context_client.SetDevice(Device(**DEVICE_R2)) + context_client.SetDevice(Device(**DEVICE_R3)) + set_link_r1_r2_response = context_client.SetLink(Link(**LINK_R1_R2)) + pytest.link_r1_r2_uuid = set_link_r1_r2_response.link_uuid.uuid + context_client.SetLink(Link(**LINK_R1_R3)) + context_client.SetLink(Link(**LINK_R2_R3)) + set_service_r1_r2_response = context_client.SetService(Service(**SERVICE_R1_R2)) + pytest.service_r1_r2_uuid = set_service_r1_r2_response.service_uuid.uuid + set_service_r1_r3_response = context_client.SetService(Service(**SERVICE_R1_R3)) + pytest.service_r1_r3_uuid = set_service_r1_r3_response.service_uuid.uuid + context_client.SetService(Service(**SERVICE_R2_R3)) + set_slice_response = context_client.SetSlice(Slice(**SLICE_R1_R3)) + pytest.slice_r1_r3_uuid = set_slice_response.slice_uuid.uuid + context_client.SetConnection(Connection(**CONNECTION_R1_R3)) + +def test_rest_get_context_ids(nbi_service_rest: RestServer): # pylint: disable=redefined-outer-name + reply = do_rest_get_request(URL_PREFIX + '/context_ids') validate_context_ids(reply) -def test_rest_get_contexts(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_get_request('/contexts') +def test_rest_get_contexts(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name + reply = do_rest_get_request(URL_PREFIX + '/contexts') + # LOGGER.warning(reply['contexts'][0]['service_ids'][0]) + # LOGGER.warning(reply['contexts'][0]['service_ids'][0].keys()) + pprint.pprint(reply) validate_contexts(reply) -def test_rest_get_context(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) - reply = do_rest_get_request('/context/{:s}'.format(context_uuid)) - validate_context(reply) - -def test_rest_get_topology_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) - reply = do_rest_get_request('/context/{:s}/topology_ids'.format(context_uuid)) - validate_topology_ids(reply) - -def test_rest_get_topologies(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) - reply = do_rest_get_request('/context/{:s}/topologies'.format(context_uuid)) - validate_topologies(reply) - -def test_rest_get_topology(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) - topology_uuid = urllib.parse.quote(DEFAULT_TOPOLOGY_NAME) - reply = do_rest_get_request('/context/{:s}/topology/{:s}'.format(context_uuid, topology_uuid)) - validate_topology(reply, num_devices=3, num_links=3) - -def test_rest_get_service_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) - reply = do_rest_get_request('/context/{:s}/service_ids'.format(context_uuid)) - validate_service_ids(reply) - -def test_rest_get_services(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) - reply = do_rest_get_request('/context/{:s}/services'.format(context_uuid)) - validate_services(reply) - -def test_rest_get_service(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) - service_uuid = urllib.parse.quote(SERVICE_R1_R2_UUID, safe='') - reply = do_rest_get_request('/context/{:s}/service/{:s}'.format(context_uuid, service_uuid)) - validate_service(reply) - -def test_rest_get_slice_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) - reply = do_rest_get_request('/context/{:s}/slice_ids'.format(context_uuid)) - #validate_slice_ids(reply) - -def test_rest_get_slices(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) - reply = do_rest_get_request('/context/{:s}/slices'.format(context_uuid)) - #validate_slices(reply) - -def test_rest_get_slice(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) - slice_uuid = urllib.parse.quote(SLICE_R1_R3_UUID, safe='') - reply = do_rest_get_request('/context/{:s}/slice/{:s}'.format(context_uuid, slice_uuid)) - #validate_slice(reply) - -def test_rest_get_device_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_get_request('/device_ids') - validate_device_ids(reply) - -def test_rest_get_devices(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_get_request('/devices') - validate_devices(reply) - -def test_rest_get_device(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - device_uuid = urllib.parse.quote(DEVICE_R1_UUID, safe='') - reply = do_rest_get_request('/device/{:s}'.format(device_uuid)) - validate_device(reply) - -def test_rest_get_link_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_get_request('/link_ids') - validate_link_ids(reply) - -def test_rest_get_links(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_get_request('/links') - validate_links(reply) - -def test_rest_get_link(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - link_uuid = urllib.parse.quote(LINK_R1_R2_UUID, safe='') - reply = do_rest_get_request('/link/{:s}'.format(link_uuid)) - validate_link(reply) - -def test_rest_get_connection_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) - service_uuid = urllib.parse.quote(SERVICE_R1_R3_UUID, safe='') - reply = do_rest_get_request('/context/{:s}/service/{:s}/connection_ids'.format(context_uuid, service_uuid)) - validate_connection_ids(reply) - -def test_rest_get_connections(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) - service_uuid = urllib.parse.quote(SERVICE_R1_R3_UUID, safe='') - reply = do_rest_get_request('/context/{:s}/service/{:s}/connections'.format(context_uuid, service_uuid)) - validate_connections(reply) - -def test_rest_get_connection(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - connection_uuid = urllib.parse.quote(CONNECTION_R1_R3_UUID, safe='') - reply = do_rest_get_request('/connection/{:s}'.format(connection_uuid)) - validate_connection(reply) - -def test_rest_get_policyrule_ids(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_get_request('/policyrule_ids') - #validate_policyrule_ids(reply) - -def test_rest_get_policyrules(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_get_request('/policyrules') - #validate_policyrules(reply) - -def test_rest_get_policyrule(context_service_rest : RestServer): # pylint: disable=redefined-outer-name - policyrule_uuid = urllib.parse.quote(POLICYRULE_UUID, safe='') - reply = do_rest_get_request('/policyrule/{:s}'.format(policyrule_uuid)) - #validate_policyrule(reply) +# def test_rest_get_context(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) +# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}'.format(context_uuid)) +# validate_context(reply) + +# def test_rest_get_topology_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) +# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/topology_ids'.format(context_uuid)) +# validate_topology_ids(reply) + +# def test_rest_get_topologies(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) +# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/topologies'.format(context_uuid)) +# validate_topologies(reply) + +# def test_rest_get_topology(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) +# topology_uuid = urllib.parse.quote(DEFAULT_TOPOLOGY_NAME) +# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/topology/{:s}'.format(context_uuid, topology_uuid)) +# validate_topology(reply, num_devices=3, num_links=3) + +# def test_rest_get_service_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) +# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/service_ids'.format(context_uuid)) +# validate_service_ids(reply) + +# def test_rest_get_services(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) +# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/services'.format(context_uuid)) +# validate_services(reply) + +# def test_rest_get_service(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) +# service_uuid = urllib.parse.quote(service_r1_r2_uuid, safe='') +# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/service/{:s}'.format(context_uuid, service_uuid)) +# validate_service(reply) + +# def test_rest_get_slice_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) +# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/slice_ids'.format(context_uuid)) +# #validate_slice_ids(reply) + +# def test_rest_get_slices(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) +# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/slices'.format(context_uuid)) +# #validate_slices(reply) + +# def test_rest_get_slice(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) +# slice_uuid = urllib.parse.quote(slice_r1_r3_uuid, safe='') +# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/slice/{:s}'.format(context_uuid, slice_uuid)) +# #validate_slice(reply) + +# def test_rest_get_device_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# reply = do_rest_get_request(URL_PREFIX + '/device_ids') +# validate_device_ids(reply) + +# def test_rest_get_devices(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# reply = do_rest_get_request(URL_PREFIX + '/devices') +# validate_devices(reply) + +# def test_rest_get_device(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# device_uuid = urllib.parse.quote(device_r1_uuid, safe='') +# reply = do_rest_get_request(URL_PREFIX + '/device/{:s}'.format(device_uuid)) +# validate_device(reply) + +# def test_rest_get_link_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# reply = do_rest_get_request(URL_PREFIX + '/link_ids') +# validate_link_ids(reply) + +# def test_rest_get_links(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# reply = do_rest_get_request(URL_PREFIX + '/links') +# validate_links(reply) + +# def test_rest_get_link(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# link_uuid = urllib.parse.quote(link_r1_r2_uuid, safe='') +# reply = do_rest_get_request(URL_PREFIX + '/link/{:s}'.format(link_uuid)) +# validate_link(reply) + +# def test_rest_get_connection_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) +# service_uuid = urllib.parse.quote(service_r1_r3_uuid, safe='') +# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/service/{:s}/connection_ids'.format(context_uuid, service_uuid)) +# validate_connection_ids(reply) + +# def test_rest_get_connections(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) +# service_uuid = urllib.parse.quote(service_r1_r3_uuid, safe='') +# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/service/{:s}/connections'.format(context_uuid, service_uuid)) +# validate_connections(reply) + +# def test_rest_get_connection(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# connection_uuid = urllib.parse.quote(connection_r1_r3_uuid, safe='') +# reply = do_rest_get_request(URL_PREFIX + '/connection/{:s}'.format(connection_uuid)) +# validate_connection(reply) + +# def test_rest_get_policyrule_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# reply = do_rest_get_request(URL_PREFIX + '/policyrule_ids') +# #validate_policyrule_ids(reply) + +# def test_rest_get_policyrules(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# reply = do_rest_get_request(URL_PREFIX + '/policyrules') +# #validate_policyrules(reply) + +# def test_rest_get_policyrule(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name +# policyrule_uuid_quoted = urllib.parse.quote(policyrule_uuid, safe='') +# reply = do_rest_get_request(URL_PREFIX + '/policyrule/{:s}'.format(policyrule_uuid_quoted)) +# #validate_policyrule(reply) -- GitLab From 44c6b0b41f5b1955829816fd113cb81414ccb299 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Thu, 18 Jan 2024 17:05:08 +0000 Subject: [PATCH 02/10] NBI component - Debug API - Added script to launch tests locally --- scripts/run_tests_locally-nbi-debug-api.sh | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100755 scripts/run_tests_locally-nbi-debug-api.sh diff --git a/scripts/run_tests_locally-nbi-debug-api.sh b/scripts/run_tests_locally-nbi-debug-api.sh new file mode 100755 index 000000000..218bad8c5 --- /dev/null +++ b/scripts/run_tests_locally-nbi-debug-api.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_debug_api.py -- GitLab From 9cc2fb42e838011389932a3f7f7092d5d2063598 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Thu, 18 Jan 2024 18:24:53 +0000 Subject: [PATCH 03/10] Common - Tests - Mock Context: - Formatted Policy-related methods - Minor cosmetic changes --- src/common/tests/MockServicerImpl_Context.py | 199 ++++++++----------- 1 file changed, 80 insertions(+), 119 deletions(-) diff --git a/src/common/tests/MockServicerImpl_Context.py b/src/common/tests/MockServicerImpl_Context.py index 6e749e17c..b50b044a1 100644 --- a/src/common/tests/MockServicerImpl_Context.py +++ b/src/common/tests/MockServicerImpl_Context.py @@ -68,58 +68,58 @@ class MockServicerImpl_Context(ContextServiceServicer): # ----- Context ---------------------------------------------------------------------------------------------------- - def ListContextIds(self, request: Empty, context : grpc.ServicerContext) -> ContextIdList: + def ListContextIds(self, request : Empty, context : grpc.ServicerContext) -> ContextIdList: LOGGER.debug('[ListContextIds] request={:s}'.format(grpc_message_to_json_string(request))) reply = ContextIdList(context_ids=[context.context_id for context in self.obj_db.get_entries('context')]) LOGGER.debug('[ListContextIds] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def ListContexts(self, request: Empty, context : grpc.ServicerContext) -> ContextList: + def ListContexts(self, request : Empty, context : grpc.ServicerContext) -> ContextList: LOGGER.debug('[ListContexts] request={:s}'.format(grpc_message_to_json_string(request))) reply = ContextList(contexts=self.obj_db.get_entries('context')) LOGGER.debug('[ListContexts] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetContext(self, request: ContextId, context : grpc.ServicerContext) -> Context: + def GetContext(self, request : ContextId, context : grpc.ServicerContext) -> Context: LOGGER.debug('[GetContext] request={:s}'.format(grpc_message_to_json_string(request))) reply = self.obj_db.get_entry('context', request.context_uuid.uuid, context) LOGGER.debug('[GetContext] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def SetContext(self, request: Context, context : grpc.ServicerContext) -> ContextId: + def SetContext(self, request : Context, context : grpc.ServicerContext) -> ContextId: LOGGER.debug('[SetContext] request={:s}'.format(grpc_message_to_json_string(request))) reply,_ = self._set(request, 'context', request.context_id.context_uuid.uuid, 'context_id', TOPIC_CONTEXT) LOGGER.debug('[SetContext] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def RemoveContext(self, request: ContextId, context : grpc.ServicerContext) -> Empty: + def RemoveContext(self, request : ContextId, context : grpc.ServicerContext) -> Empty: LOGGER.debug('[RemoveContext] request={:s}'.format(grpc_message_to_json_string(request))) reply = self._del(request, 'context', request.context_uuid.uuid, 'context_id', TOPIC_CONTEXT, context) LOGGER.debug('[RemoveContext] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetContextEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[ContextEvent]: + def GetContextEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ContextEvent]: LOGGER.debug('[GetContextEvents] request={:s}'.format(grpc_message_to_json_string(request))) for message in self.msg_broker.consume({TOPIC_CONTEXT}): yield ContextEvent(**json.loads(message.content)) # ----- Topology --------------------------------------------------------------------------------------------------- - def ListTopologyIds(self, request: ContextId, context : grpc.ServicerContext) -> TopologyIdList: + def ListTopologyIds(self, request : ContextId, context : grpc.ServicerContext) -> TopologyIdList: LOGGER.debug('[ListTopologyIds] request={:s}'.format(grpc_message_to_json_string(request))) topologies = self.obj_db.get_entries('topology[{:s}]'.format(str(request.context_uuid.uuid))) reply = TopologyIdList(topology_ids=[topology.topology_id for topology in topologies]) LOGGER.debug('[ListTopologyIds] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def ListTopologies(self, request: ContextId, context : grpc.ServicerContext) -> TopologyList: + def ListTopologies(self, request : ContextId, context : grpc.ServicerContext) -> TopologyList: LOGGER.debug('[ListTopologies] request={:s}'.format(grpc_message_to_json_string(request))) topologies = self.obj_db.get_entries('topology[{:s}]'.format(str(request.context_uuid.uuid))) reply = TopologyList(topologies=[topology for topology in topologies]) LOGGER.debug('[ListTopologies] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetTopology(self, request: TopologyId, context : grpc.ServicerContext) -> Topology: + def GetTopology(self, request : TopologyId, context : grpc.ServicerContext) -> Topology: LOGGER.debug('[GetTopology] request={:s}'.format(grpc_message_to_json_string(request))) container_name = 'topology[{:s}]'.format(str(request.context_id.context_uuid.uuid)) reply = self.obj_db.get_entry(container_name, request.topology_uuid.uuid, context) @@ -149,7 +149,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[GetTopologyDetails] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def SetTopology(self, request: Topology, context : grpc.ServicerContext) -> TopologyId: + def SetTopology(self, request : Topology, context : grpc.ServicerContext) -> TopologyId: LOGGER.debug('[SetTopology] request={:s}'.format(grpc_message_to_json_string(request))) context_uuid = str(request.topology_id.context_id.context_uuid.uuid) container_name = 'topology[{:s}]'.format(context_uuid) @@ -192,7 +192,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[SetTopology] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def RemoveTopology(self, request: TopologyId, context : grpc.ServicerContext) -> Empty: + def RemoveTopology(self, request : TopologyId, context : grpc.ServicerContext) -> Empty: LOGGER.debug('[RemoveTopology] request={:s}'.format(grpc_message_to_json_string(request))) context_uuid = str(request.context_id.context_uuid.uuid) container_name = 'topology[{:s}]'.format(context_uuid) @@ -208,32 +208,32 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[RemoveTopology] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetTopologyEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[TopologyEvent]: + def GetTopologyEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[TopologyEvent]: LOGGER.debug('[GetTopologyEvents] request={:s}'.format(grpc_message_to_json_string(request))) for message in self.msg_broker.consume({TOPIC_TOPOLOGY}): yield TopologyEvent(**json.loads(message.content)) # ----- Device ----------------------------------------------------------------------------------------------------- - def ListDeviceIds(self, request: Empty, context : grpc.ServicerContext) -> DeviceIdList: + def ListDeviceIds(self, request : Empty, context : grpc.ServicerContext) -> DeviceIdList: LOGGER.debug('[ListDeviceIds] request={:s}'.format(grpc_message_to_json_string(request))) reply = DeviceIdList(device_ids=[device.device_id for device in self.obj_db.get_entries('device')]) LOGGER.debug('[ListDeviceIds] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def ListDevices(self, request: Empty, context : grpc.ServicerContext) -> DeviceList: + def ListDevices(self, request : Empty, context : grpc.ServicerContext) -> DeviceList: LOGGER.debug('[ListDevices] request={:s}'.format(grpc_message_to_json_string(request))) reply = DeviceList(devices=self.obj_db.get_entries('device')) LOGGER.debug('[ListDevices] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetDevice(self, request: DeviceId, context : grpc.ServicerContext) -> Device: + def GetDevice(self, request : DeviceId, context : grpc.ServicerContext) -> Device: LOGGER.debug('[GetDevice] request={:s}'.format(grpc_message_to_json_string(request))) reply = self.obj_db.get_entry('device', request.device_uuid.uuid, context) LOGGER.debug('[GetDevice] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def SetDevice(self, request: Context, context : grpc.ServicerContext) -> DeviceId: + def SetDevice(self, request : Context, context : grpc.ServicerContext) -> DeviceId: LOGGER.debug('[SetDevice] request={:s}'.format(grpc_message_to_json_string(request))) device_uuid = request.device_id.device_uuid.uuid reply, device = self._set(request, 'device', device_uuid, 'device_id', TOPIC_DEVICE) @@ -259,7 +259,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[SetDevice] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def RemoveDevice(self, request: DeviceId, context : grpc.ServicerContext) -> Empty: + def RemoveDevice(self, request : DeviceId, context : grpc.ServicerContext) -> Empty: LOGGER.debug('[RemoveDevice] request={:s}'.format(grpc_message_to_json_string(request))) device_uuid = request.device_uuid.uuid device = self.obj_db.get_entry('device', device_uuid, context) @@ -285,7 +285,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[RemoveDevice] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetDeviceEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[DeviceEvent]: + def GetDeviceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[DeviceEvent]: LOGGER.debug('[GetDeviceEvents] request={:s}'.format(grpc_message_to_json_string(request))) for message in self.msg_broker.consume({TOPIC_DEVICE}): yield DeviceEvent(**json.loads(message.content)) @@ -319,25 +319,25 @@ class MockServicerImpl_Context(ContextServiceServicer): # ----- Link ------------------------------------------------------------------------------------------------------- - def ListLinkIds(self, request: Empty, context : grpc.ServicerContext) -> LinkIdList: + def ListLinkIds(self, request : Empty, context : grpc.ServicerContext) -> LinkIdList: LOGGER.debug('[ListLinkIds] request={:s}'.format(grpc_message_to_json_string(request))) reply = LinkIdList(link_ids=[link.link_id for link in self.obj_db.get_entries('link')]) LOGGER.debug('[ListLinkIds] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def ListLinks(self, request: Empty, context : grpc.ServicerContext) -> LinkList: + def ListLinks(self, request : Empty, context : grpc.ServicerContext) -> LinkList: LOGGER.debug('[ListLinks] request={:s}'.format(grpc_message_to_json_string(request))) reply = LinkList(links=self.obj_db.get_entries('link')) LOGGER.debug('[ListLinks] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetLink(self, request: LinkId, context : grpc.ServicerContext) -> Link: + def GetLink(self, request : LinkId, context : grpc.ServicerContext) -> Link: LOGGER.debug('[GetLink] request={:s}'.format(grpc_message_to_json_string(request))) reply = self.obj_db.get_entry('link', request.link_uuid.uuid, context) LOGGER.debug('[GetLink] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def SetLink(self, request: Context, context : grpc.ServicerContext) -> LinkId: + def SetLink(self, request : Context, context : grpc.ServicerContext) -> LinkId: LOGGER.debug('[SetLink] request={:s}'.format(grpc_message_to_json_string(request))) link_uuid = request.link_id.link_uuid.uuid reply, link = self._set(request, 'link', link_uuid, 'link_id', TOPIC_LINK) @@ -363,7 +363,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[SetLink] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def RemoveLink(self, request: LinkId, context : grpc.ServicerContext) -> Empty: + def RemoveLink(self, request : LinkId, context : grpc.ServicerContext) -> Empty: LOGGER.debug('[RemoveLink] request={:s}'.format(grpc_message_to_json_string(request))) link_uuid = request.link_uuid.uuid link = self.obj_db.get_entry('link', link_uuid, context) @@ -389,35 +389,35 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[RemoveLink] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetLinkEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[LinkEvent]: + def GetLinkEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[LinkEvent]: LOGGER.debug('[GetLinkEvents] request={:s}'.format(grpc_message_to_json_string(request))) for message in self.msg_broker.consume({TOPIC_LINK}): yield LinkEvent(**json.loads(message.content)) # ----- Slice ------------------------------------------------------------------------------------------------------ - def ListSliceIds(self, request: ContextId, context : grpc.ServicerContext) -> SliceIdList: + def ListSliceIds(self, request : ContextId, context : grpc.ServicerContext) -> SliceIdList: LOGGER.debug('[ListSliceIds] request={:s}'.format(grpc_message_to_json_string(request))) slices = self.obj_db.get_entries('slice[{:s}]'.format(str(request.context_uuid.uuid))) reply = SliceIdList(slice_ids=[slice.slice_id for slice in slices]) LOGGER.debug('[ListSliceIds] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def ListSlices(self, request: ContextId, context : grpc.ServicerContext) -> SliceList: + def ListSlices(self, request : ContextId, context : grpc.ServicerContext) -> SliceList: LOGGER.debug('[ListSlices] request={:s}'.format(grpc_message_to_json_string(request))) slices = self.obj_db.get_entries('slice[{:s}]'.format(str(request.context_uuid.uuid))) reply = SliceList(slices=[slice for slice in slices]) LOGGER.debug('[ListSlices] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetSlice(self, request: SliceId, context : grpc.ServicerContext) -> Slice: + def GetSlice(self, request : SliceId, context : grpc.ServicerContext) -> Slice: LOGGER.debug('[GetSlice] request={:s}'.format(grpc_message_to_json_string(request))) container_name = 'slice[{:s}]'.format(str(request.context_id.context_uuid.uuid)) reply = self.obj_db.get_entry(container_name, request.slice_uuid.uuid, context) LOGGER.debug('[GetSlice] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def SetSlice(self, request: Slice, context : grpc.ServicerContext) -> SliceId: + def SetSlice(self, request : Slice, context : grpc.ServicerContext) -> SliceId: LOGGER.debug('[SetSlice] request={:s}'.format(grpc_message_to_json_string(request))) context_uuid = str(request.slice_id.context_id.context_uuid.uuid) container_name = 'slice[{:s}]'.format(context_uuid) @@ -434,7 +434,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[SetSlice] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def RemoveSlice(self, request: SliceId, context : grpc.ServicerContext) -> Empty: + def RemoveSlice(self, request : SliceId, context : grpc.ServicerContext) -> Empty: LOGGER.debug('[RemoveSlice] request={:s}'.format(grpc_message_to_json_string(request))) context_uuid = str(request.context_id.context_uuid.uuid) container_name = 'slice[{:s}]'.format(context_uuid) @@ -450,7 +450,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[RemoveSlice] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetSliceEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[SliceEvent]: + def GetSliceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[SliceEvent]: LOGGER.debug('[GetSliceEvents] request={:s}'.format(grpc_message_to_json_string(request))) for message in self.msg_broker.consume({TOPIC_SLICE}): yield SliceEvent(**json.loads(message.content)) @@ -488,28 +488,28 @@ class MockServicerImpl_Context(ContextServiceServicer): # ----- Service ---------------------------------------------------------------------------------------------------- - def ListServiceIds(self, request: ContextId, context : grpc.ServicerContext) -> ServiceIdList: + def ListServiceIds(self, request : ContextId, context : grpc.ServicerContext) -> ServiceIdList: LOGGER.debug('[ListServiceIds] request={:s}'.format(grpc_message_to_json_string(request))) services = self.obj_db.get_entries('service[{:s}]'.format(str(request.context_uuid.uuid))) reply = ServiceIdList(service_ids=[service.service_id for service in services]) LOGGER.debug('[ListServiceIds] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def ListServices(self, request: ContextId, context : grpc.ServicerContext) -> ServiceList: + def ListServices(self, request : ContextId, context : grpc.ServicerContext) -> ServiceList: LOGGER.debug('[ListServices] request={:s}'.format(grpc_message_to_json_string(request))) services = self.obj_db.get_entries('service[{:s}]'.format(str(request.context_uuid.uuid))) reply = ServiceList(services=[service for service in services]) LOGGER.debug('[ListServices] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetService(self, request: ServiceId, context : grpc.ServicerContext) -> Service: + def GetService(self, request : ServiceId, context : grpc.ServicerContext) -> Service: LOGGER.debug('[GetService] request={:s}'.format(grpc_message_to_json_string(request))) container_name = 'service[{:s}]'.format(str(request.context_id.context_uuid.uuid)) reply = self.obj_db.get_entry(container_name, request.service_uuid.uuid, context) LOGGER.debug('[GetService] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def SetService(self, request: Service, context : grpc.ServicerContext) -> ServiceId: + def SetService(self, request : Service, context : grpc.ServicerContext) -> ServiceId: LOGGER.debug('[SetService] request={:s}'.format(grpc_message_to_json_string(request))) context_uuid = str(request.service_id.context_id.context_uuid.uuid) container_name = 'service[{:s}]'.format(context_uuid) @@ -526,7 +526,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[SetService] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def RemoveService(self, request: ServiceId, context : grpc.ServicerContext) -> Empty: + def RemoveService(self, request : ServiceId, context : grpc.ServicerContext) -> Empty: LOGGER.debug('[RemoveService] request={:s}'.format(grpc_message_to_json_string(request))) context_uuid = str(request.context_id.context_uuid.uuid) container_name = 'service[{:s}]'.format(context_uuid) @@ -542,7 +542,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[RemoveService] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetServiceEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[ServiceEvent]: + def GetServiceEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ServiceEvent]: LOGGER.debug('[GetServiceEvents] request={:s}'.format(grpc_message_to_json_string(request))) for message in self.msg_broker.consume({TOPIC_SERVICE}): yield ServiceEvent(**json.loads(message.content)) @@ -575,7 +575,7 @@ class MockServicerImpl_Context(ContextServiceServicer): # ----- Connection ------------------------------------------------------------------------------------------------- - def ListConnectionIds(self, request: ServiceId, context : grpc.ServicerContext) -> ConnectionIdList: + def ListConnectionIds(self, request : ServiceId, context : grpc.ServicerContext) -> ConnectionIdList: LOGGER.debug('[ListConnectionIds] request={:s}'.format(grpc_message_to_json_string(request))) container_name = 'service_connections[{:s}/{:s}]'.format( str(request.context_id.context_uuid.uuid), str(request.service_uuid.uuid)) @@ -583,7 +583,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[ListConnectionIds] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def ListConnections(self, request: ServiceId, context : grpc.ServicerContext) -> ConnectionList: + def ListConnections(self, request : ServiceId, context : grpc.ServicerContext) -> ConnectionList: LOGGER.debug('[ListConnections] request={:s}'.format(grpc_message_to_json_string(request))) container_name = 'service_connections[{:s}/{:s}]'.format( str(request.context_id.context_uuid.uuid), str(request.service_uuid.uuid)) @@ -591,13 +591,13 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[ListConnections] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetConnection(self, request: ConnectionId, context : grpc.ServicerContext) -> Connection: + def GetConnection(self, request : ConnectionId, context : grpc.ServicerContext) -> Connection: LOGGER.debug('[GetConnection] request={:s}'.format(grpc_message_to_json_string(request))) reply = self.obj_db.get_entry('connection', request.connection_uuid.uuid, context) LOGGER.debug('[GetConnection] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def SetConnection(self, request: Connection, context : grpc.ServicerContext) -> ConnectionId: + def SetConnection(self, request : Connection, context : grpc.ServicerContext) -> ConnectionId: LOGGER.debug('[SetConnection] request={:s}'.format(grpc_message_to_json_string(request))) container_name = 'service_connection[{:s}/{:s}]'.format( str(request.service_id.context_id.context_uuid.uuid), str(request.service_id.service_uuid.uuid)) @@ -607,7 +607,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[SetConnection] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def RemoveConnection(self, request: ConnectionId, context : grpc.ServicerContext) -> Empty: + def RemoveConnection(self, request : ConnectionId, context : grpc.ServicerContext) -> Empty: LOGGER.debug('[RemoveConnection] request={:s}'.format(grpc_message_to_json_string(request))) connection = self.obj_db.get_entry('connection', request.connection_uuid.uuid, context) container_name = 'service_connection[{:s}/{:s}]'.format( @@ -618,84 +618,45 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[RemoveConnection] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def GetConnectionEvents(self, request: Empty, context : grpc.ServicerContext) -> Iterator[ConnectionEvent]: + def GetConnectionEvents(self, request : Empty, context : grpc.ServicerContext) -> Iterator[ConnectionEvent]: LOGGER.debug('[GetConnectionEvents] request={:s}'.format(grpc_message_to_json_string(request))) for message in self.msg_broker.consume({TOPIC_CONNECTION}): yield ConnectionEvent(**json.loads(message.content)) - def ListPolicyRuleIds(self, request: Empty, context: grpc.ServicerContext): - LOGGER.debug( - "[ListPolicyRuleIds] request={:s}".format( - grpc_message_to_json_string(request) - ) - ) - reply = PolicyRuleIdList( - policyRuleIdList=[ - getattr( - policy_rule, policy_rule.WhichOneof("policy_rule") - ).policyRuleBasic.policyRuleId - for policy_rule in self.obj_db.get_entries("policy") - ] - ) - LOGGER.debug( - "[ListPolicyRuleIds] reply={:s}".format(grpc_message_to_json_string(reply)) - ) - return reply - - def ListPolicyRules(self, request: Empty, context: grpc.ServicerContext): - LOGGER.debug( - "[ListPolicyRules] request={:s}".format( - grpc_message_to_json_string(request) - ) - ) - reply = PolicyRuleList(policyRules=self.obj_db.get_entries("policy")) - LOGGER.debug( - "[ListPolicyRules] reply={:s}".format(grpc_message_to_json_string(reply)) - ) - return reply - - def GetPolicyRule(self, request: PolicyRuleId, context: grpc.ServicerContext): - LOGGER.debug( - "[GetPolicyRule] request={:s}".format(grpc_message_to_json_string(request)) - ) - reply = self.obj_db.get_entry("policy_rule", request.uuid.uuid, context) - LOGGER.debug( - "[GetPolicyRule] reply={:s}".format(grpc_message_to_json_string(reply)) - ) - return reply - - def SetPolicyRule(self, request: PolicyRule, context: grpc.ServicerContext): - LOGGER.debug( - "[SetPolicyRule] request={:s}".format(grpc_message_to_json_string(request)) - ) - policy_type = request.WhichOneof("policy_rule") - reply, _ = self._set( - request, - "policy", - getattr(request, policy_type).policyRuleBasic.policyRuleId.uuid.uuid, - f"{policy_type}.policyRuleBasic.policyRuleId", - TOPIC_POLICY, - ) - LOGGER.debug( - "[SetPolicyRule] reply={:s}".format(grpc_message_to_json_string(reply)) - ) - return reply - - def RemovePolicyRule(self, request: PolicyRuleId, context: grpc.ServicerContext): - LOGGER.debug( - "[RemovePolicyRule] request={:s}".format( - grpc_message_to_json_string(request) - ) - ) - policy_type = request.WhichOneof("policy_rule") - reply = self._del( - request, - "policy", - getattr(request, policy_type).policyRuleBasic.policyRuleId.uuid.uuid, - f"{policy_type}.policyRuleBasic.policyRuleId", - TOPIC_CONTEXT, - context, - ) - LOGGER.debug( - "[RemovePolicyRule] reply={:s}".format(grpc_message_to_json_string(reply)) - ) - return reply \ No newline at end of file + def ListPolicyRuleIds(self, request : Empty, context : grpc.ServicerContext): + LOGGER.debug('[ListPolicyRuleIds] request={:s}'.format(grpc_message_to_json_string(request))) + reply = PolicyRuleIdList(policyRuleIdList=[ + getattr(policy_rule, policy_rule.WhichOneof('policy_rule')).policyRuleBasic.policyRuleId + for policy_rule in self.obj_db.get_entries('policy') + ]) + LOGGER.debug('[ListPolicyRuleIds] reply={:s}'.format(grpc_message_to_json_string(reply))) + return reply + + def ListPolicyRules(self, request : Empty, context : grpc.ServicerContext): + LOGGER.debug('[ListPolicyRules] request={:s}'.format(grpc_message_to_json_string(request))) + reply = PolicyRuleList(policyRules=self.obj_db.get_entries('policy')) + LOGGER.debug('[ListPolicyRules] reply={:s}'.format(grpc_message_to_json_string(reply))) + return reply + + def GetPolicyRule(self, request : PolicyRuleId, context : grpc.ServicerContext): + LOGGER.debug('[GetPolicyRule] request={:s}'.format(grpc_message_to_json_string(request))) + reply = self.obj_db.get_entry('policy_rule', request.uuid.uuid, context) + LOGGER.debug('[GetPolicyRule] reply={:s}'.format(grpc_message_to_json_string(reply))) + return reply + + def SetPolicyRule(self, request : PolicyRule, context : grpc.ServicerContext): + LOGGER.debug('[SetPolicyRule] request={:s}'.format(grpc_message_to_json_string(request))) + policy_type = request.WhichOneof('policy_rule') + policy_uuid = getattr(request, policy_type).policyRuleBasic.policyRuleId.uuid.uuid + rule_id_field = '{:s}.policyRuleBasic.policyRuleId'.format(policy_type) + reply, _ = self._set(request, 'policy', policy_uuid, rule_id_field, TOPIC_POLICY) + LOGGER.debug('[SetPolicyRule] reply={:s}'.format(grpc_message_to_json_string(reply))) + return reply + + def RemovePolicyRule(self, request : PolicyRuleId, context : grpc.ServicerContext): + LOGGER.debug('[RemovePolicyRule] request={:s}'.format(grpc_message_to_json_string(request))) + policy_type = request.WhichOneof('policy_rule') + policy_uuid = getattr(request, policy_type).policyRuleBasic.policyRuleId.uuid.uuid + rule_id_field = '{:s}.policyRuleBasic.policyRuleId'.format(policy_type) + reply = self._del(request, 'policy', policy_uuid, rule_id_field, TOPIC_CONTEXT, context) + LOGGER.debug('[RemovePolicyRule] reply={:s}'.format(grpc_message_to_json_string(reply))) + return reply -- GitLab From 82ff7793ac7cadb2dba4c0c0b9fb940f3f58b4d8 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Thu, 18 Jan 2024 18:25:40 +0000 Subject: [PATCH 04/10] NBI component - Debug API - Updated unitary tests - Added test descriptor file --- src/nbi/tests/data/debug_api_dummy.json | 238 +++++++++++++++ src/nbi/tests/test_debug_api.py | 377 ++++++++++++------------ 2 files changed, 422 insertions(+), 193 deletions(-) create mode 100644 src/nbi/tests/data/debug_api_dummy.json diff --git a/src/nbi/tests/data/debug_api_dummy.json b/src/nbi/tests/data/debug_api_dummy.json new file mode 100644 index 000000000..2e0d75559 --- /dev/null +++ b/src/nbi/tests/data/debug_api_dummy.json @@ -0,0 +1,238 @@ +{ + "dummy_mode": true, + "contexts": [ + { + "context_id": {"context_uuid": {"uuid": "admin"}}, + "name": "admin", + "topology_ids": [ + {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + ], + "service_ids": [ + {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "admin"}}, + {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "admin"}}, + {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "admin"}} + ], + "slice_ids": [ + {"context_id": {"context_uuid": {"uuid": "admin"}}, "slice_uuid": {"uuid": "admin"}} + ] + } + ], + "topologies": [ + { + "device_ids": [ + {"device_uuid": {"uuid": "R1"}}, + {"device_uuid": {"uuid": "R2"}}, + {"device_uuid": {"uuid": "R3"}} + ], + "link_ids": [ + {"link_uuid": {"uuid": "R1/502==R2/501"}}, + {"link_uuid": {"uuid": "R1/503==R3/501"}}, + {"link_uuid": {"uuid": "R2/501==R1/502"}}, + {"link_uuid": {"uuid": "R2/503==R3/502"}}, + {"link_uuid": {"uuid": "R3/501==R1/503"}}, + {"link_uuid": {"uuid": "R3/502==R2/503"}} + ], + "name": "admin", + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ], + "devices": [ + { + "device_id": {"device_uuid": {"uuid": "R1"}}, "name": "R1", "device_type": "emu-packet-router", + "device_drivers": [0], "device_operational_status": 2, + "device_endpoints": [ + {"name": "200", "endpoint_type": "copper", "endpoint_id": { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }}, + {"name": "502", "endpoint_type": "optical", "endpoint_id": { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "502"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }}, + {"name": "503", "endpoint_type": "optical", "endpoint_id": { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "503"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }} + ], + "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": [ + {"uuid": "200", "name": "200", "type": "copper"}, + {"uuid": "502", "name": "502", "type": "optical"}, + {"uuid": "503", "name": "503", "type": "optical"} + ]}}}, + {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[200]", "resource_value": { + "uuid": "200", "name": "200", "type": "copper" + }}}, + {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[502]", "resource_value": { + "uuid": "502", "name": "502", "type": "optical" + }}}, + {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[503]", "resource_value": { + "uuid": "503", "name": "503", "type": "optical" + }}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "R2"}}, "name": "R2", "device_type": "emu-packet-router", + "device_drivers": [0], "device_operational_status": 2, + "device_endpoints": [ + {"name": "200", "endpoint_type": "copper", "endpoint_id": { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }}, + {"name": "501", "endpoint_type": "optical", "endpoint_id": { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "501"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }}, + {"name": "503", "endpoint_type": "optical", "endpoint_id": { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "503"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }} + ], + "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": [ + {"uuid": "200", "name": "200", "type": "copper"}, + {"uuid": "501", "name": "501", "type": "optical"}, + {"uuid": "503", "name": "503", "type": "optical"} + ]}}}, + {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[200]", "resource_value": { + "uuid": "200", "name": "200", "type": "copper" + }}}, + {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[501]", "resource_value": { + "uuid": "501", "name": "501", "type": "optical" + }}}, + {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[503]", "resource_value": { + "uuid": "503", "name": "503", "type": "optical" + }}} + ]} + }, + { + "device_id": {"device_uuid": {"uuid": "R3"}}, "name": "R3", "device_type": "emu-packet-router", + "device_drivers": [0], "device_operational_status": 2, + "device_endpoints": [ + {"name": "200", "endpoint_type": "copper", "endpoint_id": { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }}, + {"name": "502", "endpoint_type": "optical", "endpoint_id": { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "502"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }}, + {"name": "503", "endpoint_type": "optical", "endpoint_id": { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "503"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }} + ], + "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": [ + {"uuid": "200", "name": "200", "type": "copper"}, + {"uuid": "502", "name": "502", "type": "optical"}, + {"uuid": "503", "name": "503", "type": "optical"} + ]}}}, + {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[200]", "resource_value": { + "uuid": "200", "name": "200", "type": "copper" + }}}, + {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[502]", "resource_value": { + "uuid": "502", "name": "502", "type": "optical" + }}}, + {"action": 1, "custom": {"resource_key": "/endpoints/endpoint[503]", "resource_value": { + "uuid": "503", "name": "503", "type": "optical" + }}} + ]} + } + ], + "links": [ + { + "link_id": {"link_uuid": {"uuid": "R1/502==R2/501"}}, "name": "R1/502==R2/501", + "attributes": {"total_capacity_gbps": 10.0, "used_capacity_gbps": 0.0}, + "link_endpoint_ids": [ + { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "502"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "501"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R1/503==R3/501"}}, "name": "R1/503==R3/501", + "attributes": {"total_capacity_gbps": 10.0, "used_capacity_gbps": 0.0}, + "link_endpoint_ids": [ + { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "503"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "501"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R2/501==R1/502"}}, "name": "R2/501==R1/502", + "attributes": {"total_capacity_gbps": 10.0, "used_capacity_gbps": 0.0}, + "link_endpoint_ids": [ + { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "501"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "502"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R2/503==R3/502"}}, "name": "R2/503==R3/502", + "attributes": {"total_capacity_gbps": 10.0, "used_capacity_gbps": 0.0}, + "link_endpoint_ids": [ + { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "503"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "502"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R3/501==R1/503"}}, "name": "R3/501==R1/503", + "attributes": {"total_capacity_gbps": 10.0, "used_capacity_gbps": 0.0}, + "link_endpoint_ids": [ + { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "501"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "503"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ] + }, + { + "link_id": {"link_uuid": {"uuid": "R3/502==R2/503"}}, "name": "R3/502==R2/503", + "attributes": {"total_capacity_gbps": 10.0, "used_capacity_gbps": 0.0}, + "link_endpoint_ids": [ + { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "502"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "503"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ] + } + ], + "services": [], + "slices": [], + "connections": [] +} diff --git a/src/nbi/tests/test_debug_api.py b/src/nbi/tests/test_debug_api.py index ed788f469..1618b3242 100644 --- a/src/nbi/tests/test_debug_api.py +++ b/src/nbi/tests/test_debug_api.py @@ -12,211 +12,202 @@ # See the License for the specific language governing permissions and # limitations under the License. -import logging, os, pytest, time, urllib -import pprint -from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME, ServiceNameEnum -from common.proto.context_pb2 import Connection, Context, Device, Link, Service, Slice, Topology -from common.proto.policy_pb2 import PolicyRuleIdList, PolicyRuleId, PolicyRuleList, PolicyRule -from common.Settings import ( - ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, ENVVAR_SUFIX_SERVICE_PORT_HTTP, get_env_var_name, - get_service_port_grpc, get_service_port_http +import logging, urllib +from common.Constants import DEFAULT_CONTEXT_NAME, DEFAULT_TOPOLOGY_NAME +from common.proto.context_pb2 import ContextId +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.type_checkers.Assertions import ( validate_connection, validate_connection_ids, validate_connections, validate_context, validate_context_ids, validate_contexts, validate_device, validate_device_ids, validate_devices, validate_link, validate_link_ids, validate_links, validate_service, validate_service_ids, validate_services, validate_topologies, validate_topology, validate_topology_ids) -from nbi.tests.PrepareTestScenario import do_rest_get_request, context_client, nbi_service_rest -from ..service.rest_server.RestServer import RestServer -from .MockService_Dependencies import MockService_Dependencies -from context.tests.Objects import ( - CONNECTION_R1_R3, CONTEXT, DEVICE_R1, DEVICE_R2, DEVICE_R3, LINK_R1_R2, LINK_R1_R3, LINK_R2_R3, SERVICE_R1_R2, SERVICE_R1_R3, - SERVICE_R2_R3, SLICE_R1_R3, TOPOLOGY +from context.client.ContextClient import ContextClient +from nbi.service.rest_server.RestServer 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_post_request, + mock_service, nbi_service_rest, osm_wim, context_client ) -from ..service.rest_server.nbi_plugins.debug_api import URL_PREFIX -# from context.client.ContextClient import ContextClient -# from ..service.rest_server.nbi_plugins.debug_api import RESOURCES - -# connection_r1_r3_uuid = '' -# policyrule_uuid = '' -# slice_r1_r3_uuid = '' -# service_r1_r2_uuid = '' -# service_r1_r3_uuid = '' -# link_r1_r2_uuid = '' -# device_r1_uuid = '' - -def pytest_namespace(): - return { - 'connection_r1_r3_uuid' : '', - 'policyrule_uuid' : '', - 'slice_r1_r3_uuid' : '', - 'service_r1_r2_uuid' : '', - 'service_r1_r3_uuid' : '', - 'link_r1_r2_uuid' : '', - 'device_r1_uuid' : '', - } - -@pytest.fixture(scope='session') -def mock_service(): - _service = MockService_Dependencies(MOCKSERVICE_PORT) - _service.configure_env_vars() - _service.start() - yield _service - _service.stop() - - LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) -LOCAL_HOST = '127.0.0.1' -GRPC_PORT = 10000 + int(get_service_port_grpc(ServiceNameEnum.CONTEXT)) # avoid privileged ports -HTTP_PORT = 10000 + int(get_service_port_http(ServiceNameEnum.CONTEXT)) # avoid privileged ports - -MOCKSERVICE_PORT = 10000 -DEVICE_SERVICE_PORT = MOCKSERVICE_PORT + get_service_port_grpc(ServiceNameEnum.DEVICE) # avoid privileged ports - -os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_HOST )] = str(LOCAL_HOST) -os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(GRPC_PORT) -os.environ[get_env_var_name(ServiceNameEnum.CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_HTTP)] = str(HTTP_PORT) - -def test_populate_database(context_client): - set_context_response = context_client.SetContext(Context(**CONTEXT)) - pytest.connection_r1_r3_uuid = set_context_response.context_uuid.uuid - context_client.SetTopology(Topology(**TOPOLOGY)) - set_device_r1_response = context_client.SetDevice(Device(**DEVICE_R1)) - pytest.device_r1_uuid = set_device_r1_response.device_uuid.uuid - context_client.SetDevice(Device(**DEVICE_R2)) - context_client.SetDevice(Device(**DEVICE_R3)) - set_link_r1_r2_response = context_client.SetLink(Link(**LINK_R1_R2)) - pytest.link_r1_r2_uuid = set_link_r1_r2_response.link_uuid.uuid - context_client.SetLink(Link(**LINK_R1_R3)) - context_client.SetLink(Link(**LINK_R2_R3)) - set_service_r1_r2_response = context_client.SetService(Service(**SERVICE_R1_R2)) - pytest.service_r1_r2_uuid = set_service_r1_r2_response.service_uuid.uuid - set_service_r1_r3_response = context_client.SetService(Service(**SERVICE_R1_R3)) - pytest.service_r1_r3_uuid = set_service_r1_r3_response.service_uuid.uuid - context_client.SetService(Service(**SERVICE_R2_R3)) - set_slice_response = context_client.SetSlice(Slice(**SLICE_R1_R3)) - pytest.slice_r1_r3_uuid = set_slice_response.slice_uuid.uuid - context_client.SetConnection(Connection(**CONNECTION_R1_R3)) - -def test_rest_get_context_ids(nbi_service_rest: RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_get_request(URL_PREFIX + '/context_ids') +DESCRIPTOR_FILE = 'nbi/tests/data/debug_api_dummy.json' + +JSON_ADMIN_CONTEXT_ID = json_context_id(DEFAULT_CONTEXT_NAME) +ADMIN_CONTEXT_ID = ContextId(**JSON_ADMIN_CONTEXT_ID) + + +# ----- Prepare Environment -------------------------------------------------------------------------------------------- + +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 + + +# ----- Context -------------------------------------------------------------------------------------------------------- + +def test_rest_get_context_ids(nbi_service_rest: RestServer): # pylint: disable=redefined-outer-name, unused-argument + reply = do_rest_get_request('/debug-api/context_ids') validate_context_ids(reply) -def test_rest_get_contexts(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name - reply = do_rest_get_request(URL_PREFIX + '/contexts') - # LOGGER.warning(reply['contexts'][0]['service_ids'][0]) - # LOGGER.warning(reply['contexts'][0]['service_ids'][0].keys()) - pprint.pprint(reply) +def test_rest_get_contexts(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + reply = do_rest_get_request('/debug-api/contexts') validate_contexts(reply) -# def test_rest_get_context(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) -# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}'.format(context_uuid)) -# validate_context(reply) - -# def test_rest_get_topology_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) -# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/topology_ids'.format(context_uuid)) -# validate_topology_ids(reply) - -# def test_rest_get_topologies(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) -# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/topologies'.format(context_uuid)) -# validate_topologies(reply) - -# def test_rest_get_topology(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) -# topology_uuid = urllib.parse.quote(DEFAULT_TOPOLOGY_NAME) -# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/topology/{:s}'.format(context_uuid, topology_uuid)) -# validate_topology(reply, num_devices=3, num_links=3) - -# def test_rest_get_service_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) -# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/service_ids'.format(context_uuid)) -# validate_service_ids(reply) - -# def test_rest_get_services(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) -# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/services'.format(context_uuid)) -# validate_services(reply) - -# def test_rest_get_service(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) -# service_uuid = urllib.parse.quote(service_r1_r2_uuid, safe='') -# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/service/{:s}'.format(context_uuid, service_uuid)) -# validate_service(reply) - -# def test_rest_get_slice_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) -# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/slice_ids'.format(context_uuid)) -# #validate_slice_ids(reply) - -# def test_rest_get_slices(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) -# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/slices'.format(context_uuid)) -# #validate_slices(reply) - -# def test_rest_get_slice(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) -# slice_uuid = urllib.parse.quote(slice_r1_r3_uuid, safe='') -# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/slice/{:s}'.format(context_uuid, slice_uuid)) -# #validate_slice(reply) - -# def test_rest_get_device_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# reply = do_rest_get_request(URL_PREFIX + '/device_ids') -# validate_device_ids(reply) - -# def test_rest_get_devices(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# reply = do_rest_get_request(URL_PREFIX + '/devices') -# validate_devices(reply) - -# def test_rest_get_device(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# device_uuid = urllib.parse.quote(device_r1_uuid, safe='') -# reply = do_rest_get_request(URL_PREFIX + '/device/{:s}'.format(device_uuid)) -# validate_device(reply) - -# def test_rest_get_link_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# reply = do_rest_get_request(URL_PREFIX + '/link_ids') -# validate_link_ids(reply) - -# def test_rest_get_links(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# reply = do_rest_get_request(URL_PREFIX + '/links') -# validate_links(reply) - -# def test_rest_get_link(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# link_uuid = urllib.parse.quote(link_r1_r2_uuid, safe='') -# reply = do_rest_get_request(URL_PREFIX + '/link/{:s}'.format(link_uuid)) -# validate_link(reply) - -# def test_rest_get_connection_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) -# service_uuid = urllib.parse.quote(service_r1_r3_uuid, safe='') -# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/service/{:s}/connection_ids'.format(context_uuid, service_uuid)) -# validate_connection_ids(reply) - -# def test_rest_get_connections(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) -# service_uuid = urllib.parse.quote(service_r1_r3_uuid, safe='') -# reply = do_rest_get_request(URL_PREFIX + '/context/{:s}/service/{:s}/connections'.format(context_uuid, service_uuid)) -# validate_connections(reply) - -# def test_rest_get_connection(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# connection_uuid = urllib.parse.quote(connection_r1_r3_uuid, safe='') -# reply = do_rest_get_request(URL_PREFIX + '/connection/{:s}'.format(connection_uuid)) -# validate_connection(reply) - -# def test_rest_get_policyrule_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# reply = do_rest_get_request(URL_PREFIX + '/policyrule_ids') -# #validate_policyrule_ids(reply) - -# def test_rest_get_policyrules(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# reply = do_rest_get_request(URL_PREFIX + '/policyrules') -# #validate_policyrules(reply) - -# def test_rest_get_policyrule(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name -# policyrule_uuid_quoted = urllib.parse.quote(policyrule_uuid, safe='') -# reply = do_rest_get_request(URL_PREFIX + '/policyrule/{:s}'.format(policyrule_uuid_quoted)) -# #validate_policyrule(reply) +def test_rest_get_context(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) + reply = do_rest_get_request('/debug-api/context/{:s}'.format(context_uuid)) + validate_context(reply) + + +# ----- Topology ------------------------------------------------------------------------------------------------------- + +def test_rest_get_topology_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) + reply = do_rest_get_request('/debug-api/context/{:s}/topology_ids'.format(context_uuid)) + validate_topology_ids(reply) + +def test_rest_get_topologies(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) + reply = do_rest_get_request('/debug-api/context/{:s}/topologies'.format(context_uuid)) + validate_topologies(reply) + +def test_rest_get_topology(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) + topology_uuid = urllib.parse.quote(DEFAULT_TOPOLOGY_NAME) + reply = do_rest_get_request('/debug-api/context/{:s}/topology/{:s}'.format(context_uuid, topology_uuid)) + validate_topology(reply, num_devices=3, num_links=3) + + +# ----- Device --------------------------------------------------------------------------------------------------------- + +def test_rest_get_device_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + reply = do_rest_get_request('/debug-api/device_ids') + validate_device_ids(reply) + +def test_rest_get_devices(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + reply = do_rest_get_request('/debug-api/devices') + validate_devices(reply) + +def test_rest_get_device(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + device_uuid = urllib.parse.quote('R1', safe='') + reply = do_rest_get_request('/debug-api/device/{:s}'.format(device_uuid)) + validate_device(reply) + + +# ----- Link ----------------------------------------------------------------------------------------------------------- + +def test_rest_get_link_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + reply = do_rest_get_request('/debug-api/link_ids') + validate_link_ids(reply) + +def test_rest_get_links(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + reply = do_rest_get_request('/debug-api/links') + validate_links(reply) + +def test_rest_get_link(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + link_uuid = urllib.parse.quote('R1/502==R2/501', safe='') + reply = do_rest_get_request('/debug-api/link/{:s}'.format(link_uuid)) + validate_link(reply) + + +# ----- Service -------------------------------------------------------------------------------------------------------- + +def test_rest_get_service_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) + reply = do_rest_get_request('/debug-api/context/{:s}/service_ids'.format(context_uuid)) + validate_service_ids(reply) + +def test_rest_get_services(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) + reply = do_rest_get_request('/debug-api/context/{:s}/services'.format(context_uuid)) + validate_services(reply) + +def test_rest_get_service(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) + service_uuid = urllib.parse.quote('SVC:R1/200==R2/200', safe='') + reply = do_rest_get_request('/debug-api/context/{:s}/service/{:s}'.format(context_uuid, service_uuid)) + validate_service(reply) + + +# ----- Slice ---------------------------------------------------------------------------------------------------------- + +def test_rest_get_slice_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) + reply = do_rest_get_request('/debug-api/context/{:s}/slice_ids'.format(context_uuid)) + validate_slice_ids(reply) + +def test_rest_get_slices(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) + reply = do_rest_get_request('/debug-api/context/{:s}/slices'.format(context_uuid)) + validate_slices(reply) + +def test_rest_get_slice(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) + slice_uuid = urllib.parse.quote('SLC:R1-R2-R3', safe='') + reply = do_rest_get_request('/debug-api/context/{:s}/slice/{:s}'.format(context_uuid, slice_uuid)) + validate_slice(reply) + + +# ----- Connection ----------------------------------------------------------------------------------------------------- + +def test_rest_get_connection_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) + service_uuid = urllib.parse.quote('SVC:R1/200==R2/200', safe='') + reply = do_rest_get_request('/debug-api/context/{:s}/service/{:s}/connection_ids'.format(context_uuid, service_uuid)) + validate_connection_ids(reply) + +def test_rest_get_connections(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) + service_uuid = urllib.parse.quote('SVC:R1/200==R2/200', safe='') + reply = do_rest_get_request('/debug-api/context/{:s}/service/{:s}/connections'.format(context_uuid, service_uuid)) + validate_connections(reply) + +def test_rest_get_connection(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument + connection_uuid = urllib.parse.quote('CON:R1/200==R2/200:1', safe='') + reply = do_rest_get_request('/debug-api/connection/{:s}'.format(connection_uuid)) + validate_connection(reply) + +# ----- Policy --------------------------------------------------------------------------------------------------------- + +#def test_rest_get_policyrule_ids(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument +# reply = do_rest_get_request('/debug-api/policyrule_ids') +# validate_policyrule_ids(reply) + +#def test_rest_get_policyrules(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument +# reply = do_rest_get_request('/debug-api/policyrules') +# validate_policyrules(reply) + +#def test_rest_get_policyrule(nbi_service_rest : RestServer): # pylint: disable=redefined-outer-name, unused-argument +# policyrule_uuid_quoted = urllib.parse.quote(policyrule_uuid, safe='') +# reply = do_rest_get_request('/debug-api/policyrule/{:s}'.format(policyrule_uuid_quoted)) +# validate_policyrule(reply) + + +# ----- Cleanup Environment -------------------------------------------------------------------------------------------- + +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) -- GitLab From b49038f27e335ba82328d8fa84f7ab0ab00d85ee Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Thu, 18 Jan 2024 18:25:59 +0000 Subject: [PATCH 05/10] NBI component - L3VPN - Minor correction in imports --- src/nbi/tests/test_ietf_l3vpn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nbi/tests/test_ietf_l3vpn.py b/src/nbi/tests/test_ietf_l3vpn.py index 17f3c3e93..da9efdffd 100644 --- a/src/nbi/tests/test_ietf_l3vpn.py +++ b/src/nbi/tests/test_ietf_l3vpn.py @@ -21,7 +21,7 @@ from common.tools.descriptor.Loader import ( ) from common.tools.object_factory.Context import json_context_id from context.client.ContextClient import ContextClient -from nbi.service.rest_server import RestServer +from nbi.service.rest_server.RestServer 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_post_request, -- GitLab From 7acfd968a1302ea9c57d7e75ba72fed715ed1754 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Thu, 18 Jan 2024 18:35:39 +0000 Subject: [PATCH 06/10] NBI component - Debug API - Updated test descriptor file - Updated test --- src/nbi/tests/data/debug_api_dummy.json | 8 ++++---- src/nbi/tests/data/debug_api_dummy.txt | 6 ++++++ src/nbi/tests/test_debug_api.py | 8 ++++---- 3 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 src/nbi/tests/data/debug_api_dummy.txt diff --git a/src/nbi/tests/data/debug_api_dummy.json b/src/nbi/tests/data/debug_api_dummy.json index 2e0d75559..1b5491bfb 100644 --- a/src/nbi/tests/data/debug_api_dummy.json +++ b/src/nbi/tests/data/debug_api_dummy.json @@ -8,12 +8,12 @@ {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} ], "service_ids": [ - {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "admin"}}, - {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "admin"}}, - {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "admin"}} + {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R2/200"}}, + {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R3/200"}}, + {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R2/200==R3/200"}} ], "slice_ids": [ - {"context_id": {"context_uuid": {"uuid": "admin"}}, "slice_uuid": {"uuid": "admin"}} + {"context_id": {"context_uuid": {"uuid": "admin"}}, "slice_uuid": {"uuid": "SLC:R1-R2-R3"}} ] } ], diff --git a/src/nbi/tests/data/debug_api_dummy.txt b/src/nbi/tests/data/debug_api_dummy.txt new file mode 100644 index 000000000..bb8b1f113 --- /dev/null +++ b/src/nbi/tests/data/debug_api_dummy.txt @@ -0,0 +1,6 @@ +add: +context_client.SetService(Service(**SERVICE_R1_R2)) +context_client.SetService(Service(**SERVICE_R1_R3)) +context_client.SetService(Service(**SERVICE_R2_R3)) +context_client.SetSlice(Slice(**SLICE_R1_R3)) +context_client.SetConnection(Connection(**CONNECTION_R1_R3)) diff --git a/src/nbi/tests/test_debug_api.py b/src/nbi/tests/test_debug_api.py index 1618b3242..5af660ac3 100644 --- a/src/nbi/tests/test_debug_api.py +++ b/src/nbi/tests/test_debug_api.py @@ -53,8 +53,8 @@ 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) == 1 - assert len(response.service_ids ) == 0 - assert len(response.slice_ids ) == 0 + assert len(response.service_ids ) == 3 + assert len(response.slice_ids ) == 1 # ----- Context -------------------------------------------------------------------------------------------------------- @@ -203,8 +203,8 @@ def test_cleanup_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) == 1 - assert len(response.service_ids ) == 0 - assert len(response.slice_ids ) == 0 + assert len(response.service_ids ) == 3 + assert len(response.slice_ids ) == 1 # Load descriptors and validate the base scenario descriptor_loader = DescriptorLoader(descriptors_file=DESCRIPTOR_FILE, context_client=context_client) -- GitLab From 87e4ef0d4110f9a169324800f4d4b8ebb6e0e783 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Fri, 19 Jan 2024 17:48:50 +0000 Subject: [PATCH 07/10] Common - Tests - Mock Context: - Corrected addition/removal of topologies, services and slices to contexts - Minor cosmetic and linting improvements --- src/common/tests/MockServicerImpl_Context.py | 48 +++++++++++--------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/src/common/tests/MockServicerImpl_Context.py b/src/common/tests/MockServicerImpl_Context.py index b50b044a1..464517a76 100644 --- a/src/common/tests/MockServicerImpl_Context.py +++ b/src/common/tests/MockServicerImpl_Context.py @@ -25,12 +25,7 @@ from common.proto.context_pb2 import ( Slice, SliceEvent, SliceFilter, SliceId, SliceIdList, SliceList, Topology, TopologyDetails, TopologyEvent, TopologyId, TopologyIdList, TopologyList) from common.proto.context_pb2_grpc import ContextServiceServicer -from common.proto.policy_pb2 import ( - PolicyRule, - PolicyRuleId, - PolicyRuleIdList, - PolicyRuleList, -) +from common.proto.policy_pb2 import PolicyRule, PolicyRuleId, PolicyRuleIdList, PolicyRuleList from common.tools.grpc.Tools import grpc_message_to_json, grpc_message_to_json_string from common.tools.object_factory.Device import json_device_id from common.tools.object_factory.Link import json_link_id @@ -170,10 +165,12 @@ class MockServicerImpl_Context(ContextServiceServicer): rw_request = Topology() rw_request.CopyFrom(request) + # pylint: disable=no-member del rw_request.device_ids[:] for device_uuid in sorted(device_uuids): rw_request.device_ids.append(DeviceId(**json_device_id(device_uuid))) + # pylint: disable=no-member del rw_request.link_ids[:] for link_uuid in sorted(link_uuids): rw_request.link_ids.append(LinkId(**json_link_id(link_uuid))) @@ -187,7 +184,9 @@ class MockServicerImpl_Context(ContextServiceServicer): if _topology_id.topology_uuid.uuid == topology_uuid: break else: # topology not found, add it - context_.topology_ids.add().topology_uuid.uuid = topology_uuid + topology_id = context_.topology_ids.add() + topology_id.context_id.context_uuid.uuid = context_uuid + topology_id.topology_uuid.uuid = topology_uuid LOGGER.debug('[SetTopology] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply @@ -201,9 +200,10 @@ class MockServicerImpl_Context(ContextServiceServicer): context_ = self.obj_db.get_entry('context', context_uuid, context) for _topology_id in context_.topology_ids: - if _topology_id.topology_uuid.uuid == topology_uuid: - context_.topology_ids.remove(_topology_id) - break + if _topology_id.context_id.context_uuid.uuid != context_uuid: continue + if _topology_id.topology_uuid.uuid != topology_uuid: continue + context_.topology_ids.remove(_topology_id) + break LOGGER.debug('[RemoveTopology] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply @@ -429,7 +429,9 @@ class MockServicerImpl_Context(ContextServiceServicer): if _slice_id.slice_uuid.uuid == slice_uuid: break else: # slice not found, add it - context_.slice_ids.add().slice_uuid.uuid = slice_uuid + slice_id = context_.slice_ids.add() + slice_id.context_id.context_uuid.uuid = context_uuid + slice_id.slice_uuid.uuid = slice_uuid LOGGER.debug('[SetSlice] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply @@ -443,9 +445,10 @@ class MockServicerImpl_Context(ContextServiceServicer): context_ = self.obj_db.get_entry('context', context_uuid, context) for _slice_id in context_.slice_ids: - if _slice_id.slice_uuid.uuid == slice_uuid: - context_.slice_ids.remove(_slice_id) - break + if _slice_id.context_id.context_uuid.uuid != context_uuid: continue + if _slice_id.slice_uuid.uuid != slice_uuid: continue + context_.slice_ids.remove(_slice_id) + break LOGGER.debug('[RemoveSlice] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply @@ -521,7 +524,9 @@ class MockServicerImpl_Context(ContextServiceServicer): if _service_id.service_uuid.uuid == service_uuid: break else: # service not found, add it - context_.service_ids.add().service_uuid.uuid = service_uuid + service_id = context_.service_ids.add() + service_id.context_id.context_uuid.uuid = context_uuid + service_id.service_uuid.uuid = service_uuid LOGGER.debug('[SetService] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply @@ -535,9 +540,10 @@ class MockServicerImpl_Context(ContextServiceServicer): context_ = self.obj_db.get_entry('context', context_uuid, context) for _service_id in context_.service_ids: - if _service_id.service_uuid.uuid == service_uuid: - context_.service_ids.remove(_service_id) - break + if _service_id.context_id.context_uuid.uuid != context_uuid: continue + if _service_id.service_uuid.uuid != service_uuid: continue + context_.service_ids.remove(_service_id) + break LOGGER.debug('[RemoveService] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply @@ -622,7 +628,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[GetConnectionEvents] request={:s}'.format(grpc_message_to_json_string(request))) for message in self.msg_broker.consume({TOPIC_CONNECTION}): yield ConnectionEvent(**json.loads(message.content)) - def ListPolicyRuleIds(self, request : Empty, context : grpc.ServicerContext): + def ListPolicyRuleIds(self, request : Empty, context : grpc.ServicerContext): # pylint: disable=unused-argument LOGGER.debug('[ListPolicyRuleIds] request={:s}'.format(grpc_message_to_json_string(request))) reply = PolicyRuleIdList(policyRuleIdList=[ getattr(policy_rule, policy_rule.WhichOneof('policy_rule')).policyRuleBasic.policyRuleId @@ -631,7 +637,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[ListPolicyRuleIds] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def ListPolicyRules(self, request : Empty, context : grpc.ServicerContext): + def ListPolicyRules(self, request : Empty, context : grpc.ServicerContext): # pylint: disable=unused-argument LOGGER.debug('[ListPolicyRules] request={:s}'.format(grpc_message_to_json_string(request))) reply = PolicyRuleList(policyRules=self.obj_db.get_entries('policy')) LOGGER.debug('[ListPolicyRules] reply={:s}'.format(grpc_message_to_json_string(reply))) @@ -643,7 +649,7 @@ class MockServicerImpl_Context(ContextServiceServicer): LOGGER.debug('[GetPolicyRule] reply={:s}'.format(grpc_message_to_json_string(reply))) return reply - def SetPolicyRule(self, request : PolicyRule, context : grpc.ServicerContext): + def SetPolicyRule(self, request : PolicyRule, context : grpc.ServicerContext): # pylint: disable=unused-argument LOGGER.debug('[SetPolicyRule] request={:s}'.format(grpc_message_to_json_string(request))) policy_type = request.WhichOneof('policy_rule') policy_uuid = getattr(request, policy_type).policyRuleBasic.policyRuleId.uuid.uuid -- GitLab From 01bbcbfcbee824d8f98b55096cc5015b4ebaeda9 Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Fri, 19 Jan 2024 17:51:44 +0000 Subject: [PATCH 08/10] Common - Type Checkers: - Completed assertions for slices - Added assertions for Constraint actions - Added missing values in enums - Added assertions for non-custom constraints - Added field "name" in multiple objects - Added assertions for device components - Added assertions for link attributes - Added assertions for connection settings - Minor cosmetic improvements --- src/common/type_checkers/Assertions.py | 259 ++++++++++++++++++++++--- 1 file changed, 228 insertions(+), 31 deletions(-) diff --git a/src/common/type_checkers/Assertions.py b/src/common/type_checkers/Assertions.py index 98987f234..9d39c3c54 100644 --- a/src/common/type_checkers/Assertions.py +++ b/src/common/type_checkers/Assertions.py @@ -12,7 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -from typing import Dict +import logging +from typing import Callable, Dict + +LOGGER = logging.getLogger(__name__) # ----- Enumerations --------------------------------------------------------------------------------------------------- def validate_config_action_enum(message): @@ -23,6 +26,14 @@ def validate_config_action_enum(message): 'CONFIGACTION_DELETE', ] +def validate_constraint_action_enum(message): + assert isinstance(message, str) + assert message in [ + 'CONSTRAINTACTION_UNDEFINED', + 'CONSTRAINTACTION_SET', + 'CONSTRAINTACTION_DELETE', + ] + def validate_device_driver_enum(message): assert isinstance(message, str) assert message in [ @@ -35,6 +46,7 @@ def validate_device_driver_enum(message): 'DEVICEDRIVER_XR', 'DEVICEDRIVER_IETF_L2VPN', 'DEVICEDRIVER_GNMI_OPENCONFIG', + 'DEVICEDRIVER_FLEXSCALE', ] def validate_device_operational_status_enum(message): @@ -64,6 +76,8 @@ def validate_service_type_enum(message): 'SERVICETYPE_L3NM', 'SERVICETYPE_L2NM', 'SERVICETYPE_TAPI_CONNECTIVITY_SERVICE', + 'SERVICETYPE_TE', + 'SERVICETYPE_E2E', ] def validate_service_state_enum(message): @@ -77,6 +91,17 @@ def validate_service_state_enum(message): 'SERVICESTATUS_SLA_VIOLATED', ] +def validate_slice_status_enum(message): + assert isinstance(message, str) + assert message in [ + 'SLICESTATUS_UNDEFINED', + 'SLICESTATUS_PLANNED', + 'SLICESTATUS_INIT', + 'SLICESTATUS_ACTIVE', + 'SLICESTATUS_DEINIT', + 'SLICESTATUS_SLA_VIOLATED', + ] + # ----- Common --------------------------------------------------------------------------------------------------------- def validate_uuid(message, allow_empty=False): @@ -114,28 +139,61 @@ def validate_config_rules(message): assert 'config_rules' in message for config_rule in message['config_rules']: validate_config_rule(config_rule) -CONSTRAINT_TYPES = { - 'custom', - 'schedule', - 'endpoint_location', - 'sla_capacity', - 'sla_latency', - 'sla_availability', - 'sla_isolation', +def validate_constraint_custom(message): + assert isinstance(message, dict) + assert len(message.keys()) == 2 + assert 'constraint_type' in message + assert isinstance(message['constraint_type'], str) + assert 'constraint_value' in message + assert isinstance(message['constraint_value'], str) + +def validate_constraint_sla_capacity(message): + assert isinstance(message, dict) + assert len(message.keys()) == 1 + assert 'capacity_gbps' in message + assert isinstance(message['capacity_gbps'], (int, float)) + +def validate_constraint_sla_latency(message): + assert isinstance(message, dict) + assert len(message.keys()) == 1 + assert 'e2e_latency_ms' in message + assert isinstance(message['e2e_latency_ms'], (int, float)) + +def validate_constraint_sla_availability(message): + assert isinstance(message, dict) + assert len(message.keys()) == 3 + assert 'num_disjoint_paths' in message + assert isinstance(message['num_disjoint_paths'], int) + assert message['num_disjoint_paths'] >= 0 + assert 'all_active' in message + assert isinstance(message['all_active'], bool) + assert 'availability' in message + assert isinstance(message['availability'], (int, float)) + assert message['availability'] >= 0 and message['availability'] <= 100 + +CONSTRAINT_TYPE_TO_VALIDATOR = { + 'custom' : validate_constraint_custom, + #'schedule' : validate_constraint_schedule, + #'endpoint_location' : validate_constraint_endpoint_location, + #'endpoint_priority' : validate_constraint_endpoint_priority, + 'sla_capacity' : validate_constraint_sla_capacity, + 'sla_latency' : validate_constraint_sla_latency, + 'sla_availability' : validate_constraint_sla_availability, + #'sla_isolation' : validate_constraint_sla_isolation, + #'exclusions' : validate_constraint_exclusions, } + def validate_constraint(message): assert isinstance(message, dict) - assert len(message.keys()) == 1 - other_keys = list(message.keys()) - constraint_type = other_keys[0] - assert constraint_type in CONSTRAINT_TYPES - assert constraint_type == 'custom', 'Constraint Type Validator for {:s} not implemented'.format(constraint_type) - custom : Dict = message['custom'] - assert len(custom.keys()) == 2 - assert 'constraint_type' in custom - assert isinstance(custom['constraint_type'], str) - assert 'constraint_value' in custom - assert isinstance(custom['constraint_value'], str) + assert len(message.keys()) == 2 + assert 'action' in message + validate_constraint_action_enum(message['action']) + other_keys = set(list(message.keys())) + other_keys.discard('action') + constraint_type = other_keys.pop() + validator : Callable = CONSTRAINT_TYPE_TO_VALIDATOR.get(constraint_type) + assert validator is not None, 'Constraint Type Validator for {:s} not implemented'.format(constraint_type) + validator(message[constraint_type]) # ----- Identifiers ---------------------------------------------------------------------------------------------------- @@ -218,6 +276,13 @@ def validate_service_ids(message, context_uuid=None): assert isinstance(message['service_ids'], list) for service_id in message['service_ids']: validate_service_id(service_id, context_uuid=context_uuid) +def validate_slice_ids(message, context_uuid=None): + assert isinstance(message, dict) + assert len(message.keys()) == 1 + assert 'slice_ids' in message + assert isinstance(message['slice_ids'], list) + for slice_id in message['slice_ids']: validate_slice_id(slice_id, context_uuid=context_uuid) + def validate_topology_ids(message, context_uuid=None): assert isinstance(message, dict) assert len(message.keys()) == 1 @@ -252,17 +317,17 @@ def validate_connection_ids(message): def validate_context(message): assert isinstance(message, dict) assert len(message.keys()) == 5 - assert 'name' in message - assert isinstance(message['name'], str) assert 'context_id' in message validate_context_id(message['context_id']) context_uuid = message['context_id']['context_uuid']['uuid'] - assert 'service_ids' in message - assert isinstance(message['service_ids'], list) - for service_id in message['service_ids']: validate_service_id(service_id, context_uuid=context_uuid) + assert 'name' in message + assert isinstance(message['name'], str) assert 'topology_ids' in message assert isinstance(message['topology_ids'], list) for topology_id in message['topology_ids']: validate_topology_id(topology_id, context_uuid=context_uuid) + assert 'service_ids' in message + assert isinstance(message['service_ids'], list) + for service_id in message['service_ids']: validate_service_id(service_id, context_uuid=context_uuid) assert 'slice_ids' in message assert isinstance(message['slice_ids'], list) for slice_id in message['slice_ids']: validate_slice_id(slice_id, context_uuid=context_uuid) @@ -273,11 +338,19 @@ def validate_service_state(message): assert 'service_status' in message validate_service_state_enum(message['service_status']) +def validate_slice_status(message): + assert isinstance(message, dict) + assert len(message.keys()) == 1 + assert 'slice_status' in message + validate_slice_status_enum(message['slice_status']) + def validate_service(message): assert isinstance(message, dict) - assert len(message.keys()) == 6 + assert len(message.keys()) == 7 assert 'service_id' in message validate_service_id(message['service_id']) + assert 'name' in message + assert isinstance(message['name'], str) assert 'service_type' in message validate_service_type_enum(message['service_type']) assert 'service_endpoint_ids' in message @@ -291,11 +364,44 @@ def validate_service(message): assert 'service_config' in message validate_config_rules(message['service_config']) +def validate_slice(message): + assert isinstance(message, dict) + assert len(message.keys()) in {8, 9} + assert 'slice_id' in message + validate_slice_id(message['slice_id']) + assert 'name' in message + assert isinstance(message['name'], str) + assert 'slice_endpoint_ids' in message + assert isinstance(message['slice_endpoint_ids'], list) + for endpoint_id in message['slice_endpoint_ids']: validate_endpoint_id(endpoint_id) + assert 'slice_constraints' in message + assert isinstance(message['slice_constraints'], list) + for constraint in message['slice_constraints']: validate_constraint(constraint) + assert 'slice_service_ids' in message + assert isinstance(message['slice_service_ids'], list) + for service_id in message['slice_service_ids']: validate_service_id(service_id) + assert 'slice_subslice_ids' in message + assert isinstance(message['slice_subslice_ids'], list) + for slice_id in message['slice_subslice_ids']: validate_slice_id(slice_id) + assert 'slice_status' in message + validate_slice_status(message['slice_status']) + assert 'slice_config' in message + validate_config_rules(message['slice_config']) + if len(message.keys()) == 9: + assert 'slice_owner' in message + assert isinstance(message['slice_owner'], dict) + assert 'owner_uuid' in message['slice_owner'] + validate_uuid(message['slice_owner']['owner_uuid']) + assert 'owner_string' in message['slice_owner'] + assert isinstance(message['slice_owner']['owner_string'], str) + def validate_topology(message, num_devices=None, num_links=None): assert isinstance(message, dict) - assert len(message.keys()) == 3 + assert len(message.keys()) == 4 assert 'topology_id' in message validate_topology_id(message['topology_id']) + assert 'name' in message + assert isinstance(message['name'], str) assert 'device_ids' in message assert isinstance(message['device_ids'], list) if num_devices is not None: assert len(message['device_ids']) == num_devices @@ -307,20 +413,49 @@ def validate_topology(message, num_devices=None, num_links=None): def validate_endpoint(message): assert isinstance(message, dict) - assert len(message.keys()) == 3 + assert len(message.keys()) == 4 assert 'endpoint_id' in message validate_endpoint_id(message['endpoint_id']) + assert 'name' in message + assert isinstance(message['name'], str) assert 'endpoint_type' in message assert isinstance(message['endpoint_type'], str) assert 'kpi_sample_types' in message assert isinstance(message['kpi_sample_types'], list) for kpi_sample_type in message['kpi_sample_types']: validate_kpi_sample_types_enum(kpi_sample_type) +def validate_component(component): + assert isinstance(component, dict) + assert len(component.keys()) == 5 + assert 'component_uuid' in component + validate_uuid(component['component_uuid']) + assert 'name' in component + assert isinstance(component['name'], str) + assert 'type' in component + assert isinstance(component['type'], str) + assert 'attributes' in component + assert isinstance(component['attributes'], dict) + for k,v in component['attributes'].items(): + assert isinstance(k, str) + assert isinstance(v, str) + assert 'parent' in component + assert isinstance(component['parent'], str) + +def validate_link_attributes(link_attributes): + assert isinstance(link_attributes, dict) + assert len(link_attributes.keys()) == 2 + assert 'total_capacity_gbps' in link_attributes + assert isinstance(link_attributes['total_capacity_gbps'], (int, float)) + assert 'used_capacity_gbps' in link_attributes + assert isinstance(link_attributes['used_capacity_gbps'], (int, float)) + def validate_device(message): assert isinstance(message, dict) - assert len(message.keys()) == 6 + assert len(message.keys()) in {8, 9} assert 'device_id' in message validate_device_id(message['device_id']) + assert 'name' in message + assert isinstance(message['name'], str) assert 'device_type' in message assert isinstance(message['device_type'], str) assert 'device_config' in message @@ -333,19 +468,30 @@ def validate_device(message): assert 'device_endpoints' in message assert isinstance(message['device_endpoints'], list) for endpoint in message['device_endpoints']: validate_endpoint(endpoint) + assert 'components' in message + assert isinstance(message['components'], list) + for component in message['components']: validate_component(component) + if len(message.keys()) == 9: + assert 'controller_id' in message + if len(message['controller_id']) > 0: + validate_device_id(message['controller_id']) def validate_link(message): assert isinstance(message, dict) - assert len(message.keys()) == 2 + assert len(message.keys()) == 4 assert 'link_id' in message validate_link_id(message['link_id']) + assert 'name' in message + assert isinstance(message['name'], str) assert 'link_endpoint_ids' in message assert isinstance(message['link_endpoint_ids'], list) for endpoint_id in message['link_endpoint_ids']: validate_endpoint_id(endpoint_id) + assert 'attributes' in message + validate_link_attributes(message['attributes']) def validate_connection(message): assert isinstance(message, dict) - assert len(message.keys()) == 4 + assert len(message.keys()) in {4, 5} assert 'connection_id' in message validate_connection_id(message['connection_id']) assert 'service_id' in message @@ -356,6 +502,50 @@ def validate_connection(message): assert 'sub_service_ids' in message assert isinstance(message['sub_service_ids'], list) for sub_service_id in message['sub_service_ids']: validate_service_id(sub_service_id) + if len(message.keys()) == 5: + assert 'settings' in message + assert isinstance(message['settings'], dict) + # TODO: improve validation of data types, especially for uint values, IP/MAC addresses, TCP/UDP ports, etc. + if 'l0' in message['settings']: + assert isinstance(message['settings']['l0'], dict) + if 'lsp_symbolic_name' in message['settings']['l0']: + assert isinstance(message['settings']['l0']['lsp_symbolic_name'], str) + if 'l2' in message['settings']: + assert isinstance(message['settings']['l2'], dict) + if 'src_mac_address' in message['settings']['l2']: + assert isinstance(message['settings']['l2']['src_mac_address'], str) + if 'dst_mac_address' in message['settings']['l2']: + assert isinstance(message['settings']['l2']['dst_mac_address'], str) + if 'ether_type' in message['settings']['l2']: + assert isinstance(message['settings']['l2']['ether_type'], int) + if 'vlan_id' in message['settings']['l2']: + assert isinstance(message['settings']['l2']['vlan_id'], int) + if 'mpls_label' in message['settings']['l2']: + assert isinstance(message['settings']['l2']['mpls_label'], int) + if 'mpls_traffic_class' in message['settings']['l2']: + assert isinstance(message['settings']['l2']['mpls_traffic_class'], int) + if 'l3' in message['settings']: + assert isinstance(message['settings']['l3'], dict) + if 'src_ip_address' in message['settings']['l3']: + assert isinstance(message['settings']['l3']['src_ip_address'], str) + if 'dst_ip_address' in message['settings']['l3']: + assert isinstance(message['settings']['l3']['dst_ip_address'], str) + if 'dscp' in message['settings']['l3']: + assert isinstance(message['settings']['l3']['dscp'], int) + if 'protocol' in message['settings']['l3']: + assert isinstance(message['settings']['l3']['protocol'], int) + if 'ttl' in message['settings']['l3']: + assert isinstance(message['settings']['l3']['ttl'], int) + if 'l4' in message['settings']: + assert isinstance(message['settings']['l4'], dict) + if 'src_port' in message['settings']['l4']: + assert isinstance(message['settings']['l4']['src_port'], int) + if 'dst_port' in message['settings']['l4']: + assert isinstance(message['settings']['l4']['dst_port'], int) + if 'tcp_flags' in message['settings']['l4']: + assert isinstance(message['settings']['l4']['tcp_flags'], int) + if 'ttl' in message['settings']['l4']: + assert isinstance(message['settings']['l4']['ttl'], int) # ----- Lists of Objects ----------------------------------------------------------------------------------------------- @@ -374,6 +564,13 @@ def validate_services(message): assert isinstance(message['services'], list) for service in message['services']: validate_service(service) +def validate_slices(message): + assert isinstance(message, dict) + assert len(message.keys()) == 1 + assert 'slices' in message + assert isinstance(message['slices'], list) + for slice_ in message['slices']: validate_slice(slice_) + def validate_topologies(message): assert isinstance(message, dict) assert len(message.keys()) == 1 -- GitLab From 88805c736066106bfe90de863ec57f472da55fac Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Fri, 19 Jan 2024 17:52:59 +0000 Subject: [PATCH 09/10] NBI component - Debug API - Unitary Tests: - Completed test descriptor debug_api_dummy.json - Removed unneeded debug_api_dummy.txt file - Corrected unitary test --- src/nbi/tests/data/debug_api_dummy.json | 210 +++++++++++++++++++++++- src/nbi/tests/data/debug_api_dummy.txt | 6 - src/nbi/tests/test_debug_api.py | 18 +- 3 files changed, 218 insertions(+), 16 deletions(-) delete mode 100644 src/nbi/tests/data/debug_api_dummy.txt diff --git a/src/nbi/tests/data/debug_api_dummy.json b/src/nbi/tests/data/debug_api_dummy.json index 1b5491bfb..d8f513757 100644 --- a/src/nbi/tests/data/debug_api_dummy.json +++ b/src/nbi/tests/data/debug_api_dummy.json @@ -232,7 +232,211 @@ ] } ], - "services": [], - "slices": [], - "connections": [] + "services": [ + { + "service_id" : {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R2/200"}}, + "name": "SVC:R1/200==R2/200", "service_type": 1, "service_status": {"service_status": 1}, + "service_endpoint_ids": [ + { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ], + "service_constraints": [ + {"action": 1, "sla_capacity": {"capacity_gbps": 40.0}}, + {"action": 1, "sla_latency": {"e2e_latency_ms": 10.0}}, + {"action": 1, "sla_availability": {"num_disjoint_paths": 1, "all_active": true, "availability": 99.99}} + ], + "service_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "/device[R1]/endpoint[200]/settings", "resource_value": { + "ipv4_address": "10.0.1.1", "ipv4_prefix": 24 + }}}, + {"action": 1, "custom": {"resource_key": "/device[R2]/endpoint[200]/settings", "resource_value": { + "ipv4_address": "10.0.2.1", "ipv4_prefix": 24 + }}} + ]} + }, + { + "service_id" : {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R3/200"}}, + "name": "SVC:R1/200==R3/200", "service_type": 1, "service_status": {"service_status": 1}, + "service_endpoint_ids": [ + { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ], + "service_constraints": [ + {"action": 1, "sla_capacity": {"capacity_gbps": 50.0}}, + {"action": 1, "sla_latency": {"e2e_latency_ms": 8.0}}, + {"action": 1, "sla_availability": {"num_disjoint_paths": 1, "all_active": true, "availability": 99.9}} + ], + "service_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "/device[R1]/endpoint[200]/settings", "resource_value": { + "ipv4_address": "10.0.1.1", "ipv4_prefix": 24 + }}}, + {"action": 1, "custom": {"resource_key": "/device[R3]/endpoint[200]/settings", "resource_value": { + "ipv4_address": "10.0.3.1", "ipv4_prefix": 24 + }}} + ]} + }, + { + "service_id" : {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R2/200==R3/200"}}, + "name": "SVC:R2/200==R3/200", "service_type": 1, "service_status": {"service_status": 1}, + "service_endpoint_ids": [ + { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ], + "service_constraints": [ + {"action": 1, "sla_capacity": {"capacity_gbps": 10.0}}, + {"action": 1, "sla_latency": {"e2e_latency_ms": 3.0}}, + {"action": 1, "sla_availability": {"num_disjoint_paths": 1, "all_active": true, "availability": 99.9999}} + ], + "service_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "/device[R2]/endpoint[200]/settings", "resource_value": { + "ipv4_address": "10.0.2.1", "ipv4_prefix": 24 + }}}, + {"action": 1, "custom": {"resource_key": "/device[R3]/endpoint[200]/settings", "resource_value": { + "ipv4_address": "10.0.3.1", "ipv4_prefix": 24 + }}} + ]} + } + ], + "slices": [ + { + "slice_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "slice_uuid": {"uuid": "SLC:R1-R2-R3"}}, + "name": "SLC:R1-R2-R3", + "slice_endpoint_ids": [ + { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ], + "slice_constraints": [ + {"action": 1, "sla_capacity": {"capacity_gbps": 40.0}}, + {"action": 1, "sla_latency": {"e2e_latency_ms": 10.0}}, + {"action": 1, "sla_availability": {"num_disjoint_paths": 1, "all_active": true, "availability": 99.99}} + ], + "slice_service_ids": [ + {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R2/200"}}, + {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R3/200"}}, + {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R2/200==R3/200"}} + ], + "slice_subslice_ids": [], + "slice_status": {"slice_status" : 1}, + "slice_config": {"config_rules": [ + {"action": 1, "custom": {"resource_key": "/device[R1]/endpoint[200]/settings", "resource_value": { + "ipv4_address": "10.0.1.1", "ipv4_prefix": 24 + }}}, + {"action": 1, "custom": {"resource_key": "/device[R2]/endpoint[200]/settings", "resource_value": { + "ipv4_address": "10.0.2.1", "ipv4_prefix": 24 + }}}, + {"action": 1, "custom": {"resource_key": "/device[R3]/endpoint[200]/settings", "resource_value": { + "ipv4_address": "10.0.3.1", "ipv4_prefix": 24 + }}} + ]}, + "slice_owner": {"owner_uuid": {"uuid": "TFS"}, "owner_string": "TFS:SLC:R1-R2-R3"} + } + ], + "connections": [ + { + "connection_id": {"connection_uuid": {"uuid": "CON:R1/200==R2/200:1"}}, + "service_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R2/200"}}, + "path_hops_endpoint_ids" : [ + { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "502"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "501"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ], + "sub_service_ids": [], + "settings": { + "l3": {"src_ip_address": "10.0.1.10", "dst_ip_address": "10.0.2.10", "ttl": 20} + } + }, + { + "connection_id": {"connection_uuid": {"uuid": "CON:R1/200==R3/200:1"}}, + "service_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R1/200==R3/200"}}, + "path_hops_endpoint_ids" : [ + { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R1"}}, "endpoint_uuid": {"uuid": "503"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "501"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ], + "sub_service_ids": [], + "settings": { + "l3": {"src_ip_address": "10.0.1.10", "dst_ip_address": "10.0.3.10", "ttl": 20} + } + }, + { + "connection_id": {"connection_uuid": {"uuid": "CON:R2/200==R3/200:1"}}, + "service_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "service_uuid": {"uuid": "SVC:R2/200==R3/200"}}, + "path_hops_endpoint_ids" : [ + { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R2"}}, "endpoint_uuid": {"uuid": "503"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "502"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + }, + { + "device_id": {"device_uuid": {"uuid": "R3"}}, "endpoint_uuid": {"uuid": "200"}, + "topology_id": {"context_id": {"context_uuid": {"uuid": "admin"}}, "topology_uuid": {"uuid": "admin"}} + } + ], + "sub_service_ids": [], + "settings": { + "l3": {"src_ip_address": "10.0.2.10", "dst_ip_address": "10.0.3.10", "ttl": 20} + } + } + ] } diff --git a/src/nbi/tests/data/debug_api_dummy.txt b/src/nbi/tests/data/debug_api_dummy.txt deleted file mode 100644 index bb8b1f113..000000000 --- a/src/nbi/tests/data/debug_api_dummy.txt +++ /dev/null @@ -1,6 +0,0 @@ -add: -context_client.SetService(Service(**SERVICE_R1_R2)) -context_client.SetService(Service(**SERVICE_R1_R3)) -context_client.SetService(Service(**SERVICE_R2_R3)) -context_client.SetSlice(Slice(**SLICE_R1_R3)) -context_client.SetConnection(Connection(**CONNECTION_R1_R3)) diff --git a/src/nbi/tests/test_debug_api.py b/src/nbi/tests/test_debug_api.py index 5af660ac3..f19531eae 100644 --- a/src/nbi/tests/test_debug_api.py +++ b/src/nbi/tests/test_debug_api.py @@ -20,16 +20,20 @@ from common.tools.descriptor.Loader import ( ) from common.tools.object_factory.Context import json_context_id from common.type_checkers.Assertions import ( - validate_connection, validate_connection_ids, validate_connections, validate_context, validate_context_ids, - validate_contexts, validate_device, validate_device_ids, validate_devices, validate_link, validate_link_ids, - validate_links, validate_service, validate_service_ids, validate_services, validate_topologies, validate_topology, - validate_topology_ids) + validate_connection, validate_connection_ids, validate_connections, + validate_context, validate_context_ids, validate_contexts, + validate_device, validate_device_ids, validate_devices, + validate_link, validate_link_ids, validate_links, + validate_service, validate_service_ids, validate_services, + validate_slice, validate_slice_ids, validate_slices, + validate_topologies, validate_topology, validate_topology_ids +) from context.client.ContextClient import ContextClient from nbi.service.rest_server.RestServer 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_post_request, - mock_service, nbi_service_rest, osm_wim, context_client + mock_service, nbi_service_rest, context_client, + do_rest_get_request ) LOGGER = logging.getLogger(__name__) @@ -89,7 +93,7 @@ def test_rest_get_topology(nbi_service_rest : RestServer): # pylint: disable=red context_uuid = urllib.parse.quote(DEFAULT_CONTEXT_NAME) topology_uuid = urllib.parse.quote(DEFAULT_TOPOLOGY_NAME) reply = do_rest_get_request('/debug-api/context/{:s}/topology/{:s}'.format(context_uuid, topology_uuid)) - validate_topology(reply, num_devices=3, num_links=3) + validate_topology(reply, num_devices=3, num_links=6) # ----- Device --------------------------------------------------------------------------------------------------------- -- GitLab From 07da7f814979ce22564c473e7ae11fdb91d9776a Mon Sep 17 00:00:00 2001 From: gifrerenom Date: Fri, 19 Jan 2024 18:00:30 +0000 Subject: [PATCH 10/10] NBI component - Debug API - Unitary Tests: - Added test to GitLab CI/CD pipeline --- src/nbi/.gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nbi/.gitlab-ci.yml b/src/nbi/.gitlab-ci.yml index d9d790803..e0cac446a 100644 --- a/src/nbi/.gitlab-ci.yml +++ b/src/nbi/.gitlab-ci.yml @@ -66,6 +66,7 @@ unit_test nbi: - sleep 5 - docker ps -a - docker logs $IMAGE_NAME + - docker exec -i $IMAGE_NAME bash -c "coverage run --append -m pytest --log-level=INFO --verbose $IMAGE_NAME/tests/test_debug_api.py --junitxml=/opt/results/${IMAGE_NAME}_report_debug_api.xml" - 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" -- GitLab