From efcb4528362460aa2249d319c9752b63bb720fe2 Mon Sep 17 00:00:00 2001 From: ss412g Date: Mon, 2 Dec 2019 16:59:19 +0200 Subject: [PATCH] Copy latest code Change-Id: Ibfcfce723adc532458911ec1df798fcd511fddaa Signed-off-by: ss412g --- .gitignore | 1 + Automation/Dockerfile | 1 + .../ConfigurationUpdate_Verify_logs.robot | 60 --- .../ConfigurationUpdate_prepartations_tests.robot | 33 +- .../E2Term_Init_Message_Test.robot | 37 ++ .../Tests/E2Term_Initialization/__init__.robot | 20 + .../Tests/ENDC-Setup/ENDC_Setup_request_test.robot | 5 +- .../ENDC_Reset_RAN_TO_RIC/Reset_RAN_Found.robot | 46 +- .../ENDC_Reset_RAN_TO_RIC/Reset_Verify_logs.robot | 54 --- .../Reset_Happy_no_cause.robot | 7 +- .../Reset_Happy_with_cause.robot | 7 +- Automation/Tests/KeepAlive/__init__.robot | 20 + Automation/Tests/KeepAlive/keep_alive_test.robot | 43 ++ ...Loadinformation_adding_data_and_overwrite.robot | 2 +- ...Lost_Connetion_CONNECTING_TO_DISCONNECTED.robot | 2 +- .../Tests/RSM_Resource_Status/__init__.robot | 20 + .../resource_status_false_start.robot | 56 +++ .../resource_status_false_stop.robot | 56 +++ .../resource_status_keywords.robot | 36 ++ .../resource_status_true_start.robot | 54 +++ .../resource_status_true_stop.robot | 54 +++ .../RedButton_CONNECTED_SHUTDOWN_CONNECTED.robot | 9 +- .../Tests/RedButton/RedButton_DISCONNECTED.robot | 2 +- Automation/Tests/Resource/Keywords.robot | 60 +++ Automation/Tests/Resource/resource.robot | 27 +- Automation/Tests/Resource/scripts_variables.robot | 7 +- Automation/Tests/Scripts/cleanup_db.py | 21 + Automation/Tests/Scripts/e2mdbscripts.py | 49 ++ Automation/Tests/Scripts/e2t_db_script.py | 58 +++ Automation/Tests/Scripts/find_rmr_message.py | 8 +- Automation/Tests/Scripts/getnodes.py | 3 +- Automation/Tests/Scripts/loadscripts.py | 23 +- Automation/Tests/Scripts/rsmscripts.py | 97 ++++ .../Unhappy/Reset_HttpResponse400_wrongstate.robot | 2 +- .../Tests/X2-Setup/X2_Setup_reuqest_test.robot | 13 + .../x2_setup_existing_assoc_test.robot} | 50 +- .../x2_setup_existing_not_assoc_test.robot | 71 +++ .../X2_Reset_RAN_TO_RIC/Reset_RAN_Found.robot | 29 +- .../X2_Reset_RAN_TO_RIC_Unhappy/Reset_RNIB.robot | 32 +- .../Reset_Verify_logs.robot | 56 --- .../X2_Reset_RIC_TO_RAN/Reset_Happy_no_cause.robot | 7 +- .../Reset_Happy_with_cause.robot | 7 +- E2Manager/Dockerfile | 13 +- E2Manager/app/main.go | 40 +- E2Manager/clients/http_client.go | 30 ++ E2Manager/clients/routing_manager_client.go | 108 +++++ E2Manager/clients/routing_manager_client_test.go | 180 +++++++ E2Manager/configuration/configuration.go | 49 +- E2Manager/configuration/configuration_test.go | 41 +- E2Manager/container-tag.yaml | 2 +- E2Manager/controllers/e2t_controller.go | 121 +++++ E2Manager/controllers/nodeb_controller.go | 7 +- E2Manager/controllers/nodeb_controller_test.go | 106 +++-- E2Manager/controllers/root_controller_test.go | 13 +- ...go => endc_setup_failure_response_converter.go} | 20 +- ... endc_setup_failure_response_converter_test.go} | 5 +- ...rotobuf.go => endc_setup_response_converter.go} | 33 +- ...st.go => endc_setup_response_converter_test.go} | 5 +- .../e2managererrors/e2t_instance_absence_error.go | 35 ++ E2Manager/e2managererrors/routing_manager_error.go | 29 ++ E2Manager/e2mgr-sonar-scanner.properties | 14 + E2Manager/e2pdus/configuration_update.go | 107 +++++ E2Manager/e2pdus/configuration_update_test.go | 165 +++++++ E2Manager/e2pdus/x2_setup_requests_test.go | 70 --- E2Manager/go.mod | 32 +- E2Manager/go.sum | 59 ++- .../delete_all_request_handler_test.go | 26 +- .../get_e2t_instances_request_handler.go | 54 +++ .../get_e2t_instances_request_handler_test.go | 75 +++ .../get_nodeb_id_list_request_handler_test.go | 7 +- .../get_nodeb_request_handler_test.go | 6 +- .../httpmsghandlers/setup_request_handler.go | 155 ++++-- .../httpmsghandlers/setup_request_handler_test.go | 518 ++++++++++++--------- .../httpmsghandlers/x2_reset_request_handler.go | 4 +- .../x2_reset_request_handler_test.go | 28 +- .../e2_term_init_notification_handler.go | 80 +++- .../e2_term_init_notification_handler_test.go | 432 ++++++++++++++--- .../e2t_keep_alive_response_handler.go | 51 ++ .../e2t_keep_alive_response_handler_test.go | 59 +++ .../enb_load_information_notification_handler.go | 19 +- ...b_load_information_notification_handler_test.go | 4 +- .../endc_configuration_update_handler.go | 41 +- .../endc_configuration_update_handler_test.go | 22 +- .../rmrmsghandlers/notification_handler.go | 7 - .../setup_response_notification_handler_test.go | 30 +- .../x2_reset_request_notification_handler.go | 22 +- .../x2_reset_request_notification_handler_test.go | 43 +- .../rmrmsghandlers/x2_reset_response_handler.go | 2 +- .../x2_reset_response_handler_test.go | 42 +- .../x2enb_configuration_update_handler.go | 35 +- .../x2enb_configuration_update_handler_test.go | 23 +- E2Manager/httpserver/http_server.go | 16 +- E2Manager/httpserver/http_server_test.go | 89 ++-- E2Manager/logger/logger_test.go | 66 ++- E2Manager/managers/e2t_instances_manager.go | 359 ++++++++++++++ E2Manager/managers/e2t_instances_manager_test.go | 459 ++++++++++++++++++ E2Manager/managers/e2t_keep_alive_worker.go | 85 ++++ E2Manager/managers/e2t_keep_alive_worker_test.go | 198 ++++++++ E2Manager/managers/e2t_shutdown_manager.go | 48 ++ .../endc_setup_failure_response_manager.go | 13 +- .../endc_setup_failure_response_manager_test.go | 66 +++ E2Manager/managers/endc_setup_response_manager.go | 13 +- .../managers/endc_setup_response_manager_test.go | 59 +++ .../notificationmanager/notification_manager.go | 2 +- .../notification_manager_test.go | 26 +- E2Manager/managers/ran_reconnection_manager.go | 65 ++- .../managers/ran_reconnection_manager_test.go | 78 +++- E2Manager/managers/ran_setup_manager.go | 7 +- E2Manager/managers/ran_setup_manager_test.go | 24 +- E2Manager/managers/ran_status_change_manager.go | 3 +- .../managers/ran_status_change_manager_test.go | 2 +- .../x2_setup_failure_response_manager_test.go | 57 +++ E2Manager/mocks/controllerMock.go | 58 --- E2Manager/mocks/e2t_controller_mock.go | 35 ++ E2Manager/mocks/e2t_instances_manager_mock.go | 82 ++++ .../e2t_shutdown_manager_mock.go} | 21 +- E2Manager/mocks/http_client_mock.go | 41 ++ E2Manager/mocks/nodebControllerMock.go | 35 -- E2Manager/mocks/nodeb_controller_mock.go | 73 +++ E2Manager/mocks/ran_setup_manager_mock.go | 31 ++ E2Manager/mocks/rmrMessengerMock.go | 8 +- E2Manager/mocks/rnibReaderMock.go | 23 +- E2Manager/mocks/rnibWriterMock.go | 12 + E2Manager/mocks/root_controller_mock.go | 31 ++ E2Manager/mocks/routing_manager_client_mock.go | 46 ++ E2Manager/models/e2_request_message_test.go | 11 +- E2Manager/models/e2_term_init_payload.go | 22 + E2Manager/models/e2t_keep_alive_payload.go | 21 + E2Manager/models/get_e2t_instances_response.go | 49 ++ E2Manager/models/get_nodeb_id_list_response.go | 6 +- E2Manager/models/get_nodeb_response.go | 6 +- E2Manager/models/i_response.go | 2 +- E2Manager/models/notification_request.go | 4 +- E2Manager/models/rmr_message.go | 12 +- E2Manager/models/routing_manager_e2t_data.go | 41 ++ .../incoming_request_handler_provider.go | 32 +- .../incoming_request_handler_provider_test.go | 17 +- .../notification_handler_provider.go | 73 ++- .../notification_handler_provider_test.go | 61 +-- E2Manager/rNibWriter/rNibWriter.go | 107 +++-- E2Manager/rNibWriter/rNibWriter_test.go | 292 +++++------- E2Manager/resources/configuration.yaml | 4 + E2Manager/rmrCgo/rmrCgoApi.go | 36 +- E2Manager/rmrCgo/rmrCgoApi_test.go | 165 ++++--- E2Manager/rmrCgo/rmrCgoTypes.go | 7 +- E2Manager/rnibBuilders/node_info_builder_test.go | 46 -- E2Manager/router.txt | 1 + E2Manager/router_test.txt | 3 + E2Manager/services/rmrreceiver/rmr_receiver.go | 11 +- .../services/rmrreceiver/rmr_receiver_test.go | 28 +- E2Manager/services/rmrsender/rmr_sender.go | 22 +- E2Manager/services/rmrsender/rmr_sender_test.go | 24 +- E2Manager/services/rnib_data_service.go | 151 +++++- E2Manager/services/rnib_data_service_test.go | 53 ++- E2Manager/tests/dataProvider.go | 2 +- E2Manager/tests/utils.go | 59 +++ Swagger/E2Manager_API.yaml | 46 +- docs/release-notes.rst | 4 +- tools/RoutingManagerSimulator/Dockerfile | 34 ++ tools/RoutingManagerSimulator/api/swagger.yaml | 363 +++++++++++++++ .../configuration/configuration.go | 57 +++ .../configuration/configuration_test.go | 76 +++ tools/RoutingManagerSimulator/go.mod | 13 + tools/RoutingManagerSimulator/go.sum | 174 +++++++ tools/RoutingManagerSimulator/go/api_handle.go | 79 ++++ tools/RoutingManagerSimulator/go/api_health.go | 38 ++ tools/RoutingManagerSimulator/go/logger.go | 64 +++ tools/RoutingManagerSimulator/go/model_e2t_data.go | 36 ++ .../go/model_e2t_delete_data.go | 38 ++ .../go/model_health_status.go | 34 ++ .../go/model_ran_e2t_element.go | 36 ++ .../go/model_ran_e2t_map.go | 32 ++ .../go/model_ran_namelist.go | 32 ++ .../go/model_xapp_callback_data.go | 40 ++ .../go/model_xapp_element.go | 36 ++ .../RoutingManagerSimulator/go/model_xapp_list.go | 32 ++ .../go/model_xapp_subscription_data.go | 38 ++ tools/RoutingManagerSimulator/go/routers.go | 146 ++++++ tools/RoutingManagerSimulator/main.go | 49 ++ .../resources/configuration.yaml | 2 + tools/xapp_mock/configuration.json | 4 - tools/xapp_mock/main/xapp_mock.go | 112 ----- tools/xapp_mock/resources/router.txt | 4 - tools/{xapp_mock => xappmock}/Dockerfile | 23 +- tools/xappmock/dispatcher/dispatcher.go | 384 +++++++++++++++ tools/xappmock/enums/command_action.go | 25 + .../{xapp_mock => xappmock}/frontend/configfile.go | 2 +- .../frontend/jsonDecoder.go | 46 +- tools/xappmock/go.mod | 9 + tools/xappmock/go.sum | 57 +++ tools/xappmock/logger/logger.go | 184 ++++++++ tools/xappmock/main/xappmock.go | 115 +++++ tools/xappmock/models/json_command.go | 35 ++ tools/xappmock/models/message_info.go | 48 ++ tools/xappmock/models/process_result.go | 43 ++ tools/xappmock/resources/conf/configuration.json | 75 +++ tools/xappmock/resources/router.txt | 29 ++ tools/{xapp_mock => xappmock}/resp | 0 tools/{xapp_mock => xappmock}/rmr/rmrCgoApi.go | 13 +- tools/{xapp_mock => xappmock}/rmr/rmrCgoTypes.go | 10 +- tools/{xapp_mock => xappmock}/rmr/rmrCgoUtils.go | 24 +- tools/{xapp_mock => xappmock}/rmr/rmrEndPoint.go | 32 +- tools/{xapp_mock => xappmock}/sender/jsonSender.go | 58 ++- 203 files changed, 8729 insertions(+), 2015 deletions(-) delete mode 100644 Automation/Tests/ConfigurationUpdate/ConfigurationUpdate_Verify_logs.robot create mode 100644 Automation/Tests/E2Term_Initialization/E2Term_Init_Message_Test.robot create mode 100755 Automation/Tests/E2Term_Initialization/__init__.robot delete mode 100644 Automation/Tests/ENDC_Reset_RAN_TO_RIC/Reset_Verify_logs.robot create mode 100755 Automation/Tests/KeepAlive/__init__.robot create mode 100644 Automation/Tests/KeepAlive/keep_alive_test.robot create mode 100755 Automation/Tests/RSM_Resource_Status/__init__.robot create mode 100644 Automation/Tests/RSM_Resource_Status/resource_status_false_start.robot create mode 100644 Automation/Tests/RSM_Resource_Status/resource_status_false_stop.robot create mode 100644 Automation/Tests/RSM_Resource_Status/resource_status_keywords.robot create mode 100644 Automation/Tests/RSM_Resource_Status/resource_status_true_start.robot create mode 100644 Automation/Tests/RSM_Resource_Status/resource_status_true_stop.robot create mode 100644 Automation/Tests/Scripts/e2mdbscripts.py create mode 100644 Automation/Tests/Scripts/e2t_db_script.py create mode 100644 Automation/Tests/Scripts/rsmscripts.py rename Automation/Tests/{X2_Reset_RAN_TO_RIC/Reset_Verify_logs.robot => X2-Setup/x2_setup_existing_assoc_test.robot} (55%) create mode 100644 Automation/Tests/X2-Setup/x2_setup_existing_not_assoc_test.robot delete mode 100644 Automation/Tests/X2_Reset_RAN_TO_RIC_Unhappy/Reset_Verify_logs.robot create mode 100644 E2Manager/clients/http_client.go create mode 100644 E2Manager/clients/routing_manager_client.go create mode 100644 E2Manager/clients/routing_manager_client_test.go create mode 100644 E2Manager/controllers/e2t_controller.go rename E2Manager/converters/{endc_x2setupFailureResponseToProtobuf.go => endc_setup_failure_response_converter.go} (82%) rename E2Manager/converters/{endc_x2setupFailureResponseToProtobuf_test.go => endc_setup_failure_response_converter_test.go} (93%) rename E2Manager/converters/{endc_x2setupResponseToProtobuf.go => endc_setup_response_converter.go} (93%) rename E2Manager/converters/{endc_x2setupResponseToProtobuf_test.go => endc_setup_response_converter_test.go} (99%) create mode 100644 E2Manager/e2managererrors/e2t_instance_absence_error.go create mode 100644 E2Manager/e2managererrors/routing_manager_error.go create mode 100644 E2Manager/e2mgr-sonar-scanner.properties create mode 100644 E2Manager/e2pdus/configuration_update.go create mode 100644 E2Manager/e2pdus/configuration_update_test.go create mode 100644 E2Manager/handlers/httpmsghandlers/get_e2t_instances_request_handler.go create mode 100644 E2Manager/handlers/httpmsghandlers/get_e2t_instances_request_handler_test.go create mode 100644 E2Manager/handlers/rmrmsghandlers/e2t_keep_alive_response_handler.go create mode 100644 E2Manager/handlers/rmrmsghandlers/e2t_keep_alive_response_handler_test.go create mode 100644 E2Manager/managers/e2t_instances_manager.go create mode 100644 E2Manager/managers/e2t_instances_manager_test.go create mode 100644 E2Manager/managers/e2t_keep_alive_worker.go create mode 100644 E2Manager/managers/e2t_keep_alive_worker_test.go create mode 100644 E2Manager/managers/e2t_shutdown_manager.go create mode 100644 E2Manager/managers/endc_setup_failure_response_manager_test.go create mode 100644 E2Manager/managers/endc_setup_response_manager_test.go create mode 100644 E2Manager/managers/x2_setup_failure_response_manager_test.go delete mode 100644 E2Manager/mocks/controllerMock.go create mode 100644 E2Manager/mocks/e2t_controller_mock.go create mode 100644 E2Manager/mocks/e2t_instances_manager_mock.go rename E2Manager/{rnibBuilders/node_info_builder.go => mocks/e2t_shutdown_manager_mock.go} (56%) create mode 100644 E2Manager/mocks/http_client_mock.go delete mode 100644 E2Manager/mocks/nodebControllerMock.go create mode 100644 E2Manager/mocks/nodeb_controller_mock.go create mode 100644 E2Manager/mocks/ran_setup_manager_mock.go create mode 100644 E2Manager/mocks/root_controller_mock.go create mode 100644 E2Manager/mocks/routing_manager_client_mock.go create mode 100644 E2Manager/models/e2_term_init_payload.go create mode 100644 E2Manager/models/e2t_keep_alive_payload.go create mode 100644 E2Manager/models/get_e2t_instances_response.go create mode 100644 E2Manager/models/routing_manager_e2t_data.go delete mode 100644 E2Manager/rnibBuilders/node_info_builder_test.go create mode 100644 E2Manager/router_test.txt create mode 100644 E2Manager/tests/utils.go create mode 100644 tools/RoutingManagerSimulator/Dockerfile create mode 100755 tools/RoutingManagerSimulator/api/swagger.yaml create mode 100644 tools/RoutingManagerSimulator/configuration/configuration.go create mode 100644 tools/RoutingManagerSimulator/configuration/configuration_test.go create mode 100644 tools/RoutingManagerSimulator/go.mod create mode 100644 tools/RoutingManagerSimulator/go.sum create mode 100755 tools/RoutingManagerSimulator/go/api_handle.go create mode 100755 tools/RoutingManagerSimulator/go/api_health.go create mode 100755 tools/RoutingManagerSimulator/go/logger.go create mode 100755 tools/RoutingManagerSimulator/go/model_e2t_data.go create mode 100755 tools/RoutingManagerSimulator/go/model_e2t_delete_data.go create mode 100755 tools/RoutingManagerSimulator/go/model_health_status.go create mode 100755 tools/RoutingManagerSimulator/go/model_ran_e2t_element.go create mode 100755 tools/RoutingManagerSimulator/go/model_ran_e2t_map.go create mode 100755 tools/RoutingManagerSimulator/go/model_ran_namelist.go create mode 100755 tools/RoutingManagerSimulator/go/model_xapp_callback_data.go create mode 100755 tools/RoutingManagerSimulator/go/model_xapp_element.go create mode 100755 tools/RoutingManagerSimulator/go/model_xapp_list.go create mode 100755 tools/RoutingManagerSimulator/go/model_xapp_subscription_data.go create mode 100755 tools/RoutingManagerSimulator/go/routers.go create mode 100755 tools/RoutingManagerSimulator/main.go create mode 100644 tools/RoutingManagerSimulator/resources/configuration.yaml delete mode 100644 tools/xapp_mock/configuration.json delete mode 100644 tools/xapp_mock/main/xapp_mock.go delete mode 100644 tools/xapp_mock/resources/router.txt rename tools/{xapp_mock => xappmock}/Dockerfile (68%) create mode 100644 tools/xappmock/dispatcher/dispatcher.go create mode 100644 tools/xappmock/enums/command_action.go rename tools/{xapp_mock => xappmock}/frontend/configfile.go (92%) rename tools/{xapp_mock => xappmock}/frontend/jsonDecoder.go (60%) create mode 100644 tools/xappmock/go.mod create mode 100644 tools/xappmock/go.sum create mode 100644 tools/xappmock/logger/logger.go create mode 100644 tools/xappmock/main/xappmock.go create mode 100644 tools/xappmock/models/json_command.go create mode 100644 tools/xappmock/models/message_info.go create mode 100644 tools/xappmock/models/process_result.go create mode 100644 tools/xappmock/resources/conf/configuration.json create mode 100644 tools/xappmock/resources/router.txt rename tools/{xapp_mock => xappmock}/resp (100%) rename tools/{xapp_mock => xappmock}/rmr/rmrCgoApi.go (92%) rename tools/{xapp_mock => xappmock}/rmr/rmrCgoTypes.go (97%) rename tools/{xapp_mock => xappmock}/rmr/rmrCgoUtils.go (83%) rename tools/{xapp_mock => xappmock}/rmr/rmrEndPoint.go (65%) rename tools/{xapp_mock => xappmock}/sender/jsonSender.go (69%) diff --git a/.gitignore b/.gitignore index 53691a3..0baa305 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ __pycache__/ # documentation .tox docs/_build/ +/.gitreview diff --git a/Automation/Dockerfile b/Automation/Dockerfile index 6733a6b..e981b44 100755 --- a/Automation/Dockerfile +++ b/Automation/Dockerfile @@ -3,6 +3,7 @@ FROM python:3.6 RUN python3 -m pip install robotframework \ && pip install --upgrade RESTinstance \ && pip install docker \ + && pip install -U robotframework-requests\ && apt-get update WORKDIR /opt diff --git a/Automation/Tests/ConfigurationUpdate/ConfigurationUpdate_Verify_logs.robot b/Automation/Tests/ConfigurationUpdate/ConfigurationUpdate_Verify_logs.robot deleted file mode 100644 index 5e2933e..0000000 --- a/Automation/Tests/ConfigurationUpdate/ConfigurationUpdate_Verify_logs.robot +++ /dev/null @@ -1,60 +0,0 @@ -############################################################################## -# -# Copyright (c) 2019 AT&T Intellectual Property. -# -# 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. -# -############################################################################## -# -# This source code is part of the near-RT RIC (RAN Intelligent Controller) -# platform project (RICP). -# - - -*** Settings *** -Resource ../Resource/resource.robot -Resource ../Resource/scripts_variables.robot -Library String -Library OperatingSystem -Library Process -Library ../Scripts/find_rmr_message.py - - - -*** Test Cases *** -Verify logs - Confiugration update - Begin Tag Get - ${Configuration}= Grep File ./gnb.log - ${ConfigurationAfterStrip}= Strip String ${Configuration} - Should Be Equal ${ConfigurationAfterStrip} - -Verify logs - Confiugration update - End Tag Get - ${ConfigurationEnd}= Grep File ./gnb.log - ${ConfigurationEndAfterStrip}= Strip String ${ConfigurationEnd} - Should Be Equal ${ConfigurationEndAfterStrip} - -Verify logs - Confiugration update - Ack Tag Begin - ${ConfigurationAck}= Grep File ./gnb.log - ${ConfigurationAckAfter}= Strip String ${ConfigurationAck} - Should Be Equal ${ConfigurationAckAfter} - -Verify logs - Confiugration update - Ack Tag End - ${ConfigurationAckEnd}= Grep File ./gnb.log - ${ConfigurationAckEndAfterStrip}= Strip String ${ConfigurationAckEnd} - Should Be Equal ${ConfigurationAckEndAfterStrip} - -Verify logs - find RIC_ENDC_CONF_UPDATE - ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${configurationupdate_message_type} ${Meid_test1} - Should Be Equal As Strings ${result} True -Verify logs - find RIC_ENDC_CONF_UPDATE_ACK - ${result1} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${configurationupdate_ack_message_type} ${Meid_test1} - Should Be Equal As Strings ${result1} True diff --git a/Automation/Tests/ConfigurationUpdate/ConfigurationUpdate_prepartations_tests.robot b/Automation/Tests/ConfigurationUpdate/ConfigurationUpdate_prepartations_tests.robot index a2b741a..f833a3e 100644 --- a/Automation/Tests/ConfigurationUpdate/ConfigurationUpdate_prepartations_tests.robot +++ b/Automation/Tests/ConfigurationUpdate/ConfigurationUpdate_prepartations_tests.robot @@ -27,7 +27,10 @@ Resource ../Resource/resource.robot Resource ../Resource/Keywords.robot Library OperatingSystem Library REST ${url} - +Resource ../Resource/scripts_variables.robot +Library String +Library Process +Library ../Scripts/find_rmr_message.py *** Test Cases *** @@ -45,8 +48,32 @@ Prepare logs for tests Remove log files Save logs - - +Verify logs - Confiugration update - Begin Tag Get + ${Configuration}= Grep File ./${gnb_log_filename} + ${ConfigurationAfterStrip}= Strip String ${Configuration} + Should Be Equal ${ConfigurationAfterStrip} + +Verify logs - Confiugration update - End Tag Get + ${ConfigurationEnd}= Grep File ./${gnb_log_filename} + ${ConfigurationEndAfterStrip}= Strip String ${ConfigurationEnd} + Should Be Equal ${ConfigurationEndAfterStrip} + +Verify logs - Confiugration update - Ack Tag Begin + ${ConfigurationAck}= Grep File ./${gnb_log_filename} + ${ConfigurationAckAfter}= Strip String ${ConfigurationAck} + Should Be Equal ${ConfigurationAckAfter} + +Verify logs - Confiugration update - Ack Tag End + ${ConfigurationAckEnd}= Grep File ./${gnb_log_filename} + ${ConfigurationAckEndAfterStrip}= Strip String ${ConfigurationAckEnd} + Should Be Equal ${ConfigurationAckEndAfterStrip} + +Verify logs - find RIC_ENDC_CONF_UPDATE + ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${configurationupdate_message_type} ${Meid_test1} + Should Be Equal As Strings ${result} True +Verify logs - find RIC_ENDC_CONF_UPDATE_ACK + ${result1} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${configurationupdate_ack_message_type} ${Meid_test1} + Should Be Equal As Strings ${result1} True diff --git a/Automation/Tests/E2Term_Initialization/E2Term_Init_Message_Test.robot b/Automation/Tests/E2Term_Initialization/E2Term_Init_Message_Test.robot new file mode 100644 index 0000000..3ce8a50 --- /dev/null +++ b/Automation/Tests/E2Term_Initialization/E2Term_Init_Message_Test.robot @@ -0,0 +1,37 @@ +*** Settings *** +Suite Setup Prepare Enviorment +Resource ../Resource/resource.robot +Resource ../Resource/Keywords.robot +Resource ../Resource/scripts_variables.robot +Library OperatingSystem +Library ../Scripts/find_rmr_message.py +Library ../Scripts/cleanup_db.py +Library ../Scripts/e2t_db_script.py + +*** Test Cases *** + +Test New E2T Send Init + Stop E2 + + ${result}= cleanup_db.flush_and_restore_without_e2t_keys + Should Be Equal As Strings ${result} True + + Start E2 + +prepare logs for tests + Remove log files + Save logs + +E2M Logs - Verify RMR Message + ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${E2_INIT_message_type} ${None} + Should Be Equal As Strings ${result} True + +Verify E2T keys in DB + ${result}= e2t_db_script.verify_e2t_addresses_key + Should Be Equal As Strings ${result} True + + ${result}= e2t_db_script.verify_e2t_instance_key + Should Be Equal As Strings ${result} True + + + diff --git a/Automation/Tests/E2Term_Initialization/__init__.robot b/Automation/Tests/E2Term_Initialization/__init__.robot new file mode 100755 index 0000000..7112a73 --- /dev/null +++ b/Automation/Tests/E2Term_Initialization/__init__.robot @@ -0,0 +1,20 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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. +# +############################################################################## + +*** Settings *** +Documentation E2Term-Initialization diff --git a/Automation/Tests/ENDC-Setup/ENDC_Setup_request_test.robot b/Automation/Tests/ENDC-Setup/ENDC_Setup_request_test.robot index 1c75542..13ef989 100644 --- a/Automation/Tests/ENDC-Setup/ENDC_Setup_request_test.robot +++ b/Automation/Tests/ENDC-Setup/ENDC_Setup_request_test.robot @@ -27,6 +27,7 @@ Resource ../Resource/Keywords.robot Resource ../Resource/scripts_variables.robot Library OperatingSystem Library ../Scripts/find_rmr_message.py +Library ../Scripts/rsmscripts.py Library REST ${url} @@ -70,5 +71,7 @@ RSM RESOURCE STATUS REQUEST message not sent ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test2} Should Be Equal As Strings ${result} False - +Verify RSM RAN info doesn't exist in redis + ${result}= rsmscripts.verify_rsm_ran_info_start_false + Should Be Equal As Strings ${result} False diff --git a/Automation/Tests/ENDC_Reset_RAN_TO_RIC/Reset_RAN_Found.robot b/Automation/Tests/ENDC_Reset_RAN_TO_RIC/Reset_RAN_Found.robot index 089c1a7..9215ebc 100644 --- a/Automation/Tests/ENDC_Reset_RAN_TO_RIC/Reset_RAN_Found.robot +++ b/Automation/Tests/ENDC_Reset_RAN_TO_RIC/Reset_RAN_Found.robot @@ -27,19 +27,26 @@ Resource ../Resource/Keywords.robot Library OperatingSystem Library Collections Library REST ${url} - - - +Resource ../Resource/scripts_variables.robot +Library String +Library Process +Library ../Scripts/find_rmr_message.py +Library ../Scripts/find_error_script.py +Library ../Scripts/rsmscripts.py *** Test Cases *** Prepare Ran in Connected connectionStatus - Post Request setup node b endc-setup +# Post Request setup node b endc-setup + Set Headers ${header} + POST /v1/nodeb/endc-setup ${json} Integer response status 204 Sleep 1s - GET /v1/nodeb/test2 +# GET /v1/nodeb/test2 + GET /v1/nodeb/test1 Integer response status 200 - String response body ranName test2 +# String response body ranName test2 + String response body ranName test1 String response body connectionStatus CONNECTED Run Reset from RAN @@ -50,3 +57,30 @@ Prepare logs for tests Remove log files Save logs +#Verify logs - Reset Sent by e2adapter +# ${result} find_error_script.find_error ${EXECDIR} ${e2adapter_log_filename} ${E2ADAPTER_Setup_Resp} +# Should Be Equal As Strings ${result} True + +Verify logs - Reset Sent by simulator + ${Reset}= Grep File ./${gnb_log_filename} ResetRequest has been sent + Should Be Equal ${Reset} gnbe2_simu: ResetRequest has been sent + +Verify logs - e2mgr logs - messege sent + ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RIC_X2_RESET_REQ_message_type} ${Meid_test1} + Should Be Equal As Strings ${result} True + +Verify logs - e2mgr logs - messege received + ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RIC_X2_RESET_RESP_message_type} ${Meid_test1} + Should Be Equal As Strings ${result} True + +RAN Restarted messege sent + ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RAN_RESTARTED_message_type} ${Meid_test1} + Should Be Equal As Strings ${result} True + +RSM RESOURCE STATUS REQUEST message not sent + ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test2} + Should Be Equal As Strings ${result} False + +Verify RSM RAN info doesn't exist in redis + ${result}= rsmscripts.verify_rsm_ran_info_start_false + Should Be Equal As Strings ${result} False \ No newline at end of file diff --git a/Automation/Tests/ENDC_Reset_RAN_TO_RIC/Reset_Verify_logs.robot b/Automation/Tests/ENDC_Reset_RAN_TO_RIC/Reset_Verify_logs.robot deleted file mode 100644 index 6aeb109..0000000 --- a/Automation/Tests/ENDC_Reset_RAN_TO_RIC/Reset_Verify_logs.robot +++ /dev/null @@ -1,54 +0,0 @@ -############################################################################## -# -# Copyright (c) 2019 AT&T Intellectual Property. -# -# 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. -# -############################################################################## -# -# This source code is part of the near-RT RIC (RAN Intelligent Controller) -# platform project (RICP). -# - - -*** Settings *** -Resource ../Resource/scripts_variables.robot -Resource ../Resource/Keywords.robot -Library String -Library OperatingSystem -Library Process -Library ../Scripts/find_rmr_message.py -Library ../Scripts/find_error_script.py - - - -*** Test Cases *** -Verify logs - Reset Sent by e2adapter - ${result} find_error_script.find_error ${EXECDIR} ${e2adapter_log_filename} ${E2ADAPTER_Setup_Resp} - Should Be Equal As Strings ${result} True - -Verify logs - e2mgr logs - messege sent - ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RIC_X2_RESET_REQ_message_type} ${Meid_test1} - Should Be Equal As Strings ${result} True - -Verify logs - e2mgr logs - messege received - ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RIC_X2_RESET_RESP_message_type} ${Meid_test1} - Should Be Equal As Strings ${result} True - -RAN Restarted messege sent - ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RAN_RESTARTED_message_type} ${Meid_test1} - Should Be Equal As Strings ${result} True - -RSM RESOURCE STATUS REQUEST message not sent - ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test2} - Should Be Equal As Strings ${result} False \ No newline at end of file diff --git a/Automation/Tests/ENDC_Reset_RIC_TO_RAN/Reset_Happy_no_cause.robot b/Automation/Tests/ENDC_Reset_RIC_TO_RAN/Reset_Happy_no_cause.robot index 9010a68..a3ecabe 100644 --- a/Automation/Tests/ENDC_Reset_RIC_TO_RAN/Reset_Happy_no_cause.robot +++ b/Automation/Tests/ENDC_Reset_RIC_TO_RAN/Reset_Happy_no_cause.robot @@ -27,6 +27,7 @@ Resource ../Resource/resource.robot Resource ../Resource/Keywords.robot Library OperatingSystem Library ../Scripts/find_rmr_message.py +Library ../Scripts/rsmscripts.py Library REST ${url} @@ -57,4 +58,8 @@ RAN Restarted messege sent RSM RESOURCE STATUS REQUEST message not sent ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test2} - Should Be Equal As Strings ${result} False \ No newline at end of file + Should Be Equal As Strings ${result} False + +Verify RSM RAN info doesn't exist in redis + ${result}= rsmscripts.verify_rsm_ran_info_start_false + Should Be Equal As Strings ${result} False diff --git a/Automation/Tests/ENDC_Reset_RIC_TO_RAN/Reset_Happy_with_cause.robot b/Automation/Tests/ENDC_Reset_RIC_TO_RAN/Reset_Happy_with_cause.robot index e6b2492..2e5a003 100644 --- a/Automation/Tests/ENDC_Reset_RIC_TO_RAN/Reset_Happy_with_cause.robot +++ b/Automation/Tests/ENDC_Reset_RIC_TO_RAN/Reset_Happy_with_cause.robot @@ -27,6 +27,7 @@ Resource ../Resource/resource.robot Resource ../Resource/Keywords.robot Library OperatingSystem Library ../Scripts/find_rmr_message.py +Library ../Scripts/rsmscripts.py Library REST ${url} @@ -58,4 +59,8 @@ RAN Restarted messege sent RSM RESOURCE STATUS REQUEST message not sent ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test2} - Should Be Equal As Strings ${result} False \ No newline at end of file + Should Be Equal As Strings ${result} False + +Verify RSM RAN info doesn't exist in redis + ${result}= rsmscripts.verify_rsm_ran_info_start_false + Should Be Equal As Strings ${result} False \ No newline at end of file diff --git a/Automation/Tests/KeepAlive/__init__.robot b/Automation/Tests/KeepAlive/__init__.robot new file mode 100755 index 0000000..6826893 --- /dev/null +++ b/Automation/Tests/KeepAlive/__init__.robot @@ -0,0 +1,20 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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. +# +############################################################################## + +*** Settings *** +Documentation Keep Alive diff --git a/Automation/Tests/KeepAlive/keep_alive_test.robot b/Automation/Tests/KeepAlive/keep_alive_test.robot new file mode 100644 index 0000000..ac226a2 --- /dev/null +++ b/Automation/Tests/KeepAlive/keep_alive_test.robot @@ -0,0 +1,43 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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. +# +############################################################################## +*** Settings *** +Suite Setup Prepare Enviorment +Resource ../Resource/resource.robot +Resource ../Resource/Keywords.robot +Resource ../Resource/scripts_variables.robot +Library ../Scripts/find_error_script.py +Library OperatingSystem +Library Collections + + +*** Test Cases *** + +Stop E2T + stop_e2 + Sleep 1s + +Prepare logs for tests + Remove log files + Save logs + +Verify Is Dead Message Printed + ${result} find_error_script.find_error ${EXECDIR} ${e2mgr_log_filename} ${e2_is_dead_message_printed} + Should Be Equal As Strings ${result} True + +Start E2T + start_e2 \ No newline at end of file diff --git a/Automation/Tests/LoadInfomation/Loadinformation_adding_data_and_overwrite.robot b/Automation/Tests/LoadInfomation/Loadinformation_adding_data_and_overwrite.robot index f2e589c..32e81b9 100644 --- a/Automation/Tests/LoadInfomation/Loadinformation_adding_data_and_overwrite.robot +++ b/Automation/Tests/LoadInfomation/Loadinformation_adding_data_and_overwrite.robot @@ -50,7 +50,7 @@ Trigger X-2 Setup for load information String response body connectionStatus CONNECTED -Verify Load information does exist in redis +Verify Load information exists in redis ${result}= loadscripts.verify_value Should Be Equal As Strings ${result} True diff --git a/Automation/Tests/Lost_Connection/Lost_Connetion_CONNECTING_TO_DISCONNECTED.robot b/Automation/Tests/Lost_Connection/Lost_Connetion_CONNECTING_TO_DISCONNECTED.robot index 805d648..90002eb 100644 --- a/Automation/Tests/Lost_Connection/Lost_Connetion_CONNECTING_TO_DISCONNECTED.robot +++ b/Automation/Tests/Lost_Connection/Lost_Connetion_CONNECTING_TO_DISCONNECTED.robot @@ -52,7 +52,7 @@ Prepare Ran in Connecting connectionStatus Verfiy Disconnected ConnectionStatus - Sleep 1s + Sleep 10s GET /v1/nodeb/test1 Integer response status 200 String response body ranName test1 diff --git a/Automation/Tests/RSM_Resource_Status/__init__.robot b/Automation/Tests/RSM_Resource_Status/__init__.robot new file mode 100755 index 0000000..4a008d9 --- /dev/null +++ b/Automation/Tests/RSM_Resource_Status/__init__.robot @@ -0,0 +1,20 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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. +# +############################################################################## + +*** Settings *** +Documentation Resource status diff --git a/Automation/Tests/RSM_Resource_Status/resource_status_false_start.robot b/Automation/Tests/RSM_Resource_Status/resource_status_false_start.robot new file mode 100644 index 0000000..e6b969a --- /dev/null +++ b/Automation/Tests/RSM_Resource_Status/resource_status_false_start.robot @@ -0,0 +1,56 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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. +# +############################################################################## + +*** Settings *** +Suite Setup Prepare Enviorment +Resource ../Resource/resource.robot +Resource ../Resource/Keywords.robot +Resource ../Resource/scripts_variables.robot +Resource resource_status_keywords.robot +Library ../Scripts/rsmscripts.py +Library ../Scripts/find_rmr_message.py +Library OperatingSystem +Library REST ${url_rsm} +Suite Teardown Delete All Sessions + + +*** Test Cases *** +Run setup + rsmscripts.set_general_config_resource_status_false + + Prepare Ran In Connected Status + +Put Http Start Request To RSM + Put Request Resource Status Start + Integer response status 204 + +Verify RSM RAN Info Status Is Start And True In Redis + ${result}= rsmscripts.verify_rsm_ran_info_start_true + Should Be Equal As Strings ${result} True + +Verify RSM Enable Resource Status Is True In General Configuration In Redis + ${result}= rsmscripts.verify_general_config_enable_resource_status_true + Should Be Equal As Strings ${result} True + +prepare logs for tests + Remove log files + Save logs + +Verify RSM Resource Status Request Message Sent + ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test1} + Should Be Equal As Strings ${result} True \ No newline at end of file diff --git a/Automation/Tests/RSM_Resource_Status/resource_status_false_stop.robot b/Automation/Tests/RSM_Resource_Status/resource_status_false_stop.robot new file mode 100644 index 0000000..9864e3e --- /dev/null +++ b/Automation/Tests/RSM_Resource_Status/resource_status_false_stop.robot @@ -0,0 +1,56 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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. +# +############################################################################## + +*** Settings *** +Suite Setup Prepare Enviorment +Resource ../Resource/resource.robot +Resource ../Resource/Keywords.robot +Resource ../Resource/scripts_variables.robot +Resource resource_status_keywords.robot +Library ../Scripts/rsmscripts.py +Library ../Scripts/find_rmr_message.py +Library OperatingSystem +Library REST ${url_rsm} +Suite Teardown Delete All Sessions + + +*** Test Cases *** +Run setup + rsmscripts.set_general_config_resource_status_false + + Prepare Ran In Connected Status + +Put Http Stop Request To RSM + Put Request Resource Status Stop + Integer response status 204 + +Verify RSM RAN Info Status Is Stop And True In Redis + ${result}= rsmscripts.verify_rsm_ran_info_stop_true + Should Be Equal As Strings ${result} True + +Verify RSM Enable Resource Status Is False In General Configuration In Redis + ${result}= rsmscripts.verify_general_config_enable_resource_status_false + Should Be Equal As Strings ${result} True + +prepare logs for tests + Remove log files + Save logs + +Verify RSM Resource Status Request Message Not Sent + ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test1} + Should Be Equal As Strings ${result} False \ No newline at end of file diff --git a/Automation/Tests/RSM_Resource_Status/resource_status_keywords.robot b/Automation/Tests/RSM_Resource_Status/resource_status_keywords.robot new file mode 100644 index 0000000..2dc0ec2 --- /dev/null +++ b/Automation/Tests/RSM_Resource_Status/resource_status_keywords.robot @@ -0,0 +1,36 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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. +# +############################################################################## + +*** Settings *** +Documentation Keywords file +Library ../Scripts/cleanup_db.py +Resource ../Resource/resource.robot +Library Collections +Library OperatingSystem +Library json +Library RequestsLibrary + + + +*** Keywords *** +Prepare Ran In Connected Status + Create Session x2setup ${url} + ${headers}= Create Dictionary Accept=application/json Content-Type=application/json + ${resp}= Post Request x2setup /v1/nodeb/x2-setup data=${json_setup_rsm_tests} headers=${headers} + Should Be Equal As Strings ${resp.status_code} 204 + diff --git a/Automation/Tests/RSM_Resource_Status/resource_status_true_start.robot b/Automation/Tests/RSM_Resource_Status/resource_status_true_start.robot new file mode 100644 index 0000000..21f9217 --- /dev/null +++ b/Automation/Tests/RSM_Resource_Status/resource_status_true_start.robot @@ -0,0 +1,54 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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. +# +############################################################################## + +*** Settings *** +Suite Setup Prepare Enviorment +Resource ../Resource/resource.robot +Resource ../Resource/Keywords.robot +Resource ../Resource/scripts_variables.robot +Resource resource_status_keywords.robot +Library ../Scripts/rsmscripts.py +Library ../Scripts/find_rmr_message.py +Library OperatingSystem +Library REST ${url_rsm} +Suite Teardown Delete All Sessions + + +*** Test Cases *** +Run setup + Prepare Ran In Connected Status + +Put Http Start Request To RSM + Put Request Resource Status Start + Integer response status 204 + +Verify RSM RAN Info Status Is Start And True In Redis + ${result}= rsmscripts.verify_rsm_ran_info_start_true + Should Be Equal As Strings ${result} True + +Verify RSM Enable Resource Status Is True In General Configuration In Redis + ${result}= rsmscripts.verify_general_config_enable_resource_status_true + Should Be Equal As Strings ${result} True + +prepare logs for RSM tests + Remove log files + Save logs + +Verify RSM Resource Status Request Message Sent + ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test1} + Should Be Equal As Strings ${result} True \ No newline at end of file diff --git a/Automation/Tests/RSM_Resource_Status/resource_status_true_stop.robot b/Automation/Tests/RSM_Resource_Status/resource_status_true_stop.robot new file mode 100644 index 0000000..32cab38 --- /dev/null +++ b/Automation/Tests/RSM_Resource_Status/resource_status_true_stop.robot @@ -0,0 +1,54 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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. +# +############################################################################## + +*** Settings *** +Suite Setup Prepare Enviorment +Resource ../Resource/resource.robot +Resource ../Resource/Keywords.robot +Resource ../Resource/scripts_variables.robot +Resource resource_status_keywords.robot +Library ../Scripts/rsmscripts.py +Library ../Scripts/find_rmr_message.py +Library OperatingSystem +Library REST ${url_rsm} +Suite Teardown Delete All Sessions + + +*** Test Cases *** +Run setup + Prepare Ran In Connected Status + +Put Http Stop Request To RSM + Put Request Resource Status Stop + Integer response status 204 + +#Verify RSM RAN Info Status Is Stop And False In Redis +#${result}= rsmscripts.verify_rsm_ran_info_stop_false +#Should Be Equal As Strings ${result} True + +Verify RSM Enable Resource Status Is False In General Configuration In Redis + ${result}= rsmscripts.verify_general_config_enable_resource_status_false + Should Be Equal As Strings ${result} True + +prepare logs for tests + Remove log files + Save logs + +Verify RSM Resource Status Request Message Sent + ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test1} + Should Be Equal As Strings ${result} True \ No newline at end of file diff --git a/Automation/Tests/RedButton/RedButton_CONNECTED_SHUTDOWN_CONNECTED.robot b/Automation/Tests/RedButton/RedButton_CONNECTED_SHUTDOWN_CONNECTED.robot index 77bfb52..04dee6d 100644 --- a/Automation/Tests/RedButton/RedButton_CONNECTED_SHUTDOWN_CONNECTED.robot +++ b/Automation/Tests/RedButton/RedButton_CONNECTED_SHUTDOWN_CONNECTED.robot @@ -29,9 +29,6 @@ Library Collections Library REST ${url} -*** Variables *** -${restart_docker_sim} docker restart gnbe2_simu - *** Test Cases *** @@ -59,11 +56,7 @@ Verfiy Shutdown ConnectionStatus String response body connectionStatus SHUT_DOWN Restart simualtor - - Run And Return Rc And Output ${restart_docker_sim} - ${result}= Run And Return Rc And Output ${docker_command} - Should Be Equal As Integers ${result[1]} ${docker_number} - + Restart simulator repare Ran in Connected connectionStatus Post Request setup node b x-2 diff --git a/Automation/Tests/RedButton/RedButton_DISCONNECTED.robot b/Automation/Tests/RedButton/RedButton_DISCONNECTED.robot index c6bf324..547d14b 100644 --- a/Automation/Tests/RedButton/RedButton_DISCONNECTED.robot +++ b/Automation/Tests/RedButton/RedButton_DISCONNECTED.robot @@ -43,7 +43,7 @@ Pre Condition for Connecting - no E2ADAPTER Prepare Ran in Connecting connectionStatus Post Request setup node b endc-setup Integer response status 204 - Sleep 1s + Sleep 10s GET /v1/nodeb/test2 Integer response status 200 String response body ranName test2 diff --git a/Automation/Tests/Resource/Keywords.robot b/Automation/Tests/Resource/Keywords.robot index 6ed5617..2593c5f 100644 --- a/Automation/Tests/Resource/Keywords.robot +++ b/Automation/Tests/Resource/Keywords.robot @@ -36,6 +36,14 @@ Post Request setup node b x-2 POST /v1/nodeb/x2-setup ${json} +Put Request Resource Status Start + Set Headers ${header} + PUT /v1/general/resourcestatus ${resource_status_start_json} + + +Put Request Resource Status Stop + Set Headers ${header} + PUT /v1/general/resourcestatus ${resource_status_stop_json} Get Request node b enb test1 Sleep 1s @@ -50,14 +58,20 @@ Get Request node b enb test2 Remove log files Remove File ${EXECDIR}/${gnb_log_filename} Remove File ${EXECDIR}/${e2mgr_log_filename} + Remove File ${EXECDIR}/${e2t_log_filename} Remove File ${EXECDIR}/${rsm_log_filename} + Remove File ${EXECDIR}/${e2e_simu_log_filename} + Remove File ${EXECDIR}/${rm_sim_log_filename} Remove File ${EXECDIR}/${e2adapter_log_filename} Save logs Sleep 1s Run ${Save_sim_log} Run ${Save_e2mgr_log} + Run ${Save_e2t_log} Run ${Save_rsm_log} + Run ${Save_e2e_simu_log} + Run ${Save_rm_sim_log} Run ${Save_e2adapter_log} @@ -69,6 +83,7 @@ Stop Simulator Run And Return Rc And Output ${stop_simu} + Prepare Simulator For Load Information Run And Return Rc And Output ${stop_simu} Run And Return Rc And Output ${docker_Remove} @@ -79,11 +94,44 @@ Prepare Simulator For Load Information Should Be Equal As Integers ${result[1]} ${docker_number} Prepare Enviorment + ${starting_timestamp} Evaluate datetime.datetime.now(datetime.timezone.utc).isoformat("T") modules=datetime + ${e2t_log_filename} Evaluate "e2t.${SUITE NAME}.log".replace(" ","-") + ${e2mgr_log_filename} Evaluate "e2mgr.${SUITE NAME}.log".replace(" ","-") + ${gnb_log_filename} Evaluate "gnb.${SUITE NAME}.log".replace(" ","-") + ${rsm_log_filename} Evaluate "rsm.${SUITE NAME}.log".replace(" ","-") + ${e2e_simu_log_filename} Evaluate "e2e_simu.${SUITE NAME}.log".replace(" ","-") + ${rm_sim_log_filename} Evaluate "rm_sim.${SUITE NAME}.log".replace(" ","-") + ${e2adapter_log_filename} Evaluate "e2adapter.${SUITE NAME}.log".replace(" ","-") + ${Save_sim_log} Evaluate 'docker logs --since ${starting_timestamp} gnbe2_simu > ${gnb_log_filename}' + ${Save_e2mgr_log} Evaluate 'docker logs --since ${starting_timestamp} e2mgr > ${e2mgr_log_filename}' + ${Save_e2t_log} Evaluate 'docker logs --since ${starting_timestamp} e2 > ${e2t_log_filename}' + ${Save_rsm_log} Evaluate 'docker logs --since ${starting_timestamp} rsm > ${rsm_log_filename}' + ${Save_e2e_simu_log} Evaluate 'docker logs --since ${starting_timestamp} e2e_simu > ${e2e_simu_log_filename}' + ${Save_rm_sim_log} Evaluate 'docker logs --since ${starting_timestamp} rm_sim > ${rm_sim_log_filename}' + ${Save_e2adapter_log} Evaluate 'docker logs --since ${starting_timestamp} e2adapter > ${e2adapter_log_filename}' + Set Suite Variable ${e2t_log_filename} + Set Suite Variable ${e2mgr_log_filename} + Set Suite Variable ${gnb_log_filename} + Set Suite Variable ${rsm_log_filename} + Set Suite Variable ${e2e_simu_log_filename} + Set Suite Variable ${rm_sim_log_filename} + Set Suite Variable ${e2adapter_log_filename} + Set Suite Variable ${Save_sim_log} + Set Suite Variable ${Save_e2mgr_log} + Set Suite Variable ${Save_e2t_log} + Set Suite Variable ${Save_rsm_log} + Set Suite Variable ${Save_e2e_simu_log} + Set Suite Variable ${Save_rm_sim_log} + Set Suite Variable ${Save_e2adapter_log} + ${flush} cleanup_db.flush Should Be Equal As Strings ${flush} True Run And Return Rc And Output ${stop_simu} + Run And Return Rc And Output ${stop_e2e_simu} Run And Return Rc And Output ${docker_Remove} + Run And Return Rc And Output ${docker_remove_e2e_simu} Run And Return Rc And Output ${run_simu_regular} + Run And Return Rc And Output ${run_e2e_simu_regular} Run And Return Rc And Output ${restart_e2adapter} Sleep 2s ${result}= Run And Return Rc And Output ${docker_command} @@ -95,6 +143,12 @@ Start E2 Should Be Equal As Integers ${result[1]} ${docker_number} Sleep 2s +Stop E2 + Run And Return Rc And Output ${stop_e2} + ${result}= Run And Return Rc And Output ${docker_command} + Should Be Equal As Integers ${result[1]} ${docker_number-1} + Sleep 2s + Start Dbass Run And Return Rc And Output ${dbass_remove} Run And Return Rc And Output ${dbass_start} @@ -106,6 +160,12 @@ Stop Dbass ${result}= Run And Return Rc And Output ${docker_command} Should Be Equal As Integers ${result[1]} ${docker_number-1} +Restart simulator + + Run And Return Rc And Output ${restart_docker_sim} + ${result}= Run And Return Rc And Output ${docker_command} + Should Be Equal As Integers ${result[1]} ${docker_number} + diff --git a/Automation/Tests/Resource/resource.robot b/Automation/Tests/Resource/resource.robot index 4b6bcb3..90c79b2 100644 --- a/Automation/Tests/Resource/resource.robot +++ b/Automation/Tests/Resource/resource.robot @@ -25,46 +25,45 @@ Documentation Resource file *** Variables *** -${docker_number} 6 -${docker_number-1} 5 +${docker_number} 8 +${docker_number-1} 7 ${ip_gnb_simu} 10.0.2.15 ${ip_e2adapter} 10.0.2.15 ${url} http://localhost:3800 +${url_rsm} http://localhost:4800 +${json_setup_rsm_tests} {"ranIp": "10.0.2.15","ranPort": 36422,"ranName":"test1"} ${json} {"ranIp": "10.0.2.15","ranPort": 5577,"ranName":"test1"} ${endcbadjson} {"ranIp": "a","ranPort": 49999,"ranName":"test2"} ${endcjson} {"ranIp": "10.0.2.15","ranPort": 49999,"ranName":"test2"} ${resetcausejson} {"cause": "misc:not-enough-user-plane-processing-resources"} ${resetbadcausejson} {"cause": "bla" } ${resetbad1causejson} {"cause": } +${resource_status_start_json} {"enableResourceStatus":true} +${resource_status_stop_json} {"enableResourceStatus":false} ${header} {"Content-Type": "application/json"} ${docker_command} docker ps | grep Up | wc --lines ${run_simu_load} docker run -d --name gnbe2_simu --env gNBipv4=localhost --env gNBport=36422 --env duration=600000000000 --env indicationReportRate=1000000000 --env indicationInsertRate=0 -p 5577:36422/sctp snapshot.docker.ranco-dev-tools.eastus.cloudapp.azure.com:10001/gnbe2_simu:1.0.6 -#${run_simu_load} docker run -d --name gnbe2_simu -h gnb-sim --env gNBipv4=gnb-sim --env gNBport=5577/sctp --env duration=600000000000 --env indicationReportRate=1000000000 --env indicationInsertRate=0 snapshot.docker.ranco-dev-tools.eastus.cloudapp.azure.com:10001/gnbe2_simu:1.0.6 +${stop_e2e_simu} docker stop e2e_simu ${stop_simu} docker stop gnbe2_simu ${run_simu_regular} docker run -d --name gnbe2_simu --env gNBipv4=localhost --env gNBport=36422 --env duration=600000000000 --env indicationReportRate=0 --env indicationInsertRate=0 -p 5577:36422/sctp snapshot.docker.ranco-dev-tools.eastus.cloudapp.azure.com:10001/gnbe2_simu:1.0.6 -#${run_simu_regular} docker run -d --name gnbe2_simu -h gnb-sim --env gNBipv4=gnb-sim --env gNBport=5577/sctp --env duration=600000000000 --env indicationReportRate=0 --env indicationInsertRate=0 snapshot.docker.ranco-dev-tools.eastus.cloudapp.azure.com:10001/gnbe2_simu:1.0.6 +${run_e2e_simu_regular} docker run -d --name e2e_simu -p 36422:36422 --net host -it snapshot.docker.ranco-dev-tools.eastus.cloudapp.azure.com:10001/e2sim:1.4.0 sh -c "./build/e2sim 10.0.2.15 36422" ${docker_Remove} docker rm gnbe2_simu +${docker_remove_e2e_simu} docker rm e2e_simu ${docker_restart} docker restart e2mgr ${restart_simu} docker restart gnbe2_simu +${restart_e2e_simu} docker restart e2e_simu ${restart_e2adapter} docker restart e2adapter +${restart_rsm} docker restart rsm ${start_e2} docker start e2 -${stop_docker_e2} docker stop e2 +${stop_e2} docker stop e2 ${dbass_start} docker run -d --name dbass -p 6379:6379 --env DBAAS_SERVICE_HOST=10.0.2.15 snapshot.docker.ranco-dev-tools.eastus.cloudapp.azure.com:10001/dbass:1.0.0 ${dbass_remove} docker rm dbass ${dbass_stop} docker stop dbass ${restart_simu} docker restart gnbe2_simu -${start_e2} docker start e2 ${stop_docker_e2} docker stop e2 +${restart_docker_sim} docker restart gnbe2_simu ${Run_Config} docker exec gnbe2_simu pkill gnbe2_simu -INT -${Save_sim_log} docker logs gnbe2_simu > gnb.log -${Save_e2mgr_log} docker logs e2mgr > e2mgr.log -${Save_rsm_log} docker logs rsm > rsm.log -${Save_e2adapter_log} docker logs e2adapter > e2adapter.log ${403_reset_message} "Activity X2_RESET rejected. RAN current state DISCONNECTED does not allow its execution " -${e2mgr_log_filename} e2mgr.log -${gnb_log_filename} gnb.log -${rsm_log_filename} rsm.log -${e2adapter_log_filename} e2adapter.log diff --git a/Automation/Tests/Resource/scripts_variables.robot b/Automation/Tests/Resource/scripts_variables.robot index 0c64f32..3d7e46a 100644 --- a/Automation/Tests/Resource/scripts_variables.robot +++ b/Automation/Tests/Resource/scripts_variables.robot @@ -33,10 +33,15 @@ ${RAN_CONNECTED_message_type} MType: 1200 ${RAN_RESTARTED_message_type} MType: 1210 ${RIC_X2_RESET_REQ_message_type} MType: 10070 ${RIC_X2_RESET_RESP_message_type} MType: 10070 -${failed_to_retrieve_nodeb_message} failed to retrieve nodeB entity. RanName: test1. +${E2_INIT_message_type} MType: 1100 +#${failed_to_retrieve_nodeb_message} failed to retrieve nodeB entity. RanName: test1. +#{#RanReconnectionManager.ReconnectRan - RAN name: test1 - Failed fetching RAN from rNib. Error: dial tcp 172.17.0.2:637 #9: i/o timeout" +${failed_to_retrieve_nodeb_message} RAN name: test1 - Failed fetching RAN from rNib ${first_retry_to_retrieve_from_db} RnibDataService.retry - retrying 1 GetNodeb ${third_retry_to_retrieve_from_db} RnibDataService.retry - after 3 attempts of GetNodeb ${RIC_RES_STATUS_REQ_message_type_successfully_sent} Message type: 10090 - Successfully sent RMR message +${E2_TERM_KEEP_ALIVE_REQ_message_type_successfully_sent} Message type: 1101 - Successfully sent RMR message +${e2_is_dead_message_printed} E2TShutdownManager.Shutdown - E2T e2t.att.com:38000 is Dead, RIP ${RAN_NAME_test1} RAN name: test1 ${RAN_NAME_test2} RAN name: test2 ${E2ADAPTER_Setup_Resp} Send dummy ENDCX2SetupResponse to RIC diff --git a/Automation/Tests/Scripts/cleanup_db.py b/Automation/Tests/Scripts/cleanup_db.py index 61aeffa..02c5f8f 100644 --- a/Automation/Tests/Scripts/cleanup_db.py +++ b/Automation/Tests/Scripts/cleanup_db.py @@ -21,6 +21,7 @@ # import config import redis +import time def flush(): @@ -33,5 +34,25 @@ def flush(): r.flushall() + r.set("{rsm},CFG:GENERAL:v1.0.0" , "{\"enableResourceStatus\":true,\"partialSuccessAllowed\":true,\"prbPeriodic\":true,\"tnlLoadIndPeriodic\":true,\"wwLoadIndPeriodic\":true,\"absStatusPeriodic\":true,\"rsrpMeasurementPeriodic\":true,\"csiPeriodic\":true,\"periodicityMs\":1,\"periodicityRsrpMeasurementMs\":3,\"periodicityCsiMs\":3}") + + r.set("{e2Manager},E2TAddresses", "[\"e2t.att.com:38000\"]") + + r.set("{e2Manager},E2TInstance:e2t.att.com:38000", "{\"address\":\"e2t.att.com:38000\",\"associatedRanList\":[],\"keepAliveTimestamp\":" + str(int(time.time())) + ",\"state\":\"ACTIVE\"}") + + return True + +def flush_and_restore_without_e2t_keys(): + + c = config.redis_ip_address + + p = config.redis_ip_port + + r = redis.Redis(host=c, port=p, db=0) + + r.flushall() + + r.set("{rsm},CFG:GENERAL:v1.0.0" , "{\"enableResourceStatus\":true,\"partialSuccessAllowed\":true,\"prbPeriodic\":true,\"tnlLoadIndPeriodic\":true,\"wwLoadIndPeriodic\":true,\"absStatusPeriodic\":true,\"rsrpMeasurementPeriodic\":true,\"csiPeriodic\":true,\"periodicityMs\":1,\"periodicityRsrpMeasurementMs\":3,\"periodicityCsiMs\":3}") + return True diff --git a/Automation/Tests/Scripts/e2mdbscripts.py b/Automation/Tests/Scripts/e2mdbscripts.py new file mode 100644 index 0000000..7b9475b --- /dev/null +++ b/Automation/Tests/Scripts/e2mdbscripts.py @@ -0,0 +1,49 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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 config +import redis +import cleanup_db +import json + +def getRedisClientDecodeResponse(): + c = config.redis_ip_address + p = config.redis_ip_port + return redis.Redis(host=c, port=p, db=0, decode_responses=True) + +def verify_ran_is_associated_with_e2t_instance(ranName, e2tAddress): + r = getRedisClientDecodeResponse() + e2tInstanceJson = r.get("{e2Manager},E2TInstance:"+e2tAddress) + e2tInstanceDic = json.loads(e2tInstanceJson) + assocRanList = e2tInstanceDic.get("associatedRanList") + return ranName in assocRanList + +# def dissociate_ran_from_e2tInstance(ranName, e2tAddress): +# r = getRedisClientDecodeResponse() +# e2tInstanceJson = r.get("{e2Manager},E2TInstance:"+e2tAddress) +# e2tInstanceDic = json.loads(e2tInstanceJson) +# assocRanList = e2tInstanceDic.get("associatedRanList") +# print(assocRanList) +# assocRanList.remove(ranName) +# updatedE2tInstanceJson = json.dumps(e2tInstanceDic) +# print(updatedE2tInstanceJson) +# r.set("{e2Manager},E2TInstance:"+e2tAddress, updatedE2tInstanceJson) +# nodebBytes = r.get("{e2Manager},RAN:"+ranName) +# encoded = nodebBytes.decode().replace(e2tAddress,"").encode() +# r.set("{e2Manager},RAN:"+ranName, encoded) + diff --git a/Automation/Tests/Scripts/e2t_db_script.py b/Automation/Tests/Scripts/e2t_db_script.py new file mode 100644 index 0000000..add1a9b --- /dev/null +++ b/Automation/Tests/Scripts/e2t_db_script.py @@ -0,0 +1,58 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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 config +import redis + + +def getRedisClientDecodeResponse(): + + c = config.redis_ip_address + + p = config.redis_ip_port + + return redis.Redis(host=c, port=p, db=0, decode_responses=True) + + +def verify_e2t_addresses_key(): + + r = getRedisClientDecodeResponse() + + value = "[\"e2t.att.com:38000\"]" + + return r.get("{e2Manager},E2TAddresses") == value + + +def verify_e2t_instance_key(): + + r = getRedisClientDecodeResponse() + + e2_address = "\"address\":\"e2t.att.com:38000\"" + e2_associated_ran_list = "\"associatedRanList\":[]" + e2_state = "\"state\":\"ACTIVE\"" + + e2_db_instance = r.get("{e2Manager},E2TInstance:e2t.att.com:38000") + + if e2_db_instance.find(e2_address) < 0: + return False + if e2_db_instance.find(e2_associated_ran_list) < 0: + return False + if e2_db_instance.find(e2_state) < 0: + return False + + return True \ No newline at end of file diff --git a/Automation/Tests/Scripts/find_rmr_message.py b/Automation/Tests/Scripts/find_rmr_message.py index 0253ceb..e75d9c6 100644 --- a/Automation/Tests/Scripts/find_rmr_message.py +++ b/Automation/Tests/Scripts/find_rmr_message.py @@ -31,8 +31,12 @@ def verify_logs(directory,filename,mtype,meid): for l in f: - if l.find(mtype) > 0 and l.find(meid) > 0: - return True + if (meid is not None): + if l.find(mtype) > 0 and l.find(meid) > 0: + return True + else: + if l.find(mtype) > 0: + return True return False diff --git a/Automation/Tests/Scripts/getnodes.py b/Automation/Tests/Scripts/getnodes.py index 5158265..2161094 100644 --- a/Automation/Tests/Scripts/getnodes.py +++ b/Automation/Tests/Scripts/getnodes.py @@ -22,6 +22,7 @@ import config import redis +import cleanup_db def add(): @@ -32,7 +33,7 @@ def add(): r = redis.Redis(host=c, port=p, db=0) - r.flushall() + cleanup_db.flush() r.set("{e2Manager},ENB:02f829:007a80", "\n\x05test1\x12\t10.0.2.15\x18\xc9+ \x01*\x10\n\x0602f829\x12\x06007a800\x01:3\b\x01\x12/\bc\x12\x0f02f829:0007ab50\x1a\x040102\"\x0602f829*\n\n\b\b\x01\x10\x01\x18\x04 \x040\x01") diff --git a/Automation/Tests/Scripts/loadscripts.py b/Automation/Tests/Scripts/loadscripts.py index 5cc862b..aec4b59 100644 --- a/Automation/Tests/Scripts/loadscripts.py +++ b/Automation/Tests/Scripts/loadscripts.py @@ -24,14 +24,18 @@ import redis import config - -def verify_value(): +def getRedisClient(): c = config.redis_ip_address p = config.redis_ip_port - r = redis.Redis(host=c, port=p, db=0) + return redis.Redis(host=c, port=p, db=0) + + +def verify_value(): + + r = getRedisClient() value = "\b\x98\xf7\xdd\xa3\xc7\xb4\x83\xde\x15\x12\x11\n\x0f02f829:0007ab00" @@ -43,11 +47,7 @@ def verify_value(): def add(): - c = config.redis_ip_address - - p = config.redis_ip_port - - r = redis.Redis(host=c, port=p, db=0) + r = getRedisClient() r.set("{e2Manager},LOAD:test1", "\b\x98\xf7\xdd\xa3\xc7\xb4\x83\xde\x15\x12\x11\n\x0f02f829:0007ab00") @@ -59,13 +59,10 @@ def add(): def verify(): - c = config.redis_ip_address - - p = config.redis_ip_port - - r = redis.Redis(host=c, port=p, db=0) + r = getRedisClient() if r.exists("{e2Manager},LOAD:test1"): return True else: return False + diff --git a/Automation/Tests/Scripts/rsmscripts.py b/Automation/Tests/Scripts/rsmscripts.py new file mode 100644 index 0000000..db2a869 --- /dev/null +++ b/Automation/Tests/Scripts/rsmscripts.py @@ -0,0 +1,97 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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 config +import redis +import json + + +def getRedisClientDecodeResponse(): + + c = config.redis_ip_address + + p = config.redis_ip_port + + return redis.Redis(host=c, port=p, db=0, decode_responses=True) + +def set_general_config_resource_status_false(): + + r = getRedisClientDecodeResponse() + r.set("{rsm},CFG:GENERAL:v1.0.0" , "{\"enableResourceStatus\":false,\"partialSuccessAllowed\":true,\"prbPeriodic\":true,\"tnlLoadIndPeriodic\":true,\"wwLoadIndPeriodic\":true,\"absStatusPeriodic\":true,\"rsrpMeasurementPeriodic\":true,\"csiPeriodic\":true,\"periodicityMs\":1,\"periodicityRsrpMeasurementMs\":3,\"periodicityCsiMs\":3}") + +def verify_rsm_ran_info_start_false(): + + r = getRedisClientDecodeResponse() + + value = "{\"ranName\":\"test1\",\"enb1MeasurementId\":1,\"enb2MeasurementId\":0,\"action\":\"start\",\"actionStatus\":false}" + + return r.get("{rsm},RAN:test1") == value + + +def verify_rsm_ran_info_start_true(): + + r = getRedisClientDecodeResponse() + + rsmInfoStr = r.get("{rsm},RAN:test1") + rsmInfoJson = json.loads(rsmInfoStr) + + response = rsmInfoJson["ranName"] == "test1" and rsmInfoJson["enb1MeasurementId"] == 1 and rsmInfoJson["enb2MeasurementId"] != 1 and rsmInfoJson["action"] == "start" and rsmInfoJson["actionStatus"] == True + + return response + + +def verify_rsm_ran_info_stop_false(): + + r = getRedisClientDecodeResponse() + + rsmInfoStr = r.get("{rsm},RAN:test1") + rsmInfoJson = json.loads(rsmInfoStr) + + response = rsmInfoJson["ranName"] == "test1" and rsmInfoJson["enb1MeasurementId"] == 1 and rsmInfoJson["action"] == "stop" and rsmInfoJson["actionStatus"] == False + + return response + + +def verify_rsm_ran_info_stop_true(): + + r = getRedisClientDecodeResponse() + + rsmInfoStr = r.get("{rsm},RAN:test1") + rsmInfoJson = json.loads(rsmInfoStr) + + response = rsmInfoJson["ranName"] == "test1" and rsmInfoJson["action"] == "stop" and rsmInfoJson["actionStatus"] == True + + return response + +def verify_general_config_enable_resource_status_true(): + + r = getRedisClientDecodeResponse() + + configStr = r.get("{rsm},CFG:GENERAL:v1.0.0") + configJson = json.loads(configStr) + + return configJson["enableResourceStatus"] == True + +def verify_general_config_enable_resource_status_false(): + + r = getRedisClientDecodeResponse() + + configStr = r.get("{rsm},CFG:GENERAL:v1.0.0") + configJson = json.loads(configStr) + + return configJson["enableResourceStatus"] == False \ No newline at end of file diff --git a/Automation/Tests/Unhappy/Reset_HttpResponse400_wrongstate.robot b/Automation/Tests/Unhappy/Reset_HttpResponse400_wrongstate.robot index bd87ad6..f0c36f7 100644 --- a/Automation/Tests/Unhappy/Reset_HttpResponse400_wrongstate.robot +++ b/Automation/Tests/Unhappy/Reset_HttpResponse400_wrongstate.robot @@ -42,7 +42,7 @@ Pre Condition for Connecting - no simu Reset - 400 http - 403 wrong state Post Request setup node b x-2 Integer response status 204 - Sleep 1s + Sleep 10s GET /v1/nodeb/test1 String response body connectionStatus DISCONNECTED Set Headers ${header} diff --git a/Automation/Tests/X2-Setup/X2_Setup_reuqest_test.robot b/Automation/Tests/X2-Setup/X2_Setup_reuqest_test.robot index b5dfdc8..337bf7a 100644 --- a/Automation/Tests/X2-Setup/X2_Setup_reuqest_test.robot +++ b/Automation/Tests/X2-Setup/X2_Setup_reuqest_test.robot @@ -27,6 +27,8 @@ Resource ../Resource/Keywords.robot Resource ../Resource/scripts_variables.robot Library OperatingSystem Library ../Scripts/find_rmr_message.py +Library ../Scripts/rsmscripts.py +Library ../Scripts/e2mdbscripts.py Library REST ${url} *** Test Cases *** @@ -42,6 +44,7 @@ X2 - Get Nodeb Integer response body port 5577 String response body connectionStatus CONNECTED String response body nodeType ENB + String response body associatedE2tInstanceAddress e2t.att.com:38000 String response body enb enbType MACRO_ENB Integer response body enb servedCells 0 pci 99 String response body enb servedCells 0 cellId 02f829:0007ab00 @@ -66,3 +69,13 @@ RSM RESOURCE STATUS REQUEST message sent ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test1} Should Be Equal As Strings ${result} True +Verify RSM RAN info exists in redis + ${result}= rsmscripts.verify_rsm_ran_info_start_false + Should Be Equal As Strings ${result} True + +Verify RAN is associated with E2T instance + ${result} e2mdbscripts.verify_ran_is_associated_with_e2t_instance test1 e2t.att.com:38000 + Should Be True ${result} + + + diff --git a/Automation/Tests/X2_Reset_RAN_TO_RIC/Reset_Verify_logs.robot b/Automation/Tests/X2-Setup/x2_setup_existing_assoc_test.robot similarity index 55% rename from Automation/Tests/X2_Reset_RAN_TO_RIC/Reset_Verify_logs.robot rename to Automation/Tests/X2-Setup/x2_setup_existing_assoc_test.robot index 01aa675..f1ec70d 100644 --- a/Automation/Tests/X2_Reset_RAN_TO_RIC/Reset_Verify_logs.robot +++ b/Automation/Tests/X2-Setup/x2_setup_existing_assoc_test.robot @@ -20,34 +20,48 @@ # platform project (RICP). # - *** Settings *** -Resource ../Resource/scripts_variables.robot +Suite Setup Prepare Enviorment +Resource ../Resource/resource.robot Resource ../Resource/Keywords.robot -Library String +Resource ../Resource/scripts_variables.robot Library OperatingSystem -Library Process Library ../Scripts/find_rmr_message.py - - +Library ../Scripts/rsmscripts.py +Library ../Scripts/e2mdbscripts.py +Library REST ${url} *** Test Cases *** -Verify logs - Reset Sent by simulator - ${Reset}= Grep File ./gnb.log ResetRequest has been sent - Should Be Equal ${Reset} gnbe2_simu: ResetRequest has been sent +X2 - Setup Test 1 + Post Request setup node b x-2 + Integer response status 204 -Verify logs - e2mgr logs - messege sent - ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RIC_X2_RESET_REQ_message_type} ${Meid_test1} - Should Be Equal As Strings ${result} True +X2 - Setup Test 2 + Post Request setup node b x-2 + Integer response status 204 -Verify logs - e2mgr logs - messege received - ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RIC_X2_RESET_RESP_message_type} ${Meid_test1} - Should Be Equal As Strings ${result} True +X2 - Get Nodeb + Get Request Node B Enb test1 + Integer response status 200 + String response body ranName test1 + String response body associatedE2tInstanceAddress e2t.att.com:38000 + +prepare logs for tests + Remove log files + Save logs -RAN Restarted messege sent - ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RAN_RESTARTED_message_type} ${Meid_test1} +X2 - RAN Connected message going to be sent + ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RAN_CONNECTED_message_type} ${Meid_test1} Should Be Equal As Strings ${result} True RSM RESOURCE STATUS REQUEST message sent ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test1} - Should Be Equal As Strings ${result} True \ No newline at end of file + Should Be Equal As Strings ${result} True + +Verify RSM RAN info exists in redis + ${result}= rsmscripts.verify_rsm_ran_info_start_false + Should Be Equal As Strings ${result} True + +Verify RAN is associated with E2T instance + ${result} e2mdbscripts.verify_ran_is_associated_with_e2t_instance test1 e2t.att.com:38000 + Should Be True ${result} diff --git a/Automation/Tests/X2-Setup/x2_setup_existing_not_assoc_test.robot b/Automation/Tests/X2-Setup/x2_setup_existing_not_assoc_test.robot new file mode 100644 index 0000000..457ca9c --- /dev/null +++ b/Automation/Tests/X2-Setup/x2_setup_existing_not_assoc_test.robot @@ -0,0 +1,71 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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. +# +############################################################################## + +*** Settings *** +Suite Setup Prepare Enviorment +Resource ../Resource/resource.robot +Resource ../Resource/Keywords.robot +Resource ../Resource/scripts_variables.robot +Library OperatingSystem +Library ../Scripts/find_rmr_message.py +Library ../Scripts/rsmscripts.py +Library ../Scripts/e2mdbscripts.py +Library REST ${url} + +*** Test Cases *** +X2 - Setup Test 1 + Post Request setup node b x-2 + Integer response status 204 + +Restart Simulator + Restart Simulator + +Verify RAN is NOT associated with E2T instance + ${result} e2mdbscripts.verify_ran_is_associated_with_e2t_instance test1 e2t.att.com:38000 + Should Be True ${result} == False + + +X2 - Setup Test 2 + Post Request setup node b x-2 + Integer response status 204 + +X2 - Get Nodeb + Get Request Node B Enb test1 + Integer response status 200 + String response body ranName test1 + String response body associatedE2tInstanceAddress e2t.att.com:38000 + +prepare logs for tests + Remove log files + Save logs + +X2 - RAN Connected message going to be sent + ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RAN_CONNECTED_message_type} ${Meid_test1} + Should Be Equal As Strings ${result} True + +RSM RESOURCE STATUS REQUEST message sent + ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test1} + Should Be Equal As Strings ${result} True + +Verify RSM RAN info exists in redis + ${result}= rsmscripts.verify_rsm_ran_info_start_false + Should Be Equal As Strings ${result} True + +Verify RAN is associated with E2T instance + ${result} e2mdbscripts.verify_ran_is_associated_with_e2t_instance test1 e2t.att.com:38000 + Should Be True ${result} diff --git a/Automation/Tests/X2_Reset_RAN_TO_RIC/Reset_RAN_Found.robot b/Automation/Tests/X2_Reset_RAN_TO_RIC/Reset_RAN_Found.robot index 780d966..6f50b7e 100644 --- a/Automation/Tests/X2_Reset_RAN_TO_RIC/Reset_RAN_Found.robot +++ b/Automation/Tests/X2_Reset_RAN_TO_RIC/Reset_RAN_Found.robot @@ -27,7 +27,11 @@ Resource ../Resource/Keywords.robot Library OperatingSystem Library Collections Library REST ${url} - +Resource ../Resource/scripts_variables.robot +Library String +Library Process +Library ../Scripts/find_rmr_message.py +Library ../Scripts/rsmscripts.py @@ -50,3 +54,26 @@ Prepare logs for tests Remove log files Save logs +Verify logs - Reset Sent by simulator + ${Reset}= Grep File ./${gnb_log_filename} ResetRequest has been sent + Should Be Equal ${Reset} gnbe2_simu: ResetRequest has been sent + +Verify logs - e2mgr logs - messege sent + ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RIC_X2_RESET_REQ_message_type} ${Meid_test1} + Should Be Equal As Strings ${result} True + +Verify logs - e2mgr logs - messege received + ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RIC_X2_RESET_RESP_message_type} ${Meid_test1} + Should Be Equal As Strings ${result} True + +RAN Restarted messege sent + ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RAN_RESTARTED_message_type} ${Meid_test1} + Should Be Equal As Strings ${result} True + +RSM RESOURCE STATUS REQUEST message sent + ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test1} + Should Be Equal As Strings ${result} True + +Verify RSM RAN info exists in redis + ${result}= rsmscripts.verify_rsm_ran_info_start_false + Should Be Equal As Strings ${result} True \ No newline at end of file diff --git a/Automation/Tests/X2_Reset_RAN_TO_RIC_Unhappy/Reset_RNIB.robot b/Automation/Tests/X2_Reset_RAN_TO_RIC_Unhappy/Reset_RNIB.robot index 02f69f1..8dc416b 100644 --- a/Automation/Tests/X2_Reset_RAN_TO_RIC_Unhappy/Reset_RNIB.robot +++ b/Automation/Tests/X2_Reset_RAN_TO_RIC_Unhappy/Reset_RNIB.robot @@ -27,9 +27,12 @@ Resource ../Resource/Keywords.robot Library OperatingSystem Library Collections Library REST ${url} - - - +Resource ../Resource/scripts_variables.robot +Library String +Library Process +Library ../Scripts/find_rmr_message.py +Library ../Scripts/find_error_script.py +Suite Teardown Start Dbass with 4 dockers *** Test Cases *** @@ -49,9 +52,30 @@ Stop RNIB Run Reset from RAN Run ${Run_Config} - Sleep 1s + Sleep 60s Prepare logs for tests Remove log files Save logs +Verify logs - Reset Sent by simulator + ${Reset}= Grep File ./${gnb_log_filename} ResetRequest has been sent + Should Be Equal ${Reset} gnbe2_simu: ResetRequest has been sent + +Verify logs for restart received + ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RIC_X2_RESET_REQ_message_type} ${Meid_test1} + Should Be Equal As Strings ${result} True + +Verify for error on retrying + ${result} find_error_script.find_error ${EXECDIR} ${e2mgr_log_filename} ${failed_to_retrieve_nodeb_message} + Should Be Equal As Strings ${result} True + + +*** Keywords *** +Start Dbass with 4 dockers + Run And Return Rc And Output ${dbass_remove} + Run And Return Rc And Output ${dbass_start} + Sleep 5s + ${result}= Run And Return Rc And Output ${docker_command} + Should Be Equal As Integers ${result[1]} ${docker_number-1} + diff --git a/Automation/Tests/X2_Reset_RAN_TO_RIC_Unhappy/Reset_Verify_logs.robot b/Automation/Tests/X2_Reset_RAN_TO_RIC_Unhappy/Reset_Verify_logs.robot deleted file mode 100644 index 1328660..0000000 --- a/Automation/Tests/X2_Reset_RAN_TO_RIC_Unhappy/Reset_Verify_logs.robot +++ /dev/null @@ -1,56 +0,0 @@ -############################################################################## -# -# Copyright (c) 2019 AT&T Intellectual Property. -# -# 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. -# -############################################################################## -# -# This source code is part of the near-RT RIC (RAN Intelligent Controller) -# platform project (RICP). -# - - -*** Settings *** -Resource ../Resource/scripts_variables.robot -Library String -Library OperatingSystem -Library Process -Resource ../Resource/Keywords.robot -Library ../Scripts/find_rmr_message.py -Library ../Scripts/find_error_script.py -Test Teardown Start Dbass with 4 dockers - - - -*** Test Cases *** -Verify logs - Reset Sent by simulator - ${Reset}= Grep File ./gnb.log ResetRequest has been sent - Should Be Equal ${Reset} gnbe2_simu: ResetRequest has been sent - -Verify logs for restart received - ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${RIC_X2_RESET_REQ_message_type} ${Meid_test1} - Should Be Equal As Strings ${result} True - -Verify for error on retrying - ${result} find_error_script.find_error ${EXECDIR} ${e2mgr_log_filename} ${failed_to_retrieve_nodeb_message} - Should Be Equal As Strings ${result} True - - -*** Keywords *** -Start Dbass with 4 dockers - Run And Return Rc And Output ${dbass_remove} - Run And Return Rc And Output ${dbass_start} - ${result}= Run And Return Rc And Output ${docker_command} - Should Be Equal As Integers ${result[1]} ${docker_number-1} - Sleep 5s diff --git a/Automation/Tests/X2_Reset_RIC_TO_RAN/Reset_Happy_no_cause.robot b/Automation/Tests/X2_Reset_RIC_TO_RAN/Reset_Happy_no_cause.robot index 83a60cb..3227fe7 100644 --- a/Automation/Tests/X2_Reset_RIC_TO_RAN/Reset_Happy_no_cause.robot +++ b/Automation/Tests/X2_Reset_RIC_TO_RAN/Reset_Happy_no_cause.robot @@ -27,6 +27,7 @@ Resource ../Resource/resource.robot Resource ../Resource/Keywords.robot Library OperatingSystem Library ../Scripts/find_rmr_message.py +Library ../Scripts/rsmscripts.py Library REST ${url} @@ -57,4 +58,8 @@ RAN Restarted messege sent RSM RESOURCE STATUS REQUEST message sent ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test1} - Should Be Equal As Strings ${result} True \ No newline at end of file + Should Be Equal As Strings ${result} True + +Verify RSM RAN info exists in redis + ${result}= rsmscripts.verify_rsm_ran_info_start_false + Should Be Equal As Strings ${result} True \ No newline at end of file diff --git a/Automation/Tests/X2_Reset_RIC_TO_RAN/Reset_Happy_with_cause.robot b/Automation/Tests/X2_Reset_RIC_TO_RAN/Reset_Happy_with_cause.robot index b0c1669..d4103e8 100644 --- a/Automation/Tests/X2_Reset_RIC_TO_RAN/Reset_Happy_with_cause.robot +++ b/Automation/Tests/X2_Reset_RIC_TO_RAN/Reset_Happy_with_cause.robot @@ -27,6 +27,7 @@ Resource ../Resource/resource.robot Resource ../Resource/Keywords.robot Library OperatingSystem Library ../Scripts/find_rmr_message.py +Library ../Scripts/rsmscripts.py Library REST ${url} @@ -58,4 +59,8 @@ RAN Restarted messege sent RSM RESOURCE STATUS REQUEST message sent ${result} find_rmr_message.verify_logs ${EXECDIR} ${rsm_log_filename} ${RIC_RES_STATUS_REQ_message_type_successfully_sent} ${RAN_NAME_test1} - Should Be Equal As Strings ${result} True \ No newline at end of file + Should Be Equal As Strings ${result} True + +Verify RSM RAN info exists in redis + ${result}= rsmscripts.verify_rsm_ran_info_start_false + Should Be Equal As Strings ${result} True \ No newline at end of file diff --git a/E2Manager/Dockerfile b/E2Manager/Dockerfile index 74db25b..4f9561b 100644 --- a/E2Manager/Dockerfile +++ b/E2Manager/Dockerfile @@ -20,17 +20,17 @@ # platform project (RICP). # -FROM nexus3.o-ran-sc.org:10004/bldr-ubuntu16-c-go:2-u16.04-nng as ubuntu +FROM nexus3.o-ran-sc.org:10004/bldr-ubuntu16-c-go:3-u16.04-nng as ubuntu WORKDIR /opt/E2Manager COPY . . ENV PATH=$PATH:/usr/local/go/bin:/usr/lib/go-1.12/bin #RUN git clone https://gerrit.o-ran-sc.org/r/ric-plt/lib/rmr && cd rmr/; mkdir build; cd build; /opt/bin/cmake -DDEV_PKG=1 ..; make install # Install RMr library and dev files -RUN wget --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr_1.10.0_amd64.deb/download.deb -RUN dpkg -i rmr_1.10.0_amd64.deb -RUN wget --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr-dev_1.10.0_amd64.deb/download.deb -RUN dpkg -i rmr-dev_1.10.0_amd64.deb +RUN wget --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr_1.13.0_amd64.deb/download.deb +RUN dpkg -i rmr_1.13.0_amd64.deb +RUN wget --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr-dev_1.13.0_amd64.deb/download.deb +RUN dpkg -i rmr-dev_1.13.0_amd64.deb RUN cd 3rdparty/asn1codec && make RUN go build app/main.go @@ -45,7 +45,8 @@ ENV LD_LIBRARY_PATH=/usr/local/lib # Setting allocfreetrace=1 causes every allocation to be profiled and a stack trace printed on each object's allocation and free. ENV GODEBUG=cgocheck=2,clobberfree=1,gcstoptheworld=2,allocfreetrace=0 ENV RIC_ID="bbbccc-abcd0e/20" -RUN go test ./... +ENV RMR_SEED_RT=/opt/E2Manager/router_test.txt +RUN go-acc $(go list ./... | grep -v e2mgr/mocks | grep -v e2mgr/tests |grep -v e2mgr/e2managererrors| grep -v e2mgr/enums) FROM ubuntu:16.04 diff --git a/E2Manager/app/main.go b/E2Manager/app/main.go index dd0875d..443b7eb 100644 --- a/E2Manager/app/main.go +++ b/E2Manager/app/main.go @@ -21,9 +21,9 @@ package main import ( + "e2mgr/clients" "e2mgr/configuration" "e2mgr/controllers" - "e2mgr/converters" "e2mgr/httpserver" "e2mgr/logger" "e2mgr/managers" @@ -37,12 +37,12 @@ import ( "e2mgr/services/rmrsender" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" + "gerrit.o-ran-sc.org/r/ric-plt/sdlgo" + "net/http" "os" "strconv" ) -const MAX_RNIB_POOL_INSTANCES = 4 - func main() { config := configuration.ParseConfiguration() logLevel, _ := logger.LogLevelTokenToLevel(config.Logging.LogLevel) @@ -51,32 +51,34 @@ func main() { fmt.Printf("#app.main - failed to initialize logger, error: %s", err) os.Exit(1) } - rNibWriter.Init("e2Manager", MAX_RNIB_POOL_INSTANCES) - defer rNibWriter.Close() - reader.Init("e2Manager", MAX_RNIB_POOL_INSTANCES) - defer reader.Close() - rnibDataService := services.NewRnibDataService(logger, config, reader.GetRNibReader, rNibWriter.GetRNibWriter) + db := sdlgo.NewDatabase() + sdl := sdlgo.NewSdlInstance("e2Manager", db) + defer sdl.Close() + rnibDataService := services.NewRnibDataService(logger, config, reader.GetRNibReader(sdl), rNibWriter.GetRNibWriter( sdl)) var msgImpl *rmrCgo.Context rmrMessenger := msgImpl.Init("tcp:"+strconv.Itoa(config.Rmr.Port), config.Rmr.MaxMsgSize, 0, logger) rmrSender := rmrsender.NewRmrSender(logger, rmrMessenger) ranSetupManager := managers.NewRanSetupManager(logger, rmrSender, rnibDataService) - ranReconnectionManager := managers.NewRanReconnectionManager(logger, config, rnibDataService, ranSetupManager) - ranStatusChangeManager := managers.NewRanStatusChangeManager(logger, rmrSender) - x2SetupResponseConverter := converters.NewX2SetupResponseConverter(logger) - x2SetupResponseManager := managers.NewX2SetupResponseManager(x2SetupResponseConverter) - x2SetupFailureResponseConverter := converters.NewX2SetupFailureResponseConverter(logger) - x2SetupFailureResponseManager := managers.NewX2SetupFailureResponseManager(x2SetupFailureResponseConverter) - rmrNotificationHandlerProvider := rmrmsghandlerprovider.NewNotificationHandlerProvider(logger, rnibDataService, ranReconnectionManager, ranStatusChangeManager, rmrSender, x2SetupResponseManager, x2SetupFailureResponseManager) + e2tInstancesManager := managers.NewE2TInstancesManager(rnibDataService, logger) + e2tShutdownManager := managers.NewE2TShutdownManager(logger, rnibDataService, e2tInstancesManager) + e2tKeepAliveWorker := managers.NewE2TKeepAliveWorker(logger, rmrSender, e2tInstancesManager, e2tShutdownManager, config) + routingManagerClient := clients.NewRoutingManagerClient(logger, config, &http.Client{}) + rmrNotificationHandlerProvider := rmrmsghandlerprovider.NewNotificationHandlerProvider() + rmrNotificationHandlerProvider.Init(logger, config, rnibDataService, rmrSender, ranSetupManager, e2tInstancesManager, routingManagerClient) notificationManager := notificationmanager.NewNotificationManager(logger, rmrNotificationHandlerProvider) rmrReceiver := rmrreceiver.NewRmrReceiver(logger, rmrMessenger, notificationManager) - defer (*rmrMessenger).Close() + e2tInstancesManager.ResetKeepAliveTimestampsForAllE2TInstances() + + defer rmrMessenger.Close() go rmrReceiver.ListenAndHandle() + go e2tKeepAliveWorker.Execute() - httpMsgHandlerProvider := httpmsghandlerprovider.NewIncomingRequestHandlerProvider(logger, rmrSender, config, rnibDataService, ranSetupManager) + httpMsgHandlerProvider := httpmsghandlerprovider.NewIncomingRequestHandlerProvider(logger, rmrSender, config, rnibDataService, ranSetupManager, e2tInstancesManager) rootController := controllers.NewRootController(rnibDataService) nodebController := controllers.NewNodebController(logger, httpMsgHandlerProvider) - httpserver.Run(config.Http.Port, rootController, nodebController) -} + e2tController := controllers.NewE2TController(logger, httpMsgHandlerProvider) + _ = httpserver.Run(logger, config.Http.Port, rootController, nodebController, e2tController) +} \ No newline at end of file diff --git a/E2Manager/clients/http_client.go b/E2Manager/clients/http_client.go new file mode 100644 index 0000000..e3692f5 --- /dev/null +++ b/E2Manager/clients/http_client.go @@ -0,0 +1,30 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + + +package clients + +import ( + "io" + "net/http" +) + +type HttpClient interface { + Post(url, contentType string, body io.Reader) (resp *http.Response, err error) +} \ No newline at end of file diff --git a/E2Manager/clients/routing_manager_client.go b/E2Manager/clients/routing_manager_client.go new file mode 100644 index 0000000..c584f5b --- /dev/null +++ b/E2Manager/clients/routing_manager_client.go @@ -0,0 +1,108 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +package clients + +import ( + "bytes" + "e2mgr/configuration" + "e2mgr/e2managererrors" + "e2mgr/logger" + "e2mgr/models" + "encoding/json" + "net/http" +) + +const ( + AddE2TInstanceApiSuffix = "e2t" + AssociateRanToE2TInstanceApiSuffix = "associate-ran-to-e2t" + DissociateRanE2TInstanceApiSuffix = "dissociate-ran" +) + +type RoutingManagerClient struct { + logger *logger.Logger + config *configuration.Configuration + httpClient HttpClient +} + +type IRoutingManagerClient interface { + AddE2TInstance(e2tAddress string) error + AssociateRanToE2TInstance(e2tAddress string, ranName string) error + DissociateRanE2TInstance(e2tAddress string, ranName string) error +} + +func NewRoutingManagerClient(logger *logger.Logger, config *configuration.Configuration, httpClient HttpClient) *RoutingManagerClient { + return &RoutingManagerClient{ + logger: logger, + config: config, + httpClient: httpClient, + } +} + +func (c *RoutingManagerClient) AddE2TInstance(e2tAddress string) error { + + data := models.NewRoutingManagerE2TData(e2tAddress) + url := c.config.RoutingManager.BaseUrl + AddE2TInstanceApiSuffix + + return c.PostMessage(data, url) +} + +func (c *RoutingManagerClient) AssociateRanToE2TInstance(e2tAddress string, ranName string) error { + + data := models.NewRoutingManagerE2TData(e2tAddress, ranName) + url := c.config.RoutingManager.BaseUrl + AssociateRanToE2TInstanceApiSuffix + + return c.PostMessage(data, url) +} + +func (c *RoutingManagerClient) DissociateRanE2TInstance(e2tAddress string, ranName string) error { + + data := models.NewRoutingManagerE2TData(e2tAddress, ranName) + url := c.config.RoutingManager.BaseUrl + DissociateRanE2TInstanceApiSuffix + + return c.PostMessage(data, url) +} + +func (c *RoutingManagerClient) PostMessage(data *models.RoutingManagerE2TData, url string) error { + marshaled, err := json.Marshal(data) + + if err != nil { + return e2managererrors.NewRoutingManagerError() + } + + body := bytes.NewBuffer(marshaled) + c.logger.Infof("[E2M -> Routing Manager] #RoutingManagerClient.PostMessage - url: %s, request body: %+v", url, body) + + resp, err := c.httpClient.Post(url, "application/json", body) + + if err != nil { + c.logger.Errorf("#RoutingManagerClient.PostMessage - failed sending request. error: %s", err) + return e2managererrors.NewRoutingManagerError() + } + + defer resp.Body.Close() + + if resp.StatusCode >= http.StatusOK && resp.StatusCode < http.StatusMultipleChoices { + c.logger.Infof("[Routing Manager -> E2M] #RoutingManagerClient.PostMessage - success. http status code: %d", resp.StatusCode) + return nil + } + + c.logger.Errorf("[Routing Manager -> E2M] #RoutingManagerClient.PostMessage - failure. http status code: %d", resp.StatusCode) + return e2managererrors.NewRoutingManagerError() +} \ No newline at end of file diff --git a/E2Manager/clients/routing_manager_client_test.go b/E2Manager/clients/routing_manager_client_test.go new file mode 100644 index 0000000..2d02cfd --- /dev/null +++ b/E2Manager/clients/routing_manager_client_test.go @@ -0,0 +1,180 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + + +package clients + +import ( + "bytes" + "e2mgr/configuration" + "e2mgr/logger" + "e2mgr/mocks" + "e2mgr/models" + "encoding/json" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "io/ioutil" + "net/http" + "testing" +) + +const E2TAddress = "10.0.2.15:38000" +const RanName = "test1" + + +func initRoutingManagerClientTest(t *testing.T) (*RoutingManagerClient, *mocks.HttpClientMock, *configuration.Configuration) { + logger := initLog(t) + config := &configuration.Configuration{} + config.RoutingManager.BaseUrl = "http://iltlv740.intl.att.com:8080/ric/v1/handles/" + httpClientMock := &mocks.HttpClientMock{} + rmClient := NewRoutingManagerClient(logger, config, httpClientMock) + return rmClient, httpClientMock, config +} + +func TestAddE2TInstanceSuccess(t *testing.T) { + rmClient, httpClientMock, config := initRoutingManagerClientTest(t) + + data := models.NewRoutingManagerE2TData(E2TAddress) + marshaled, _ := json.Marshal(data) + body := bytes.NewBuffer(marshaled) + url := config.RoutingManager.BaseUrl + "e2t" + respBody := ioutil.NopCloser(bytes.NewBufferString("")) + httpClientMock.On("Post", url, "application/json", body).Return(&http.Response{StatusCode: http.StatusCreated, Body: respBody}, nil) + err := rmClient.AddE2TInstance(E2TAddress) + assert.Nil(t, err) +} + +func TestAddE2TInstanceHttpPostFailure(t *testing.T) { + rmClient, httpClientMock, config := initRoutingManagerClientTest(t) + + data := models.NewRoutingManagerE2TData(E2TAddress) + marshaled, _ := json.Marshal(data) + body := bytes.NewBuffer(marshaled) + url := config.RoutingManager.BaseUrl + "e2t" + httpClientMock.On("Post", url, "application/json", body).Return(&http.Response{}, errors.New("error")) + err := rmClient.AddE2TInstance(E2TAddress) + assert.NotNil(t, err) +} + +func TestAddE2TInstanceFailure(t *testing.T) { + rmClient, httpClientMock, config := initRoutingManagerClientTest(t) + + data := models.NewRoutingManagerE2TData(E2TAddress) + marshaled, _ := json.Marshal(data) + body := bytes.NewBuffer(marshaled) + url := config.RoutingManager.BaseUrl + "e2t" + respBody := ioutil.NopCloser(bytes.NewBufferString("")) + httpClientMock.On("Post", url, "application/json", body).Return(&http.Response{StatusCode: http.StatusBadRequest, Body:respBody}, nil) + err := rmClient.AddE2TInstance(E2TAddress) + assert.NotNil(t, err) +} + +func TestAssociateRanToE2TInstance_Success(t *testing.T) { + rmClient, httpClientMock, config := initRoutingManagerClientTest(t) + + data := models.NewRoutingManagerE2TData(E2TAddress,RanName) + marshaled, _ := json.Marshal(data) + body := bytes.NewBuffer(marshaled) + url := config.RoutingManager.BaseUrl + AssociateRanToE2TInstanceApiSuffix + respBody := ioutil.NopCloser(bytes.NewBufferString("")) + httpClientMock.On("Post", url, "application/json", body).Return(&http.Response{StatusCode: http.StatusCreated, Body: respBody}, nil) + err := rmClient.AssociateRanToE2TInstance(E2TAddress, RanName) + assert.Nil(t, err) +} + +func TestAssociateRanToE2TInstance_RoutingManagerError(t *testing.T) { + rmClient, httpClientMock, config := initRoutingManagerClientTest(t) + + data := models.NewRoutingManagerE2TData(E2TAddress,RanName) + marshaled, _ := json.Marshal(data) + body := bytes.NewBuffer(marshaled) + url := config.RoutingManager.BaseUrl + AssociateRanToE2TInstanceApiSuffix + httpClientMock.On("Post", url, "application/json", body).Return(&http.Response{}, errors.New("error")) + err := rmClient.AssociateRanToE2TInstance(E2TAddress, RanName) + assert.NotNil(t, err) +} + +func TestAssociateRanToE2TInstance_RoutingManager_400(t *testing.T) { + rmClient, httpClientMock, config := initRoutingManagerClientTest(t) + + data := models.NewRoutingManagerE2TData(E2TAddress,RanName) + marshaled, _ := json.Marshal(data) + body := bytes.NewBuffer(marshaled) + url := config.RoutingManager.BaseUrl + AssociateRanToE2TInstanceApiSuffix + respBody := ioutil.NopCloser(bytes.NewBufferString("")) + httpClientMock.On("Post", url, "application/json", body).Return(&http.Response{StatusCode: http.StatusBadRequest, Body:respBody}, nil) + err := rmClient.AssociateRanToE2TInstance(E2TAddress, RanName) + assert.NotNil(t, err) +} + +func TestDissociateRanE2TInstance_Success(t *testing.T) { + rmClient, httpClientMock, config := initRoutingManagerClientTest(t) + + data := models.NewRoutingManagerE2TData(E2TAddress,RanName) + marshaled, _ := json.Marshal(data) + body := bytes.NewBuffer(marshaled) + url := config.RoutingManager.BaseUrl + DissociateRanE2TInstanceApiSuffix + respBody := ioutil.NopCloser(bytes.NewBufferString("")) + httpClientMock.On("Post", url, "application/json", body).Return(&http.Response{StatusCode: http.StatusCreated, Body: respBody}, nil) + err := rmClient.DissociateRanE2TInstance(E2TAddress, RanName) + assert.Nil(t, err) +} + +func TestDissociateRanE2TInstance_RoutingManagerError(t *testing.T) { + rmClient, httpClientMock, config := initRoutingManagerClientTest(t) + + data := models.NewRoutingManagerE2TData(E2TAddress,RanName) + marshaled, _ := json.Marshal(data) + body := bytes.NewBuffer(marshaled) + url := config.RoutingManager.BaseUrl + DissociateRanE2TInstanceApiSuffix + httpClientMock.On("Post", url, "application/json", body).Return(&http.Response{}, errors.New("error")) + err := rmClient.DissociateRanE2TInstance(E2TAddress, RanName) + assert.NotNil(t, err) +} + +func TestDissociateRanE2TInstance_RoutingManager_400(t *testing.T) { + rmClient, httpClientMock, config := initRoutingManagerClientTest(t) + + data := models.NewRoutingManagerE2TData(E2TAddress,RanName) + marshaled, _ := json.Marshal(data) + body := bytes.NewBuffer(marshaled) + url := config.RoutingManager.BaseUrl + DissociateRanE2TInstanceApiSuffix + respBody := ioutil.NopCloser(bytes.NewBufferString("")) + httpClientMock.On("Post", url, "application/json", body).Return(&http.Response{StatusCode: http.StatusBadRequest, Body:respBody}, nil) + err := rmClient.DissociateRanE2TInstance(E2TAddress, RanName) + assert.NotNil(t, err) +} + +// TODO: extract to test_utils +func initLog(t *testing.T) *logger.Logger { + log, err := logger.InitLogger(logger.InfoLevel) + if err != nil { + t.Errorf("#delete_all_request_handler_test.TestHandleSuccessFlow - failed to initialize logger, error: %s", err) + } + return log +} + +//func TestAddE2TInstanceInteg(t *testing.T) { +// logger := initLog(t) +// config := configuration.ParseConfiguration() +// httpClient := &http.Client{} +// rmClient := NewRoutingManagerClient(logger, config, httpClient) +// err := rmClient.AddE2TInstance(E2TAddress) +// assert.Nil(t, err) +//} diff --git a/E2Manager/configuration/configuration.go b/E2Manager/configuration/configuration.go index 43fbd71..d37c497 100644 --- a/E2Manager/configuration/configuration.go +++ b/E2Manager/configuration/configuration.go @@ -36,19 +36,24 @@ type Configuration struct { Port int MaxMsgSize int } - NotificationResponseBuffer int - BigRedButtonTimeoutSec int - MaxConnectionAttempts int - MaxRnibConnectionAttempts int - RnibRetryIntervalMs int + RoutingManager struct { + BaseUrl string + } + NotificationResponseBuffer int + BigRedButtonTimeoutSec int + MaxConnectionAttempts int + MaxRnibConnectionAttempts int + RnibRetryIntervalMs int + KeepAliveResponseTimeoutMs int + KeepAliveDelayMs int } -func ParseConfiguration() *Configuration{ +func ParseConfiguration() *Configuration { viper.SetConfigType("yaml") viper.SetConfigName("configuration") viper.AddConfigPath("E2Manager/resources/") - viper.AddConfigPath("./resources/") //For production - viper.AddConfigPath("../resources/") //For test under Docker + viper.AddConfigPath("./resources/") //For production + viper.AddConfigPath("../resources/") //For test under Docker viper.AddConfigPath("../../resources/") //For test under Docker err := viper.ReadInConfig() if err != nil { @@ -56,37 +61,45 @@ func ParseConfiguration() *Configuration{ } config := Configuration{} - config.fillRmrConfig(viper.Sub("rmr")) - config.fillHttpConfig(viper.Sub("http")) - config.fillLoggingConfig(viper.Sub("logging")) - + config.populateRmrConfig(viper.Sub("rmr")) + config.populateHttpConfig(viper.Sub("http")) + config.populateLoggingConfig(viper.Sub("logging")) + config.populateRoutingManagerConfig(viper.Sub("routingManager")) config.NotificationResponseBuffer = viper.GetInt("notificationResponseBuffer") config.BigRedButtonTimeoutSec = viper.GetInt("bigRedButtonTimeoutSec") config.MaxConnectionAttempts = viper.GetInt("maxConnectionAttempts") config.MaxRnibConnectionAttempts = viper.GetInt("maxRnibConnectionAttempts") config.RnibRetryIntervalMs = viper.GetInt("rnibRetryIntervalMs") + config.KeepAliveResponseTimeoutMs = viper.GetInt("keepAliveResponseTimeoutMs") + config.KeepAliveDelayMs = viper.GetInt("KeepAliveDelayMs") return &config } -func (c *Configuration)fillLoggingConfig(logConfig *viper.Viper) { +func (c *Configuration) populateLoggingConfig(logConfig *viper.Viper) { if logConfig == nil { - panic(fmt.Sprintf("#configuration.fillLoggingConfig - failed to fill logging configuration: The entry 'logging' not found\n")) + panic(fmt.Sprintf("#configuration.populateLoggingConfig - failed to populate logging configuration: The entry 'logging' not found\n")) } c.Logging.LogLevel = logConfig.GetString("logLevel") } -func (c *Configuration)fillHttpConfig(httpConfig *viper.Viper) { +func (c *Configuration) populateHttpConfig(httpConfig *viper.Viper) { if httpConfig == nil { - panic(fmt.Sprintf("#configuration.fillHttpConfig - failed to fill HTTP configuration: The entry 'http' not found\n")) + panic(fmt.Sprintf("#configuration.populateHttpConfig - failed to populate HTTP configuration: The entry 'http' not found\n")) } c.Http.Port = httpConfig.GetInt("port") } -func (c *Configuration)fillRmrConfig(rmrConfig *viper.Viper) { +func (c *Configuration) populateRmrConfig(rmrConfig *viper.Viper) { if rmrConfig == nil { - panic(fmt.Sprintf("#configuration.fillRmrConfig - failed to fill RMR configuration: The entry 'rmr' not found\n")) + panic(fmt.Sprintf("#configuration.populateRmrConfig - failed to populate RMR configuration: The entry 'rmr' not found\n")) } c.Rmr.Port = rmrConfig.GetInt("port") c.Rmr.MaxMsgSize = rmrConfig.GetInt("maxMsgSize") } +func (c *Configuration) populateRoutingManagerConfig(rmConfig *viper.Viper) { + if rmConfig == nil { + panic(fmt.Sprintf("#configuration.populateRoutingManagerConfig - failed to populate Routing Manager configuration: The entry 'routingManager' not found\n")) + } + c.RoutingManager.BaseUrl = rmConfig.GetString("baseUrl") +} diff --git a/E2Manager/configuration/configuration_test.go b/E2Manager/configuration/configuration_test.go index e1c5088..ec16c1f 100644 --- a/E2Manager/configuration/configuration_test.go +++ b/E2Manager/configuration/configuration_test.go @@ -36,6 +36,8 @@ func TestParseConfigurationSuccess(t *testing.T) { assert.Equal(t, "info", config.Logging.LogLevel) assert.Equal(t, 100, config.NotificationResponseBuffer) assert.Equal(t, 5, config.BigRedButtonTimeoutSec) + assert.Equal(t, 1500, config.KeepAliveResponseTimeoutMs) + assert.Equal(t, 500, config.KeepAliveDelayMs) } func TestParseConfigurationFileNotFoundFailure(t *testing.T) { @@ -70,6 +72,7 @@ func TestRmrConfigNotFoundFailure(t *testing.T) { yamlMap := map[string]interface{}{ "logging": map[string]interface{}{"logLevel": "info"}, "http": map[string]interface{}{"port": 3800}, + "routingManager": map[string]interface{}{"baseUrl": "http://iltlv740.intl.att.com:8080/ric/v1/handles/"}, } buf, err := yaml.Marshal(yamlMap) if err != nil { @@ -79,7 +82,7 @@ func TestRmrConfigNotFoundFailure(t *testing.T) { if err != nil { t.Errorf("#TestRmrConfigNotFoundFailure - failed to write configuration file: %s\n", configPath) } - assert.PanicsWithValue(t, "#configuration.fillRmrConfig - failed to fill RMR configuration: The entry 'rmr' not found\n", func() { ParseConfiguration() }) + assert.PanicsWithValue(t, "#configuration.populateRmrConfig - failed to populate RMR configuration: The entry 'rmr' not found\n", func() { ParseConfiguration() }) } func TestLoggingConfigNotFoundFailure(t *testing.T) { @@ -98,6 +101,7 @@ func TestLoggingConfigNotFoundFailure(t *testing.T) { yamlMap := map[string]interface{}{ "rmr": map[string]interface{}{"port": 3801, "maxMsgSize": 4096}, "http": map[string]interface{}{"port": 3800}, + "routingManager": map[string]interface{}{"baseUrl": "http://iltlv740.intl.att.com:8080/ric/v1/handles/"}, } buf, err := yaml.Marshal(yamlMap) if err != nil { @@ -107,7 +111,7 @@ func TestLoggingConfigNotFoundFailure(t *testing.T) { if err != nil { t.Errorf("#TestRmrConfigNotFoundFailure - failed to write configuration file: %s\n", configPath) } - assert.PanicsWithValue(t, "#configuration.fillLoggingConfig - failed to fill logging configuration: The entry 'logging' not found\n", + assert.PanicsWithValue(t, "#configuration.populateLoggingConfig - failed to populate logging configuration: The entry 'logging' not found\n", func() { ParseConfiguration() }) } @@ -127,6 +131,7 @@ func TestHttpConfigNotFoundFailure(t *testing.T) { yamlMap := map[string]interface{}{ "rmr": map[string]interface{}{"port": 3801, "maxMsgSize": 4096}, "logging": map[string]interface{}{"logLevel": "info"}, + "routingManager": map[string]interface{}{"baseUrl": "http://iltlv740.intl.att.com:8080/ric/v1/handles/"}, } buf, err := yaml.Marshal(yamlMap) if err != nil { @@ -136,6 +141,36 @@ func TestHttpConfigNotFoundFailure(t *testing.T) { if err != nil { t.Errorf("#TestHttpConfigNotFoundFailure - failed to write configuration file: %s\n", configPath) } - assert.PanicsWithValue(t, "#configuration.fillHttpConfig - failed to fill HTTP configuration: The entry 'http' not found\n", + assert.PanicsWithValue(t, "#configuration.populateHttpConfig - failed to populate HTTP configuration: The entry 'http' not found\n", + func() { ParseConfiguration() }) +} + +func TestRoutingManagerConfigNotFoundFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestRoutingManagerConfigNotFoundFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestRoutingManagerConfigNotFoundFailure - failed to rename configuration file: %s\n", configPath) + } + }() + yamlMap := map[string]interface{}{ + "rmr": map[string]interface{}{"port": 3801, "maxMsgSize": 4096}, + "logging": map[string]interface{}{"logLevel": "info"}, + "http": map[string]interface{}{"port": 3800}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestRoutingManagerConfigNotFoundFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestRoutingManagerConfigNotFoundFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.populateRoutingManagerConfig - failed to populate Routing Manager configuration: The entry 'routingManager' not found\n", func() { ParseConfiguration() }) } diff --git a/E2Manager/container-tag.yaml b/E2Manager/container-tag.yaml index feb9ae0..d5f8e1e 100644 --- a/E2Manager/container-tag.yaml +++ b/E2Manager/container-tag.yaml @@ -1,4 +1,4 @@ # The Jenkins job requires a tag to build the Docker image. # Global-JJB script assumes this file is in the repo root. --- -tag: 2.0.10 +tag: 3.0.3 diff --git a/E2Manager/controllers/e2t_controller.go b/E2Manager/controllers/e2t_controller.go new file mode 100644 index 0000000..2d95542 --- /dev/null +++ b/E2Manager/controllers/e2t_controller.go @@ -0,0 +1,121 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package controllers + +import ( + "e2mgr/e2managererrors" + "e2mgr/logger" + "e2mgr/models" + "e2mgr/providers/httpmsghandlerprovider" + "encoding/json" + "net/http" + "net/http/httputil" + "strings" +) + +type IE2TController interface { + GetE2TInstances(writer http.ResponseWriter, r *http.Request) +} + +type E2TController struct { + logger *logger.Logger + handlerProvider *httpmsghandlerprovider.IncomingRequestHandlerProvider +} + +func NewE2TController(logger *logger.Logger, handlerProvider *httpmsghandlerprovider.IncomingRequestHandlerProvider) *E2TController { + return &E2TController{ + logger: logger, + handlerProvider: handlerProvider, + } +} + +func (c *E2TController) GetE2TInstances(writer http.ResponseWriter, r *http.Request) { + c.logger.Infof("[Client -> E2 Manager] #E2TController.GetE2TInstances - request: %v", c.prettifyRequest(r)) + c.handleRequest(writer, &r.Header, httpmsghandlerprovider.GetE2TInstancesRequest, nil, false) +} + +func (c *E2TController) handleRequest(writer http.ResponseWriter, header *http.Header, requestName httpmsghandlerprovider.IncomingRequest, request models.Request, validateHeader bool) { + + handler, err := c.handlerProvider.GetHandler(requestName) + + if err != nil { + c.handleErrorResponse(err, writer) + return + } + + response, err := handler.Handle(request) + + if err != nil { + c.handleErrorResponse(err, writer) + return + } + + if response == nil { + writer.WriteHeader(http.StatusNoContent) + c.logger.Infof("[E2 Manager -> Client] #E2TController.handleRequest - status response: %v", http.StatusNoContent) + return + } + + result, err := response.Marshal() + + if err != nil { + c.handleErrorResponse(err, writer) + return + } + + c.logger.Infof("[E2 Manager -> Client] #E2TController.handleRequest - response: %s", result) + writer.Header().Set("Content-Type", "application/json") + writer.Write(result) +} + +func (c *E2TController) handleErrorResponse(err error, writer http.ResponseWriter) { + + var errorResponseDetails models.ErrorResponse + var httpError int + + if err != nil { + switch err.(type) { + case *e2managererrors.RnibDbError: + e2Error, _ := err.(*e2managererrors.RnibDbError) + errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message} + httpError = http.StatusInternalServerError + default: + e2Error := e2managererrors.NewInternalError() + errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message} + httpError = http.StatusInternalServerError + } + } + + errorResponse, _ := json.Marshal(errorResponseDetails) + + c.logger.Errorf("[E2 Manager -> Client] #E2TController.handleErrorResponse - http status: %d, error response: %+v", httpError, errorResponseDetails) + + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(httpError) + _, err = writer.Write(errorResponse) + + if err != nil { + c.logger.Errorf("#E2TController.handleErrorResponse - Cannot send response. writer:%v", writer) + } +} + +func (c *E2TController) prettifyRequest(request *http.Request) string { + dump, _ := httputil.DumpRequest(request, true) + requestPrettyPrint := strings.Replace(string(dump), "\r\n", " ", -1) + return strings.Replace(requestPrettyPrint, "\n", "", -1) +} diff --git a/E2Manager/controllers/nodeb_controller.go b/E2Manager/controllers/nodeb_controller.go index 912b4a9..cbfa7d6 100644 --- a/E2Manager/controllers/nodeb_controller.go +++ b/E2Manager/controllers/nodeb_controller.go @@ -176,7 +176,7 @@ func (c *NodebController) handleRequest(writer http.ResponseWriter, header *http c.logger.Infof("[E2 Manager -> Client] #NodebController.handleRequest - response: %s", result) writer.Header().Set("Content-Type", "application/json") - writer.Write([]byte(result)) + writer.Write(result) } func (c *NodebController) validateRequestHeader(header *http.Header) error { @@ -228,7 +228,10 @@ func (c *NodebController) handleErrorResponse(err error, writer http.ResponseWri e2Error, _ := err.(*e2managererrors.ResourceNotFoundError) errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message} httpError = http.StatusNotFound - + case *e2managererrors.E2TInstanceAbsenceError: + e2Error, _ := err.(*e2managererrors.E2TInstanceAbsenceError) + errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message} + httpError = http.StatusServiceUnavailable default: e2Error := e2managererrors.NewInternalError() errorResponseDetails = models.ErrorResponse{Code: e2Error.Code, Message: e2Error.Message} diff --git a/E2Manager/controllers/nodeb_controller_test.go b/E2Manager/controllers/nodeb_controller_test.go index 47b217b..f819138 100644 --- a/E2Manager/controllers/nodeb_controller_test.go +++ b/E2Manager/controllers/nodeb_controller_test.go @@ -30,7 +30,6 @@ import ( "e2mgr/mocks" "e2mgr/models" "e2mgr/providers/httpmsghandlerprovider" - "e2mgr/rNibWriter" "e2mgr/rmrCgo" "e2mgr/services" "e2mgr/services/rmrsender" @@ -39,7 +38,6 @@ import ( "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/gorilla/mux" "github.com/pkg/errors" "github.com/stretchr/testify/assert" @@ -67,30 +65,27 @@ type controllerGetNodebIdListTestContext struct { expectedJsonResponse string } -func setupControllerTest(t *testing.T) (*NodebController, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.RmrMessengerMock) { +func setupControllerTest(t *testing.T) (*NodebController, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.RmrMessengerMock, *mocks.E2TInstancesManagerMock) { log := initLog(t) config := configuration.ParseConfiguration() rmrMessengerMock := &mocks.RmrMessengerMock{} readerMock := &mocks.RnibReaderMock{} - readerProvider := func() reader.RNibReader { - return readerMock - } + writerMock := &mocks.RnibWriterMock{} - writerProvider := func() rNibWriter.RNibWriter { - return writerMock - } - rnibDataService := services.NewRnibDataService(log, config, readerProvider, writerProvider) + + rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock) rmrSender := getRmrSender(rmrMessengerMock, log) ranSetupManager := managers.NewRanSetupManager(log, rmrSender, rnibDataService) - handlerProvider := httpmsghandlerprovider.NewIncomingRequestHandlerProvider(log, rmrSender, config, rnibDataService, ranSetupManager) + e2tInstancesManager := &mocks.E2TInstancesManagerMock{} + handlerProvider := httpmsghandlerprovider.NewIncomingRequestHandlerProvider(log, rmrSender, config, rnibDataService, ranSetupManager, e2tInstancesManager) controller := NewNodebController(log, handlerProvider) - return controller, readerMock, writerMock, rmrMessengerMock + return controller, readerMock, writerMock, rmrMessengerMock, e2tInstancesManager } func TestX2SetupInvalidBody(t *testing.T) { - controller, _, _, _ := setupControllerTest(t) + controller, _, _, _, _ := setupControllerTest(t) header := http.Header{} header.Set("Content-Type", "application/json") @@ -108,20 +103,23 @@ func TestX2SetupInvalidBody(t *testing.T) { func TestX2SetupSuccess(t *testing.T) { - controller, readerMock, writerMock, rmrMessengerMock := setupControllerTest(t) + controller, readerMock, writerMock, rmrMessengerMock, _ := setupControllerTest(t) ranName := "test" - nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} + nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, AssociatedE2TInstanceAddress:"10.0.2.15:8989"} readerMock.On("GetNodeb", ranName).Return(nb, nil) + var nbUpdated = *nb + nbUpdated.ConnectionAttempts = 0 + writerMock.On("UpdateNodebInfo", &nbUpdated).Return(nil) - var nbUpdated = &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, ConnectionAttempts: 1} - writerMock.On("UpdateNodebInfo", nbUpdated).Return(nil) + var nbUpdated2 = &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, ConnectionAttempts: 1, AssociatedE2TInstanceAddress:"10.0.2.15:8989"} + writerMock.On("UpdateNodebInfo", nbUpdated2).Return(nil) payload := e2pdus.PackedX2setupRequest - xaction := []byte(ranName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction) + var xAction []byte + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil) header := http.Header{} header.Set("Content-Type", "application/json") @@ -134,22 +132,26 @@ func TestX2SetupSuccess(t *testing.T) { assert.Equal(t, http.StatusNoContent, writer.Result().StatusCode) } + func TestEndcSetupSuccess(t *testing.T) { - controller, readerMock, writerMock, rmrMessengerMock := setupControllerTest(t) + controller, readerMock, writerMock, rmrMessengerMock, _ := setupControllerTest(t) ranName := "test" - nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST} + nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, AssociatedE2TInstanceAddress:"10.0.2.15:8989"} readerMock.On("GetNodeb", ranName).Return(nb, nil) + var nbUpdated = *nb + nbUpdated.ConnectionAttempts = 0 + writerMock.On("UpdateNodebInfo", &nbUpdated).Return(nil) - var nbUpdated = &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, ConnectionAttempts: 1} - writerMock.On("UpdateNodebInfo", nbUpdated).Return(nil) + var nbUpdated2 = &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, ConnectionAttempts: 1, AssociatedE2TInstanceAddress:"10.0.2.15:8989"} + writerMock.On("UpdateNodebInfo", nbUpdated2).Return(nil) payload := e2pdus.PackedEndcX2setupRequest - xaction := []byte(ranName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction) + var xAction[]byte + msg := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_X2_SETUP_REQ, len(payload), ranName, &payload, &xAction) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil) header := http.Header{} header.Set("Content-Type", "application/json") @@ -163,7 +165,7 @@ func TestEndcSetupSuccess(t *testing.T) { } func TestShutdownHandlerRnibError(t *testing.T) { - controller, readerMock, _, _ := setupControllerTest(t) + controller, readerMock, _, _, _ := setupControllerTest(t) rnibErr := &common.ResourceNotFoundError{} var nbIdentityList []*entities.NbIdentity @@ -180,7 +182,7 @@ func TestShutdownHandlerRnibError(t *testing.T) { } func controllerGetNodebTestExecuter(t *testing.T, context *controllerGetNodebTestContext) { - controller, readerMock, _, _ := setupControllerTest(t) + controller, readerMock, _, _, _ := setupControllerTest(t) writer := httptest.NewRecorder() readerMock.On("GetNodeb", context.ranName).Return(context.nodebInfo, context.rnibError) req, _ := http.NewRequest("GET", "/nodeb", nil) @@ -192,7 +194,7 @@ func controllerGetNodebTestExecuter(t *testing.T, context *controllerGetNodebTes } func controllerGetNodebIdListTestExecuter(t *testing.T, context *controllerGetNodebIdListTestContext) { - controller, readerMock, _, _ := setupControllerTest(t) + controller, readerMock, _, _, _ := setupControllerTest(t) writer := httptest.NewRecorder() readerMock.On("GetListNodebIds").Return(context.nodebIdList, context.rnibError) req, _ := http.NewRequest("GET", "/nodeb/ids", nil) @@ -289,7 +291,7 @@ func TestControllerGetNodebIdListInternal(t *testing.T) { } func TestHeaderValidationFailed(t *testing.T) { - controller, _, _, _ := setupControllerTest(t) + controller, _, _, _, _ := setupControllerTest(t) writer := httptest.NewRecorder() @@ -306,7 +308,7 @@ func TestHeaderValidationFailed(t *testing.T) { } func TestShutdownStatusNoContent(t *testing.T) { - controller, readerMock, _, _ := setupControllerTest(t) + controller, readerMock, _, _, _ := setupControllerTest(t) var rnibError error nbIdentityList := []*entities.NbIdentity{} @@ -319,7 +321,7 @@ func TestShutdownStatusNoContent(t *testing.T) { } func TestHandleInternalError(t *testing.T) { - controller, _, _, _ := setupControllerTest(t) + controller, _, _, _, _ := setupControllerTest(t) writer := httptest.NewRecorder() err := e2managererrors.NewInternalError() @@ -333,7 +335,7 @@ func TestHandleInternalError(t *testing.T) { } func TestHandleCommandAlreadyInProgressError(t *testing.T) { - controller, _, _, _ := setupControllerTest(t) + controller, _, _, _, _ := setupControllerTest(t) writer := httptest.NewRecorder() err := e2managererrors.NewCommandAlreadyInProgressError() @@ -345,8 +347,22 @@ func TestHandleCommandAlreadyInProgressError(t *testing.T) { assert.Equal(t, errorResponse.Message, err.Message) } +func TestHandleE2TInstanceAbsenceError(t *testing.T) { + controller, _, _, _, _ := setupControllerTest(t) + + writer := httptest.NewRecorder() + err := e2managererrors.NewE2TInstanceAbsenceError() + + controller.handleErrorResponse(err, writer) + var errorResponse = parseJsonRequest(t, writer.Body) + + assert.Equal(t, http.StatusServiceUnavailable, writer.Result().StatusCode) + assert.Equal(t, errorResponse.Code, err.Code) + assert.Equal(t, errorResponse.Message, err.Message) +} + func TestValidateHeaders(t *testing.T) { - controller, _, _, _ := setupControllerTest(t) + controller, _, _, _, _ := setupControllerTest(t) header := http.Header{} header.Set("Content-Type", "application/json") @@ -376,12 +392,12 @@ func initLog(t *testing.T) *logger.Logger { } func TestX2ResetHandleSuccessfulRequestedCause(t *testing.T) { - controller, readerMock, _, rmrMessengerMock := setupControllerTest(t) + controller, readerMock, _, rmrMessengerMock, _ := setupControllerTest(t) ranName := "test1" payload := []byte{0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x40} - xaction := []byte(ranName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xaction) + var xAction []byte + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xAction) rmrMessengerMock.On("SendMsg", msg, mock.Anything).Return(msg, nil) writer := httptest.NewRecorder() @@ -401,14 +417,14 @@ func TestX2ResetHandleSuccessfulRequestedCause(t *testing.T) { } func TestX2ResetHandleSuccessfulRequestedDefault(t *testing.T) { - controller, readerMock, _, rmrMessengerMock := setupControllerTest(t) + controller, readerMock, _, rmrMessengerMock, _ := setupControllerTest(t) ranName := "test1" // o&m intervention payload := []byte{0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x64} - xaction := []byte(ranName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", msg).Return(msg, nil) + var xAction []byte + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xAction) + rmrMessengerMock.On("SendMsg", msg, true).Return(msg, nil) writer := httptest.NewRecorder() @@ -426,7 +442,7 @@ func TestX2ResetHandleSuccessfulRequestedDefault(t *testing.T) { } func TestX2ResetHandleFailureInvalidBody(t *testing.T) { - controller, _, _, _ := setupControllerTest(t) + controller, _, _, _ , _:= setupControllerTest(t) ranName := "test1" @@ -443,7 +459,7 @@ func TestX2ResetHandleFailureInvalidBody(t *testing.T) { } func TestHandleErrorResponse(t *testing.T) { - controller, _, _, _ := setupControllerTest(t) + controller, _, _, _ , _:= setupControllerTest(t) writer := httptest.NewRecorder() controller.handleErrorResponse(e2managererrors.NewRnibDbError(), writer) @@ -481,5 +497,5 @@ func TestHandleErrorResponse(t *testing.T) { func getRmrSender(rmrMessengerMock *mocks.RmrMessengerMock, log *logger.Logger) *rmrsender.RmrSender { rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock) rmrMessengerMock.On("Init", tests.GetPort(), tests.MaxMsgSize, tests.Flags, log).Return(&rmrMessenger) - return rmrsender.NewRmrSender(log, &rmrMessenger) + return rmrsender.NewRmrSender(log, rmrMessenger) } diff --git a/E2Manager/controllers/root_controller_test.go b/E2Manager/controllers/root_controller_test.go index 289e20b..42d0bdf 100644 --- a/E2Manager/controllers/root_controller_test.go +++ b/E2Manager/controllers/root_controller_test.go @@ -24,12 +24,10 @@ import ( "e2mgr/configuration" "e2mgr/logger" "e2mgr/mocks" - "e2mgr/rNibWriter" "e2mgr/services" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/stretchr/testify/assert" "net" "net/http" @@ -44,13 +42,10 @@ func setupNodebControllerTest(t *testing.T) (services.RNibDataService, *mocks.Rn } config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} readerMock := &mocks.RnibReaderMock{} - rnibReaderProvider := func() reader.RNibReader { - return readerMock - } - rnibWriterProvider := func() rNibWriter.RNibWriter { - return &mocks.RnibWriterMock{} - } - rnibDataService := services.NewRnibDataService(logger, config, rnibReaderProvider, rnibWriterProvider) + + writerMock := &mocks.RnibWriterMock{} + + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) return rnibDataService, readerMock } diff --git a/E2Manager/converters/endc_x2setupFailureResponseToProtobuf.go b/E2Manager/converters/endc_setup_failure_response_converter.go similarity index 82% rename from E2Manager/converters/endc_x2setupFailureResponseToProtobuf.go rename to E2Manager/converters/endc_setup_failure_response_converter.go index ccb48ee..587fedf 100644 --- a/E2Manager/converters/endc_x2setupFailureResponseToProtobuf.go +++ b/E2Manager/converters/endc_setup_failure_response_converter.go @@ -26,11 +26,27 @@ package converters // #include import "C" import ( + "e2mgr/e2pdus" "e2mgr/logger" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" "unsafe" ) +type EndcSetupFailureResponseConverter struct { + logger *logger.Logger +} + +type IEndcSetupFailureResponseConverter interface { + UnpackEndcSetupFailureResponseAndExtract(packedBuf []byte) (*entities.SetupFailure, error) +} + +func NewEndcSetupFailureResponseConverter(logger *logger.Logger) *EndcSetupFailureResponseConverter { + return &EndcSetupFailureResponseConverter{ + logger: logger, + } +} + + // Populate and return the EN-DC/X2 setup response failure structure with data from the pdu func endcX2SetupFailureResponseToProtobuf(pdu *C.E2AP_PDU_t) (*entities.SetupFailure, error) { setupFailure := entities.SetupFailure{} @@ -71,8 +87,8 @@ func endcX2SetupFailureResponseToProtobuf(pdu *C.E2AP_PDU_t) (*entities.SetupFai return &setupFailure, nil } -func UnpackEndcX2SetupFailureResponseAndExtract(logger *logger.Logger, allocationBufferSize int, packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (*entities.SetupFailure, error) { - pdu, err := UnpackX2apPdu(logger, allocationBufferSize, packedBufferSize, packedBuf, maxMessageBufferSize) +func (c *EndcSetupFailureResponseConverter) UnpackEndcSetupFailureResponseAndExtract(packedBuf []byte) (*entities.SetupFailure, error) { + pdu, err := UnpackX2apPdu(c.logger, e2pdus.MaxAsn1CodecAllocationBufferSize, len(packedBuf), packedBuf, e2pdus.MaxAsn1CodecMessageBufferSize) if err != nil { return nil, err } diff --git a/E2Manager/converters/endc_x2setupFailureResponseToProtobuf_test.go b/E2Manager/converters/endc_setup_failure_response_converter_test.go similarity index 93% rename from E2Manager/converters/endc_x2setupFailureResponseToProtobuf_test.go rename to E2Manager/converters/endc_setup_failure_response_converter_test.go index f0ab525..77c60b5 100644 --- a/E2Manager/converters/endc_x2setupFailureResponseToProtobuf_test.go +++ b/E2Manager/converters/endc_setup_failure_response_converter_test.go @@ -22,7 +22,6 @@ package converters import ( - "e2mgr/e2pdus" "e2mgr/logger" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" @@ -78,6 +77,8 @@ func TestUnpackEndcX2SetupFailureResponseAndExtract(t *testing.T) { /**** shares the same code with x2setup failure response to protobuf ****/ } + converter := NewEndcSetupFailureResponseConverter(logger) + for _, tc := range testCases { t.Run(tc.packedPdu, func(t *testing.T) { @@ -87,7 +88,7 @@ func TestUnpackEndcX2SetupFailureResponseAndExtract(t *testing.T) { t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err) } - response, err := UnpackEndcX2SetupFailureResponseAndExtract(logger, e2pdus.MaxAsn1CodecAllocationBufferSize /*allocation buffer*/, len(payload), payload, e2pdus.MaxAsn1CodecMessageBufferSize /*message buffer*/) + response, err := converter.UnpackEndcSetupFailureResponseAndExtract(payload) if err != nil { if tc.failure == nil { diff --git a/E2Manager/converters/endc_x2setupResponseToProtobuf.go b/E2Manager/converters/endc_setup_response_converter.go similarity index 93% rename from E2Manager/converters/endc_x2setupResponseToProtobuf.go rename to E2Manager/converters/endc_setup_response_converter.go index 3870f99..8901a92 100644 --- a/E2Manager/converters/endc_x2setupResponseToProtobuf.go +++ b/E2Manager/converters/endc_setup_response_converter.go @@ -26,10 +26,10 @@ package converters // #include import "C" import ( + "e2mgr/e2pdus" "e2mgr/logger" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" -// "github.com/pkg/errors" "unsafe" ) @@ -39,6 +39,20 @@ const ( maxnoofNrCellBands = 32 ) +type EndcSetupResponseConverter struct { + logger *logger.Logger +} + +type IEndcSetupResponseConverter interface { + UnpackEndcSetupResponseAndExtract(packedBuf []byte) (*entities.GlobalNbId, *entities.Gnb, error) +} + +func NewEndcSetupResponseConverter(logger *logger.Logger) *EndcSetupResponseConverter { + return &EndcSetupResponseConverter{ + logger: logger, + } +} + func getNRFreqInfo(freqInfo C.NRFreqInfo_t) (*entities.NrFrequencyInfo, error) { var info *entities.NrFrequencyInfo info = &entities.NrFrequencyInfo{NrArFcn: uint64(freqInfo.nRARFCN)} @@ -60,7 +74,7 @@ func getNRFreqInfo(freqInfo C.NRFreqInfo_t) (*entities.NrFrequencyInfo, error) { frequencyBand := &entities.FrequencyBandItem{NrFrequencyBand: uint32(freqBandNrItem.freqBandIndicatorNr)} if freqBandNrItem.supportedSULBandList.list.count > 0 && freqBandNrItem.supportedSULBandList.list.count <= maxnoofNrCellBands { - count:= int(freqBandNrItem.supportedSULBandList.list.count) + count := int(freqBandNrItem.supportedSULBandList.list.count) supportedSULBandList_slice := (*[1 << 30]*C.SupportedSULFreqBandItem_t)(unsafe.Pointer(freqBandNrItem.supportedSULBandList.list.array))[:count:count] for _, supportedSULFreqBandItem := range supportedSULBandList_slice { frequencyBand.SupportedSulBands = append(frequencyBand.SupportedSulBands, uint32(supportedSULFreqBandItem.freqBandIndicatorNr)) @@ -165,7 +179,7 @@ func getnRNeighbourInfo(neighbour_Information *C.NRNeighbour_Information_t) ([]* var neighbours []*entities.NrNeighbourInformation if neighbour_Information != nil && neighbour_Information.list.count > 0 && neighbour_Information.list.count <= maxofNRNeighbours { - count:=int(neighbour_Information.list.count) + count := int(neighbour_Information.list.count) neighbour_Information_slice := (*[1 << 30]*C.NRNeighbour_Information__Member)(unsafe.Pointer(neighbour_Information.list.array))[:count:count] for _, member := range neighbour_Information_slice { info := &entities.NrNeighbourInformation{NrPci: uint32(member.nrpCI)} @@ -206,7 +220,7 @@ func getServedNRCells(servedNRcellsManagementList *C.ServedNRcellsENDCX2Manageme var servedNRCells []*entities.ServedNRCell if servedNRcellsManagementList != nil && servedNRcellsManagementList.list.count > 0 && servedNRcellsManagementList.list.count <= maxCellinengNB { - count :=int(servedNRcellsManagementList.list.count) + count := int(servedNRcellsManagementList.list.count) servedNRcellsENDCX2ManagementList__Member_slice := (*[1 << 30]*C.ServedNRcellsENDCX2ManagementList__Member)(unsafe.Pointer(servedNRcellsManagementList.list.array))[:count:count] for _, servedNRcellsENDCX2ManagementList__Member := range servedNRcellsENDCX2ManagementList__Member_slice { servedNRCellInfo := servedNRcellsENDCX2ManagementList__Member.servedNRCellInfo @@ -226,7 +240,7 @@ func getServedNRCells(servedNRcellsManagementList *C.ServedNRcellsENDCX2Manageme } if servedNRCellInfo.broadcastPLMNs.list.count > 0 && servedNRCellInfo.broadcastPLMNs.list.count <= maxnoofBPLMNs { - count:=int(servedNRCellInfo.broadcastPLMNs.list.count) + count := int(servedNRCellInfo.broadcastPLMNs.list.count) pLMN_Identity_slice := (*[1 << 30]*C.PLMN_Identity_t)(unsafe.Pointer(servedNRCellInfo.broadcastPLMNs.list.array))[:count:count] for _, pLMN_Identity := range pLMN_Identity_slice { servedNRCell.ServedNrCellInformation.ServedPlmns = append(servedNRCell.ServedNrCellInformation.ServedPlmns, fmt.Sprintf("%02x", C.GoBytes(unsafe.Pointer(pLMN_Identity.buf), C.int(pLMN_Identity.size)))) @@ -274,7 +288,7 @@ func endcX2SetupResponseToProtobuf(pdu *C.E2AP_PDU_t) (*entities.GlobalNbId, *en if successfulOutcome != nil && successfulOutcome.value.present == C.SuccessfulOutcome__value_PR_ENDCX2SetupResponse { endcX2SetupResponse := (*C.ENDCX2SetupResponse_t)(unsafe.Pointer(&successfulOutcome.value.choice[0])) if endcX2SetupResponse != nil && endcX2SetupResponse.protocolIEs.list.count > 0 { - count:=int(endcX2SetupResponse.protocolIEs.list.count) + count := int(endcX2SetupResponse.protocolIEs.list.count) endcX2SetupResponse_IEs_slice := (*[1 << 30]*C.ENDCX2SetupResponse_IEs_t)(unsafe.Pointer(endcX2SetupResponse.protocolIEs.list.array))[:count:count] for _, endcX2SetupResponse_IE := range endcX2SetupResponse_IEs_slice { if endcX2SetupResponse_IE.value.present == C.ENDCX2SetupResponse_IEs__value_PR_RespondingNodeType_EndcX2Setup { @@ -283,7 +297,7 @@ func endcX2SetupResponseToProtobuf(pdu *C.E2AP_PDU_t) (*entities.GlobalNbId, *en case C.RespondingNodeType_EndcX2Setup_PR_respond_en_gNB: en_gNB_ENDCX2SetupReqAckIEs_Container := *(**C.ProtocolIE_Container_119P89_t)(unsafe.Pointer(&respondingNodeType.choice[0])) if en_gNB_ENDCX2SetupReqAckIEs_Container != nil && en_gNB_ENDCX2SetupReqAckIEs_Container.list.count > 0 { - count:=int(en_gNB_ENDCX2SetupReqAckIEs_Container.list.count) + count := int(en_gNB_ENDCX2SetupReqAckIEs_Container.list.count) en_gNB_ENDCX2SetupReqAckIEs_slice := (*[1 << 30]*C.En_gNB_ENDCX2SetupReqAckIEs_t)(unsafe.Pointer(en_gNB_ENDCX2SetupReqAckIEs_Container.list.array))[:count:count] for _, en_gNB_ENDCX2SetupReqAckIE := range en_gNB_ENDCX2SetupReqAckIEs_slice { switch en_gNB_ENDCX2SetupReqAckIE.value.present { @@ -318,8 +332,9 @@ func endcX2SetupResponseToProtobuf(pdu *C.E2AP_PDU_t) (*entities.GlobalNbId, *en return globalNbId, gnb, nil } -func UnpackEndcX2SetupResponseAndExtract(logger *logger.Logger, allocationBufferSize int, packedBufferSize int, packedBuf []byte, maxMessageBufferSize int) (*entities.GlobalNbId, *entities.Gnb, error) { - pdu, err := UnpackX2apPdu(logger, allocationBufferSize, packedBufferSize, packedBuf, maxMessageBufferSize) +func (c *EndcSetupResponseConverter) UnpackEndcSetupResponseAndExtract(packedBuf []byte) (*entities.GlobalNbId, *entities.Gnb, error) { + pdu, err := UnpackX2apPdu(c.logger, e2pdus.MaxAsn1CodecAllocationBufferSize, len(packedBuf), packedBuf, e2pdus.MaxAsn1CodecMessageBufferSize) + if err != nil { return nil, nil, err } diff --git a/E2Manager/converters/endc_x2setupResponseToProtobuf_test.go b/E2Manager/converters/endc_setup_response_converter_test.go similarity index 99% rename from E2Manager/converters/endc_x2setupResponseToProtobuf_test.go rename to E2Manager/converters/endc_setup_response_converter_test.go index 11fa704..f68e4c0 100644 --- a/E2Manager/converters/endc_x2setupResponseToProtobuf_test.go +++ b/E2Manager/converters/endc_setup_response_converter_test.go @@ -22,7 +22,6 @@ package converters import ( - "e2mgr/e2pdus" "e2mgr/logger" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" @@ -559,6 +558,8 @@ func TestUnpackEndcX2SetupResponseAndExtract(t *testing.T) { failure: fmt.Errorf("getList for path [successfulOutcome_t ENDCX2SetupResponse protocolIEs_t ProtocolIE_Container_elm RespondingNodeType-EndcX2Setup respond_en_gNB_t ProtocolIE_Container_elm ServedNRcellsENDCX2ManagementList ServedNRcellsENDCX2ManagementList_elm servedNRCellInfo_t nrpCI_t] failed, rc = 1" /*NO_ITEMS*/),}, } + converter := NewEndcSetupResponseConverter(logger) + for _, tc := range testCases { t.Run(tc.packedPdu, func(t *testing.T) { @@ -570,7 +571,7 @@ func TestUnpackEndcX2SetupResponseAndExtract(t *testing.T) { t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err) } - key, gnb, err := UnpackEndcX2SetupResponseAndExtract(logger, e2pdus.MaxAsn1CodecAllocationBufferSize, len(payload), payload, e2pdus.MaxAsn1CodecMessageBufferSize) + key, gnb, err := converter.UnpackEndcSetupResponseAndExtract(payload) if err != nil { if tc.failure == nil { diff --git a/E2Manager/e2managererrors/e2t_instance_absence_error.go b/E2Manager/e2managererrors/e2t_instance_absence_error.go new file mode 100644 index 0000000..772d62a --- /dev/null +++ b/E2Manager/e2managererrors/e2t_instance_absence_error.go @@ -0,0 +1,35 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package e2managererrors + +type E2TInstanceAbsenceError struct { + *BaseError +} + +func NewE2TInstanceAbsenceError() *E2TInstanceAbsenceError { + return &E2TInstanceAbsenceError{ + &BaseError{ + Code: 510, + Message: "The New RAN can't be added, please try later.", + }, + } +} + +func (e *E2TInstanceAbsenceError) Error() string { + return e.Message +} diff --git a/E2Manager/e2managererrors/routing_manager_error.go b/E2Manager/e2managererrors/routing_manager_error.go new file mode 100644 index 0000000..529df35 --- /dev/null +++ b/E2Manager/e2managererrors/routing_manager_error.go @@ -0,0 +1,29 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package e2managererrors + +type RoutingManagerError struct { +} + +func NewRoutingManagerError() *RoutingManagerError { + return &RoutingManagerError{} +} + +func (e *RoutingManagerError) Error() string { + return "Routing Manager Error" +} diff --git a/E2Manager/e2mgr-sonar-scanner.properties b/E2Manager/e2mgr-sonar-scanner.properties new file mode 100644 index 0000000..a0c9ca9 --- /dev/null +++ b/E2Manager/e2mgr-sonar-scanner.properties @@ -0,0 +1,14 @@ +#----- Default SonarQube server +sonar.host.url=http://135.25.121.110:9000 +sonar.projectKey=oran:e2mgr +sonar.projectName=e2mgr +sonar.login=admin +sonar.password=admin +sonar.go.coverage.reportPaths=coverage.txt +#----- Default source code encoding +#sonar.sourceEncoding=UTF-8 +sonar.projectBaseDir=/home/ubuntu/oran_repo/e2mgr/E2Manager/ +sonar.sources=. +sonar.exclusions=**/*_test.go,**/generate_source.go,**/*_generated.go,**/build/**,**/.gogradle/**,**/mocks/**,**/tests/**,**/e2managererrors/**,**/enums/** +sonar.go.golangci-lint.reportPaths=sca.xml + diff --git a/E2Manager/e2pdus/configuration_update.go b/E2Manager/e2pdus/configuration_update.go new file mode 100644 index 0000000..032c6cf --- /dev/null +++ b/E2Manager/e2pdus/configuration_update.go @@ -0,0 +1,107 @@ +/******************************************************************************* + * + * Copyright (c) 2019 AT&T Intellectual Property. + * + * 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. + * + *******************************************************************************/ +package e2pdus + +// #cgo CFLAGS: -I../asn1codec/inc/ -I../asn1codec/e2ap_engine/ +// #cgo LDFLAGS: -L ../asn1codec/lib/ -L../asn1codec/e2ap_engine/ -le2ap_codec -lasncodec +// #include +import "C" +import ( + "fmt" + "unsafe" +) + +var PackedEndcConfigurationUpdateFailure []byte +var PackedEndcConfigurationUpdateAck []byte +var PackedX2EnbConfigurationUpdateFailure []byte +var PackedX2EnbConfigurationUpdateAck []byte + +func prepareEndcConfigurationUpdateFailurePDU(maxAsn1PackedBufferSize int, maxAsn1CodecMessageBufferSize int) error { + + packedBuffer := make([]C.uchar, maxAsn1PackedBufferSize) + errorBuffer := make([]C.char, maxAsn1CodecMessageBufferSize) + var payloadSize = C.ulong(maxAsn1PackedBufferSize) + + if status := C.build_pack_endc_configuration_update_failure(&payloadSize, &packedBuffer[0], C.ulong(maxAsn1CodecMessageBufferSize), &errorBuffer[0]); !status { + return fmt.Errorf("#configuration_update.prepareEndcConfigurationUpdateFailurePDU - failed to build and pack the endc configuration update failure message %s ", C.GoString(&errorBuffer[0])) + + } + PackedEndcConfigurationUpdateFailure = C.GoBytes(unsafe.Pointer(&packedBuffer[0]), C.int(payloadSize)) + + return nil +} + +func prepareX2EnbConfigurationUpdateFailurePDU(maxAsn1PackedBufferSize int, maxAsn1CodecMessageBufferSize int) error { + + packedBuffer := make([]C.uchar, maxAsn1PackedBufferSize) + errorBuffer := make([]C.char, maxAsn1CodecMessageBufferSize) + var payloadSize = C.ulong(maxAsn1PackedBufferSize) + + if status := C.build_pack_x2enb_configuration_update_failure(&payloadSize, &packedBuffer[0], C.ulong(maxAsn1CodecMessageBufferSize), &errorBuffer[0]); !status { + return fmt.Errorf("#configuration_update.prepareX2EnbConfigurationUpdateFailurePDU - failed to build and pack the x2 configuration update failure message %s ", C.GoString(&errorBuffer[0])) + + } + PackedX2EnbConfigurationUpdateFailure = C.GoBytes(unsafe.Pointer(&packedBuffer[0]), C.int(payloadSize)) + + return nil +} + +func prepareEndcConfigurationUpdateAckPDU(maxAsn1PackedBufferSize int, maxAsn1CodecMessageBufferSize int) error { + + packedBuffer := make([]C.uchar, maxAsn1PackedBufferSize) + errorBuffer := make([]C.char, maxAsn1CodecMessageBufferSize) + var payloadSize = C.ulong(maxAsn1PackedBufferSize) + + if status := C.build_pack_endc_configuration_update_ack(&payloadSize, &packedBuffer[0], C.ulong(maxAsn1CodecMessageBufferSize), &errorBuffer[0]); !status { + return fmt.Errorf("#configuration_update.prepareEndcConfigurationUpdateAckPDU - failed to build and pack the endc configuration update ack message %s ", C.GoString(&errorBuffer[0])) + + } + PackedEndcConfigurationUpdateAck = C.GoBytes(unsafe.Pointer(&packedBuffer[0]), C.int(payloadSize)) + + return nil +} + +func prepareX2EnbConfigurationUpdateAckPDU(maxAsn1PackedBufferSize int, maxAsn1CodecMessageBufferSize int) error { + + packedBuffer := make([]C.uchar, maxAsn1PackedBufferSize) + errorBuffer := make([]C.char, maxAsn1CodecMessageBufferSize) + var payloadSize = C.ulong(maxAsn1PackedBufferSize) + + if status := C.build_pack_x2enb_configuration_update_ack(&payloadSize, &packedBuffer[0], C.ulong(maxAsn1CodecMessageBufferSize), &errorBuffer[0]); !status { + return fmt.Errorf("#configuration_update.prepareX2EnbConfigurationUpdateAckPDU - failed to build and pack the x2 configuration update ack message %s ", C.GoString(&errorBuffer[0])) + + } + PackedX2EnbConfigurationUpdateAck = C.GoBytes(unsafe.Pointer(&packedBuffer[0]), C.int(payloadSize)) + + return nil +} + +func init() { + if err := prepareEndcConfigurationUpdateFailurePDU(MaxAsn1PackedBufferSize, MaxAsn1CodecMessageBufferSize); err != nil { + panic(err) + } + if err := prepareEndcConfigurationUpdateAckPDU(MaxAsn1PackedBufferSize, MaxAsn1CodecMessageBufferSize); err != nil { + panic(err) + } + if err := prepareX2EnbConfigurationUpdateFailurePDU(MaxAsn1PackedBufferSize, MaxAsn1CodecMessageBufferSize); err != nil { + panic(err) + } + if err := prepareX2EnbConfigurationUpdateAckPDU(MaxAsn1PackedBufferSize, MaxAsn1CodecMessageBufferSize); err != nil { + panic(err) + } +} diff --git a/E2Manager/e2pdus/configuration_update_test.go b/E2Manager/e2pdus/configuration_update_test.go new file mode 100644 index 0000000..a90ba13 --- /dev/null +++ b/E2Manager/e2pdus/configuration_update_test.go @@ -0,0 +1,165 @@ +/******************************************************************************* + * + * Copyright (c) 2019 AT&T Intellectual Property. + * + * 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. + * + *******************************************************************************/ +package e2pdus + +import ( + "e2mgr/logger" + "fmt" + "strings" + "testing" +) + +func TestPrepareEndcConfigurationUpdateFailurePDU(t *testing.T) { + _,err := logger.InitLogger(logger.InfoLevel) + if err!=nil{ + t.Errorf("failed to initialize logger, error: %s", err) + } + packedPdu := "402500080000010005400142" + packedEndcConfigurationUpdateFailure := PackedEndcConfigurationUpdateFailure + + tmp := fmt.Sprintf("%x", packedEndcConfigurationUpdateFailure) + if len(tmp) != len(packedPdu) { + t.Errorf("want packed len:%d, got: %d\n", len(packedPdu)/2, len(packedEndcConfigurationUpdateFailure)/2) + } + + if strings.Compare(tmp, packedPdu) != 0 { + t.Errorf("\nwant :\t[%s]\n got: \t\t[%s]\n", packedPdu, tmp) + } +} + +func TestPrepareEndcConfigurationUpdateFailurePDUFailure(t *testing.T) { + _, err := logger.InitLogger(logger.InfoLevel) + if err != nil { + t.Errorf("failed to initialize logger, error: %s", err) + } + + err = prepareEndcConfigurationUpdateFailurePDU(1, 4096) + if err == nil { + t.Errorf("want: error, got: success.\n") + } + + expected:= "#configuration_update.prepareEndcConfigurationUpdateFailurePDU - failed to build and pack the endc configuration update failure message #src/asn1codec_utils.c.pack_pdu_aux - Encoded output of E2AP-PDU, is too big" + if !strings.Contains(err.Error(), expected) { + t.Errorf("want :[%s], got: [%s]\n", expected, err) + } +} + +func TestPrepareX2EnbConfigurationUpdateFailurePDU(t *testing.T) { + _,err := logger.InitLogger(logger.InfoLevel) + if err!=nil{ + t.Errorf("failed to initialize logger, error: %s", err) + } + packedPdu := "400800080000010005400142" + packedEndcX2ConfigurationUpdateFailure := PackedX2EnbConfigurationUpdateFailure + + tmp := fmt.Sprintf("%x", packedEndcX2ConfigurationUpdateFailure) + if len(tmp) != len(packedPdu) { + t.Errorf("want packed len:%d, got: %d\n", len(packedPdu)/2, len(packedEndcX2ConfigurationUpdateFailure)/2) + } + + if strings.Compare(tmp, packedPdu) != 0 { + t.Errorf("\nwant :\t[%s]\n got: \t\t[%s]\n", packedPdu, tmp) + } +} + +func TestPrepareX2EnbConfigurationUpdateFailurePDUFailure(t *testing.T) { + _, err := logger.InitLogger(logger.InfoLevel) + if err != nil { + t.Errorf("failed to initialize logger, error: %s", err) + } + + err = prepareX2EnbConfigurationUpdateFailurePDU(1, 4096) + if err == nil { + t.Errorf("want: error, got: success.\n") + } + + expected:= "#configuration_update.prepareX2EnbConfigurationUpdateFailurePDU - failed to build and pack the x2 configuration update failure message #src/asn1codec_utils.c.pack_pdu_aux - Encoded output of E2AP-PDU, is too big" + if !strings.Contains(err.Error(), expected) { + t.Errorf("want :[%s], got: [%s]\n", expected, err) + } +} + +func TestPrepareEndcConfigurationUpdateAckPDU(t *testing.T) { + _,err := logger.InitLogger(logger.InfoLevel) + if err!=nil{ + t.Errorf("failed to initialize logger, error: %s", err) + } + packedPdu := "2025000a00000100f70003000000" + packedEndcConfigurationUpdateAck := PackedEndcConfigurationUpdateAck + + tmp := fmt.Sprintf("%x", packedEndcConfigurationUpdateAck) + if len(tmp) != len(packedPdu) { + t.Errorf("want packed len:%d, got: %d\n", len(packedPdu)/2, len(packedEndcConfigurationUpdateAck)/2) + } + + if strings.Compare(tmp, packedPdu) != 0 { + t.Errorf("\nwant :\t[%s]\n got: \t\t[%s]\n", packedPdu, tmp) + } +} + +func TestPrepareEndcConfigurationUpdateAckPDUFailure(t *testing.T) { + _, err := logger.InitLogger(logger.InfoLevel) + if err != nil { + t.Errorf("failed to initialize logger, error: %s", err) + } + + err = prepareEndcConfigurationUpdateAckPDU(1, 4096) + if err == nil { + t.Errorf("want: error, got: success.\n") + } + + expected:= "#configuration_update.prepareEndcConfigurationUpdateAckPDU - failed to build and pack the endc configuration update ack message #src/asn1codec_utils.c.pack_pdu_aux - Encoded output of E2AP-PDU, is too big" + if !strings.Contains(err.Error(), expected) { + t.Errorf("want :[%s], got: [%s]\n", expected, err) + } +} + +func TestPrepareX2EnbConfigurationUpdateAckPDU(t *testing.T) { + _,err := logger.InitLogger(logger.InfoLevel) + if err!=nil{ + t.Errorf("failed to initialize logger, error: %s", err) + } + packedPdu := "200800080000010011400100" + packedEndcX2ConfigurationUpdateAck := PackedX2EnbConfigurationUpdateAck + + tmp := fmt.Sprintf("%x", packedEndcX2ConfigurationUpdateAck) + if len(tmp) != len(packedPdu) { + t.Errorf("want packed len:%d, got: %d\n", len(packedPdu)/2, len(packedEndcX2ConfigurationUpdateAck)/2) + } + + if strings.Compare(tmp, packedPdu) != 0 { + t.Errorf("\nwant :\t[%s]\n got: \t\t[%s]\n", packedPdu, tmp) + } +} + +func TestPrepareX2EnbConfigurationUpdateAckPDUFailure(t *testing.T) { + _, err := logger.InitLogger(logger.InfoLevel) + if err != nil { + t.Errorf("failed to initialize logger, error: %s", err) + } + + err = prepareX2EnbConfigurationUpdateAckPDU(1, 4096) + if err == nil { + t.Errorf("want: error, got: success.\n") + } + + expected:= "#configuration_update.prepareX2EnbConfigurationUpdateAckPDU - failed to build and pack the x2 configuration update ack message #src/asn1codec_utils.c.pack_pdu_aux - Encoded output of E2AP-PDU, is too big" + if !strings.Contains(err.Error(), expected) { + t.Errorf("want :[%s], got: [%s]\n", expected, err) + } +} \ No newline at end of file diff --git a/E2Manager/e2pdus/x2_setup_requests_test.go b/E2Manager/e2pdus/x2_setup_requests_test.go index 12789ec..e63577b 100644 --- a/E2Manager/e2pdus/x2_setup_requests_test.go +++ b/E2Manager/e2pdus/x2_setup_requests_test.go @@ -23,81 +23,11 @@ package e2pdus import ( "bytes" - "e2mgr/logger" "fmt" "strings" "testing" ) -func TestPreparePackedEndcX2SetupRequest(t *testing.T) { - _,err := logger.InitLogger(logger.InfoLevel) - if err!=nil{ - t.Errorf("failed to initialize logger, error: %s", err) - } - packedPdu := "0024003100000100f4002a0000020015000800bbbccc00abcde000fa0017000001f700bbbcccabcde0000000bbbccc000000000001" - packedEndcX2setupRequest := PackedEndcX2setupRequest - - tmp := fmt.Sprintf("%x", packedEndcX2setupRequest) - if len(tmp) != len(packedPdu) { - t.Errorf("want packed len:%d, got: %d\n", len(packedPdu)/2, len(packedEndcX2setupRequest)/2) - } - - if strings.Compare(tmp, packedPdu) != 0 { - t.Errorf("\nwant :\t[%s]\n got: \t\t[%s]\n", packedPdu, tmp) - } -} - -func TestPreparePackedX2SetupRequest(t *testing.T) { - _,err := logger.InitLogger(logger.InfoLevel) - if err!=nil{ - t.Errorf("failed to initialize logger, error: %s", err) - } - packedPdu := "0006002a0000020015000800bbbccc00abcde000140017000001f700bbbcccabcde0000000bbbccc000000000001" - packedX2setupRequest := PackedX2setupRequest - - tmp := fmt.Sprintf("%x", packedX2setupRequest) - if len(tmp) != len(packedPdu) { - t.Errorf("want packed len:%d, got: %d\n", len(packedPdu)/2, len(packedX2setupRequest)/2) - } - - if strings.Compare(tmp, packedPdu) != 0 { - t.Errorf("\nwant :\t[%s]\n got: \t\t[%s]\n", packedPdu, tmp) - } -} - -func TestPreparePackedX2SetupRequestFailure(t *testing.T) { - _, err := logger.InitLogger(logger.InfoLevel) - if err != nil { - t.Errorf("failed to initialize logger, error: %s", err) - } - - _, _, err = preparePackedX2SetupRequest(1, 4096, pLMNId, eNBId, eNBIdBitqty, ricFlag) - if err == nil { - t.Errorf("want: error, got: success.\n") - } - - expected:= "packing error: #src/asn1codec_utils.c.pack_pdu_aux - Encoded output of E2AP-PDU, is too big" - if !strings.Contains(err.Error(), expected) { - t.Errorf("want :[%s], got: [%s]\n", expected, err) - } -} - -func TestPreparePackedEndcSetupRequestFailure(t *testing.T) { - _, err := logger.InitLogger(logger.InfoLevel) - if err != nil { - t.Errorf("failed to initialize logger, error: %s", err) - } - - _, _, err = preparePackedEndcX2SetupRequest(1, 4096, pLMNId, eNBId, eNBIdBitqty, ricFlag) - if err == nil { - t.Errorf("want: error, got: success.\n") - } - - expected:= "packing error: #src/asn1codec_utils.c.pack_pdu_aux - Encoded output of E2AP-PDU, is too big" - if !strings.Contains(err.Error(), expected) { - t.Errorf("want :[%s], got: [%s]\n", expected, err) - } -} func TestParseRicId(t *testing.T) { var testCases = []struct { diff --git a/E2Manager/go.mod b/E2Manager/go.mod index 6892b02..1fd1095 100644 --- a/E2Manager/go.mod +++ b/E2Manager/go.mod @@ -1,20 +1,30 @@ module e2mgr require ( - gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.23 - gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.23 - gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.23 - gerrit.o-ran-sc.org/r/ric-plt/sdlgo v0.3.1 + gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.28 + gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.28 + gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.28 + gerrit.o-ran-sc.org/r/ric-plt/sdlgo v0.5.0 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect github.com/go-ozzo/ozzo-validation v3.5.0+incompatible - github.com/golang/protobuf v1.3.1 - github.com/gorilla/context v1.1.1 // indirect - github.com/gorilla/mux v1.6.2 + github.com/golang/protobuf v1.3.2 + github.com/gorilla/mux v1.7.0 + github.com/magiconair/properties v1.8.1 // indirect + github.com/pelletier/go-toml v1.5.0 // indirect github.com/pkg/errors v0.8.1 + github.com/spf13/afero v1.2.2 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.4.0 - github.com/stretchr/testify v1.3.0 - go.uber.org/zap v1.10.0 - gopkg.in/yaml.v2 v2.2.2 + github.com/stretchr/objx v0.2.0 // indirect + github.com/stretchr/testify v1.4.0 + go.uber.org/multierr v1.2.0 // indirect + go.uber.org/zap v1.11.0 + golang.org/x/net v0.0.0-20191021144547-ec77196f6094 // indirect + golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 // indirect + golang.org/x/text v0.3.2 // indirect + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect + gopkg.in/yaml.v2 v2.2.4 ) -replace gerrit.o-ran-sc.org/r/ric-plt/sdlgo => gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.3.1 +replace gerrit.o-ran-sc.org/r/ric-plt/sdlgo => gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.5.0 diff --git a/E2Manager/go.sum b/E2Manager/go.sum index 6576a0b..9c518c1 100644 --- a/E2Manager/go.sum +++ b/E2Manager/go.sum @@ -1,12 +1,18 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.23 h1:JbSOhvj9fVEUF2XZg8cw5QAyeKUi5xXgpwXrrxfDgLM= -gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.23/go.mod h1:QJ1uPPZosGbhxUWpUpeM5fLqFHdnWTrVnvW2DgyOCes= -gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.23 h1:akVZc8NWJ9oPujd7cQY3Ti3se4PF1/NoC+Dwt+YzINc= -gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.23/go.mod h1:GXiXLz4ORBeIr0FLIbzENRykgh3Po5uPkX2jICxnRF0= -gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.23 h1:TYV3HE2UNwGOWiA4C226/WhB94crwjuHKIFTgDDvo8I= -gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.23/go.mod h1:uZVjwZjfWV4JJzyQVO/O48Ykph57zfpfMB7nK+WGKX8= -gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.3.1 h1:ZIhABs0WLMn8lp1Y3719315/3jbV+yLcovOGScL03eM= -gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.3.1/go.mod h1:y2WhrCvdLkAKdH+ySdHSOSehACJkTMyZghCGVcqoZzc= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.27 h1:frasTDcg8Q8FgYutzJ+xSLHz9YseR2BmPSSBs4GI/1M= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.27/go.mod h1:QJ1uPPZosGbhxUWpUpeM5fLqFHdnWTrVnvW2DgyOCes= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.28 h1:Rewapfbc30ZkBaYB/3gW3W1BEivoiPdQm5UnmUswcMA= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.28/go.mod h1:QJ1uPPZosGbhxUWpUpeM5fLqFHdnWTrVnvW2DgyOCes= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.27 h1:nvZDzuB/SYKDuF1It7M4/Y/iVlVrCZ0Ob8AITAyppKo= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.27/go.mod h1:Fh23KkroYw5CRBh39WzZzxpKSkpQWL3scdzGnMngLo8= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.28 h1:+8Nn+Jn/AvhwBI1LtLsNS1PtOGAOYUHdicOrMn/8mmU= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.28/go.mod h1:Fh23KkroYw5CRBh39WzZzxpKSkpQWL3scdzGnMngLo8= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.27 h1:sWjlU/wBiWIBeSixnr9etCqtNmS2LW8jv+x2JGpf2eI= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.27/go.mod h1:vZ/335+rRSQW82wcbc80fNNICSK3TiCqIxmkqeC2Pfo= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.28 h1:AaYvK59fxDXQUV9NCo6WuxDOvBQbnRU3WTPyJaYhkkg= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.28/go.mod h1:vZ/335+rRSQW82wcbc80fNNICSK3TiCqIxmkqeC2Pfo= +gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.5.0 h1:+P3XuWKSaMbzh5PNtrW9gkZlCN0hKrZq+Cn8JetwBys= +gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.5.0/go.mod h1:y2WhrCvdLkAKdH+ySdHSOSehACJkTMyZghCGVcqoZzc= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -48,12 +54,12 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U= +github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -76,6 +82,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -88,6 +96,8 @@ github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.5.0 h1:5BakdOZdtKJ1FFk6QdL8iSGrMWsXgchNJcrnarjbmJQ= +github.com/pelletier/go-toml v1.5.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -108,20 +118,30 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= +github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= @@ -131,8 +151,12 @@ go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.2.0 h1:6I+W7f5VwC5SV9dNrZ3qXrDB9mD0dyGOi/ZJmYw03T4= +go.uber.org/multierr v1.2.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.11.0 h1:gSmpCfs+R47a4yQPAI4xJ0IPDLTRGXskm6UelqNXpqE= +go.uber.org/zap v1.11.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -144,6 +168,8 @@ golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20191021144547-ec77196f6094 h1:5O4U9trLjNpuhpynaDsqwCk+Tw6seqJz1EbqbnzHrc8= +golang.org/x/net v0.0.0-20191021144547-ec77196f6094/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -156,10 +182,15 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7 h1:HmbHVPwrPEKPGLAcHSrMe6+hqSUlvZU0rab6x5EXfGU= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -170,6 +201,8 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -179,4 +212,6 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/E2Manager/handlers/httpmsghandlers/delete_all_request_handler_test.go b/E2Manager/handlers/httpmsghandlers/delete_all_request_handler_test.go index 5093589..956a366 100644 --- a/E2Manager/handlers/httpmsghandlers/delete_all_request_handler_test.go +++ b/E2Manager/handlers/httpmsghandlers/delete_all_request_handler_test.go @@ -25,7 +25,6 @@ import ( "e2mgr/e2managererrors" "e2mgr/logger" "e2mgr/mocks" - "e2mgr/rNibWriter" "e2mgr/rmrCgo" "e2mgr/services" "e2mgr/services/rmrsender" @@ -33,7 +32,6 @@ import ( "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "reflect" @@ -45,14 +43,10 @@ func setupTest(t *testing.T) (*logger.Logger, *configuration.Configuration, *moc config := configuration.ParseConfiguration() readerMock := &mocks.RnibReaderMock{} - readerProvider := func() reader.RNibReader { - return readerMock - } + writerMock := &mocks.RnibWriterMock{} - writerProvider := func() rNibWriter.RNibWriter { - return writerMock - } - rnibDataService := services.NewRnibDataService(log, config, readerProvider, writerProvider) + + rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock) rmrMessengerMock := &mocks.RmrMessengerMock{} return log, config, readerMock, writerMock, rnibDataService, rmrMessengerMock } @@ -144,7 +138,7 @@ func TestHandleSuccessFlow(t *testing.T) { writerMock.On("SaveNodeb", mock.Anything, updatedNb3AfterTimer).Return(nil) mbuf := rmrCgo.NewMBuf(tests.MessageType, tests.MaxMsgSize, "RanName", &tests.DummyPayload, &tests.DummyXAction) - rmrMessengerMock.On("SendMsg", mock.AnythingOfType(fmt.Sprintf("%T", mbuf))).Return(mbuf, nil) + rmrMessengerMock.On("SendMsg", mock.AnythingOfType(fmt.Sprintf("%T", mbuf)), true).Return(mbuf, nil) _, actual := handler.Handle(nil) @@ -176,7 +170,7 @@ func TestHandleSuccessGetNextStatusFlow(t *testing.T) { writerMock.On("SaveNodeb", mock.Anything, updatedNb1AfterTimer).Return(nil) mbuf := rmrCgo.NewMBuf(tests.MessageType, tests.MaxMsgSize, "RanName", &tests.DummyPayload, &tests.DummyXAction) - rmrMessengerMock.On("SendMsg", mock.AnythingOfType(fmt.Sprintf("%T", mbuf))).Return(mbuf, nil) + rmrMessengerMock.On("SendMsg", mock.AnythingOfType(fmt.Sprintf("%T", mbuf)), true).Return(mbuf, nil) _, actual := handler.Handle(nil) @@ -205,7 +199,7 @@ func TestHandleShuttingDownStatusFlow(t *testing.T) { writerMock.On("SaveNodeb", mock.Anything, updatedNb1AfterTimer).Return(nil) mbuf := rmrCgo.NewMBuf(tests.MessageType, tests.MaxMsgSize, "RanName", &tests.DummyPayload, &tests.DummyXAction) - rmrMessengerMock.On("SendMsg", mock.AnythingOfType(fmt.Sprintf("%T", mbuf))).Return(mbuf, nil) + rmrMessengerMock.On("SendMsg", mock.AnythingOfType(fmt.Sprintf("%T", mbuf)), true).Return(mbuf, nil) _, actual := handler.Handle(nil) @@ -251,7 +245,7 @@ func TestHandleGetNodebFailedFlow(t *testing.T) { writerMock.On("SaveNodeb", mock.Anything, updatedNb3AfterTimer).Return(nil) mbuf := rmrCgo.NewMBuf(tests.MessageType, tests.MaxMsgSize, "RanName", &tests.DummyPayload, &tests.DummyXAction) - rmrMessengerMock.On("SendMsg", mock.AnythingOfType(fmt.Sprintf("%T", mbuf))).Return(mbuf, nil) + rmrMessengerMock.On("SendMsg", mock.AnythingOfType(fmt.Sprintf("%T", mbuf)), true).Return(mbuf, nil) _, actual := handler.Handle(nil) @@ -297,7 +291,7 @@ func TestHandleSaveFailedFlow(t *testing.T) { writerMock.On("SaveNodeb", mock.Anything, updatedNb3AfterTimer).Return(errRnib) mbuf := rmrCgo.NewMBuf(tests.MessageType, tests.MaxMsgSize, "RanName", &tests.DummyPayload, &tests.DummyXAction) - rmrMessengerMock.On("SendMsg", mock.AnythingOfType(fmt.Sprintf("%T", mbuf))).Return(mbuf, nil) + rmrMessengerMock.On("SendMsg", mock.AnythingOfType(fmt.Sprintf("%T", mbuf)), true).Return(mbuf, nil) _, actual := handler.Handle(nil) @@ -343,7 +337,7 @@ func TestHandleSendRmrFailedFlow(t *testing.T) { expected := e2managererrors.NewRmrError() mbuf := rmrCgo.NewMBuf(tests.MessageType, tests.MaxMsgSize, "RanName", &tests.DummyPayload, &tests.DummyXAction) - rmrMessengerMock.On("SendMsg", mock.AnythingOfType(fmt.Sprintf("%T", mbuf))).Return(mbuf, expected) + rmrMessengerMock.On("SendMsg", mock.AnythingOfType(fmt.Sprintf("%T", mbuf)), true).Return(mbuf, expected) _, actual := handler.Handle(nil) @@ -391,5 +385,5 @@ func initLog(t *testing.T) *logger.Logger { func getRmrSender(rmrMessengerMock *mocks.RmrMessengerMock, log *logger.Logger) *rmrsender.RmrSender { rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock) rmrMessengerMock.On("Init", tests.GetPort(), tests.MaxMsgSize, tests.Flags, log).Return(&rmrMessenger) - return rmrsender.NewRmrSender(log, &rmrMessenger) + return rmrsender.NewRmrSender(log, rmrMessenger) } diff --git a/E2Manager/handlers/httpmsghandlers/get_e2t_instances_request_handler.go b/E2Manager/handlers/httpmsghandlers/get_e2t_instances_request_handler.go new file mode 100644 index 0000000..fd20bdf --- /dev/null +++ b/E2Manager/handlers/httpmsghandlers/get_e2t_instances_request_handler.go @@ -0,0 +1,54 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package httpmsghandlers + +import ( + "e2mgr/logger" + "e2mgr/managers" + "e2mgr/models" +) + +type GetE2TInstancesRequestHandler struct { + e2tInstancesManager managers.IE2TInstancesManager + logger *logger.Logger +} + +func NewGetE2TInstancesRequestHandler(logger *logger.Logger, e2tInstancesManager managers.IE2TInstancesManager) *GetE2TInstancesRequestHandler { + return &GetE2TInstancesRequestHandler{ + logger: logger, + e2tInstancesManager: e2tInstancesManager, + } +} + +func (h *GetE2TInstancesRequestHandler) Handle(request models.Request) (models.IResponse, error) { + + e2tInstances, err := h.e2tInstancesManager.GetE2TInstances() + + if err != nil { + h.logger.Errorf("#GetE2TInstancesRequestHandler.Handle - Error fetching E2T instances from rNib: %s", err) + return nil, err + } + + mapped := make([]*models.E2TInstanceResponseModel, len(e2tInstances)) + + for i, v := range e2tInstances { + mapped[i] = models.NewE2TInstanceResponseModel(v.Address, v.AssociatedRanList) + } + + return models.E2TInstancesResponse(mapped), nil +} diff --git a/E2Manager/handlers/httpmsghandlers/get_e2t_instances_request_handler_test.go b/E2Manager/handlers/httpmsghandlers/get_e2t_instances_request_handler_test.go new file mode 100644 index 0000000..b4ee6b4 --- /dev/null +++ b/E2Manager/handlers/httpmsghandlers/get_e2t_instances_request_handler_test.go @@ -0,0 +1,75 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package httpmsghandlers + +import ( + "e2mgr/configuration" + "e2mgr/managers" + "e2mgr/mocks" + "e2mgr/models" + "e2mgr/services" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" + "testing" +) + +const E2TAddress2 = "10.0.2.15:3213" + +func setupGetE2TInstancesListRequestHandlerTest(t *testing.T) (*GetE2TInstancesRequestHandler, *mocks.RnibReaderMock) { + log := initLog(t) + config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} + readerMock := &mocks.RnibReaderMock{} + rnibDataService := services.NewRnibDataService(log, config, readerMock, nil) + e2tInstancesManager := managers.NewE2TInstancesManager(rnibDataService, log) + handler := NewGetE2TInstancesRequestHandler(log, e2tInstancesManager) + return handler, readerMock +} + +func TestGetE2TInstancesFailure(t *testing.T) { + handler, rnibReaderMock := setupGetE2TInstancesListRequestHandlerTest(t) + rnibReaderMock.On("GetE2TAddresses").Return([]string{}, common.NewInternalError(errors.New("error"))) + _, err := handler.Handle(nil) + assert.NotNil(t, err) +} + +func TestGetE2TInstancesNoInstances(t *testing.T) { + handler, rnibReaderMock := setupGetE2TInstancesListRequestHandlerTest(t) + rnibReaderMock.On("GetE2TAddresses").Return([]string{}, nil) + resp, err := handler.Handle(nil) + assert.Nil(t, err) + assert.IsType(t, models.E2TInstancesResponse{}, resp) + assert.Len(t, resp, 0) +} + +func TestGetE2TInstancesSuccess(t *testing.T) { + handler, rnibReaderMock := setupGetE2TInstancesListRequestHandlerTest(t) + + e2tAddresses := []string{E2TAddress, E2TAddress2} + rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, nil) + e2tInstance := entities.E2TInstance{Address: E2TAddress, AssociatedRanList: []string{"test1", "test2"}} + e2tInstance2 := entities.E2TInstance{Address: E2TAddress2, AssociatedRanList: []string{"test3", "test4", "test5"}} + + rnibReaderMock.On("GetE2TInstances", e2tAddresses).Return([]*entities.E2TInstance{&e2tInstance, &e2tInstance2}, nil) + resp, err := handler.Handle(nil) + assert.Nil(t, err) + assert.IsType(t, models.E2TInstancesResponse{}, resp) + assert.Len(t, resp, 2) +} diff --git a/E2Manager/handlers/httpmsghandlers/get_nodeb_id_list_request_handler_test.go b/E2Manager/handlers/httpmsghandlers/get_nodeb_id_list_request_handler_test.go index a835377..eb5bae3 100644 --- a/E2Manager/handlers/httpmsghandlers/get_nodeb_id_list_request_handler_test.go +++ b/E2Manager/handlers/httpmsghandlers/get_nodeb_id_list_request_handler_test.go @@ -27,7 +27,6 @@ import ( "e2mgr/services" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "testing" @@ -37,10 +36,8 @@ func setupGetNodebIdListRequestHandlerTest(t *testing.T) (*GetNodebIdListRequest log := initLog(t) config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} readerMock := &mocks.RnibReaderMock{} - readerProvider := func() reader.RNibReader { - return readerMock - } - rnibDataService := services.NewRnibDataService(log, config, readerProvider, nil) + + rnibDataService := services.NewRnibDataService(log, config, readerMock, nil) handler := NewGetNodebIdListRequestHandler(log, rnibDataService) return handler, readerMock } diff --git a/E2Manager/handlers/httpmsghandlers/get_nodeb_request_handler_test.go b/E2Manager/handlers/httpmsghandlers/get_nodeb_request_handler_test.go index 12e3226..0177561 100644 --- a/E2Manager/handlers/httpmsghandlers/get_nodeb_request_handler_test.go +++ b/E2Manager/handlers/httpmsghandlers/get_nodeb_request_handler_test.go @@ -27,7 +27,6 @@ import ( "e2mgr/services" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "testing" @@ -37,10 +36,7 @@ func setupGetNodebRequestHandlerTest(t *testing.T) (*GetNodebRequestHandler, *mo log := initLog(t) config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} readerMock := &mocks.RnibReaderMock{} - readerProvider := func() reader.RNibReader { - return readerMock - } - rnibDataService := services.NewRnibDataService(log, config, readerProvider, nil) + rnibDataService := services.NewRnibDataService(log, config, readerMock, nil) handler := NewGetNodebRequestHandler(log, rnibDataService) return handler, readerMock } diff --git a/E2Manager/handlers/httpmsghandlers/setup_request_handler.go b/E2Manager/handlers/httpmsghandlers/setup_request_handler.go index 9233411..92ec944 100644 --- a/E2Manager/handlers/httpmsghandlers/setup_request_handler.go +++ b/E2Manager/handlers/httpmsghandlers/setup_request_handler.go @@ -24,7 +24,6 @@ import ( "e2mgr/logger" "e2mgr/managers" "e2mgr/models" - "e2mgr/rnibBuilders" "e2mgr/services" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" @@ -38,77 +37,173 @@ const ( ) type SetupRequestHandler struct { - rNibDataService services.RNibDataService - logger *logger.Logger - ranSetupManager *managers.RanSetupManager - protocol entities.E2ApplicationProtocol + rNibDataService services.RNibDataService + logger *logger.Logger + ranSetupManager managers.IRanSetupManager + protocol entities.E2ApplicationProtocol + e2tInstancesManager managers.IE2TInstancesManager } func NewSetupRequestHandler(logger *logger.Logger, rNibDataService services.RNibDataService, - ranSetupManager *managers.RanSetupManager, protocol entities.E2ApplicationProtocol) *SetupRequestHandler { + ranSetupManager managers.IRanSetupManager, protocol entities.E2ApplicationProtocol, e2tInstancesManager managers.IE2TInstancesManager) *SetupRequestHandler { return &SetupRequestHandler{ - logger: logger, - rNibDataService: rNibDataService, - ranSetupManager: ranSetupManager, - protocol: protocol, + logger: logger, + rNibDataService: rNibDataService, + ranSetupManager: ranSetupManager, + protocol: protocol, + e2tInstancesManager: e2tInstancesManager, } } -func (handler *SetupRequestHandler) Handle(request models.Request) (models.IResponse, error) { +func (h *SetupRequestHandler) Handle(request models.Request) (models.IResponse, error) { setupRequest := request.(models.SetupRequest) - err := handler.validateRequestDetails(setupRequest) + err := h.validateRequestDetails(setupRequest) if err != nil { return nil, err } - nodebInfo, err := handler.rNibDataService.GetNodeb(setupRequest.RanName) + nodebInfo, err := h.rNibDataService.GetNodeb(setupRequest.RanName) + if err != nil { _, ok := err.(*common.ResourceNotFoundError) if !ok { - handler.logger.Errorf("#SetupRequestHandler.Handle - failed to get nodeB entity for ran name: %v from RNIB. Error: %s", - setupRequest.RanName, err.Error()) + h.logger.Errorf("#SetupRequestHandler.Handle - failed to get nodeB entity for ran name: %v from RNIB. Error: %s", setupRequest.RanName, err) return nil, e2managererrors.NewRnibDbError() } - result := handler.connectNewRan(&setupRequest, handler.protocol) + result := h.connectNewRan(&setupRequest, h.protocol) + return nil, result + } + + if nodebInfo.ConnectionStatus == entities.ConnectionStatus_SHUTTING_DOWN { + h.logger.Errorf("#SetupRequestHandler.connectExistingRanWithAssociatedE2TAddress - RAN: %s in wrong state (%s)", nodebInfo.RanName, entities.ConnectionStatus_name[int32(nodebInfo.ConnectionStatus)]) + result := e2managererrors.NewWrongStateError(h.getActivityName(h.protocol), entities.ConnectionStatus_name[int32(nodebInfo.ConnectionStatus)]) + return nil, result + } + + if len(nodebInfo.AssociatedE2TInstanceAddress) != 0 { + result := h.connectExistingRanWithAssociatedE2TAddress(nodebInfo) return nil, result } - result := handler.connectExistingRan(nodebInfo) + result := h.connectExistingRanWithoutAssociatedE2TAddress(nodebInfo) return nil, result } -func (handler *SetupRequestHandler) connectExistingRan(nodebInfo *entities.NodebInfo) error { +func createInitialNodeInfo(requestDetails *models.SetupRequest, protocol entities.E2ApplicationProtocol, e2tAddress string) (*entities.NodebInfo, *entities.NbIdentity) { - if nodebInfo.ConnectionStatus == entities.ConnectionStatus_SHUTTING_DOWN { - handler.logger.Errorf("#SetupRequestHandler.connectExistingRan - RAN: %s in wrong state (%s)", nodebInfo.RanName, entities.ConnectionStatus_name[int32(nodebInfo.ConnectionStatus)]) - return e2managererrors.NewWrongStateError(handler.getActivityName(handler.protocol), entities.ConnectionStatus_name[int32(nodebInfo.ConnectionStatus)]) + nodebInfo := &entities.NodebInfo{ + Ip: requestDetails.RanIp, + Port: uint32(requestDetails.RanPort), + ConnectionStatus: entities.ConnectionStatus_CONNECTING, + E2ApplicationProtocol: protocol, + RanName: requestDetails.RanName, + ConnectionAttempts: 0, + AssociatedE2TInstanceAddress: e2tAddress, + } + + nbIdentity := &entities.NbIdentity{ + InventoryName: requestDetails.RanName, + } + + return nodebInfo, nbIdentity +} + +func (h *SetupRequestHandler) connectExistingRanWithoutAssociatedE2TAddress(nodebInfo *entities.NodebInfo) error { + e2tAddress, err := h.e2tInstancesManager.SelectE2TInstance() + + if err != nil { + h.logger.Errorf("#SetupRequestHandler.connectExistingRanWithoutAssociatedE2TAddress - RAN name: %s - failed selecting E2T instance", nodebInfo.RanName) + + if nodebInfo.ConnectionStatus == entities.ConnectionStatus_DISCONNECTED && nodebInfo.ConnectionAttempts == 0 { + return err + } + + nodebInfo.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED + nodebInfo.ConnectionAttempts = 0 + updateError := h.rNibDataService.UpdateNodebInfo(nodebInfo) + + if updateError != nil { + h.logger.Errorf("#SetupRequestHandler.connectExistingRanWithoutAssociatedE2TAddress - RAN name: %s - failed updating nodeb. error: %s", nodebInfo.RanName, updateError) + } + + return err + } + + err = h.e2tInstancesManager.AssociateRan(nodebInfo.RanName, e2tAddress) + + if err != nil { + h.logger.Errorf("#SetupRequestHandler.connectExistingRanWithoutAssociatedE2TAddress - RAN name: %s - failed associating ran to e2t address %s. error: %s", nodebInfo.RanName, e2tAddress, err) + return err + } + + nodebInfo.AssociatedE2TInstanceAddress = e2tAddress + nodebInfo.ConnectionAttempts = 0 + + err = h.rNibDataService.UpdateNodebInfo(nodebInfo) + + if err != nil { + h.logger.Errorf("#SetupRequestHandler.connectExistingRanWithoutAssociatedE2TAddress - RAN name: %s - failed updating nodeb in rNib. error: %s", nodebInfo.RanName, err) + return e2managererrors.NewRnibDbError() } + h.logger.Infof("#SetupRequestHandler.connectExistingRanWithoutAssociatedE2TAddress - RAN name: %s - successfully updated nodeb in rNib", nodebInfo.RanName) + + result := h.ranSetupManager.ExecuteSetup(nodebInfo, entities.ConnectionStatus_CONNECTING) + return result +} + +func (h *SetupRequestHandler) connectExistingRanWithAssociatedE2TAddress(nodebInfo *entities.NodebInfo) error { status := entities.ConnectionStatus_CONNECTING - if nodebInfo.ConnectionStatus == entities.ConnectionStatus_CONNECTED{ + if nodebInfo.ConnectionStatus == entities.ConnectionStatus_CONNECTED { status = nodebInfo.ConnectionStatus } nodebInfo.ConnectionAttempts = 0 + err := h.rNibDataService.UpdateNodebInfo(nodebInfo) + + if err != nil { + h.logger.Errorf("#SetupRequestHandler.connectExistingRanWithAssociatedE2TAddress - RAN name: %s - failed resetting connection attempts of RAN. error: %s", nodebInfo.RanName, err) + return e2managererrors.NewRnibDbError() + } - result := handler.ranSetupManager.ExecuteSetup(nodebInfo, status) + h.logger.Infof("#SetupRequestHandler.connectExistingRanWithAssociatedE2TAddress - RAN name: %s - successfully reset connection attempts of RAN", nodebInfo.RanName) + + + result := h.ranSetupManager.ExecuteSetup(nodebInfo, status) return result } -func (handler *SetupRequestHandler) connectNewRan(request *models.SetupRequest, protocol entities.E2ApplicationProtocol) error { +func (h *SetupRequestHandler) connectNewRan(request *models.SetupRequest, protocol entities.E2ApplicationProtocol) error { + + e2tAddress, err := h.e2tInstancesManager.SelectE2TInstance() + + if err != nil { + h.logger.Errorf("#SetupRequestHandler.connectNewRan - RAN name: %s - failed selecting E2T instance", request.RanName) + return err + } + + err = h.e2tInstancesManager.AssociateRan(request.RanName, e2tAddress) - nodebInfo, nodebIdentity := rnibBuilders.CreateInitialNodeInfo(request, protocol) + if err != nil { + h.logger.Errorf("#SetupRequestHandler.connectNewRan - RAN name: %s - failed associating ran to e2t address %s. error: %s", request.RanName, e2tAddress, err) + return err + } + + nodebInfo, nodebIdentity := createInitialNodeInfo(request, protocol, e2tAddress) + + err = h.rNibDataService.SaveNodeb(nodebIdentity, nodebInfo) - rNibErr := handler.rNibDataService.SaveNodeb(nodebIdentity, nodebInfo) - if rNibErr != nil { - handler.logger.Errorf("#SetupRequestHandler.connectNewRan - failed to initial nodeb entity for ran name: %v in RNIB. Error: %s", request.RanName, rNibErr.Error()) + if err != nil { + h.logger.Errorf("#SetupRequestHandler.connectNewRan - RAN name: %s - failed to save initial nodeb entity in RNIB. error: %s", request.RanName, err) return e2managererrors.NewRnibDbError() } - handler.logger.Infof("#SetupRequestHandler.connectNewRan - initial nodeb entity for ran name: %v was saved to RNIB ", request.RanName) - result := handler.ranSetupManager.ExecuteSetup(nodebInfo, entities.ConnectionStatus_CONNECTING) + h.logger.Infof("#SetupRequestHandler.connectNewRan - RAN name: %s - initial nodeb entity was saved to rNib", request.RanName) + + result := h.ranSetupManager.ExecuteSetup(nodebInfo, entities.ConnectionStatus_CONNECTING) + return result } diff --git a/E2Manager/handlers/httpmsghandlers/setup_request_handler_test.go b/E2Manager/handlers/httpmsghandlers/setup_request_handler_test.go index 23cb44f..5086c91 100644 --- a/E2Manager/handlers/httpmsghandlers/setup_request_handler_test.go +++ b/E2Manager/handlers/httpmsghandlers/setup_request_handler_test.go @@ -20,292 +20,370 @@ package httpmsghandlers import ( - "e2mgr/rnibBuilders" "e2mgr/configuration" "e2mgr/e2managererrors" "e2mgr/e2pdus" "e2mgr/managers" "e2mgr/mocks" "e2mgr/models" - "e2mgr/rNibWriter" "e2mgr/rmrCgo" "e2mgr/services" + "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "reflect" "testing" ) -func TestSetupHandleNewRanSave_Error(t *testing.T) { - readerMock, writerMock, handler, rmrMessengerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST) +const E2TAddress = "10.0.2.15:8989" +const RanName = "test" - ranName := "RanName" - rnibErr := &common.ResourceNotFoundError{} - sr := models.SetupRequest{"127.0.0.1", 8080, ranName,} - - nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST} - readerMock.On("GetNodeb", ranName).Return(nb, rnibErr) - - vErr := &common.ValidationError{} - updatedNb, _ := rnibBuilders.CreateInitialNodeInfo(&sr, entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST) - writerMock.On("SaveNodeb", mock.Anything, updatedNb).Return(vErr) - - var nbUpdated = &entities.NodebInfo{RanName: ranName, Ip: sr.RanIp, Port: uint32(sr.RanPort), ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, ConnectionAttempts: 1} - writerMock.On("UpdateNodebInfo", nbUpdated).Return(nil) - - payload := e2pdus.PackedEndcX2setupRequest - xaction := []byte(ranName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction) +func initSetupRequestTest(t *testing.T, protocol entities.E2ApplicationProtocol) (*mocks.RnibReaderMock, *mocks.RnibWriterMock, *SetupRequestHandler, *mocks.E2TInstancesManagerMock, *mocks.RanSetupManagerMock) { + log := initLog(t) + config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil) + readerMock := &mocks.RnibReaderMock{} + writerMock := &mocks.RnibWriterMock{} - _, actual := handler.Handle(sr) - expected := &e2managererrors.RnibDbError{} + rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock) - if reflect.TypeOf(actual) != reflect.TypeOf(expected) { - t.Errorf("Error actual = %v, and Expected = %v.", actual, expected) - } + ranSetupManagerMock := &mocks.RanSetupManagerMock{} + e2tInstancesManagerMock := &mocks.E2TInstancesManagerMock{} + handler := NewSetupRequestHandler(log, rnibDataService, ranSetupManagerMock, protocol, e2tInstancesManagerMock) - writerMock.AssertNumberOfCalls(t, "SaveNodeb", 1) - writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 0) - rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 0) + return readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock } -func TestSetupHandleNewRan_Success(t *testing.T) { - readerMock, writerMock, handler, rmrMessengerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST) - - ranName := "RanName" - rnibErr := &common.ResourceNotFoundError{} - sr := models.SetupRequest{"127.0.0.1", 8080, ranName,} - - nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST} - readerMock.On("GetNodeb", ranName).Return(nb, rnibErr) - - updatedNb, _ := rnibBuilders.CreateInitialNodeInfo(&sr, entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST) - writerMock.On("SaveNodeb", mock.Anything, updatedNb).Return(nil) - - var nbUpdated = &entities.NodebInfo{RanName: ranName, Ip: sr.RanIp, Port: uint32(sr.RanPort), ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, ConnectionAttempts: 1} - writerMock.On("UpdateNodebInfo", nbUpdated).Return(nil) - - payload := e2pdus.PackedEndcX2setupRequest - xaction := []byte(ranName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction) +func initSetupRequestTestBasicMocks(t *testing.T, protocol entities.E2ApplicationProtocol) (*mocks.RnibReaderMock, *mocks.RnibWriterMock, *SetupRequestHandler, *mocks.RmrMessengerMock) { + log := initLog(t) + config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil) + readerMock := &mocks.RnibReaderMock{} + writerMock := &mocks.RnibWriterMock{} - _, actual := handler.Handle(sr) + rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock) - assert.Nil(t, actual) + rmrMessengerMock := &mocks.RmrMessengerMock{} + rmrSender := getRmrSender(rmrMessengerMock, log) + ranSetupManager := managers.NewRanSetupManager(log, rmrSender, rnibDataService) + e2tInstancesManager := managers.NewE2TInstancesManager(rnibDataService, log) + handler := NewSetupRequestHandler(log, rnibDataService, ranSetupManager, protocol, e2tInstancesManager) - writerMock.AssertNumberOfCalls(t, "SaveNodeb", 1) - writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1) - rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1) + return readerMock, writerMock, handler, rmrMessengerMock } -func TestEndcSetupHandleRmr_Error(t *testing.T) { - readerMock, writerMock, handler, rmrMessengerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST) - - ranName := "RanName" - nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST} - readerMock.On("GetNodeb", ranName).Return(nb, nil) - - var nbUpdated = &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, ConnectionAttempts: 1} - writerMock.On("UpdateNodebInfo", nbUpdated).Return(nil) - - var nbDisconnected = &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, ConnectionAttempts: 0} - writerMock.On("UpdateNodebInfo", nbDisconnected).Return(nil) - - payload := e2pdus.PackedEndcX2setupRequest - xaction := []byte(ranName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction) - - rmrErr := &e2managererrors.RmrError{} - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, rmrErr) - - sr := models.SetupRequest{"127.0.0.1", 8080, ranName,} - _, actual := handler.Handle(sr) +func TestX2SetupHandleNoPortError(t *testing.T) { + readerMock, _, handler, _, _ := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) - if reflect.TypeOf(actual) != reflect.TypeOf(rmrErr) { - t.Errorf("Error actual = %v, and Expected = %v.", actual, rmrErr) - } - - writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 2) - rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1) + sr := models.SetupRequest{"127.0.0.1", 0, RanName,} + _, err := handler.Handle(sr) + assert.IsType(t, &e2managererrors.RequestValidationError{}, err) + readerMock.AssertNotCalled(t, "GetNodeb") } -func TestEndcSetupHandleExistingDisconnectedRan_Success(t *testing.T) { - readerMock, writerMock, handler, rmrMessengerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST) - - ranName := "RanName" - nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST} - readerMock.On("GetNodeb", ranName).Return(nb, nil) - - var nbUpdated = &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, ConnectionAttempts: 1} - writerMock.On("UpdateNodebInfo", nbUpdated).Return(nil) - - payload := e2pdus.PackedEndcX2setupRequest - xaction := []byte(ranName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction) +func TestX2SetupHandleNoRanNameError(t *testing.T) { + readerMock, _, handler, _, _ := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil) - - sr := models.SetupRequest{"127.0.0.1", 8080, ranName,} - _, actual := handler.Handle(sr) - - assert.Nil(t, actual) - - writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1) - rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1) + sr := models.SetupRequest{RanPort: 8080, RanIp: "127.0.0.1"} + _, err := handler.Handle(sr) + assert.IsType(t, &e2managererrors.RequestValidationError{}, err) + readerMock.AssertNotCalled(t, "GetNodeb") } -func TestX2SetupHandleExistingConnectedRan_Success(t *testing.T) { - readerMock, writerMock, handler, rmrMessengerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) - - ranName := "RanName" - nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} - readerMock.On("GetNodeb", ranName).Return(nb, nil) +func TestX2SetupHandleNoIpError(t *testing.T) { + readerMock, _, handler, _, _ := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) - var nbUpdated = &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, ConnectionAttempts: 1} - writerMock.On("UpdateNodebInfo", nbUpdated).Return(nil) - - payload := e2pdus.PackedX2setupRequest - xaction := []byte(ranName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction) - - rmrMessengerMock.On("SendMsg", mock.Anything, mock.Anything).Return(msg, nil) - - sr := models.SetupRequest{"127.0.0.1", 8080, ranName,} - _, actual := handler.Handle(sr) + sr := models.SetupRequest{RanPort: 8080, RanName: RanName} + _, err := handler.Handle(sr) + assert.IsType(t, &e2managererrors.RequestValidationError{}, err) + readerMock.AssertNotCalled(t, "GetNodeb") +} - assert.Nil(t, actual) +func TestX2SetupHandleInvalidIpError(t *testing.T) { + readerMock, _, handler, _, _ := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) - writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1) - rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1) + sr := models.SetupRequest{RanPort: 8080, RanName: RanName, RanIp: "invalid ip"} + _, err := handler.Handle(sr) + assert.IsType(t, &e2managererrors.RequestValidationError{}, err) + readerMock.AssertNotCalled(t, "GetNodeb") } -func TestX2SetupHandleRnibGet_Error(t *testing.T) { - readerMock, _, handler, rmrMessengerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) +func TestSetupGetNodebFailure(t *testing.T) { + readerMock, _, handler, _, _ := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) rnibErr := &common.ValidationError{} - nb := &entities.NodebInfo{RanName: "RanName", ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN,} - readerMock.On("GetNodeb", "RanName").Return(nb, rnibErr) + nb := &entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN,} + readerMock.On("GetNodeb", RanName).Return(nb, rnibErr) - sr := models.SetupRequest{"127.0.0.1", 8080, "RanName",} - _, actual := handler.Handle(sr) - - expected := &e2managererrors.RnibDbError{} - if reflect.TypeOf(actual) != reflect.TypeOf(expected) { - t.Errorf("Error actual = %v, and Expected = %v.", actual, expected) - } - rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 0) + sr := models.SetupRequest{"127.0.0.1", 8080, RanName,} + _, err := handler.Handle(sr) + assert.IsType(t, &e2managererrors.RnibDbError{}, err) } -func TestX2SetupHandleShuttingDownRan_Error(t *testing.T) { - readerMock, writerMock, handler, rmrMessengerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) - - nb := &entities.NodebInfo{RanName: "RanName", ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN,} - readerMock.On("GetNodeb", "RanName").Return(nb, nil) - - sr := models.SetupRequest{"127.0.0.1", 8080, "RanName",} - _, actual := handler.Handle(sr) - - expected := &e2managererrors.WrongStateError{} - if reflect.TypeOf(actual) != reflect.TypeOf(expected) { - t.Errorf("Error actual = %v, and Expected = %v.", actual, expected) - } - writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 0) - rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 0) +func TestSetupNewRanSelectE2TInstancesDbError(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + readerMock.On("GetNodeb", RanName).Return(&entities.NodebInfo{}, common.NewResourceNotFoundError("")) + e2tInstancesManagerMock.On("SelectE2TInstance").Return("", e2managererrors.NewRnibDbError()) + _, err := handler.Handle(models.SetupRequest{"127.0.0.1", 8080, RanName,}) + assert.IsType(t, &e2managererrors.RnibDbError{}, err) + e2tInstancesManagerMock.AssertNotCalled(t, "AssociateRan") + writerMock.AssertNotCalled(t, "SaveNodeb") + ranSetupManagerMock.AssertNotCalled(t, "ExecuteSetup") } -func TestX2SetupHandleNoPort_Error(t *testing.T) { - _, writerMock, handler, rmrMessengerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) - - sr := models.SetupRequest{"127.0.0.1", 0, "RanName",} - _, actual := handler.Handle(sr) - - expected := &e2managererrors.RequestValidationError{} - if reflect.TypeOf(actual) != reflect.TypeOf(expected) { - t.Errorf("Error actual = %v, and Expected = %v.", actual, expected) - } - writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 0) - rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 0) +func TestSetupNewRanSelectE2TInstancesNoInstances(t *testing.T) { + readerMock, writerMock, handler, rmrMessengerMock := initSetupRequestTestBasicMocks(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + readerMock.On("GetNodeb", RanName).Return(&entities.NodebInfo{}, common.NewResourceNotFoundError("")) + readerMock.On("GetE2TAddresses").Return([]string{}, nil) + _, err := handler.Handle(models.SetupRequest{"127.0.0.1", 8080, RanName,}) + assert.IsType(t, &e2managererrors.E2TInstanceAbsenceError{}, err) + writerMock.AssertNotCalled(t, "SaveNodeb") + rmrMessengerMock.AssertNotCalled(t, "SendMsg") } -func TestX2SetupHandleNoRanName_Error(t *testing.T) { - _, writerMock, handler, rmrMessengerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) +func TestSetupNewRanAssociateRanFailure(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + readerMock.On("GetNodeb", RanName).Return(&entities.NodebInfo{}, common.NewResourceNotFoundError("")) + e2tInstancesManagerMock.On("SelectE2TInstance").Return(E2TAddress, nil) + e2tInstancesManagerMock.On("AssociateRan", RanName, E2TAddress).Return(e2managererrors.NewRnibDbError()) + _, err := handler.Handle(models.SetupRequest{"127.0.0.1", 8080, RanName,}) + assert.IsType(t, &e2managererrors.RnibDbError{}, err) + writerMock.AssertNotCalled(t, "SaveNodeb") + ranSetupManagerMock.AssertNotCalled(t, "ExecuteSetup") +} - sr := models.SetupRequest{} - sr.RanPort = 8080 - sr.RanIp = "127.0.0.1" +func TestSetupNewRanSaveNodebFailure(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + readerMock.On("GetNodeb", RanName).Return(&entities.NodebInfo{}, common.NewResourceNotFoundError("")) + e2tInstancesManagerMock.On("SelectE2TInstance").Return(E2TAddress, nil) + e2tInstancesManagerMock.On("AssociateRan", RanName, E2TAddress).Return(nil) + setupRequest := models.SetupRequest{"127.0.0.1", 8080, RanName,} + nodebInfo, nbIdentity := createInitialNodeInfo(&setupRequest, entities.E2ApplicationProtocol_X2_SETUP_REQUEST, E2TAddress) + writerMock.On("SaveNodeb", nbIdentity, nodebInfo).Return(common.NewInternalError(fmt.Errorf(""))) + _, err := handler.Handle(setupRequest) + assert.IsType(t, &e2managererrors.RnibDbError{}, err) + ranSetupManagerMock.AssertNotCalled(t, "ExecuteSetup") +} - _, actual := handler.Handle(sr) +func TestSetupNewRanSetupDbError(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + readerMock.On("GetNodeb", RanName).Return(&entities.NodebInfo{}, common.NewResourceNotFoundError("")) + e2tInstancesManagerMock.On("SelectE2TInstance").Return(E2TAddress, nil) + e2tInstancesManagerMock.On("AssociateRan", RanName, E2TAddress).Return(nil) + setupRequest := models.SetupRequest{"127.0.0.1", 8080, RanName,} + nodebInfo, nbIdentity := createInitialNodeInfo(&setupRequest, entities.E2ApplicationProtocol_X2_SETUP_REQUEST, E2TAddress) + writerMock.On("SaveNodeb", nbIdentity, nodebInfo).Return(nil) + ranSetupManagerMock.On("ExecuteSetup", nodebInfo, entities.ConnectionStatus_CONNECTING).Return(e2managererrors.NewRnibDbError()) + _, err := handler.Handle(setupRequest) + assert.IsType(t, &e2managererrors.RnibDbError{}, err) +} - expected := &e2managererrors.RequestValidationError{} - if reflect.TypeOf(actual) != reflect.TypeOf(expected) { - t.Errorf("Error actual = %v, and Expected = %v.", actual, expected) - } - writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 0) - rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 0) +func TestSetupNewRanSetupRmrError(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + readerMock.On("GetNodeb", RanName).Return(&entities.NodebInfo{}, common.NewResourceNotFoundError("")) + e2tInstancesManagerMock.On("SelectE2TInstance").Return(E2TAddress, nil) + e2tInstancesManagerMock.On("AssociateRan", RanName, E2TAddress).Return(nil) + setupRequest := models.SetupRequest{"127.0.0.1", 8080, RanName,} + nodebInfo, nbIdentity := createInitialNodeInfo(&setupRequest, entities.E2ApplicationProtocol_X2_SETUP_REQUEST, E2TAddress) + writerMock.On("SaveNodeb", nbIdentity, nodebInfo).Return(nil) + ranSetupManagerMock.On("ExecuteSetup", nodebInfo, entities.ConnectionStatus_CONNECTING).Return(e2managererrors.NewRmrError()) + _, err := handler.Handle(setupRequest) + assert.IsType(t, &e2managererrors.RmrError{}, err) } -func TestX2SetupHandleNoIP_Error(t *testing.T) { - _, writerMock, handler, rmrMessengerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) +func TestSetupNewRanSetupSuccess(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + readerMock.On("GetNodeb", RanName).Return(&entities.NodebInfo{}, common.NewResourceNotFoundError("")) + e2tInstancesManagerMock.On("SelectE2TInstance").Return(E2TAddress, nil) + e2tInstancesManagerMock.On("AssociateRan", RanName, E2TAddress).Return(nil) + setupRequest := models.SetupRequest{"127.0.0.1", 8080, RanName,} + nodebInfo, nbIdentity := createInitialNodeInfo(&setupRequest, entities.E2ApplicationProtocol_X2_SETUP_REQUEST, E2TAddress) + writerMock.On("SaveNodeb", nbIdentity, nodebInfo).Return(nil) + ranSetupManagerMock.On("ExecuteSetup", nodebInfo, entities.ConnectionStatus_CONNECTING).Return(nil) + _, err := handler.Handle(setupRequest) + assert.Nil(t, err) +} - sr := models.SetupRequest{} - sr.RanPort = 8080 - sr.RanName = "RanName" +func TestX2SetupExistingRanShuttingDown(t *testing.T) { + readerMock, _, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + readerMock.On("GetNodeb", RanName).Return(&entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN}, nil) + setupRequest := models.SetupRequest{"127.0.0.1", 8080, RanName,} + _, err := handler.Handle(setupRequest) + assert.IsType(t, &e2managererrors.WrongStateError{}, err) + e2tInstancesManagerMock.AssertNotCalled(t, "SelectE2TInstance") + ranSetupManagerMock.AssertNotCalled(t, "ExecuteSetup") +} - _, actual := handler.Handle(sr) +func TestEndcSetupExistingRanShuttingDown(t *testing.T) { + readerMock, _, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST) + readerMock.On("GetNodeb", RanName).Return(&entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN}, nil) + setupRequest := models.SetupRequest{"127.0.0.1", 8080, RanName,} + _, err := handler.Handle(setupRequest) + assert.IsType(t, &e2managererrors.WrongStateError{}, err) + e2tInstancesManagerMock.AssertNotCalled(t, "SelectE2TInstance") + ranSetupManagerMock.AssertNotCalled(t, "ExecuteSetup") +} - expected := &e2managererrors.RequestValidationError{} - if reflect.TypeOf(actual) != reflect.TypeOf(expected) { - t.Errorf("Error actual = %v, and Expected = %v.", actual, expected) - } - writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 0) - rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 0) +func TestSetupExistingRanWithoutAssocE2TInstanceSelectDbError(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""} + readerMock.On("GetNodeb", RanName).Return(nb, nil) + e2tInstancesManagerMock.On("SelectE2TInstance").Return("", e2managererrors.NewRnibDbError()) + updatedNb := *nb + updatedNb.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED + writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil) + setupRequest := models.SetupRequest{"127.0.0.1", 8080, RanName,} + _, err := handler.Handle(setupRequest) + assert.IsType(t, &e2managererrors.RnibDbError{}, err) + ranSetupManagerMock.AssertNotCalled(t, "ExecuteSetup") } -func TestX2SetupHandleInvalidIp_Error(t *testing.T) { - _, writerMock, handler, rmrMessengerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) +func TestSetupExistingRanWithoutAssocE2TInstanceSelectNoInstanceError(t *testing.T) { + readerMock, writerMock, handler, rmrMessengerMock := initSetupRequestTestBasicMocks(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""} + readerMock.On("GetNodeb", RanName).Return(nb, nil) + readerMock.On("GetE2TAddresses").Return([]string{}, nil) + updatedNb := *nb + updatedNb.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED + writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil) + setupRequest := models.SetupRequest{"127.0.0.1", 8080, RanName,} + _, err := handler.Handle(setupRequest) + assert.IsType(t, &e2managererrors.E2TInstanceAbsenceError{}, err) + rmrMessengerMock.AssertNotCalled(t, "SendMsg") + writerMock.AssertExpectations(t) +} - sr := models.SetupRequest{} - sr.RanPort = 8080 - sr.RanName = "RanName" - sr.RanIp = "invalid ip" +func TestSetupExistingRanWithoutAssocE2TInstanceSelectNoInstanceErrorUpdateFailure(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""} + readerMock.On("GetNodeb", RanName).Return(nb, nil) + e2tInstancesManagerMock.On("SelectE2TInstance").Return("", e2managererrors.NewE2TInstanceAbsenceError()) + updatedNb := *nb + updatedNb.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED + writerMock.On("UpdateNodebInfo", &updatedNb).Return(common.NewInternalError(fmt.Errorf(""))) + setupRequest := models.SetupRequest{"127.0.0.1", 8080, RanName,} + _, err := handler.Handle(setupRequest) + assert.IsType(t, &e2managererrors.E2TInstanceAbsenceError{}, err) + ranSetupManagerMock.AssertNotCalled(t, "ExecuteSetup") +} - _, actual := handler.Handle(sr) +func TestSetupExistingRanWithoutAssocE2TInstanceSelectErrorAlreadyDisconnected(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: "", ConnectionStatus: entities.ConnectionStatus_DISCONNECTED} + readerMock.On("GetNodeb", RanName).Return(nb, nil) + e2tInstancesManagerMock.On("SelectE2TInstance").Return(E2TAddress, e2managererrors.NewE2TInstanceAbsenceError()) + setupRequest := models.SetupRequest{"127.0.0.1", 8080, RanName,} + _, err := handler.Handle(setupRequest) + assert.IsType(t, &e2managererrors.E2TInstanceAbsenceError{}, err) + writerMock.AssertNotCalled(t, "UpdateNodebInfo") + ranSetupManagerMock.AssertNotCalled(t, "ExecuteSetup") +} - expected := &e2managererrors.RequestValidationError{} - if reflect.TypeOf(actual) != reflect.TypeOf(expected) { - t.Errorf("Error actual = %v, and Expected = %v.", actual, expected) - } - writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 0) - rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 0) +func TestSetupExistingRanWithoutAssocE2TInstanceAssociateRanFailure(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""} + readerMock.On("GetNodeb", RanName).Return(nb, nil) + e2tInstancesManagerMock.On("SelectE2TInstance").Return(E2TAddress, nil) + e2tInstancesManagerMock.On("AssociateRan", RanName, E2TAddress).Return(e2managererrors.NewRnibDbError()) + _, err := handler.Handle(models.SetupRequest{"127.0.0.1", 8080, RanName,}) + assert.IsType(t, &e2managererrors.RnibDbError{}, err) + writerMock.AssertNotCalled(t, "UpdateNodebInfo") + ranSetupManagerMock.AssertNotCalled(t, "ExecuteSetup") } -func initSetupRequestTest(t *testing.T, protocol entities.E2ApplicationProtocol) (*mocks.RnibReaderMock, *mocks.RnibWriterMock, *SetupRequestHandler, *mocks.RmrMessengerMock) { - log := initLog(t) - config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} +func TestSetupExistingRanWithoutAssocE2TInstanceAssociateRanSucceedsUpdateNodebFails(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""} + readerMock.On("GetNodeb", RanName).Return(nb, nil) + e2tInstancesManagerMock.On("SelectE2TInstance").Return(E2TAddress, nil) + e2tInstancesManagerMock.On("AssociateRan", RanName, E2TAddress).Return(nil) + updatedNb := *nb + updatedNb.AssociatedE2TInstanceAddress = E2TAddress + updatedNb.ConnectionAttempts = 0 + writerMock.On("UpdateNodebInfo", &updatedNb).Return(common.NewInternalError(fmt.Errorf(""))) + _, err := handler.Handle(models.SetupRequest{"127.0.0.1", 8080, RanName,}) + assert.IsType(t, &e2managererrors.RnibDbError{}, err) + ranSetupManagerMock.AssertNotCalled(t, "ExecuteSetup") +} - readerMock := &mocks.RnibReaderMock{} - readerProvider := func() reader.RNibReader { - return readerMock - } - writerMock := &mocks.RnibWriterMock{} - writerProvider := func() rNibWriter.RNibWriter { - return writerMock - } +func TestSetupExistingRanWithoutAssocE2TInstanceExecuteSetupFailure(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""} + readerMock.On("GetNodeb", RanName).Return(nb, nil) + e2tInstancesManagerMock.On("SelectE2TInstance").Return(E2TAddress, nil) + e2tInstancesManagerMock.On("AssociateRan", RanName, E2TAddress).Return(nil) + updatedNb := *nb + updatedNb.AssociatedE2TInstanceAddress = E2TAddress + updatedNb.ConnectionAttempts = 0 + writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil) + ranSetupManagerMock.On("ExecuteSetup", &updatedNb, entities.ConnectionStatus_CONNECTING).Return(e2managererrors.NewRnibDbError()) + _, err := handler.Handle(models.SetupRequest{"127.0.0.1", 8080, RanName,}) + assert.IsType(t, &e2managererrors.RnibDbError{}, err) +} - rmrMessengerMock := &mocks.RmrMessengerMock{} - rmrSender := getRmrSender(rmrMessengerMock, log) +func TestSetupExistingRanWithoutAssocE2TInstanceSuccess(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: ""} + readerMock.On("GetNodeb", RanName).Return(nb, nil) + e2tInstancesManagerMock.On("SelectE2TInstance").Return(E2TAddress, nil) + e2tInstancesManagerMock.On("AssociateRan", RanName, E2TAddress).Return(nil) + updatedNb := *nb + updatedNb.AssociatedE2TInstanceAddress = E2TAddress + updatedNb.ConnectionAttempts = 0 + writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil) + ranSetupManagerMock.On("ExecuteSetup", &updatedNb, entities.ConnectionStatus_CONNECTING).Return(nil) + _, err := handler.Handle(models.SetupRequest{"127.0.0.1", 8080, RanName,}) + assert.Nil(t, err) +} - rnibDataService := services.NewRnibDataService(log, config, readerProvider, writerProvider) +func TestSetupExistingRanWithAssocE2TInstanceUpdateNodebFailure(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress} + readerMock.On("GetNodeb", RanName).Return(nb, nil) + updatedNb := *nb + updatedNb.ConnectionAttempts = 0 + writerMock.On("UpdateNodebInfo", &updatedNb).Return(common.NewInternalError(fmt.Errorf(""))) + _, err := handler.Handle(models.SetupRequest{"127.0.0.1", 8080, RanName,}) + assert.IsType(t, &e2managererrors.RnibDbError{}, err) + e2tInstancesManagerMock.AssertNotCalled(t, "SelectE2TInstance") + e2tInstancesManagerMock.AssertNotCalled(t, "AssociateRan") + ranSetupManagerMock.AssertNotCalled(t, "ExecuteSetup") +} - ranSetupManager := managers.NewRanSetupManager(log, rmrSender, rnibDataService) - handler := NewSetupRequestHandler(log, rnibDataService, ranSetupManager, protocol) +func TestSetupExistingRanWithAssocE2TInstanceExecuteSetupRmrError(t *testing.T) { + readerMock, writerMock, handler, rmrMessengerMock := initSetupRequestTestBasicMocks(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress, ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol:entities.E2ApplicationProtocol_X2_SETUP_REQUEST} + readerMock.On("GetNodeb", RanName).Return(nb, nil) + updatedNb := *nb + updatedNb.ConnectionAttempts = 0 + updatedNb2 := updatedNb + updatedNb2.ConnectionAttempts++ + updatedNb3 := updatedNb2 + updatedNb3.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED + updatedNb3.ConnectionAttempts-- + writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil) + writerMock.On("UpdateNodebInfo", &updatedNb2).Return(nil) + payload := e2pdus.PackedX2setupRequest + xaction := []byte(RanName) + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), RanName, &payload, &xaction) + rmrMessengerMock.On("SendMsg",mock.Anything, true).Return(msg, e2managererrors.NewRmrError()) + writerMock.On("UpdateNodebInfo", &updatedNb3).Return(nil) + _, err := handler.Handle(models.SetupRequest{"127.0.0.1", 8080, RanName,}) + assert.IsType(t, &e2managererrors.RmrError{}, err) + writerMock.AssertExpectations(t) +} - return readerMock, writerMock, handler, rmrMessengerMock +func TestSetupExistingRanWithAssocE2TInstanceConnectedSuccess(t *testing.T) { + readerMock, writerMock, handler, e2tInstancesManagerMock, ranSetupManagerMock := initSetupRequestTest(t, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) + nb := &entities.NodebInfo{RanName: RanName, AssociatedE2TInstanceAddress: E2TAddress, ConnectionStatus: entities.ConnectionStatus_CONNECTED} + readerMock.On("GetNodeb", RanName).Return(nb, nil) + updatedNb := *nb + updatedNb.ConnectionAttempts = 0 + writerMock.On("UpdateNodebInfo", &updatedNb).Return(nil) + ranSetupManagerMock.On("ExecuteSetup", &updatedNb, entities.ConnectionStatus_CONNECTED).Return(nil) + _, err := handler.Handle(models.SetupRequest{"127.0.0.1", 8080, RanName,}) + assert.Nil(t, err) + e2tInstancesManagerMock.AssertNotCalled(t, "SelectE2TInstance") + e2tInstancesManagerMock.AssertNotCalled(t, "AssociateRan") } diff --git a/E2Manager/handlers/httpmsghandlers/x2_reset_request_handler.go b/E2Manager/handlers/httpmsghandlers/x2_reset_request_handler.go index 0738eae..13a88ad 100644 --- a/E2Manager/handlers/httpmsghandlers/x2_reset_request_handler.go +++ b/E2Manager/handlers/httpmsghandlers/x2_reset_request_handler.go @@ -81,7 +81,9 @@ func (handler *X2ResetRequestHandler) Handle(request models.Request) (models.IRe return nil, e2managererrors.NewWrongStateError(X2_RESET_ACTIVITY_NAME, entities.ConnectionStatus_name[int32(nodeb.ConnectionStatus)]) } - msg := models.NewRmrMessage(rmrCgo.RIC_X2_RESET, resetRequest.RanName, payload) + var xAction []byte + + msg := models.NewRmrMessage(rmrCgo.RIC_X2_RESET, resetRequest.RanName, payload, xAction) err = handler.rmrSender.Send(msg) diff --git a/E2Manager/handlers/httpmsghandlers/x2_reset_request_handler_test.go b/E2Manager/handlers/httpmsghandlers/x2_reset_request_handler_test.go index 870385b..16def4c 100644 --- a/E2Manager/handlers/httpmsghandlers/x2_reset_request_handler_test.go +++ b/E2Manager/handlers/httpmsghandlers/x2_reset_request_handler_test.go @@ -5,13 +5,11 @@ import ( "e2mgr/e2managererrors" "e2mgr/mocks" "e2mgr/models" - "e2mgr/rNibWriter" "e2mgr/rmrCgo" "e2mgr/services" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/stretchr/testify/assert" "testing" ) @@ -20,14 +18,8 @@ func setupX2ResetRequestHandlerTest(t *testing.T) (*X2ResetRequestHandler, *mock log := initLog(t) config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} readerMock := &mocks.RnibReaderMock{} - readerProvider := func() reader.RNibReader { - return readerMock - } writerMock := &mocks.RnibWriterMock{} - writerProvider := func() rNibWriter.RNibWriter { - return writerMock - } - rnibDataService := services.NewRnibDataService(log, config, readerProvider, writerProvider) + rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock) rmrMessengerMock := &mocks.RmrMessengerMock{} rmrSender := getRmrSender(rmrMessengerMock, log) handler := NewX2ResetRequestHandler(log, rmrSender, rnibDataService) @@ -40,10 +32,10 @@ func TestHandleSuccessfulDefaultCause(t *testing.T) { ranName := "test1" // o&m intervention payload := []byte{0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x64} - xaction := []byte(ranName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xaction) + var xAction[]byte + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xAction) - rmrMessengerMock.On("SendMsg", msg).Return(msg, nil) + rmrMessengerMock.On("SendMsg", msg, true).Return(msg, nil) var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED} readerMock.On("GetNodeb", ranName).Return(nodeb, nil) @@ -58,9 +50,9 @@ func TestHandleSuccessfulRequestedCause(t *testing.T) { ranName := "test1" payload := []byte{0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x40} - xaction := []byte(ranName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", msg).Return(msg, nil) + var xAction[]byte + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xAction) + rmrMessengerMock.On("SendMsg", msg, true).Return(msg, nil) var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED} readerMock.On("GetNodeb", ranName).Return(nodeb, nil) @@ -125,9 +117,9 @@ func TestHandleFailureRmrError(t *testing.T) { ranName := "test1" // o&m intervention payload := []byte{0x00, 0x07, 0x00, 0x08, 0x00, 0x00, 0x01, 0x00, 0x05, 0x40, 0x01, 0x64} - xaction := []byte(ranName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", msg).Return(&rmrCgo.MBuf{}, fmt.Errorf("rmr error")) + var xAction[]byte + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET, len(payload), ranName, &payload, &xAction) + rmrMessengerMock.On("SendMsg", msg, true).Return(&rmrCgo.MBuf{}, fmt.Errorf("rmr error")) var nodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED} readerMock.On("GetNodeb", ranName).Return(nodeb, nil) diff --git a/E2Manager/handlers/rmrmsghandlers/e2_term_init_notification_handler.go b/E2Manager/handlers/rmrmsghandlers/e2_term_init_notification_handler.go index 6bc047c..283de35 100644 --- a/E2Manager/handlers/rmrmsghandlers/e2_term_init_notification_handler.go +++ b/E2Manager/handlers/rmrmsghandlers/e2_term_init_notification_handler.go @@ -21,52 +21,110 @@ package rmrmsghandlers import ( + "e2mgr/clients" "e2mgr/logger" "e2mgr/managers" "e2mgr/models" "e2mgr/services" + "encoding/json" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" ) type E2TermInitNotificationHandler struct { logger *logger.Logger rnibDataService services.RNibDataService ranReconnectionManager *managers.RanReconnectionManager + e2tInstancesManager managers.IE2TInstancesManager + routingManagerClient clients.IRoutingManagerClient } -func NewE2TermInitNotificationHandler(logger *logger.Logger, ranReconnectionManager *managers.RanReconnectionManager, rnibDataService services.RNibDataService) E2TermInitNotificationHandler { +func NewE2TermInitNotificationHandler(logger *logger.Logger, ranReconnectionManager *managers.RanReconnectionManager, rnibDataService services.RNibDataService, e2tInstancesManager managers.IE2TInstancesManager, routingManagerClient clients.IRoutingManagerClient) E2TermInitNotificationHandler { return E2TermInitNotificationHandler{ logger: logger, rnibDataService: rnibDataService, ranReconnectionManager: ranReconnectionManager, + e2tInstancesManager: e2tInstancesManager, + routingManagerClient: routingManagerClient, } } func (h E2TermInitNotificationHandler) Handle(request *models.NotificationRequest) { + unmarshalledPayload := models.E2TermInitPayload{} + err := json.Unmarshal(request.Payload, &unmarshalledPayload) - h.logger.Infof("#E2TermInitNotificationHandler.Handle - Handling E2_TERM_INIT") + if err != nil { + h.logger.Errorf("#E2TermInitNotificationHandler.Handle - Error unmarshaling E2 Term Init payload: %s", err) + return + } + + e2tAddress := unmarshalledPayload.Address + + if len(e2tAddress) == 0 { + h.logger.Errorf("#E2TermInitNotificationHandler.Handle - Empty E2T address received") + return + } + + h.logger.Infof("#E2TermInitNotificationHandler.Handle - E2T address: %s - handling E2_TERM_INIT", e2tAddress) + + e2tInstance, err := h.e2tInstancesManager.GetE2TInstance(e2tAddress) - nbIdentityList, err := h.rnibDataService.GetListNodebIds() if err != nil { - h.logger.Errorf("#E2TermInitNotificationHandler.Handle - Failed to get nodes list from RNIB. Error: %s", err.Error()) + _, ok := err.(*common.ResourceNotFoundError) + + if !ok { + h.logger.Errorf("#E2TermInitNotificationHandler.Handle - Failed retrieving E2TInstance. error: %s", err) + return + } + + h.HandleNewE2TInstance(e2tAddress) return } - if len(nbIdentityList) == 0 { - h.logger.Warnf("#E2TermInitNotificationHandler.Handle - The Nodes list in RNIB is empty") + if len(e2tInstance.AssociatedRanList) == 0 { + h.logger.Infof("#E2TermInitNotificationHandler.Handle - E2T Address: %s - E2T instance has no associated RANs", e2tInstance.Address) return } - for _, nbIdentity := range nbIdentityList { + if e2tInstance.State == entities.ToBeDeleted{ + h.logger.Infof("#E2TermInitNotificationHandler.Handle - E2T Address: %s - E2T instance status is: %s, ignore", e2tInstance.Address, e2tInstance.State) + return + } - if err := h.ranReconnectionManager.ReconnectRan(nbIdentity.InventoryName); err != nil { - h.logger.Errorf("#E2TermInitNotificationHandler.Handle - Ran name: %s - connection attempt failure, error: %s", (*nbIdentity).GetInventoryName(), err.Error()) + if e2tInstance.State == entities.RoutingManagerFailure { + err := h.e2tInstancesManager.ActivateE2TInstance(e2tInstance) + if err != nil { + return + } + } + + h.HandleExistingE2TInstance(e2tInstance) + + h.logger.Infof("#E2TermInitNotificationHandler.Handle - Completed handling of E2_TERM_INIT") +} + +func (h E2TermInitNotificationHandler) HandleExistingE2TInstance(e2tInstance *entities.E2TInstance) { + + for _, ranName := range e2tInstance.AssociatedRanList { + + if err := h.ranReconnectionManager.ReconnectRan(ranName); err != nil { + h.logger.Errorf("#E2TermInitNotificationHandler.HandleExistingE2TInstance - Ran name: %s - connection attempt failure, error: %s", ranName, err) _, ok := err.(*common.ResourceNotFoundError) if !ok { break } } } - - h.logger.Infof("#E2TermInitNotificationHandler.Handle - Completed handling of E2_TERM_INIT") } + +func (h E2TermInitNotificationHandler) HandleNewE2TInstance(e2tAddress string) { + + err := h.routingManagerClient.AddE2TInstance(e2tAddress) + + if err != nil{ + h.logger.Errorf("#E2TermInitNotificationHandler.HandleNewE2TInstance - e2t address: %s - routing manager failure", e2tAddress) + return + } + + _ = h.e2tInstancesManager.AddE2TInstance(e2tAddress) +} \ No newline at end of file diff --git a/E2Manager/handlers/rmrmsghandlers/e2_term_init_notification_handler_test.go b/E2Manager/handlers/rmrmsghandlers/e2_term_init_notification_handler_test.go index ae88cb2..f6779df 100644 --- a/E2Manager/handlers/rmrmsghandlers/e2_term_init_notification_handler_test.go +++ b/E2Manager/handlers/rmrmsghandlers/e2_term_init_notification_handler_test.go @@ -1,3 +1,19 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// package rmrmsghandlers import ( @@ -7,7 +23,6 @@ import ( "e2mgr/managers" "e2mgr/mocks" "e2mgr/models" - "e2mgr/rNibWriter" "e2mgr/rmrCgo" "e2mgr/services" "e2mgr/services/rmrsender" @@ -15,12 +30,14 @@ import ( "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/stretchr/testify/mock" "testing" ) -func initRanLostConnectionTest(t *testing.T) (*logger.Logger, E2TermInitNotificationHandler, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.RmrMessengerMock) { +const e2tInstanceAddress = "10.0.2.15" +const e2tInitPayload = "{\"address\":\"10.0.2.15\", \"fqdn\":\"\"}" + +func initRanLostConnectionTest(t *testing.T) (*logger.Logger, E2TermInitNotificationHandler, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.RmrMessengerMock, *mocks.E2TInstancesManagerMock, *mocks.RoutingManagerClientMock) { logger := initLog(t) config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} @@ -29,78 +46,325 @@ func initRanLostConnectionTest(t *testing.T) (*logger.Logger, E2TermInitNotifica rmrSender := initRmrSender(rmrMessengerMock, logger) readerMock := &mocks.RnibReaderMock{} - rnibReaderProvider := func() reader.RNibReader { - return readerMock - } + writerMock := &mocks.RnibWriterMock{} - rnibWriterProvider := func() rNibWriter.RNibWriter { - return writerMock - } - rnibDataService := services.NewRnibDataService(logger, config, rnibReaderProvider, rnibWriterProvider) + + routingManagerClientMock := &mocks.RoutingManagerClientMock{} + + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) + ranSetupManager := managers.NewRanSetupManager(logger, rmrSender, rnibDataService) + + e2tInstancesManagerMock := &mocks.E2TInstancesManagerMock{} + + ranReconnectionManager := managers.NewRanReconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, ranSetupManager, e2tInstancesManagerMock) + handler := NewE2TermInitNotificationHandler(logger, ranReconnectionManager, rnibDataService, e2tInstancesManagerMock, routingManagerClientMock) + + return logger, handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock +} + +func initRanLostConnectionTestWithRealE2tInstanceManager(t *testing.T) (*logger.Logger, E2TermInitNotificationHandler, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.RmrMessengerMock) { + + logger := initLog(t) + config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} + + rmrMessengerMock := &mocks.RmrMessengerMock{} + rmrSender := initRmrSender(rmrMessengerMock, logger) + + readerMock := &mocks.RnibReaderMock{} + + writerMock := &mocks.RnibWriterMock{} + routingManagerClientMock := &mocks.RoutingManagerClientMock{} + + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) ranSetupManager := managers.NewRanSetupManager(logger, rmrSender, rnibDataService) - ranReconnectionManager := managers.NewRanReconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, ranSetupManager) - handler := NewE2TermInitNotificationHandler(logger, ranReconnectionManager, rnibDataService) + + e2tInstancesManager := managers.NewE2TInstancesManager(rnibDataService, logger) + ranReconnectionManager := managers.NewRanReconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, ranSetupManager, e2tInstancesManager) + handler := NewE2TermInitNotificationHandler(logger, ranReconnectionManager, rnibDataService, e2tInstancesManager, routingManagerClientMock) return logger, handler, readerMock, writerMock, rmrMessengerMock } -func TestE2TerminInitHandlerSuccessOneRan(t *testing.T) { - _, handler, readerMock, writerMock, rmrMessengerMock := initRanLostConnectionTest(t) - var rnibErr error +func TestE2TermInitUnmarshalPayloadFailure(t *testing.T) { + _, handler, _, _, _, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte("asd")} + handler.Handle(notificationRequest) + e2tInstancesManagerMock.AssertNotCalled(t, "GetE2TInstance") + e2tInstancesManagerMock.AssertNotCalled(t, "AddE2TInstance") +} - ids := []*entities.NbIdentity{{InventoryName: "test1"}} - readerMock.On("GetListNodebIds").Return(ids, rnibErr) +func TestE2TermInitEmptyE2TAddress(t *testing.T) { + _, handler, _, _, _, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte("{\"address\":\"\"}")} + handler.Handle(notificationRequest) + e2tInstancesManagerMock.AssertNotCalled(t, "GetE2TInstance") + e2tInstancesManagerMock.AssertNotCalled(t, "AddE2TInstance") +} + +func TestE2TermInitGetE2TInstanceFailure(t *testing.T) { + _, handler, _, _, _, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) + var e2tInstance *entities.E2TInstance + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, common.NewInternalError(fmt.Errorf("internal error"))) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + handler.Handle(notificationRequest) + e2tInstancesManagerMock.AssertNotCalled(t, "AddE2TInstance") +} + +func TestE2TermInitGetE2TInstanceDbFailure(t *testing.T) { + _, handler, readerMock, writerMock, rmrMessengerMock := initRanLostConnectionTestWithRealE2tInstanceManager(t) + var e2tInstance *entities.E2TInstance + readerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, common.NewInternalError(fmt.Errorf("internal error"))) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + handler.Handle(notificationRequest) + writerMock.AssertNotCalled(t, "UpdateNodebInfo") + rmrMessengerMock.AssertNotCalled(t, "SendMsg") +} + +func TestE2TermInitNewE2TInstance(t *testing.T) { + _, handler, _, _, _, e2tInstancesManagerMock, routingManagerClient := initRanLostConnectionTest(t) + var e2tInstance *entities.E2TInstance + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, common.NewResourceNotFoundError("not found")) + e2tInstance = entities.NewE2TInstance(e2tInstanceAddress) + e2tInstancesManagerMock.On("AddE2TInstance", e2tInstanceAddress).Return(nil) + routingManagerClient.On("AddE2TInstance", e2tInstanceAddress).Return(nil) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + handler.Handle(notificationRequest) + routingManagerClient.AssertCalled(t, "AddE2TInstance", e2tInstanceAddress) + e2tInstancesManagerMock.AssertCalled(t, "AddE2TInstance", e2tInstanceAddress) +} + +func TestE2TermInitNewE2TInstance_RoutingManagerError(t *testing.T) { + _, handler, _, _, _, e2tInstancesManagerMock, routingManagerClient := initRanLostConnectionTest(t) + var e2tInstance *entities.E2TInstance + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, common.NewResourceNotFoundError("not found")) + e2tInstance = entities.NewE2TInstance(e2tInstanceAddress) + e2tInstancesManagerMock.On("AddE2TInstance", e2tInstanceAddress).Return(nil) + routingManagerClient.On("AddE2TInstance", e2tInstanceAddress).Return(fmt.Errorf("error")) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + + handler.Handle(notificationRequest) + + routingManagerClient.AssertCalled(t, "AddE2TInstance", e2tInstanceAddress) + e2tInstancesManagerMock.AssertNotCalled(t, "AddE2TInstance", e2tInstanceAddress) +} + +func TestE2TermInitExistingE2TInstanceNoAssociatedRans(t *testing.T) { + _, handler, _, _, _, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + handler.Handle(notificationRequest) + e2tInstancesManagerMock.AssertCalled(t, "GetE2TInstance", e2tInstanceAddress) +} + +func TestE2TermInitHandlerSuccessOneRan(t *testing.T) { + _, handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) + var rnibErr error var initialNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} - readerMock.On("GetNodeb", ids[0].InventoryName).Return(initialNodeb, rnibErr) + readerMock.On("GetNodeb", RanName).Return(initialNodeb, rnibErr) var argNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, ConnectionAttempts: 1} writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr) payload := e2pdus.PackedX2setupRequest - xaction := []byte(ids[0].InventoryName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ids[0].InventoryName, &payload, &xaction) + xaction := []byte(RanName) + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), RanName, &payload, &xaction) + + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil) + + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + + handler.Handle(notificationRequest) + + writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1) + rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1) +} + +func TestE2TermInitHandlerSuccessOneRanShuttingdown(t *testing.T) { + _, handler, readerMock, writerMock, rmrMessengerMock := initRanLostConnectionTestWithRealE2tInstanceManager(t) + var rnibErr error + + var initialNodeb = &entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} + readerMock.On("GetNodeb", RanName).Return(initialNodeb, rnibErr) + + var argNodeb = &entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_SHUT_DOWN, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, ConnectionAttempts: 0} + writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr) + + payload := e2pdus.PackedX2setupRequest + xaction := []byte(RanName) + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), RanName, &payload, &xaction) rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil) - handler.Handle(nil) + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName) + readerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + + handler.Handle(notificationRequest) + + writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1) + rmrMessengerMock.AssertNotCalled(t, "SendMsg") +} + +func TestE2TermInitHandlerSuccessOneRan_ToBeDeleted(t *testing.T) { + _, handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) + var rnibErr error + + var initialNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} + readerMock.On("GetNodeb", RanName).Return(initialNodeb, rnibErr) + + var argNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, ConnectionAttempts: 1} + writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr) + + payload := e2pdus.PackedX2setupRequest + xaction := []byte(RanName) + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), RanName, &payload, &xaction) + + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil) + + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstance.State = entities.ToBeDeleted + e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName) + + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + + handler.Handle(notificationRequest) + + writerMock.AssertNotCalled(t, "UpdateNodebInfo") + rmrMessengerMock.AssertNotCalled(t, "SendMsg") +} + +func TestE2TermInitHandlerSuccessOneRan_RoutingManagerFailure(t *testing.T) { + _, handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) + var rnibErr error + + var initialNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} + readerMock.On("GetNodeb", RanName).Return(initialNodeb, rnibErr) + + var argNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, ConnectionAttempts: 1} + writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr) + + payload := e2pdus.PackedX2setupRequest + xaction := []byte(RanName) + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), RanName, &payload, &xaction) + + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil) + + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstance.State = entities.RoutingManagerFailure + e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName) + + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + e2tInstancesManagerMock.On("ActivateE2TInstance", e2tInstance).Return(nil) + writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr) + + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + + handler.Handle(notificationRequest) writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1) rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1) } -func TestE2TerminInitHandlerSuccessTwoRans(t *testing.T) { - _, handler, readerMock, writerMock, rmrMessengerMock := initRanLostConnectionTest(t) +func TestE2TermInitHandlerSuccessOneRan_RoutingManagerFailure_Error(t *testing.T) { + _, handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) var rnibErr error - ids := []*entities.NbIdentity{{InventoryName: "test1"}, {InventoryName: "test2"}} - readerMock.On("GetListNodebIds").Return(ids, rnibErr) + var initialNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} + readerMock.On("GetNodeb", RanName).Return(initialNodeb, rnibErr) + + var argNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, ConnectionAttempts: 1} + writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr) + payload := e2pdus.PackedX2setupRequest + xaction := []byte(RanName) + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), RanName, &payload, &xaction) + + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil) + + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstance.State = entities.RoutingManagerFailure + e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName) + + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + e2tInstancesManagerMock.On("ActivateE2TInstance", e2tInstance).Return(fmt.Errorf(" Error ")) + writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr) + + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + + handler.Handle(notificationRequest) + + writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 0) + rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 0) +} + +func TestE2TermInitHandlerSuccessTwoRans(t *testing.T) { + _, handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) + var rnibErr error var initialNodeb0 = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} var initialNodeb1 = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} - readerMock.On("GetNodeb", ids[0].InventoryName).Return(initialNodeb0, rnibErr) - readerMock.On("GetNodeb", ids[1].InventoryName).Return(initialNodeb1, rnibErr) + readerMock.On("GetNodeb", RanName).Return(initialNodeb0, rnibErr) + readerMock.On("GetNodeb", "test2").Return(initialNodeb1, rnibErr) var argNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, ConnectionAttempts: 1} writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr) payload := e2pdus.PackedX2setupRequest - xaction := []byte(ids[0].InventoryName) - msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ids[0].InventoryName, &payload, &xaction) + xaction := []byte(RanName) + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), RanName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil) + + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName, "test2") + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} - handler.Handle(nil) + handler.Handle(notificationRequest) writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 2) rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 2) } -func TestE2TerminInitHandlerSuccessThreeRansFirstRmrFailure(t *testing.T) { - log, handler, readerMock, writerMock, rmrMessengerMock := initRanLostConnectionTest(t) +func TestE2TermInitHandlerSuccessTwoRansSecondRanShutdown(t *testing.T) { + _, handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) + var rnibErr error + var initialNodeb0 = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} + var initialNodeb1 = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_SHUT_DOWN, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} + readerMock.On("GetNodeb", RanName).Return(initialNodeb0, rnibErr) + readerMock.On("GetNodeb", "test2").Return(initialNodeb1, rnibErr) + + var argNodeb = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, ConnectionAttempts: 1} + writerMock.On("UpdateNodebInfo", argNodeb).Return(rnibErr) + + payload := e2pdus.PackedX2setupRequest + xaction := []byte(RanName) + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), RanName, &payload, &xaction) + + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil) + + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName, "test2") + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + + handler.Handle(notificationRequest) + + writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1) + rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1) + writerMock.AssertExpectations(t) +} + +func TestE2TermInitHandlerSuccessThreeRansFirstRmrFailure(t *testing.T) { + log, handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) var rnibErr error ids := []*entities.NbIdentity{{InventoryName: "test1"}, {InventoryName: "test2"}, {InventoryName: "test3"}} - readerMock.On("GetListNodebIds").Return(ids, rnibErr) var initialNodeb0 = &entities.NodebInfo{RanName: ids[0].InventoryName, ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} var initialNodeb1 = &entities.NodebInfo{RanName: ids[1].InventoryName, ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} @@ -123,9 +387,14 @@ func TestE2TerminInitHandlerSuccessThreeRansFirstRmrFailure(t *testing.T) { //xaction = []byte(ids[1].InventoryName) //msg1 := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ids[1].InventoryName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg0, fmt.Errorf("RMR Error")) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg0, fmt.Errorf("RMR Error")) - handler.Handle(nil) + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, "test1", "test2", "test3") + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + + handler.Handle(notificationRequest) //test1 (before send +1, after failure +1), test2 (0) test3 (0) writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 2) @@ -133,12 +402,11 @@ func TestE2TerminInitHandlerSuccessThreeRansFirstRmrFailure(t *testing.T) { rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1) } -func TestE2TerminInitHandlerSuccessThreeRansSecondNotFoundFailure(t *testing.T) { - log, handler, readerMock, writerMock, rmrMessengerMock := initRanLostConnectionTest(t) +func TestE2TermInitHandlerSuccessThreeRansSecondNotFoundFailure(t *testing.T) { + log, handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) var rnibErr error ids := []*entities.NbIdentity{{InventoryName: "test1"}, {InventoryName: "test2"}, {InventoryName: "test3"}} - readerMock.On("GetListNodebIds").Return(ids, rnibErr) var initialNodeb0 = &entities.NodebInfo{RanName: ids[0].InventoryName, ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} var initialNodeb1 = &entities.NodebInfo{RanName: ids[1].InventoryName, ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} @@ -166,9 +434,14 @@ func TestE2TerminInitHandlerSuccessThreeRansSecondNotFoundFailure(t *testing.T) //xaction = []byte(ids[1].InventoryName) //msg1 := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ids[1].InventoryName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg0, nil) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg0, nil) + + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, "test1", "test2", "test3") + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} - handler.Handle(nil) + handler.Handle(notificationRequest) readerMock.AssertNumberOfCalls(t, "GetNodeb", 3) //test1 (+1), test2 failure (0) test3 (+1) @@ -177,12 +450,11 @@ func TestE2TerminInitHandlerSuccessThreeRansSecondNotFoundFailure(t *testing.T) rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 2) } -func TestE2TerminInitHandlerSuccessThreeRansSecondRnibInternalErrorFailure(t *testing.T) { - log, handler, readerMock, writerMock, rmrMessengerMock := initRanLostConnectionTest(t) +func TestE2TermInitHandlerSuccessThreeRansSecondRnibInternalErrorFailure(t *testing.T) { + log, handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) var rnibErr error ids := []*entities.NbIdentity{{InventoryName: "test1"}, {InventoryName: "test2"}, {InventoryName: "test3"}} - readerMock.On("GetListNodebIds").Return(ids, rnibErr) var initialNodeb0 = &entities.NodebInfo{RanName: ids[0].InventoryName, ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} var initialNodeb1 = &entities.NodebInfo{RanName: ids[1].InventoryName, ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} @@ -210,9 +482,14 @@ func TestE2TerminInitHandlerSuccessThreeRansSecondRnibInternalErrorFailure(t *te //xaction = []byte(ids[1].InventoryName) //msg1 := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ids[1].InventoryName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg0, nil) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg0, nil) - handler.Handle(nil) + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, "test1", "test2", "test3") + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + + handler.Handle(notificationRequest) readerMock.AssertNumberOfCalls(t, "GetNodeb", 2) //test1 (+1), test2 failure (0) test3 (0) @@ -221,34 +498,69 @@ func TestE2TerminInitHandlerSuccessThreeRansSecondRnibInternalErrorFailure(t *te rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 1) } -func TestE2TerminInitHandlerSuccessZeroRans(t *testing.T) { - _, handler, readerMock, writerMock, rmrMessengerMock := initRanLostConnectionTest(t) - var rnibErr error +func TestE2TermInitHandlerSuccessZeroRans(t *testing.T) { + _, handler, _, writerMock, rmrMessengerMock, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) - readerMock.On("GetListNodebIds").Return([]*entities.NbIdentity{}, rnibErr) + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} - handler.Handle(nil) + handler.Handle(notificationRequest) - writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 0) - rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 0) + writerMock.AssertNotCalled(t, "UpdateNodebInfo") + rmrMessengerMock.AssertNotCalled(t, "SendMsg") } -func TestE2TerminInitHandlerFailureGetListNodebIds(t *testing.T) { - _, handler, readerMock, writerMock, rmrMessengerMock := initRanLostConnectionTest(t) +func TestE2TermInitHandlerFailureGetNodebInternalError(t *testing.T) { + _, handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) - readerMock.On("GetListNodebIds").Return([]*entities.NbIdentity{}, common.NewInternalError(fmt.Errorf("internal error"))) + var nodebInfo *entities.NodebInfo + readerMock.On("GetNodeb", "test1").Return(nodebInfo, common.NewInternalError(fmt.Errorf("internal error"))) - handler.Handle(nil) + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, "test1") + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + handler.Handle(notificationRequest) - writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 0) - rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 0) + writerMock.AssertNotCalled(t, "UpdateNodebInfo") + rmrMessengerMock.AssertNotCalled(t, "SendMsg") +} + +func TestE2TermInitHandlerSuccessTwoRansSecondIsDisconnected(t *testing.T) { + _, handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, _ := initRanLostConnectionTest(t) + var rnibErr error + var initialNodeb0 = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} + var initialNodeb1 = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST} + readerMock.On("GetNodeb", RanName).Return(initialNodeb0, rnibErr) + readerMock.On("GetNodeb", "test2").Return(initialNodeb1, rnibErr) + + var argNodeb1 = &entities.NodebInfo{ConnectionStatus: entities.ConnectionStatus_CONNECTING, E2ApplicationProtocol: entities.E2ApplicationProtocol_X2_SETUP_REQUEST, ConnectionAttempts: 1} + writerMock.On("UpdateNodebInfo", argNodeb1).Return(rnibErr) + + payload := e2pdus.PackedX2setupRequest + xaction := []byte(RanName) + msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), RanName, &payload, &xaction) + + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil) + + e2tInstance := entities.NewE2TInstance(e2tInstanceAddress) + e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, RanName, "test2") + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceAddress).Return(e2tInstance, nil) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(e2tInitPayload)} + + handler.Handle(notificationRequest) + + writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 2) + rmrMessengerMock.AssertNumberOfCalls(t, "SendMsg", 2) } + // TODO: extract to test_utils func initRmrSender(rmrMessengerMock *mocks.RmrMessengerMock, log *logger.Logger) *rmrsender.RmrSender { rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock) rmrMessengerMock.On("Init", tests.GetPort(), tests.MaxMsgSize, tests.Flags, log).Return(&rmrMessenger) - return rmrsender.NewRmrSender(log, &rmrMessenger) + return rmrsender.NewRmrSender(log, rmrMessenger) } // TODO: extract to test_utils diff --git a/E2Manager/handlers/rmrmsghandlers/e2t_keep_alive_response_handler.go b/E2Manager/handlers/rmrmsghandlers/e2t_keep_alive_response_handler.go new file mode 100644 index 0000000..73583d4 --- /dev/null +++ b/E2Manager/handlers/rmrmsghandlers/e2t_keep_alive_response_handler.go @@ -0,0 +1,51 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package rmrmsghandlers + +import ( + "e2mgr/logger" + "e2mgr/managers" + "e2mgr/models" + "e2mgr/services" + "encoding/json" +) + +type E2TKeepAliveResponseHandler struct { + logger *logger.Logger + rnibDataService services.RNibDataService + e2TInstancesManager managers.IE2TInstancesManager +} + +func NewE2TKeepAliveResponseHandler(logger *logger.Logger, rnibDataService services.RNibDataService, e2TInstancesManager managers.IE2TInstancesManager) E2TKeepAliveResponseHandler { + return E2TKeepAliveResponseHandler{ + logger: logger, + rnibDataService: rnibDataService, + e2TInstancesManager: e2TInstancesManager, + } +} + +func (h E2TKeepAliveResponseHandler) Handle(request *models.NotificationRequest) { + unmarshalledPayload := models.E2TKeepAlivePayload{} + err := json.Unmarshal(request.Payload, &unmarshalledPayload) + + if err != nil { + h.logger.Errorf("#E2TKeepAliveResponseHandler.Handle - Error unmarshaling RMR request payload: %v", err) + return + } + + _ = h.e2TInstancesManager.ResetKeepAliveTimestamp(unmarshalledPayload.Address) +} diff --git a/E2Manager/handlers/rmrmsghandlers/e2t_keep_alive_response_handler_test.go b/E2Manager/handlers/rmrmsghandlers/e2t_keep_alive_response_handler_test.go new file mode 100644 index 0000000..ba9fc43 --- /dev/null +++ b/E2Manager/handlers/rmrmsghandlers/e2t_keep_alive_response_handler_test.go @@ -0,0 +1,59 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package rmrmsghandlers + +import ( + "e2mgr/configuration" + "e2mgr/logger" + "e2mgr/mocks" + "e2mgr/models" + "e2mgr/services" + "testing" +) + +func initE2TKeepAliveTest(t *testing.T) (*logger.Logger, E2TKeepAliveResponseHandler, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.E2TInstancesManagerMock) { + + logger := initLog(t) + config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} + + readerMock := &mocks.RnibReaderMock{} + writerMock := &mocks.RnibWriterMock{} + + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) + + e2tInstancesManagerMock := &mocks.E2TInstancesManagerMock{} + handler := NewE2TKeepAliveResponseHandler(logger, rnibDataService, e2tInstancesManagerMock) + return logger, handler, readerMock, writerMock, e2tInstancesManagerMock +} + +func TestE2TKeepAliveUnmarshalPayloadFailure(t *testing.T) { + _, handler, _, _, e2tInstancesManagerMock := initE2TKeepAliveTest(t) + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte("asd")} + handler.Handle(notificationRequest) + e2tInstancesManagerMock.AssertNotCalled(t, "ResetKeepAliveTimestamp") +} + +func TestE2TKeepAliveUnmarshalPayloadSuccess(t *testing.T) { + _, handler, _, _, e2tInstancesManagerMock := initE2TKeepAliveTest(t) + + jsonRequest := "{\"address\":\"10.10.2.15:9800\"}" + notificationRequest := &models.NotificationRequest{RanName: RanName, Payload: []byte(jsonRequest)} + + e2tInstancesManagerMock.On("ResetKeepAliveTimestamp", "10.10.2.15:9800").Return(nil) + handler.Handle(notificationRequest) + e2tInstancesManagerMock.AssertCalled(t, "ResetKeepAliveTimestamp", "10.10.2.15:9800") +} diff --git a/E2Manager/handlers/rmrmsghandlers/enb_load_information_notification_handler.go b/E2Manager/handlers/rmrmsghandlers/enb_load_information_notification_handler.go index a6a6234..8989af5 100644 --- a/E2Manager/handlers/rmrmsghandlers/enb_load_information_notification_handler.go +++ b/E2Manager/handlers/rmrmsghandlers/enb_load_information_notification_handler.go @@ -1,6 +1,21 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// package rmrmsghandlers -import "C" import ( "e2mgr/converters" "e2mgr/e2pdus" @@ -44,7 +59,7 @@ func (h EnbLoadInformationNotificationHandler) Handle(request *models.Notificati err = h.extractor.ExtractAndBuildRanLoadInformation(pdu, ranLoadInformation) - if (err != nil) { + if err != nil { h.logger.Errorf("#EnbLoadInformationNotificationHandler.Handle - RAN name: %s - Failed at ExtractAndBuildRanLoadInformation. Error: %v", request.RanName, err) return } diff --git a/E2Manager/handlers/rmrmsghandlers/enb_load_information_notification_handler_test.go b/E2Manager/handlers/rmrmsghandlers/enb_load_information_notification_handler_test.go index 9c58274..8c5627a 100644 --- a/E2Manager/handlers/rmrmsghandlers/enb_load_information_notification_handler_test.go +++ b/E2Manager/handlers/rmrmsghandlers/enb_load_information_notification_handler_test.go @@ -34,7 +34,7 @@ const ( GarbagePdu string = "12312312" ) -func createNotificationRequest(ranName string, transactionId string, packedPdu string) (*models.NotificationRequest, error) { +func createNotificationRequest(ranName string, transactionId []byte, packedPdu string) (*models.NotificationRequest, error) { var packedByteSlice []byte _, err := fmt.Sscanf(packedPdu, "%x", &packedByteSlice) @@ -46,7 +46,7 @@ func createNotificationRequest(ranName string, transactionId string, packedPdu s return models.NewNotificationRequest(ranName, packedByteSlice, time.Now(), transactionId), nil } -func createNotificationRequestAndHandle(ranName string, transactionId string, loadInformationHandler EnbLoadInformationNotificationHandler, pdu string) error { +func createNotificationRequestAndHandle(ranName string, transactionId []byte, loadInformationHandler EnbLoadInformationNotificationHandler, pdu string) error { notificationRequest, err := createNotificationRequest(ranName, transactionId, pdu) if err != nil { diff --git a/E2Manager/handlers/rmrmsghandlers/endc_configuration_update_handler.go b/E2Manager/handlers/rmrmsghandlers/endc_configuration_update_handler.go index bfc4e1b..c460941 100644 --- a/E2Manager/handlers/rmrmsghandlers/endc_configuration_update_handler.go +++ b/E2Manager/handlers/rmrmsghandlers/endc_configuration_update_handler.go @@ -32,7 +32,7 @@ import ( "e2mgr/models" "e2mgr/rmrCgo" "e2mgr/services/rmrsender" - "unsafe" + "e2mgr/utils" ) type EndcConfigurationUpdateHandler struct { @@ -49,35 +49,22 @@ func NewEndcConfigurationUpdateHandler(logger *logger.Logger, rmrSender *rmrsend func (h EndcConfigurationUpdateHandler) Handle(request *models.NotificationRequest) { - var payloadSize C.ulong - payloadSize = e2pdus.MaxAsn1PackedBufferSize - packedBuffer := [e2pdus.MaxAsn1PackedBufferSize]C.uchar{} - errorBuffer := [e2pdus.MaxAsn1PackedBufferSize]C.char{} refinedMessage, err := converters.UnpackX2apPduAndRefine(h.logger, e2pdus.MaxAsn1CodecAllocationBufferSize /*allocation buffer*/, request.Len, request.Payload, e2pdus.MaxAsn1CodecMessageBufferSize /*message buffer*/) + if err != nil { - status := C.build_pack_endc_configuration_update_failure(&payloadSize, &packedBuffer[0], e2pdus.MaxAsn1PackedBufferSize, &errorBuffer[0]) - if status { - payload := (*[1 << 30]byte)(unsafe.Pointer(&packedBuffer))[:payloadSize:payloadSize] - h.logger.Debugf("#endc_configuration_update_handler.Handle - Endc configuration update negative ack message payload: (%d) %02x", len(payload), payload) - msg := models.NewRmrMessage(rmrCgo.RIC_ENDC_CONF_UPDATE_FAILURE, request.RanName, payload) - _ = h.rmrSender.Send(msg) - } else { - h.logger.Errorf("#endc_configuration_update_handler.Handle - failed to build and pack Endc configuration update unsuccessful outcome message. Error: %v", errorBuffer) - } h.logger.Errorf("#endc_configuration_update_handler.Handle - unpack failed. Error: %v", err) - } else { - h.logger.Infof("#endc_configuration_update_handler.Handle - Endc configuration update initiating message received") - h.logger.Debugf("#endc_configuration_update_handler.Handle - Endc configuration update initiating message payload: %s", refinedMessage.PduPrint) - status := C.build_pack_endc_configuration_update_ack(&payloadSize, &packedBuffer[0], e2pdus.MaxAsn1PackedBufferSize, &errorBuffer[0]) - if status { - payload := (*[1 << 30]byte)(unsafe.Pointer(&packedBuffer))[:payloadSize:payloadSize] - h.logger.Debugf("#endc_configuration_update_handler.Handle - Endc configuration update positive ack message payload: (%d) %02x", len(payload), payload) - msg := models.NewRmrMessage(rmrCgo.RIC_ENDC_CONF_UPDATE_ACK, request.RanName, payload) - _ = h.rmrSender.Send(msg) - } else { - h.logger.Errorf("#endc_configuration_update_handler.Handle - failed to build and pack endc configuration update successful outcome message. Error: %v", errorBuffer) - } + + msg := models.NewRmrMessage(rmrCgo.RIC_ENDC_CONF_UPDATE_FAILURE, request.RanName, e2pdus.PackedEndcConfigurationUpdateFailure, request.TransactionId) + _ = h.rmrSender.Send(msg) + + h.logger.Infof("#EndcConfigurationUpdateHandler.Handle - Summary: elapsed time for receiving and handling endc configuration update initiating message from E2 terminator: %f ms", utils.ElapsedTime(request.StartTime)) + return } - printHandlingSetupResponseElapsedTimeInMs(h.logger, "#endc_configuration_update_handler.Handle - Summary: Elapsed time for receiving and handling endc configuration update initiating message from E2 terminator", request.StartTime) + h.logger.Infof("#endc_configuration_update_handler.Handle - Endc configuration update initiating message received") + h.logger.Debugf("#endc_configuration_update_handler.Handle - Endc configuration update initiating message payload: %s", refinedMessage.PduPrint) + msg := models.NewRmrMessage(rmrCgo.RIC_ENDC_CONF_UPDATE_ACK, request.RanName, e2pdus.PackedEndcConfigurationUpdateAck, request.TransactionId) + _ = h.rmrSender.Send(msg) + + h.logger.Infof("#EndcConfigurationUpdateHandler.Handle - Summary: elapsed time for receiving and handling endc configuration update initiating message from E2 terminator: %f ms", utils.ElapsedTime(request.StartTime)) } diff --git a/E2Manager/handlers/rmrmsghandlers/endc_configuration_update_handler_test.go b/E2Manager/handlers/rmrmsghandlers/endc_configuration_update_handler_test.go index db847ad..1c2afe9 100644 --- a/E2Manager/handlers/rmrmsghandlers/endc_configuration_update_handler_test.go +++ b/E2Manager/handlers/rmrmsghandlers/endc_configuration_update_handler_test.go @@ -43,31 +43,33 @@ func TestHandleEndcConfigUpdateSuccess(t *testing.T) { h, rmrMessengerMock := initEndcConfigurationUpdateHandlerTest(t) ranName := "test" - xaction := []byte(ranName) + xAction := []byte("123456aa") var payload []byte _, _ = fmt.Sscanf(PackedEndcConfigurationUpdateAck, "%x", &payload) - mBuf := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_CONF_UPDATE_ACK, len(payload), ranName, &payload, &xaction) - notificationRequest := models.NotificationRequest{RanName: mBuf.Meid, Len: mBuf.Len, Payload: *mBuf.Payload, StartTime: time.Now()} + mBuf := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_CONF_UPDATE_ACK, len(payload), ranName, &payload, &xAction) + notificationRequest := models.NotificationRequest{RanName: mBuf.Meid, Len: mBuf.Len, Payload: *mBuf.Payload, StartTime: time.Now(), + TransactionId: *mBuf.XAction} var err error - rmrMessengerMock.On("SendMsg", mBuf).Return(&rmrCgo.MBuf{}, err) + rmrMessengerMock.On("SendMsg", mBuf, true).Return(&rmrCgo.MBuf{}, err) h.Handle(¬ificationRequest) - rmrMessengerMock.AssertCalled(t, "SendMsg", mBuf) + rmrMessengerMock.AssertCalled(t, "SendMsg", mBuf, true) } func TestHandleEndcConfigUpdateFailure(t *testing.T) { h, rmrMessengerMock := initEndcConfigurationUpdateHandlerTest(t) ranName := "test" - xaction := []byte(ranName) + xAction := []byte("123456aa") var payload []byte _, _ = fmt.Sscanf(PackedEndcConfigurationUpdateFailure, "%x", &payload) - mBuf := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_CONF_UPDATE_FAILURE, len(payload), ranName, &payload, &xaction) - notificationRequest := models.NotificationRequest{RanName: mBuf.Meid, Len: 0, Payload: []byte{0}, StartTime: time.Now()} - rmrMessengerMock.On("SendMsg", mBuf).Return(&rmrCgo.MBuf{}, fmt.Errorf("send failure")) + mBuf := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_CONF_UPDATE_FAILURE, len(payload), ranName, &payload, &xAction) + notificationRequest := models.NotificationRequest{RanName: mBuf.Meid, Len: 0, Payload: []byte{0}, StartTime: time.Now(), + TransactionId: *mBuf.XAction} + rmrMessengerMock.On("SendMsg", mBuf, true).Return(&rmrCgo.MBuf{}, fmt.Errorf("send failure")) h.Handle(¬ificationRequest) - rmrMessengerMock.AssertCalled(t, "SendMsg", mBuf) + rmrMessengerMock.AssertCalled(t, "SendMsg", mBuf, true) } diff --git a/E2Manager/handlers/rmrmsghandlers/notification_handler.go b/E2Manager/handlers/rmrmsghandlers/notification_handler.go index 6ec0720..4a85de2 100644 --- a/E2Manager/handlers/rmrmsghandlers/notification_handler.go +++ b/E2Manager/handlers/rmrmsghandlers/notification_handler.go @@ -21,16 +21,9 @@ package rmrmsghandlers import ( - "e2mgr/logger" "e2mgr/models" - "time" ) type NotificationHandler interface { Handle(*models.NotificationRequest) } - -//TODO: remove that -func printHandlingSetupResponseElapsedTimeInMs(logger *logger.Logger, msg string, startTime time.Time) { - logger.Infof("%s: %f ms", msg, float64(time.Since(startTime))/float64(time.Millisecond)) -} diff --git a/E2Manager/handlers/rmrmsghandlers/setup_response_notification_handler_test.go b/E2Manager/handlers/rmrmsghandlers/setup_response_notification_handler_test.go index 111b1a4..f4bfd63 100644 --- a/E2Manager/handlers/rmrmsghandlers/setup_response_notification_handler_test.go +++ b/E2Manager/handlers/rmrmsghandlers/setup_response_notification_handler_test.go @@ -29,7 +29,6 @@ import ( "e2mgr/managers" "e2mgr/mocks" "e2mgr/models" - "e2mgr/rNibWriter" "e2mgr/rmrCgo" "e2mgr/services" "e2mgr/services/rmrsender" @@ -37,7 +36,6 @@ import ( "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -84,13 +82,8 @@ func NewSetupResponseTestContext(manager managers.ISetupResponseManager) *setupR config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} readerMock := &mocks.RnibReaderMock{} writerMock := &mocks.RnibWriterMock{} - rnibReaderProvider := func() reader.RNibReader { - return readerMock - } - rnibWriterProvider := func() rNibWriter.RNibWriter { - return writerMock - } - rnibDataService := services.NewRnibDataService(logger, config, rnibReaderProvider, rnibWriterProvider) + + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) rmrMessengerMock := &mocks.RmrMessengerMock{} rmrSender := initRmrSender(rmrMessengerMock, logger) @@ -157,17 +150,17 @@ func executeHandleSetupSuccessResponse(t *testing.T, tc setupSuccessResponseTest testContext.readerMock.On("GetNodeb", RanName).Return(nodebInfo, rnibErr) testContext.writerMock.On("SaveNodeb", mock.Anything, mock.Anything).Return(tc.saveNodebMockError) - testContext.rmrMessengerMock.On("SendMsg", tc.statusChangeMbuf).Return(&rmrCgo.MBuf{}, tc.sendMsgError) + testContext.rmrMessengerMock.On("SendMsg", tc.statusChangeMbuf, true).Return(&rmrCgo.MBuf{}, tc.sendMsgError) handler.Handle(¬ificationRequest) return testContext, nodebInfo } func getRanConnectedMbuf(nodeType entities.Node_Type) *rmrCgo.MBuf { - xaction := []byte(RanName) + var xAction []byte resourceStatusPayload := models.NewResourceStatusPayload(nodeType, enums.RIC_TO_RAN) resourceStatusJson, _ := json.Marshal(resourceStatusPayload) - return rmrCgo.NewMBuf(rmrCgo.RAN_CONNECTED, len(resourceStatusJson), RanName, &resourceStatusJson, &xaction) + return rmrCgo.NewMBuf(rmrCgo.RAN_CONNECTED, len(resourceStatusJson), RanName, &resourceStatusJson, &xAction) } func executeHandleSetupFailureResponse(t *testing.T, tc setupFailureResponseTestCase) (*setupResponseTestContext, *entities.NodebInfo) { @@ -222,7 +215,7 @@ func TestX2SetupResponse(t *testing.T) { assert.IsType(t, &entities.NodebInfo_Enb{}, nodebInfo.Configuration) i, _ := nodebInfo.Configuration.(*entities.NodebInfo_Enb) assert.NotNil(t, i.Enb) - testContext.rmrMessengerMock.AssertCalled(t, "SendMsg", tc.statusChangeMbuf) + testContext.rmrMessengerMock.AssertCalled(t, "SendMsg", tc.statusChangeMbuf, true) } func TestX2SetupFailureResponse(t *testing.T) { @@ -246,11 +239,12 @@ func TestX2SetupFailureResponse(t *testing.T) { } func TestEndcSetupResponse(t *testing.T) { + logger := initLog(t) var saveNodebMockError error var sendMsgError error tc := setupSuccessResponseTestCase{ EndcSetupResponsePackedPdu, - &managers.EndcSetupResponseManager{}, + managers.NewEndcSetupResponseManager(converters.NewEndcSetupResponseConverter(logger)), rmrCgo.RIC_ENDC_X2_SETUP_RESP, saveNodebMockError, sendMsgError, @@ -267,15 +261,15 @@ func TestEndcSetupResponse(t *testing.T) { i, _ := nodebInfo.Configuration.(*entities.NodebInfo_Gnb) assert.NotNil(t, i.Gnb) - testContext.rmrMessengerMock.AssertCalled(t, "SendMsg", tc.statusChangeMbuf) + testContext.rmrMessengerMock.AssertCalled(t, "SendMsg", tc.statusChangeMbuf, true) } func TestEndcSetupFailureResponse(t *testing.T) { - + logger := initLog(t) var saveNodebMockError error tc := setupFailureResponseTestCase{ EndcSetupFailureResponsePackedPdu, - &managers.EndcSetupFailureResponseManager{}, + managers.NewEndcSetupFailureResponseManager(converters.NewEndcSetupFailureResponseConverter(logger)), rmrCgo.RIC_ENDC_X2_SETUP_FAILURE, saveNodebMockError, } @@ -346,5 +340,5 @@ func TestSetupResponseStatusChangeSendFailure(t *testing.T) { assert.IsType(t, &entities.NodebInfo_Enb{}, nodebInfo.Configuration) i, _ := nodebInfo.Configuration.(*entities.NodebInfo_Enb) assert.NotNil(t, i.Enb) - testContext.rmrMessengerMock.AssertCalled(t, "SendMsg", tc.statusChangeMbuf) + testContext.rmrMessengerMock.AssertCalled(t, "SendMsg", tc.statusChangeMbuf, true) } diff --git a/E2Manager/handlers/rmrmsghandlers/x2_reset_request_notification_handler.go b/E2Manager/handlers/rmrmsghandlers/x2_reset_request_notification_handler.go index 53af51e..164984a 100644 --- a/E2Manager/handlers/rmrmsghandlers/x2_reset_request_notification_handler.go +++ b/E2Manager/handlers/rmrmsghandlers/x2_reset_request_notification_handler.go @@ -35,9 +35,7 @@ import ( "e2mgr/services" "e2mgr/services/rmrsender" "e2mgr/utils" - "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "unsafe" ) type X2ResetRequestNotificationHandler struct { @@ -81,27 +79,9 @@ func (h X2ResetRequestNotificationHandler) Handle(request *models.NotificationRe return } - msg, err := createX2ResetResponseNotification(request) - if err != nil { - h.logger.Errorf("#X2ResetRequestNotificationHandler.Handle - %s", err) - return - } + msg := models.NewRmrMessage(rmrCgo.RIC_X2_RESET_RESP, request.RanName, e2pdus.PackedX2ResetResponse, request.TransactionId) _ = h.rmrSender.Send(msg) h.logger.Infof("#X2ResetRequestNotificationHandler.Handle - Summary: elapsed time for receiving and handling reset request message from E2 terminator: %f ms", utils.ElapsedTime(request.StartTime)) _ = h.ranStatusChangeManager.Execute(rmrCgo.RAN_RESTARTED, enums.RAN_TO_RIC, nb) } - -func createX2ResetResponseNotification(request *models.NotificationRequest) (*models.RmrMessage, error) { - - packedBuffer := make([]C.uchar, e2pdus.MaxAsn1PackedBufferSize) - errorBuffer := make([]C.char, e2pdus.MaxAsn1CodecMessageBufferSize) - var payloadSize = C.ulong(e2pdus.MaxAsn1PackedBufferSize) - - if status := C.build_pack_x2reset_response(&payloadSize, &packedBuffer[0], C.ulong(e2pdus.MaxAsn1CodecMessageBufferSize), &errorBuffer[0]); !status { - return nil, fmt.Errorf("failed to build and pack the reset response message %s ", C.GoString(&errorBuffer[0])) - } - payload := C.GoBytes(unsafe.Pointer(&packedBuffer[0]), C.int(payloadSize)) - msg := models.NewRmrMessage(rmrCgo.RIC_X2_RESET_RESP, request.RanName, payload) - return msg, nil -} diff --git a/E2Manager/handlers/rmrmsghandlers/x2_reset_request_notification_handler_test.go b/E2Manager/handlers/rmrmsghandlers/x2_reset_request_notification_handler_test.go index 7a7e95c..6b6f00c 100644 --- a/E2Manager/handlers/rmrmsghandlers/x2_reset_request_notification_handler_test.go +++ b/E2Manager/handlers/rmrmsghandlers/x2_reset_request_notification_handler_test.go @@ -33,7 +33,6 @@ import ( "encoding/json" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "testing" "time" ) @@ -42,10 +41,8 @@ func initX2ResetRequestNotificationHandlerTest(t *testing.T) (X2ResetRequestNoti log := initLog(t) config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} readerMock := &mocks.RnibReaderMock{} - readerProvider := func() reader.RNibReader { - return readerMock - } - rnibDataService := services.NewRnibDataService(log, config, readerProvider, nil) + + rnibDataService := services.NewRnibDataService(log, config, readerMock, nil) rmrMessengerMock := &mocks.RmrMessengerMock{} rmrSender := initRmrSender(rmrMessengerMock, log) @@ -55,38 +52,38 @@ func initX2ResetRequestNotificationHandlerTest(t *testing.T) (X2ResetRequestNoti } func getRanRestartedMbuf(nodeType entities.Node_Type, messageDirection enums.MessageDirection) *rmrCgo.MBuf { - xaction := []byte(RanName) + var xAction []byte resourceStatusPayload := models.NewResourceStatusPayload(nodeType, messageDirection) resourceStatusJson, _ := json.Marshal(resourceStatusPayload) - return rmrCgo.NewMBuf(rmrCgo.RAN_RESTARTED, len(resourceStatusJson), RanName, &resourceStatusJson, &xaction) + return rmrCgo.NewMBuf(rmrCgo.RAN_RESTARTED, len(resourceStatusJson), RanName, &resourceStatusJson, &xAction) } func TestHandleX2ResetRequestNotificationSuccess(t *testing.T) { h, readerMock, rmrMessengerMock := initX2ResetRequestNotificationHandlerTest(t) ranName := "test" - xaction := []byte(ranName) - notificationRequest := models.NewNotificationRequest(ranName, []byte{}, time.Now(), ranName) + xAction := []byte("123456aa") + notificationRequest := models.NewNotificationRequest(ranName, []byte{}, time.Now(), xAction) nb := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_CONNECTED, NodeType: entities.Node_ENB} var err error readerMock.On("GetNodeb", ranName).Return(nb, err) - resetResponseMbuf := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET_RESP, len(e2pdus.PackedX2ResetResponse), ranName, &e2pdus.PackedX2ResetResponse, &xaction) - rmrMessengerMock.On("SendMsg", resetResponseMbuf).Return(&rmrCgo.MBuf{}, err) + resetResponseMbuf := rmrCgo.NewMBuf(rmrCgo.RIC_X2_RESET_RESP, len(e2pdus.PackedX2ResetResponse), ranName, &e2pdus.PackedX2ResetResponse, &xAction) + rmrMessengerMock.On("SendMsg", resetResponseMbuf, true).Return(&rmrCgo.MBuf{}, err) ranRestartedMbuf := getRanRestartedMbuf(nb.NodeType, enums.RAN_TO_RIC) - rmrMessengerMock.On("SendMsg", ranRestartedMbuf).Return(&rmrCgo.MBuf{}, err) + rmrMessengerMock.On("SendMsg", ranRestartedMbuf, true).Return(&rmrCgo.MBuf{}, err) h.Handle(notificationRequest) - rmrMessengerMock.AssertCalled(t, "SendMsg", resetResponseMbuf) - rmrMessengerMock.AssertCalled(t, "SendMsg", ranRestartedMbuf) + rmrMessengerMock.AssertCalled(t, "SendMsg", resetResponseMbuf, true) + rmrMessengerMock.AssertCalled(t, "SendMsg", ranRestartedMbuf, true) } func TestHandleX2ResetRequestNotificationShuttingDownStatus(t *testing.T) { h, readerMock, rmrMessengerMock := initX2ResetRequestNotificationHandlerTest(t) var payload []byte - xaction := []byte("RanName") - mBuf := rmrCgo.NewMBuf(tests.MessageType, len(payload), "RanName", &payload, &xaction) + xAction := []byte("123456aa") + mBuf := rmrCgo.NewMBuf(tests.MessageType, len(payload), "RanName", &payload, &xAction) notificationRequest := models.NotificationRequest{RanName: mBuf.Meid, Len: mBuf.Len, Payload: *mBuf.Payload, - StartTime: time.Now(), TransactionId: string(xaction)} + StartTime: time.Now(), TransactionId: xAction} nb := &entities.NodebInfo{RanName: mBuf.Meid, ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN,} var rnibErr error @@ -100,9 +97,9 @@ func TestHandleX2ResetRequestNotificationShuttingDownStatus(t *testing.T) { func TestHandleX2ResetRequestNotificationDisconnectStatus(t *testing.T) { h, readerMock, rmrMessengerMock := initX2ResetRequestNotificationHandlerTest(t) var payload []byte - xaction := []byte("RanName") - mBuf := rmrCgo.NewMBuf(tests.MessageType, len(payload), "RanName", &payload, &xaction) - notificationRequest := models.NotificationRequest{RanName: mBuf.Meid, Len: mBuf.Len, Payload: *mBuf.Payload, StartTime: time.Now(), TransactionId: string(xaction)} + xAction := []byte("123456aa") + mBuf := rmrCgo.NewMBuf(tests.MessageType, len(payload), "RanName", &payload, &xAction) + notificationRequest := models.NotificationRequest{RanName: mBuf.Meid, Len: mBuf.Len, Payload: *mBuf.Payload, StartTime: time.Now(), TransactionId: xAction} nb := &entities.NodebInfo{RanName: mBuf.Meid, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED,} var rnibErr error readerMock.On("GetNodeb", mBuf.Meid).Return(nb, rnibErr) @@ -115,10 +112,10 @@ func TestHandleX2ResetRequestNotificationGetNodebFailed(t *testing.T) { h, readerMock, rmrMessengerMock := initX2ResetRequestNotificationHandlerTest(t) var payload []byte - xaction := []byte("RanName") - mBuf := rmrCgo.NewMBuf(tests.MessageType, len(payload), "RanName", &payload, &xaction) + var xAction []byte + mBuf := rmrCgo.NewMBuf(tests.MessageType, len(payload), "RanName", &payload, &xAction) notificationRequest := models.NotificationRequest{RanName: mBuf.Meid, Len: mBuf.Len, Payload: *mBuf.Payload, - StartTime: time.Now(), TransactionId: string(xaction)} + StartTime: time.Now(), TransactionId: xAction} var nb *entities.NodebInfo rnibErr := &common.ResourceNotFoundError{} diff --git a/E2Manager/handlers/rmrmsghandlers/x2_reset_response_handler.go b/E2Manager/handlers/rmrmsghandlers/x2_reset_response_handler.go index 2c26b43..1097ed2 100644 --- a/E2Manager/handlers/rmrmsghandlers/x2_reset_response_handler.go +++ b/E2Manager/handlers/rmrmsghandlers/x2_reset_response_handler.go @@ -56,7 +56,7 @@ func (h X2ResetResponseHandler) Handle(request *models.NotificationRequest) { ranName := request.RanName h.logger.Infof("#X2ResetResponseHandler.Handle - RAN name: %s - received reset response. Payload: %x", ranName, request.Payload) - nodebInfo, err := h.rnibDataService.GetNodeb(ranName); + nodebInfo, err := h.rnibDataService.GetNodeb(ranName) if err != nil { h.logger.Errorf("#x2ResetResponseHandler.Handle - RAN name: %s - failed to retrieve nodebInfo entity. Error: %s", ranName, err) return diff --git a/E2Manager/handlers/rmrmsghandlers/x2_reset_response_handler_test.go b/E2Manager/handlers/rmrmsghandlers/x2_reset_response_handler_test.go index 2ff6094..7a99903 100644 --- a/E2Manager/handlers/rmrmsghandlers/x2_reset_response_handler_test.go +++ b/E2Manager/handlers/rmrmsghandlers/x2_reset_response_handler_test.go @@ -33,7 +33,6 @@ import ( "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "testing" "time" ) @@ -51,11 +50,8 @@ func initX2ResetResponseHandlerTest(t *testing.T) (X2ResetResponseHandler, *mock t.Errorf("#initX2ResetResponseHandlerTest - failed to initialize logger, error: %s", err) } readerMock := &mocks.RnibReaderMock{} - rnibReaderProvider := func() reader.RNibReader { - return readerMock - } - rnibDataService := services.NewRnibDataService(log, config, rnibReaderProvider, nil) + rnibDataService := services.NewRnibDataService(log, config, readerMock, nil) rmrMessengerMock := &mocks.RmrMessengerMock{} rmrSender := initRmrSender(rmrMessengerMock, log) @@ -73,15 +69,15 @@ func TestX2ResetResponseSuccess(t *testing.T) { t.Fatalf("Failed converting packed pdu. Error: %v\n", err) } - xaction := []byte(RanName) - notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: string(xaction)} + var xAction []byte + notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: xAction} nb := &entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_CONNECTED, NodeType: entities.Node_ENB} var rnibErr error readerMock.On("GetNodeb", RanName).Return(nb, rnibErr) ranRestartedMbuf := getRanRestartedMbuf(nb.NodeType, enums.RIC_TO_RAN) - rmrMessengerMock.On("SendMsg", ranRestartedMbuf).Return(&rmrCgo.MBuf{}, err) + rmrMessengerMock.On("SendMsg", ranRestartedMbuf, true).Return(&rmrCgo.MBuf{}, err) h.Handle(¬ificationRequest) - rmrMessengerMock.AssertCalled(t, "SendMsg", ranRestartedMbuf) + rmrMessengerMock.AssertCalled(t, "SendMsg", ranRestartedMbuf, true) } func TestX2ResetResponseSuccessEmptyIEs(t *testing.T) { @@ -92,15 +88,15 @@ func TestX2ResetResponseSuccessEmptyIEs(t *testing.T) { t.Fatalf("Failed converting packed pdu. Error: %v\n", err) } - xaction := []byte(RanName) - notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: string(xaction)} + var xAction []byte + notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: xAction} nb := &entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_CONNECTED, NodeType: entities.Node_ENB} var rnibErr error readerMock.On("GetNodeb", RanName).Return(nb, rnibErr) ranRestartedMbuf := getRanRestartedMbuf(nb.NodeType, enums.RIC_TO_RAN) - rmrMessengerMock.On("SendMsg", ranRestartedMbuf).Return(&rmrCgo.MBuf{}, err) + rmrMessengerMock.On("SendMsg", ranRestartedMbuf, true).Return(&rmrCgo.MBuf{}, err) h.Handle(¬ificationRequest) - rmrMessengerMock.AssertCalled(t, "SendMsg", ranRestartedMbuf) + rmrMessengerMock.AssertCalled(t, "SendMsg", ranRestartedMbuf, true) } func TestX2ResetResponseShuttingDown(t *testing.T) { @@ -111,8 +107,8 @@ func TestX2ResetResponseShuttingDown(t *testing.T) { t.Fatalf("Failed converting packed pdu. Error: %v\n", err) } - xaction := []byte(RanName) - notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: string(xaction)} + var xAction []byte + notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: xAction} nb := &entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN, NodeType: entities.Node_ENB} var rnibErr error readerMock.On("GetNodeb", RanName).Return(nb, rnibErr) @@ -128,8 +124,8 @@ func TestX2ResetResponseInvalidConnectionStatus(t *testing.T) { t.Fatalf("Failed converting packed pdu. Error: %v\n", err) } - xaction := []byte(RanName) - notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: string(xaction)} + var xAction []byte + notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: xAction} nb := &entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED, NodeType: entities.Node_ENB} var rnibErr error readerMock.On("GetNodeb", RanName).Return(nb, rnibErr) @@ -145,8 +141,8 @@ func TestX2ResetResponseError(t *testing.T) { t.Fatalf("Failed converting packed pdu. Error: %v\n", err) } - xaction := []byte(RanName) - notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: string(xaction)} + var xAction []byte + notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: xAction} nb := &entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_CONNECTED, NodeType: entities.Node_ENB} var rnibErr error readerMock.On("GetNodeb", RanName).Return(nb, rnibErr) @@ -163,8 +159,8 @@ func TestX2ResetResponseGetNodebFailure(t *testing.T) { t.Fatalf("Failed converting packed pdu. Error: %v\n", err) } - xaction := []byte(RanName) - notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: string(xaction)} + var xAction []byte + notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: xAction} var nb *entities.NodebInfo rnibErr := common.NewResourceNotFoundError("nodeb not found") @@ -178,8 +174,8 @@ func TestX2ResetResponseUnpackFailure(t *testing.T) { h, readerMock, rmrMessengerMock := initX2ResetResponseHandlerTest(t) payload := []byte("Invalid payload") - xaction := []byte(RanName) - notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: string(xaction)} + var xAction []byte + notificationRequest := models.NotificationRequest{RanName: RanName, Len: len(payload), Payload: payload, StartTime: time.Now(), TransactionId: xAction} nb := &entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_CONNECTED, NodeType: entities.Node_ENB} var rnibErr error readerMock.On("GetNodeb", RanName).Return(nb, rnibErr) diff --git a/E2Manager/handlers/rmrmsghandlers/x2enb_configuration_update_handler.go b/E2Manager/handlers/rmrmsghandlers/x2enb_configuration_update_handler.go index d33f784..591acff 100644 --- a/E2Manager/handlers/rmrmsghandlers/x2enb_configuration_update_handler.go +++ b/E2Manager/handlers/rmrmsghandlers/x2enb_configuration_update_handler.go @@ -32,7 +32,7 @@ import ( "e2mgr/models" "e2mgr/rmrCgo" "e2mgr/services/rmrsender" - "unsafe" + "e2mgr/utils" ) type X2EnbConfigurationUpdateHandler struct { @@ -49,40 +49,23 @@ func NewX2EnbConfigurationUpdateHandler(logger *logger.Logger, rmrSender *rmrsen func (h X2EnbConfigurationUpdateHandler) Handle(request *models.NotificationRequest) { - var payloadSize C.ulong - payloadSize = e2pdus.MaxAsn1PackedBufferSize - packedBuffer := [e2pdus.MaxAsn1PackedBufferSize]C.uchar{} - errorBuffer := [e2pdus.MaxAsn1PackedBufferSize]C.char{} - refinedMessage, err := converters.UnpackX2apPduAndRefine(h.logger, e2pdus.MaxAsn1CodecAllocationBufferSize, request.Len, request.Payload, e2pdus.MaxAsn1CodecMessageBufferSize) if err != nil { - status := C.build_pack_x2enb_configuration_update_failure(&payloadSize, &packedBuffer[0], e2pdus.MaxAsn1PackedBufferSize, &errorBuffer[0]) - if status { - payload := (*[1 << 30]byte)(unsafe.Pointer(&packedBuffer))[:payloadSize:payloadSize] - h.logger.Debugf("#x2enb_configuration_update_handler.Handle - Enb configuration update negative ack message payload: (%d) %02x", len(payload), payload) - msg := models.NewRmrMessage(rmrCgo.RIC_ENB_CONFIGURATION_UPDATE_FAILURE, request.RanName, payload) - _ = h.rmrSender.Send(msg) - } else { - h.logger.Errorf("#x2enb_configuration_update_handler.Handle - failed to build and pack Enb configuration update unsuccessful outcome message. Error: %v", errorBuffer) - } h.logger.Errorf("#x2enb_configuration_update_handler.Handle - unpack failed. Error: %v", err) - printHandlingSetupResponseElapsedTimeInMs(h.logger, "#x2enb_configuration_update_handler.Handle - Summary: Elapsed time for receiving and handling enb configuration update initiating message from E2 terminator", request.StartTime) + msg := models.NewRmrMessage(rmrCgo.RIC_ENB_CONFIGURATION_UPDATE_FAILURE, request.RanName, e2pdus.PackedX2EnbConfigurationUpdateFailure, request.TransactionId) + _ = h.rmrSender.Send(msg) + + h.logger.Infof("#X2EnbConfigurationUpdateHandler.Handle - Summary: elapsed time for receiving and handling enb configuration update initiating message from E2 terminator: %f ms", utils.ElapsedTime(request.StartTime)) return } h.logger.Infof("#x2enb_configuration_update_handler.Handle - Enb configuration update initiating message received") h.logger.Debugf("#x2enb_configuration_update_handler.Handle - Enb configuration update initiating message payload: %s", refinedMessage.PduPrint) - status := C.build_pack_x2enb_configuration_update_ack(&payloadSize, &packedBuffer[0], e2pdus.MaxAsn1PackedBufferSize, &errorBuffer[0]) - if status { - payload := (*[1 << 30]byte)(unsafe.Pointer(&packedBuffer))[:payloadSize:payloadSize] - h.logger.Debugf("#x2enb_configuration_update_handler.Handle - Enb configuration update positive ack message payload: (%d) %02x", len(payload), payload) - msg := models.NewRmrMessage(rmrCgo.RIC_ENB_CONFIGURATION_UPDATE_ACK, request.RanName, payload) - _ = h.rmrSender.Send(msg) - } else { - h.logger.Errorf("#x2enb_configuration_update_handler.Handle - failed to build and pack enb configuration update successful outcome message. Error: %v", errorBuffer) - } - printHandlingSetupResponseElapsedTimeInMs(h.logger, "#x2enb_configuration_update_handler.Handle - Summary: Elapsed time for receiving and handling enb configuration update initiating message from E2 terminator", request.StartTime) + msg := models.NewRmrMessage(rmrCgo.RIC_ENB_CONFIGURATION_UPDATE_ACK, request.RanName, e2pdus.PackedX2EnbConfigurationUpdateAck,request.TransactionId) + _ = h.rmrSender.Send(msg) + + h.logger.Infof("#X2EnbConfigurationUpdateHandler.Handle - Summary: elapsed time for receiving and handling enb configuration update initiating message from E2 terminator: %f ms", utils.ElapsedTime(request.StartTime)) } diff --git a/E2Manager/handlers/rmrmsghandlers/x2enb_configuration_update_handler_test.go b/E2Manager/handlers/rmrmsghandlers/x2enb_configuration_update_handler_test.go index 60a3a96..c29d21b 100644 --- a/E2Manager/handlers/rmrmsghandlers/x2enb_configuration_update_handler_test.go +++ b/E2Manager/handlers/rmrmsghandlers/x2enb_configuration_update_handler_test.go @@ -43,31 +43,32 @@ func TestHandleX2EnbConfigUpdateSuccess(t *testing.T) { h, rmrMessengerMock := initX2EnbConfigurationUpdateHandlerTest(t) ranName := "test" - xaction := []byte(ranName) - + xAction := []byte("123456aa") var payload []byte _, _ = fmt.Sscanf(PackedX2EnbConfigurationUpdateAck, "%x", &payload) - mBuf := rmrCgo.NewMBuf(rmrCgo.RIC_ENB_CONFIGURATION_UPDATE_ACK, len(payload), ranName, &payload, &xaction) - notificationRequest := models.NotificationRequest{RanName: mBuf.Meid, Len: mBuf.Len, Payload: *mBuf.Payload, StartTime: time.Now()} + mBuf := rmrCgo.NewMBuf(rmrCgo.RIC_ENB_CONFIGURATION_UPDATE_ACK, len(payload), ranName, &payload, &xAction) + notificationRequest := models.NotificationRequest{RanName: mBuf.Meid, Len: mBuf.Len, Payload: *mBuf.Payload, + StartTime: time.Now(), TransactionId:xAction} var err error - rmrMessengerMock.On("SendMsg", mBuf).Return(&rmrCgo.MBuf{}, err) + rmrMessengerMock.On("SendMsg", mBuf, true).Return(&rmrCgo.MBuf{}, err) h.Handle(¬ificationRequest) - rmrMessengerMock.AssertCalled(t, "SendMsg", mBuf) + rmrMessengerMock.AssertCalled(t, "SendMsg", mBuf, true) } func TestHandleX2EnbConfigUpdateFailure(t *testing.T) { h, rmrMessengerMock := initX2EnbConfigurationUpdateHandlerTest(t) ranName := "test" - xaction := []byte(ranName) + xAction := []byte("123456aa") var payload []byte _, _ = fmt.Sscanf(PackedX2EnbConfigurationUpdateFailure, "%x", &payload) - mBuf := rmrCgo.NewMBuf(rmrCgo.RIC_ENB_CONFIGURATION_UPDATE_FAILURE, len(payload), ranName, &payload, &xaction) - notificationRequest := models.NotificationRequest{RanName: mBuf.Meid, Len: 0, Payload: []byte{0}, StartTime: time.Now()} - rmrMessengerMock.On("SendMsg", mBuf).Return(&rmrCgo.MBuf{}, fmt.Errorf("send failure")) + mBuf := rmrCgo.NewMBuf(rmrCgo.RIC_ENB_CONFIGURATION_UPDATE_FAILURE, len(payload), ranName, &payload, &xAction) + notificationRequest := models.NotificationRequest{RanName: mBuf.Meid, Len: 0, Payload: []byte{0}, + StartTime: time.Now(), TransactionId:xAction} + rmrMessengerMock.On("SendMsg", mBuf, true).Return(&rmrCgo.MBuf{}, fmt.Errorf("send failure")) h.Handle(¬ificationRequest) - rmrMessengerMock.AssertCalled(t, "SendMsg", mBuf) + rmrMessengerMock.AssertCalled(t, "SendMsg", mBuf, true) } diff --git a/E2Manager/httpserver/http_server.go b/E2Manager/httpserver/http_server.go index 1c087bd..608110f 100644 --- a/E2Manager/httpserver/http_server.go +++ b/E2Manager/httpserver/http_server.go @@ -22,27 +22,26 @@ package httpserver import ( "e2mgr/controllers" + "e2mgr/logger" "fmt" "github.com/gorilla/mux" - "log" "net/http" ) -func Run(port int, controller controllers.IRootController, newController controllers.INodebController) { +func Run(log *logger.Logger, port int, rootController controllers.IRootController, nodebController controllers.INodebController, e2tController controllers.IE2TController) error { router := mux.NewRouter(); - initializeRoutes(router, controller, newController) + initializeRoutes(router, rootController, nodebController, e2tController) addr := fmt.Sprintf(":%d", port) err := http.ListenAndServe(addr, router) - if err != nil { - log.Fatalf("#http_server.Run - Fail initiating HTTP server. Error: %v", err) - } + log.Errorf("#http_server.Run - Fail initiating HTTP server. Error: %v", err) + return err } -func initializeRoutes(router *mux.Router, rootController controllers.IRootController, nodebController controllers.INodebController) { +func initializeRoutes(router *mux.Router, rootController controllers.IRootController, nodebController controllers.INodebController, e2tController controllers.IE2TController) { r := router.PathPrefix("/v1").Subrouter() r.HandleFunc("/health", rootController.HandleHealthCheckRequest).Methods("GET") @@ -53,4 +52,7 @@ func initializeRoutes(router *mux.Router, rootController controllers.IRootContro rr.HandleFunc("/{ranName}/reset", nodebController.X2Reset).Methods("PUT") rr.HandleFunc("/x2-setup", nodebController.X2Setup).Methods("POST") rr.HandleFunc("/endc-setup", nodebController.EndcSetup).Methods("POST") + + rrr := r.PathPrefix("/e2t").Subrouter() + rrr.HandleFunc("/list", e2tController.GetE2TInstances).Methods("GET") } diff --git a/E2Manager/httpserver/http_server_test.go b/E2Manager/httpserver/http_server_test.go index c841681..e6e1ef5 100644 --- a/E2Manager/httpserver/http_server_test.go +++ b/E2Manager/httpserver/http_server_test.go @@ -21,37 +21,39 @@ package httpserver import ( + "e2mgr/logger" "e2mgr/mocks" "github.com/gorilla/mux" "github.com/stretchr/testify/assert" "net/http" "net/http/httptest" "testing" + "time" ) -func setupRouterAndMocks() (*mux.Router, *mocks.ControllerMock, *mocks.NodebControllerMock) { - controllerMock := &mocks.ControllerMock{} - controllerMock.On("Shutdown").Return(nil) - controllerMock.On("X2Reset").Return(nil) - controllerMock.On("X2Setup").Return(nil) - controllerMock.On("EndcSetup").Return(nil) - controllerMock.On("GetNodeb").Return(nil) - controllerMock.On("GetNodebIdList").Return(nil) - - +func setupRouterAndMocks() (*mux.Router, *mocks.RootControllerMock, *mocks.NodebControllerMock, *mocks.E2TControllerMock) { + rootControllerMock := &mocks.RootControllerMock{} + rootControllerMock.On("HandleHealthCheckRequest").Return(nil) nodebControllerMock := &mocks.NodebControllerMock{} + nodebControllerMock.On("Shutdown").Return(nil) + nodebControllerMock.On("X2Reset").Return(nil) + nodebControllerMock.On("X2Setup").Return(nil) + nodebControllerMock.On("EndcSetup").Return(nil) + nodebControllerMock.On("GetNodeb").Return(nil) nodebControllerMock.On("GetNodebIdList").Return(nil) - nodebControllerMock.On("GetNodeb").Return(nil) // TODO: remove - nodebControllerMock.On("HandleHealthCheckRequest").Return(nil) + + e2tControllerMock := &mocks.E2TControllerMock{} + + e2tControllerMock.On("GetE2TInstances").Return(nil) router := mux.NewRouter() - initializeRoutes(router, nodebControllerMock, controllerMock) - return router, controllerMock, nodebControllerMock + initializeRoutes(router, rootControllerMock, nodebControllerMock, e2tControllerMock) + return router, rootControllerMock, nodebControllerMock, e2tControllerMock } func TestRoutePostEndcSetup(t *testing.T) { - router, controllerMock, _ := setupRouterAndMocks() + router, _, nodebControllerMock, _ := setupRouterAndMocks() req, err := http.NewRequest("POST", "/v1/nodeb/endc-setup", nil) if err != nil { @@ -60,11 +62,11 @@ func TestRoutePostEndcSetup(t *testing.T) { rr := httptest.NewRecorder() router.ServeHTTP(rr, req) - controllerMock.AssertNumberOfCalls(t,"EndcSetup", 1) + nodebControllerMock.AssertNumberOfCalls(t, "EndcSetup", 1) } func TestRoutePostX2Setup(t *testing.T) { - router, controllerMock, _ := setupRouterAndMocks() + router, _, nodebControllerMock, _ := setupRouterAndMocks() req, err := http.NewRequest("POST", "/v1/nodeb/x2-setup", nil) if err != nil { @@ -73,11 +75,11 @@ func TestRoutePostX2Setup(t *testing.T) { rr := httptest.NewRecorder() router.ServeHTTP(rr, req) - controllerMock.AssertNumberOfCalls(t,"X2Setup", 1) + nodebControllerMock.AssertNumberOfCalls(t, "X2Setup", 1) } func TestRouteGetNodebIds(t *testing.T) { - router, controllerMock, _ := setupRouterAndMocks() + router, _, nodebControllerMock, _ := setupRouterAndMocks() req, err := http.NewRequest("GET", "/v1/nodeb/ids", nil) if err != nil { @@ -86,11 +88,11 @@ func TestRouteGetNodebIds(t *testing.T) { rr := httptest.NewRecorder() router.ServeHTTP(rr, req) - controllerMock.AssertNumberOfCalls(t, "GetNodebIdList", 1) + nodebControllerMock.AssertNumberOfCalls(t, "GetNodebIdList", 1) } func TestRouteGetNodebRanName(t *testing.T) { - router, controllerMock,_ := setupRouterAndMocks() + router, _, nodebControllerMock, _ := setupRouterAndMocks() req, err := http.NewRequest("GET", "/v1/nodeb/ran1", nil) if err != nil { @@ -101,11 +103,11 @@ func TestRouteGetNodebRanName(t *testing.T) { assert.Equal(t, http.StatusOK, rr.Code, "handler returned wrong status code") assert.Equal(t, "ran1", rr.Body.String(), "handler returned wrong body") - controllerMock.AssertNumberOfCalls(t, "GetNodeb", 1) + nodebControllerMock.AssertNumberOfCalls(t, "GetNodeb", 1) } func TestRouteGetHealth(t *testing.T) { - router, _, nodebControllerMock := setupRouterAndMocks() + router, rootControllerMock, _, _ := setupRouterAndMocks() req, err := http.NewRequest("GET", "/v1/health", nil) if err != nil { @@ -114,11 +116,11 @@ func TestRouteGetHealth(t *testing.T) { rr := httptest.NewRecorder() router.ServeHTTP(rr, req) - nodebControllerMock.AssertNumberOfCalls(t, "HandleHealthCheckRequest", 1) + rootControllerMock.AssertNumberOfCalls(t, "HandleHealthCheckRequest", 1) } func TestRoutePutNodebShutdown(t *testing.T) { - router, controllerMock, _ := setupRouterAndMocks() + router, _, nodebControllerMock, _ := setupRouterAndMocks() req, err := http.NewRequest("PUT", "/v1/nodeb/shutdown", nil) if err != nil { @@ -127,11 +129,11 @@ func TestRoutePutNodebShutdown(t *testing.T) { rr := httptest.NewRecorder() router.ServeHTTP(rr, req) - controllerMock.AssertNumberOfCalls(t, "Shutdown", 1) + nodebControllerMock.AssertNumberOfCalls(t, "Shutdown", 1) } func TestRoutePutNodebResetRanName(t *testing.T) { - router, controllerMock, _ := setupRouterAndMocks() + router, _, nodebControllerMock, _ := setupRouterAndMocks() req, err := http.NewRequest("PUT", "/v1/nodeb/ran1/reset", nil) if err != nil { @@ -142,11 +144,11 @@ func TestRoutePutNodebResetRanName(t *testing.T) { assert.Equal(t, http.StatusOK, rr.Code, "handler returned wrong status code") assert.Equal(t, "ran1", rr.Body.String(), "handler returned wrong body") - controllerMock.AssertNumberOfCalls(t, "X2Reset", 1) + nodebControllerMock.AssertNumberOfCalls(t, "X2Reset", 1) } func TestRouteNotFound(t *testing.T) { - router, _, _ := setupRouterAndMocks() + router, _, _,_ := setupRouterAndMocks() req, err := http.NewRequest("GET", "/v1/no/such/route", nil) if err != nil { @@ -156,4 +158,31 @@ func TestRouteNotFound(t *testing.T) { router.ServeHTTP(rr, req) assert.Equal(t, http.StatusNotFound, rr.Code, "handler returned wrong status code") -} \ No newline at end of file +} + +func TestRunError(t *testing.T) { + log := initLog(t) + err := Run(log, 1234567, &mocks.RootControllerMock{}, &mocks.NodebControllerMock{}, &mocks.E2TControllerMock{}) + assert.NotNil(t, err) +} + +func TestRun(t *testing.T) { + log := initLog(t) + _, rootControllerMock, nodebControllerMock, e2tControllerMock := setupRouterAndMocks() + go Run(log, 11223, rootControllerMock, nodebControllerMock, e2tControllerMock) + + time.Sleep(time.Millisecond * 100) + resp, err := http.Get("http://localhost:11223/v1/health") + if err != nil { + t.Fatalf("failed to perform GET to http://localhost:11223/v1/health") + } + assert.Equal(t, 200, resp.StatusCode) +} + +func initLog(t *testing.T) *logger.Logger { + log, err := logger.InitLogger(logger.InfoLevel) + if err != nil { + t.Errorf("#initLog test - failed to initialize logger, error: %s", err) + } + return log +} diff --git a/E2Manager/logger/logger_test.go b/E2Manager/logger/logger_test.go index 9921ce1..d1d00d2 100644 --- a/E2Manager/logger/logger_test.go +++ b/E2Manager/logger/logger_test.go @@ -44,6 +44,34 @@ func TestInitInfoLoggerSuccess(t *testing.T) { assert.True(t, log.Logger.Core().Enabled(zap.InfoLevel)) } +func TestInitWarnLoggerSuccess(t *testing.T) { + log, err := InitLogger(WarnLevel) + assert.Nil(t, err) + assert.NotNil(t, log) + assert.True(t, log.Logger.Core().Enabled(zap.WarnLevel)) +} + +func TestInitErrorLoggerSuccess(t *testing.T) { + log, err := InitLogger(ErrorLevel) + assert.Nil(t, err) + assert.NotNil(t, log) + assert.True(t, log.Logger.Core().Enabled(zap.ErrorLevel)) +} + +func TestInitDPanicLoggerSuccess(t *testing.T) { + log, err := InitLogger(DPanicLevel) + assert.Nil(t, err) + assert.NotNil(t, log) + assert.True(t, log.Logger.Core().Enabled(zap.DPanicLevel)) +} + +func TestInitPanicLoggerSuccess(t *testing.T) { + log, err := InitLogger(PanicLevel) + assert.Nil(t, err) + assert.NotNil(t, log) + assert.True(t, log.Logger.Core().Enabled(zap.PanicLevel)) +} + func TestInitInfoLoggerFailure(t *testing.T) { log, err := InitLogger(99) assert.NotNil(t, err) @@ -63,7 +91,7 @@ func TestSyncSuccess(t *testing.T){ } err = log.Sync() assert.Nil(t, err) - + os.Stdout = old logFile, err = os.Open("./loggerTest.txt") if err != nil{ @@ -144,6 +172,22 @@ func TestDebugfFatalLevel(t *testing.T) { assert.False(t,validateRecordExists(FatalLevel, zap.DebugLevel, t)) } +func TestWarnfWarnLevel(t *testing.T) { + assert.True(t,validateRecordExists(WarnLevel, zap.WarnLevel, t)) +} + +func TestWarnfDebugLevel(t *testing.T) { + assert.True(t,validateRecordExists(DebugLevel, zap.WarnLevel, t)) +} + +func TestWarnfInfoLevel(t *testing.T) { + assert.True(t,validateRecordExists(InfoLevel, zap.WarnLevel, t)) +} + +func TestWarnfFatalLevel(t *testing.T) { + assert.False(t,validateRecordExists(FatalLevel, zap.WarnLevel, t)) +} + func TestLogLevelTokenToLevel(t *testing.T) { level, ok := LogLevelTokenToLevel("deBug") assert.True(t, ok) @@ -218,14 +262,16 @@ func validateRecordExists(logLevel LogLevel, recordLevel zapcore.Level, t *testi t.Errorf("logger_test.TestSyncFailure - failed to initialize logger, error: %s", err) } switch recordLevel{ - case zap.DebugLevel: - log.Debugf("%v, %v, %v", 1, "abc", 0.1) - case zap.InfoLevel: - log.Infof("%v, %v, %v", 1, "abc", 0.1) - case zap.ErrorLevel: - log.Errorf("%v, %v, %v", 1, "abc", 0.1) - case zap.DPanicLevel: - log.DPanicf("%v, %v, %v", 1, "abc", 0.1) + case zap.DebugLevel: + log.Debugf("%v, %v, %v", 1, "abc", 0.1) + case zap.InfoLevel: + log.Infof("%v, %v, %v", 1, "abc", 0.1) + case zap.WarnLevel: + log.Warnf("%v, %v, %v", 1, "abc", 0.1) + case zap.ErrorLevel: + log.Errorf("%v, %v, %v", 1, "abc", 0.1) + case zap.DPanicLevel: + log.DPanicf("%v, %v, %v", 1, "abc", 0.1) } err = w.Close() if err != nil { @@ -244,4 +290,4 @@ func validateRecordExists(logLevel LogLevel, recordLevel zapcore.Level, t *testi s,_= buf.ReadString('\n') } return entryNum == 1 -} +} \ No newline at end of file diff --git a/E2Manager/managers/e2t_instances_manager.go b/E2Manager/managers/e2t_instances_manager.go new file mode 100644 index 0000000..74f6a51 --- /dev/null +++ b/E2Manager/managers/e2t_instances_manager.go @@ -0,0 +1,359 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package managers + +import ( + "e2mgr/e2managererrors" + "e2mgr/logger" + "e2mgr/services" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "math" + "sync" + "time" +) + +type E2TInstancesManager struct { + rnibDataService services.RNibDataService + logger *logger.Logger + mux sync.Mutex +} + +type IE2TInstancesManager interface { + GetE2TInstance(e2tAddress string) (*entities.E2TInstance, error) + GetE2TInstances() ([]*entities.E2TInstance, error) + GetE2TInstancesNoLogs() ([]*entities.E2TInstance, error) + AddE2TInstance(e2tAddress string) error + RemoveE2TInstance(e2tInstance *entities.E2TInstance) error + SelectE2TInstance() (string, error) + AssociateRan(ranName string, e2tAddress string) error + DissociateRan(ranName string, e2tAddress string) error + ActivateE2TInstance(e2tInstance *entities.E2TInstance) error + ResetKeepAliveTimestamp(e2tAddress string) error +} + +func NewE2TInstancesManager(rnibDataService services.RNibDataService, logger *logger.Logger) *E2TInstancesManager { + return &E2TInstancesManager{ + rnibDataService: rnibDataService, + logger: logger, + } +} + +func (m *E2TInstancesManager) GetE2TInstance(e2tAddress string) (*entities.E2TInstance, error) { + e2tInstance, err := m.rnibDataService.GetE2TInstance(e2tAddress) + + if err != nil { + + _, ok := err.(*common.ResourceNotFoundError) + + if !ok { + m.logger.Errorf("#E2TInstancesManager.GetE2TInstance - E2T Instance address: %s - Failed retrieving E2TInstance. error: %s", e2tAddress, err) + } else { + m.logger.Infof("#E2TInstancesManager.GetE2TInstance - E2T Instance address: %s not found on DB", e2tAddress) + } + } + + return e2tInstance, err +} + +func (m *E2TInstancesManager) GetE2TInstancesNoLogs() ([]*entities.E2TInstance, error) { + e2tAddresses, err := m.rnibDataService.GetE2TAddressesNoLogs() + + if err != nil { + _, ok := err.(*common.ResourceNotFoundError) + + if !ok { + m.logger.Errorf("#E2TInstancesManager.GetE2TInstancesNoLogs - Failed retrieving E2T addresses. error: %s", err) + return nil, e2managererrors.NewRnibDbError() + } + + return []*entities.E2TInstance{}, nil + } + + if len(e2tAddresses) == 0 { + return []*entities.E2TInstance{}, nil + } + + e2tInstances, err := m.rnibDataService.GetE2TInstancesNoLogs(e2tAddresses) + + if err != nil { + _, ok := err.(*common.ResourceNotFoundError) + + if !ok { + m.logger.Errorf("#E2TInstancesManager.GetE2TInstancesNoLogs - Failed retrieving E2T instances list. error: %s", err) + } + return e2tInstances, err + } + + return e2tInstances, nil +} + +func (m *E2TInstancesManager) GetE2TInstances() ([]*entities.E2TInstance, error) { + e2tAddresses, err := m.rnibDataService.GetE2TAddresses() + + if err != nil { + + _, ok := err.(*common.ResourceNotFoundError) + + if !ok { + m.logger.Errorf("#E2TInstancesManager.GetE2TInstances - Failed retrieving E2T addresses. error: %s", err) + return nil, e2managererrors.NewRnibDbError() + } + + m.logger.Infof("#E2TInstancesManager.GetE2TInstances - Empty E2T addresses list") + return []*entities.E2TInstance{}, nil + } + + if len(e2tAddresses) == 0 { + m.logger.Infof("#E2TInstancesManager.GetE2TInstances - Empty E2T addresses list") + return []*entities.E2TInstance{}, nil + } + + e2tInstances, err := m.rnibDataService.GetE2TInstances(e2tAddresses) + + if err != nil { + m.logger.Errorf("#E2TInstancesManager.GetE2TInstances - Failed retrieving E2T instances list. error: %s", err) + return e2tInstances, e2managererrors.NewRnibDbError() + } + + if len(e2tInstances) == 0 { + m.logger.Warnf("#E2TInstancesManager.GetE2TInstances - Empty E2T instances list") + return e2tInstances, nil + } + + return e2tInstances, nil +} + +func (m *E2TInstancesManager) ResetKeepAliveTimestampsForAllE2TInstances() { + + e2tInstances, err := m.GetE2TInstances() + + if err != nil { + m.logger.Errorf("E2TInstancesManager.ResetKeepAliveTimestampForAllE2TInstances - Couldn't reset timestamps due to a DB error") + return + } + + if len(e2tInstances) == 0 { + m.logger.Infof("E2TInstancesManager.ResetKeepAliveTimestampForAllE2TInstances - No instances, ignoring reset") + return + } + + for _, v := range e2tInstances { + + if v.State != entities.Active { + continue + } + + v.KeepAliveTimestamp = time.Now().UnixNano() + + err := m.rnibDataService.SaveE2TInstance(v) + + if err != nil { + m.logger.Errorf("E2TInstancesManager.ResetKeepAliveTimestampForAllE2TInstances - E2T address: %s - failed resetting e2t instance keep alive timestamp. error: %s", v.Address, err) + } + } + + m.logger.Infof("E2TInstancesManager.ResetKeepAliveTimestampForAllE2TInstances - Done with reset") +} + +func findActiveE2TInstanceWithMinimumAssociatedRans(e2tInstances []*entities.E2TInstance) *entities.E2TInstance { + var minInstance *entities.E2TInstance + minAssociatedRanCount := math.MaxInt32 + + for _, v := range e2tInstances { + if v.State == entities.Active && len(v.AssociatedRanList) < minAssociatedRanCount { + minAssociatedRanCount = len(v.AssociatedRanList) + minInstance = v + } + } + + return minInstance +} + +func (m *E2TInstancesManager) AddE2TInstance(e2tAddress string) error { + + m.mux.Lock() + defer m.mux.Unlock() + + e2tInstance := entities.NewE2TInstance(e2tAddress) + err := m.rnibDataService.SaveE2TInstance(e2tInstance) + + if err != nil { + m.logger.Errorf("#E2TInstancesManager.AddE2TInstance - E2T Instance address: %s - Failed saving E2T instance. error: %s", e2tInstance.Address, err) + return err + } + + e2tAddresses, err := m.rnibDataService.GetE2TAddresses() + + if err != nil { + + _, ok := err.(*common.ResourceNotFoundError) + + if !ok { + m.logger.Errorf("#E2TInstancesManager.AddE2TInstance - E2T Instance address: %s - Failed retrieving E2T addresses list. error: %s", e2tInstance.Address, err) + return err + } + } + + e2tAddresses = append(e2tAddresses, e2tInstance.Address) + + err = m.rnibDataService.SaveE2TAddresses(e2tAddresses) + + if err != nil { + m.logger.Errorf("#E2TInstancesManager.AddE2TInstance - E2T Instance address: %s - Failed saving E2T addresses list. error: %s", e2tInstance.Address, err) + return err + } + + m.logger.Infof("#E2TInstancesManager.AddE2TInstance - E2T Instance address: %s - successfully added E2T instance", e2tInstance.Address) + return nil +} + +func (m *E2TInstancesManager) DissociateRan(ranName string, e2tAddress string) error { + + m.mux.Lock() + defer m.mux.Unlock() + + e2tInstance, err := m.rnibDataService.GetE2TInstance(e2tAddress) + + if err != nil { + m.logger.Errorf("#E2TInstancesManager.DissociateRan - E2T Instance address: %s - Failed retrieving E2TInstance. error: %s", e2tAddress, err) + return err + } + + i := 0 // output index + for _, v := range e2tInstance.AssociatedRanList { + if v != ranName { + // copy and increment index + e2tInstance.AssociatedRanList[i] = v + i++ + } + } + + e2tInstance.AssociatedRanList = e2tInstance.AssociatedRanList[:i] + + err = m.rnibDataService.SaveE2TInstance(e2tInstance) + + if err != nil { + m.logger.Errorf("#E2TInstancesManager.DissociateRan - E2T Instance address: %s - Failed saving E2TInstance. error: %s", e2tAddress, err) + return err + } + + m.logger.Infof("#E2TInstancesManager.DissociateRan - successfully dissociated RAN %s from E2T %s", ranName, e2tInstance.Address) + return nil +} + +func (m *E2TInstancesManager) RemoveE2TInstance(e2tInstance *entities.E2TInstance) error { + return nil +} +func (m *E2TInstancesManager) SelectE2TInstance() (string, error) { + + e2tInstances, err := m.GetE2TInstances() + + if err != nil { + return "", err + } + + if len(e2tInstances) == 0 { + m.logger.Errorf("#E2TInstancesManager.SelectE2TInstance - No E2T instance found") + return "", e2managererrors.NewE2TInstanceAbsenceError() + } + + min := findActiveE2TInstanceWithMinimumAssociatedRans(e2tInstances) + + if min == nil { + m.logger.Errorf("#E2TInstancesManager.SelectE2TInstance - No active E2T instance found") + return "", e2managererrors.NewE2TInstanceAbsenceError() + } + + m.logger.Infof("#E2TInstancesManager.SelectE2TInstance - successfully selected E2T instance. address: %s", min.Address) + return min.Address, nil +} + +func (m *E2TInstancesManager) AssociateRan(ranName string, e2tAddress string) error { + + m.mux.Lock() + defer m.mux.Unlock() + + e2tInstance, err := m.rnibDataService.GetE2TInstance(e2tAddress) + + if err != nil { + m.logger.Errorf("#E2TInstancesManager.AssociateRan - E2T Instance address: %s - Failed retrieving E2TInstance. error: %s", e2tAddress, err) + return e2managererrors.NewRnibDbError() + } + + e2tInstance.AssociatedRanList = append(e2tInstance.AssociatedRanList, ranName) + + err = m.rnibDataService.SaveE2TInstance(e2tInstance) + + if err != nil { + m.logger.Errorf("#E2TInstancesManager.AssociateRan - E2T Instance address: %s - Failed saving E2TInstance. error: %s", e2tAddress, err) + return e2managererrors.NewRnibDbError() + } + + m.logger.Infof("#E2TInstancesManager.AssociateRan - successfully associated RAN %s with E2T %s", ranName, e2tInstance.Address) + return nil +} + +func (h E2TInstancesManager) ActivateE2TInstance(e2tInstance *entities.E2TInstance) error{ + + if e2tInstance == nil { + h.logger.Errorf("#E2TInstancesManager.ActivateE2TInstance - e2tInstance empty") + return e2managererrors.NewInternalError() + } + + h.logger.Infof("#E2TInstancesManager.ActivateE2TInstance - E2T Address: %s - activate E2T instance", e2tInstance.Address) + + e2tInstance.State = entities.Active + e2tInstance.KeepAliveTimestamp = time.Now().UnixNano() + + err := h.rnibDataService.SaveE2TInstance(e2tInstance) + if err != nil { + h.logger.Errorf("#E2TInstancesManager.ActivateE2TInstance - E2T Instance address: %s - Failed saving E2TInstance. error: %s", e2tInstance.Address, err) + return err + } + return nil +} + +func (m *E2TInstancesManager) ResetKeepAliveTimestamp(e2tAddress string) error { + + m.mux.Lock() + defer m.mux.Unlock() + + e2tInstance, err := m.rnibDataService.GetE2TInstanceNoLogs(e2tAddress) + + if err != nil { + m.logger.Errorf("#E2TInstancesManager.ResetKeepAliveTimestamp - E2T Instance address: %s - Failed retrieving E2TInstance. error: %s", e2tAddress, err) + return err + } + + if e2tInstance.State == entities.ToBeDeleted || e2tInstance.State == entities.RoutingManagerFailure { + m.logger.Warnf("#E2TInstancesManager.ResetKeepAliveTimestamp - Ignore. This Instance is about to deleted") + return nil + + } + + e2tInstance.KeepAliveTimestamp = time.Now().UnixNano() + err = m.rnibDataService.SaveE2TInstanceNoLogs(e2tInstance) + + if err != nil { + m.logger.Errorf("#E2TInstancesManager.ResetKeepAliveTimestamp - E2T Instance address: %s - Failed saving E2TInstance. error: %s", e2tAddress, err) + return err + } + + return nil +} diff --git a/E2Manager/managers/e2t_instances_manager_test.go b/E2Manager/managers/e2t_instances_manager_test.go new file mode 100644 index 0000000..fb564e5 --- /dev/null +++ b/E2Manager/managers/e2t_instances_manager_test.go @@ -0,0 +1,459 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package managers + +import ( + "e2mgr/configuration" + "e2mgr/logger" + "e2mgr/mocks" + "e2mgr/services" + "fmt" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "testing" +) + +const E2TAddress = "10.10.2.15:9800" +const E2TAddress2 = "10.10.2.16:9800" + +func initE2TInstancesManagerTest(t *testing.T) (*mocks.RnibReaderMock, *mocks.RnibWriterMock, *E2TInstancesManager) { + logger, err := logger.InitLogger(logger.DebugLevel) + if err != nil { + t.Errorf("#... - failed to initialize logger, error: %s", err) + } + config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} + + readerMock := &mocks.RnibReaderMock{} + writerMock := &mocks.RnibWriterMock{} + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) + e2tInstancesManager := NewE2TInstancesManager(rnibDataService, logger) + return readerMock, writerMock, e2tInstancesManager +} + +func TestAddNewE2TInstanceSaveE2TInstanceFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(common.NewInternalError(errors.New("Error"))) + err := e2tInstancesManager.AddE2TInstance(E2TAddress) + assert.NotNil(t, err) + rnibReaderMock.AssertNotCalled(t, "GetE2TAddresses") +} + +func TestAddNewE2TInstanceGetE2TAddressesInternalFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil) + e2tAddresses := []string{} + rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, common.NewInternalError(errors.New("Error"))) + err := e2tInstancesManager.AddE2TInstance(E2TAddress) + assert.NotNil(t, err) + rnibReaderMock.AssertNotCalled(t, "SaveE2TAddresses") +} + +func TestAddNewE2TInstanceSaveE2TAddressesFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil) + E2TAddresses := []string{} + rnibReaderMock.On("GetE2TAddresses").Return(E2TAddresses, nil) + E2TAddresses = append(E2TAddresses, E2TAddress) + rnibWriterMock.On("SaveE2TAddresses", E2TAddresses).Return(common.NewResourceNotFoundError("")) + err := e2tInstancesManager.AddE2TInstance(E2TAddress) + assert.NotNil(t, err) +} + +func TestAddNewE2TInstanceNoE2TAddressesSuccess(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil) + e2tAddresses := []string{} + rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, common.NewResourceNotFoundError("")) + e2tAddresses = append(e2tAddresses, E2TAddress) + rnibWriterMock.On("SaveE2TAddresses", e2tAddresses).Return(nil) + err := e2tInstancesManager.AddE2TInstance(E2TAddress) + assert.Nil(t, err) + rnibWriterMock.AssertCalled(t, "SaveE2TAddresses", e2tAddresses) +} + +func TestAddNewE2TInstanceEmptyE2TAddressesSuccess(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil) + e2tAddresses := []string{} + rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, nil) + e2tAddresses = append(e2tAddresses, E2TAddress) + rnibWriterMock.On("SaveE2TAddresses", e2tAddresses).Return(nil) + err := e2tInstancesManager.AddE2TInstance(E2TAddress) + assert.Nil(t, err) + rnibWriterMock.AssertCalled(t, "SaveE2TAddresses", e2tAddresses) +} + +func TestAddNewE2TInstanceExistingE2TAddressesSuccess(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil) + E2TAddresses := []string{"10.0.1.15:3030"} + rnibReaderMock.On("GetE2TAddresses").Return(E2TAddresses, nil) + E2TAddresses = append(E2TAddresses, E2TAddress) + rnibWriterMock.On("SaveE2TAddresses", E2TAddresses).Return(nil) + err := e2tInstancesManager.AddE2TInstance(E2TAddress) + assert.Nil(t, err) +} + +func TestGetE2TInstanceFailure(t *testing.T) { + rnibReaderMock, _, e2tInstancesManager := initE2TInstancesManagerTest(t) + var e2tInstance *entities.E2TInstance + rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, common.NewInternalError(fmt.Errorf("for test"))) + res, err := e2tInstancesManager.GetE2TInstance(E2TAddress) + assert.NotNil(t, err) + assert.Nil(t, res) +} + +func TestGetE2TInstanceSuccess(t *testing.T) { + rnibReaderMock, _, e2tInstancesManager := initE2TInstancesManagerTest(t) + address := "10.10.2.15:9800" + e2tInstance := entities.NewE2TInstance(address) + rnibReaderMock.On("GetE2TInstance", address).Return(e2tInstance, nil) + res, err := e2tInstancesManager.GetE2TInstance(address) + assert.Nil(t, err) + assert.Equal(t, e2tInstance, res) +} + +func TestAssociateRanGetInstanceFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + var e2tInstance1 *entities.E2TInstance + rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, common.NewInternalError(fmt.Errorf("for test"))) + + err := e2tInstancesManager.AssociateRan("test1", E2TAddress) + assert.NotNil(t, err) + rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance") +} + +func TestAssociateRanSaveInstanceFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, nil) + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(common.NewInternalError(fmt.Errorf("for test"))) + + err := e2tInstancesManager.AssociateRan("test1", E2TAddress) + assert.NotNil(t, err) + rnibReaderMock.AssertExpectations(t) + rnibWriterMock.AssertExpectations(t) +} + +func TestAssociateRanSuccess(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + e2tInstance := entities.NewE2TInstance(E2TAddress) + rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil) + + updateE2TInstance := *e2tInstance + updateE2TInstance.AssociatedRanList = append(updateE2TInstance.AssociatedRanList, "test1") + + rnibWriterMock.On("SaveE2TInstance", &updateE2TInstance).Return(nil) + + err := e2tInstancesManager.AssociateRan("test1", E2TAddress) + assert.Nil(t, err) + rnibReaderMock.AssertExpectations(t) + rnibWriterMock.AssertExpectations(t) +} + +func TestDissociateRanGetInstanceFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + var e2tInstance1 *entities.E2TInstance + rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, common.NewInternalError(fmt.Errorf("for test"))) + err := e2tInstancesManager.DissociateRan("test1", E2TAddress) + assert.NotNil(t, err) + rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance") +} + +func TestDissociateRanSaveInstanceFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance1, nil) + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(common.NewInternalError(fmt.Errorf("for test"))) + + err := e2tInstancesManager.DissociateRan("test1", E2TAddress) + assert.NotNil(t, err) + rnibReaderMock.AssertExpectations(t) + rnibWriterMock.AssertExpectations(t) +} + +func TestDissociateRanSuccess(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + e2tInstance := entities.NewE2TInstance(E2TAddress) + e2tInstance.AssociatedRanList = []string{"test0", "test1"} + updatedE2TInstance := *e2tInstance + updatedE2TInstance.AssociatedRanList = []string{"test0"} + rnibReaderMock.On("GetE2TInstance", E2TAddress).Return(e2tInstance, nil) + rnibWriterMock.On("SaveE2TInstance", &updatedE2TInstance).Return(nil) + + err := e2tInstancesManager.DissociateRan("test1", E2TAddress) + assert.Nil(t, err) + rnibReaderMock.AssertExpectations(t) + rnibWriterMock.AssertExpectations(t) +} + +func TestSelectE2TInstancesGetE2TAddressesFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + rnibReaderMock.On("GetE2TAddresses").Return([]string{}, common.NewInternalError(fmt.Errorf("for test"))) + address, err := e2tInstancesManager.SelectE2TInstance() + assert.NotNil(t, err) + assert.Empty(t, address) + rnibReaderMock.AssertExpectations(t) + rnibWriterMock.AssertNotCalled(t, "GetE2TInstances") +} + +func TestSelectE2TInstancesEmptyE2TAddressList(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + rnibReaderMock.On("GetE2TAddresses").Return([]string{}, nil) + address, err := e2tInstancesManager.SelectE2TInstance() + assert.NotNil(t, err) + assert.Empty(t, address) + rnibReaderMock.AssertExpectations(t) + rnibWriterMock.AssertNotCalled(t, "GetE2TInstances") +} + +func TestSelectE2TInstancesGetE2TInstancesFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + addresses := []string{E2TAddress} + rnibReaderMock.On("GetE2TAddresses").Return(addresses, nil) + rnibReaderMock.On("GetE2TInstances", addresses).Return([]*entities.E2TInstance{}, common.NewInternalError(fmt.Errorf("for test"))) + address, err := e2tInstancesManager.SelectE2TInstance() + assert.NotNil(t, err) + assert.Empty(t, address) + rnibReaderMock.AssertExpectations(t) + rnibWriterMock.AssertExpectations(t) +} + +func TestSelectE2TInstancesEmptyE2TInstancesList(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + addresses := []string{E2TAddress} + rnibReaderMock.On("GetE2TAddresses").Return(addresses, nil) + rnibReaderMock.On("GetE2TInstances", addresses).Return([]*entities.E2TInstance{}, nil) + address, err := e2tInstancesManager.SelectE2TInstance() + assert.NotNil(t, err) + assert.Empty(t, address) + rnibReaderMock.AssertExpectations(t) + rnibWriterMock.AssertExpectations(t) +} + +func TestSelectE2TInstancesNoActiveE2TInstance(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + addresses := []string{E2TAddress, E2TAddress2} + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + e2tInstance1.State = entities.ToBeDeleted + e2tInstance1.AssociatedRanList = []string{"test1", "test2", "test3"} + e2tInstance2 := entities.NewE2TInstance(E2TAddress2) + e2tInstance2.State = entities.ToBeDeleted + e2tInstance2.AssociatedRanList = []string{"test4", "test5", "test6", "test7"} + + rnibReaderMock.On("GetE2TAddresses").Return(addresses, nil) + rnibReaderMock.On("GetE2TInstances", addresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil) + address, err := e2tInstancesManager.SelectE2TInstance() + assert.NotNil(t, err) + assert.Equal(t, "", address) + rnibReaderMock.AssertExpectations(t) + rnibWriterMock.AssertExpectations(t) +} + +func TestSelectE2TInstancesSuccess(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + addresses := []string{E2TAddress, E2TAddress2} + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + e2tInstance1.AssociatedRanList = []string{"test1", "test2", "test3"} + e2tInstance2 := entities.NewE2TInstance(E2TAddress2) + e2tInstance2.AssociatedRanList = []string{"test4", "test5", "test6", "test7"} + + rnibReaderMock.On("GetE2TAddresses").Return(addresses, nil) + rnibReaderMock.On("GetE2TInstances", addresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil) + address, err := e2tInstancesManager.SelectE2TInstance() + assert.Nil(t, err) + assert.Equal(t, E2TAddress, address) + rnibReaderMock.AssertExpectations(t) + rnibWriterMock.AssertExpectations(t) +} + +func TestActivateE2TInstanceSuccess(t *testing.T) { + _, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + e2tInstance1.State = entities.RoutingManagerFailure + e2tInstance1.AssociatedRanList = []string{"test1","test2","test3"} + + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil) + + err := e2tInstancesManager.ActivateE2TInstance(e2tInstance1) + assert.Nil(t, err) + assert.Equal(t, entities.Active, e2tInstance1.State) + rnibWriterMock.AssertExpectations(t) +} + +func TestActivateE2TInstance_RnibError(t *testing.T) { + _, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + e2tInstance1.State = entities.RoutingManagerFailure + e2tInstance1.AssociatedRanList = []string{"test1","test2","test3"} + + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(common.NewInternalError(errors.New("Error"))) + + err := e2tInstancesManager.ActivateE2TInstance(e2tInstance1) + assert.NotNil(t, err) +} + +func TestActivateE2TInstance_NoInstance(t *testing.T) { + _, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + err := e2tInstancesManager.ActivateE2TInstance(nil) + + assert.NotNil(t, err) + rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance") +} + +func TestResetKeepAliveTimestampGetInternalFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + address := "10.10.2.15:9800" + e2tInstance := entities.NewE2TInstance(address) + rnibReaderMock.On("GetE2TInstance", address).Return(e2tInstance, common.NewInternalError(errors.New("Error"))) + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil) + + err := e2tInstancesManager.ResetKeepAliveTimestamp(address) + assert.NotNil(t, err) + rnibReaderMock.AssertNotCalled(t, "SaveE2TInstance") +} + +func TestAResetKeepAliveTimestampSaveInternalFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + address := "10.10.2.15:9800" + e2tInstance := entities.NewE2TInstance(address) + rnibReaderMock.On("GetE2TInstance", address).Return(e2tInstance, nil) + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(common.NewInternalError(errors.New("Error"))) + + err := e2tInstancesManager.ResetKeepAliveTimestamp(address) + assert.NotNil(t, err) +} + +func TestResetKeepAliveTimestampSuccess(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + address := "10.10.2.15:9800" + e2tInstance := entities.NewE2TInstance(address) + rnibReaderMock.On("GetE2TInstance", address).Return(e2tInstance, nil) + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil) + + err := e2tInstancesManager.ResetKeepAliveTimestamp(address) + assert.Nil(t, err) + rnibReaderMock.AssertCalled(t, "GetE2TInstance", address) + rnibWriterMock.AssertNumberOfCalls(t, "SaveE2TInstance", 1) +} + +func TestResetKeepAliveTimestampToBeDeleted(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + address := "10.10.2.15:9800" + e2tInstance := entities.NewE2TInstance(address) + e2tInstance.State = entities.ToBeDeleted + rnibReaderMock.On("GetE2TInstance", address).Return(e2tInstance, nil) + + err := e2tInstancesManager.ResetKeepAliveTimestamp(address) + assert.Nil(t, err) + rnibReaderMock.AssertCalled(t, "GetE2TInstance", address) + rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance") +} + +func TestResetKeepAliveTimestampRoutingManagerFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + + address := "10.10.2.15:9800" + e2tInstance := entities.NewE2TInstance(address) + e2tInstance.State = entities.RoutingManagerFailure + rnibReaderMock.On("GetE2TInstance", address).Return(e2tInstance, nil) + + err := e2tInstancesManager.ResetKeepAliveTimestamp(address) + assert.Nil(t, err) + rnibReaderMock.AssertCalled(t, "GetE2TInstance", address) + rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance") +} + +func TestRemoveE2TInstance(t *testing.T) { + _, _, e2tInstancesManager := initE2TInstancesManagerTest(t) + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + err := e2tInstancesManager.RemoveE2TInstance(e2tInstance1) + assert.Nil(t, err) +} + +func TestResetKeepAliveTimestampsForAllE2TInstancesGetE2TInstancesFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + rnibReaderMock.On("GetE2TAddresses").Return([]string{}, common.NewInternalError(errors.New("Error"))) + e2tInstancesManager.ResetKeepAliveTimestampsForAllE2TInstances() + rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance") +} + +func TestResetKeepAliveTimestampsForAllE2TInstancesNoInstances(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + rnibReaderMock.On("GetE2TAddresses").Return([]string{}, nil) + e2tInstancesManager.ResetKeepAliveTimestampsForAllE2TInstances() + rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance") +} + +func TestResetKeepAliveTimestampsForAllE2TInstancesNoActiveInstances(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + e2tAddresses := []string{E2TAddress, E2TAddress2} + rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, nil) + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + e2tInstance1.State = entities.ToBeDeleted + e2tInstance2 := entities.NewE2TInstance(E2TAddress2) + e2tInstance2.State = entities.RoutingManagerFailure + rnibReaderMock.On("GetE2TInstances", e2tAddresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil) + e2tInstancesManager.ResetKeepAliveTimestampsForAllE2TInstances() + rnibWriterMock.AssertNotCalled(t, "SaveE2TInstance") +} + +func TestResetKeepAliveTimestampsForAllE2TInstancesOneActiveInstance(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + e2tAddresses := []string{E2TAddress, E2TAddress2} + rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, nil) + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + e2tInstance1.State = entities.Active + e2tInstance2 := entities.NewE2TInstance(E2TAddress2) + e2tInstance2.State = entities.ToBeDeleted + rnibReaderMock.On("GetE2TInstances", e2tAddresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil) + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(nil) + e2tInstancesManager.ResetKeepAliveTimestampsForAllE2TInstances() + rnibWriterMock.AssertNumberOfCalls(t, "SaveE2TInstance",1) +} + +func TestResetKeepAliveTimestampsForAllE2TInstancesSaveE2TInstanceFailure(t *testing.T) { + rnibReaderMock, rnibWriterMock, e2tInstancesManager := initE2TInstancesManagerTest(t) + e2tAddresses := []string{E2TAddress, E2TAddress2} + rnibReaderMock.On("GetE2TAddresses").Return(e2tAddresses, nil) + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + e2tInstance1.State = entities.Active + e2tInstance2 := entities.NewE2TInstance(E2TAddress2) + e2tInstance2.State = entities.ToBeDeleted + rnibReaderMock.On("GetE2TInstances", e2tAddresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil) + rnibWriterMock.On("SaveE2TInstance", mock.Anything).Return(common.NewInternalError(errors.New("Error"))) + e2tInstancesManager.ResetKeepAliveTimestampsForAllE2TInstances() + rnibWriterMock.AssertNumberOfCalls(t, "SaveE2TInstance",1) +} diff --git a/E2Manager/managers/e2t_keep_alive_worker.go b/E2Manager/managers/e2t_keep_alive_worker.go new file mode 100644 index 0000000..45c5c08 --- /dev/null +++ b/E2Manager/managers/e2t_keep_alive_worker.go @@ -0,0 +1,85 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package managers + +import ( + "e2mgr/configuration" + "e2mgr/logger" + "e2mgr/models" + "e2mgr/rmrCgo" + "e2mgr/services/rmrsender" + "time" +) + +type E2TKeepAliveWorker struct { + logger *logger.Logger + e2tShutdownManager IE2TShutdownManager + e2TInstancesManager IE2TInstancesManager + rmrSender *rmrsender.RmrSender + config *configuration.Configuration +} + +func NewE2TKeepAliveWorker(logger *logger.Logger, rmrSender *rmrsender.RmrSender, e2TInstancesManager IE2TInstancesManager, e2tShutdownManager IE2TShutdownManager, config *configuration.Configuration) E2TKeepAliveWorker { + return E2TKeepAliveWorker{ + logger: logger, + e2tShutdownManager: e2tShutdownManager, + e2TInstancesManager: e2TInstancesManager, + rmrSender: rmrSender, + config: config, + } +} + +func (h E2TKeepAliveWorker) Execute() { + + h.logger.Infof("#E2TKeepAliveWorker.Execute - keep alive started") + + ticker := time.NewTicker(time.Duration(h.config.KeepAliveDelayMs) * time.Millisecond) + + for _= range ticker.C { + + h.SendKeepAliveRequest() + h.E2TKeepAliveExpired() + } +} + +func (h E2TKeepAliveWorker) E2TKeepAliveExpired() { + + e2tInstances, err := h.e2TInstancesManager.GetE2TInstancesNoLogs() + + if err != nil || len(e2tInstances) == 0 { + return + } + + for _, e2tInstance := range e2tInstances { + + delta := int64(time.Now().UnixNano()) - e2tInstance.KeepAliveTimestamp + timestampNanosec := int64(time.Duration(h.config.KeepAliveResponseTimeoutMs) * time.Millisecond) + + if delta > timestampNanosec { + + h.logger.Warnf("#E2TKeepAliveWorker.E2TKeepAliveExpired - e2t address: %s time expired, shutdown e2 instance", e2tInstance.Address) + + h.e2tShutdownManager.Shutdown(e2tInstance) + } + } +} + +func (h E2TKeepAliveWorker) SendKeepAliveRequest() { + + request := models.RmrMessage{MsgType: rmrCgo.E2_TERM_KEEP_ALIVE_REQ} + h.rmrSender.SendWithoutLogs(&request) +} \ No newline at end of file diff --git a/E2Manager/managers/e2t_keep_alive_worker_test.go b/E2Manager/managers/e2t_keep_alive_worker_test.go new file mode 100644 index 0000000..00714ca --- /dev/null +++ b/E2Manager/managers/e2t_keep_alive_worker_test.go @@ -0,0 +1,198 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package managers + +import ( + "e2mgr/configuration" + "e2mgr/logger" + "e2mgr/mocks" + "e2mgr/rmrCgo" + "e2mgr/services" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "github.com/pkg/errors" + "github.com/stretchr/testify/mock" + "testing" + "time" +) + +func initE2TKeepAliveTest(t *testing.T) (*mocks.RmrMessengerMock, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.E2TShutdownManagerMock, *E2TKeepAliveWorker) { + logger, err := logger.InitLogger(logger.DebugLevel) + if err != nil { + t.Errorf("#... - failed to initialize logger, error: %s", err) + } + config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3, KeepAliveResponseTimeoutMs: 400, KeepAliveDelayMs: 100} + + readerMock := &mocks.RnibReaderMock{} + writerMock := &mocks.RnibWriterMock{} + e2tShutdownManagerMock := &mocks.E2TShutdownManagerMock{} + + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) + e2tInstancesManager := NewE2TInstancesManager(rnibDataService, logger) + + rmrMessengerMock := &mocks.RmrMessengerMock{} + rmrSender := initRmrSender(rmrMessengerMock, logger) + + e2tKeepAliveWorker := NewE2TKeepAliveWorker(logger, rmrSender, e2tInstancesManager, e2tShutdownManagerMock, config) + + return rmrMessengerMock, readerMock, writerMock, e2tShutdownManagerMock, &e2tKeepAliveWorker +} + +func TestSendKeepAliveRequest(t *testing.T) { + rmrMessengerMock, _, _, _, e2tKeepAliveWorker := initE2TKeepAliveTest(t) + + rmrMessengerMock.On("SendMsg", mock.Anything, false).Return(&rmrCgo.MBuf{}, nil) + + e2tKeepAliveWorker.SendKeepAliveRequest() + + var payload, xAction []byte + req := rmrCgo.NewMBuf(rmrCgo.E2_TERM_KEEP_ALIVE_REQ, 0, "", &payload, &xAction) + + rmrMessengerMock.AssertCalled(t, "SendMsg", req, false) +} + +func TestShutdownExpiredE2T_InternalError(t *testing.T) { + rmrMessengerMock, readerMock, _, _, e2tKeepAliveWorker := initE2TKeepAliveTest(t) + + readerMock.On("GetE2TAddresses").Return([]string{}, common.NewInternalError(errors.New("#reader.GetNodeb - Internal Error"))) + + e2tKeepAliveWorker.E2TKeepAliveExpired() + + rmrMessengerMock.AssertNotCalled(t, "Shutdown") +} + +func TestShutdownExpiredE2T_NoAddresses(t *testing.T) { + rmrMessengerMock, readerMock, _, _, e2tKeepAliveWorker := initE2TKeepAliveTest(t) + + addresses := []string{} + + readerMock.On("GetE2TAddresses").Return(addresses, nil) + + e2tKeepAliveWorker.E2TKeepAliveExpired() + + rmrMessengerMock.AssertNotCalled(t, "Shutdown") +} + +func TestShutdownExpiredE2T_NotExpired_InternalError(t *testing.T) { + rmrMessengerMock, readerMock, _, _, e2tKeepAliveWorker := initE2TKeepAliveTest(t) + + addresses := []string{E2TAddress,E2TAddress2} + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + e2tInstance1.AssociatedRanList = []string{"test1","test2","test3"} + e2tInstance2 := entities.NewE2TInstance(E2TAddress2) + e2tInstance2.AssociatedRanList = []string{"test4","test5","test6", "test7"} + + readerMock.On("GetE2TAddresses").Return(addresses, nil) + readerMock.On("GetE2TInstances",addresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, common.NewInternalError(errors.New("#reader.GetNodeb - Internal Error"))) + + e2tKeepAliveWorker.E2TKeepAliveExpired() + + rmrMessengerMock.AssertNotCalled(t, "Shutdown") +} + +func TestShutdownExpiredE2T_NoE2T(t *testing.T) { + rmrMessengerMock, readerMock, _, _, e2tKeepAliveWorker := initE2TKeepAliveTest(t) + + readerMock.On("GetE2TAddresses").Return([]string{}, common.NewResourceNotFoundError("not found")) + + e2tKeepAliveWorker.E2TKeepAliveExpired() + + rmrMessengerMock.AssertNotCalled(t, "Shutdown") +} + +func TestShutdownExpiredE2T_NotExpired(t *testing.T) { + rmrMessengerMock, readerMock, _, _, e2tKeepAliveWorker := initE2TKeepAliveTest(t) + + addresses := []string{E2TAddress,E2TAddress2} + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + e2tInstance1.AssociatedRanList = []string{"test1","test2","test3"} + e2tInstance2 := entities.NewE2TInstance(E2TAddress2) + e2tInstance2.AssociatedRanList = []string{"test4","test5","test6", "test7"} + + readerMock.On("GetE2TAddresses").Return(addresses, nil) + readerMock.On("GetE2TInstances",addresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil) + + e2tKeepAliveWorker.E2TKeepAliveExpired() + + rmrMessengerMock.AssertNotCalled(t, "Shutdown") +} + +func TestShutdownExpiredE2T_One_E2TExpired(t *testing.T) { + _, readerMock, _, e2tShutdownManagerMock, e2tKeepAliveWorker := initE2TKeepAliveTest(t) + + addresses := []string{E2TAddress,E2TAddress2} + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + e2tInstance1.AssociatedRanList = []string{"test1","test2","test3"} + + time.Sleep(time.Duration(400) * time.Millisecond) + + e2tInstance2 := entities.NewE2TInstance(E2TAddress2) + e2tInstance2.AssociatedRanList = []string{"test4","test5","test6", "test7"} + + readerMock.On("GetE2TAddresses").Return(addresses, nil) + readerMock.On("GetE2TInstances",addresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil) + e2tShutdownManagerMock.On("Shutdown", e2tInstance1).Return(nil) + + e2tKeepAliveWorker.E2TKeepAliveExpired() + + e2tShutdownManagerMock.AssertNumberOfCalls(t, "Shutdown", 1) +} + +func TestShutdownExpiredE2T_Two_E2TExpired(t *testing.T) { + _, readerMock, _, e2tShutdownManagerMock, e2tKeepAliveWorker := initE2TKeepAliveTest(t) + + addresses := []string{E2TAddress,E2TAddress2} + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + e2tInstance1.AssociatedRanList = []string{"test1","test2","test3"} + + e2tInstance2 := entities.NewE2TInstance(E2TAddress2) + e2tInstance2.AssociatedRanList = []string{"test4","test5","test6", "test7"} + + time.Sleep(time.Duration(400) * time.Millisecond) + + readerMock.On("GetE2TAddresses").Return(addresses, nil) + readerMock.On("GetE2TInstances",addresses).Return([]*entities.E2TInstance{e2tInstance1, e2tInstance2}, nil) + e2tShutdownManagerMock.On("Shutdown", e2tInstance1).Return(nil) + e2tShutdownManagerMock.On("Shutdown", e2tInstance2).Return(nil) + + e2tKeepAliveWorker.E2TKeepAliveExpired() + + e2tShutdownManagerMock.AssertNumberOfCalls(t, "Shutdown", 2) +} + +func TestExecute_Two_E2TExpired(t *testing.T) { + rmrMessengerMock, readerMock, _, e2tShutdownManagerMock, e2tKeepAliveWorker := initE2TKeepAliveTest(t) + + addresses := []string{E2TAddress,E2TAddress2} + e2tInstance1 := entities.NewE2TInstance(E2TAddress) + e2tInstance1.AssociatedRanList = []string{"test1","test2","test3"} + + readerMock.On("GetE2TAddresses").Return(addresses, nil) + readerMock.On("GetE2TInstances",addresses).Return([]*entities.E2TInstance{e2tInstance1}, nil) + e2tShutdownManagerMock.On("Shutdown", e2tInstance1).Return(nil) + rmrMessengerMock.On("SendMsg", mock.Anything, false).Return(&rmrCgo.MBuf{}, nil) + + go e2tKeepAliveWorker.Execute() + + time.Sleep(time.Duration(500) * time.Millisecond) + + var payload, xAction []byte + req := rmrCgo.NewMBuf(rmrCgo.E2_TERM_KEEP_ALIVE_REQ, 0, "", &payload, &xAction) + + rmrMessengerMock.AssertCalled(t, "SendMsg", req, false) + e2tShutdownManagerMock.AssertCalled(t, "Shutdown", e2tInstance1) +} \ No newline at end of file diff --git a/E2Manager/managers/e2t_shutdown_manager.go b/E2Manager/managers/e2t_shutdown_manager.go new file mode 100644 index 0000000..e789689 --- /dev/null +++ b/E2Manager/managers/e2t_shutdown_manager.go @@ -0,0 +1,48 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package managers + +import ( + "e2mgr/logger" + "e2mgr/services" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" +) + + +type IE2TShutdownManager interface { + Shutdown(e2tInstance *entities.E2TInstance) error +} + +type E2TShutdownManager struct { + logger *logger.Logger + rnibDataService services.RNibDataService + e2TInstancesManager IE2TInstancesManager +} + +func NewE2TShutdownManager(logger *logger.Logger, rnibDataService services.RNibDataService, e2TInstancesManager IE2TInstancesManager) E2TShutdownManager { + return E2TShutdownManager{ + logger: logger, + rnibDataService: rnibDataService, + e2TInstancesManager: e2TInstancesManager, + } +} + +func (h E2TShutdownManager) Shutdown(e2tInstance *entities.E2TInstance) error{ + h.logger.Infof("#E2TShutdownManager.Shutdown - E2T %s is Dead, RIP", e2tInstance.Address) + + return nil +} diff --git a/E2Manager/managers/endc_setup_failure_response_manager.go b/E2Manager/managers/endc_setup_failure_response_manager.go index 1b7a34a..8ef22c9 100644 --- a/E2Manager/managers/endc_setup_failure_response_manager.go +++ b/E2Manager/managers/endc_setup_failure_response_manager.go @@ -22,20 +22,23 @@ package managers import ( "e2mgr/converters" - "e2mgr/e2pdus" "e2mgr/logger" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" ) -type EndcSetupFailureResponseManager struct{} +type EndcSetupFailureResponseManager struct { + converter converters.IEndcSetupFailureResponseConverter +} -func NewEndcSetupFailureResponseManager() *EndcSetupFailureResponseManager { - return &EndcSetupFailureResponseManager{} +func NewEndcSetupFailureResponseManager(converter converters.IEndcSetupFailureResponseConverter) *EndcSetupFailureResponseManager { + return &EndcSetupFailureResponseManager{ + converter: converter, + } } func (m *EndcSetupFailureResponseManager) PopulateNodebByPdu(logger *logger.Logger, nbIdentity *entities.NbIdentity, nodebInfo *entities.NodebInfo, payload []byte) error { - failureResponse, err := converters.UnpackEndcX2SetupFailureResponseAndExtract(logger, e2pdus.MaxAsn1CodecAllocationBufferSize, len(payload), payload, e2pdus.MaxAsn1CodecMessageBufferSize) + failureResponse, err := m.converter.UnpackEndcSetupFailureResponseAndExtract(payload) if err != nil { logger.Errorf("#EndcSetupFailureResponseManager.PopulateNodebByPdu - RAN name: %s - Unpack and extract failed. Error: %v", nodebInfo.RanName, err) diff --git a/E2Manager/managers/endc_setup_failure_response_manager_test.go b/E2Manager/managers/endc_setup_failure_response_manager_test.go new file mode 100644 index 0000000..4bdc9fa --- /dev/null +++ b/E2Manager/managers/endc_setup_failure_response_manager_test.go @@ -0,0 +1,66 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package managers + +import ( + "e2mgr/converters" + "e2mgr/tests" + "fmt" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "github.com/stretchr/testify/assert" + "math/rand" + "testing" +) + +func TestPopulateNodebByPduFailure(t *testing.T) { + logger := tests.InitLog(t) + nodebInfo := &entities.NodebInfo{} + nodebIdentity := &entities.NbIdentity{} + converter := converters.NewEndcSetupFailureResponseConverter(logger) + handler := NewEndcSetupFailureResponseManager(converter) + err := handler.PopulateNodebByPdu(logger, nodebIdentity, nodebInfo, createRandomPayload()) + assert.NotNil(t, err) +} + +func TestPopulateNodebByPduSuccess(t *testing.T) { + logger := tests.InitLog(t) + nodebInfo := &entities.NodebInfo{} + nodebIdentity := &entities.NbIdentity{} + converter := converters.NewEndcSetupFailureResponseConverter(logger) + handler := NewEndcSetupFailureResponseManager(converter) + err := handler.PopulateNodebByPdu(logger, nodebIdentity, nodebInfo, createSetupFailureResponsePayload(t)) + assert.Nil(t, err) + assert.Equal(t, entities.ConnectionStatus_CONNECTED_SETUP_FAILED, nodebInfo.ConnectionStatus) + assert.Equal(t, entities.Failure_ENDC_X2_SETUP_FAILURE, nodebInfo.FailureType) + +} + +func createSetupFailureResponsePayload(t *testing.T) []byte { + packedPdu := "4024001a0000030005400200000016400100001140087821a00000008040" + var payload []byte + _, err := fmt.Sscanf(packedPdu, "%x", &payload) + if err != nil { + t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err) + } + return payload +} + +func createRandomPayload() []byte { + payload := make([]byte, 20) + rand.Read(payload) + return payload +} diff --git a/E2Manager/managers/endc_setup_response_manager.go b/E2Manager/managers/endc_setup_response_manager.go index 60da306..a6118c4 100644 --- a/E2Manager/managers/endc_setup_response_manager.go +++ b/E2Manager/managers/endc_setup_response_manager.go @@ -22,20 +22,23 @@ package managers import ( "e2mgr/converters" - "e2mgr/e2pdus" "e2mgr/logger" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" ) -type EndcSetupResponseManager struct{} +type EndcSetupResponseManager struct{ + converter converters.IEndcSetupResponseConverter +} -func NewEndcSetupResponseManager() *EndcSetupResponseManager { - return &EndcSetupResponseManager{} +func NewEndcSetupResponseManager(converter converters.IEndcSetupResponseConverter) *EndcSetupResponseManager { + return &EndcSetupResponseManager{ + converter: converter, + } } func (m *EndcSetupResponseManager) PopulateNodebByPdu(logger *logger.Logger, nbIdentity *entities.NbIdentity, nodebInfo *entities.NodebInfo, payload []byte) error { - gnbId, gnb, err := converters.UnpackEndcX2SetupResponseAndExtract(logger, e2pdus.MaxAsn1CodecAllocationBufferSize, len(payload), payload, e2pdus.MaxAsn1CodecMessageBufferSize) + gnbId, gnb, err := m.converter.UnpackEndcSetupResponseAndExtract(payload) if err != nil { logger.Errorf("#EndcSetupResponseManager.PopulateNodebByPdu - RAN name: %s - Unpack and extract failed. Error: %v", nodebInfo.RanName, err) diff --git a/E2Manager/managers/endc_setup_response_manager_test.go b/E2Manager/managers/endc_setup_response_manager_test.go new file mode 100644 index 0000000..55726c2 --- /dev/null +++ b/E2Manager/managers/endc_setup_response_manager_test.go @@ -0,0 +1,59 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package managers + +import ( + "e2mgr/converters" + "e2mgr/tests" + "fmt" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestSetupResponsePopulateNodebByPduFailure(t *testing.T) { + logger := tests.InitLog(t) + nodebInfo := &entities.NodebInfo{} + nodebIdentity := &entities.NbIdentity{} + converter:= converters.NewEndcSetupResponseConverter(logger) + handler := NewEndcSetupResponseManager(converter) + err := handler.PopulateNodebByPdu(logger, nodebIdentity, nodebInfo, createRandomPayload()) + assert.NotNil(t, err) +} + +func TestSetupResponsePopulateNodebByPduSuccess(t *testing.T) { + logger := tests.InitLog(t) + nodebInfo := &entities.NodebInfo{} + nodebIdentity := &entities.NbIdentity{} + converter:= converters.NewEndcSetupResponseConverter(logger) + handler := NewEndcSetupResponseManager(converter) + err := handler.PopulateNodebByPdu(logger, nodebIdentity, nodebInfo, createSetupResponsePayload(t)) + assert.Nil(t, err) + assert.Equal(t, entities.ConnectionStatus_CONNECTED, nodebInfo.ConnectionStatus) + assert.Equal(t, entities.Node_GNB, nodebInfo.NodeType) + +} + +func createSetupResponsePayload(t *testing.T) []byte { + packedPdu := "202400808e00000100f600808640000200fc00090002f829504a952a0a00fd007200010c0005001e3f271f2e3d4ff03d44d34e4f003e4e5e4400010000150400000a000211e148033e4e5e4c0005001e3f271f2e3d4ff03d44d34e4f003e4e5e4400010000150400000a00021a0044033e4e5e000000002c001e3f271f2e3d4ff0031e3f274400010000150400000a00020000" + var payload []byte + _, err := fmt.Sscanf(packedPdu, "%x", &payload) + if err != nil { + t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err) + } + return payload +} diff --git a/E2Manager/managers/notificationmanager/notification_manager.go b/E2Manager/managers/notificationmanager/notification_manager.go index 9583ea2..a44608b 100644 --- a/E2Manager/managers/notificationmanager/notification_manager.go +++ b/E2Manager/managers/notificationmanager/notification_manager.go @@ -49,7 +49,7 @@ func (m NotificationManager) HandleMessage(mbuf *rmrCgo.MBuf) error { return err } - notificationRequest := models.NewNotificationRequest(mbuf.Meid, *mbuf.Payload, time.Now(), string(*mbuf.XAction)) + notificationRequest := models.NewNotificationRequest(mbuf.Meid, *mbuf.Payload, time.Now(), *mbuf.XAction) go notificationHandler.Handle(notificationRequest) return nil } diff --git a/E2Manager/managers/notificationmanager/notification_manager_test.go b/E2Manager/managers/notificationmanager/notification_manager_test.go index 770ed02..5bce096 100644 --- a/E2Manager/managers/notificationmanager/notification_manager_test.go +++ b/E2Manager/managers/notificationmanager/notification_manager_test.go @@ -1,20 +1,18 @@ package notificationmanager import ( + "e2mgr/clients" "e2mgr/configuration" - "e2mgr/converters" "e2mgr/logger" "e2mgr/managers" "e2mgr/mocks" "e2mgr/providers/rmrmsghandlerprovider" - "e2mgr/rNibWriter" "e2mgr/rmrCgo" "e2mgr/services" "e2mgr/services/rmrsender" "e2mgr/tests" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/stretchr/testify/assert" "testing" ) @@ -24,24 +22,16 @@ func initNotificationManagerTest(t *testing.T) (*logger.Logger, *mocks.RnibReade config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} readerMock := &mocks.RnibReaderMock{} - rnibReaderProvider := func() reader.RNibReader { - return readerMock - } writerMock := &mocks.RnibWriterMock{} - rnibWriterProvider := func() rNibWriter.RNibWriter { - return writerMock - } + httpClient := &mocks.HttpClientMock{} rmrSender := initRmrSender(&mocks.RmrMessengerMock{}, logger) - rnibDataService := services.NewRnibDataService(logger, config, rnibReaderProvider, rnibWriterProvider) + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) ranSetupManager := managers.NewRanSetupManager(logger, rmrSender, rnibDataService) - ranReconnectionManager := managers.NewRanReconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, ranSetupManager) - ranStatusChangeManager := managers.NewRanStatusChangeManager(logger, rmrSender) - x2SetupResponseConverter := converters.NewX2SetupResponseConverter(logger) - x2SetupResponseManager := managers.NewX2SetupResponseManager(x2SetupResponseConverter) - x2SetupFailureResponseConverter := converters.NewX2SetupFailureResponseConverter(logger) - x2SetupFailureResponseManager := managers.NewX2SetupFailureResponseManager(x2SetupFailureResponseConverter) - rmrNotificationHandlerProvider := rmrmsghandlerprovider.NewNotificationHandlerProvider(logger, rnibDataService, ranReconnectionManager, ranStatusChangeManager, rmrSender, x2SetupResponseManager, x2SetupFailureResponseManager) + e2tInstancesManager := managers.NewE2TInstancesManager(rnibDataService, logger) + routingManagerClient := clients.NewRoutingManagerClient(logger, config, httpClient) + rmrNotificationHandlerProvider := rmrmsghandlerprovider.NewNotificationHandlerProvider() + rmrNotificationHandlerProvider.Init(logger, config, rnibDataService, rmrSender, ranSetupManager, e2tInstancesManager,routingManagerClient) notificationManager := NewNotificationManager(logger, rmrNotificationHandlerProvider ) return logger, readerMock, notificationManager } @@ -69,7 +59,7 @@ func TestHandleMessageExistingMessageType(t *testing.T) { func initRmrSender(rmrMessengerMock *mocks.RmrMessengerMock, log *logger.Logger) *rmrsender.RmrSender { rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock) rmrMessengerMock.On("Init", tests.GetPort(), tests.MaxMsgSize, tests.Flags, log).Return(&rmrMessenger) - return rmrsender.NewRmrSender(log, &rmrMessenger) + return rmrsender.NewRmrSender(log, rmrMessenger) } // TODO: extract to test_utils diff --git a/E2Manager/managers/ran_reconnection_manager.go b/E2Manager/managers/ran_reconnection_manager.go index 8e2ff8d..530a2cf 100644 --- a/E2Manager/managers/ran_reconnection_manager.go +++ b/E2Manager/managers/ran_reconnection_manager.go @@ -32,21 +32,27 @@ type IRanReconnectionManager interface { } type RanReconnectionManager struct { - logger *logger.Logger - config *configuration.Configuration - rnibDataService services.RNibDataService - ranSetupManager *RanSetupManager + logger *logger.Logger + config *configuration.Configuration + rnibDataService services.RNibDataService + ranSetupManager *RanSetupManager + e2tInstancesManager IE2TInstancesManager } -func NewRanReconnectionManager(logger *logger.Logger, config *configuration.Configuration, rnibDataService services.RNibDataService, ranSetupManager *RanSetupManager) *RanReconnectionManager { +func NewRanReconnectionManager(logger *logger.Logger, config *configuration.Configuration, rnibDataService services.RNibDataService, ranSetupManager *RanSetupManager, e2tInstancesManager IE2TInstancesManager) *RanReconnectionManager { return &RanReconnectionManager{ - logger: logger, - config: config, - rnibDataService: rnibDataService, - ranSetupManager: ranSetupManager, + logger: logger, + config: config, + rnibDataService: rnibDataService, + ranSetupManager: ranSetupManager, + e2tInstancesManager: e2tInstancesManager, } } +func (m *RanReconnectionManager) isRanExceededConnectionAttempts(nodebInfo *entities.NodebInfo) bool { + return int(nodebInfo.GetConnectionAttempts()) >= m.config.MaxConnectionAttempts +} + func (m *RanReconnectionManager) ReconnectRan(inventoryName string) error { nodebInfo, rnibErr := m.rnibDataService.GetNodeb(inventoryName) @@ -58,7 +64,18 @@ func (m *RanReconnectionManager) ReconnectRan(inventoryName string) error { m.logger.Infof("#RanReconnectionManager.ReconnectRan - RAN name: %s - RAN's connection status: %s, RAN's connection attempts: %d", nodebInfo.RanName, nodebInfo.ConnectionStatus, nodebInfo.ConnectionAttempts) if !m.canReconnectRan(nodebInfo) { - return m.setConnectionStatusOfUnconnectableRan(nodebInfo) + e2tAddress := nodebInfo.AssociatedE2TInstanceAddress + err := m.updateUnconnectableRan(nodebInfo) + + if err != nil { + return err + } + + if m.isRanExceededConnectionAttempts(nodebInfo) { + return m.e2tInstancesManager.DissociateRan(nodebInfo.RanName, e2tAddress) + } + + return nil } err := m.ranSetupManager.ExecuteSetup(nodebInfo, entities.ConnectionStatus_CONNECTING) @@ -77,39 +94,41 @@ func (m *RanReconnectionManager) canReconnectRan(nodebInfo *entities.NodebInfo) int(nodebInfo.GetConnectionAttempts()) < m.config.MaxConnectionAttempts } -func (m *RanReconnectionManager) updateNodebInfoStatus(nodebInfo *entities.NodebInfo, connectionStatus entities.ConnectionStatus) error { - if nodebInfo.ConnectionStatus == connectionStatus { - return nil - } +func (m *RanReconnectionManager) updateNodebInfo(nodebInfo *entities.NodebInfo, connectionStatus entities.ConnectionStatus, resetE2tAddress bool) error { nodebInfo.ConnectionStatus = connectionStatus; + + if resetE2tAddress { + nodebInfo.AssociatedE2TInstanceAddress = "" + } + err := m.rnibDataService.UpdateNodebInfo(nodebInfo) if err != nil { - m.logger.Errorf("#RanReconnectionManager.updateNodebInfoStatus - RAN name: %s - Failed updating RAN's connection status to %s in rNib. Error: %v", nodebInfo.RanName, connectionStatus, err) + m.logger.Errorf("#RanReconnectionManager.updateNodebInfo - RAN name: %s - Failed updating RAN's connection status to %s in rNib. Error: %v", nodebInfo.RanName, connectionStatus, err) return err } - m.logger.Infof("#RanReconnectionManager.updateNodebInfoStatus - RAN name: %s - Successfully updated rNib. RAN's current connection status: %s", nodebInfo.RanName, nodebInfo.ConnectionStatus) + m.logger.Infof("#RanReconnectionManager.updateNodebInfo - RAN name: %s - Successfully updated rNib. RAN's current connection status: %s", nodebInfo.RanName, nodebInfo.ConnectionStatus) return nil } -func (m *RanReconnectionManager) setConnectionStatusOfUnconnectableRan(nodebInfo *entities.NodebInfo) error { +func (m *RanReconnectionManager) updateUnconnectableRan(nodebInfo *entities.NodebInfo) error { connectionStatus := nodebInfo.GetConnectionStatus() if connectionStatus == entities.ConnectionStatus_SHUT_DOWN { - m.logger.Warnf("#RanReconnectionManager.ReconnectRan - RAN name: %s - Cannot reconnect RAN. Reason: connection status is SHUT_DOWN", nodebInfo.RanName) + m.logger.Warnf("#RanReconnectionManager.updateUnconnectableRan - RAN name: %s - Cannot reconnect RAN. Reason: connection status is SHUT_DOWN", nodebInfo.RanName) return nil } if connectionStatus == entities.ConnectionStatus_SHUTTING_DOWN { - m.logger.Warnf("#RanReconnectionManager.ReconnectRan - RAN name: %s - Cannot reconnect RAN. Reason: connection status is SHUTTING_DOWN", nodebInfo.RanName) - return m.updateNodebInfoStatus(nodebInfo, entities.ConnectionStatus_SHUT_DOWN) + m.logger.Warnf("#RanReconnectionManager.updateUnconnectableRan - RAN name: %s - Cannot reconnect RAN. Reason: connection status is SHUTTING_DOWN", nodebInfo.RanName) + return m.updateNodebInfo(nodebInfo, entities.ConnectionStatus_SHUT_DOWN, false) } - if int(nodebInfo.GetConnectionAttempts()) >= m.config.MaxConnectionAttempts { - m.logger.Warnf("#RanReconnectionManager.ReconnectRan - RAN name: %s - Cannot reconnect RAN. Reason: RAN's connection attempts exceeded the limit (%d)", nodebInfo.RanName, m.config.MaxConnectionAttempts) - return m.updateNodebInfoStatus(nodebInfo, entities.ConnectionStatus_DISCONNECTED) + if m.isRanExceededConnectionAttempts(nodebInfo) { + m.logger.Warnf("#RanReconnectionManager.updateUnconnectableRan - RAN name: %s - Cannot reconnect RAN. Reason: RAN's connection attempts exceeded the limit (%d)", nodebInfo.RanName, m.config.MaxConnectionAttempts) + return m.updateNodebInfo(nodebInfo, entities.ConnectionStatus_DISCONNECTED, true) } return nil diff --git a/E2Manager/managers/ran_reconnection_manager_test.go b/E2Manager/managers/ran_reconnection_manager_test.go index 9ccb1fd..44a3c78 100644 --- a/E2Manager/managers/ran_reconnection_manager_test.go +++ b/E2Manager/managers/ran_reconnection_manager_test.go @@ -24,14 +24,12 @@ import ( "e2mgr/configuration" "e2mgr/logger" "e2mgr/mocks" - "e2mgr/rNibWriter" "e2mgr/rmrCgo" "e2mgr/services" "e2mgr/services/rmrsender" "e2mgr/tests" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -49,19 +47,37 @@ func initRanLostConnectionTest(t *testing.T) (*logger.Logger, *mocks.RmrMessenge rmrSender := initRmrSender(rmrMessengerMock, logger) readerMock := &mocks.RnibReaderMock{} - rnibReaderProvider := func() reader.RNibReader { - return readerMock - } + writerMock := &mocks.RnibWriterMock{} - rnibWriterProvider := func() rNibWriter.RNibWriter { - return writerMock - } - rnibDataService := services.NewRnibDataService(logger, config, rnibReaderProvider, rnibWriterProvider) + + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) + e2tInstancesManager := NewE2TInstancesManager(rnibDataService, logger) ranSetupManager := NewRanSetupManager(logger, rmrSender, rnibDataService) - ranReconnectionManager := NewRanReconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, ranSetupManager) + ranReconnectionManager := NewRanReconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, ranSetupManager, e2tInstancesManager) return logger, rmrMessengerMock, readerMock, writerMock, ranReconnectionManager } +func initRanLostConnectionTestBasicMocks(t *testing.T) (*logger.Logger, *mocks.RmrMessengerMock, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *RanReconnectionManager, *mocks.E2TInstancesManagerMock) { + logger, err := logger.InitLogger(logger.DebugLevel) + if err != nil { + t.Errorf("#... - failed to initialize logger, error: %s", err) + } + config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} + + rmrMessengerMock := &mocks.RmrMessengerMock{} + rmrSender := initRmrSender(rmrMessengerMock, logger) + + readerMock := &mocks.RnibReaderMock{} + + writerMock := &mocks.RnibWriterMock{} + + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) + e2tInstancesManagerMock := &mocks.E2TInstancesManagerMock{} + ranSetupManager := NewRanSetupManager(logger, rmrSender, rnibDataService) + ranReconnectionManager := NewRanReconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, ranSetupManager, e2tInstancesManagerMock) + return logger, rmrMessengerMock, readerMock, writerMock, ranReconnectionManager, e2tInstancesManagerMock +} + func TestRanReconnectionGetNodebFailure(t *testing.T) { _, _, readerMock, writerMock, ranReconnectionManager := initRanLostConnectionTest(t) ranName := "test" @@ -100,21 +116,48 @@ func TestShuttingdownRanReconnection(t *testing.T) { writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1) } -func TestConnectingRanWithMaxAttemptsReconnection(t *testing.T) { +func TestConnectingRanWithMaxAttemptsReconnectionDissociateSucceeds(t *testing.T) { _, _, readerMock, writerMock, ranReconnectionManager := initRanLostConnectionTest(t) ranName := "test" - origNodebInfo := &entities.NodebInfo{RanName: ranName, GlobalNbId: &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"}, ConnectionStatus: entities.ConnectionStatus_CONNECTING, ConnectionAttempts: 20} + e2tAddress := "10.0.2.15" + origNodebInfo := &entities.NodebInfo{RanName: ranName, GlobalNbId: &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"}, ConnectionStatus: entities.ConnectionStatus_CONNECTING, ConnectionAttempts: 20, AssociatedE2TInstanceAddress: e2tAddress} var rnibErr error readerMock.On("GetNodeb", ranName).Return(origNodebInfo, rnibErr) updatedNodebInfo := *origNodebInfo updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED + updatedNodebInfo.AssociatedE2TInstanceAddress = "" writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(rnibErr) + e2tInstance := &entities.E2TInstance{Address:e2tAddress, AssociatedRanList:[]string{ranName}} + readerMock.On("GetE2TInstance",e2tAddress).Return(e2tInstance, nil) + e2tInstanceToSave := * e2tInstance + e2tInstanceToSave .AssociatedRanList = []string{} + writerMock.On("SaveE2TInstance", &e2tInstanceToSave).Return(nil) err := ranReconnectionManager.ReconnectRan(ranName) assert.Nil(t, err) readerMock.AssertCalled(t, "GetNodeb", ranName) writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1) } +func TestConnectingRanWithMaxAttemptsReconnectionDissociateFails(t *testing.T) { + _, _, readerMock, writerMock, ranReconnectionManager := initRanLostConnectionTest(t) + ranName := "test" + e2tAddress := "10.0.2.15" + origNodebInfo := &entities.NodebInfo{RanName: ranName, GlobalNbId: &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"}, ConnectionStatus: entities.ConnectionStatus_CONNECTING, ConnectionAttempts: 20, AssociatedE2TInstanceAddress: e2tAddress} + var rnibErr error + readerMock.On("GetNodeb", ranName).Return(origNodebInfo, rnibErr) + updatedNodebInfo := *origNodebInfo + updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED + updatedNodebInfo.AssociatedE2TInstanceAddress = "" + writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(rnibErr) + e2tInstance := &entities.E2TInstance{Address:e2tAddress, AssociatedRanList:[]string{ranName}} + readerMock.On("GetE2TInstance",e2tAddress).Return(e2tInstance, common.NewInternalError(errors.New("Error"))) + err := ranReconnectionManager.ReconnectRan(ranName) + assert.NotNil(t, err) + readerMock.AssertCalled(t, "GetNodeb", ranName) + writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1) + writerMock.AssertNotCalled(t, "SaveE2TInstance", ) +} + func TestUnconnectableRanUpdateNodebInfoFailure(t *testing.T) { _, _, readerMock, writerMock, ranReconnectionManager := initRanLostConnectionTest(t) ranName := "test" @@ -140,7 +183,7 @@ func TestConnectedRanExecuteSetupSuccess(t *testing.T) { updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_CONNECTING updatedNodebInfo.ConnectionAttempts++ writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(nil) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(&rmrCgo.MBuf{}, nil) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(&rmrCgo.MBuf{}, nil) err := ranReconnectionManager.ReconnectRan(ranName) assert.Nil(t, err) readerMock.AssertCalled(t, "GetNodeb", ranName) @@ -164,8 +207,15 @@ func TestConnectedRanExecuteSetupFailure(t *testing.T) { writerMock.AssertNumberOfCalls(t, "UpdateNodebInfo", 1) } +func TestNoSetConnectionStatus(t *testing.T) { + _, _, _, _, ranReconnectionManager := initRanLostConnectionTest(t) + nodebInfo := &entities.NodebInfo{RanName: "ranName", GlobalNbId: &entities.GlobalNbId{PlmnId: "xxx", NbId: "yyy"}, ConnectionStatus: entities.ConnectionStatus_CONNECTED} + err := ranReconnectionManager.updateUnconnectableRan(nodebInfo) + assert.Nil(t, err) +} + func initRmrSender(rmrMessengerMock *mocks.RmrMessengerMock, log *logger.Logger) *rmrsender.RmrSender { rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock) rmrMessengerMock.On("Init", tests.GetPort(), tests.MaxMsgSize, tests.Flags, log).Return(&rmrMessenger) - return rmrsender.NewRmrSender(log, &rmrMessenger) + return rmrsender.NewRmrSender(log, rmrMessenger) } diff --git a/E2Manager/managers/ran_setup_manager.go b/E2Manager/managers/ran_setup_manager.go index 40b4d00..de54308 100644 --- a/E2Manager/managers/ran_setup_manager.go +++ b/E2Manager/managers/ran_setup_manager.go @@ -37,6 +37,10 @@ type RanSetupManager struct { rmrSender *rmrsender.RmrSender } +type IRanSetupManager interface { + ExecuteSetup(nodebInfo *entities.NodebInfo, status entities.ConnectionStatus) error +} + func NewRanSetupManager(logger *logger.Logger, rmrSender *rmrsender.RmrSender, rnibDataService services.RNibDataService) *RanSetupManager { return &RanSetupManager{ logger: logger, @@ -105,7 +109,8 @@ func (m *RanSetupManager) ExecuteSetup(nodebInfo *entities.NodebInfo, status ent } // Send the endc/x2 setup request - msg := models.NewRmrMessage(rmrMsgType, nodebInfo.RanName, request.GetMessageAsBytes(m.logger)) + var xAction []byte + msg := models.NewRmrMessage(rmrMsgType, nodebInfo.RanName, request.GetMessageAsBytes(m.logger), xAction) err = m.rmrSender.Send(msg) diff --git a/E2Manager/managers/ran_setup_manager_test.go b/E2Manager/managers/ran_setup_manager_test.go index 4ea7919..4178062 100644 --- a/E2Manager/managers/ran_setup_manager_test.go +++ b/E2Manager/managers/ran_setup_manager_test.go @@ -26,13 +26,11 @@ import ( "e2mgr/e2pdus" "e2mgr/logger" "e2mgr/mocks" - "e2mgr/rNibWriter" "e2mgr/rmrCgo" "e2mgr/services" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "testing" @@ -49,14 +47,10 @@ func initRanSetupManagerTest(t *testing.T) (*mocks.RmrMessengerMock, *mocks.Rnib rmrSender := initRmrSender(rmrMessengerMock, logger) readerMock := &mocks.RnibReaderMock{} - rnibReaderProvider := func() reader.RNibReader { - return readerMock - } + writerMock := &mocks.RnibWriterMock{} - rnibWriterProvider := func() rNibWriter.RNibWriter { - return writerMock - } - rnibDataService := services.NewRnibDataService(logger, config, rnibReaderProvider, rnibWriterProvider) + + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) ranSetupManager := NewRanSetupManager(logger, rmrSender, rnibDataService) return rmrMessengerMock, writerMock, ranSetupManager } @@ -74,7 +68,7 @@ func TestExecuteSetupConnectingX2Setup(t *testing.T) { payload := e2pdus.PackedX2setupRequest xaction := []byte(ranName) msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil) if err := mgr.ExecuteSetup(initialNodeb, entities.ConnectionStatus_CONNECTING); err != nil { t.Errorf("want: success, got: error: %s", err) @@ -97,7 +91,7 @@ func TestExecuteSetupConnectingEndcX2Setup(t *testing.T) { payload := e2pdus.PackedEndcX2setupRequest xaction := []byte(ranName) msg := rmrCgo.NewMBuf(rmrCgo.RIC_ENDC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil) if err := mgr.ExecuteSetup(initialNodeb, entities.ConnectionStatus_CONNECTING); err != nil { t.Errorf("want: success, got: error: %s", err) @@ -122,7 +116,7 @@ func TestExecuteSetupDisconnected(t *testing.T) { payload := []byte{0} xaction := []byte(ranName) msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, fmt.Errorf("send failure")) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, fmt.Errorf("send failure")) if err := mgr.ExecuteSetup(initialNodeb, entities.ConnectionStatus_CONNECTING); err == nil { t.Errorf("want: failure, got: success") @@ -147,7 +141,7 @@ func TestExecuteSetupConnectingRnibError(t *testing.T) { payload := []byte{0} xaction := []byte(ranName) msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, fmt.Errorf("send failure")) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, fmt.Errorf("send failure")) if err := mgr.ExecuteSetup(initialNodeb, entities.ConnectionStatus_CONNECTING); err == nil { t.Errorf("want: failure, got: success") @@ -174,7 +168,7 @@ func TestExecuteSetupDisconnectedRnibError(t *testing.T) { payload := []byte{0} xaction := []byte(ranName) msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, fmt.Errorf("send failure")) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, fmt.Errorf("send failure")) if err := mgr.ExecuteSetup(initialNodeb, entities.ConnectionStatus_CONNECTING); err == nil { t.Errorf("want: failure, got: success") @@ -199,7 +193,7 @@ func TestExecuteSetupUnsupportedProtocol(t *testing.T) { payload := e2pdus.PackedX2setupRequest xaction := []byte(ranName) msg := rmrCgo.NewMBuf(rmrCgo.RIC_X2_SETUP_REQ, len(payload), ranName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", mock.Anything).Return(msg, nil) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(msg, nil) if err := mgr.ExecuteSetup(initialNodeb, entities.ConnectionStatus_CONNECTING); err == nil { t.Errorf("want: error, got: success") diff --git a/E2Manager/managers/ran_status_change_manager.go b/E2Manager/managers/ran_status_change_manager.go index 153255a..049cc86 100644 --- a/E2Manager/managers/ran_status_change_manager.go +++ b/E2Manager/managers/ran_status_change_manager.go @@ -35,6 +35,7 @@ func (m *RanStatusChangeManager) Execute(msgType int, msgDirection enums.Message return err } - rmrMessage := models.NewRmrMessage(msgType, nodebInfo.RanName, resourceStatusJson) + var xAction []byte + rmrMessage := models.NewRmrMessage(msgType, nodebInfo.RanName, resourceStatusJson, xAction) return m.rmrSender.Send(rmrMessage) } diff --git a/E2Manager/managers/ran_status_change_manager_test.go b/E2Manager/managers/ran_status_change_manager_test.go index be8642e..ea9bfcd 100644 --- a/E2Manager/managers/ran_status_change_manager_test.go +++ b/E2Manager/managers/ran_status_change_manager_test.go @@ -40,7 +40,7 @@ func TestMarshalSuccess(t *testing.T) { nodebInfo := entities.NodebInfo{NodeType: entities.Node_ENB} var err error - rmrMessengerMock.On("SendMsg", mock.Anything).Return(&rmrCgo.MBuf{}, err) + rmrMessengerMock.On("SendMsg", mock.Anything, true).Return(&rmrCgo.MBuf{}, err) err = m.Execute(rmrCgo.RAN_CONNECTED, enums.RIC_TO_RAN, &nodebInfo) assert.Nil(t, err) diff --git a/E2Manager/managers/x2_setup_failure_response_manager_test.go b/E2Manager/managers/x2_setup_failure_response_manager_test.go new file mode 100644 index 0000000..b5e1849 --- /dev/null +++ b/E2Manager/managers/x2_setup_failure_response_manager_test.go @@ -0,0 +1,57 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package managers + +import ( + "e2mgr/converters" + "e2mgr/tests" + "fmt" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestPopulateX2NodebByPduFailure(t *testing.T) { + logger := tests.InitLog(t) + nodebInfo := &entities.NodebInfo{} + nodebIdentity := &entities.NbIdentity{} + handler := NewX2SetupFailureResponseManager(converters.NewX2SetupFailureResponseConverter(logger)) + err := handler.PopulateNodebByPdu(logger, nodebIdentity, nodebInfo, createRandomPayload()) + assert.NotNil(t, err) +} + +func TestPopulateX2NodebByPduSuccess(t *testing.T) { + logger := tests.InitLog(t) + nodebInfo := &entities.NodebInfo{} + nodebIdentity := &entities.NbIdentity{} + handler := NewX2SetupFailureResponseManager(converters.NewX2SetupFailureResponseConverter(logger)) + err := handler.PopulateNodebByPdu(logger, nodebIdentity, nodebInfo, createX2SetupFailureResponsePayload(t)) + assert.Nil(t, err) + assert.Equal(t, entities.ConnectionStatus_CONNECTED_SETUP_FAILED, nodebInfo.ConnectionStatus) + assert.Equal(t, entities.Failure_X2_SETUP_FAILURE, nodebInfo.FailureType) + +} + +func createX2SetupFailureResponsePayload(t *testing.T) []byte { + packedPdu := "4006001a0000030005400200000016400100001140087821a00000008040" + var payload []byte + _, err := fmt.Sscanf(packedPdu, "%x", &payload) + if err != nil { + t.Errorf("convert inputPayloadAsStr to payloadAsByte. Error: %v\n", err) + } + return payload +} diff --git a/E2Manager/mocks/controllerMock.go b/E2Manager/mocks/controllerMock.go deleted file mode 100644 index 7575f72..0000000 --- a/E2Manager/mocks/controllerMock.go +++ /dev/null @@ -1,58 +0,0 @@ -package mocks - -import ( - "github.com/gorilla/mux" - "github.com/stretchr/testify/mock" - "net/http" -) - -type ControllerMock struct { - mock.Mock -} - -func (c *ControllerMock) GetNodeb(writer http.ResponseWriter, r *http.Request){ - writer.Header().Set("Content-Type", "application/json") - writer.WriteHeader(http.StatusOK) - - vars := mux.Vars(r) - ranName := vars["ranName"] - - writer.Write([]byte(ranName)) - - c.Called() -} - -func (c *ControllerMock) GetNodebIdList(writer http.ResponseWriter, r *http.Request){ - c.Called() -} - - -func (c *ControllerMock) Shutdown(writer http.ResponseWriter, r *http.Request){ - c.Called() -} - -func (c *ControllerMock) X2Reset(writer http.ResponseWriter, r *http.Request){ - writer.Header().Set("Content-Type", "application/json") - writer.WriteHeader(http.StatusOK) - - vars := mux.Vars(r) - ranName := vars["ranName"] - - writer.Write([]byte(ranName)) - - c.Called() -} - -func (c *ControllerMock) X2Setup(writer http.ResponseWriter, r *http.Request){ - writer.Header().Set("Content-Type", "application/json") - writer.WriteHeader(http.StatusOK) - - c.Called() -} - -func (c *ControllerMock) EndcSetup(writer http.ResponseWriter, r *http.Request){ - writer.Header().Set("Content-Type", "application/json") - writer.WriteHeader(http.StatusOK) - - c.Called() -} \ No newline at end of file diff --git a/E2Manager/mocks/e2t_controller_mock.go b/E2Manager/mocks/e2t_controller_mock.go new file mode 100644 index 0000000..d72c292 --- /dev/null +++ b/E2Manager/mocks/e2t_controller_mock.go @@ -0,0 +1,35 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package mocks + +import ( + "github.com/stretchr/testify/mock" + "net/http" +) + +type E2TControllerMock struct { + mock.Mock +} + +func (m *E2TControllerMock) HandleRequest(writer http.ResponseWriter, request *http.Request) { + m.Called() +} + +func (m *E2TControllerMock) GetE2TInstances(writer http.ResponseWriter, request *http.Request) { + m.Called() +} diff --git a/E2Manager/mocks/e2t_instances_manager_mock.go b/E2Manager/mocks/e2t_instances_manager_mock.go new file mode 100644 index 0000000..235c76a --- /dev/null +++ b/E2Manager/mocks/e2t_instances_manager_mock.go @@ -0,0 +1,82 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package mocks + +import ( + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "github.com/stretchr/testify/mock" +) + +type E2TInstancesManagerMock struct { + mock.Mock +} + +func (m *E2TInstancesManagerMock) GetE2TInstance(e2tAddress string) (*entities.E2TInstance, error) { + args := m.Called(e2tAddress) + + return args.Get(0).(*entities.E2TInstance), args.Error(1) +} + +func (m *E2TInstancesManagerMock) AddE2TInstance(e2tInstanceAddress string) error { + args := m.Called(e2tInstanceAddress) + return args.Error(0) +} + +func (m *E2TInstancesManagerMock) RemoveE2TInstance(e2tInstance *entities.E2TInstance) error { + args := m.Called(e2tInstance) + return args.Error(0) +} + +func (m *E2TInstancesManagerMock) SelectE2TInstance() (string, error) { + args := m.Called() + return args.String(0), args.Error(1) +} + +func (m *E2TInstancesManagerMock) AssociateRan(ranName string, e2tAddress string) error { + args := m.Called(ranName, e2tAddress) + return args.Error(0) + +} +func (m *E2TInstancesManagerMock) DissociateRan(ranName string, e2tAddress string) error { + args := m.Called(ranName, e2tAddress) + return args.Error(0) + +} + +func (m *E2TInstancesManagerMock) GetE2TInstances() ([]*entities.E2TInstance, error) { + args := m.Called() + + return args.Get(0).([]*entities.E2TInstance), args.Error(1) +} + +func (m *E2TInstancesManagerMock) GetE2TInstancesNoLogs() ([]*entities.E2TInstance, error) { + args := m.Called() + + return args.Get(0).([]*entities.E2TInstance), args.Error(1) +} + +func (m *E2TInstancesManagerMock) ResetKeepAliveTimestamp(e2tAddress string) error { + args := m.Called(e2tAddress) + return args.Error(0) + +} + +func (m *E2TInstancesManagerMock) ActivateE2TInstance(e2tInstance *entities.E2TInstance) error { + args := m.Called(e2tInstance) + return args.Error(0) + +} \ No newline at end of file diff --git a/E2Manager/rnibBuilders/node_info_builder.go b/E2Manager/mocks/e2t_shutdown_manager_mock.go similarity index 56% rename from E2Manager/rnibBuilders/node_info_builder.go rename to E2Manager/mocks/e2t_shutdown_manager_mock.go index bfee4f6..c560f1d 100644 --- a/E2Manager/rnibBuilders/node_info_builder.go +++ b/E2Manager/mocks/e2t_shutdown_manager_mock.go @@ -18,23 +18,18 @@ // platform project (RICP). -package rnibBuilders +package mocks import ( "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "e2mgr/models" + "github.com/stretchr/testify/mock" ) -func CreateInitialNodeInfo(requestDetails *models.SetupRequest, protocol entities.E2ApplicationProtocol) (*entities.NodebInfo, *entities.NbIdentity) { - nodebInfo := &entities.NodebInfo{} - nodebInfo.Ip = requestDetails.RanIp - nodebInfo.Port = uint32(requestDetails.RanPort) - nodebInfo.ConnectionStatus = entities.ConnectionStatus_CONNECTING - nodebInfo.E2ApplicationProtocol = protocol - nodebInfo.RanName = requestDetails.RanName - nodebInfo.ConnectionAttempts = 0 +type E2TShutdownManagerMock struct { + mock.Mock +} - nodebIdentity := &entities.NbIdentity{} - nodebIdentity.InventoryName = requestDetails.RanName - return nodebInfo, nodebIdentity +func (m *E2TShutdownManagerMock) Shutdown(e2tInstance *entities.E2TInstance) error { + args := m.Called(e2tInstance) + return args.Error(0) } \ No newline at end of file diff --git a/E2Manager/mocks/http_client_mock.go b/E2Manager/mocks/http_client_mock.go new file mode 100644 index 0000000..1294c48 --- /dev/null +++ b/E2Manager/mocks/http_client_mock.go @@ -0,0 +1,41 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + + +package mocks + +import ( + "github.com/stretchr/testify/mock" + "io" + "net/http" +) + +type HttpClientMock struct { + mock.Mock +} + +func (c *HttpClientMock) Post(url, contentType string, body io.Reader) (resp *http.Response, err error) { + args := c.Called(url, contentType, body) + return args.Get(0).(*http.Response), args.Error(1) +} + +//func (c *HttpClientMock) Do(req *http.Request) (*http.Response, error) { +// args := c.Called(req) +// return args.Get(0).(*http.Response), args.Error(1) +//} diff --git a/E2Manager/mocks/nodebControllerMock.go b/E2Manager/mocks/nodebControllerMock.go deleted file mode 100644 index 51b5bf0..0000000 --- a/E2Manager/mocks/nodebControllerMock.go +++ /dev/null @@ -1,35 +0,0 @@ -package mocks - -import ( - "github.com/gorilla/mux" - "github.com/stretchr/testify/mock" - "net/http" -) - -type NodebControllerMock struct { - mock.Mock -} - -func (rc *NodebControllerMock) HandleRequest(writer http.ResponseWriter, request *http.Request) { - rc.Called() -} - -func (rc *NodebControllerMock) GetNodebIdList (writer http.ResponseWriter, request *http.Request) { - rc.Called() -} - -func (rc *NodebControllerMock) GetNodeb(writer http.ResponseWriter, request *http.Request) { - writer.Header().Set("Content-Type", "application/json") - writer.WriteHeader(http.StatusOK) - - vars := mux.Vars(request) - ranName := vars["ranName"] - - writer.Write([]byte(ranName)) - - rc.Called() -} - -func (rc *NodebControllerMock) HandleHealthCheckRequest(writer http.ResponseWriter, request *http.Request) { - rc.Called() -} diff --git a/E2Manager/mocks/nodeb_controller_mock.go b/E2Manager/mocks/nodeb_controller_mock.go new file mode 100644 index 0000000..eafc935 --- /dev/null +++ b/E2Manager/mocks/nodeb_controller_mock.go @@ -0,0 +1,73 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package mocks + +import ( + "github.com/gorilla/mux" + "github.com/stretchr/testify/mock" + "net/http" +) + +type NodebControllerMock struct { + mock.Mock +} + +func (c *NodebControllerMock) GetNodeb(writer http.ResponseWriter, r *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + + vars := mux.Vars(r) + ranName := vars["ranName"] + + writer.Write([]byte(ranName)) + c.Called() +} + +func (c *NodebControllerMock) GetNodebIdList(writer http.ResponseWriter, r *http.Request) { + c.Called() +} + +func (c *NodebControllerMock) Shutdown(writer http.ResponseWriter, r *http.Request) { + c.Called() +} + +func (c *NodebControllerMock) X2Reset(writer http.ResponseWriter, r *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + + vars := mux.Vars(r) + ranName := vars["ranName"] + + writer.Write([]byte(ranName)) + + c.Called() +} + +func (c *NodebControllerMock) X2Setup(writer http.ResponseWriter, r *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + + c.Called() +} + +func (c *NodebControllerMock) EndcSetup(writer http.ResponseWriter, r *http.Request) { + writer.Header().Set("Content-Type", "application/json") + writer.WriteHeader(http.StatusOK) + + c.Called() +} diff --git a/E2Manager/mocks/ran_setup_manager_mock.go b/E2Manager/mocks/ran_setup_manager_mock.go new file mode 100644 index 0000000..656657c --- /dev/null +++ b/E2Manager/mocks/ran_setup_manager_mock.go @@ -0,0 +1,31 @@ +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package mocks + +import ( + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "github.com/stretchr/testify/mock" +) + +type RanSetupManagerMock struct { + mock.Mock +} + +func (m *RanSetupManagerMock) ExecuteSetup(nodebInfo *entities.NodebInfo, status entities.ConnectionStatus) error { + args := m.Called(nodebInfo, status) + + return args.Error(0) +} diff --git a/E2Manager/mocks/rmrMessengerMock.go b/E2Manager/mocks/rmrMessengerMock.go index dccd7d0..b517fe9 100644 --- a/E2Manager/mocks/rmrMessengerMock.go +++ b/E2Manager/mocks/rmrMessengerMock.go @@ -30,13 +30,13 @@ type RmrMessengerMock struct { mock.Mock } -func (m *RmrMessengerMock) Init(port string, maxMsgSize int, flags int, logger *logger.Logger) *rmrCgo.RmrMessenger{ +func (m *RmrMessengerMock) Init(port string, maxMsgSize int, flags int, logger *logger.Logger) rmrCgo.RmrMessenger{ args := m.Called(port, maxMsgSize, flags, logger) - return args.Get(0).(*rmrCgo.RmrMessenger) + return args.Get(0).(rmrCgo.RmrMessenger) } -func (m *RmrMessengerMock) SendMsg(msg *rmrCgo.MBuf) (*rmrCgo.MBuf, error){ - args := m.Called(msg) +func (m *RmrMessengerMock) SendMsg(msg *rmrCgo.MBuf, printLogs bool) (*rmrCgo.MBuf, error){ + args := m.Called(msg, printLogs) return args.Get(0).(*rmrCgo.MBuf), args.Error(1) } diff --git a/E2Manager/mocks/rnibReaderMock.go b/E2Manager/mocks/rnibReaderMock.go index 237cdac..59c635e 100644 --- a/E2Manager/mocks/rnibReaderMock.go +++ b/E2Manager/mocks/rnibReaderMock.go @@ -32,7 +32,6 @@ func (m *RnibReaderMock) GetNodeb(inventoryName string) (*entities.NodebInfo, er args := m.Called(inventoryName) errArg := args.Get(1); - if errArg != nil { return args.Get(0).(*entities.NodebInfo), errArg.(error); } @@ -44,7 +43,6 @@ func (m *RnibReaderMock) GetNodebByGlobalNbId(nodeType entities.Node_Type, globa args := m.Called(nodeType, globalNbId) errArg := args.Get(1); - if errArg != nil { return args.Get(0).(*entities.NodebInfo), errArg.(error); } @@ -56,7 +54,6 @@ func (m *RnibReaderMock) GetCellList(inventoryName string) (*entities.Cells, err args := m.Called(inventoryName) errArg := args.Get(1); - if errArg != nil { return args.Get(0).(*entities.Cells), errArg.(error); } @@ -68,7 +65,6 @@ func (m *RnibReaderMock) GetListGnbIds() ([]*entities.NbIdentity, error) { args := m.Called() errArg := args.Get(1); - if errArg != nil { return args.Get(0).([]*entities.NbIdentity), errArg.(error); } @@ -80,7 +76,6 @@ func (m *RnibReaderMock) GetListEnbIds() ([]*entities.NbIdentity, error) { args := m.Called() errArg := args.Get(1); - if errArg != nil { return args.Get(0).([]*entities.NbIdentity), errArg.(error); } @@ -93,7 +88,6 @@ func (m *RnibReaderMock) GetCountGnbList() (int, error) { args := m.Called() errArg := args.Get(1); - if errArg != nil { return args.Int(0), errArg.(error); } @@ -106,7 +100,6 @@ func (m *RnibReaderMock) GetCell(inventoryName string, pci uint32) (*entities.Ce args := m.Called(inventoryName, pci) errArg := args.Get(1); - if errArg != nil { return args.Get(0).(*entities.Cell), errArg.(error); } @@ -118,7 +111,6 @@ func (m *RnibReaderMock) GetCellById(cellType entities.Cell_Type, cellId string) args := m.Called(cellType, cellId) errArg := args.Get(1); - if errArg != nil { return args.Get(0).(*entities.Cell), errArg.(error); } @@ -149,3 +141,18 @@ func (m *RnibReaderMock) GetRanLoadInformation(inventoryName string) (*entities. return args.Get(0).(*entities.RanLoadInformation), nil } + +func (m *RnibReaderMock) GetE2TInstance(e2taddress string) (*entities.E2TInstance, error) { + args := m.Called(e2taddress) + return args.Get(0).(*entities.E2TInstance), args.Error(1) +} + +func (m *RnibReaderMock) GetE2TInstances(addresses []string) ([]*entities.E2TInstance, error) { + args := m.Called(addresses) + return args.Get(0).([]*entities.E2TInstance), args.Error(1) +} + +func (m *RnibReaderMock) GetE2TAddresses() ([]string, error) { + args := m.Called() + return args.Get(0).([]string), args.Error(1) +} diff --git a/E2Manager/mocks/rnibWriterMock.go b/E2Manager/mocks/rnibWriterMock.go index 53ec47a..5ca925f 100644 --- a/E2Manager/mocks/rnibWriterMock.go +++ b/E2Manager/mocks/rnibWriterMock.go @@ -64,3 +64,15 @@ func (rnibWriterMock *RnibWriterMock) SaveRanLoadInformation(inventoryName strin return nil } + +func (rnibWriterMock *RnibWriterMock) SaveE2TInstance(e2tInstance *entities.E2TInstance) error { + args := rnibWriterMock.Called(e2tInstance) + + return args.Error(0) +} + +func (rnibWriterMock *RnibWriterMock) SaveE2TAddresses(addresses []string) error { + args := rnibWriterMock.Called(addresses) + + return args.Error(0) +} diff --git a/E2Manager/mocks/root_controller_mock.go b/E2Manager/mocks/root_controller_mock.go new file mode 100644 index 0000000..df58b61 --- /dev/null +++ b/E2Manager/mocks/root_controller_mock.go @@ -0,0 +1,31 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package mocks + +import ( + "github.com/stretchr/testify/mock" + "net/http" +) + +type RootControllerMock struct { + mock.Mock +} + +func (rc *RootControllerMock) HandleHealthCheckRequest(writer http.ResponseWriter, request *http.Request) { + rc.Called() +} diff --git a/E2Manager/mocks/routing_manager_client_mock.go b/E2Manager/mocks/routing_manager_client_mock.go new file mode 100644 index 0000000..24edd55 --- /dev/null +++ b/E2Manager/mocks/routing_manager_client_mock.go @@ -0,0 +1,46 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +package mocks + +import ( + "github.com/stretchr/testify/mock" +) + +type RoutingManagerClientMock struct { + mock.Mock +} + +func (m *RoutingManagerClientMock) AddE2TInstance(e2tAddress string) error { + + args := m.Called(e2tAddress) + return args.Error(0) +} + +func (m *RoutingManagerClientMock) AssociateRanToE2TInstance(e2tAddress string, ranName string) error { + + args := m.Called(e2tAddress, ranName) + return args.Error(0) +} + +func (m *RoutingManagerClientMock) DissociateRanE2TInstance(e2tAddress string, ranName string) error { + + args := m.Called(e2tAddress, ranName) + return args.Error(0) +} \ No newline at end of file diff --git a/E2Manager/models/e2_request_message_test.go b/E2Manager/models/e2_request_message_test.go index eac92b0..e7ca8c7 100644 --- a/E2Manager/models/e2_request_message_test.go +++ b/E2Manager/models/e2_request_message_test.go @@ -18,10 +18,11 @@ // platform project (RICP). -package models +package models_test import ( "e2mgr/logger" + "e2mgr/models" "e2mgr/tests" "encoding/hex" "github.com/stretchr/testify/assert" @@ -29,12 +30,12 @@ import ( ) const transactionId = "transactionId" -const expectedMessageAsBytesHex = "31302e302e302e337c353535357c746573747c347c01020304" +const expectedMessageAsBytesHex = "31302e302e302e337c333830317c746573747c347c01020304" func TestNewE2RequestMessage(t *testing.T){ - e2 :=NewE2RequestMessage(transactionId, tests.RanIp, uint16(tests.Port), tests.RanName, tests.DummyPayload) + e2 :=models.NewE2RequestMessage(transactionId, tests.RanIp, uint16(tests.Port), tests.RanName, tests.DummyPayload) assert.NotNil(t, e2) - assert.IsType(t, *e2, E2RequestMessage{}) + assert.IsType(t, *e2, models.E2RequestMessage{}) assert.Equal(t, tests.RanName, e2.RanName()) assert.Equal(t, transactionId, e2.TransactionId()) } @@ -45,7 +46,7 @@ func TestGetMessageAsBytes(t *testing.T){ t.Errorf("#nodeb_controller_test.TestHandleRequestSuccess - failed to initialize logger, error: %s", err) } - e2 :=NewE2RequestMessage(transactionId, tests.RanIp, uint16(tests.Port), tests.RanName, tests.DummyPayload) + e2 := models.NewE2RequestMessage(transactionId, tests.RanIp, uint16(tests.Port), tests.RanName, tests.DummyPayload) bytes := e2.GetMessageAsBytes(log) assert.Equal(t, expectedMessageAsBytesHex, hex.EncodeToString(bytes)) } \ No newline at end of file diff --git a/E2Manager/models/e2_term_init_payload.go b/E2Manager/models/e2_term_init_payload.go new file mode 100644 index 0000000..e533582 --- /dev/null +++ b/E2Manager/models/e2_term_init_payload.go @@ -0,0 +1,22 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package models + +type E2TermInitPayload struct { + Address string `json:"address"` + Fqdn string `json:"fqdn"` +} \ No newline at end of file diff --git a/E2Manager/models/e2t_keep_alive_payload.go b/E2Manager/models/e2t_keep_alive_payload.go new file mode 100644 index 0000000..cdc8ba6 --- /dev/null +++ b/E2Manager/models/e2t_keep_alive_payload.go @@ -0,0 +1,21 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package models + +type E2TKeepAlivePayload struct { + Address string `json:"address"` +} \ No newline at end of file diff --git a/E2Manager/models/get_e2t_instances_response.go b/E2Manager/models/get_e2t_instances_response.go new file mode 100644 index 0000000..f39c1ff --- /dev/null +++ b/E2Manager/models/get_e2t_instances_response.go @@ -0,0 +1,49 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package models + +import ( + "e2mgr/e2managererrors" + "encoding/json" +) + +type E2TInstancesResponse []*E2TInstanceResponseModel + +type E2TInstanceResponseModel struct { + E2TAddress string `json:"e2tAddress"` + RanNames []string `json:"ranNames"` +} + +func NewE2TInstanceResponseModel(e2tAddress string, ranNames []string) *E2TInstanceResponseModel { + return &E2TInstanceResponseModel{ + E2TAddress: e2tAddress, + RanNames: ranNames, + } +} + +func (response E2TInstancesResponse) Marshal() ([]byte, error) { + + data, err := json.Marshal(response) + + if err != nil { + return nil, e2managererrors.NewInternalError() + } + + return data, nil + +} diff --git a/E2Manager/models/get_nodeb_id_list_response.go b/E2Manager/models/get_nodeb_id_list_response.go index dfafab5..7ed83aa 100644 --- a/E2Manager/models/get_nodeb_id_list_response.go +++ b/E2Manager/models/get_nodeb_id_list_response.go @@ -36,13 +36,13 @@ func NewGetNodebIdListResponse(nodebIdList []*entities.NbIdentity) *GetNodebIdLi } } -func (response *GetNodebIdListResponse) Marshal() (string, error) { +func (response *GetNodebIdListResponse) Marshal() ([]byte, error) { pmList := utils.ConvertNodebIdListToProtoMessageList(response.nodebIdList) result, err := utils.MarshalProtoMessageListToJsonArray(pmList) if err != nil { - return "", e2managererrors.NewInternalError(); + return nil, e2managererrors.NewInternalError(); } - return result, nil + return []byte(result), nil } diff --git a/E2Manager/models/get_nodeb_response.go b/E2Manager/models/get_nodeb_response.go index 9474465..1eaa32a 100644 --- a/E2Manager/models/get_nodeb_response.go +++ b/E2Manager/models/get_nodeb_response.go @@ -36,14 +36,14 @@ func NewGetNodebResponse(nodebInfo *entities.NodebInfo) *GetNodebResponse { } } -func (response *GetNodebResponse) Marshal() (string, error) { +func (response *GetNodebResponse) Marshal() ([]byte, error) { m := jsonpb.Marshaler{} result, err := m.MarshalToString(response.nodebInfo) if err != nil { - return "", e2managererrors.NewInternalError() + return nil, e2managererrors.NewInternalError() } - return result, nil + return []byte(result), nil } diff --git a/E2Manager/models/i_response.go b/E2Manager/models/i_response.go index 531fbbd..9620297 100644 --- a/E2Manager/models/i_response.go +++ b/E2Manager/models/i_response.go @@ -21,5 +21,5 @@ package models type IResponse interface { - Marshal() (string, error) + Marshal() ([]byte, error) } diff --git a/E2Manager/models/notification_request.go b/E2Manager/models/notification_request.go index 7e3892a..b275587 100644 --- a/E2Manager/models/notification_request.go +++ b/E2Manager/models/notification_request.go @@ -27,10 +27,10 @@ type NotificationRequest struct { Len int Payload []byte StartTime time.Time - TransactionId string + TransactionId []byte } -func NewNotificationRequest(ranName string, payload []byte, startTime time.Time, transactionId string) *NotificationRequest { +func NewNotificationRequest(ranName string, payload []byte, startTime time.Time, transactionId []byte) *NotificationRequest { return &NotificationRequest{ ranName, len(payload), diff --git a/E2Manager/models/rmr_message.go b/E2Manager/models/rmr_message.go index 5fd39f8..1971b1e 100644 --- a/E2Manager/models/rmr_message.go +++ b/E2Manager/models/rmr_message.go @@ -20,24 +20,18 @@ package models -import ( - "e2mgr/logger" -) - type RmrMessage struct { MsgType int RanName string Payload []byte + XAction []byte } -func NewRmrMessage(msgType int, ranName string, payload []byte) *RmrMessage { +func NewRmrMessage(msgType int, ranName string, payload []byte, xAction []byte) *RmrMessage { return &RmrMessage{ MsgType: msgType, RanName: ranName, Payload: payload, + XAction: xAction, } } - -func (response RmrMessage) GetMessageAsBytes(logger *logger.Logger) []byte { - return response.Payload -} diff --git a/E2Manager/models/routing_manager_e2t_data.go b/E2Manager/models/routing_manager_e2t_data.go new file mode 100644 index 0000000..9e8e313 --- /dev/null +++ b/E2Manager/models/routing_manager_e2t_data.go @@ -0,0 +1,41 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +package models + +type RoutingManagerE2TData struct { + E2TAddress string `json:"E2TAddress"` + RanNamelist []string `json:"ranNamelist,omitempty"` +} + +func NewRoutingManagerE2TData (e2tAddress string, ranNameList ...string) *RoutingManagerE2TData { + data := &RoutingManagerE2TData{ + E2TAddress: e2tAddress, + } + + if len(ranNameList) == 0 { + return data + } + + for _, ranName := range ranNameList { + data.RanNamelist = append(data.RanNamelist, ranName) + } + + return data +} diff --git a/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider.go b/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider.go index 70c2327..1e601f9 100644 --- a/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider.go +++ b/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider.go @@ -33,12 +33,13 @@ import ( type IncomingRequest string const ( - ShutdownRequest IncomingRequest = "Shutdown" - ResetRequest IncomingRequest = "Reset" - X2SetupRequest IncomingRequest = "X2SetupRequest" - EndcSetupRequest IncomingRequest = "EndcSetupRequest" - GetNodebRequest IncomingRequest = "GetNodebRequest" - GetNodebIdListRequest IncomingRequest = "GetNodebIdListRequest" + ShutdownRequest IncomingRequest = "Shutdown" + ResetRequest IncomingRequest = "Reset" + X2SetupRequest IncomingRequest = "X2SetupRequest" + EndcSetupRequest IncomingRequest = "EndcSetupRequest" + GetNodebRequest IncomingRequest = "GetNodebRequest" + GetNodebIdListRequest IncomingRequest = "GetNodebIdListRequest" + GetE2TInstancesRequest IncomingRequest = "GetE2TInstancesRequest" ) type IncomingRequestHandlerProvider struct { @@ -46,23 +47,24 @@ type IncomingRequestHandlerProvider struct { logger *logger.Logger } -func NewIncomingRequestHandlerProvider(logger *logger.Logger, rmrSender *rmrsender.RmrSender, config *configuration.Configuration, rNibDataService services.RNibDataService, ranSetupManager *managers.RanSetupManager) *IncomingRequestHandlerProvider { +func NewIncomingRequestHandlerProvider(logger *logger.Logger, rmrSender *rmrsender.RmrSender, config *configuration.Configuration, rNibDataService services.RNibDataService, ranSetupManager *managers.RanSetupManager, e2tInstancesManager managers.IE2TInstancesManager) *IncomingRequestHandlerProvider { return &IncomingRequestHandlerProvider{ - requestMap: initRequestHandlerMap(logger, rmrSender, config, rNibDataService, ranSetupManager), + requestMap: initRequestHandlerMap(logger, rmrSender, config, rNibDataService, ranSetupManager, e2tInstancesManager), logger: logger, } } -func initRequestHandlerMap(logger *logger.Logger, rmrSender *rmrsender.RmrSender, config *configuration.Configuration, rNibDataService services.RNibDataService, ranSetupManager *managers.RanSetupManager) map[IncomingRequest]httpmsghandlers.RequestHandler { +func initRequestHandlerMap(logger *logger.Logger, rmrSender *rmrsender.RmrSender, config *configuration.Configuration, rNibDataService services.RNibDataService, ranSetupManager *managers.RanSetupManager, e2tInstancesManager managers.IE2TInstancesManager) map[IncomingRequest]httpmsghandlers.RequestHandler { return map[IncomingRequest]httpmsghandlers.RequestHandler{ - ShutdownRequest: httpmsghandlers.NewDeleteAllRequestHandler(logger, rmrSender, config, rNibDataService), //TODO change to pointer - ResetRequest: httpmsghandlers.NewX2ResetRequestHandler(logger, rmrSender, rNibDataService), - X2SetupRequest: httpmsghandlers.NewSetupRequestHandler(logger, rNibDataService, ranSetupManager, entities.E2ApplicationProtocol_X2_SETUP_REQUEST), - EndcSetupRequest: httpmsghandlers.NewSetupRequestHandler(logger, rNibDataService, ranSetupManager, entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST), //TODO change to pointer - GetNodebRequest: httpmsghandlers.NewGetNodebRequestHandler(logger, rNibDataService), - GetNodebIdListRequest: httpmsghandlers.NewGetNodebIdListRequestHandler(logger, rNibDataService), + ShutdownRequest: httpmsghandlers.NewDeleteAllRequestHandler(logger, rmrSender, config, rNibDataService), //TODO change to pointer + ResetRequest: httpmsghandlers.NewX2ResetRequestHandler(logger, rmrSender, rNibDataService), + X2SetupRequest: httpmsghandlers.NewSetupRequestHandler(logger, rNibDataService, ranSetupManager, entities.E2ApplicationProtocol_X2_SETUP_REQUEST, e2tInstancesManager), + EndcSetupRequest: httpmsghandlers.NewSetupRequestHandler(logger, rNibDataService, ranSetupManager, entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, e2tInstancesManager), + GetNodebRequest: httpmsghandlers.NewGetNodebRequestHandler(logger, rNibDataService), + GetNodebIdListRequest: httpmsghandlers.NewGetNodebIdListRequestHandler(logger, rNibDataService), + GetE2TInstancesRequest: httpmsghandlers.NewGetE2TInstancesRequestHandler(logger, e2tInstancesManager), } } diff --git a/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider_test.go b/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider_test.go index 73dfbf6..840d9c2 100644 --- a/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider_test.go +++ b/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider_test.go @@ -27,12 +27,10 @@ import ( "e2mgr/logger" "e2mgr/managers" "e2mgr/mocks" - "e2mgr/rNibWriter" "e2mgr/rmrCgo" "e2mgr/services" "e2mgr/services/rmrsender" "e2mgr/tests" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/stretchr/testify/assert" "reflect" "testing" @@ -41,23 +39,20 @@ import ( func getRmrSender(rmrMessengerMock *mocks.RmrMessengerMock, log *logger.Logger) *rmrsender.RmrSender { rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock) rmrMessengerMock.On("Init", tests.GetPort(), tests.MaxMsgSize, tests.Flags, log).Return(&rmrMessenger) - return rmrsender.NewRmrSender(log, &rmrMessenger) + return rmrsender.NewRmrSender(log, rmrMessenger) } func setupTest(t *testing.T) *IncomingRequestHandlerProvider { rmrMessengerMock := &mocks.RmrMessengerMock{} log := initLog(t) config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} - readerProvider := func() reader.RNibReader { - return &mocks.RnibReaderMock{} - } - writerProvider := func() rNibWriter.RNibWriter { - return &mocks.RnibWriterMock{} - } - rnibDataService := services.NewRnibDataService(log, config, readerProvider, writerProvider) + readerMock := &mocks.RnibReaderMock{} + writerMock := &mocks.RnibWriterMock{} + rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock) rmrSender := getRmrSender(rmrMessengerMock, log) ranSetupManager := managers.NewRanSetupManager(log, rmrSender, rnibDataService) - return NewIncomingRequestHandlerProvider(log, rmrSender, configuration.ParseConfiguration(), rnibDataService, ranSetupManager) + e2tInstancesManager := managers.NewE2TInstancesManager(rnibDataService, log) + return NewIncomingRequestHandlerProvider(log, rmrSender, configuration.ParseConfiguration(), rnibDataService, ranSetupManager, e2tInstancesManager) } func TestNewIncomingRequestHandlerProvider(t *testing.T) { diff --git a/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider.go b/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider.go index 55c786b..b161c93 100644 --- a/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider.go +++ b/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider.go @@ -21,6 +21,8 @@ package rmrmsghandlerprovider import ( + "e2mgr/clients" + "e2mgr/configuration" "e2mgr/converters" "e2mgr/handlers/rmrmsghandlers" "e2mgr/logger" @@ -35,28 +37,13 @@ type NotificationHandlerProvider struct { notificationHandlers map[int]rmrmsghandlers.NotificationHandler } -func NewNotificationHandlerProvider(logger *logger.Logger, rnibDataService services.RNibDataService, ranReconnectionManager *managers.RanReconnectionManager, ranStatusChangeManager *managers.RanStatusChangeManager, rmrSender *rmrsender.RmrSender, x2SetupResponseManager *managers.X2SetupResponseManager, x2SetupFailureResponseManager *managers.X2SetupFailureResponseManager) *NotificationHandlerProvider { +func NewNotificationHandlerProvider() *NotificationHandlerProvider { return &NotificationHandlerProvider{ - notificationHandlers: initNotificationHandlersMap(logger, rnibDataService, ranReconnectionManager, ranStatusChangeManager, rmrSender, x2SetupResponseManager, x2SetupFailureResponseManager), - } -} - -func initNotificationHandlersMap(logger *logger.Logger, rnibDataService services.RNibDataService, ranReconnectionManager *managers.RanReconnectionManager, ranStatusChangeManager *managers.RanStatusChangeManager, rmrSender *rmrsender.RmrSender, x2SetupResponseManager *managers.X2SetupResponseManager, x2SetupFailureResponseManager *managers.X2SetupFailureResponseManager) map[int]rmrmsghandlers.NotificationHandler { - return map[int]rmrmsghandlers.NotificationHandler{ - rmrCgo.RIC_X2_SETUP_RESP: rmrmsghandlers.NewSetupResponseNotificationHandler(logger, rnibDataService, x2SetupResponseManager, ranStatusChangeManager, rmrCgo.RIC_X2_SETUP_RESP), - rmrCgo.RIC_X2_SETUP_FAILURE: rmrmsghandlers.NewSetupResponseNotificationHandler(logger, rnibDataService, x2SetupFailureResponseManager, nil, rmrCgo.RIC_X2_SETUP_FAILURE), - rmrCgo.RIC_ENDC_X2_SETUP_RESP: rmrmsghandlers.NewSetupResponseNotificationHandler(logger, rnibDataService, managers.NewEndcSetupResponseManager(), ranStatusChangeManager, rmrCgo.RIC_ENDC_X2_SETUP_RESP), - rmrCgo.RIC_ENDC_X2_SETUP_FAILURE: rmrmsghandlers.NewSetupResponseNotificationHandler(logger, rnibDataService, managers.NewEndcSetupFailureResponseManager(), nil, rmrCgo.RIC_ENDC_X2_SETUP_FAILURE), - rmrCgo.RIC_SCTP_CONNECTION_FAILURE: rmrmsghandlers.NewRanLostConnectionHandler(logger, ranReconnectionManager), - rmrCgo.RIC_ENB_LOAD_INFORMATION: rmrmsghandlers.NewEnbLoadInformationNotificationHandler(logger, rnibDataService, converters.NewEnbLoadInformationExtractor(logger)), - rmrCgo.RIC_ENB_CONF_UPDATE: rmrmsghandlers.NewX2EnbConfigurationUpdateHandler(logger, rmrSender), - rmrCgo.RIC_ENDC_CONF_UPDATE: rmrmsghandlers.NewEndcConfigurationUpdateHandler(logger, rmrSender), - rmrCgo.RIC_X2_RESET_RESP: rmrmsghandlers.NewX2ResetResponseHandler(logger, rnibDataService, ranStatusChangeManager, converters.NewX2ResetResponseExtractor(logger)), - rmrCgo.RIC_X2_RESET: rmrmsghandlers.NewX2ResetRequestNotificationHandler(logger, rnibDataService, ranStatusChangeManager, rmrSender), - rmrCgo.RIC_E2_TERM_INIT: rmrmsghandlers.NewE2TermInitNotificationHandler(logger, ranReconnectionManager, rnibDataService), + notificationHandlers: map[int]rmrmsghandlers.NotificationHandler{}, } } +// TODO: check whether it has been initialized func (provider NotificationHandlerProvider) GetNotificationHandler(messageType int) (rmrmsghandlers.NotificationHandler, error) { handler, ok := provider.notificationHandlers[messageType] @@ -66,3 +53,53 @@ func (provider NotificationHandlerProvider) GetNotificationHandler(messageType i return handler, nil } + +func (provider *NotificationHandlerProvider) Register(msgType int, handler rmrmsghandlers.NotificationHandler) { + provider.notificationHandlers[msgType] = handler +} + +func (provider *NotificationHandlerProvider) Init(logger *logger.Logger, config *configuration.Configuration, rnibDataService services.RNibDataService, rmrSender *rmrsender.RmrSender, ranSetupManager *managers.RanSetupManager, e2tInstancesManager managers.IE2TInstancesManager, routingManagerClient clients.IRoutingManagerClient) { + + // Init converters + x2SetupResponseConverter := converters.NewX2SetupResponseConverter(logger) + x2SetupFailureResponseConverter := converters.NewX2SetupFailureResponseConverter(logger) + endcSetupResponseConverter := converters.NewEndcSetupResponseConverter(logger) + endcSetupFailureResponseConverter := converters.NewEndcSetupFailureResponseConverter(logger) + enbLoadInformationExtractor := converters.NewEnbLoadInformationExtractor(logger) + x2ResetResponseExtractor := converters.NewX2ResetResponseExtractor(logger) + + // Init managers + ranReconnectionManager := managers.NewRanReconnectionManager(logger, config, rnibDataService, ranSetupManager, e2tInstancesManager) + ranStatusChangeManager := managers.NewRanStatusChangeManager(logger, rmrSender) + x2SetupResponseManager := managers.NewX2SetupResponseManager(x2SetupResponseConverter) + x2SetupFailureResponseManager := managers.NewX2SetupFailureResponseManager(x2SetupFailureResponseConverter) + endcSetupResponseManager := managers.NewEndcSetupResponseManager(endcSetupResponseConverter) + endcSetupFailureResponseManager := managers.NewEndcSetupFailureResponseManager(endcSetupFailureResponseConverter) + + // Init handlers + x2SetupResponseHandler := rmrmsghandlers.NewSetupResponseNotificationHandler(logger, rnibDataService, x2SetupResponseManager, ranStatusChangeManager, rmrCgo.RIC_X2_SETUP_RESP) + x2SetupFailureResponseHandler := rmrmsghandlers.NewSetupResponseNotificationHandler(logger, rnibDataService, x2SetupFailureResponseManager, nil, rmrCgo.RIC_X2_SETUP_FAILURE) + endcSetupResponseHandler := rmrmsghandlers.NewSetupResponseNotificationHandler(logger, rnibDataService, endcSetupResponseManager, ranStatusChangeManager, rmrCgo.RIC_ENDC_X2_SETUP_RESP) + endcSetupFailureResponseHandler := rmrmsghandlers.NewSetupResponseNotificationHandler(logger, rnibDataService, endcSetupFailureResponseManager, nil, rmrCgo.RIC_ENDC_X2_SETUP_FAILURE) + ranLostConnectionHandler := rmrmsghandlers.NewRanLostConnectionHandler(logger, ranReconnectionManager) + enbLoadInformationNotificationHandler := rmrmsghandlers.NewEnbLoadInformationNotificationHandler(logger, rnibDataService, enbLoadInformationExtractor) + x2EnbConfigurationUpdateHandler := rmrmsghandlers.NewX2EnbConfigurationUpdateHandler(logger, rmrSender) + endcConfigurationUpdateHandler := rmrmsghandlers.NewEndcConfigurationUpdateHandler(logger, rmrSender) + x2ResetResponseHandler := rmrmsghandlers.NewX2ResetResponseHandler(logger, rnibDataService, ranStatusChangeManager, x2ResetResponseExtractor) + x2ResetRequestNotificationHandler := rmrmsghandlers.NewX2ResetRequestNotificationHandler(logger, rnibDataService, ranStatusChangeManager, rmrSender) + e2TermInitNotificationHandler := rmrmsghandlers.NewE2TermInitNotificationHandler(logger, ranReconnectionManager, rnibDataService, e2tInstancesManager, routingManagerClient) + e2TKeepAliveResponseHandler := rmrmsghandlers.NewE2TKeepAliveResponseHandler(logger, rnibDataService, e2tInstancesManager) + + provider.Register(rmrCgo.RIC_X2_SETUP_RESP, x2SetupResponseHandler) + provider.Register(rmrCgo.RIC_X2_SETUP_FAILURE, x2SetupFailureResponseHandler) + provider.Register(rmrCgo.RIC_ENDC_X2_SETUP_RESP, endcSetupResponseHandler) + provider.Register(rmrCgo.RIC_ENDC_X2_SETUP_FAILURE, endcSetupFailureResponseHandler) + provider.Register(rmrCgo.RIC_SCTP_CONNECTION_FAILURE, ranLostConnectionHandler) + provider.Register(rmrCgo.RIC_ENB_LOAD_INFORMATION, enbLoadInformationNotificationHandler) + provider.Register(rmrCgo.RIC_ENB_CONF_UPDATE, x2EnbConfigurationUpdateHandler) + provider.Register(rmrCgo.RIC_ENDC_CONF_UPDATE, endcConfigurationUpdateHandler) + provider.Register(rmrCgo.RIC_X2_RESET_RESP, x2ResetResponseHandler) + provider.Register(rmrCgo.RIC_X2_RESET, x2ResetRequestNotificationHandler) + provider.Register(rmrCgo.RIC_E2_TERM_INIT, e2TermInitNotificationHandler) + provider.Register(rmrCgo.E2_TERM_KEEP_ALIVE_RESP, e2TKeepAliveResponseHandler) +} diff --git a/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider_test.go b/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider_test.go index d86b55d..fb5dadb 100644 --- a/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider_test.go +++ b/E2Manager/providers/rmrmsghandlerprovider/notification_handler_provider_test.go @@ -21,18 +21,17 @@ package rmrmsghandlerprovider import ( + "e2mgr/clients" "e2mgr/configuration" "e2mgr/converters" "e2mgr/handlers/rmrmsghandlers" "e2mgr/logger" "e2mgr/managers" "e2mgr/mocks" - "e2mgr/rNibWriter" "e2mgr/services" "e2mgr/services/rmrsender" "e2mgr/tests" "fmt" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "strings" "testing" @@ -43,23 +42,28 @@ import ( * Verify support for known providers. */ -func initTestCase(t *testing.T) (*logger.Logger, services.RNibDataService, *managers.RanReconnectionManager, *managers.RanStatusChangeManager, *rmrsender.RmrSender, *managers.X2SetupResponseManager, *managers.X2SetupFailureResponseManager) { +func initTestCase(t *testing.T) (*logger.Logger, *configuration.Configuration, services.RNibDataService, *rmrsender.RmrSender, *managers.RanSetupManager, managers.IE2TInstancesManager, clients.IRoutingManagerClient) { logger := initLog(t) config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} readerMock := &mocks.RnibReaderMock{} - rnibReaderProvider := func() reader.RNibReader { - return readerMock - } writerMock := &mocks.RnibWriterMock{} - rnibWriterProvider := func() rNibWriter.RNibWriter { - return writerMock - } + httpClient := &mocks.HttpClientMock{} rmrSender := initRmrSender(&mocks.RmrMessengerMock{}, logger) - rnibDataService := services.NewRnibDataService(logger, config, rnibReaderProvider, rnibWriterProvider) + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) ranSetupManager := managers.NewRanSetupManager(logger, rmrSender, rnibDataService) - ranReconnectionManager := managers.NewRanReconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, ranSetupManager) + e2tInstancesManager := managers.NewE2TInstancesManager(rnibDataService, logger) + routingManagerClient := clients.NewRoutingManagerClient(logger, config, httpClient) + + return logger, config, rnibDataService, rmrSender, ranSetupManager, e2tInstancesManager, routingManagerClient +} + +func TestGetNotificationHandlerSuccess(t *testing.T) { + + logger, config, rnibDataService, rmrSender, ranSetupManager, e2tInstancesManager, routingManagerClient := initTestCase(t) + + ranReconnectionManager := managers.NewRanReconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, ranSetupManager, e2tInstancesManager) ranStatusChangeManager := managers.NewRanStatusChangeManager(logger, rmrSender) x2SetupResponseConverter := converters.NewX2SetupResponseConverter(logger) @@ -68,34 +72,36 @@ func initTestCase(t *testing.T) (*logger.Logger, services.RNibDataService, *mana x2SetupFailureResponseConverter := converters.NewX2SetupFailureResponseConverter(logger) x2SetupFailureResponseManager := managers.NewX2SetupFailureResponseManager(x2SetupFailureResponseConverter) + endcSetupResponseConverter := converters.NewEndcSetupResponseConverter(logger) + endcSetupResponseManager := managers.NewEndcSetupResponseManager(endcSetupResponseConverter) - return logger, rnibDataService, ranReconnectionManager, ranStatusChangeManager, rmrSender, x2SetupResponseManager, x2SetupFailureResponseManager -} -func TestGetNotificationHandlerSuccess(t *testing.T) { + endcSetupFailureResponseConverter := converters.NewEndcSetupFailureResponseConverter(logger) + endcSetupFailureResponseManager := managers.NewEndcSetupFailureResponseManager(endcSetupFailureResponseConverter) - logger, rnibDataService, ranReconnectionManager, ranStatusChangeManager, rmrSender, x2SetupResponseManager, x2SetupFailureResponseManager := initTestCase(t) var testCases = []struct { msgType int handler rmrmsghandlers.NotificationHandler }{ - {rmrCgo.RIC_X2_SETUP_RESP, rmrmsghandlers.NewSetupResponseNotificationHandler(logger,rnibDataService, x2SetupResponseManager, ranStatusChangeManager, rmrCgo.RIC_X2_SETUP_RESP)}, - {rmrCgo.RIC_X2_SETUP_FAILURE, rmrmsghandlers.NewSetupResponseNotificationHandler(logger,rnibDataService, x2SetupFailureResponseManager, ranStatusChangeManager, rmrCgo.RIC_X2_SETUP_FAILURE)}, - {rmrCgo.RIC_ENDC_X2_SETUP_RESP, rmrmsghandlers.NewSetupResponseNotificationHandler(logger,rnibDataService, managers.NewEndcSetupResponseManager(), ranStatusChangeManager, rmrCgo.RIC_ENDC_X2_SETUP_RESP)}, - {rmrCgo.RIC_ENDC_X2_SETUP_FAILURE, rmrmsghandlers.NewSetupResponseNotificationHandler(logger,rnibDataService, managers.NewEndcSetupFailureResponseManager(), ranStatusChangeManager, rmrCgo.RIC_ENDC_X2_SETUP_FAILURE),}, - {rmrCgo.RIC_SCTP_CONNECTION_FAILURE, rmrmsghandlers.NewRanLostConnectionHandler(logger,ranReconnectionManager)}, - {rmrCgo.RIC_ENB_LOAD_INFORMATION, rmrmsghandlers.NewEnbLoadInformationNotificationHandler(logger,rnibDataService, converters.NewEnbLoadInformationExtractor(logger))}, + {rmrCgo.RIC_X2_SETUP_RESP, rmrmsghandlers.NewSetupResponseNotificationHandler(logger, rnibDataService, x2SetupResponseManager, ranStatusChangeManager, rmrCgo.RIC_X2_SETUP_RESP)}, + {rmrCgo.RIC_X2_SETUP_FAILURE, rmrmsghandlers.NewSetupResponseNotificationHandler(logger, rnibDataService, x2SetupFailureResponseManager, ranStatusChangeManager, rmrCgo.RIC_X2_SETUP_FAILURE)}, + {rmrCgo.RIC_ENDC_X2_SETUP_RESP, rmrmsghandlers.NewSetupResponseNotificationHandler(logger, rnibDataService, endcSetupResponseManager, ranStatusChangeManager, rmrCgo.RIC_ENDC_X2_SETUP_RESP)}, + {rmrCgo.RIC_ENDC_X2_SETUP_FAILURE, rmrmsghandlers.NewSetupResponseNotificationHandler(logger, rnibDataService, endcSetupFailureResponseManager, ranStatusChangeManager, rmrCgo.RIC_ENDC_X2_SETUP_FAILURE),}, + {rmrCgo.RIC_SCTP_CONNECTION_FAILURE, rmrmsghandlers.NewRanLostConnectionHandler(logger, ranReconnectionManager)}, + {rmrCgo.RIC_ENB_LOAD_INFORMATION, rmrmsghandlers.NewEnbLoadInformationNotificationHandler(logger, rnibDataService, converters.NewEnbLoadInformationExtractor(logger))}, {rmrCgo.RIC_ENB_CONF_UPDATE, rmrmsghandlers.NewX2EnbConfigurationUpdateHandler(logger, rmrSender)}, {rmrCgo.RIC_ENDC_CONF_UPDATE, rmrmsghandlers.NewEndcConfigurationUpdateHandler(logger, rmrSender)}, - {rmrCgo.RIC_E2_TERM_INIT, rmrmsghandlers.NewE2TermInitNotificationHandler(logger,ranReconnectionManager, rnibDataService)}, + {rmrCgo.RIC_E2_TERM_INIT, rmrmsghandlers.NewE2TermInitNotificationHandler(logger, ranReconnectionManager, rnibDataService, e2tInstancesManager, routingManagerClient)}, + {rmrCgo.E2_TERM_KEEP_ALIVE_RESP, rmrmsghandlers.NewE2TKeepAliveResponseHandler(logger, rnibDataService, e2tInstancesManager)}, {rmrCgo.RIC_X2_RESET_RESP, rmrmsghandlers.NewX2ResetResponseHandler(logger, rnibDataService, ranStatusChangeManager, converters.NewX2ResetResponseExtractor(logger))}, - {rmrCgo.RIC_X2_RESET, rmrmsghandlers.NewX2ResetRequestNotificationHandler(logger,rnibDataService, ranStatusChangeManager, rmrSender)}, + {rmrCgo.RIC_X2_RESET, rmrmsghandlers.NewX2ResetRequestNotificationHandler(logger, rnibDataService, ranStatusChangeManager, rmrSender)}, } for _, tc := range testCases { - provider := NewNotificationHandlerProvider(logger, rnibDataService, ranReconnectionManager, ranStatusChangeManager, rmrSender, x2SetupResponseManager, x2SetupFailureResponseManager) + provider := NewNotificationHandlerProvider() + provider.Init(logger, config, rnibDataService, rmrSender, ranSetupManager, e2tInstancesManager, routingManagerClient) t.Run(fmt.Sprintf("%d", tc.msgType), func(t *testing.T) { handler, err := provider.GetNotificationHandler(tc.msgType) if err != nil { @@ -124,8 +130,9 @@ func TestGetNotificationHandlerFailure(t *testing.T) { } for _, tc := range testCases { - logger, rnibDataService, ranReconnectionManager, ranStatusChangeManager, rmrSender, x2SetupResponseManager, x2SetupFailureResponseManager := initTestCase(t) - provider := NewNotificationHandlerProvider(logger, rnibDataService, ranReconnectionManager, ranStatusChangeManager, rmrSender, x2SetupResponseManager, x2SetupFailureResponseManager) + logger, config, rnibDataService, rmrSender, ranSetupManager, e2tInstancesManager, routingManagerClient := initTestCase(t) + provider := NewNotificationHandlerProvider() + provider.Init(logger, config, rnibDataService, rmrSender, ranSetupManager, e2tInstancesManager, routingManagerClient) t.Run(fmt.Sprintf("%d", tc.msgType), func(t *testing.T) { _, err := provider.GetNotificationHandler(tc.msgType) if err == nil { @@ -142,7 +149,7 @@ func TestGetNotificationHandlerFailure(t *testing.T) { func initRmrSender(rmrMessengerMock *mocks.RmrMessengerMock, log *logger.Logger) *rmrsender.RmrSender { rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock) rmrMessengerMock.On("Init", tests.GetPort(), tests.MaxMsgSize, tests.Flags, log).Return(&rmrMessenger) - return rmrsender.NewRmrSender(log, &rmrMessenger) + return rmrsender.NewRmrSender(log, rmrMessenger) } // TODO: extract to test_utils diff --git a/E2Manager/rNibWriter/rNibWriter.go b/E2Manager/rNibWriter/rNibWriter.go index c996a1e..13a31f3 100644 --- a/E2Manager/rNibWriter/rNibWriter.go +++ b/E2Manager/rNibWriter/rNibWriter.go @@ -21,18 +21,17 @@ package rNibWriter import ( + "encoding/json" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/sdlgo" "github.com/golang/protobuf/proto" ) -var writerPool *common.Pool +const E2TAddressesKey = "E2TAddresses" type rNibWriterInstance struct { - sdl *common.ISdlInstance - namespace string + sdl common.ISdlInstance } /* @@ -42,45 +41,27 @@ type RNibWriter interface { SaveNodeb(nbIdentity *entities.NbIdentity, nb *entities.NodebInfo) error UpdateNodebInfo(nodebInfo *entities.NodebInfo) error SaveRanLoadInformation(inventoryName string, ranLoadInformation *entities.RanLoadInformation) error + SaveE2TInstance(e2tInstance *entities.E2TInstance) error + SaveE2TAddresses(addresses []string) error } -/* -Init initializes the infrastructure required for the RNibWriter instance -*/ -func Init(namespace string, poolSize int) { - initPool(poolSize, - func() interface{} { - var sdlI common.ISdlInstance = sdlgo.NewSdlInstance(namespace, sdlgo.NewDatabase()) - return &rNibWriterInstance{sdl: &sdlI, namespace: namespace} - }, - func(obj interface{}) { - (*obj.(*rNibWriterInstance).sdl).Close() - }) -} - -/* -InitPool initializes the writer's instances pool -*/ -func initPool(poolSize int, newObj func() interface{}, destroyObj func(interface{})) { - writerPool = common.NewPool(poolSize, newObj, destroyObj) -} /* GetRNibWriter returns reference to RNibWriter */ -func GetRNibWriter() RNibWriter { - return &rNibWriterInstance{} + +func GetRNibWriter(sdl common.ISdlInstance) RNibWriter { + return &rNibWriterInstance{sdl: sdl} } + /* SaveNodeb saves nodeB entity data in the redis DB according to the specified data model */ -func (*rNibWriterInstance) SaveNodeb(nbIdentity *entities.NbIdentity, entity *entities.NodebInfo) error { - w := writerPool.Get().(*rNibWriterInstance) +func (w *rNibWriterInstance) SaveNodeb(nbIdentity *entities.NbIdentity, entity *entities.NodebInfo) error { isNotEmptyIdentity := isNotEmpty(nbIdentity) if isNotEmptyIdentity && entity.GetNodeType() == entities.Node_UNKNOWN { return common.NewValidationError(fmt.Sprintf("#rNibWriter.saveNodeB - Unknown responding node type, entity: %v", entity)) } - defer writerPool.Put(w) data, err := proto.Marshal(entity) if err != nil { return common.NewInternalError(err) @@ -112,7 +93,7 @@ func (*rNibWriterInstance) SaveNodeb(nbIdentity *entities.NbIdentity, entity *en return rNibErr } } - err = (*w.sdl).Set(pairs) + err = w.sdl.Set(pairs) if err != nil { return common.NewInternalError(err) } @@ -124,7 +105,7 @@ func (*rNibWriterInstance) SaveNodeb(nbIdentity *entities.NbIdentity, entity *en if err != nil { return common.NewInternalError(err) } - err = (*w.sdl).RemoveMember(entities.Node_UNKNOWN.String(), nbIdData) + err = w.sdl.RemoveMember(entities.Node_UNKNOWN.String(), nbIdData) if err != nil { return common.NewInternalError(err) } @@ -136,7 +117,7 @@ func (*rNibWriterInstance) SaveNodeb(nbIdentity *entities.NbIdentity, entity *en if err != nil { return common.NewInternalError(err) } - err = (*w.sdl).AddMember(entity.GetNodeType().String(), nbIdData) + err = w.sdl.AddMember(entity.GetNodeType().String(), nbIdData) if err != nil { return common.NewInternalError(err) } @@ -146,9 +127,7 @@ func (*rNibWriterInstance) SaveNodeb(nbIdentity *entities.NbIdentity, entity *en /* UpdateNodebInfo... */ -func (*rNibWriterInstance) UpdateNodebInfo(nodebInfo *entities.NodebInfo) error { - w := writerPool.Get().(*rNibWriterInstance) - defer writerPool.Put(w) +func (w *rNibWriterInstance) UpdateNodebInfo(nodebInfo *entities.NodebInfo) error { nodebNameKey, rNibErr := common.ValidateAndBuildNodeBNameKey(nodebInfo.GetRanName()) @@ -171,7 +150,7 @@ func (*rNibWriterInstance) UpdateNodebInfo(nodebInfo *entities.NodebInfo) error pairs = append(pairs, nodebIdKey, data) } - err = (*w.sdl).Set(pairs) + err = w.sdl.Set(pairs) if err != nil { return common.NewInternalError(err) @@ -183,9 +162,7 @@ func (*rNibWriterInstance) UpdateNodebInfo(nodebInfo *entities.NodebInfo) error /* SaveRanLoadInformation stores ran load information for the provided ran */ -func (*rNibWriterInstance) SaveRanLoadInformation(inventoryName string, ranLoadInformation *entities.RanLoadInformation) error { - w := writerPool.Get().(*rNibWriterInstance) - defer writerPool.Put(w) +func (w *rNibWriterInstance) SaveRanLoadInformation(inventoryName string, ranLoadInformation *entities.RanLoadInformation) error { key, rnibErr := common.ValidateAndBuildRanLoadInformationKey(inventoryName) @@ -202,7 +179,53 @@ func (*rNibWriterInstance) SaveRanLoadInformation(inventoryName string, ranLoadI var pairs []interface{} pairs = append(pairs, key, data) - err = (*w.sdl).Set(pairs) + err = w.sdl.Set(pairs) + + if err != nil { + return common.NewInternalError(err) + } + + return nil +} + +func (w *rNibWriterInstance) SaveE2TInstance(e2tInstance *entities.E2TInstance) error { + + key, rnibErr := common.ValidateAndBuildE2TInstanceKey(e2tInstance.Address) + + if rnibErr != nil { + return rnibErr + } + + data, err := json.Marshal(e2tInstance) + + if err != nil { + return common.NewInternalError(err) + } + + var pairs []interface{} + pairs = append(pairs, key, data) + + err = w.sdl.Set(pairs) + + if err != nil { + return common.NewInternalError(err) + } + + return nil +} + +func (w *rNibWriterInstance) SaveE2TAddresses(addresses []string) error { + + data, err := json.Marshal(addresses) + + if err != nil { + return common.NewInternalError(err) + } + + var pairs []interface{} + pairs = append(pairs, E2TAddressesKey, data) + + err = w.sdl.Set(pairs) if err != nil { return common.NewInternalError(err) @@ -212,10 +235,10 @@ func (*rNibWriterInstance) SaveRanLoadInformation(inventoryName string, ranLoadI } /* -Close closes writer's pool +Close the writer */ func Close() { - writerPool.Close() + //Nothing to do } func appendEnbCells(nbIdentity *entities.NbIdentity, cells []*entities.ServedCellInfo, pairs []interface{}) ([]interface{}, error) { diff --git a/E2Manager/rNibWriter/rNibWriter_test.go b/E2Manager/rNibWriter/rNibWriter_test.go index f16228b..34ef4c8 100644 --- a/E2Manager/rNibWriter/rNibWriter_test.go +++ b/E2Manager/rNibWriter/rNibWriter_test.go @@ -22,6 +22,7 @@ package rNibWriter import ( "e2mgr/mocks" + "encoding/json" "errors" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" @@ -32,55 +33,19 @@ import ( "time" ) -func TestInitRNibWriter(t *testing.T) { - writerPool = nil - initSdlInstanceMock(namespace, 1) - available, created := writerPool.Stats() - assert.Equal(t, available, 0, "number of available objects in the writerPool should be 0") - assert.Equal(t, created, 0, "number of created objects in the writerPool should be 0") - w := GetRNibWriter() - assert.NotNil(t, w) -} - -func TestInitPool(t *testing.T) { - writerPool = nil - sdlInstanceMock := new(mocks.MockSdlInstance) - initPool(1, func() interface{} { - sdlI := common.ISdlInstance(sdlInstanceMock) - return &rNibWriterInstance{sdl: &sdlI, namespace: namespace} - }, - func(obj interface{}) { - }, - ) - assert.NotNil(t, writerPool) - assert.NotNil(t, writerPool.New) - assert.NotNil(t, writerPool.Destroy) - available, created := writerPool.Stats() - assert.Equal(t, 0, available, "number of available objects in the writerPool should be 0") - assert.Equal(t, 0, created, "number of created objects in the writerPool should be 0") +func initSdlInstanceMock(namespace string) (w RNibWriter, sdlInstanceMock *mocks.MockSdlInstance) { + sdlInstanceMock = new(mocks.MockSdlInstance) + w = GetRNibWriter(sdlInstanceMock) + return } var namespace = "namespace" -func initSdlInstanceMock(namespace string, poolSize int) *mocks.MockSdlInstance { - sdlInstanceMock := new(mocks.MockSdlInstance) - initPool(poolSize, func() interface{} { - sdlI := common.ISdlInstance(sdlInstanceMock) - return &rNibWriterInstance{sdl: &sdlI, namespace: namespace} - }, - func(obj interface{}) { - }, - ) - return sdlInstanceMock -} - func TestUpdateNodebInfoSuccess(t *testing.T) { inventoryName := "name" plmnId := "02f829" nbId := "4a952a0a" - writerPool = nil - sdlInstanceMock := initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, sdlInstanceMock := initSdlInstanceMock(namespace) nodebInfo := &entities.NodebInfo{} nodebInfo.RanName = inventoryName nodebInfo.GlobalNbId = &entities.GlobalNbId{PlmnId: plmnId, NbId: nbId} @@ -110,9 +75,7 @@ func TestUpdateNodebInfoMissingInventoryNameFailure(t *testing.T) { inventoryName := "name" plmnId := "02f829" nbId := "4a952a0a" - writerPool = nil - sdlInstanceMock := initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, sdlInstanceMock := initSdlInstanceMock(namespace) nodebInfo := &entities.NodebInfo{} data, err := proto.Marshal(nodebInfo) if err != nil { @@ -136,9 +99,7 @@ func TestUpdateNodebInfoMissingInventoryNameFailure(t *testing.T) { func TestUpdateNodebInfoMissingGlobalNbId(t *testing.T) { inventoryName := "name" - writerPool = nil - sdlInstanceMock := initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, sdlInstanceMock := initSdlInstanceMock(namespace) nodebInfo := &entities.NodebInfo{} nodebInfo.RanName = inventoryName data, err := proto.Marshal(nodebInfo) @@ -160,9 +121,7 @@ func TestUpdateNodebInfoMissingGlobalNbId(t *testing.T) { func TestSaveEnb(t *testing.T) { name := "name" ranName := "RAN:" + name - writerPool = nil - sdlInstanceMock := initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, sdlInstanceMock := initSdlInstanceMock(namespace) nb := entities.NodebInfo{} nb.NodeType = entities.Node_ENB nb.ConnectionStatus = 1 @@ -210,9 +169,7 @@ func TestSaveEnb(t *testing.T) { func TestSaveEnbCellIdValidationFailure(t *testing.T) { name := "name" - writerPool = nil - initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, _ := initSdlInstanceMock(namespace) nb := entities.NodebInfo{} nb.NodeType = entities.Node_ENB nb.ConnectionStatus = 1 @@ -231,9 +188,7 @@ func TestSaveEnbCellIdValidationFailure(t *testing.T) { } func TestSaveEnbInventoryNameValidationFailure(t *testing.T) { - writerPool = nil - initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, _ := initSdlInstanceMock(namespace) nb := entities.NodebInfo{} nb.NodeType = entities.Node_ENB nb.ConnectionStatus = 1 @@ -251,35 +206,9 @@ func TestSaveEnbInventoryNameValidationFailure(t *testing.T) { assert.Equal(t, "#utils.ValidateAndBuildNodeBNameKey - an empty inventory name received", rNibErr.Error()) } -func TestSaveEnbOnClosedPool(t *testing.T) { - name := "name" - writerPool = nil - sdlInstanceMock := initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() - nb := entities.NodebInfo{} - nb.NodeType = entities.Node_ENB - nb.ConnectionStatus = 1 - nb.Ip = "localhost" - nb.Port = 5656 - enb := entities.Enb{} - nb.Configuration = &entities.NodebInfo_Enb{Enb: &enb} - data, err := proto.Marshal(&nb) - if err != nil { - t.Errorf("#rNibWriter_test.TestSaveEnbOnClosedPool - Failed to marshal NodeB entity. Error: %v", err) - } - setExpected := []interface{}{name, data} - var e error - sdlInstanceMock.On("Set", setExpected).Return(e) - writerPool.Close() - nbIdentity := &entities.NbIdentity{} - assert.Panics(t, func() { w.SaveNodeb(nbIdentity, &nb) }) -} - func TestSaveGnbCellIdValidationFailure(t *testing.T) { name := "name" - writerPool = nil - initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, _ := initSdlInstanceMock(namespace) nb := entities.NodebInfo{} nb.NodeType = entities.Node_GNB nb.ConnectionStatus = 1 @@ -301,9 +230,7 @@ func TestSaveGnbCellIdValidationFailure(t *testing.T) { func TestSaveGnb(t *testing.T) { name := "name" ranName := "RAN:" + name - writerPool = nil - sdlInstanceMock := initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, sdlInstanceMock := initSdlInstanceMock(namespace) nb := entities.NodebInfo{} nb.NodeType = entities.Node_GNB nb.ConnectionStatus = 1 @@ -357,9 +284,7 @@ func TestSaveRanLoadInformationSuccess(t *testing.T) { t.Errorf("#rNibWriter_test.TestSaveRanLoadInformationSuccess - Failed to build ran load infromation key. Error: %v", validationErr) } - writerPool = nil - sdlInstanceMock := initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, sdlInstanceMock := initSdlInstanceMock(namespace) ranLoadInformation := generateRanLoadInformation() data, err := proto.Marshal(ranLoadInformation) @@ -379,9 +304,7 @@ func TestSaveRanLoadInformationSuccess(t *testing.T) { func TestSaveRanLoadInformationMarshalNilFailure(t *testing.T) { inventoryName := "name2" - writerPool = nil - initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, _ := initSdlInstanceMock(namespace) expectedErr := common.NewInternalError(errors.New("proto: Marshal called with nil")) err := w.SaveRanLoadInformation(inventoryName, nil) @@ -390,9 +313,7 @@ func TestSaveRanLoadInformationMarshalNilFailure(t *testing.T) { func TestSaveRanLoadInformationEmptyInventoryNameFailure(t *testing.T) { inventoryName := "" - writerPool = nil - initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, _ := initSdlInstanceMock(namespace) err := w.SaveRanLoadInformation(inventoryName, nil) assert.NotNil(t, err) @@ -408,9 +329,7 @@ func TestSaveRanLoadInformationSdlFailure(t *testing.T) { t.Errorf("#rNibWriter_test.TestSaveRanLoadInformationSuccess - Failed to build ran load infromation key. Error: %v", validationErr) } - writerPool = nil - sdlInstanceMock := initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, sdlInstanceMock := initSdlInstanceMock(namespace) ranLoadInformation := generateRanLoadInformation() data, err := proto.Marshal(ranLoadInformation) @@ -503,9 +422,7 @@ func generateRanLoadInformation() *entities.RanLoadInformation { } func TestSaveNilEntityFailure(t *testing.T) { - writerPool = nil - initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, _ := initSdlInstanceMock(namespace) expectedErr := common.NewInternalError(errors.New("proto: Marshal called with nil")) nbIdentity := &entities.NbIdentity{} actualErr := w.SaveNodeb(nbIdentity, nil) @@ -513,9 +430,7 @@ func TestSaveNilEntityFailure(t *testing.T) { } func TestSaveUnknownTypeEntityFailure(t *testing.T) { - writerPool = nil - initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, _ := initSdlInstanceMock(namespace) expectedErr := common.NewValidationError("#rNibWriter.saveNodeB - Unknown responding node type, entity: ip:\"localhost\" port:5656 ") nbIdentity := &entities.NbIdentity{InventoryName: "name", GlobalNbId: &entities.GlobalNbId{PlmnId: "02f829", NbId: "4a952a0a"}} nb := &entities.NodebInfo{} @@ -530,9 +445,7 @@ func TestSaveEntityFailure(t *testing.T) { plmnId := "02f829" nbId := "4a952a0a" - writerPool = nil - sdlInstanceMock := initSdlInstanceMock(namespace, 1) - w := GetRNibWriter() + w, sdlInstanceMock := initSdlInstanceMock(namespace) gnb := entities.NodebInfo{} gnb.NodeType = entities.Node_GNB data, err := proto.Marshal(&gnb) @@ -548,77 +461,120 @@ func TestSaveEntityFailure(t *testing.T) { assert.NotEmpty(t, rNibErr) } -func TestGetRNibWriterPoolNotInitializedFailure(t *testing.T) { - writerPool = nil - assert.Panics(t, func() { GetRNibWriter().SaveNodeb(nil,nil) }) -} - func TestGetRNibWriter(t *testing.T) { - writerPool = nil - initSdlInstanceMock(namespace, 1) - received := GetRNibWriter() - assert.Empty(t, received) - available, created := writerPool.Stats() - assert.Equal(t, 0, available, "number of available objects in the writerPool should be 0") - assert.Equal(t, 0, created, "number of created objects in the writerPool should be 0") - writerPool.Close() + received, _ := initSdlInstanceMock(namespace) + assert.NotEmpty(t, received) } -func TestClose(t *testing.T) { - writerPool = nil - instanceMock := initSdlInstanceMock(namespace, 2) - w1 := GetRNibWriter() - w2 := GetRNibWriter() - writerPool.Put(w1) - writerPool.Put(w2) - available, created := writerPool.Stats() - assert.Equal(t, 2, available, "number of available objects in the writerPool should be 2") - assert.Equal(t, 0, created, "number of created objects in the writerPool should be 0") +func TestSaveE2TInstanceSuccess(t *testing.T) { + address := "10.10.2.15:9800" + loadKey, validationErr := common.ValidateAndBuildE2TInstanceKey(address) + + if validationErr != nil { + t.Errorf("#rNibWriter_test.TestSaveE2TInstanceSuccess - Failed to build E2T Instance key. Error: %v", validationErr) + } + + w, sdlInstanceMock := initSdlInstanceMock(namespace) + + e2tInstance := generateE2tInstance(address) + data, err := json.Marshal(e2tInstance) + + if err != nil { + t.Errorf("#rNibWriter_test.TestSaveE2TInstanceSuccess - Failed to marshal E2tInstance entity. Error: %v", err) + } + var e error - instanceMock.On("Close").Return(e) - Close() - available, created = writerPool.Stats() - assert.Equal(t, 0, available, "number of available objects in the writerPool should be 0") + var setExpected []interface{} + setExpected = append(setExpected, loadKey, data) + sdlInstanceMock.On("Set", []interface{}{setExpected}).Return(e) + + rNibErr := w.SaveE2TInstance(e2tInstance) + assert.Nil(t, rNibErr) } -func TestCloseOnClosedPoolFailure(t *testing.T) { - writerPool = nil - instanceMock := initSdlInstanceMock(namespace, 1) - w1 := GetRNibWriter() - writerPool.Put(w1) - available, created := writerPool.Stats() - assert.Equal(t, 1, available, "number of available objects in the writerPool should be 1") - assert.Equal(t, 0, created, "number of created objects in the writerPool should be 0") - var e error - instanceMock.On("Close").Return(e) - Close() - assert.Panics(t, func() { Close() }) +func TestSaveE2TInstanceNullE2tInstanceFailure(t *testing.T) { + w, _ := initSdlInstanceMock(namespace) + var address string + e2tInstance := entities.NewE2TInstance(address) + err := w.SaveE2TInstance(e2tInstance) + assert.NotNil(t, err) + assert.IsType(t, &common.ValidationError{}, err) } -func TestCloseFailure(t *testing.T) { - writerPool = nil - instanceMock := initSdlInstanceMock(namespace, 2) - w1 := GetRNibWriter() - writerPool.Put(w1) - available, created := writerPool.Stats() - assert.Equal(t, 1, available, "number of available objects in the writerPool should be 1") - assert.Equal(t, 0, created, "number of created objects in the writerPool should be 0") - e := errors.New("expected error") - instanceMock.On("Close").Return(e) - Close() - available, created = writerPool.Stats() - assert.Equal(t, 0, available, "number of available objects in the writerPool should be 0") +func TestSaveE2TInstanceSdlFailure(t *testing.T) { + address := "10.10.2.15:9800" + loadKey, validationErr := common.ValidateAndBuildE2TInstanceKey(address) + + if validationErr != nil { + t.Errorf("#rNibWriter_test.TestSaveE2TInstanceSdlFailure - Failed to build E2T Instance key. Error: %v", validationErr) + } + + w, sdlInstanceMock := initSdlInstanceMock(namespace) + + e2tInstance := generateE2tInstance(address) + data, err := json.Marshal(e2tInstance) + + if err != nil { + t.Errorf("#rNibWriter_test.TestSaveE2TInstanceSdlFailure - Failed to marshal E2tInstance entity. Error: %v", err) + } + + expectedErr := errors.New("expected error") + var setExpected []interface{} + setExpected = append(setExpected, loadKey, data) + sdlInstanceMock.On("Set", []interface{}{setExpected}).Return(expectedErr) + + rNibErr := w.SaveE2TInstance(e2tInstance) + assert.NotNil(t, rNibErr) + assert.IsType(t, &common.InternalError{}, rNibErr) +} + +func generateE2tInstance(address string) *entities.E2TInstance { + e2tInstance := entities.NewE2TInstance(address) + + e2tInstance.AssociatedRanList = []string{"test1", "test2"} + + return e2tInstance } -func TestInit(t *testing.T) { - writerPool = nil - Init("", 1) - assert.NotNil(t, writerPool) - assert.NotNil(t, writerPool.New) - assert.NotNil(t, writerPool.Destroy) - available, created := writerPool.Stats() - assert.Equal(t, 0, available, "number of available objects in the writerPool should be 0") - assert.Equal(t, 0, created, "number of created objects in the writerPool should be 0") +func TestSaveE2TAddressesSuccess(t *testing.T) { + address := "10.10.2.15:9800" + w, sdlInstanceMock := initSdlInstanceMock(namespace) + + e2tAddresses := []string{address} + data, err := json.Marshal(e2tAddresses) + + if err != nil { + t.Errorf("#rNibWriter_test.TestSaveE2TInfoListSuccess - Failed to marshal E2TInfoList. Error: %v", err) + } + + var e error + var setExpected []interface{} + setExpected = append(setExpected, E2TAddressesKey, data) + sdlInstanceMock.On("Set", []interface{}{setExpected}).Return(e) + + rNibErr := w.SaveE2TAddresses(e2tAddresses) + assert.Nil(t, rNibErr) +} + +func TestSaveE2TAddressesSdlFailure(t *testing.T) { + address := "10.10.2.15:9800" + w, sdlInstanceMock := initSdlInstanceMock(namespace) + + e2tAddresses := []string{address} + data, err := json.Marshal(e2tAddresses) + + if err != nil { + t.Errorf("#rNibWriter_test.TestSaveE2TInfoListSdlFailure - Failed to marshal E2TInfoList. Error: %v", err) + } + + expectedErr := errors.New("expected error") + var setExpected []interface{} + setExpected = append(setExpected, E2TAddressesKey, data) + sdlInstanceMock.On("Set", []interface{}{setExpected}).Return(expectedErr) + + rNibErr := w.SaveE2TAddresses(e2tAddresses) + assert.NotNil(t, rNibErr) + assert.IsType(t, &common.InternalError{}, rNibErr) } //Integration tests diff --git a/E2Manager/resources/configuration.yaml b/E2Manager/resources/configuration.yaml index 0b73b60..f10d275 100644 --- a/E2Manager/resources/configuration.yaml +++ b/E2Manager/resources/configuration.yaml @@ -5,8 +5,12 @@ http: rmr: port: 3801 maxMsgSize: 65536 +routingManager: + baseUrl: http://10.0.2.15:12020/ric/v1/handles/v1/ notificationResponseBuffer: 100 bigRedButtonTimeoutSec: 5 maxConnectionAttempts: 3 maxRnibConnectionAttempts: 3 rnibRetryIntervalMs: 10 +keepAliveResponseTimeoutMs: 1500 +keepAliveDelayMs: 500 diff --git a/E2Manager/rmrCgo/rmrCgoApi.go b/E2Manager/rmrCgo/rmrCgoApi.go index d7d0870..f65d10d 100644 --- a/E2Manager/rmrCgo/rmrCgoApi.go +++ b/E2Manager/rmrCgo/rmrCgoApi.go @@ -34,7 +34,7 @@ import ( "e2mgr/logger" ) -func (*Context) Init(port string, maxMsgSize int, flags int, logger *logger.Logger) *RmrMessenger {//TODO remove pointer from interface +func (*Context) Init(port string, maxMsgSize int, flags int, logger *logger.Logger) RmrMessenger { pp := C.CString(port) defer C.free(unsafe.Pointer(pp)) logger.Debugf("#rmrCgoApi.Init - Going to initiate RMR router") @@ -54,10 +54,10 @@ func (*Context) Init(port string, maxMsgSize int, flags int, logger *logger.Logg // Each round is about 1000 attempts with a short sleep between each round. C.rmr_set_stimeout(ctx.RmrCtx, C.int(1000)) r := RmrMessenger(ctx) - return &r + return r } -func (ctx *Context) SendMsg(msg *MBuf) (*MBuf, error) { +func (ctx *Context) SendMsg(msg *MBuf, printLogs bool) (*MBuf, error) { ctx.checkContextInitialized() ctx.Logger.Debugf("#rmrCgoApi.SendMsg - Going to send message. MBuf: %v", *msg) allocatedCMBuf := ctx.getAllocatedCRmrMBuf(ctx.Logger, msg, ctx.MaxMsgSize) @@ -68,21 +68,21 @@ func (ctx *Context) SendMsg(msg *MBuf) (*MBuf, error) { return nil, errors.New(errorMessage) } - //TODO: if debug enabled - transactionId := string(*msg.XAction) - tmpTid := strings.TrimSpace(transactionId) - ctx.Logger.Infof("[E2 Manager -> RMR] #rmrCgoApi.SendMsg - Going to send message %v for transaction id: %s", *msg, tmpTid) + if printLogs { + //TODO: if debug enabled + transactionId := string(*msg.XAction) + tmpTid := strings.TrimSpace(transactionId) + ctx.Logger.Infof("[E2 Manager -> RMR] #rmrCgoApi.SendMsg - Going to send message %v for transaction id: %s", *msg, tmpTid) + } currCMBuf := C.rmr_send_msg(ctx.RmrCtx, allocatedCMBuf) state = currCMBuf.state - ctx.Logger.Debugf("#rmrCgoApi.SendMsg - The current message state: %v, message buffer:%v", state, currCMBuf) if state != RMR_OK { errorMessage := fmt.Sprintf("#rmrCgoApi.SendMsg - Failed to send message. state: %v - %s", state, states[int(state)]) return nil, errors.New(errorMessage) } - ctx.Logger.Debugf("#rmrCgoApi.SendMsg - The message has been sent successfully ") return convertToMBuf(ctx.Logger, currCMBuf), nil } @@ -102,18 +102,14 @@ func (ctx *Context) RecvMsg() (*MBuf, error) { } mbuf := convertToMBuf(ctx.Logger, currCMBuf) - transactionId := string(*mbuf.XAction) - tmpTid := strings.TrimSpace(transactionId) - ctx.Logger.Infof("[RMR -> E2 Manager] #rmrCgoApi.RecvMsg - message %v has been received for transaction id: %s", *mbuf, tmpTid) - return mbuf, nil -} -func (ctx *Context) RtsMsg(msg *MBuf) { - ctx.checkContextInitialized() - ctx.Logger.Debugf("#rmrCgoApi.RtsMsg - Going to return message to the sender") - allocatedCMBuf := C.rmr_alloc_msg(ctx.RmrCtx, C.int(ctx.MaxMsgSize)) - defer C.rmr_free_msg(allocatedCMBuf) - C.rmr_rts_msg(ctx.RmrCtx, allocatedCMBuf) + if mbuf.MType != E2_TERM_KEEP_ALIVE_RESP { + + transactionId := string(*mbuf.XAction) + tmpTid := strings.TrimSpace(transactionId) + ctx.Logger.Infof("[RMR -> E2 Manager] #rmrCgoApi.RecvMsg - message %v has been received for transaction id: %s", *mbuf, tmpTid) + } + return mbuf, nil } func (ctx *Context) IsReady() bool { diff --git a/E2Manager/rmrCgo/rmrCgoApi_test.go b/E2Manager/rmrCgo/rmrCgoApi_test.go index f675b5a..5d226a8 100644 --- a/E2Manager/rmrCgo/rmrCgoApi_test.go +++ b/E2Manager/rmrCgo/rmrCgoApi_test.go @@ -18,46 +18,36 @@ // platform project (RICP). -package rmrCgo +package rmrCgo_test import ( + "bytes" "e2mgr/logger" + "e2mgr/rmrCgo" "e2mgr/tests" - "bytes" "encoding/json" "github.com/stretchr/testify/assert" "io/ioutil" "testing" - "time" ) var ( - log *logger.Logger - msgr *RmrMessenger + log *logger.Logger + msgr rmrCgo.RmrMessenger ) -func TestLogger(t *testing.T){ - var err error - log, err = logger.InitLogger(logger.DebugLevel) - if err != nil { - t.Errorf("#rmrCgoApi_test.TestLogger - failed to initialize logger, error: %s", err) - } - data := map[string]interface{}{"messageType": 1001, "ranIp":"10.0.0.3", "ranPort": 879, "ranName":"test1"} +func TestLogger(t *testing.T) { + log := initLog(t) + data := map[string]interface{}{"messageType": 1001, "ranIp": "10.0.0.3", "ranPort": 879, "ranName": "test1"} b := new(bytes.Buffer) _ = json.NewEncoder(b).Encode(data) req := tests.GetHttpRequest() boo, _ := ioutil.ReadAll(req.Body) - log.Debugf("#rmrCgoApi_test.TestLogger - request header: %v\n; request body: %s\n", req.Header, string(boo)) + log.Debugf("#rmr_c_go_api_test.TestLogger - request header: %v\n; request body: %s\n", req.Header, string(boo)) } - func TestNewMBufSuccess(t *testing.T) { - var err error - log, err = logger.InitLogger(logger.DebugLevel) - if err != nil { - t.Errorf("#rmrCgoApi_test.TestNewMBufSuccess - failed to initialize logger, error: %s", err) - } - msg := NewMBuf(tests.MessageType, len(tests.DummyPayload),"RanName", &tests.DummyPayload, &tests.DummyXAction) + msg := rmrCgo.NewMBuf(tests.MessageType, len(tests.DummyPayload), "RanName", &tests.DummyPayload, &tests.DummyXAction) assert.NotNil(t, msg) assert.NotEmpty(t, msg.Payload) assert.NotEmpty(t, msg.XAction) @@ -66,80 +56,81 @@ func TestNewMBufSuccess(t *testing.T) { assert.Equal(t, msg.Len, len(tests.DummyPayload)) } -func TestInitFailure(t *testing.T) { - var err error - log, err = logger.InitLogger(logger.DebugLevel) - if err != nil { - t.Errorf("#rmrCgoApi_test.TestInitFailure - failed to initialize logger, error: %s", err) +/*func TestIsReadySuccess(t *testing.T) { + log := initLog(t) + + initRmr(tests.GetPort(), tests.MaxMsgSize, tests.Flags, log) + if msgr == nil || !msgr.IsReady() { + t.Errorf("#rmr_c_go_api_test.TestIsReadySuccess - The rmr router is not ready") } - go initRmr(tests.GetPort(), tests.MaxMsgSize, tests.Flags, log) - time.Sleep(time.Second) - if msgr != nil { - t.Errorf("The rmr router is ready, should be not ready") + msgr.Close() +} +func TestSendRecvMsgSuccess(t *testing.T) { + log := initLog(t) + + initRmr(tests.GetPort(), tests.MaxMsgSize, tests.Flags, log) + if msgr == nil || !msgr.IsReady() { + t.Errorf("#rmr_c_go_api_test.TestSendRecvMsgSuccess - The rmr router is not ready") + } + msg := rmrCgo.NewMBuf(1, tests.MaxMsgSize, "test 1", &tests.DummyPayload, &tests.DummyXAction) + log.Debugf("#rmr_c_go_api_test.TestSendRecvMsgSuccess - Going to send the message: %#v\n", msg) + result, err := msgr.SendMsg(msg, true) + + assert.Nil(t, err) + assert.NotNil(t, result) + + msgR, err := msgr.RecvMsg() + + assert.Nil(t, err) + assert.NotNil(t, msgR) + msgr.Close() +} + +func TestSendMsgRmrInvalidMsgNumError(t *testing.T) { + log := initLog(t) + + initRmr(tests.GetPort(), tests.MaxMsgSize, tests.Flags, log) + if msgr == nil || !msgr.IsReady() { + t.Errorf("#rmr_c_go_api_test.TestSendMsgRmrInvalidMsgNumError - The rmr router is not ready") } + + msg := rmrCgo.NewMBuf(10, tests.MaxMsgSize, "test 1", &tests.DummyPayload, &tests.DummyXAction) + log.Debugf("#rmr_c_go_api_test.TestSendMsgRmrInvalidMsgNumError - Going to send the message: %#v\n", msg) + result, err := msgr.SendMsg(msg, true) + + assert.NotNil(t, err) + assert.Nil(t, result) + + msgr.Close() } -//func TestInitSuccess(t *testing.T) { -// var err error -// log, err = logger.InitLogger(true) -// if err != nil { -// t.Errorf("#rmrCgoApi_test.TestInitSuccess - failed to initialize logger, error: %s", err) -// } -// go initRmr(tests.GetPort(), tests.MaxMsgSize, tests.Flags, log) -// time.Sleep(time.Second) -// if msgr == nil { -// t.Errorf("The rmr router is not ready, should be ready") -// } -//} - -func TestIsReadyFailure(t *testing.T) { - var err error - log, err = logger.InitLogger(logger.InfoLevel) - if err != nil { - t.Errorf("#rmrCgoApi_test.TestIsReadyFailure - failed to initialize logger, error: %s", err) +func TestSendMsgRmrInvalidPortError(t *testing.T) { + log := initLog(t) + + initRmr("tcp:"+strconv.Itoa(5555), tests.MaxMsgSize, tests.Flags, log) + if msgr == nil || !msgr.IsReady() { + t.Errorf("#rmr_c_go_api_test.TestSendMsgRmrInvalidPortError - The rmr router is not ready") } - go initRmr(tests.GetPort(), tests.MaxMsgSize, tests.Flags, log) - time.Sleep(time.Second) - assert.True(t, msgr == nil || !(*msgr).IsReady()) + msg := rmrCgo.NewMBuf(1, tests.MaxMsgSize, "test 1", &tests.DummyPayload, &tests.DummyXAction) + log.Debugf("#rmr_c_go_api_test.TestSendMsgRmrInvalidPortError - Going to send the message: %#v\n", msg) + result, err := msgr.SendMsg(msg, true) + + assert.NotNil(t, err) + assert.Nil(t, result) + + msgr.Close() } -//func TestSendRecvMsgSuccess(t *testing.T) { -// var err error -// log, err = logger.InitLogger(true) -// if err != nil { -// t.Errorf("#rmrCgoApi_test.TestSendRecvMsgSuccess - failed to initialize logger, error: %s", err) -// } -// go initRmr(tests.GetPort(), tests.MaxMsgSize, tests.Flags, log) -// time.Sleep(time.Second) -// if msgr == nil || !(*msgr).IsReady() { -// t.Errorf("#rmrCgoApi_test.TestSendRecvMsgSuccess - The rmr router is not ready") -// } -// msg := NewMBuf(1, tests.MaxMsgSize, &tests.DummyPayload, &tests.DummyXAction) -// log.Debugf("#rmrCgoApi_test.TestSendRecvMsgSuccess - Going to send the message: %#v\n", msg) -// msgR, _ := (*msgr).SendMsg(msg) -// log.Debugf("#rmrCgoApi_test.TestSendRecvMsgSuccess - The message has been sent %#v\n", msgR) -// log.Debugf("#rmrCgoApi_test.TestSendRecvMsgSuccess - The payload: %#v\n", msgR.Payload) -// msgR = (*msgr).RecvMsg() -// log.Debugf("#rmrCgoApi_test.TestSendRecvMsgSuccess - The message has been received: %#v\n", msgR) -// log.Debugf("#rmrCgoApi_test.TestSendRecvMsgSuccess - The payload: %#v\n", msgR.Payload) -// (*msgr).Close() -//} - -//func TestIsReadySuccess(t *testing.T) { -// var err error -// log, err = logger.InitLogger(true) -// if err != nil { -// t.Errorf("#rmrCgoApi_test.TestIsReadySuccess - The rmr router is not ready") -// } -// go initRmr(tests.GetPort(), tests.MaxMsgSize, tests.Flags, log) -// time.Sleep(time.Second) -// if msgr == nil || !(*msgr).IsReady() { -// t.Errorf("#rmrCgoApi_test.TestIsReadySuccess - The rmr router is not ready") -// } -//} - -func initRmr(port string, maxMsgSize int, flags int, log *logger.Logger){ - var ctx *Context +func initRmr(port string, maxMsgSize int, flags int, log *logger.Logger) { + var ctx *rmrCgo.Context msgr = ctx.Init(port, maxMsgSize, flags, log) +}*/ + +func initLog(t *testing.T) *logger.Logger { + log, err := logger.InitLogger(logger.DebugLevel) + if err != nil { + t.Errorf("#rmr_c_go_api_test.initLog - failed to initialize logger, error: %s", err) + } + return log } diff --git a/E2Manager/rmrCgo/rmrCgoTypes.go b/E2Manager/rmrCgo/rmrCgoTypes.go index 3f8b189..eff707c 100644 --- a/E2Manager/rmrCgo/rmrCgoTypes.go +++ b/E2Manager/rmrCgo/rmrCgoTypes.go @@ -74,6 +74,8 @@ const ( RAN_CONNECTED = C.RAN_CONNECTED RAN_RESTARTED = C.RAN_RESTARTED RAN_RECONFIGURED = C.RAN_RECONFIGURED + E2_TERM_KEEP_ALIVE_REQ = C.E2_TERM_KEEP_ALIVE_REQ + E2_TERM_KEEP_ALIVE_RESP = C.E2_TERM_KEEP_ALIVE_RESP ) const ( @@ -138,10 +140,9 @@ type Context struct { } type RmrMessenger interface { - Init(port string, maxMsgSize int, flags int, logger *logger.Logger) *RmrMessenger - SendMsg(msg *MBuf) (*MBuf, error) + Init(port string, maxMsgSize int, flags int, logger *logger.Logger) RmrMessenger + SendMsg(msg *MBuf, printLogs bool) (*MBuf, error) RecvMsg() (*MBuf, error) - RtsMsg(msg *MBuf) IsReady() bool Close() } diff --git a/E2Manager/rnibBuilders/node_info_builder_test.go b/E2Manager/rnibBuilders/node_info_builder_test.go deleted file mode 100644 index fb95f8a..0000000 --- a/E2Manager/rnibBuilders/node_info_builder_test.go +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright 2019 AT&T Intellectual Property -// Copyright 2019 Nokia -// -// 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. - -// This source code is part of the near-RT RIC (RAN Intelligent Controller) -// platform project (RICP). - - -package rnibBuilders - -import ( - "e2mgr/models" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "github.com/stretchr/testify/assert" - "testing" -) - -const ranName = "name" -const ranIP = "ip" -const ranPort = uint16(30000) - -func TestCreateInitialNodeInfo(t *testing.T) { - requestDetails := &models.SetupRequest{ - RanName: ranName, - RanPort:ranPort, - RanIp:ranIP, - } - nodebInfo, identity := CreateInitialNodeInfo(requestDetails, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) - assert.Equal(t, identity.InventoryName, ranName) - assert.Equal(t, nodebInfo.Ip, ranIP) - assert.Equal(t, nodebInfo.ConnectionStatus, entities.ConnectionStatus_CONNECTING) - assert.Equal(t, nodebInfo.E2ApplicationProtocol, entities.E2ApplicationProtocol_X2_SETUP_REQUEST) - assert.Equal(t, nodebInfo.Port, uint32(ranPort)) -} \ No newline at end of file diff --git a/E2Manager/router.txt b/E2Manager/router.txt index db4c6b0..8dfc5bc 100644 --- a/E2Manager/router.txt +++ b/E2Manager/router.txt @@ -20,4 +20,5 @@ rte|1200|10.0.2.15:4801 rte|1210|10.0.2.15:4801 rte|1220|10.0.2.15:4801 rte|10090|10.0.2.15:38000 +rte|1101|10.0.2.15:38000 newrt|end diff --git a/E2Manager/router_test.txt b/E2Manager/router_test.txt new file mode 100644 index 0000000..2315519 --- /dev/null +++ b/E2Manager/router_test.txt @@ -0,0 +1,3 @@ +newrt|start +rte|1|127.0.0.1:3801 +newrt|end diff --git a/E2Manager/services/rmrreceiver/rmr_receiver.go b/E2Manager/services/rmrreceiver/rmr_receiver.go index 60f3330..0a8eb8d 100644 --- a/E2Manager/services/rmrreceiver/rmr_receiver.go +++ b/E2Manager/services/rmrreceiver/rmr_receiver.go @@ -29,10 +29,10 @@ import ( type RmrReceiver struct { logger *logger.Logger nManager *notificationmanager.NotificationManager - messenger *rmrCgo.RmrMessenger + messenger rmrCgo.RmrMessenger } -func NewRmrReceiver(logger *logger.Logger, messenger *rmrCgo.RmrMessenger, nManager *notificationmanager.NotificationManager) *RmrReceiver { +func NewRmrReceiver(logger *logger.Logger, messenger rmrCgo.RmrMessenger, nManager *notificationmanager.NotificationManager) *RmrReceiver { return &RmrReceiver{ logger: logger, nManager: nManager, @@ -43,14 +43,15 @@ func NewRmrReceiver(logger *logger.Logger, messenger *rmrCgo.RmrMessenger, nMana func (r *RmrReceiver) ListenAndHandle() { for { - mbuf, err := (*r.messenger).RecvMsg() - r.logger.Debugf("#RmrReceiver.ListenAndHandle - Going to handle received message: %#v\n", mbuf) + mbuf, err := r.messenger.RecvMsg() if err != nil { - // TODO: error handling? + r.logger.Errorf("#RmrReceiver.ListenAndHandle - error: %s", err) continue } + r.logger.Debugf("#RmrReceiver.ListenAndHandle - Going to handle received message: %#v\n", mbuf) + // TODO: go routine? _ = r.nManager.HandleMessage(mbuf) } diff --git a/E2Manager/services/rmrreceiver/rmr_receiver_test.go b/E2Manager/services/rmrreceiver/rmr_receiver_test.go index c1729ce..5e766f7 100644 --- a/E2Manager/services/rmrreceiver/rmr_receiver_test.go +++ b/E2Manager/services/rmrreceiver/rmr_receiver_test.go @@ -21,20 +21,18 @@ package rmrreceiver import ( + "e2mgr/clients" "e2mgr/configuration" - "e2mgr/converters" "e2mgr/logger" "e2mgr/managers" "e2mgr/managers/notificationmanager" "e2mgr/mocks" "e2mgr/providers/rmrmsghandlerprovider" - "e2mgr/rNibWriter" "e2mgr/rmrCgo" "e2mgr/services" "e2mgr/services/rmrsender" "e2mgr/tests" "fmt" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "testing" "time" ) @@ -49,7 +47,7 @@ func TestListenAndHandle(t *testing.T) { time.Sleep(time.Microsecond * 10) } -func initRmrMessenger(log *logger.Logger) *rmrCgo.RmrMessenger { +func initRmrMessenger(log *logger.Logger) rmrCgo.RmrMessenger { rmrMessengerMock := &mocks.RmrMessengerMock{} rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock) rmrMessengerMock.On("Init", tests.GetPort(), tests.MaxMsgSize, tests.Flags, log).Return(&rmrMessenger) @@ -58,32 +56,24 @@ func initRmrMessenger(log *logger.Logger) *rmrCgo.RmrMessenger { var buf *rmrCgo.MBuf e := fmt.Errorf("test error") rmrMessengerMock.On("RecvMsg").Return(buf, e) - return &rmrMessenger + return rmrMessenger } func initRmrReceiver(logger *logger.Logger) *RmrReceiver { config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} readerMock := &mocks.RnibReaderMock{} - rnibReaderProvider := func() reader.RNibReader { - return readerMock - } writerMock := &mocks.RnibWriterMock{} - rnibWriterProvider := func() rNibWriter.RNibWriter { - return writerMock - } + httpClient := &mocks.HttpClientMock{} - rnibDataService := services.NewRnibDataService(logger, config, rnibReaderProvider, rnibWriterProvider) + rnibDataService := services.NewRnibDataService(logger, config, readerMock, writerMock) rmrMessenger := initRmrMessenger(logger) rmrSender := rmrsender.NewRmrSender(logger, rmrMessenger) ranSetupManager := managers.NewRanSetupManager(logger, rmrSender, rnibDataService) - ranReconnectionManager := managers.NewRanReconnectionManager(logger, configuration.ParseConfiguration(), rnibDataService, ranSetupManager) - ranStatusChangeManager := managers.NewRanStatusChangeManager(logger, rmrSender) - x2SetupResponseConverter := converters.NewX2SetupResponseConverter(logger) - x2SetupResponseManager := managers.NewX2SetupResponseManager(x2SetupResponseConverter) - x2SetupFailureResponseConverter := converters.NewX2SetupFailureResponseConverter(logger) - x2SetupFailureResponseManager := managers.NewX2SetupFailureResponseManager(x2SetupFailureResponseConverter) - rmrNotificationHandlerProvider := rmrmsghandlerprovider.NewNotificationHandlerProvider(logger, rnibDataService, ranReconnectionManager, ranStatusChangeManager, rmrSender, x2SetupResponseManager, x2SetupFailureResponseManager ) + e2tInstancesManager := managers.NewE2TInstancesManager(rnibDataService, logger) + routingManagerClient := clients.NewRoutingManagerClient(logger, config, httpClient) + rmrNotificationHandlerProvider := rmrmsghandlerprovider.NewNotificationHandlerProvider() + rmrNotificationHandlerProvider.Init(logger, config, rnibDataService, rmrSender, ranSetupManager, e2tInstancesManager, routingManagerClient) notificationManager := notificationmanager.NewNotificationManager(logger, rmrNotificationHandlerProvider) return NewRmrReceiver(logger, rmrMessenger, notificationManager) } diff --git a/E2Manager/services/rmrsender/rmr_sender.go b/E2Manager/services/rmrsender/rmr_sender.go index 1d832d9..10e6a42 100644 --- a/E2Manager/services/rmrsender/rmr_sender.go +++ b/E2Manager/services/rmrsender/rmr_sender.go @@ -28,10 +28,10 @@ import ( type RmrSender struct { logger *logger.Logger - messenger *rmrCgo.RmrMessenger + messenger rmrCgo.RmrMessenger } -func NewRmrSender(logger *logger.Logger, messenger *rmrCgo.RmrMessenger) *RmrSender { +func NewRmrSender(logger *logger.Logger, messenger rmrCgo.RmrMessenger) *RmrSender { return &RmrSender{ logger: logger, messenger: messenger, @@ -39,10 +39,9 @@ func NewRmrSender(logger *logger.Logger, messenger *rmrCgo.RmrMessenger) *RmrSen } func (r *RmrSender) Send(rmrMessage *models.RmrMessage) error { - transactionIdByteArr := []byte(rmrMessage.RanName) - msg := rmrCgo.NewMBuf(rmrMessage.MsgType, len(rmrMessage.Payload), rmrMessage.RanName, &rmrMessage.Payload, &transactionIdByteArr) + msg := rmrCgo.NewMBuf(rmrMessage.MsgType, len(rmrMessage.Payload), rmrMessage.RanName, &rmrMessage.Payload, &rmrMessage.XAction) - _, err := (*r.messenger).SendMsg(msg) + _, err := r.messenger.SendMsg(msg, true) if err != nil { r.logger.Errorf("#RmrSender.Send - RAN name: %s , Message type: %d - Failed sending message. Error: %v", rmrMessage.RanName, rmrMessage.MsgType, err) @@ -52,3 +51,16 @@ func (r *RmrSender) Send(rmrMessage *models.RmrMessage) error { r.logger.Infof("#RmrSender.Send - RAN name: %s , Message type: %d - Successfully sent RMR message", rmrMessage.RanName, rmrMessage.MsgType) return nil } + +func (r *RmrSender) SendWithoutLogs(rmrMessage *models.RmrMessage) error { + msg := rmrCgo.NewMBuf(rmrMessage.MsgType, len(rmrMessage.Payload), rmrMessage.RanName, &rmrMessage.Payload, &rmrMessage.XAction) + + _, err := r.messenger.SendMsg(msg, false) + + if err != nil { + r.logger.Errorf("#RmrSender.Send - RAN name: %s , Message type: %d - Failed sending message. Error: %v", rmrMessage.RanName, rmrMessage.MsgType, err) + return err + } + + return nil +} diff --git a/E2Manager/services/rmrsender/rmr_sender_test.go b/E2Manager/services/rmrsender/rmr_sender_test.go index df53959..bc45307 100644 --- a/E2Manager/services/rmrsender/rmr_sender_test.go +++ b/E2Manager/services/rmrsender/rmr_sender_test.go @@ -53,15 +53,15 @@ func TestRmrSenderSendSuccess(t *testing.T) { ranName := "test" payload := []byte("some payload") - xaction := []byte(ranName) - mbuf := rmrCgo.NewMBuf(123, len(payload), ranName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", mbuf).Return(&rmrCgo.MBuf{}, nil) - rmrMsg := models.NewRmrMessage(123, ranName, payload) + var xAction []byte + mbuf := rmrCgo.NewMBuf(123, len(payload), ranName, &payload, &xAction) + rmrMessengerMock.On("SendMsg", mbuf, true).Return(&rmrCgo.MBuf{}, nil) + rmrMsg := models.NewRmrMessage(123, ranName, payload, xAction) rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock) - rmrSender := NewRmrSender(logger, &rmrMessenger) + rmrSender := NewRmrSender(logger, rmrMessenger) err := rmrSender.Send(rmrMsg) assert.Nil(t, err) - rmrMessengerMock.AssertCalled(t, "SendMsg",mbuf) + rmrMessengerMock.AssertCalled(t, "SendMsg",mbuf, true) } @@ -70,14 +70,14 @@ func TestRmrSenderSendFailure(t *testing.T) { ranName := "test" payload := []byte("some payload") - xaction := []byte(ranName) - mbuf := rmrCgo.NewMBuf(123, len(payload), ranName, &payload, &xaction) - rmrMessengerMock.On("SendMsg", mbuf).Return(mbuf, fmt.Errorf("rmr send failure")) - rmrMsg := models.NewRmrMessage(123, ranName, payload) + var xAction []byte + mbuf := rmrCgo.NewMBuf(123, len(payload), ranName, &payload, &xAction) + rmrMessengerMock.On("SendMsg", mbuf, true).Return(mbuf, fmt.Errorf("rmr send failure")) + rmrMsg := models.NewRmrMessage(123, ranName, payload, xAction) rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock) - rmrSender := NewRmrSender(logger, &rmrMessenger) + rmrSender := NewRmrSender(logger, rmrMessenger) err := rmrSender.Send(rmrMsg) - rmrMessengerMock.AssertCalled(t, "SendMsg",mbuf) + rmrMessengerMock.AssertCalled(t, "SendMsg",mbuf, true) assert.NotNil(t, err) } diff --git a/E2Manager/services/rnib_data_service.go b/E2Manager/services/rnib_data_service.go index 38b4723..1274c53 100644 --- a/E2Manager/services/rnib_data_service.go +++ b/E2Manager/services/rnib_data_service.go @@ -24,9 +24,9 @@ import ( "e2mgr/configuration" "e2mgr/logger" "e2mgr/rNibWriter" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "net" "time" ) @@ -38,23 +38,32 @@ type RNibDataService interface { GetNodeb(ranName string) (*entities.NodebInfo, error) GetListNodebIds() ([]*entities.NbIdentity, error) PingRnib() bool + GetE2TInstance(address string) (*entities.E2TInstance, error) + GetE2TInstances(addresses []string) ([]*entities.E2TInstance, error) + GetE2TAddresses() ([]string, error) + SaveE2TInstance(e2tInstance *entities.E2TInstance) error + SaveE2TAddresses(addresses []string) error + GetE2TInstanceNoLogs(address string) (*entities.E2TInstance, error) + GetE2TInstancesNoLogs(addresses []string) ([]*entities.E2TInstance, error) + SaveE2TInstanceNoLogs(e2tInstance *entities.E2TInstance) error + GetE2TAddressesNoLogs() ([]string, error) } type rNibDataService struct { - logger *logger.Logger - rnibReaderProvider func() reader.RNibReader - rnibWriterProvider func() rNibWriter.RNibWriter - maxAttempts int - retryInterval time.Duration + logger *logger.Logger + rnibReader reader.RNibReader + rnibWriter rNibWriter.RNibWriter + maxAttempts int + retryInterval time.Duration } -func NewRnibDataService(logger *logger.Logger, config *configuration.Configuration, rnibReaderProvider func() reader.RNibReader, rnibWriterProvider func() rNibWriter.RNibWriter) *rNibDataService { +func NewRnibDataService(logger *logger.Logger, config *configuration.Configuration, rnibReader reader.RNibReader, rnibWriter rNibWriter.RNibWriter) *rNibDataService { return &rNibDataService{ - logger: logger, - rnibReaderProvider: rnibReaderProvider, - rnibWriterProvider: rnibWriterProvider, - maxAttempts: config.MaxRnibConnectionAttempts, - retryInterval: time.Duration(config.RnibRetryIntervalMs) * time.Millisecond, + logger: logger, + rnibReader: rnibReader, + rnibWriter: rnibWriter, + maxAttempts: config.MaxRnibConnectionAttempts, + retryInterval: time.Duration(config.RnibRetryIntervalMs) * time.Millisecond, } } @@ -62,7 +71,7 @@ func (w *rNibDataService) UpdateNodebInfo(nodebInfo *entities.NodebInfo) error { w.logger.Infof("#RnibDataService.UpdateNodebInfo - nodebInfo: %s", nodebInfo) err := w.retry("UpdateNodebInfo", func() (err error) { - err = w.rnibWriterProvider().UpdateNodebInfo(nodebInfo) + err = w.rnibWriter.UpdateNodebInfo(nodebInfo) return }) @@ -73,7 +82,7 @@ func (w *rNibDataService) SaveNodeb(nbIdentity *entities.NbIdentity, nb *entitie w.logger.Infof("#RnibDataService.SaveNodeb - nbIdentity: %s, nodebInfo: %s", nbIdentity, nb) err := w.retry("SaveNodeb", func() (err error) { - err = w.rnibWriterProvider().SaveNodeb(nbIdentity, nb) + err = w.rnibWriter.SaveNodeb(nbIdentity, nb) return }) @@ -84,7 +93,7 @@ func (w *rNibDataService) SaveRanLoadInformation(inventoryName string, ranLoadIn w.logger.Infof("#RnibDataService.SaveRanLoadInformation - inventoryName: %s, ranLoadInformation: %s", inventoryName, ranLoadInformation) err := w.retry("SaveRanLoadInformation", func() (err error) { - err = w.rnibWriterProvider().SaveRanLoadInformation(inventoryName, ranLoadInformation) + err = w.rnibWriter.SaveRanLoadInformation(inventoryName, ranLoadInformation) return }) @@ -97,7 +106,7 @@ func (w *rNibDataService) GetNodeb(ranName string) (*entities.NodebInfo, error) var nodeb *entities.NodebInfo = nil err := w.retry("GetNodeb", func() (err error) { - nodeb, err = w.rnibReaderProvider().GetNodeb(ranName) + nodeb, err = w.rnibReader.GetNodeb(ranName) return }) @@ -110,16 +119,121 @@ func (w *rNibDataService) GetListNodebIds() ([]*entities.NbIdentity, error) { var nodeIds []*entities.NbIdentity = nil err := w.retry("GetListNodebIds", func() (err error) { - nodeIds, err = w.rnibReaderProvider().GetListNodebIds() + nodeIds, err = w.rnibReader.GetListNodebIds() return }) return nodeIds, err } +func (w *rNibDataService) GetE2TInstance(address string) (*entities.E2TInstance, error) { + var e2tInstance *entities.E2TInstance = nil + + err := w.retry("GetE2TInstance", func() (err error) { + e2tInstance, err = w.rnibReader.GetE2TInstance(address) + return + }) + + if err == nil { + w.logger.Infof("#RnibDataService.GetE2TInstance - E2T instance address: %s, state: %s, associated RANs count: %d, keep Alive ts: %d", e2tInstance.Address, e2tInstance.State, len(e2tInstance.AssociatedRanList), e2tInstance.KeepAliveTimestamp) + } + + return e2tInstance, err +} + +func (w *rNibDataService) GetE2TInstanceNoLogs(address string) (*entities.E2TInstance, error) { + var e2tInstance *entities.E2TInstance = nil + + err := w.retry("GetE2TInstance", func() (err error) { + e2tInstance, err = w.rnibReader.GetE2TInstance(address) + return + }) + + return e2tInstance, err +} + +func (w *rNibDataService) GetE2TInstances(addresses []string) ([]*entities.E2TInstance, error) { + w.logger.Infof("#RnibDataService.GetE2TInstances - addresses: %s", addresses) + var e2tInstances []*entities.E2TInstance = nil + + err := w.retry("GetE2TInstance", func() (err error) { + e2tInstances, err = w.rnibReader.GetE2TInstances(addresses) + return + }) + + return e2tInstances, err +} + +func (w *rNibDataService) GetE2TInstancesNoLogs(addresses []string) ([]*entities.E2TInstance, error) { + + var e2tInstances []*entities.E2TInstance = nil + + err := w.retry("GetE2TInstance", func() (err error) { + e2tInstances, err = w.rnibReader.GetE2TInstances(addresses) + return + }) + + return e2tInstances, err +} + +func (w *rNibDataService) GetE2TAddresses() ([]string, error) { + + var e2tAddresses []string = nil + + err := w.retry("GetE2TAddresses", func() (err error) { + e2tAddresses, err = w.rnibReader.GetE2TAddresses() + return + }) + + if err == nil { + w.logger.Infof("#RnibDataService.GetE2TAddresses - addresses: %s", e2tAddresses) + } + + return e2tAddresses, err +} + +func (w *rNibDataService) GetE2TAddressesNoLogs() ([]string, error) { + + var e2tAddresses []string = nil + + err := w.retry("GetE2TAddresses", func() (err error) { + e2tAddresses, err = w.rnibReader.GetE2TAddresses() + return + }) + + return e2tAddresses, err +} + +func (w *rNibDataService) SaveE2TInstance(e2tInstance *entities.E2TInstance) error { + w.logger.Infof("#RnibDataService.SaveE2TInstance - E2T instance address: %s, state: %s, associated RANs count: %d, keep Alive ts: %d", e2tInstance.Address, e2tInstance.State, len(e2tInstance.AssociatedRanList), e2tInstance.KeepAliveTimestamp) + + return w.SaveE2TInstanceNoLogs(e2tInstance) +} + +func (w *rNibDataService) SaveE2TInstanceNoLogs(e2tInstance *entities.E2TInstance) error { + + err := w.retry("SaveE2TInstance", func() (err error) { + err = w.rnibWriter.SaveE2TInstance(e2tInstance) + return + }) + + return err +} + +func (w *rNibDataService) SaveE2TAddresses(addresses []string) error { + w.logger.Infof("#RnibDataService.SaveE2TAddresses - addresses: %s", addresses) + + err := w.retry("SaveE2TAddresses", func() (err error) { + err = w.rnibWriter.SaveE2TAddresses(addresses) + return + }) + + return err +} + func (w *rNibDataService) PingRnib() bool { err := w.retry("GetListNodebIds", func() (err error) { - _, err = w.rnibReaderProvider().GetListNodebIds() + _, err = w.rnibReader.GetListNodebIds() return }) @@ -147,7 +261,6 @@ func (w *rNibDataService) retry(rnibFunc string, f func() error) (err error) { } } - func isRnibConnectionError(err error) bool { internalErr, ok := err.(*common.InternalError) if !ok { diff --git a/E2Manager/services/rnib_data_service_test.go b/E2Manager/services/rnib_data_service_test.go index fb86fe8..ab67a32 100644 --- a/E2Manager/services/rnib_data_service_test.go +++ b/E2Manager/services/rnib_data_service_test.go @@ -24,11 +24,9 @@ import ( "e2mgr/configuration" "e2mgr/logger" "e2mgr/mocks" - "e2mgr/rNibWriter" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader" "github.com/stretchr/testify/assert" "net" "strings" @@ -48,16 +46,12 @@ func setupRnibDataServiceTestWithMaxAttempts(t *testing.T, maxAttempts int) (*rN config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: maxAttempts} readerMock := &mocks.RnibReaderMock{} - rnibReaderProvider := func() reader.RNibReader { - return readerMock - } + writerMock := &mocks.RnibWriterMock{} - rnibWriterProvider := func() rNibWriter.RNibWriter { - return writerMock - } - rnibDataService := NewRnibDataService(logger, config, rnibReaderProvider, rnibWriterProvider) + + rnibDataService := NewRnibDataService(logger, config, readerMock, writerMock) assert.NotNil(t, rnibDataService) return rnibDataService, readerMock, writerMock @@ -277,3 +271,44 @@ func TestPingRnibOkOtherError(t *testing.T) { // assert.True(t, strings.Contains(err.Error(),"connection failure", )) // assert.Equal(t, nodeIds, res) //} + +func TestGetE2TInstanceConnFailure(t *testing.T) { + rnibDataService, readerMock, _ := setupRnibDataServiceTest(t) + + address := "10.10.5.20:3200" + var e2tInstance *entities.E2TInstance = nil + mockErr := &common.InternalError{Err: &net.OpError{Err: fmt.Errorf("connection error")}} + readerMock.On("GetE2TInstance", address).Return(e2tInstance, mockErr) + + res, err := rnibDataService.GetE2TInstance(address) + readerMock.AssertNumberOfCalls(t, "GetE2TInstance", 3) + assert.Nil(t, res) + assert.NotNil(t, err) +} + +func TestGetE2TInstanceOkNoError(t *testing.T) { + rnibDataService, readerMock, _ := setupRnibDataServiceTest(t) + + address := "10.10.5.20:3200" + e2tInstance := &entities.E2TInstance{} + readerMock.On("GetE2TInstance", address).Return(e2tInstance, nil) + + res, err := rnibDataService.GetE2TInstance(address) + readerMock.AssertNumberOfCalls(t, "GetE2TInstance", 1) + assert.Nil(t, err) + assert.Equal(t, e2tInstance, res) +} + +func TestGetE2TInstanceOkOtherError(t *testing.T) { + rnibDataService, readerMock, _ := setupRnibDataServiceTest(t) + + address := "10.10.5.20:3200" + var e2tInstance *entities.E2TInstance = nil + mockErr := &common.InternalError{Err: fmt.Errorf("non connection error")} + readerMock.On("GetE2TInstance", address).Return(e2tInstance, mockErr) + + res, err := rnibDataService.GetE2TInstance(address) + readerMock.AssertNumberOfCalls(t, "GetE2TInstance", 1) + assert.Nil(t, res) + assert.NotNil(t, err) +} diff --git a/E2Manager/tests/dataProvider.go b/E2Manager/tests/dataProvider.go index 82df174..8095663 100644 --- a/E2Manager/tests/dataProvider.go +++ b/E2Manager/tests/dataProvider.go @@ -31,7 +31,7 @@ import ( const ( MaxMsgSize int = 4096 - Port int = 5555 + Port int = 3801 Flags int = 0 MessageType int = 1001 RanPort uint16 = 879 diff --git a/E2Manager/tests/utils.go b/E2Manager/tests/utils.go new file mode 100644 index 0000000..894f554 --- /dev/null +++ b/E2Manager/tests/utils.go @@ -0,0 +1,59 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package tests + +import ( + "e2mgr/configuration" + "e2mgr/logger" + "e2mgr/mocks" + "e2mgr/rmrCgo" + "e2mgr/services" + "e2mgr/services/rmrsender" + "testing" +) + +func InitLog(t *testing.T) *logger.Logger { + log, err := logger.InitLogger(logger.InfoLevel) + if err != nil { + t.Errorf("#test.utils.InitLog - failed to initialize logger, error: %s", err) + } + return log +} + +func InitRmrSender(rmrMessengerMock *mocks.RmrMessengerMock, log *logger.Logger) *rmrsender.RmrSender { + rmrMessenger := rmrCgo.RmrMessenger(rmrMessengerMock) + rmrMessengerMock.On("Init", GetPort(), MaxMsgSize, Flags, log).Return(&rmrMessenger) + return rmrsender.NewRmrSender(log, rmrMessenger) +} + +func InitRnibDataService(t *testing.T) services.RNibDataService{ + + logger := InitLog(t) + config := InitConfiguration() + + readerMock := &mocks.RnibReaderMock{} + writerMock := &mocks.RnibWriterMock{} + + return services.NewRnibDataService(logger, config, readerMock, writerMock) +} + +func InitConfiguration() *configuration.Configuration{ + return &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} +} + + diff --git a/Swagger/E2Manager_API.yaml b/Swagger/E2Manager_API.yaml index 685ac2d..65d5014 100644 --- a/Swagger/E2Manager_API.yaml +++ b/Swagger/E2Manager_API.yaml @@ -20,7 +20,7 @@ openapi: 3.0.0 info: title: E2 Manager Service description: E2 Manager Service APIs - version: 2.0.5 + version: 3.0.3 servers: - url: 'http://{apiRoot}/v1' variables: @@ -205,6 +205,26 @@ paths: responses: '200': description: OK + /e2t/list: + get: + tags: + - e2t + summary: Gets a list of all E2T Instances address and their associated RANs + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/E2tIdentity' + '500': + description: Internal Error + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ErrorResponse' components: schemas: SetupRequest: @@ -919,3 +939,27 @@ radioNetwork:pDCP-Overload] errorMessage: type: string description: Human readable text + E2tIdentity: + type: object + required: + - e2tAddress + - ranNames + properties: + e2tAddress: + type: string + ranNames: + items: + type: string + type: array + E2tErrorResponse: + type: object + required: + - errorCode + - errorMessage + properties: + errorCode: + type: string + description: '500 - RNIB error, 501 - internal problem' + errorMessage: + type: string + description: Human readable text \ No newline at end of file diff --git a/docs/release-notes.rst b/docs/release-notes.rst index 81c71b6..09e3399 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -20,7 +20,7 @@ Release-Notes ============= -This document provides the release notes for the Amber Release of E2Manager +This document provides the release notes for the Amber release of E2Manager .. contents:: :depth: 3 @@ -44,7 +44,7 @@ Version history Summary ------- -The Amber release of E2Manager supports The following flows: +The Amber release of E2Manager supports the following flows: - ENDC Setup - X2 Setup - ENDC Configuration Update diff --git a/tools/RoutingManagerSimulator/Dockerfile b/tools/RoutingManagerSimulator/Dockerfile new file mode 100644 index 0000000..66bff79 --- /dev/null +++ b/tools/RoutingManagerSimulator/Dockerfile @@ -0,0 +1,34 @@ +############################################################################## +# +# Copyright (c) 2019 AT&T Intellectual Property. +# +# 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. +# +############################################################################## + +FROM nexus3.o-ran-sc.org:10004/bldr-ubuntu16-c-go:2-u16.04-nng as ubuntu + +WORKDIR /opt/rmsimulator +COPY . . +ENV PATH=$PATH:/usr/local/go/bin:/usr/lib/go-1.12/bin + +RUN go build main.go + + +FROM ubuntu:16.04 +COPY --from=ubuntu /opt/rmsimulator/main /opt/rmsimulator/main +COPY --from=ubuntu /opt/rmsimulator/resources /opt/rmsimulator/resources + +WORKDIR /opt/rmsimulator +#CMD mkdir -p resources/conf exec ./xappmock +CMD exec ./main diff --git a/tools/RoutingManagerSimulator/api/swagger.yaml b/tools/RoutingManagerSimulator/api/swagger.yaml new file mode 100755 index 0000000..db343d7 --- /dev/null +++ b/tools/RoutingManagerSimulator/api/swagger.yaml @@ -0,0 +1,363 @@ +--- +swagger: "2.0" +info: + description: "This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound\ + \ API." + version: "0.4.0" + title: "Routing Manager" + license: + name: "Apache 2.0" + url: "http://www.apache.org/licenses/LICENSE-2.0.html" +host: "rtmgr" +basePath: "/ric/v1" +tags: +- name: "handle" + description: "Available handles" +- name: "health" + description: "Health of the system" +schemes: +- "http" +paths: + /health: + get: + tags: + - "health" + summary: "Retrive the health of Routing Manager" + description: "By performing a GET method on the health resource, the API caller\ + \ is able to retrieve the health of Routing Manager" + operationId: "get_health" + consumes: + - "application/json" + produces: + - "application/json" + parameters: [] + responses: + "200": + description: "The health of the system" + schema: + $ref: "#/definitions/health-status" + /handles: + get: + tags: + - "handle" + summary: "Placeholder for further usage" + description: "Placeholder for further usage." + operationId: "get_handles" + consumes: + - "application/json" + produces: + - "application/json" + parameters: [] + responses: + "200": + description: "Dummy response" + /handles/xapp-handle: + post: + tags: + - "handle" + summary: "Provide callback" + description: "By performing a POST method on the xapp-handle resource, the API\ + \ caller is able to perform a callback on Routing Manager." + operationId: "provide_xapp_handle" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - in: "body" + name: "xapp-callback-data" + description: "xApp related callback data" + required: true + schema: + $ref: "#/definitions/xapp-callback-data" + x-exportParamName: "XappCallbackData" + responses: + "201": + description: "Callback received" + "400": + description: "Invalid data" + /handles/xapp-subscription-handle: + post: + tags: + - "handle" + summary: "API for updating about new xapp subscription" + description: "By performing a POST method on the xapp-subscription-handle resource,\ + \ the API caller is able to update the Routing manager about the creation\ + \ of new subscription by an Xapp instance." + operationId: "provide_xapp_subscription_handle" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - in: "body" + name: "xapp-subscription-data" + description: "xApp related subscription data" + required: true + schema: + $ref: "#/definitions/xapp-subscription-data" + x-exportParamName: "XappSubscriptionData" + responses: + "201": + description: "Xapp Subscription data received" + "400": + description: "Invalid data" + delete: + tags: + - "handle" + summary: "API for deleting an xapp subscription" + description: "By performing the delete operation on xapp-subscription-handle\ + \ resource, the API caller will be able to update routing manager about the\ + \ deletion of an xapp's subscription" + operationId: "delete_xapp_subscription_handle" + consumes: + - "application/json" + parameters: + - in: "body" + name: "xapp-subscription-data" + description: "xApp related subscription data" + required: true + schema: + $ref: "#/definitions/xapp-subscription-data" + x-exportParamName: "XappSubscriptionData" + responses: + "200": + description: "Xapp Subscription deleted" + "204": + description: "Content not found" + /handles/xapp-subscription-handle/{subscription_id}: + put: + tags: + - "handle" + summary: "API for updating the subscriber xApp list" + description: "By performing a PUT method on a xapp-subscription-handle/{subscription_id}\ + \ resource, the API caller is able to update the Routing manager about the\ + \ list of subscriber xApps related to the subscription denoted by the {subsription_id}." + operationId: "update_xapp_subscription_handle" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - name: "subscription_id" + in: "path" + description: "Subscription ID" + required: true + type: "integer" + format: "uint16" + x-exportParamName: "SubscriptionId" + - in: "body" + name: "xapp-list" + description: "xApp list" + required: true + schema: + $ref: "#/definitions/xapp-list" + x-exportParamName: "XappList" + responses: + "201": + description: "Xapp list received" + "400": + description: "Invalid data" + /handles/v1/e2t: + post: + tags: + - "handle" + summary: "API for establishing platform routes when a new e2t instance gets\ + \ added to platform" + description: "E2T updates its FQDN to E2M during its initialisation, hence\ + \ after E2M informs routing manager about new E2T instances FQDN. At this\ + \ point Routing Mgr would establish platform routes" + operationId: "create_new_e2t_handle" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - in: "body" + name: "e2t-data" + description: "FQDN of the newly joined E2T instance" + required: true + schema: + $ref: "#/definitions/e2t-data" + x-exportParamName: "E2tData" + responses: + "201": + description: "new e2t instance is considered and platform routes are established" + "400": + description: "Invalid data" + delete: + tags: + - "handle" + summary: "API for clearing routes specific to a particular e2T instance" + description: "E2M would monitor E2T instances using its keep alive based mechanism\ + \ during this time if an E2T instance is detected to be dead, E2M would distribute\ + \ already associated ran's to other available/healthy E2T instances. Here\ + \ E2M would share E2T instance address to be removed OR which is unhealthy\ + \ and list of RAN instances to be dissociated and an association list which\ + \ contains E2T FQDN and associated RAN names" + operationId: "delete_e2t_handle" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - in: "body" + name: "e2t-data" + description: "FQDN of the newly joined E2T instance" + required: true + schema: + $ref: "#/definitions/e2t-delete-data" + x-exportParamName: "E2tData" + responses: + "201": + description: "new e2t instance is considered and platform routes are established" + "400": + description: "Invalid data" + /handles/v1/associate-ran-to-e2t: + post: + tags: + - "handle" + summary: "API for associating a ran to e2t instance" + description: "By performing a POST method on rane2tmapping, the API caller is\ + \ able to update the Routing manager about the ran to e2t mapping which would\ + \ be finally used to distribute routes to corresponding xApp and E2T instance" + operationId: "associate_ran_to_e2t_handle" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - in: "body" + name: "ran-e2t-list" + description: "ran to e2t mapping" + required: true + schema: + $ref: "#/definitions/ran-e2t-map" + x-exportParamName: "RanE2tList" + responses: + "201": + description: "e2t ran mapping recieved, platform routes" + "400": + description: "Invalid data" + /handles/v1/dissociate-ran: + post: + tags: + - "handle" + summary: "API to dissociate ran from e2t" + description: "By performing a POST method on rane2tmapping, routing manager\ + \ will dissociate ran name from e2t instance by updating or clearing routes" + operationId: "dissociate_ran" + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - in: "body" + name: "dissociate-list" + description: "list of RAN to dissociate" + required: true + schema: + $ref: "#/definitions/ran-e2t-map" + x-exportParamName: "DissociateList" + responses: + "201": + description: "ran instances disociated" + "400": + description: "Invalid data" +definitions: + health-status: + type: "object" + properties: + status: + type: "string" + enum: + - "healthy" + - "unhealthy" + example: + status: "healthy" + xapp-callback-data: + type: "object" + properties: + id: + type: "string" + event: + type: "string" + version: + type: "integer" + format: "int64" + xApps: + type: "string" + xapp-subscription-data: + type: "object" + required: + - "address" + - "port" + - "subscription_id" + properties: + address: + type: "string" + port: + type: "integer" + format: "uint16" + minimum: 0 + maximum: 65535 + subscription_id: + type: "integer" + format: "int32" + xapp-list: + type: "array" + items: + $ref: "#/definitions/xapp-element" + xapp-element: + type: "object" + required: + - "address" + - "port" + properties: + address: + type: "string" + port: + type: "integer" + format: "uint16" + minimum: 0 + maximum: 65535 + ran-e2t-map: + type: "array" + items: + $ref: "#/definitions/ran-e2t-element" + ran-e2t-element: + type: "object" + required: + - "E2TAddress" + properties: + E2TAddress: + type: "string" + ranNamelist: + $ref: "#/definitions/ranNamelist" + ranNamelist: + type: "array" + items: + type: "string" + e2t-data: + type: "object" + required: + - "E2TAddress" + properties: + E2TAddress: + type: "string" + ranNamelist: + $ref: "#/definitions/ranNamelist" + e2t-delete-data: + type: "object" + required: + - "E2TAddress" + properties: + E2TAddress: + type: "string" + ranNamelistTobeDissociated: + $ref: "#/definitions/ranNamelist" + ranAssocList: + $ref: "#/definitions/ran-e2t-map" +externalDocs: + description: "Routing Manager" + url: "http://placeholder" diff --git a/tools/RoutingManagerSimulator/configuration/configuration.go b/tools/RoutingManagerSimulator/configuration/configuration.go new file mode 100644 index 0000000..7e2cdef --- /dev/null +++ b/tools/RoutingManagerSimulator/configuration/configuration.go @@ -0,0 +1,57 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + + +package configuration + +import ( + "fmt" + "github.com/spf13/viper" +) + +type Configuration struct { + Http struct { + Port int + } + +} + +func ParseConfiguration() *Configuration{ + viper.SetConfigType("yaml") + viper.SetConfigName("configuration") + viper.AddConfigPath("RoutingManagerSimulator/resources/") + viper.AddConfigPath("./resources/") //For production + viper.AddConfigPath("../resources/") //For test under Docker + viper.AddConfigPath("../../resources/") //For test under Docker + err := viper.ReadInConfig() + if err != nil { + panic(fmt.Sprintf("#configuration.ParseConfiguration - failed to read configuration file: %s\n", err)) + } + + config := Configuration{} + config.fillHttpConfig(viper.Sub("http")) + return &config +} + +func (c *Configuration)fillHttpConfig(httpConfig *viper.Viper) { + if httpConfig == nil { + panic(fmt.Sprintf("#configuration.fillHttpConfig - failed to fill HTTP configuration: The entry 'http' not found\n")) + } + c.Http.Port = httpConfig.GetInt("port") +} diff --git a/tools/RoutingManagerSimulator/configuration/configuration_test.go b/tools/RoutingManagerSimulator/configuration/configuration_test.go new file mode 100644 index 0000000..a12f525 --- /dev/null +++ b/tools/RoutingManagerSimulator/configuration/configuration_test.go @@ -0,0 +1,76 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + + +package configuration + +import ( + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v2" + "io/ioutil" + "os" + "testing" +) + +func TestParseConfigurationSuccess(t *testing.T) { + config := ParseConfiguration() + assert.Equal(t, 12020, config.Http.Port) +} + +func TestParseConfigurationFileNotFoundFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestParseConfigurationFileNotFoundFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestParseConfigurationFileNotFoundFailure - failed to rename configuration file: %s\n", configPath) + } + }() + assert.Panics(t, func() { ParseConfiguration() }) +} + +func TestHttpConfigNotFoundFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestHttpConfigNotFoundFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestHttpConfigNotFoundFailure - failed to rename configuration file: %s\n", configPath) + } + }() + yamlMap := map[string]interface{}{} + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestHttpConfigNotFoundFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestHttpConfigNotFoundFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.fillHttpConfig - failed to fill HTTP configuration: The entry 'http' not found\n", + func() { ParseConfiguration() }) +} diff --git a/tools/RoutingManagerSimulator/go.mod b/tools/RoutingManagerSimulator/go.mod new file mode 100644 index 0000000..4ca14f1 --- /dev/null +++ b/tools/RoutingManagerSimulator/go.mod @@ -0,0 +1,13 @@ +module rmsimulator + +go 1.12 + +require ( + github.com/gorilla/mux v1.7.0 + github.com/pkg/errors v0.8.1 + github.com/spf13/viper v1.6.1 + github.com/stretchr/testify v1.4.0 + go.uber.org/atomic v1.5.0 + go.uber.org/zap v1.13.0 + gopkg.in/yaml.v2 v2.2.4 +) diff --git a/tools/RoutingManagerSimulator/go.sum b/tools/RoutingManagerSimulator/go.sum new file mode 100644 index 0000000..0d7ed5a --- /dev/null +++ b/tools/RoutingManagerSimulator/go.sum @@ -0,0 +1,174 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U= +github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.6.1 h1:VPZzIkznI1YhVMRi6vNFLHSwhnhReBfgTxIPccpfdZk= +github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/tools/RoutingManagerSimulator/go/api_handle.go b/tools/RoutingManagerSimulator/go/api_handle.go new file mode 100755 index 0000000..cb8936d --- /dev/null +++ b/tools/RoutingManagerSimulator/go/api_handle.go @@ -0,0 +1,79 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +import ( + "net/http" +) + +func AssociateRanToE2tHandle(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func CreateNewE2tHandle(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func DeleteE2tHandle(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func DeleteXappSubscriptionHandle(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func DissociateRan(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func GetHandles(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func ProvideXappHandle(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func ProvideXappSubscriptionHandle(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} + +func UpdateXappSubscriptionHandle(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} diff --git a/tools/RoutingManagerSimulator/go/api_health.go b/tools/RoutingManagerSimulator/go/api_health.go new file mode 100755 index 0000000..455f2d2 --- /dev/null +++ b/tools/RoutingManagerSimulator/go/api_health.go @@ -0,0 +1,38 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +import ( + "net/http" +) + +func GetHealth(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json; charset=UTF-8") + w.WriteHeader(http.StatusOK) +} diff --git a/tools/RoutingManagerSimulator/go/logger.go b/tools/RoutingManagerSimulator/go/logger.go new file mode 100755 index 0000000..4e0d47b --- /dev/null +++ b/tools/RoutingManagerSimulator/go/logger.go @@ -0,0 +1,64 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "log" + "net/http" + "time" +) + +func Logger(inner http.Handler, name string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() + + inner.ServeHTTP(w, r) + + body, err := ioutil.ReadAll(r.Body) + if err != nil { + log.Printf("Error reading body: %v", err) + http.Error(w, "can't read body", http.StatusBadRequest) + return + } + + buffer := new(bytes.Buffer) + _ =json.Compact(buffer, body) + + log.Printf( + "%s %s body: %s elapsed: %s", + r.Method, + r.RequestURI, + buffer, + time.Since(start), + ) + }) +} diff --git a/tools/RoutingManagerSimulator/go/model_e2t_data.go b/tools/RoutingManagerSimulator/go/model_e2t_data.go new file mode 100755 index 0000000..a939e90 --- /dev/null +++ b/tools/RoutingManagerSimulator/go/model_e2t_data.go @@ -0,0 +1,36 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +type E2tData struct { + + E2TAddress string `json:"E2TAddress"` + + RanNamelist *RanNamelist `json:"ranNamelist,omitempty"` +} diff --git a/tools/RoutingManagerSimulator/go/model_e2t_delete_data.go b/tools/RoutingManagerSimulator/go/model_e2t_delete_data.go new file mode 100755 index 0000000..88c21cc --- /dev/null +++ b/tools/RoutingManagerSimulator/go/model_e2t_delete_data.go @@ -0,0 +1,38 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +type E2tDeleteData struct { + + E2TAddress string `json:"E2TAddress"` + + RanNamelistTobeDissociated *RanNamelist `json:"ranNamelistTobeDissociated,omitempty"` + + RanAssocList *RanE2tMap `json:"ranAssocList,omitempty"` +} diff --git a/tools/RoutingManagerSimulator/go/model_health_status.go b/tools/RoutingManagerSimulator/go/model_health_status.go new file mode 100755 index 0000000..a238b06 --- /dev/null +++ b/tools/RoutingManagerSimulator/go/model_health_status.go @@ -0,0 +1,34 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +type HealthStatus struct { + + Status string `json:"status,omitempty"` +} diff --git a/tools/RoutingManagerSimulator/go/model_ran_e2t_element.go b/tools/RoutingManagerSimulator/go/model_ran_e2t_element.go new file mode 100755 index 0000000..1cf7397 --- /dev/null +++ b/tools/RoutingManagerSimulator/go/model_ran_e2t_element.go @@ -0,0 +1,36 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +type RanE2tElement struct { + + E2TAddress string `json:"E2TAddress"` + + RanNamelist *RanNamelist `json:"ranNamelist,omitempty"` +} diff --git a/tools/RoutingManagerSimulator/go/model_ran_e2t_map.go b/tools/RoutingManagerSimulator/go/model_ran_e2t_map.go new file mode 100755 index 0000000..8ed6edc --- /dev/null +++ b/tools/RoutingManagerSimulator/go/model_ran_e2t_map.go @@ -0,0 +1,32 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +type RanE2tMap struct { +} diff --git a/tools/RoutingManagerSimulator/go/model_ran_namelist.go b/tools/RoutingManagerSimulator/go/model_ran_namelist.go new file mode 100755 index 0000000..ed69175 --- /dev/null +++ b/tools/RoutingManagerSimulator/go/model_ran_namelist.go @@ -0,0 +1,32 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +type RanNamelist struct { +} diff --git a/tools/RoutingManagerSimulator/go/model_xapp_callback_data.go b/tools/RoutingManagerSimulator/go/model_xapp_callback_data.go new file mode 100755 index 0000000..1807b1e --- /dev/null +++ b/tools/RoutingManagerSimulator/go/model_xapp_callback_data.go @@ -0,0 +1,40 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +type XappCallbackData struct { + + Id string `json:"id,omitempty"` + + Event string `json:"event,omitempty"` + + Version int64 `json:"version,omitempty"` + + XApps string `json:"xApps,omitempty"` +} diff --git a/tools/RoutingManagerSimulator/go/model_xapp_element.go b/tools/RoutingManagerSimulator/go/model_xapp_element.go new file mode 100755 index 0000000..1439dec --- /dev/null +++ b/tools/RoutingManagerSimulator/go/model_xapp_element.go @@ -0,0 +1,36 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +type XappElement struct { + + Address string `json:"address"` + + Port int32 `json:"port"` +} diff --git a/tools/RoutingManagerSimulator/go/model_xapp_list.go b/tools/RoutingManagerSimulator/go/model_xapp_list.go new file mode 100755 index 0000000..f561145 --- /dev/null +++ b/tools/RoutingManagerSimulator/go/model_xapp_list.go @@ -0,0 +1,32 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +type XappList struct { +} diff --git a/tools/RoutingManagerSimulator/go/model_xapp_subscription_data.go b/tools/RoutingManagerSimulator/go/model_xapp_subscription_data.go new file mode 100755 index 0000000..b36067d --- /dev/null +++ b/tools/RoutingManagerSimulator/go/model_xapp_subscription_data.go @@ -0,0 +1,38 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +type XappSubscriptionData struct { + + Address string `json:"address"` + + Port int32 `json:"port"` + + SubscriptionId int32 `json:"subscription_id"` +} diff --git a/tools/RoutingManagerSimulator/go/routers.go b/tools/RoutingManagerSimulator/go/routers.go new file mode 100755 index 0000000..6c34230 --- /dev/null +++ b/tools/RoutingManagerSimulator/go/routers.go @@ -0,0 +1,146 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package swagger + +import ( + "fmt" + "net/http" + "strings" + + "github.com/gorilla/mux" +) + +type Route struct { + Name string + Method string + Pattern string + HandlerFunc http.HandlerFunc +} + +type Routes []Route + +func NewRouter() *mux.Router { + router := mux.NewRouter().StrictSlash(true) + for _, route := range routes { + var handler http.Handler + handler = route.HandlerFunc + handler = Logger(handler, route.Name) + + router. + Methods(route.Method). + Path(route.Pattern). + Name(route.Name). + Handler(handler) + } + + return router +} + +func Index(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello World!") +} + +var routes = Routes{ + Route{ + "Index", + "GET", + "/ric/v1/", + Index, + }, + + Route{ + "AssociateRanToE2tHandle", + strings.ToUpper("Post"), + "/ric/v1/handles/v1/associate-ran-to-e2t", + AssociateRanToE2tHandle, + }, + + Route{ + "CreateNewE2tHandle", + strings.ToUpper("Post"), + "/ric/v1/handles/v1/e2t", + CreateNewE2tHandle, + }, + + Route{ + "DeleteE2tHandle", + strings.ToUpper("Delete"), + "/ric/v1/handles/v1/e2t", + DeleteE2tHandle, + }, + + Route{ + "DeleteXappSubscriptionHandle", + strings.ToUpper("Delete"), + "/ric/v1/handles/xapp-subscription-handle", + DeleteXappSubscriptionHandle, + }, + + Route{ + "DissociateRan", + strings.ToUpper("Post"), + "/ric/v1/handles/v1/dissociate-ran", + DissociateRan, + }, + + Route{ + "GetHandles", + strings.ToUpper("Get"), + "/ric/v1/handles", + GetHandles, + }, + + Route{ + "ProvideXappHandle", + strings.ToUpper("Post"), + "/ric/v1/handles/xapp-handle", + ProvideXappHandle, + }, + + Route{ + "ProvideXappSubscriptionHandle", + strings.ToUpper("Post"), + "/ric/v1/handles/xapp-subscription-handle", + ProvideXappSubscriptionHandle, + }, + + Route{ + "UpdateXappSubscriptionHandle", + strings.ToUpper("Put"), + "/ric/v1/handles/xapp-subscription-handle/{subscription_id}", + UpdateXappSubscriptionHandle, + }, + + Route{ + "GetHealth", + strings.ToUpper("Get"), + "/ric/v1/health", + GetHealth, + }, +} diff --git a/tools/RoutingManagerSimulator/main.go b/tools/RoutingManagerSimulator/main.go new file mode 100755 index 0000000..f9f4824 --- /dev/null +++ b/tools/RoutingManagerSimulator/main.go @@ -0,0 +1,49 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + + +/* + * Routing Manager + * + * This is the Swagger/OpenAPI 2.0 definition of Routing Manager's Northbound API. + * + * API version: 0.4.0 + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ + +package main + +import ( + "fmt" + "log" + "net/http" + "rmsimulator/configuration" + "rmsimulator/go" +) + +func main() { + config := configuration.ParseConfiguration() + port := config.Http.Port + + log.Printf("Server started on port %d", port) + + router := swagger.NewRouter() + + log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), router)) +} diff --git a/tools/RoutingManagerSimulator/resources/configuration.yaml b/tools/RoutingManagerSimulator/resources/configuration.yaml new file mode 100644 index 0000000..e6fb1c2 --- /dev/null +++ b/tools/RoutingManagerSimulator/resources/configuration.yaml @@ -0,0 +1,2 @@ +http: + port: 12020 diff --git a/tools/xapp_mock/configuration.json b/tools/xapp_mock/configuration.json deleted file mode 100644 index 9df43a1..0000000 --- a/tools/xapp_mock/configuration.json +++ /dev/null @@ -1,4 +0,0 @@ -[ - {“id”: “RIC_X2_SETUP_REQ” , “rmrMessageType”: 10060, “transactionId”: “e2e$”, “payloadHeader”: “$ranIp|$ranPort|$ranName|#packedPayload|”, “packedPayload”: "3137322e31372e302e357c353537377c74657374327c34367c0006002a000002001500080013302300fffff000140017000001f700133023fffff0000000133023000000000001" }, - {“id”: “RIC_ENB_CONF_UPDATE_ACK_positive” , “rmrMessageType”: 10081, “transactionId”: “e2e$”, “payloadHeader”: “$ranIp|$ranPort|$ranName|#packedPayload|”, “packedPayload”: "2025000a00000100f70003000000" } -] diff --git a/tools/xapp_mock/main/xapp_mock.go b/tools/xapp_mock/main/xapp_mock.go deleted file mode 100644 index fd259f5..0000000 --- a/tools/xapp_mock/main/xapp_mock.go +++ /dev/null @@ -1,112 +0,0 @@ -// -// Copyright 2019 AT&T Intellectual Property -// Copyright 2019 Nokia -// -// 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. - -// This source code is part of the near-RT RIC (RAN Intelligent Controller) -// platform project (RICP). - -package main - -import ( - "../frontend" - "../rmr" - "../sender" - "flag" - "fmt" - "github.com/pkg/errors" - "log" - "os" - "strconv" -) - -const ( - ENV_RMR_PORT = "RMR_PORT" - RMR_PORT_DEFAULT = 5001 -) - -var rmrService *rmr.Service - -func main() { - var rmrContext *rmr.Context - - var rmrConfig rmr.Config = rmr.Config{Port: RMR_PORT_DEFAULT, MaxMsgSize: rmr.RMR_MAX_MSG_SIZE, MaxRetries: 3, Flags: 0} - if port, err := strconv.ParseUint(os.Getenv(ENV_RMR_PORT), 10, 16); err == nil { - rmrConfig.Port = int(port) - } else { - log.Printf("%s: %s, using default (%d).", ENV_RMR_PORT, err,RMR_PORT_DEFAULT) - } - rmrService = rmr.NewService(rmrConfig, rmrContext) - - /* Load configuration file*/ - err := frontend.ProcessConfigurationFile("resources","conf", ".json", - func(data []byte) error { - return frontend.JsonCommandsDecoder(data,jsonCommandsDecoderCB) - }) - if err != nil { - log.Fatalf("processing Error: %s", err) - } - - log.Print("xapp_mock is up and running.") - - cmd:= flag.Arg(0) /*first remaining argument after flags have been processed*/ - if err := frontend.JsonCommandDecoder([]byte(cmd),jsonCommandDecoderCB); err != nil { - log.Printf("command processing Error: %s", err) - } - - rmrService.CloseContext() - - log.Print("xapp_mock is down.") -} - - -// TODO: move callbacks to Dispatcher. -func jsonCommandsDecoderCB(command *frontend.JsonCommand) error { - if len(command.Id) == 0{ - return errors.New(fmt.Sprintf("invalid command, no Id")) - } - frontend.Configuration[command.Id] = command - if rmrMsgId, err := rmr.MessageIdToUint(command.WaitForRmrMessageType); err != nil { - return errors.New(fmt.Sprintf("invalid rmr message id: %s",command.WaitForRmrMessageType)) - } else { - frontend.WaitedForRmrMessageType[int(rmrMsgId)] = command - } - return nil -} - -// TODO: merge command with configuration -func jsonCommandDecoderCB(command *frontend.JsonCommand) error { - if len(command.Id) == 0{ - return errors.New(fmt.Sprintf("invalid command, no Id")) - } - switch command.Action { - case frontend.SendRmrMessage: - if err := sender.SendJsonRmrMessage(*command, nil, rmrService); err != nil { - return err - } - if len(command.WaitForRmrMessageType) > 0 { - rmrService.ListenAndHandle() //TODO: handle error - } - case frontend.ReceiveRmrMessage: - if rmrMsgId, err := rmr.MessageIdToUint(command.RmrMessageType); err != nil { - return errors.New(fmt.Sprintf("invalid rmr message id: %s",command.WaitForRmrMessageType)) - } else { - frontend.WaitedForRmrMessageType[int(rmrMsgId)] = command - } - rmrService.ListenAndHandle() //TODO: handle error - default: - return errors.New(fmt.Sprintf("invalid command action %s", command.Action)) - } - return nil -} \ No newline at end of file diff --git a/tools/xapp_mock/resources/router.txt b/tools/xapp_mock/resources/router.txt deleted file mode 100644 index 1d3fea3..0000000 --- a/tools/xapp_mock/resources/router.txt +++ /dev/null @@ -1,4 +0,0 @@ -newrt|start -rte|1001|10.0.2.15:38000 -rte|2002|10.0.2.15:3801 -newrt|end diff --git a/tools/xapp_mock/Dockerfile b/tools/xappmock/Dockerfile similarity index 68% rename from tools/xapp_mock/Dockerfile rename to tools/xappmock/Dockerfile index 4e08703..38db680 100644 --- a/tools/xapp_mock/Dockerfile +++ b/tools/xappmock/Dockerfile @@ -20,30 +20,29 @@ # platform project (RICP). # -FROM nexus3.o-ran-sc.org:10004/bldr-ubuntu16-c-go:1-u16.04-nng1.1.1 as ubuntu +FROM nexus3.o-ran-sc.org:10004/bldr-ubuntu16-c-go:2-u16.04-nng as ubuntu -WORKDIR /opt/xapp_mock +WORKDIR /opt/xappmock COPY . . ENV PATH=$PATH:/usr/local/go/bin:/usr/lib/go-1.12/bin # Install RMr library and dev files -RUN wget --content-disposition https://packagecloud.io/o-ran-sc/master/packages/debian/stretch/rmr_1.3.0_amd64.deb/download.deb -RUN dpkg -i rmr_1.3.0_amd64.deb -RUN wget --content-disposition https://packagecloud.io/o-ran-sc/master/packages/debian/stretch/rmr-dev_1.3.0_amd64.deb/download.deb -RUN dpkg -i rmr-dev_1.3.0_amd64.deb +RUN wget --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr_1.10.0_amd64.deb/download.deb +RUN dpkg -i rmr_1.10.0_amd64.deb +RUN wget --content-disposition https://packagecloud.io/o-ran-sc/staging/packages/debian/stretch/rmr-dev_1.10.0_amd64.deb/download.deb +RUN dpkg -i rmr-dev_1.10.0_amd64.deb -RUN go get github.com/pkg/errors -RUN go build main/xapp_mock.go +RUN go build main/xappmock.go FROM ubuntu:16.04 -COPY --from=ubuntu /opt/xapp_mock/xapp_mock /opt/xapp_mock/xapp_mock -COPY --from=ubuntu /opt/xapp_mock/resources /opt/xapp_mock/resources +COPY --from=ubuntu /opt/xappmock/xappmock /opt/xappmock/xappmock +COPY --from=ubuntu /opt/xappmock/resources /opt/xappmock/resources COPY --from=ubuntu /usr/local/lib/librmr_nng.so.1 /usr/local/lib/librmr_nng.so.1 COPY --from=ubuntu /usr/local/lib/libnng.so.1 /usr/local/lib/libnng.so.1 -WORKDIR /opt/xapp_mock +WORKDIR /opt/xappmock ENV LD_LIBRARY_PATH=/usr/local/lib ENV RMR_SEED_RT=resources/router.txt ENV RMR_PORT=5001 -#CMD mkdir -p resources/conf exec ./xapp_mock +#CMD mkdir -p resources/conf exec ./xappmock CMD mkdir -p resources/conf && exec /bin/bash diff --git a/tools/xappmock/dispatcher/dispatcher.go b/tools/xappmock/dispatcher/dispatcher.go new file mode 100644 index 0000000..6e00592 --- /dev/null +++ b/tools/xappmock/dispatcher/dispatcher.go @@ -0,0 +1,384 @@ +package dispatcher + +import ( + "context" + "fmt" + "github.com/pkg/errors" + "reflect" + "sync" + "time" + "xappmock/enums" + "xappmock/logger" + "xappmock/models" + "xappmock/rmr" + "xappmock/sender" +) + +// Id -> Command +var configuration = make(map[string]*models.JsonCommand) + +// Rmr Message Id -> Command +var waitForRmrMessageType = make(map[int]*models.JsonCommand) + +func addRmrMessageToWaitFor(rmrMessageToWaitFor string, command models.JsonCommand) error { + rmrMsgId, err := rmr.MessageIdToUint(rmrMessageToWaitFor) + + if err != nil { + return errors.New(fmt.Sprintf("invalid rmr message id: %s", rmrMessageToWaitFor)) + } + + waitForRmrMessageType[int(rmrMsgId)] = &command + return nil +} + +type Dispatcher struct { + rmrService *rmr.Service + processResult models.ProcessResult + logger *logger.Logger + jsonSender *sender.JsonSender +} + +func (d *Dispatcher) GetProcessResult() models.ProcessResult { + return d.processResult +} + +func New(logger *logger.Logger, rmrService *rmr.Service, jsonSender *sender.JsonSender) *Dispatcher { + return &Dispatcher{ + rmrService: rmrService, + logger: logger, + jsonSender: jsonSender, + } +} + +func (d *Dispatcher) JsonCommandsDecoderCB(cmd models.JsonCommand) error { + if len(cmd.Id) == 0 { + return errors.New(fmt.Sprintf("invalid cmd, no id")) + } + configuration[cmd.Id] = &cmd + return nil + + // if len(cmd.ReceiveCommandId) == 0 { + // return nil + // } + // + // return addRmrMessageToWaitFor(cmd.ReceiveCommandId, cmd) +} + +func (d *Dispatcher) sendNoRepeat(command models.JsonCommand) error { + + if enums.CommandAction(command.Action) == enums.SendRmrMessage && d.processResult.StartTime == nil { + now := time.Now() + d.processResult.StartTime = &now + } + + err := d.jsonSender.SendJsonRmrMessage(command, nil, d.rmrService) + + if err != nil { + d.logger.Errorf("#Dispatcher.sendNoRepeat - error sending rmr message: %s", err) + d.processResult.Err = err + d.processResult.Stats.SentErrorCount.Inc() + return err + } + + d.processResult.Stats.SentCount.Inc() + return nil +} + +func (d *Dispatcher) sendWithRepeat(ctx context.Context, command models.JsonCommand) { + + if enums.CommandAction(command.Action) == enums.SendRmrMessage && d.processResult.StartTime == nil { + now := time.Now() + d.processResult.StartTime = &now + } + + for repeatCount := command.RepeatCount; repeatCount > 0; repeatCount-- { + + select { + case <-ctx.Done(): + return + default: + } + + err := d.jsonSender.SendJsonRmrMessage(command, nil, d.rmrService) + + if err != nil { + d.logger.Errorf("#Dispatcher.sendWithRepeat - error sending rmr message: %s", err) + d.processResult.Stats.SentErrorCount.Inc() + continue + } + + d.processResult.Stats.SentCount.Inc() + time.Sleep(time.Duration(command.RepeatDelayInMs) * time.Millisecond) + } +} + +func getReceiveRmrMessageType(receiveCommandId string) (string, error) { + command, ok := configuration[receiveCommandId] + + if !ok { + return "", errors.New(fmt.Sprintf("invalid receive command id: %s", receiveCommandId)) + } + + if len(command.RmrMessageType) == 0 { + return "", errors.New(fmt.Sprintf("missing RmrMessageType for command id: %s", receiveCommandId)) + } + + return command.RmrMessageType, nil +} + +func (d *Dispatcher) sendHandler(ctx context.Context, sendAndReceiveWg *sync.WaitGroup, command models.JsonCommand) { + + defer sendAndReceiveWg.Done() + var listenAndHandleWg sync.WaitGroup + + if len(command.ReceiveCommandId) > 0 { + rmrMessageToWaitFor, err := getReceiveRmrMessageType(command.ReceiveCommandId) + + if err != nil { + d.processResult.Err = err + return + } + + err = addRmrMessageToWaitFor(rmrMessageToWaitFor, command) + + if err != nil { + d.processResult.Err = err + return + } + + listenAndHandleWg.Add(1) + go d.listenAndHandle(ctx, &listenAndHandleWg, command) + } + + if command.RepeatCount == 0 { + err := d.sendNoRepeat(command) + + if err != nil { + return + } + + } else { + d.sendWithRepeat(ctx, command) + } + + if len(command.ReceiveCommandId) > 0 { + listenAndHandleWg.Wait() + } +} + +func (d *Dispatcher) receiveHandler(ctx context.Context, sendAndReceiveWg *sync.WaitGroup, command models.JsonCommand) { + + defer sendAndReceiveWg.Done() + + err := addRmrMessageToWaitFor(command.RmrMessageType, command) + + if err != nil { + d.processResult.Err = err + return + } + + var listenAndHandleWg sync.WaitGroup + listenAndHandleWg.Add(1) // this is due to the usage of listenAndHandle as a goroutine in the sender case + d.listenAndHandle(ctx, &listenAndHandleWg, command) +} + +func getMergedCommand(cmd *models.JsonCommand) (models.JsonCommand, error) { + var command models.JsonCommand + if len(cmd.Id) == 0 { + return command, errors.New(fmt.Sprintf("invalid command, no id")) + } + + command = *cmd + + conf, ok := configuration[cmd.Id] + + if ok { + command = *conf + mergeConfigurationAndCommand(&command, cmd) + } + + return command, nil +} + +func (d *Dispatcher) ProcessJsonCommand(ctx context.Context, cmd *models.JsonCommand) { + + command, err := getMergedCommand(cmd) + + if err != nil { + d.processResult.Err = err + return + } + + var sendAndReceiveWg sync.WaitGroup + + commandAction := enums.CommandAction(command.Action) + + switch commandAction { + + case enums.SendRmrMessage: + sendAndReceiveWg.Add(1) + go d.sendHandler(ctx, &sendAndReceiveWg, command) + case enums.ReceiveRmrMessage: + sendAndReceiveWg.Add(1) + go d.receiveHandler(ctx, &sendAndReceiveWg, command) + default: + d.processResult = models.ProcessResult{Err: errors.New(fmt.Sprintf("invalid command action %s", command.Action))} + return + } + + sendAndReceiveWg.Wait() +} + +func getResponseCommand(command models.JsonCommand) (*models.JsonCommand, error) { + responseCommand, ok := configuration[command.SendCommandId] + + if !ok { + return nil, errors.New(fmt.Sprintf("invalid SendCommandId %s", command.SendCommandId)) + } + + return responseCommand, nil +} + +func (d *Dispatcher) listenAndHandleNoRepeat(ctx context.Context, command models.JsonCommand) { + for { + select { + case <-ctx.Done(): + return + default: + } + + mbuf, err := d.rmrService.RecvMessage() + + if err != nil { + d.logger.Errorf("#Dispatcher.listenAndHandleNoRepeat - error receiving message: %s", err) + d.processResult.Err = err + d.processResult.Stats.ReceivedErrorCount.Inc() + return + } + + if enums.CommandAction(command.Action) == enums.ReceiveRmrMessage && d.processResult.StartTime == nil { + now := time.Now() + d.processResult.StartTime = &now + } + + messageInfo := models.NewMessageInfo(mbuf.MType, mbuf.Meid, mbuf.Payload, mbuf.XAction) + + _, ok := waitForRmrMessageType[mbuf.MType] + + if !ok { + d.logger.Infof("#Dispatcher.listenAndHandleNoRepeat - received unexpected msg: %s", messageInfo) + d.processResult.Stats.ReceivedUnexpectedCount.Inc() + continue + } + + d.logger.Infof("#Dispatcher.listenAndHandleNoRepeat - received expected msg: %s", messageInfo) + d.processResult.Stats.ReceivedExpectedCount.Inc() + + if len(command.SendCommandId) > 0 { + responseCommand, err := getResponseCommand(command) + + if err != nil { + d.processResult.Err = err + return + } + + _ = d.sendNoRepeat(*responseCommand) + } + + return + } +} + +func (d *Dispatcher) listenAndHandleWithRepeat(ctx context.Context, command models.JsonCommand) { + + var responseCommand *models.JsonCommand + + if len(command.SendCommandId) > 0 { + var err error + responseCommand, err = getResponseCommand(command) + + if err != nil { + d.processResult.Err = err + return + } + } + + for d.processResult.Stats.ReceivedExpectedCount.Load() < int32(command.RepeatCount) { + select { + case <-ctx.Done(): + return + default: + } + + mbuf, err := d.rmrService.RecvMessage() + + if err != nil { + d.logger.Errorf("#Dispatcher.listenAndHandleWithRepeat - error receiving message: %s", err) + d.processResult.Stats.ReceivedErrorCount.Inc() + continue + } + + if enums.CommandAction(command.Action) == enums.ReceiveRmrMessage && d.processResult.StartTime == nil { + now := time.Now() + d.processResult.StartTime = &now + } + + messageInfo := models.NewMessageInfo(mbuf.MType, mbuf.Meid, mbuf.Payload, mbuf.XAction) + + _, ok := waitForRmrMessageType[mbuf.MType] + + if !ok { + d.logger.Infof("#Dispatcher.listenAndHandleWithRepeat - received unexpected msg: %s", messageInfo) + d.processResult.Stats.ReceivedUnexpectedCount.Inc() + continue + } + + d.logger.Infof("#Dispatcher.listenAndHandleWithRepeat - received expected msg: %s", messageInfo) + d.processResult.Stats.ReceivedExpectedCount.Inc() + + if responseCommand != nil { + _ = d.sendNoRepeat(*responseCommand) // TODO: goroutine? + error handling + } + } +} + +func (d *Dispatcher) listenAndHandle(ctx context.Context, listenAndHandleWg *sync.WaitGroup, command models.JsonCommand) { + + defer listenAndHandleWg.Done() + + if command.RepeatCount == 0 { + d.listenAndHandleNoRepeat(ctx, command) + return + } + + d.listenAndHandleWithRepeat(ctx, command) +} + +func mergeConfigurationAndCommand(conf *models.JsonCommand, cmd *models.JsonCommand) { + nFields := reflect.Indirect(reflect.ValueOf(cmd)).NumField() + + for i := 0; i < nFields; i++ { + if fieldValue := reflect.Indirect(reflect.ValueOf(cmd)).Field(i); fieldValue.IsValid() { + switch fieldValue.Kind() { + case reflect.String: + if fieldValue.Len() > 0 { + reflect.Indirect(reflect.ValueOf(conf)).Field(i).Set(fieldValue) + } + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + if fieldValue.Int() != 0 { + reflect.Indirect(reflect.ValueOf(conf)).Field(i).Set(fieldValue) + } + case reflect.Bool: + if fieldValue.Bool() { + reflect.Indirect(reflect.ValueOf(conf)).Field(i).Set(fieldValue) + } + case reflect.Float64, reflect.Float32: + if fieldValue.Float() != 0 { + reflect.Indirect(reflect.ValueOf(conf)).Field(i).Set(fieldValue) + } + default: + reflect.Indirect(reflect.ValueOf(conf)).Field(i).Set(fieldValue) + } + } + } +} diff --git a/tools/xappmock/enums/command_action.go b/tools/xappmock/enums/command_action.go new file mode 100644 index 0000000..7e31239 --- /dev/null +++ b/tools/xappmock/enums/command_action.go @@ -0,0 +1,25 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package enums + +type CommandAction string + +const ( + SendRmrMessage CommandAction = "send" + ReceiveRmrMessage CommandAction = "receive" +) diff --git a/tools/xapp_mock/frontend/configfile.go b/tools/xappmock/frontend/configfile.go similarity index 92% rename from tools/xapp_mock/frontend/configfile.go rename to tools/xappmock/frontend/configfile.go index 2f1923f..105d1dc 100644 --- a/tools/xapp_mock/frontend/configfile.go +++ b/tools/xappmock/frontend/configfile.go @@ -27,7 +27,7 @@ import ( "strings" ) -func ProcessConfigurationFile(resourcesFolder, inputFolder, suffix string, processor func(data []byte) error) error { +func ProcessConfigurationFile(resourcesFolder, inputFolder, suffix string, processor func(data []byte) error) error { cwd, err := os.Getwd() if err != nil { return errors.New(err.Error()) diff --git a/tools/xapp_mock/frontend/jsonDecoder.go b/tools/xappmock/frontend/jsonDecoder.go similarity index 60% rename from tools/xapp_mock/frontend/jsonDecoder.go rename to tools/xappmock/frontend/jsonDecoder.go index e5ee02a..844e63d 100644 --- a/tools/xapp_mock/frontend/jsonDecoder.go +++ b/tools/xappmock/frontend/jsonDecoder.go @@ -25,57 +25,31 @@ import ( "fmt" "github.com/pkg/errors" "io" + "xappmock/models" ) -const ( - SendRmrMessage = "send" - ReceiveRmrMessage = "receive" -) - - -type JsonCommand struct { - Id string - RmrMessageType string - TransactionId string - RanName string - RanIp string - RanPort int - PayloadHeader string - PackedPayload string - Payload string - Action string - WaitForRmrMessageType string -} - -// Id -> Command -var Configuration = make(map[string]*JsonCommand) -// Rmr Message Id -> Command -var WaitedForRmrMessageType = make(map[int]*JsonCommand) - -func JsonCommandDecoder(data []byte, processor func (*JsonCommand) error ) error { +func DecodeJsonCommand(data []byte) (*models.JsonCommand, error) { dec := json.NewDecoder(bytes.NewReader(data)) - var cmd JsonCommand + var cmd models.JsonCommand if err := dec.Decode(&cmd); err != nil && err != io.EOF { - return errors.New(err.Error()) - } - if err := processor (&cmd); err != nil { - return err + return nil, errors.New(err.Error()) } - return nil + + return &cmd, nil } -func JsonCommandsDecoder(data []byte, processor func (*JsonCommand) error ) error { +func JsonCommandsDecoder(data []byte, processor func(models.JsonCommand) error) error { dec := json.NewDecoder(bytes.NewReader(data)) for { - var commands []JsonCommand + var commands []models.JsonCommand if err := dec.Decode(&commands); err == io.EOF { break } else if err != nil { return errors.New(err.Error()) } for i, cmd := range commands { - if err := processor(&cmd); err != nil { - return errors.New(fmt.Sprintf("processing error at #%d, %s",i,err)) + if err := processor(cmd); err != nil { + return errors.New(fmt.Sprintf("processing error at #%d, %s", i, err)) } } } diff --git a/tools/xappmock/go.mod b/tools/xappmock/go.mod new file mode 100644 index 0000000..b61ff4a --- /dev/null +++ b/tools/xappmock/go.mod @@ -0,0 +1,9 @@ +module xappmock + +go 1.12 + +require ( + github.com/pkg/errors v0.8.1 + go.uber.org/atomic v1.5.0 + go.uber.org/zap v1.13.0 +) diff --git a/tools/xappmock/go.sum b/tools/xappmock/go.sum new file mode 100644 index 0000000..81ca7d4 --- /dev/null +++ b/tools/xappmock/go.sum @@ -0,0 +1,57 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c h1:IGkKhmfzcztjm6gYkykvu/NiS8kaqbCWAEWWAyf8J5U= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/tools/xappmock/logger/logger.go b/tools/xappmock/logger/logger.go new file mode 100644 index 0000000..0c168d7 --- /dev/null +++ b/tools/xappmock/logger/logger.go @@ -0,0 +1,184 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package logger + +import ( + "fmt" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" + "strings" + "time" +) + +type Logger struct { + Logger *zap.Logger +} + +// Copied from zap logger +// +// A Level is a logging priority. Higher levels are more important. +type LogLevel int8 + +const ( + // DebugLevel logs are typically voluminous, and are usually disabled in + // production. + DebugLevel LogLevel = iota - 1 + // InfoLevel is the default logging priority. + InfoLevel + // WarnLevel logs are more important than Info, but don't need individual + // human review. + WarnLevel + // ErrorLevel logs are high-priority. If an application is running smoothly, + // it shouldn't generate any error-level logs. + ErrorLevel + // DPanicLevel logs are particularly important errors. In development the + // logger panics after writing the message. + DPanicLevel + // PanicLevel logs a message, then panics. + PanicLevel + // FatalLevel logs a message, then calls os.Exit(1). + FatalLevel + + _minLevel = DebugLevel + _maxLevel = FatalLevel +) + +var logLevelTokenToLevel = map[string] LogLevel { + "debug" : DebugLevel, + "info": InfoLevel, + "warn": WarnLevel, + "error": ErrorLevel, + "dpanic": DPanicLevel, + "panic": PanicLevel, + "fatal": FatalLevel, +} + +func LogLevelTokenToLevel(level string) (LogLevel, bool) { + if level, ok := logLevelTokenToLevel[strings.TrimSpace(strings.ToLower(level))];ok { + return level, true + } + return _maxLevel+1, false +} + +func InitLogger(requested LogLevel) (*Logger, error) { + var logger *zap.Logger + var err error + switch requested { + case DebugLevel: + logger, err = initLoggerByLevel(zapcore.DebugLevel) + case InfoLevel: + logger, err = initLoggerByLevel(zapcore.InfoLevel) + case WarnLevel: + logger, err = initLoggerByLevel(zapcore.WarnLevel) + case ErrorLevel: + logger, err = initLoggerByLevel(zapcore.ErrorLevel) + case DPanicLevel: + logger, err = initLoggerByLevel(zapcore.DPanicLevel) + case PanicLevel: + logger, err = initLoggerByLevel(zapcore.PanicLevel) + case FatalLevel: + logger, err = initLoggerByLevel(zapcore.FatalLevel) + default: + err = fmt.Errorf("Invalid logging Level :%d",requested) + } + if err != nil { + return nil, err + } + return &Logger{Logger:logger}, nil + +} +func(l *Logger)Sync() error { + l.Debugf("#logger.Sync - Going to flush buffered log") + return l.Logger.Sync() +} + +func (l *Logger)Infof(formatMsg string, a ...interface{}) { + if l.InfoEnabled() { + msg := fmt.Sprintf(formatMsg, a...) + l.Logger.Info(msg, zap.Any("mdc", l.getTimeStampMdc())) + } +} + +func (l *Logger)Debugf(formatMsg string, a ...interface{}) { + if l.DebugEnabled(){ + msg := fmt.Sprintf(formatMsg, a...) + l.Logger.Debug(msg, zap.Any("mdc", l.getTimeStampMdc())) + } +} + +func (l *Logger)Errorf(formatMsg string, a ...interface{}) { + msg := fmt.Sprintf(formatMsg, a...) + l.Logger.Error(msg, zap.Any("mdc", l.getTimeStampMdc())) +} + +func (l *Logger)Warnf(formatMsg string, a ...interface{}) { + msg := fmt.Sprintf(formatMsg, a...) + l.Logger.Warn(msg, zap.Any("mdc", l.getTimeStampMdc())) +} + +func (l *Logger) getTimeStampMdc() map[string]string { + timeStr := time.Now().Format("2006-01-02 15:04:05.000") + mdc := map[string]string{"time": timeStr} + return mdc +} + +func (l *Logger)InfoEnabled()bool{ + return l.Logger.Core().Enabled(zap.InfoLevel) +} + +func (l *Logger)DebugEnabled()bool{ + return l.Logger.Core().Enabled(zap.DebugLevel) +} + +func (l *Logger)DPanicf(formatMsg string, a ...interface{}) { + msg := fmt.Sprintf(formatMsg, a...) + l.Logger.DPanic(msg, zap.Any("mdc", l.getTimeStampMdc())) +} + +func initLoggerByLevel(l zapcore.Level) (*zap.Logger, error) { + cfg := zap.Config{ + Encoding: "json", + Level: zap.NewAtomicLevelAt(l), + OutputPaths: []string{"stdout"}, + ErrorOutputPaths: []string{"stderr"}, + EncoderConfig: zapcore.EncoderConfig{ + MessageKey: "msg", + + LevelKey: "crit", + EncodeLevel: zapcore.CapitalLevelEncoder, + + TimeKey: "ts", + EncodeTime: epochMillisIntegerTimeEncoder, + + CallerKey: "id", + EncodeCaller: xAppMockCallerEncoder, + }, + } + return cfg.Build() +} + +func xAppMockCallerEncoder(caller zapcore.EntryCaller, enc zapcore.PrimitiveArrayEncoder) { + enc.AppendString("xAppMock") +} + +func epochMillisIntegerTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) { + nanos := t.UnixNano() + millis := int64(nanos) / int64(time.Millisecond) + enc.AppendInt64(millis) +} + diff --git a/tools/xappmock/main/xappmock.go b/tools/xappmock/main/xappmock.go new file mode 100644 index 0000000..8ae62f7 --- /dev/null +++ b/tools/xappmock/main/xappmock.go @@ -0,0 +1,115 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// +package main + +import ( + "context" + "flag" + "fmt" + "os" + "os/signal" + "strconv" + "time" + "xappmock/dispatcher" + "xappmock/frontend" + "xappmock/logger" + "xappmock/rmr" + "xappmock/sender" +) + +const ( + ENV_RMR_PORT = "RMR_PORT" + RMR_PORT_DEFAULT = 5001 +) + +var rmrService *rmr.Service + +func main() { + + logLevel, _ := logger.LogLevelTokenToLevel("info") + logger, err := logger.InitLogger(logLevel) + if err != nil { + fmt.Printf("#app.main - failed to initialize logger, error: %s", err) + os.Exit(1) + } + + var rmrContext *rmr.Context + var rmrConfig = rmr.Config{Port: RMR_PORT_DEFAULT, MaxMsgSize: rmr.RMR_MAX_MSG_SIZE, MaxRetries: 10, Flags: 0} + + if port, err := strconv.ParseUint(os.Getenv(ENV_RMR_PORT), 10, 16); err == nil { + rmrConfig.Port = int(port) + } else { + logger.Infof("#main - %s: %s, using default (%d).", ENV_RMR_PORT, err, RMR_PORT_DEFAULT) + } + + rmrService = rmr.NewService(rmrConfig, rmrContext) + jsonSender := sender.NewJsonSender(logger) + dispatcherDesc := dispatcher.New(logger, rmrService, jsonSender) + + /* Load configuration file*/ + err = frontend.ProcessConfigurationFile("resources", "conf", ".json", + func(data []byte) error { + return frontend.JsonCommandsDecoder(data, dispatcherDesc.JsonCommandsDecoderCB) + }) + + if err != nil { + logger.Errorf("#main - processing error: %s", err) + os.Exit(1) + } + + logger.Infof("#main - xApp Mock is up and running...") + + flag.Parse() + cmd := flag.Arg(0) /*first remaining argument after flags have been processed*/ + + command, err := frontend.DecodeJsonCommand([]byte(cmd)) + + if err != nil { + logger.Errorf("#main - command decoding error: %s", err) + rmrService.CloseContext() + logger.Infof("#main - xApp Mock is down") + return + } + + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + ctx, cancel := context.WithCancel(context.Background()) + + go func() { + oscall := <-c + logger.Infof("system call:%+v", oscall) + cancel() + rmrService.CloseContext() + }() + + dispatcherDesc.ProcessJsonCommand(ctx, command) + pr := dispatcherDesc.GetProcessResult() + + if pr.Err != nil { + logger.Errorf("#main - command processing Error: %s", pr.Err) + } + + if pr.StartTime != nil { + processElapsedTimeInMs := float64(time.Since(*pr.StartTime)) / float64(time.Millisecond) + logger.Infof("#main - processing (sending/receiving) messages took %.2f ms", processElapsedTimeInMs) + + } + logger.Infof("#main - process stats: %s", pr.Stats) + + rmrService.CloseContext() // TODO: called twice + logger.Infof("#main - xApp Mock is down") +} diff --git a/tools/xappmock/models/json_command.go b/tools/xappmock/models/json_command.go new file mode 100644 index 0000000..6ebd731 --- /dev/null +++ b/tools/xappmock/models/json_command.go @@ -0,0 +1,35 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package models + +type JsonCommand struct { + Id string + RmrMessageType string + SendCommandId string + ReceiveCommandId string + TransactionId string + RanName string + RanIp string + RanPort int + PayloadHeader string + PackedPayload string + Payload string + Action string + RepeatCount int + RepeatDelayInMs int +} diff --git a/tools/xappmock/models/message_info.go b/tools/xappmock/models/message_info.go new file mode 100644 index 0000000..0833ffa --- /dev/null +++ b/tools/xappmock/models/message_info.go @@ -0,0 +1,48 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package models + +import ( + "fmt" + "time" +) + +// TODO: message command id / source / dest + +type MessageInfo struct { + MessageTimestamp int64 `json:"messageTimestamp"` + MessageType int `json:"messageType"` + Meid string `json:"meid"` + Payload []byte `json:"payload"` + TransactionId string `json:"transactionId"` +} + +func NewMessageInfo(messageType int, meid string, payload []byte, transactionId []byte) MessageInfo { + return MessageInfo{ + MessageTimestamp: time.Now().Unix(), + MessageType: messageType, + Meid: meid, + Payload: payload, + TransactionId: string(transactionId), + } +} + +func (mi MessageInfo) String() string { + return fmt.Sprintf("message timestamp: %d | message type: %d | meid: %s | payload: %x | transaction id: %s", + mi.MessageTimestamp, mi.MessageType, mi.Meid, mi.Payload, mi.TransactionId) +} diff --git a/tools/xappmock/models/process_result.go b/tools/xappmock/models/process_result.go new file mode 100644 index 0000000..8847d2d --- /dev/null +++ b/tools/xappmock/models/process_result.go @@ -0,0 +1,43 @@ +// +// Copyright 2019 AT&T Intellectual Property +// Copyright 2019 Nokia +// +// 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. +// + +package models + +import ( + "fmt" + "go.uber.org/atomic" + "time" +) + +type ProcessStats struct { + SentCount atomic.Int32 + SentErrorCount atomic.Int32 + ReceivedExpectedCount atomic.Int32 + ReceivedUnexpectedCount atomic.Int32 + ReceivedErrorCount atomic.Int32 +} + +type ProcessResult struct { + StartTime *time.Time + Stats ProcessStats + Err error +} + +func (ps ProcessStats) String() string { + return fmt.Sprintf("sent messages: %d | send errors: %d | expected received messages: %d | unexpected received messages: %d | receive errors: %d", + ps.SentCount, ps.SentErrorCount, ps.ReceivedExpectedCount, ps.ReceivedUnexpectedCount, ps.ReceivedErrorCount) +} diff --git a/tools/xappmock/resources/conf/configuration.json b/tools/xappmock/resources/conf/configuration.json new file mode 100644 index 0000000..212a955 --- /dev/null +++ b/tools/xappmock/resources/conf/configuration.json @@ -0,0 +1,75 @@ +[ + { + "id": "X2_SETUP_REQUEST", + "rmrMessageType": "10060", + "transactionId": "e2e$", + "payloadHeader": "$ranIp|$ranPort|$ranName|#packedPayload|", + "packedPayload": "0006002a000002001500080013302300fffff000140017000001f700133023fffff0000000133023000000000001" + }, + { + "id": "X2_SETUP_RESPONSE", + "rmrMessageType": "10061", + "packedPayload": "2006002a000002001500080002f82900007ab000140017000000630002f8290007ab00102002f829000001000133" + }, + { + "id": "RIC_SUBSCRIPTION_REQUEST", + "rmrMessageType": "12010", + "transactionId": "e2e$", + "packedPayload": "00c9002b000003ea7e0005004eec0182ea6300020001ea810015000a0011121300212224264000ea6b000420000000" + }, + { + "id": "RIC_SUBSCRIPTION_RESPONSE", + "rmrMessageType": "12011", + "transactionId": "e2e$", + "packedPayload": "20c9001d000003ea7e0005004eec0182ea6300020001ea6c000700ea6d40020000" + }, + { + "id": "RIC_SUBSCRIPTION_FAILURE", + "rmrMessageType": "12012", + "transactionId": "e2e$", + "packedPayload": "40c9001f000003ea7e00050000010001ea6300020000ea6e000908ea6f400400014100" + }, + { + "id": "RIC_SUBSCRIPTION_DELETE_REQUEST", + "rmrMessageType": "12020", + "transactionId": "e2e$", + "packedPayload": "00ca0012000002ea7e0005004eec0182ea6300020001" + }, + { + "id": "RIC_SUBSCRIPTION_DELETE_RESPONSE", + "rmrMessageType": "12021", + "transactionId": "e2e$", + "packedPayload": "20ca0012000002ea7e0005004eec0182ea6300020001" + }, + { + "id": "RIC_INDICATION", + "rmrMessageType": "12050" + }, + { + "id": "RESOURCE_STATUS_REQUEST", + "rmrMessageType": "10090", + "transactionId": "e2e$", + "packedPayload": "0009003c0000080027000300000e001c00010000260004fe000000001d400d00001f4008000a0b0cabcd8000001e4001000040400100006d4001000091400100" + }, + { + "id": "RESOURCE_STATUS_RESPONSE", + "rmrMessageType": "10091", + "transactionId": "e2e$", + "packedPayload": "20090065000003002700030000000028000300004a00414050000042404b4013302302b030a2800043400700020000000a000043400700040000000a000043400700080000000a000043400700200000000a000043400700400000000a000043400700800000000a00" + }, + { + "id": "RESOURCE_STATUS_FAILURE", + "rmrMessageType": "10092", + "transactionId": "e2e$", + "packedPayload": "400900320000040027000300000e0028000300000c00054001620044401800004540130002f8290007ab500000434006000000000740" + }, + { + "id": "RESOURCE_STATUS_UPDATE", + "rmrMessageType": "10090" + }, + { + "id": "LOAD_INFORMATION", + "rmrMessageType": "10020" + } +] + diff --git a/tools/xappmock/resources/router.txt b/tools/xappmock/resources/router.txt new file mode 100644 index 0000000..015ca2e --- /dev/null +++ b/tools/xappmock/resources/router.txt @@ -0,0 +1,29 @@ +newrt|start +rte|10060|10.0.2.15:38000 +rte|10360|10.0.2.15:38000 +rte|10070|10.0.2.15:38000 +rte|10071|10.0.2.15:3801 +rte|10061|10.0.2.15:3801 +rte|10361|10.0.2.15:3801 +rte|10062|10.0.2.15:3801 +rte|10362|10.0.2.15:3801 +rte|1080|10.0.2.15:3801 +rte|10020|10.0.2.15:5557 +rte|10370|10.0.2.15:3801 +rte|10371|10.0.2.15:38000 +rte|10372|10.0.2.15:38000 +rte|10080|10.0.2.15:3801 +rte|10081|10.0.2.15:38000 +rte|10082|10.0.2.15:38000 +rte|1100|10.0.2.15:3801 +rte|1090|10.0.2.15:38000 +rte|1200|10.0.2.15:4801 +rte|1210|10.0.2.15:4801 +rte|1220|10.0.2.15:4801 +rte|10090|10.0.2.15:38000 +rte|12010|10.0.2.15:38000 +rte|12011|10.0.2.15:5555 +rte|12020|10.0.2.15:38000 +rte|10091|10.0.2.15:4801 +rte|10092|10.0.2.15:4801 +newrt|end diff --git a/tools/xapp_mock/resp b/tools/xappmock/resp similarity index 100% rename from tools/xapp_mock/resp rename to tools/xappmock/resp diff --git a/tools/xapp_mock/rmr/rmrCgoApi.go b/tools/xappmock/rmr/rmrCgoApi.go similarity index 92% rename from tools/xapp_mock/rmr/rmrCgoApi.go rename to tools/xappmock/rmr/rmrCgoApi.go index 86b2c81..489591e 100644 --- a/tools/xapp_mock/rmr/rmrCgoApi.go +++ b/tools/xappmock/rmr/rmrCgoApi.go @@ -52,7 +52,7 @@ func (*Context) Init(port string, maxMsgSize int, maxRetries int, flags int) *Me func (ctx *Context) SendMsg(msg *MBuf) (*MBuf, error) { allocatedCMBuf, err := ctx.getAllocatedCRmrMBuf(msg, ctx.MaxMsgSize) - if err != nil{ + if err != nil { return nil, err } if state := allocatedCMBuf.state; state != RMR_OK { @@ -61,14 +61,14 @@ func (ctx *Context) SendMsg(msg *MBuf) (*MBuf, error) { } defer C.rmr_free_msg(allocatedCMBuf) - for i:=0; i < ctx.MaxRetries; i++ { + for i := 0; i < ctx.MaxRetries; i++ { currCMBuf := C.rmr_send_msg(ctx.RmrCtx, allocatedCMBuf) if state := currCMBuf.state; state != RMR_OK { if state != RMR_ERR_RETRY { errorMessage := fmt.Sprintf("#rmrCgoApi.SendMsg - Failed to send message. state: %v - %s", state, states[int(state)]) return nil, errors.New(errorMessage) } - time.Sleep(100*time.Millisecond) + time.Sleep(100 * time.Millisecond) continue } return convertToMBuf(currCMBuf) @@ -78,11 +78,11 @@ func (ctx *Context) SendMsg(msg *MBuf) (*MBuf, error) { } func (ctx *Context) RecvMsg() (*MBuf, error) { - allocatedCMBuf, err :=C.rmr_alloc_msg(ctx.RmrCtx, C.int(ctx.MaxMsgSize)) - if err != nil{ + allocatedCMBuf, err := C.rmr_alloc_msg(ctx.RmrCtx, C.int(ctx.MaxMsgSize)) + if err != nil { return nil, err } - if state := allocatedCMBuf.state;state != RMR_OK { + if state := allocatedCMBuf.state; state != RMR_OK { errorMessage := fmt.Sprintf("#rmrCgoApi.SendMsg - Failed to get allocated message. state: %v - %s", state, states[int(state)]) return nil, errors.New(errorMessage) } @@ -97,7 +97,6 @@ func (ctx *Context) RecvMsg() (*MBuf, error) { return convertToMBuf(currCMBuf) } - func (ctx *Context) IsReady() bool { return int(C.rmr_ready(ctx.RmrCtx)) != 0 } diff --git a/tools/xapp_mock/rmr/rmrCgoTypes.go b/tools/xappmock/rmr/rmrCgoTypes.go similarity index 97% rename from tools/xapp_mock/rmr/rmrCgoTypes.go rename to tools/xappmock/rmr/rmrCgoTypes.go index 7307aac..3f1ce24 100644 --- a/tools/xapp_mock/rmr/rmrCgoTypes.go +++ b/tools/xappmock/rmr/rmrCgoTypes.go @@ -98,17 +98,15 @@ type MBuf struct { XAction []byte } - func (m MBuf) String() string { return fmt.Sprintf("{ MType: %d, Len: %d, Meid: %q, Xaction: %q, Payload: [%x] }", m.MType, m.Len, m.Meid, m.XAction, m.Payload) } - type Context struct { - MaxMsgSize int - MaxRetries int - Flags int - RmrCtx unsafe.Pointer + MaxMsgSize int + MaxRetries int + Flags int + RmrCtx unsafe.Pointer } type Messenger interface { diff --git a/tools/xapp_mock/rmr/rmrCgoUtils.go b/tools/xappmock/rmr/rmrCgoUtils.go similarity index 83% rename from tools/xapp_mock/rmr/rmrCgoUtils.go rename to tools/xappmock/rmr/rmrCgoUtils.go index 868b79c..d2fa040 100644 --- a/tools/xapp_mock/rmr/rmrCgoUtils.go +++ b/tools/xappmock/rmr/rmrCgoUtils.go @@ -38,9 +38,9 @@ import ( Allocates an mBuf and initialize it with the content of C.rmr_mbuf_t. The xAction field is assigned a a value without trailing spaces. */ -func convertToMBuf( m *C.rmr_mbuf_t) (*MBuf, error) { - payloadArr := C.GoBytes(unsafe.Pointer(m.payload),C.int(m.len)) - xActionArr := C.GoBytes(unsafe.Pointer(m.xaction),C.int(RMR_MAX_XACTION_LEN)) +func convertToMBuf(m *C.rmr_mbuf_t) (*MBuf, error) { + payloadArr := C.GoBytes(unsafe.Pointer(m.payload), C.int(m.len)) + xActionArr := C.GoBytes(unsafe.Pointer(m.xaction), C.int(RMR_MAX_XACTION_LEN)) // Trim padding (space and 0) xActionStr := strings.TrimRight(string(xActionArr), "\040\000") @@ -57,7 +57,7 @@ func convertToMBuf( m *C.rmr_mbuf_t) (*MBuf, error) { meidBuf := make([]byte, RMR_MAX_MEID_LEN) if meidCstr := C.rmr_get_meid(m, (*C.uchar)(unsafe.Pointer(&meidBuf[0]))); meidCstr != nil { - mbuf.Meid = strings.TrimRight(string(meidBuf), "\000") + mbuf.Meid = strings.TrimRight(string(meidBuf), "\000") } return mbuf, nil @@ -67,9 +67,9 @@ func convertToMBuf( m *C.rmr_mbuf_t) (*MBuf, error) { Allocates an C.rmr_mbuf_t and initialize it with the content of mBuf. The xAction field is padded with trailing spaces upto capacity */ -func (ctx *Context) getAllocatedCRmrMBuf( mBuf *MBuf, maxMsgSize int) (cMBuf *C.rmr_mbuf_t, rc error) { +func (ctx *Context) getAllocatedCRmrMBuf(mBuf *MBuf, maxMsgSize int) (cMBuf *C.rmr_mbuf_t, rc error) { var xActionBuf [RMR_MAX_XACTION_LEN]byte - var meidBuf[RMR_MAX_MEID_LEN]byte + var meidBuf [RMR_MAX_MEID_LEN]byte cMBuf = C.rmr_alloc_msg(ctx.RmrCtx, C.int(maxMsgSize)) cMBuf.mtype = C.int(mBuf.MType) @@ -79,13 +79,13 @@ func (ctx *Context) getAllocatedCRmrMBuf( mBuf *MBuf, maxMsgSize int) (cMBuf *C. xActionLen := len(mBuf.XAction) copy(xActionBuf[:], mBuf.XAction) - for i:= xActionLen; i < RMR_MAX_XACTION_LEN; i++{ + for i := xActionLen; i < RMR_MAX_XACTION_LEN; i++ { xActionBuf[i] = '\040' //space } // Add padding copy(meidBuf[:], mBuf.Meid) - for i:= len(mBuf.Meid); i < RMR_MAX_MEID_LEN; i++{ + for i := len(mBuf.Meid); i < RMR_MAX_MEID_LEN; i++ { meidBuf[i] = 0 } @@ -101,19 +101,19 @@ func (ctx *Context) getAllocatedCRmrMBuf( mBuf *MBuf, maxMsgSize int) (cMBuf *C. return nil, errors.New(fmt.Sprintf("#rmrCgoUtils.getAllocatedCRmrMBuf - Failed to read xAction data to allocated RMR message buffer, %s", err)) } - len := C.rmr_bytes2meid(cMBuf, (*C.uchar)(unsafe.Pointer(&meidBuf[0])), C.int(RMR_MAX_XACTION_LEN)) + len := C.rmr_bytes2meid(cMBuf, (*C.uchar)(unsafe.Pointer(&meidBuf[0])), C.int(RMR_MAX_XACTION_LEN)) if int(len) != RMR_MAX_MEID_LEN { return nil, errors.New( "#rmrCgoUtils.getAllocatedCRmrMBuf - Failed to copy meid data to allocated RMR message buffer") } - return cMBuf,nil + return cMBuf, nil } func MessageIdToUint(id string) (msgId uint64, err error) { if len(id) == 0 { msgId, err = 0, nil - } else{ + } else { msgId, err = strconv.ParseUint(id, 10, 16) } return -} \ No newline at end of file +} diff --git a/tools/xapp_mock/rmr/rmrEndPoint.go b/tools/xappmock/rmr/rmrEndPoint.go similarity index 65% rename from tools/xapp_mock/rmr/rmrEndPoint.go rename to tools/xappmock/rmr/rmrEndPoint.go index 03c0852..c8c8ae2 100644 --- a/tools/xapp_mock/rmr/rmrEndPoint.go +++ b/tools/xappmock/rmr/rmrEndPoint.go @@ -20,13 +20,12 @@ package rmr import ( - "../frontend" - "log" "strconv" ) + // RmrService holds an instance of RMR messenger as well as its configuration type Service struct { - messenger *Messenger + messenger *Messenger } // NewRmrService instantiates a new Rmr service instance @@ -36,36 +35,17 @@ func NewService(rmrConfig Config, messenger Messenger) *Service { } } -func (r *Service) SendMessage(messageType int, msg []byte, transactionId []byte) (*MBuf, error){ - log.Printf( "SendMessage (type: %d, tid: %s, msg: %v", messageType, transactionId, msg) +func (r *Service) SendMessage(messageType int, ranName string, msg []byte, transactionId []byte) (*MBuf, error) { mbuf := NewMBuf(messageType, len(msg), msg, transactionId) + mbuf.Meid = ranName return (*r.messenger).SendMsg(mbuf) } -// ListenAndHandle waits for messages coming from rmr_rcv_msg and sends it to a designated message handler -func (r *Service) ListenAndHandle() error { - for { - mbuf, err := (*r.messenger).RecvMsg() - - if err != nil { - return err - } - - if _, ok := frontend.WaitedForRmrMessageType[mbuf.MType]; ok { - log.Printf( "ListenAndHandle Expected msg: %s", mbuf) - break - } else { - log.Printf( "ListenAndHandle Unexpected msg: %s", mbuf) - } - } - return nil +func (r *Service) RecvMessage() (*MBuf, error) { + return (*r.messenger).RecvMsg() } - func (r *Service) CloseContext() { (*r.messenger).Close() } - - - diff --git a/tools/xapp_mock/sender/jsonSender.go b/tools/xappmock/sender/jsonSender.go similarity index 69% rename from tools/xapp_mock/sender/jsonSender.go rename to tools/xappmock/sender/jsonSender.go index d7d4ffb..f890add 100644 --- a/tools/xapp_mock/sender/jsonSender.go +++ b/tools/xappmock/sender/jsonSender.go @@ -20,22 +20,33 @@ Binary file (standard input) matches package sender import ( - "../frontend" - "../rmr" "fmt" "github.com/pkg/errors" - "log" + "os" "reflect" "strconv" "strings" "sync/atomic" "time" "unicode" + "xappmock/logger" + "xappmock/models" + "xappmock/rmr" ) var counter uint64 -func SendJsonRmrMessage(command frontend.JsonCommand /*the copy is modified locally*/, xAction *[]byte, r *rmr.Service) error { +type JsonSender struct { + logger *logger.Logger +} + +func NewJsonSender(logger *logger.Logger) *JsonSender { + return &JsonSender{ + logger: logger, + } +} + +func (s *JsonSender) SendJsonRmrMessage(command models.JsonCommand /*the copy is modified locally*/, xAction *[]byte, r *rmr.Service) error { var payload []byte _, err := fmt.Sscanf(command.PackedPayload, "%x", &payload) if err != nil { @@ -46,12 +57,18 @@ func SendJsonRmrMessage(command frontend.JsonCommand /*the copy is modified loca if len(command.TransactionId) == 0 { command.TransactionId = string(*xAction) } - command.PayloadHeader = expandPayloadHeader(command.PayloadHeader, &command) + command.PayloadHeader = s.expandPayloadHeader(command.PayloadHeader, &command) + s.logger.Infof("#JsonSender.SendJsonRmrMessage - command payload header: %s", command.PayloadHeader) rmrMsgId, err := rmr.MessageIdToUint(command.RmrMessageType) if err != nil { - return errors.New(fmt.Sprintf("invalid rmr message id: %s",command.WaitForRmrMessageType)) + return errors.New(fmt.Sprintf("invalid rmr message id: %s", command.RmrMessageType)) } - _, err = r.SendMessage(int(rmrMsgId), append([]byte(command.PayloadHeader), payload...), []byte(command.TransactionId)) + + msg := append([]byte(command.PayloadHeader), payload...) + messageInfo := models.NewMessageInfo(int(rmrMsgId), command.RanName, msg, []byte(command.TransactionId)) + s.logger.Infof("#JsonSender.SendJsonRmrMessage - going to send message: %s", messageInfo) + + _, err = r.SendMessage(int(rmrMsgId), command.RanName, msg, []byte(command.TransactionId)) return err } @@ -78,7 +95,7 @@ func expandTransactionId(id string) string { * Example: “payloadHeader”: “$ranIp|$ranPort|$ranName|#packedPayload|” */ -func expandPayloadHeader(header string, command *frontend.JsonCommand) string { +func (s *JsonSender) expandPayloadHeader(header string, command *models.JsonCommand) string { var name strings.Builder var expandedHeader strings.Builder @@ -88,12 +105,17 @@ func expandPayloadHeader(header string, command *frontend.JsonCommand) string { if err != nil { break } + switch ch { case '$': for { - ch, err = r.ReadByte() //on error ch == 0 + ch, err = r.ReadByte() //on error ch == 0 if unicode.IsDigit(rune(ch)) || unicode.IsLetter(rune(ch)) { - name.WriteByte(ch) + if name.Len() == 0 { + name.WriteByte(byte(unicode.ToUpper(rune(ch)))) + } else { + name.WriteByte(ch) + } } else { if fieldValue := reflect.Indirect(reflect.ValueOf(command)).FieldByName(name.String()); fieldValue.IsValid() { switch fieldValue.Kind() { @@ -106,7 +128,8 @@ func expandPayloadHeader(header string, command *frontend.JsonCommand) string { case reflect.Float64, reflect.Float32: expandedHeader.WriteString(fmt.Sprintf("%g", fieldValue.Float())) default: - log.Fatalf("invalid type for $%s, value must be a string, an int, a bool or a float", name.String()) + s.logger.Errorf("#JsonSender.expandPayloadHeader - invalid type for $%s, value must be a string, an int, a bool or a float", name.String()) + os.Exit(1) } } name.Reset() @@ -115,15 +138,20 @@ func expandPayloadHeader(header string, command *frontend.JsonCommand) string { } case '#': for { - ch, err = r.ReadByte() //on error ch == 0 + ch, err = r.ReadByte() //on error ch == 0 if unicode.IsDigit(rune(ch)) || unicode.IsLetter(rune(ch)) { - name.WriteByte(ch) + if name.Len() == 0 { + name.WriteByte(byte(unicode.ToUpper(rune(ch)))) + } else { + name.WriteByte(ch) + } } else { if fieldValue := reflect.Indirect(reflect.ValueOf(command)).FieldByName(name.String()); fieldValue.IsValid() { if fieldValue.Kind() == reflect.String { expandedHeader.WriteString(strconv.FormatInt(int64(len(fieldValue.String())), 10)) } else { - log.Fatalf("invalid type for #%s, value must be a string", name.String()) + s.logger.Errorf("#JsonSender.expandPayloadHeader - invalid type for #%s, value must be a string", name.String()) + os.Exit(1) } } name.Reset() @@ -145,5 +173,5 @@ func incAndGetCounter() uint64 { } func init() { - counter = uint64(time.Now().Second()) + counter = uint64(time.Now().Unix() - 1572000000) } -- 2.16.6