diff --git a/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_Service.py b/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_Service.py index 27489410f5f0d00b74042f0f4b9da5115b82e782..17ae49478f26a2884d54f95607aafc27c809425d 100644 --- a/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_Service.py +++ b/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_Service.py @@ -17,7 +17,6 @@ from flask import request from flask.json import jsonify from flask_restful import Resource from common.Constants import DEFAULT_CONTEXT_UUID -from common.Settings import get_setting from context.client.ContextClient import ContextClient from context.proto.context_pb2 import ServiceId, SliceStatusEnum from service.client.ServiceClient import ServiceClient @@ -29,22 +28,16 @@ from .tools.HttpStatusCodes import HTTP_GATEWAYTIMEOUT, HTTP_NOCONTENT, HTTP_OK, LOGGER = logging.getLogger(__name__) class L2VPN_Service(Resource): - def __init__(self) -> None: - super().__init__() - self.context_client = ContextClient( - get_setting('CONTEXTSERVICE_SERVICE_HOST'), get_setting('CONTEXTSERVICE_SERVICE_PORT_GRPC')) - self.service_client = ServiceClient( - get_setting('SERVICESERVICE_SERVICE_HOST'), get_setting('SERVICESERVICE_SERVICE_PORT_GRPC')) - @HTTP_AUTH.login_required def get(self, vpn_id : str): LOGGER.debug('VPN_Id: {:s}'.format(str(vpn_id))) LOGGER.debug('Request: {:s}'.format(str(request))) response = jsonify({}) - try: - target = get_service(self.context_client, vpn_id) + context_client = ContextClient() + + target = get_service(context_client, vpn_id) if target is not None: if target.service_id.service_uuid.uuid != vpn_id: # pylint: disable=no-member raise Exception('Service retrieval failed. Wrong Service Id was returned') @@ -53,7 +46,7 @@ class L2VPN_Service(Resource): response.status_code = HTTP_OK if service_status == service_ready_status else HTTP_GATEWAYTIMEOUT return response - target = get_slice(self.context_client, vpn_id) + target = get_slice(context_client, vpn_id) if target is not None: if target.slice_id.slice_uuid.uuid != vpn_id: # pylint: disable=no-member raise Exception('Slice retrieval failed. Wrong Slice Id was returned') @@ -80,7 +73,8 @@ class L2VPN_Service(Resource): service_id_request.service_uuid.uuid = vpn_id try: - self.service_client.DeleteService(service_id_request) + service_client = ServiceClient() + service_client.DeleteService(service_id_request) response = jsonify({}) response.status_code = HTTP_NOCONTENT except Exception as e: # pylint: disable=broad-except diff --git a/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_Services.py b/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_Services.py index 6d39cfe2db2ccba5ca75fe6861599b8ef178a038..e0de1b7321d5618d3a7d33af4a59b47b12482e3a 100644 --- a/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_Services.py +++ b/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_Services.py @@ -19,7 +19,6 @@ from flask.json import jsonify from flask_restful import Resource from werkzeug.exceptions import UnsupportedMediaType from common.Constants import DEFAULT_CONTEXT_UUID -from common.Settings import get_setting from service.client.ServiceClient import ServiceClient from service.proto.context_pb2 import Service, ServiceStatusEnum, ServiceTypeEnum from slice.client.SliceClient import SliceClient @@ -32,13 +31,6 @@ from .tools.Validator import validate_message LOGGER = logging.getLogger(__name__) class L2VPN_Services(Resource): - def __init__(self) -> None: - super().__init__() - self.service_client = ServiceClient( - get_setting('SERVICESERVICE_SERVICE_HOST'), get_setting('SERVICESERVICE_SERVICE_PORT_GRPC')) - self.slice_client = SliceClient( - get_setting('SLICESERVICE_SERVICE_HOST'), get_setting('SLICESERVICE_SERVICE_PORT_GRPC')) - @HTTP_AUTH.login_required def get(self): return {} @@ -62,7 +54,8 @@ class L2VPN_Services(Resource): service_request.service_type = ServiceTypeEnum.SERVICETYPE_L3NM service_request.service_status.service_status = ServiceStatusEnum.SERVICESTATUS_PLANNED - service_reply = self.service_client.CreateService(service_request) + service_client = ServiceClient() + service_reply = service_client.CreateService(service_request) if service_reply != service_request.service_id: # pylint: disable=no-member raise Exception('Service creation failed. Wrong Service Id was returned') elif vpn_service_type == 'vpls': @@ -72,7 +65,8 @@ class L2VPN_Services(Resource): slice_request.slice_id.slice_uuid.uuid = vpn_service['vpn-id'] slice_request.slice_status.slice_status = SliceStatusEnum.SLICESTATUS_PLANNED - slice_reply = self.slice_client.CreateSlice(slice_request) + slice_client = SliceClient() + slice_reply = slice_client.CreateSlice(slice_request) if slice_reply != slice_request.slice_id: # pylint: disable=no-member raise Exception('Slice creation failed. Wrong Slice Id was returned') diff --git a/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_SiteNetworkAccesses.py b/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_SiteNetworkAccesses.py index 2c0245b9ae790dd91509f51d821530c589fedf9c..3e7928067daac258431cc8c5b5ccac7257e1cbb8 100644 --- a/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_SiteNetworkAccesses.py +++ b/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_SiteNetworkAccesses.py @@ -204,25 +204,20 @@ def process_list_site_network_access( return response class L2VPN_SiteNetworkAccesses(Resource): - def __init__(self) -> None: - super().__init__() - self.context_client = ContextClient( - get_setting('CONTEXTSERVICE_SERVICE_HOST'), get_setting('CONTEXTSERVICE_SERVICE_PORT_GRPC')) - self.service_client = ServiceClient( - get_setting('SERVICESERVICE_SERVICE_HOST'), get_setting('SERVICESERVICE_SERVICE_PORT_GRPC')) - self.slice_client = SliceClient( - get_setting('SLICESERVICE_SERVICE_HOST'), get_setting('SLICESERVICE_SERVICE_PORT_GRPC')) - @HTTP_AUTH.login_required def post(self, site_id : str): if not request.is_json: raise UnsupportedMediaType('JSON payload is required') LOGGER.debug('Site_Id: {:s}'.format(str(site_id))) - return process_list_site_network_access( - self.context_client, self.service_client, self.slice_client, request.json) + context_client = ContextClient() + service_client = ServiceClient() + slice_client = SliceClient() + return process_list_site_network_access(context_client, service_client, slice_client, request.json) @HTTP_AUTH.login_required def put(self, site_id : str): if not request.is_json: raise UnsupportedMediaType('JSON payload is required') LOGGER.debug('Site_Id: {:s}'.format(str(site_id))) - return process_list_site_network_access( - self.context_client, self.service_client, self.slice_client, request.json) + context_client = ContextClient() + service_client = ServiceClient() + slice_client = SliceClient() + return process_list_site_network_access(context_client, service_client, slice_client, request.json) diff --git a/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/__init__.py b/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/__init__.py index 79be6b7433a4e448febb37777cd0b310d5bf132d..c8b23bcee09bb7f16d75bde02e6f3a7f4ca66b4d 100644 --- a/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/__init__.py +++ b/src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/__init__.py @@ -21,7 +21,7 @@ from .L2VPN_Services import L2VPN_Services from .L2VPN_Service import L2VPN_Service from .L2VPN_SiteNetworkAccesses import L2VPN_SiteNetworkAccesses -URL_PREFIX = '/ietf-l2vpn-svc:l2vpn-svc' +URL_PREFIX = '/ietf-l2vpn-svc:l2vpn-svc' def _add_resource(rest_server : RestServer, resource : Resource, *urls, **kwargs): urls = [(URL_PREFIX + url) for url in urls] diff --git a/src/compute/tests/MockService_Dependencies.py b/src/compute/tests/MockService_Dependencies.py new file mode 100644 index 0000000000000000000000000000000000000000..8b0e4b3cc49d39a245b76ab5c4099f682ca4c92c --- /dev/null +++ b/src/compute/tests/MockService_Dependencies.py @@ -0,0 +1,58 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +from typing import Union +from common.Constants import ServiceNameEnum +from common.Settings import ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_GRPC, get_env_var_name +from common.tests.MockServicerImpl_Context import MockServicerImpl_Context +from common.tests.MockServicerImpl_Service import MockServicerImpl_Service +from common.tests.MockServicerImpl_Slice import MockServicerImpl_Slice +from common.tools.service.GenericGrpcService import GenericGrpcService +from context.proto.context_pb2_grpc import add_ContextServiceServicer_to_server +from service.proto.service_pb2_grpc import add_ServiceServiceServicer_to_server +from slice.proto.slice_pb2_grpc import add_SliceServiceServicer_to_server + +LOCAL_HOST = '127.0.0.1' + +SERVICE_CONTEXT = ServiceNameEnum.CONTEXT +SERVICE_SERVICE = ServiceNameEnum.SERVICE +SERVICE_SLICE = ServiceNameEnum.SLICE + +class MockService_Dependencies(GenericGrpcService): + # Mock Service implementing Context, Service and Slice to simplify unitary tests of Compute + + def __init__(self, bind_port: Union[str, int]) -> None: + super().__init__(bind_port, LOCAL_HOST, enable_health_servicer=False, cls_name='MockService') + + # pylint: disable=attribute-defined-outside-init + def install_servicers(self): + self.context_servicer = MockServicerImpl_Context() + add_ContextServiceServicer_to_server(self.context_servicer, self.server) + + self.service_servicer = MockServicerImpl_Service() + add_ServiceServiceServicer_to_server(self.service_servicer, self.server) + + self.slice_servicer = MockServicerImpl_Slice() + add_SliceServiceServicer_to_server(self.slice_servicer, self.server) + + def configure_env_vars(self): + os.environ[get_env_var_name(SERVICE_CONTEXT, ENVVAR_SUFIX_SERVICE_HOST )] = str(self.bind_address) + os.environ[get_env_var_name(SERVICE_CONTEXT, ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(self.bind_port) + + os.environ[get_env_var_name(SERVICE_SERVICE, ENVVAR_SUFIX_SERVICE_HOST )] = str(self.bind_address) + os.environ[get_env_var_name(SERVICE_SERVICE, ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(self.bind_port) + + os.environ[get_env_var_name(SERVICE_SLICE, ENVVAR_SUFIX_SERVICE_HOST )] = str(self.bind_address) + os.environ[get_env_var_name(SERVICE_SLICE, ENVVAR_SUFIX_SERVICE_PORT_GRPC)] = str(self.bind_port) diff --git a/src/compute/tests/PrepareTestScenario.py b/src/compute/tests/PrepareTestScenario.py new file mode 100644 index 0000000000000000000000000000000000000000..d534a4a28280c80964096a9cb7291c498ebe6b93 --- /dev/null +++ b/src/compute/tests/PrepareTestScenario.py @@ -0,0 +1,52 @@ +# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/) +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os, pytest, time +from common.Constants import ServiceNameEnum +from common.Settings import ( + ENVVAR_SUFIX_SERVICE_HOST, ENVVAR_SUFIX_SERVICE_PORT_HTTP, get_env_var_name, get_service_port_http) +from compute.service.rest_server.RestServer import RestServer +from compute.service.rest_server.nbi_plugins.ietf_l2vpn import register_ietf_l2vpn +from compute.tests.MockService_Dependencies import MockService_Dependencies +from .mock_osm.MockOSM import MockOSM +from .Constants import WIM_MAPPING, WIM_USERNAME, WIM_PASSWORD + +LOCAL_HOST = '127.0.0.1' +MOCKSERVICE_PORT = 10000 +COMPUTE_SERVICE_PORT = MOCKSERVICE_PORT + get_service_port_http(ServiceNameEnum.COMPUTE) # avoid privileged ports +os.environ[get_env_var_name(ServiceNameEnum.COMPUTE, ENVVAR_SUFIX_SERVICE_HOST )] = str(LOCAL_HOST) +os.environ[get_env_var_name(ServiceNameEnum.COMPUTE, ENVVAR_SUFIX_SERVICE_PORT_HTTP)] = str(COMPUTE_SERVICE_PORT) + +@pytest.fixture(scope='session') +def mock_service(): + _service = MockService_Dependencies(MOCKSERVICE_PORT) + _service.configure_env_vars() + _service.start() + yield _service + _service.stop() + +@pytest.fixture(scope='session') +def compute_service_rest(mock_service): # pylint: disable=redefined-outer-name + _rest_server = RestServer() + register_ietf_l2vpn(_rest_server) + _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 osm_wim(compute_service_rest): # pylint: disable=redefined-outer-name + wim_url = 'http://{:s}:{:d}'.format(LOCAL_HOST, COMPUTE_SERVICE_PORT) + return MockOSM(wim_url, WIM_MAPPING, WIM_USERNAME, WIM_PASSWORD) diff --git a/src/compute/tests/test_unitary.py b/src/compute/tests/test_unitary.py index 1fbc74ecc7fc49129b789ba99af7276a94bd662e..05c45c1b3554d21084a4a20cac6856b049fe7ca3 100644 --- a/src/compute/tests/test_unitary.py +++ b/src/compute/tests/test_unitary.py @@ -12,75 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -import logging, os, pytest, time -from common.tests.MockService import MockService -from common.tests.MockServicerImpl_Context import MockServicerImpl_Context -from common.tests.MockServicerImpl_Service import MockServicerImpl_Service -from common.tests.MockServicerImpl_Slice import MockServicerImpl_Slice -from compute.Config import RESTAPI_SERVICE_PORT, RESTAPI_BASE_URL -from compute.service.rest_server.RestServer import RestServer -from context.proto.context_pb2_grpc import add_ContextServiceServicer_to_server -from service.proto.service_pb2_grpc import add_ServiceServiceServicer_to_server -from slice.proto.slice_pb2_grpc import add_SliceServiceServicer_to_server +import logging from .mock_osm.MockOSM import MockOSM -from .Constants import ( - SERVICE_CONNECTION_POINTS_1, SERVICE_CONNECTION_POINTS_2, SERVICE_TYPE, WIM_MAPPING, WIM_USERNAME, WIM_PASSWORD) +from .Constants import SERVICE_CONNECTION_POINTS_1, SERVICE_CONNECTION_POINTS_2, SERVICE_TYPE +from .PrepareTestScenario import ( # pylint: disable=unused-import + # be careful, order of symbols is important here! + mock_service, compute_service_rest, osm_wim) LOGGER = logging.getLogger(__name__) LOGGER.setLevel(logging.DEBUG) -LOCALHOST = '127.0.0.1' -MOCKSERVER_GRPC_PORT = 10000 -COMPUTE_RESTAPI_PORT = 10000 + RESTAPI_SERVICE_PORT # avoid privileged ports - -class MockService_ContextService(MockService): - # Mock Server implementing Context and Service to simplify unitary tests of Compute - - def __init__(self, cls_name='MockService_Service'): - super().__init__(LOCALHOST, MOCKSERVER_GRPC_PORT, cls_name=cls_name) - - # pylint: disable=attribute-defined-outside-init - def install_servicers(self): - self.context_servicer = MockServicerImpl_Context() - add_ContextServiceServicer_to_server(self.context_servicer, self.server) - self.service_servicer = MockServicerImpl_Service() - add_ServiceServiceServicer_to_server(self.service_servicer, self.server) - self.slice_servicer = MockServicerImpl_Slice() - add_SliceServiceServicer_to_server(self.slice_servicer, self.server) - -os.environ['CONTEXTSERVICE_SERVICE_HOST'] = LOCALHOST -os.environ['CONTEXTSERVICE_SERVICE_PORT_GRPC'] = str(MOCKSERVER_GRPC_PORT) -os.environ['SERVICESERVICE_SERVICE_HOST'] = LOCALHOST -os.environ['SERVICESERVICE_SERVICE_PORT_GRPC'] = str(MOCKSERVER_GRPC_PORT) -os.environ['SLICESERVICE_SERVICE_HOST'] = LOCALHOST -os.environ['SLICESERVICE_SERVICE_PORT_GRPC'] = str(MOCKSERVER_GRPC_PORT) - -# NBI Plugin IETF L2VPN requires environment variables CONTEXTSERVICE_SERVICE_HOST, CONTEXTSERVICE_SERVICE_PORT_GRPC, -# SERVICESERVICE_SERVICE_HOST, and SERVICESERVICE_SERVICE_PORT_GRPC to work properly. -# pylint: disable=wrong-import-position,ungrouped-imports -from compute.service.rest_server.nbi_plugins.ietf_l2vpn import register_ietf_l2vpn - -@pytest.fixture(scope='session') -def mockservice(): - _service = MockService_ContextService() - _service.start() - yield _service - _service.stop() - -@pytest.fixture(scope='session') -def compute_service_rest(mockservice): # pylint: disable=redefined-outer-name - _rest_server = RestServer(port=COMPUTE_RESTAPI_PORT, base_url=RESTAPI_BASE_URL) - register_ietf_l2vpn(_rest_server) - _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 osm_wim(compute_service_rest): # pylint: disable=redefined-outer-name - wim_url = 'http://{:s}:{:d}'.format(LOCALHOST, COMPUTE_RESTAPI_PORT) - return MockOSM(wim_url, WIM_MAPPING, WIM_USERNAME, WIM_PASSWORD) def test_compute_create_connectivity_service_rest_api(osm_wim : MockOSM): # pylint: disable=redefined-outer-name osm_wim.create_connectivity_service(SERVICE_TYPE, SERVICE_CONNECTION_POINTS_1)