From a07b8597afc9d063a7f37a376a5bcf29ba29b557 Mon Sep 17 00:00:00 2001 From: ss412g Date: Tue, 16 Jun 2020 21:51:33 +0300 Subject: [PATCH] Add R5 content to master Change-Id: Ibfbabbcd1ec599b69f1011a337d0979e7098ad15 Signed-off-by: ss412g --- .../E2Term_Init_Message_Test.robot | 22 + .../Enable_Ric_False_Setup_Failure.robot | 50 +++ .../E2_Setup_Failure/RM_Error_Setup_Failure.robot | 60 +++ Automation/Tests/E2_Setup_Failure/__init__.robot | 24 + .../Get_E2T_Instances/get_e2t_instances.robot | 2 +- Automation/Tests/Resource/Keywords.robot | 7 + Automation/Tests/Resource/resource.robot | 4 +- Automation/Tests/Resource/scripts_variables.robot | 3 +- Automation/Tests/Scripts/cleanup_db.py | 3 +- Automation/Tests/Scripts/e2mdbscripts.py | 38 +- .../Tests/SetGeneralConfiguration/__init__.robot | 20 + .../set_general_configuration.robot | 48 ++ E2Manager/configuration/configuration.go | 130 +++++- E2Manager/configuration/configuration_test.go | 488 ++++++++++++++++++++- E2Manager/container-tag.yaml | 2 +- E2Manager/controllers/nodeb_controller.go | 22 +- E2Manager/controllers/nodeb_controller_test.go | 33 ++ .../endc_setup_failure_response_converter_test.go | 13 +- .../endc_setup_response_converter_test.go | 20 +- .../x2_setup_failure_response_converter_test.go | 26 +- .../converters/x2_setup_response_converter.go | 8 +- .../converters/x2_setup_response_converter_test.go | 52 ++- E2Manager/go.mod | 9 +- E2Manager/go.sum | 34 +- .../set_general_configuration_handler.go | 68 +++ .../set_general_configuration_handler_test.go | 102 +++++ .../e2_setup_request_notification_handler.go | 115 +++-- .../e2_setup_request_notification_handler_test.go | 233 +++++++--- .../x2_reset_request_notification_handler.go | 10 +- .../rmrmsghandlers/x2_reset_response_handler.go | 8 +- E2Manager/httpserver/http_server.go | 1 + E2Manager/httpserver/http_server_test.go | 14 + .../managers/ran_connect_status_change_manager.go | 131 ++++++ .../ran_connect_status_change_manager_test.go | 187 ++++++++ E2Manager/managers/ran_list_manager.go | 44 ++ E2Manager/mocks/nodeb_controller_mock.go | 7 + E2Manager/mocks/ran_alarm_service_mock.go | 35 ++ E2Manager/mocks/ran_list_manager_mock.go | 35 ++ E2Manager/mocks/rnibReaderMock.go | 5 + E2Manager/mocks/rnibWriterMock.go | 11 + E2Manager/models/cause.go | 79 ++++ E2Manager/models/e2_setup_request_message.go | 356 +++++++++++++-- E2Manager/models/e2_setup_response_message.go | 30 +- E2Manager/models/general_configuration_request.go | 23 + E2Manager/models/general_configuration_response.go | 41 ++ .../incoming_request_handler_provider.go | 34 +- .../incoming_request_handler_provider_test.go | 12 + E2Manager/rNibWriter/rNibWriter.go | 55 ++- E2Manager/rNibWriter/rNibWriter_test.go | 115 ++++- E2Manager/resources/configuration.yaml | 6 +- E2Manager/services/ran_alarm_service.go | 47 ++ E2Manager/services/rnib_data_service.go | 62 ++- E2Manager/services/rnib_data_service_test.go | 27 +- E2Manager/tests/dataProvider.go | 2 +- E2Manager/tests/resources/setupRequest_gnb.xml | 69 +-- 55 files changed, 2673 insertions(+), 409 deletions(-) create mode 100644 Automation/Tests/E2_Setup_Failure/Enable_Ric_False_Setup_Failure.robot create mode 100644 Automation/Tests/E2_Setup_Failure/RM_Error_Setup_Failure.robot create mode 100644 Automation/Tests/E2_Setup_Failure/__init__.robot create mode 100644 Automation/Tests/SetGeneralConfiguration/__init__.robot create mode 100644 Automation/Tests/SetGeneralConfiguration/set_general_configuration.robot create mode 100644 E2Manager/handlers/httpmsghandlers/set_general_configuration_handler.go create mode 100644 E2Manager/handlers/httpmsghandlers/set_general_configuration_handler_test.go create mode 100644 E2Manager/managers/ran_connect_status_change_manager.go create mode 100644 E2Manager/managers/ran_connect_status_change_manager_test.go create mode 100644 E2Manager/managers/ran_list_manager.go create mode 100644 E2Manager/mocks/ran_alarm_service_mock.go create mode 100644 E2Manager/mocks/ran_list_manager_mock.go create mode 100644 E2Manager/models/cause.go create mode 100644 E2Manager/models/general_configuration_request.go create mode 100644 E2Manager/models/general_configuration_response.go create mode 100644 E2Manager/services/ran_alarm_service.go diff --git a/Automation/Tests/E2Term_Initialization/E2Term_Init_Message_Test.robot b/Automation/Tests/E2Term_Initialization/E2Term_Init_Message_Test.robot index b575dd8..1351df7 100644 --- a/Automation/Tests/E2Term_Initialization/E2Term_Init_Message_Test.robot +++ b/Automation/Tests/E2Term_Initialization/E2Term_Init_Message_Test.robot @@ -1,3 +1,25 @@ +############################################################################## +# +# 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 *** Suite Setup Prepare Enviorment Resource ../Resource/resource.robot diff --git a/Automation/Tests/E2_Setup_Failure/Enable_Ric_False_Setup_Failure.robot b/Automation/Tests/E2_Setup_Failure/Enable_Ric_False_Setup_Failure.robot new file mode 100644 index 0000000..acada18 --- /dev/null +++ b/Automation/Tests/E2_Setup_Failure/Enable_Ric_False_Setup_Failure.robot @@ -0,0 +1,50 @@ +############################################################################## +# +# 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 *** +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/e2mdbscripts.py +Library REST ${url} +Suite Teardown Flush And Populate DB + + +*** Test Cases *** + +Disable ric and restart simulator + ${result} e2mdbscripts.set_enable_ric_false + Restart simulator + + +prepare logs for tests + Remove log files + Save logs + + +E2M Logs - Verify RMR Message + ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${Setup_failure_message_type} ${None} + Should Be Equal As Strings ${result} True \ No newline at end of file diff --git a/Automation/Tests/E2_Setup_Failure/RM_Error_Setup_Failure.robot b/Automation/Tests/E2_Setup_Failure/RM_Error_Setup_Failure.robot new file mode 100644 index 0000000..aca558f --- /dev/null +++ b/Automation/Tests/E2_Setup_Failure/RM_Error_Setup_Failure.robot @@ -0,0 +1,60 @@ +############################################################################## +# +# 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 *** +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 REST ${url} +Suite Teardown Start RoutingManager Simulator + + +*** Test Cases *** +Stop Routing manager simulator and restarting simulator + Stop RoutingManager Simulator + Restart simulator with less docker + +prepare logs for tests + Remove log files + Save logs + +Get request gnb + Sleep 2s + Get Request node b gnb + Integer response status 200 + String response body ranName ${ranname} + String response body connectionStatus DISCONNECTED + String response body nodeType GNB + Integer response body gnb ranFunctions 0 ranFunctionId 1 + Integer response body gnb ranFunctions 0 ranFunctionRevision 1 + Integer response body gnb ranFunctions 1 ranFunctionId 2 + Integer response body gnb ranFunctions 1 ranFunctionRevision 1 + Integer response body gnb ranFunctions 2 ranFunctionId 3 + Integer response body gnb ranFunctions 2 ranFunctionRevision 1 + +E2M Logs - Verify RMR Message + ${result} find_rmr_message.verify_logs ${EXECDIR} ${e2mgr_log_filename} ${Setup_failure_message_type} ${None} + Should Be Equal As Strings ${result} True \ No newline at end of file diff --git a/Automation/Tests/E2_Setup_Failure/__init__.robot b/Automation/Tests/E2_Setup_Failure/__init__.robot new file mode 100644 index 0000000..51e9ef6 --- /dev/null +++ b/Automation/Tests/E2_Setup_Failure/__init__.robot @@ -0,0 +1,24 @@ +############################################################################## +# +# 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 *** +Documentation Setup Failure diff --git a/Automation/Tests/Get_E2T_Instances/get_e2t_instances.robot b/Automation/Tests/Get_E2T_Instances/get_e2t_instances.robot index 09bc6ca..4f580c0 100644 --- a/Automation/Tests/Get_E2T_Instances/get_e2t_instances.robot +++ b/Automation/Tests/Get_E2T_Instances/get_e2t_instances.robot @@ -37,7 +37,7 @@ Get E2T instances ${headers}= Create Dictionary Accept=application/json ${resp}= Get Request getE2tInstances /v1/e2t/list headers=${headers} Should Be Equal As Strings ${resp.status_code} 200 - Should Be Equal As Strings ${resp.content} [{"e2tAddress":"e2t.att.com:38000","ranNames":["test1","test2","test3"]},{"e2tAddress":"e2t.att.com:38001","ranNames":[]}] + Should Be Equal As Strings ${resp.content} [{"e2tAddress":"e2t.att.com:38000","ranNames":["test1","test2","test3"]}] ${flush} cleanup_db.flush diff --git a/Automation/Tests/Resource/Keywords.robot b/Automation/Tests/Resource/Keywords.robot index 46296d8..1f453df 100644 --- a/Automation/Tests/Resource/Keywords.robot +++ b/Automation/Tests/Resource/Keywords.robot @@ -35,6 +35,9 @@ Update Ran request Sleep 1s PUT ${update_gnb_url} ${update_gnb_body} +Set General Configuration request + Sleep 1s + PUT ${set_general_configuration} ${set_general_configuration_body} Update Ran request not valid Sleep 1s @@ -126,3 +129,7 @@ Restart simulator with less docker ${result}= Run And Return Rc And Output ${docker_command} Should Be Equal As Integers ${result[1]} ${docker_number-1} +Flush And Populate DB + ${flush} cleanup_db.flush + Sleep 2s + diff --git a/Automation/Tests/Resource/resource.robot b/Automation/Tests/Resource/resource.robot index 29e15f8..dc33988 100644 --- a/Automation/Tests/Resource/resource.robot +++ b/Automation/Tests/Resource/resource.robot @@ -28,8 +28,10 @@ Documentation Resource file ${docker_number} 5 ${docker_number-1} 4 ${url} http://localhost:3800 -${ranName} gnb:208-092-303030 +${ranName} gnb_208_092_303030 ${getNodeb} /v1/nodeb/${ranName} +${set_general_configuration} /v1/nodeb/parameters +${set_general_configuration_body} {"enableRic":false} ${update_gnb_url} /v1/nodeb/${ranName}/update ${update_gnb_body} {"servedNrCells":[{"servedNrCellInformation":{"cellId":"abcd","choiceNrMode":{"fdd":{}},"nrMode":1,"nrPci":1,"servedPlmns":["whatever"]},"nrNeighbourInfos":[{"nrCgi":"one","choiceNrMode":{"fdd":{}},"nrMode":1,"nrPci":1}]}]} ${update_gnb_body_notvalid} {"servedNrCells":[{"servedNrCellInformation":{"choiceNrMode":{"fdd":{}},"nrMode":1,"nrPci":1,"servedPlmns":["whatever"]},"nrNeighbourInfos":[{"nrCgi":"whatever","choiceNrMode":{"fdd":{}},"nrMode":1,"nrPci":1}]}]} diff --git a/Automation/Tests/Resource/scripts_variables.robot b/Automation/Tests/Resource/scripts_variables.robot index 89dc05a..99c2944 100644 --- a/Automation/Tests/Resource/scripts_variables.robot +++ b/Automation/Tests/Resource/scripts_variables.robot @@ -32,5 +32,4 @@ ${first_retry_to_retrieve_from_db} RnibDataService.retry - retrying 1 GetNo ${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 - - +${save_general_configuration} RnibDataService.SaveGeneralConfiguration - configuration: {EnableRic:false} \ No newline at end of file diff --git a/Automation/Tests/Scripts/cleanup_db.py b/Automation/Tests/Scripts/cleanup_db.py index 4dd3ff0..979da9a 100644 --- a/Automation/Tests/Scripts/cleanup_db.py +++ b/Automation/Tests/Scripts/cleanup_db.py @@ -33,9 +33,8 @@ def flush(): r = redis.Redis(host=c, port=p, db=0) r.flushall() - + r.set("{e2Manager},GENERAL","{\"enableRic\":true}") r.set("{e2Manager},E2TAddresses", "[\"10.0.2.15:38000\"]") - r.set("{e2Manager},E2TInstance:10.0.2.15:38000","{\"address\":\"10.0.2.15:38000\",\"associatedRanList\":[],\"keepAliveTimestamp\":" + str(int((time.time()+2) * 1000000000)) + ",\"state\":\"ACTIVE\",\"deletionTimeStamp\":0}") return True diff --git a/Automation/Tests/Scripts/e2mdbscripts.py b/Automation/Tests/Scripts/e2mdbscripts.py index b452b93..b209ea3 100644 --- a/Automation/Tests/Scripts/e2mdbscripts.py +++ b/Automation/Tests/Scripts/e2mdbscripts.py @@ -17,57 +17,53 @@ ############################################################################## import config -import redis -import cleanup_db import json +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_ran_is_associated_with_e2t_instance(ranName, e2tAddress): r = getRedisClientDecodeResponse() - e2tInstanceJson = r.get("{e2Manager},E2TInstance:"+e2tAddress) + e2tInstanceJson = r.get("{e2Manager},E2TInstance:" + e2tAddress) e2tInstanceDic = json.loads(e2tInstanceJson) assocRanList = e2tInstanceDic.get("associatedRanList") return ranName in assocRanList + def verify_e2t_instance_has_no_associated_rans(e2tAddress): r = getRedisClientDecodeResponse() - e2tInstanceJson = r.get("{e2Manager},E2TInstance:"+e2tAddress) + e2tInstanceJson = r.get("{e2Manager},E2TInstance:" + e2tAddress) e2tInstanceDic = json.loads(e2tInstanceJson) assocRanList = e2tInstanceDic.get("associatedRanList") return not assocRanList + def verify_e2t_instance_exists_in_addresses(e2tAddress): r = getRedisClientDecodeResponse() e2tAddressesJson = r.get("{e2Manager},E2TAddresses") e2tAddresses = json.loads(e2tAddressesJson) return e2tAddress in e2tAddresses + def verify_e2t_instance_key_exists(e2tAddress): r = getRedisClientDecodeResponse() - return r.exists("{e2Manager},E2TInstance:"+e2tAddress) + return r.exists("{e2Manager},E2TInstance:" + e2tAddress) + def populate_e2t_instances_in_e2m_db_for_get_e2t_instances_tc(): r = getRedisClientDecodeResponse() - r.set("{e2Manager},E2TAddresses", "[\"e2t.att.com:38000\",\"e2t.att.com:38001\"]") - r.set("{e2Manager},E2TInstance:e2t.att.com:38000", "{\"address\":\"e2t.att.com:38000\",\"associatedRanList\":[\"test1\",\"test2\",\"test3\"],\"keepAliveTimestamp\":1577619310484022369,\"state\":\"ACTIVE\"}") - r.set("{e2Manager},E2TInstance:e2t.att.com:38001", "{\"address\":\"e2t.att.com:38001\",\"associatedRanList\":[],\"keepAliveTimestamp\":1577619310484022369,\"state\":\"ACTIVE\"}") + r.set("{e2Manager},E2TAddresses", "[\"e2t.att.com:38000\"]") + r.set("{e2Manager},E2TInstance:e2t.att.com:38000", + "{\"address\":\"e2t.att.com:38000\",\"associatedRanList\":[\"test1\",\"test2\",\"test3\"],\"keepAliveTimestamp\":1577619310484022369,\"state\":\"ACTIVE\"}") return True -# 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) +def set_enable_ric_false(): + r = getRedisClientDecodeResponse() + r.set("{e2Manager},GENERAL", "{\"enableRic\":false}") + return True diff --git a/Automation/Tests/SetGeneralConfiguration/__init__.robot b/Automation/Tests/SetGeneralConfiguration/__init__.robot new file mode 100644 index 0000000..4a008d9 --- /dev/null +++ b/Automation/Tests/SetGeneralConfiguration/__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/SetGeneralConfiguration/set_general_configuration.robot b/Automation/Tests/SetGeneralConfiguration/set_general_configuration.robot new file mode 100644 index 0000000..da7356b --- /dev/null +++ b/Automation/Tests/SetGeneralConfiguration/set_general_configuration.robot @@ -0,0 +1,48 @@ +############################################################################## +# +# 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 *** +Suite Setup Prepare Enviorment +Resource ../Resource/resource.robot +Resource ../Resource/Keywords.robot +Library OperatingSystem +Library REST ${url} + + + + +*** Test Cases *** + +prepare logs for tests + Remove log files + Save logs + +Set General Configuration + Sleep 2s + Set General Configuration request + Integer response status 200 + String response body enableRic false + +Verify e2mgr logs - Third retry to retrieve from db + ${result} find_error_script.find_error ${EXECDIR} ${e2mgr_log_filename} ${save_general_configuration} + Should Be Equal As Strings ${result} True \ No newline at end of file diff --git a/E2Manager/configuration/configuration.go b/E2Manager/configuration/configuration.go index 5e4c31e..f539c5d 100644 --- a/E2Manager/configuration/configuration.go +++ b/E2Manager/configuration/configuration.go @@ -20,8 +20,10 @@ package configuration import ( + "errors" "fmt" "github.com/spf13/viper" + "strconv" ) type Configuration struct { @@ -38,10 +40,7 @@ type Configuration struct { RoutingManager struct { BaseUrl string } -/* Kubernetes struct { - ConfigPath string - KubeNamespace string - }*/ + NotificationResponseBuffer int BigRedButtonTimeoutSec int MaxRnibConnectionAttempts int @@ -50,9 +49,11 @@ type Configuration struct { KeepAliveDelayMs int E2TInstanceDeletionTimeoutMs int GlobalRicId struct { - PlmnId string - RicNearRtId string + RicId string + Mcc string + Mnc string } + StateChangeMessageChannel string } func ParseConfiguration() *Configuration { @@ -72,7 +73,6 @@ func ParseConfiguration() *Configuration { config.populateHttpConfig(viper.Sub("http")) config.populateLoggingConfig(viper.Sub("logging")) config.populateRoutingManagerConfig(viper.Sub("routingManager")) - //config.populateKubernetesConfig(viper.Sub("kubernetes")) config.NotificationResponseBuffer = viper.GetInt("notificationResponseBuffer") config.BigRedButtonTimeoutSec = viper.GetInt("bigRedButtonTimeoutSec") config.MaxRnibConnectionAttempts = viper.GetInt("maxRnibConnectionAttempts") @@ -81,6 +81,7 @@ func ParseConfiguration() *Configuration { config.KeepAliveDelayMs = viper.GetInt("KeepAliveDelayMs") config.E2TInstanceDeletionTimeoutMs = viper.GetInt("e2tInstanceDeletionTimeoutMs") config.populateGlobalRicIdConfig(viper.Sub("globalRicId")) + config.StateChangeMessageChannel = viper.GetString("stateChangeMessageChannel") return &config } @@ -113,27 +114,112 @@ func (c *Configuration) populateRoutingManagerConfig(rmConfig *viper.Viper) { c.RoutingManager.BaseUrl = rmConfig.GetString("baseUrl") } -/*func (c *Configuration) populateKubernetesConfig(rmConfig *viper.Viper) { - if rmConfig == nil { - panic(fmt.Sprintf("#configuration.populateKubernetesConfig - failed to populate Kubernetes configuration: The entry 'kubernetes' not found\n")) +func (c *Configuration) populateGlobalRicIdConfig(globalRicIdConfig *viper.Viper) { + err := validateGlobalRicIdConfig(globalRicIdConfig) + if err != nil { + panic(err.Error()) } - c.Kubernetes.ConfigPath = rmConfig.GetString("configPath") - c.Kubernetes.KubeNamespace = rmConfig.GetString("kubeNamespace") -}*/ + c.GlobalRicId.RicId = globalRicIdConfig.GetString("ricId") + c.GlobalRicId.Mcc = globalRicIdConfig.GetString("mcc") + c.GlobalRicId.Mnc = globalRicIdConfig.GetString("mnc") +} -func (c *Configuration) populateGlobalRicIdConfig(globalRicIdConfig *viper.Viper) { +func validateGlobalRicIdConfig(globalRicIdConfig *viper.Viper) error { if globalRicIdConfig == nil { - panic(fmt.Sprintf("#configuration.populateGlobalRicIdConfig - failed to populate Global RicId configuration: The entry 'globalRicId' not found\n")) + return errors.New("#configuration.validateGlobalRicIdConfig - failed to populate Global RicId configuration: The entry 'globalRicId' not found\n") + } + + err := validateRicId(globalRicIdConfig.GetString("ricId")) + + if err != nil { + return err + } + + err = validateMcc(globalRicIdConfig.GetString("mcc")) + + if err != nil { + return err + } + + err = validateMnc(globalRicIdConfig.GetString("mnc")) + + if err != nil { + return err + } + + + return nil +} + +func validateMcc(mcc string) error { + + if len(mcc) == 0{ + return errors.New("#configuration.validateMcc - mcc is missing or empty\n") + } + + if len(mcc) != 3{ + return errors.New("#configuration.validateMcc - mcc is not 3 digits\n") + } + + mccInt, err := strconv.Atoi(mcc) + + if err != nil{ + return errors.New("#configuration.validateMcc - mcc is not a number\n") + } + + if mccInt < 0 { + return errors.New("#configuration.validateMcc - mcc is negative\n") } - c.GlobalRicId.PlmnId = globalRicIdConfig.GetString("plmnId") - c.GlobalRicId.RicNearRtId = globalRicIdConfig.GetString("ricNearRtId") + return nil } +func validateMnc(mnc string) error { + + if len(mnc) == 0{ + return errors.New("#configuration.validateMnc - mnc is missing or empty\n") + } + + if len(mnc) < 2 || len(mnc) >3 { + return errors.New("#configuration.validateMnc - mnc is not 2 or 3 digits\n") + } + + mncAsInt, err := strconv.Atoi(mnc) + + if err != nil{ + return errors.New("#configuration.validateMnc - mnc is not a number\n") + } + + if mncAsInt < 0 { + return errors.New("#configuration.validateMnc - mnc is negative\n") + } + + return nil +} + +func validateRicId(ricId string) error{ + + if len(ricId) == 0{ + return errors.New("#configuration.validateRicId - ricId is missing or empty\n") + } + + if len(ricId) != 5 { + return errors.New("#configuration.validateRicId - ricId length should be 5 hex characters\n") + } + + _, err := strconv.ParseUint(ricId, 16, 64) + if err != nil { + return errors.New("#configuration.validateRicId - ricId is not hex number\n") + } + + return nil +} + + func (c *Configuration) String() string { return fmt.Sprintf("{logging.logLevel: %s, http.port: %d, rmr: { port: %d, maxMsgSize: %d}, routingManager.baseUrl: %s, "+ "notificationResponseBuffer: %d, bigRedButtonTimeoutSec: %d, maxRnibConnectionAttempts: %d, "+ "rnibRetryIntervalMs: %d, keepAliveResponseTimeoutMs: %d, keepAliveDelayMs: %d, e2tInstanceDeletionTimeoutMs: %d, "+ - "globalRicId: { plmnId: %s, ricNearRtId: %s}",//, kubernetes: {configPath: %s, kubeNamespace: %s}}", + "globalRicId: { ricId: %s, mcc: %s, mnc: %s}, StateChangeMessageChannel: %s", c.Logging.LogLevel, c.Http.Port, c.Rmr.Port, @@ -146,9 +232,9 @@ func (c *Configuration) String() string { c.KeepAliveResponseTimeoutMs, c.KeepAliveDelayMs, c.E2TInstanceDeletionTimeoutMs, - c.GlobalRicId.PlmnId, - c.GlobalRicId.RicNearRtId, -/* c.Kubernetes.ConfigPath, - c.Kubernetes.KubeNamespace,*/ + c.GlobalRicId.RicId, + c.GlobalRicId.Mcc, + c.GlobalRicId.Mnc, + c.StateChangeMessageChannel, ) } diff --git a/E2Manager/configuration/configuration_test.go b/E2Manager/configuration/configuration_test.go index 695ed9a..27fd1b4 100644 --- a/E2Manager/configuration/configuration_test.go +++ b/E2Manager/configuration/configuration_test.go @@ -40,10 +40,10 @@ func TestParseConfigurationSuccess(t *testing.T) { assert.Equal(t, 1500, config.KeepAliveDelayMs) assert.Equal(t, 15000, config.E2TInstanceDeletionTimeoutMs) assert.NotNil(t, config.GlobalRicId) - assert.NotEmpty(t, config.GlobalRicId.PlmnId) - assert.NotEmpty(t, config.GlobalRicId.RicNearRtId) -/* assert.NotEmpty(t, config.Kubernetes.KubeNamespace) - assert.NotEmpty(t, config.Kubernetes.ConfigPath)*/ + assert.Equal(t, "AACCE", config.GlobalRicId.RicId) + assert.Equal(t, "310", config.GlobalRicId.Mcc) + assert.Equal(t, "411", config.GlobalRicId.Mnc) + assert.Equal(t, "RAN_CONNECTION_STATUS_CHANGE", config.StateChangeMessageChannel) } func TestStringer(t *testing.T) { @@ -83,7 +83,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/"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, "globalRicId": map[string]interface{}{"plmnId": "131014", "ricNearRtId": "556670"}, } buf, err := yaml.Marshal(yamlMap) @@ -113,7 +113,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/"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, "globalRicId": map[string]interface{}{"plmnId": "131014", "ricNearRtId": "556670"}, } buf, err := yaml.Marshal(yamlMap) @@ -144,7 +144,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/"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, "globalRicId": map[string]interface{}{"plmnId": "131014", "ricNearRtId": "556670"}, } buf, err := yaml.Marshal(yamlMap) @@ -176,7 +176,7 @@ func TestRoutingManagerConfigNotFoundFailure(t *testing.T) { "rmr": map[string]interface{}{"port": 3801, "maxMsgSize": 4096}, "logging": map[string]interface{}{"logLevel": "info"}, "http": map[string]interface{}{"port": 3800}, - "globalRicId": map[string]interface{}{"plmnId": "131014", "ricNearRtId": "556670"}, + "globalRicId": map[string]interface{}{"mcc": 327, "mnc": 94, "ricId": "AACCE"}, } buf, err := yaml.Marshal(yamlMap) if err != nil { @@ -207,8 +207,7 @@ func TestGlobalRicIdConfigNotFoundFailure(t *testing.T) { "rmr": map[string]interface{}{"port": 3801, "maxMsgSize": 4096}, "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/"}, - //"kubernetes": map[string]interface{}{"kubeNamespace": "test", "ConfigPath": "test"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, } buf, err := yaml.Marshal(yamlMap) if err != nil { @@ -218,38 +217,487 @@ func TestGlobalRicIdConfigNotFoundFailure(t *testing.T) { if err != nil { t.Errorf("#TestGlobalRicIdConfigNotFoundFailure - failed to write configuration file: %s\n", configPath) } - assert.PanicsWithValue(t, "#configuration.populateGlobalRicIdConfig - failed to populate Global RicId configuration: The entry 'globalRicId' not found\n", + assert.PanicsWithValue(t, "#configuration.validateGlobalRicIdConfig - failed to populate Global RicId configuration: The entry 'globalRicId' not found\n", func() { ParseConfiguration() }) } -/*func TestKubernetesConfigNotFoundFailure(t *testing.T) { +func TestEmptyRicIdFailure(t *testing.T) { +configPath := "../resources/configuration.yaml" +configPathTmp := "../resources/configuration.yaml_tmp" +err := os.Rename(configPath, configPathTmp) +if err != nil { +t.Errorf("#TestEmptyRicIdFailure - failed to rename configuration file: %s\n", configPath) +} +defer func() { +err = os.Rename(configPathTmp, configPath) +if err != nil { +t.Errorf("#TestEmptyRicIdFailure - 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}, +"globalRicId": map[string]interface{}{"mcc": "327", "mnc": "94", "ricId": ""}, +"routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, +} +buf, err := yaml.Marshal(yamlMap) +if err != nil { +t.Errorf("#TestEmptyRicIdFailure - failed to marshal configuration map\n") +} +err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) +if err != nil { +t.Errorf("#TestEmptyRicIdFailure - failed to write configuration file: %s\n", configPath) +} +assert.PanicsWithValue(t, "#configuration.validateRicId - ricId is missing or empty\n", +func() { ParseConfiguration() }) +} + +func TestMissingRicIdFailure(t *testing.T) { configPath := "../resources/configuration.yaml" configPathTmp := "../resources/configuration.yaml_tmp" err := os.Rename(configPath, configPathTmp) if err != nil { - t.Errorf("#TestKubernetesConfigNotFoundFailure - failed to rename configuration file: %s\n", configPath) + t.Errorf("#TestEmptyRicIdFailure - failed to rename configuration file: %s\n", configPath) } defer func() { err = os.Rename(configPathTmp, configPath) if err != nil { - t.Errorf("#TestKubernetesConfigNotFoundFailure - failed to rename configuration file: %s\n", configPath) + t.Errorf("#TestEmptyRicIdFailure - 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}, - "routingManager": map[string]interface{}{"baseUrl": "http://iltlv740.intl.att.com:8080/ric/v1/handles/"}, - "globalRicId": map[string]interface{}{"plmnId": "131014", "ricNearRtId": "556670"}, + "globalRicId": map[string]interface{}{"mcc": "327", "mnc": "94"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestEmptyRicIdFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestEmptyRicIdFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.validateRicId - ricId is missing or empty\n", + func() { ParseConfiguration() }) +} + +func TestNonHexRicIdFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestNonHexRicIdFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestNonHexRicIdFailure - 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}, + "globalRicId": map[string]interface{}{"mcc": "327", "mnc": "94", "ricId": "TEST1"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestNonHexRicIdFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestNonHexRicIdFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.validateRicId - ricId is not hex number\n", + func() { ParseConfiguration() }) +} + +func TestWrongRicIdLengthFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestWrongRicIdLengthFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestWrongRicIdLengthFailure - 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}, + "globalRicId": map[string]interface{}{"mcc": "327", "mnc": "94", "ricId": "AA43"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestWrongRicIdLengthFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestWrongRicIdLengthFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.validateRicId - ricId length should be 5 hex characters\n", + func() { ParseConfiguration() }) +} + +func TestMccNotThreeDigitsFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestMccNotThreeDigitsFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestMccNotThreeDigitsFailure - 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}, + "globalRicId": map[string]interface{}{"mcc": "31", "mnc": "94", "ricId": "AA443"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, } buf, err := yaml.Marshal(yamlMap) if err != nil { - t.Errorf("#TestKubernetesConfigNotFoundFailure - failed to marshal configuration map\n") + t.Errorf("#TestMccNotThreeDigitsFailure - failed to marshal configuration map\n") } err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) if err != nil { - t.Errorf("#TestKubernetesConfigNotFoundFailure - failed to write configuration file: %s\n", configPath) + t.Errorf("#TestMccNotThreeDigitsFailure - failed to write configuration file: %s\n", configPath) } - assert.PanicsWithValue(t, "#configuration.populateKubernetesConfig - failed to populate Kubernetes configuration: The entry 'kubernetes' not found\n", + assert.PanicsWithValue(t, "#configuration.validateMcc - mcc is not 3 digits\n", func() { ParseConfiguration() }) -}*/ +} + +func TestMncLengthIsGreaterThanThreeDigitsFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestMncLengthIsGreaterThanThreeDigitsFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestMncLengthIsGreaterThanThreeDigitsFailure - 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}, + "globalRicId": map[string]interface{}{"mcc": "310", "mnc": "6794", "ricId": "AA443"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestMncLengthIsGreaterThanThreeDigitsFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestMncLengthIsGreaterThanThreeDigitsFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.validateMnc - mnc is not 2 or 3 digits\n", + func() { ParseConfiguration() }) +} + +func TestMncLengthIsLessThanTwoDigitsFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestMncLengthIsLessThanTwoDigitsFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestMncLengthIsLessThanTwoDigitsFailure - 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}, + "globalRicId": map[string]interface{}{"mcc": "310", "mnc": "4", "ricId": "AA443"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestMncLengthIsLessThanTwoDigitsFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestMncLengthIsLessThanTwoDigitsFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.validateMnc - mnc is not 2 or 3 digits\n", + func() { ParseConfiguration() }) +} + +func TestNegativeMncFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestNegativeMncFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestNegativeMncFailure - 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}, + "globalRicId": map[string]interface{}{"mcc": "310", "mnc": "-2", "ricId": "AA443"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestNegativeMncFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestNegativeMncFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.validateMnc - mnc is negative\n", + func() { ParseConfiguration() }) +} + +func TestNegativeMccFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestNegativeMncFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestNegativeMncFailure - 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}, + "globalRicId": map[string]interface{}{"mcc": "-31", "mnc": "222", "ricId": "AA443"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestNegativeMncFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestNegativeMncFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.validateMcc - mcc is negative\n", + func() { ParseConfiguration() }) +} + +func TestAlphaNumericMccFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestAlphaNumericMccFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestAlphaNumericMccFailure - 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}, + "globalRicId": map[string]interface{}{"mcc": "1W2", "mnc": "222", "ricId": "AA443"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestAlphaNumericMccFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestAlphaNumericMccFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.validateMcc - mcc is not a number\n", + func() { ParseConfiguration() }) +} + +func TestAlphaNumericMncFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestAlphaNumericMncFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestAlphaNumericMncFailure - 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}, + "globalRicId": map[string]interface{}{"mcc": "111", "mnc": "2A8", "ricId": "AA443"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestAlphaNumericMncFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestAlphaNumericMncFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.validateMnc - mnc is not a number\n", + func() { ParseConfiguration() }) +} + +func TestMissingMmcFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestMissingMmcFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestMissingMmcFailure - 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}, + "globalRicId": map[string]interface{}{"mnc": "94", "ricId": "AABB3"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestMissingMmcFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestMissingMmcFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.validateMcc - mcc is missing or empty\n", + func() { ParseConfiguration() }) +} + + +func TestEmptyMmcFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestEmptyMmcFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestEmptyMmcFailure - 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}, + "globalRicId": map[string]interface{}{"mcc": "", "mnc": "94", "ricId": "AABB3"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestEmptyMmcFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestEmptyMmcFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.validateMcc - mcc is missing or empty\n", + func() { ParseConfiguration() }) +} + +func TestEmptyMncFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestEmptyMncFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestEmptyMncFailure - 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}, + "globalRicId": map[string]interface{}{"mcc": "111", "mnc": "", "ricId": "AABB3"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestEmptyMncFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestEmptyMncFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.validateMnc - mnc is missing or empty\n", + func() { ParseConfiguration() }) +} + +func TestMissingMncFailure(t *testing.T) { + configPath := "../resources/configuration.yaml" + configPathTmp := "../resources/configuration.yaml_tmp" + err := os.Rename(configPath, configPathTmp) + if err != nil { + t.Errorf("#TestMissingMncFailure - failed to rename configuration file: %s\n", configPath) + } + defer func() { + err = os.Rename(configPathTmp, configPath) + if err != nil { + t.Errorf("#TestMissingMncFailure - 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}, + "globalRicId": map[string]interface{}{"mcc": "111", "ricId": "AABB3"}, + "routingManager": map[string]interface{}{"baseUrl": "http://localhost:8080/ric/v1/handles/"}, + } + buf, err := yaml.Marshal(yamlMap) + if err != nil { + t.Errorf("#TestMissingMncFailure - failed to marshal configuration map\n") + } + err = ioutil.WriteFile("../resources/configuration.yaml", buf, 0644) + if err != nil { + t.Errorf("#TestMissingMncFailure - failed to write configuration file: %s\n", configPath) + } + assert.PanicsWithValue(t, "#configuration.validateMnc - mnc is missing or empty\n", + func() { ParseConfiguration() }) +} diff --git a/E2Manager/container-tag.yaml b/E2Manager/container-tag.yaml index ccff1ff..273b7ac 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: 4.4.12 +tag: 5.2.0 diff --git a/E2Manager/controllers/nodeb_controller.go b/E2Manager/controllers/nodeb_controller.go index 90b9311..49e821d 100644 --- a/E2Manager/controllers/nodeb_controller.go +++ b/E2Manager/controllers/nodeb_controller.go @@ -40,6 +40,8 @@ const ( ParamRanName = "ranName" LimitRequest = 2000 ) +const ApplicationJson = "application/json" +const ContentType = "Content-Type" type INodebController interface { Shutdown(writer http.ResponseWriter, r *http.Request) @@ -49,6 +51,7 @@ type INodebController interface { GetNodeb(writer http.ResponseWriter, r *http.Request) UpdateGnb(writer http.ResponseWriter, r *http.Request) GetNodebIdList(writer http.ResponseWriter, r *http.Request) + SetGeneralConfiguration(writer http.ResponseWriter, r *http.Request) } type NodebController struct { @@ -90,11 +93,22 @@ func (c *NodebController) UpdateGnb(writer http.ResponseWriter, r *http.Request) return } - request.Gnb = &gnb; + request.Gnb = &gnb request.RanName = ranName c.handleRequest(writer, &r.Header, httpmsghandlerprovider.UpdateGnbRequest, request, true) } +func (c *NodebController) SetGeneralConfiguration(writer http.ResponseWriter, r *http.Request) { + c.logger.Infof("[Client -> E2 Manager] #NodebController.SetGeneralConfiguration - request: %v", c.prettifyRequest(r)) + + request := models.GeneralConfigurationRequest{} + + if !c.extractJsonBody(r, &request, writer){ + return + } + c.handleRequest(writer, &r.Header, httpmsghandlerprovider.SetGeneralConfigurationRequest, request, false) +} + func (c *NodebController) Shutdown(writer http.ResponseWriter, r *http.Request) { c.logger.Infof("[Client -> E2 Manager] #NodebController.Shutdown - request: %v", c.prettifyRequest(r)) c.handleRequest(writer, &r.Header, httpmsghandlerprovider.ShutdownRequest, nil, false) @@ -210,13 +224,13 @@ 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.Header().Set(ContentType, ApplicationJson) writer.Write(result) } func (c *NodebController) validateRequestHeader(header *http.Header) error { - if header.Get("Content-Type") != "application/json" { + if header.Get(ContentType) != ApplicationJson { c.logger.Errorf("#NodebController.validateRequestHeader - validation failure, incorrect content type") return e2managererrors.NewHeaderValidationError() @@ -281,7 +295,7 @@ func (c *NodebController) handleErrorResponse(err error, writer http.ResponseWri c.logger.Errorf("[E2 Manager -> Client] #NodebController.handleErrorResponse - http status: %d, error response: %+v", httpError, errorResponseDetails) - writer.Header().Set("Content-Type", "application/json") + writer.Header().Set(ContentType, ApplicationJson) writer.WriteHeader(httpError) _, err = writer.Write(errorResponse) } diff --git a/E2Manager/controllers/nodeb_controller_test.go b/E2Manager/controllers/nodeb_controller_test.go index a9bccdc..1543674 100644 --- a/E2Manager/controllers/nodeb_controller_test.go +++ b/E2Manager/controllers/nodeb_controller_test.go @@ -277,6 +277,39 @@ func TestShutdownHandlerRnibError(t *testing.T) { assert.Equal(t, errorResponse.Code, e2managererrors.NewRnibDbError().Code) } +func TestSetGeneralConfigurationHandlerRnibError(t *testing.T) { + controller, readerMock, _, _, _ := setupControllerTest(t) + + configuration := &entities.GeneralConfiguration{} + readerMock.On("GetGeneralConfiguration").Return(configuration, e2managererrors.NewRnibDbError()) + + writer := httptest.NewRecorder() + + httpRequest, _ := http.NewRequest("PUT", "https://localhost:3800/v1/nodeb/parameters", strings.NewReader("{\"enableRic\":false}")) + + controller.SetGeneralConfiguration(writer, httpRequest) + + var errorResponse = parseJsonRequest(t, writer.Body) + + assert.Equal(t, http.StatusInternalServerError, writer.Result().StatusCode) + assert.Equal(t, e2managererrors.NewRnibDbError().Code, errorResponse.Code) +} + +func TestSetGeneralConfigurationInvalidJson(t *testing.T) { + controller, _, _, _, _ := setupControllerTest(t) + + writer := httptest.NewRecorder() + + httpRequest, _ := http.NewRequest("PUT", "https://localhost:3800/v1/nodeb/parameters", strings.NewReader("{}{}")) + + controller.SetGeneralConfiguration(writer, httpRequest) + + var errorResponse = parseJsonRequest(t, writer.Body) + + assert.Equal(t, http.StatusBadRequest, writer.Result().StatusCode) + assert.Equal(t, e2managererrors.NewInvalidJsonError().Code, errorResponse.Code) +} + func controllerGetNodebTestExecuter(t *testing.T, context *controllerGetNodebTestContext) { controller, readerMock, _, _, _ := setupControllerTest(t) writer := httptest.NewRecorder() diff --git a/E2Manager/converters/endc_setup_failure_response_converter_test.go b/E2Manager/converters/endc_setup_failure_response_converter_test.go index 77c60b5..ac5aa52 100644 --- a/E2Manager/converters/endc_setup_failure_response_converter_test.go +++ b/E2Manager/converters/endc_setup_failure_response_converter_test.go @@ -25,6 +25,7 @@ import ( "e2mgr/logger" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "regexp" "strings" "testing" ) @@ -42,7 +43,7 @@ func TestUnpackEndcX2SetupFailureResponseAndExtract(t *testing.T) { failure error }{ { - response: "CONNECTED_SETUP_FAILED network_layer_cause:HANDOVER_DESIRABLE_FOR_RADIO_REASONS time_to_wait:V1S criticality_diagnostics: > ", + response: "CONNECTED_SETUP_FAILED network_layer_cause:HANDOVER_DESIRABLE_FOR_RADIO_REASONS time_to_wait:V1S criticality_diagnostics:{procedure_code:33 triggering_message:UNSUCCESSFUL_OUTCOME procedure_criticality:NOTIFY information_element_criticality_diagnostics:{ie_criticality:REJECT ie_id:128 type_of_error:MISSING}}", /* E2AP-PDU: unsuccessfulOutcome_t @@ -110,10 +111,14 @@ func TestUnpackEndcX2SetupFailureResponseAndExtract(t *testing.T) { nb.SetupFailure = response nb.FailureType = entities.Failure_X2_SETUP_FAILURE respStr := fmt.Sprintf("%s %s", nb.ConnectionStatus, response) - if !strings.EqualFold(respStr, tc.response) { - t.Errorf("want: response=[%s], got: [%s]", tc.response, respStr) - } + space := regexp.MustCompile(`\s+`) + s1 := space.ReplaceAllString(respStr, " ") + s2 := space.ReplaceAllString(tc.response," ") + + if !strings.EqualFold(s1, s2) { + t.Errorf("want: [%s], got: [%s]", tc.response, respStr) + } } }) } diff --git a/E2Manager/converters/endc_setup_response_converter_test.go b/E2Manager/converters/endc_setup_response_converter_test.go index f68e4c0..d4b2848 100644 --- a/E2Manager/converters/endc_setup_response_converter_test.go +++ b/E2Manager/converters/endc_setup_response_converter_test.go @@ -25,6 +25,7 @@ import ( "e2mgr/logger" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "regexp" "strings" "testing" ) @@ -44,7 +45,7 @@ func TestUnpackEndcX2SetupResponseAndExtract(t *testing.T) { }{ { key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "4a952a0a"}, - gnb: "CONNECTED [served_nr_cell_information: > frequency_bands: > transmission_bandwidth: > > > served_nr_cell_information: > frequency_bands: > transmission_bandwidth: > > > nr_neighbour_infos: > frequency_bands: > > > > ]", + gnb: "CONNECTED [served_nr_cell_information:{nr_pci:5 cell_id:\"1e3f27:1f2e3d4ff0\" stac5g:\"3d44d3\" configured_stac:\"4e4f\" served_plmns:\"3e4e5e\" nr_mode:TDD choice_nr_mode:{tdd:{nr_freq_info:{nr_ar_fcn:1 sulInformation:{sul_ar_fcn:2 sul_transmission_bandwidth:{nrscs:SCS60 ncnrb:NRB107}} frequency_bands:{nr_frequency_band:22 supported_sul_bands:11}} transmission_bandwidth:{nrscs:SCS30 ncnrb:NRB133}}}} served_nr_cell_information:{nr_pci:5 cell_id:\"1e3f27:1f2e3d4ff0\" stac5g:\"3d44d3\" configured_stac:\"4e4f\" served_plmns:\"3e4e5e\" nr_mode:TDD choice_nr_mode:{tdd:{nr_freq_info:{nr_ar_fcn:1 sulInformation:{sul_ar_fcn:2 sul_transmission_bandwidth:{nrscs:SCS120 ncnrb:NRB121}} frequency_bands:{nr_frequency_band:22 supported_sul_bands:11}} transmission_bandwidth:{nrscs:SCS15 ncnrb:NRB132}}}} nr_neighbour_infos:{nr_pci:44 nr_cgi:\"1e3f27:1f2e3d4ff0\" nr_mode:TDD choice_nr_mode:{tdd:{ar_fcn_nr_freq_info:{nr_ar_fcn:1 sulInformation:{sul_ar_fcn:2 sul_transmission_bandwidth:{nrscs:SCS15 ncnrb:NRB11}} frequency_bands:{nr_frequency_band:22 supported_sul_bands:11}}}}}]", /* E2AP-PDU: successfulOutcome_t @@ -153,7 +154,7 @@ func TestUnpackEndcX2SetupResponseAndExtract(t *testing.T) { packedPdu: "202400808e00000100f600808640000200fc00090002f829504a952a0a00fd007200010c0005001e3f271f2e3d4ff03d44d34e4f003e4e5e4400010000150400000a000211e148033e4e5e4c0005001e3f271f2e3d4ff03d44d34e4f003e4e5e4400010000150400000a00021a0044033e4e5e000000002c001e3f271f2e3d4ff0031e3f274400010000150400000a00020000"}, { key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "4a952a0a"}, - gnb: "CONNECTED [served_nr_cell_information: > frequency_bands: > transmission_bandwidth: > > > nr_neighbour_infos: > frequency_bands: > > > > ]", + gnb: "CONNECTED [served_nr_cell_information:{nr_pci:5 cell_id:\"1e3f27:1f2e3d4ff0\" stac5g:\"3d44d3\" configured_stac:\"4e4f\" served_plmns:\"3e4e5e\" nr_mode:TDD choice_nr_mode:{tdd:{nr_freq_info:{nr_ar_fcn:1 sulInformation:{sul_ar_fcn:2 sul_transmission_bandwidth:{nrscs:SCS30 ncnrb:NRB107}} frequency_bands:{nr_frequency_band:22 supported_sul_bands:11}} transmission_bandwidth:{nrscs:SCS15 ncnrb:NRB121}}}} nr_neighbour_infos:{nr_pci:44 nr_cgi:\"1e3f27:1f2e3d4ff0\" nr_mode:TDD choice_nr_mode:{tdd:{ar_fcn_nr_freq_info:{nr_ar_fcn:5 sulInformation:{sul_ar_fcn:6 sul_transmission_bandwidth:{nrscs:SCS120 ncnrb:NRB18}} frequency_bands:{nr_frequency_band:22 supported_sul_bands:11}}}}}]", /* E2AP-PDU: successfulOutcome_t @@ -234,7 +235,7 @@ func TestUnpackEndcX2SetupResponseAndExtract(t *testing.T) { { key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "4a952a0a"}, - gnb: "CONNECTED [served_nr_cell_information: > frequency_bands: > transmission_bandwidth: > > > served_nr_cell_information: > frequency_bands: > transmission_bandwidth: > > > nr_neighbour_infos: > frequency_bands: > > > > ]", + gnb: "CONNECTED [served_nr_cell_information:{nr_pci:5 cell_id:\"1e3f27:1f2e3d4ff0\" stac5g:\"3d44d3\" configured_stac:\"4e4f\" served_plmns:\"3e4e5e\" nr_mode:TDD choice_nr_mode:{tdd:{nr_freq_info:{nr_ar_fcn:1 sulInformation:{sul_ar_fcn:2 sul_transmission_bandwidth:{nrscs:SCS60 ncnrb:NRB107}} frequency_bands:{nr_frequency_band:22 supported_sul_bands:11}} transmission_bandwidth:{nrscs:SCS30 ncnrb:NRB133}}}} served_nr_cell_information:{nr_pci:8 cell_id:\"2e3f45:1f2e3d4ff0\" stac5g:\"4faa3c\" configured_stac:\"1a2f\" served_plmns:\"50321e\" nr_mode:TDD choice_nr_mode:{tdd:{nr_freq_info:{nr_ar_fcn:4 sulInformation:{sul_ar_fcn:8 sul_transmission_bandwidth:{nrscs:SCS120 ncnrb:NRB121}} frequency_bands:{nr_frequency_band:7 supported_sul_bands:3}} transmission_bandwidth:{nrscs:SCS15 ncnrb:NRB132}}}} nr_neighbour_infos:{nr_pci:44 nr_cgi:\"1e3f27:1f2e3d4ff0\" nr_mode:TDD choice_nr_mode:{tdd:{ar_fcn_nr_freq_info:{nr_ar_fcn:1 sulInformation:{sul_ar_fcn:2 sul_transmission_bandwidth:{nrscs:SCS15 ncnrb:NRB11}} frequency_bands:{nr_frequency_band:22 supported_sul_bands:11}}}}}]", /* E2AP-PDU: successfulOutcome_t @@ -343,7 +344,7 @@ func TestUnpackEndcX2SetupResponseAndExtract(t *testing.T) { { key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "4a952a0a"}, - gnb: "CONNECTED [served_nr_cell_information: > dl_freq_info: > ul_transmission_bandwidth: dl_transmission_bandwidth: > > > nr_neighbour_infos: > dlar_fcn_freq_info: > > > > ]", + gnb: "CONNECTED [served_nr_cell_information:{nr_pci:5 cell_id:\"1e3f27:1f2e3d4ff0\" served_plmns:\"3e4e5e\" nr_mode:FDD choice_nr_mode:{fdd:{ul_freq_info:{nr_ar_fcn:5 frequency_bands:{nr_frequency_band:44 supported_sul_bands:33}} dl_freq_info:{nr_ar_fcn:1 frequency_bands:{nr_frequency_band:22 supported_sul_bands:11}} ul_transmission_bandwidth:{nrscs:SCS120 ncnrb:NRB11} dl_transmission_bandwidth:{nrscs:SCS15 ncnrb:NRB135}}}} nr_neighbour_infos:{nr_pci:44 nr_cgi:\"1e3f27:1f2e3d4ff0\" nr_mode:FDD choice_nr_mode:{fdd:{ular_fcn_freq_info:{nr_ar_fcn:5 frequency_bands:{nr_frequency_band:22 supported_sul_bands:11}} dlar_fcn_freq_info:{nr_ar_fcn:1 frequency_bands:{nr_frequency_band:22 supported_sul_bands:11}}}}}]", /* E2AP-PDU: successfulOutcome_t @@ -433,7 +434,7 @@ func TestUnpackEndcX2SetupResponseAndExtract(t *testing.T) { { key: &entities.GlobalNbId{PlmnId: "04a5c1", NbId: "4fc52bff"}, - gnb: "CONNECTED [served_nr_cell_information: > frequency_bands: > transmission_bandwidth: > > > nr_neighbour_infos: > frequency_bands: > > > > nr_neighbour_infos: > frequency_bands: > > > > ]", + gnb: "CONNECTED [served_nr_cell_information:{nr_pci:9 cell_id:\"aeafa7:2a3e3b4cd0\" stac5g:\"7d4773\" configured_stac:\"477f\" served_plmns:\"7e7e7e\" nr_mode:TDD choice_nr_mode:{tdd:{nr_freq_info:{nr_ar_fcn:8 sulInformation:{sul_ar_fcn:9 sul_transmission_bandwidth:{nrscs:SCS15 ncnrb:NRB121}} frequency_bands:{nr_frequency_band:22 supported_sul_bands:11}} transmission_bandwidth:{nrscs:SCS60 ncnrb:NRB18}}}} nr_neighbour_infos:{nr_pci:44 nr_cgi:\"5a5ff1:2a3e3b4cd0\" nr_mode:TDD choice_nr_mode:{tdd:{ar_fcn_nr_freq_info:{nr_ar_fcn:5 sulInformation:{sul_ar_fcn:6 sul_transmission_bandwidth:{nrscs:SCS30 ncnrb:NRB18}} frequency_bands:{nr_frequency_band:4 supported_sul_bands:3}}}}} nr_neighbour_infos:{nr_pci:9 nr_cgi:\"5d5caa:af3e354ac0\" nr_mode:TDD choice_nr_mode:{tdd:{ar_fcn_nr_freq_info:{nr_ar_fcn:7 sulInformation:{sul_ar_fcn:8 sul_transmission_bandwidth:{nrscs:SCS120 ncnrb:NRB25}} frequency_bands:{nr_frequency_band:3 supported_sul_bands:1}}}}}]", /* E2AP-PDU: successfulOutcome_t @@ -602,8 +603,13 @@ func TestUnpackEndcX2SetupResponseAndExtract(t *testing.T) { nb.ConnectionStatus = entities.ConnectionStatus_CONNECTED nb.Configuration = &entities.NodebInfo_Gnb{Gnb: gnb} gnbStr := fmt.Sprintf("%s %s", nb.ConnectionStatus, gnb.ServedNrCells) - if !strings.EqualFold(gnbStr, tc.gnb) { - t.Errorf("want: enb=%s, got: %s", tc.gnb, gnbStr) + + space := regexp.MustCompile(`\s+`) + s1 := space.ReplaceAllString(gnbStr, " ") + s2 := space.ReplaceAllString(tc.gnb," ") + + if !strings.EqualFold(s1, s2) { + t.Errorf("want: [%s], got: [%s]", tc.gnb, gnbStr) } } diff --git a/E2Manager/converters/x2_setup_failure_response_converter_test.go b/E2Manager/converters/x2_setup_failure_response_converter_test.go index 54a1f53..3f4cebd 100644 --- a/E2Manager/converters/x2_setup_failure_response_converter_test.go +++ b/E2Manager/converters/x2_setup_failure_response_converter_test.go @@ -25,6 +25,7 @@ import ( "e2mgr/logger" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "regexp" "strings" "testing" ) @@ -42,7 +43,7 @@ func TestUnpackX2SetupFailureResponseAndExtract(t *testing.T) { failure error }{ { - response: "CONNECTED_SETUP_FAILED network_layer_cause:HANDOVER_DESIRABLE_FOR_RADIO_REASONS time_to_wait:V1S criticality_diagnostics: > ", + response: "CONNECTED_SETUP_FAILED network_layer_cause:HANDOVER_DESIRABLE_FOR_RADIO_REASONS time_to_wait:V1S criticality_diagnostics:{procedure_code:33 triggering_message:UNSUCCESSFUL_OUTCOME procedure_criticality:NOTIFY information_element_criticality_diagnostics:{ie_criticality:REJECT ie_id:128 type_of_error:MISSING}}", /* E2AP-PDU: unsuccessfulOutcome_t @@ -74,7 +75,7 @@ func TestUnpackX2SetupFailureResponseAndExtract(t *testing.T) { */ packedPdu: "4006001a0000030005400200000016400100001140087821a00000008040"}, { - response: "CONNECTED_SETUP_FAILED transport_layer_cause:TRANSPORT_RESOURCE_UNAVAILABLE criticality_diagnostics: > ", + response: "CONNECTED_SETUP_FAILED transport_layer_cause:TRANSPORT_RESOURCE_UNAVAILABLE criticality_diagnostics:{procedure_code:33 triggering_message:UNSUCCESSFUL_OUTCOME procedure_criticality:NOTIFY information_element_criticality_diagnostics:{ie_criticality:REJECT ie_id:128 type_of_error:MISSING}}", /* E2AP-PDU: unsuccessfulOutcome_t @@ -102,7 +103,7 @@ func TestUnpackX2SetupFailureResponseAndExtract(t *testing.T) { */ packedPdu: "400600140000020005400120001140087821a00000008040"}, { - response: "CONNECTED_SETUP_FAILED protocol_cause:ABSTRACT_SYNTAX_ERROR_IGNORE_AND_NOTIFY criticality_diagnostics: > ", + response: "CONNECTED_SETUP_FAILED protocol_cause:ABSTRACT_SYNTAX_ERROR_IGNORE_AND_NOTIFY criticality_diagnostics:{triggering_message:UNSUCCESSFUL_OUTCOME procedure_criticality:NOTIFY information_element_criticality_diagnostics:{ie_criticality:REJECT ie_id:128 type_of_error:MISSING}}", /* E2AP-PDU: unsuccessfulOutcome_t @@ -130,7 +131,7 @@ func TestUnpackX2SetupFailureResponseAndExtract(t *testing.T) { packedPdu: "400600130000020005400144001140073a800000008040"}, { - response: "CONNECTED_SETUP_FAILED miscellaneous_cause:UNSPECIFIED criticality_diagnostics: > ", + response: "CONNECTED_SETUP_FAILED miscellaneous_cause:UNSPECIFIED criticality_diagnostics:{procedure_criticality:NOTIFY information_element_criticality_diagnostics:{ie_criticality:REJECT ie_id:128 type_of_error:MISSING}}", /* E2AP-PDU: unsuccessfulOutcome_t @@ -157,7 +158,7 @@ func TestUnpackX2SetupFailureResponseAndExtract(t *testing.T) { packedPdu: "400600120000020005400168001140061a0000008040"}, { - response: "CONNECTED_SETUP_FAILED miscellaneous_cause:UNSPECIFIED criticality_diagnostics: information_element_criticality_diagnostics: > ", + response: "CONNECTED_SETUP_FAILED miscellaneous_cause:UNSPECIFIED criticality_diagnostics:{information_element_criticality_diagnostics:{ie_criticality:REJECT ie_id:128 type_of_error:MISSING} information_element_criticality_diagnostics:{ie_criticality:NOTIFY ie_id:255 type_of_error:NOT_UNDERSTOOD}}", /* E2AP-PDU: unsuccessfulOutcome_t @@ -188,7 +189,7 @@ func TestUnpackX2SetupFailureResponseAndExtract(t *testing.T) { { - response: "CONNECTED_SETUP_FAILED miscellaneous_cause:UNSPECIFIED criticality_diagnostics: ", + response: "CONNECTED_SETUP_FAILED miscellaneous_cause:UNSPECIFIED criticality_diagnostics:{procedure_code:33}", /* E2AP-PDU: unsuccessfulOutcome_t @@ -210,7 +211,7 @@ func TestUnpackX2SetupFailureResponseAndExtract(t *testing.T) { packedPdu: "4006000e0000020005400168001140024021"}, { - response: "CONNECTED_SETUP_FAILED miscellaneous_cause:UNSPECIFIED ", + response: "CONNECTED_SETUP_FAILED miscellaneous_cause:UNSPECIFIED", /* E2AP-PDU: unsuccessfulOutcome_t @@ -226,7 +227,7 @@ func TestUnpackX2SetupFailureResponseAndExtract(t *testing.T) { */ packedPdu: "400600080000010005400168"}, { - response: "CONNECTED_SETUP_FAILED network_layer_cause:HANDOVER_DESIRABLE_FOR_RADIO_REASONS time_to_wait:V1S criticality_diagnostics: > ", + response: "CONNECTED_SETUP_FAILED network_layer_cause:HANDOVER_DESIRABLE_FOR_RADIO_REASONS time_to_wait:V1S criticality_diagnostics:{procedure_code:33 triggering_message:UNSUCCESSFUL_OUTCOME procedure_criticality:NOTIFY information_element_criticality_diagnostics:{ie_criticality:REJECT ie_id:128 type_of_error:MISSING}}", /* E2AP-PDU: unsuccessfulOutcome_t @@ -294,8 +295,13 @@ func TestUnpackX2SetupFailureResponseAndExtract(t *testing.T) { nb.SetupFailure = response nb.FailureType = entities.Failure_X2_SETUP_FAILURE respStr := fmt.Sprintf("%s %s", nb.ConnectionStatus, response) - if !strings.EqualFold(respStr, tc.response) { - t.Errorf("want: response=[%s], got: [%s]", tc.response, respStr) + + space := regexp.MustCompile(`\s+`) + s1 := space.ReplaceAllString(respStr, " ") + s2 := space.ReplaceAllString(tc.response," ") + + if !strings.EqualFold(s1, s2) { + t.Errorf("want: [%s], got: [%s]", tc.response, respStr) } } diff --git a/E2Manager/converters/x2_setup_response_converter.go b/E2Manager/converters/x2_setup_response_converter.go index 2ce50b4..e98523f 100644 --- a/E2Manager/converters/x2_setup_response_converter.go +++ b/E2Manager/converters/x2_setup_response_converter.go @@ -44,6 +44,8 @@ const ( maxnoofNeighbours = 512 ) +const Format = "%02x:%02x" + type X2SetupResponseConverter struct { logger *logger.Logger } @@ -293,7 +295,7 @@ func getServedCellsNeighbour_Info(neighbour_Information *C.Neighbour_Information //pLMN_Identity:eUTRANcellIdentifier plmnId := C.GoBytes(unsafe.Pointer(member.eCGI.pLMN_Identity.buf), C.int(member.eCGI.pLMN_Identity.size)) eUTRANcellIdentifier := C.GoBytes(unsafe.Pointer(member.eCGI.eUTRANcellIdentifier.buf), C.int(member.eCGI.eUTRANcellIdentifier.size)) - neighbourInfo := &entities.NeighbourInformation{Ecgi: fmt.Sprintf("%02x:%02x", plmnId, eUTRANcellIdentifier)} + neighbourInfo := &entities.NeighbourInformation{Ecgi: fmt.Sprintf(Format, plmnId, eUTRANcellIdentifier)} neighbourInfo.Pci = uint32(member.pCI) @@ -334,7 +336,7 @@ func getServedCells(servedCellsIE *C.ServedCells_t) ([]*entities.ServedCellInfo, //pLMN_Identity:eUTRANcellIdentifier plmnId := C.GoBytes(unsafe.Pointer(member.servedCellInfo.cellId.pLMN_Identity.buf), C.int(member.servedCellInfo.cellId.pLMN_Identity.size)) eUTRANcellIdentifier := C.GoBytes(unsafe.Pointer(member.servedCellInfo.cellId.eUTRANcellIdentifier.buf), C.int(member.servedCellInfo.cellId.eUTRANcellIdentifier.size)) - servedCellInfo.CellId = fmt.Sprintf("%02x:%02x", plmnId, eUTRANcellIdentifier) + servedCellInfo.CellId = fmt.Sprintf(Format, plmnId, eUTRANcellIdentifier) servedCellInfo.Tac = fmt.Sprintf("%02x", C.GoBytes(unsafe.Pointer(member.servedCellInfo.tAC.buf), C.int(member.servedCellInfo.tAC.size))) @@ -388,7 +390,7 @@ func getGUGroupIDList(guGroupIDList *C.GUGroupIDList_t) []string { for _, guGroupID := range guGroupIDList_slice { plmnId := C.GoBytes(unsafe.Pointer(guGroupID.pLMN_Identity.buf), C.int(guGroupID.pLMN_Identity.size)) mME_Group_ID := C.GoBytes(unsafe.Pointer(guGroupID.mME_Group_ID.buf), C.int(guGroupID.mME_Group_ID.size)) - ids = append(ids, fmt.Sprintf("%02x:%02x", plmnId, mME_Group_ID)) + ids = append(ids, fmt.Sprintf(Format, plmnId, mME_Group_ID)) } } diff --git a/E2Manager/converters/x2_setup_response_converter_test.go b/E2Manager/converters/x2_setup_response_converter_test.go index 8161747..739a412 100644 --- a/E2Manager/converters/x2_setup_response_converter_test.go +++ b/E2Manager/converters/x2_setup_response_converter_test.go @@ -25,6 +25,7 @@ import ( "e2mgr/logger" "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "regexp" "strings" "testing" ) @@ -44,7 +45,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { }{ { key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD ] []", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD] []", /* X2AP-PDU: successfulOutcome_t @@ -82,7 +83,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { packedPdu: "2006002a000002001500080002f82900007a8000140017000000630002f8290007ab50102002f829000001000133"}, { key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode: > eutra_mode:FDD ] []", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode:{fdd:{ulear_fcn:2 dlear_fcn:3 ul_transmission_bandwidth:BW75 dl_transmission_bandwidth:BW75}} eutra_mode:FDD] []", /* X2AP-PDU: successfulOutcome_t @@ -136,7 +137,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { packedPdu: "20060043000002001500080002f82900007a8000140030010000630002f8290007ab50102002f8290000010001330000640002f9290007ac50203202f82902f929000002000344"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD ] []", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:2 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD] []", /* X2AP-PDU: successfulOutcome_t @@ -178,7 +179,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { */ packedPdu: "20060033000002001500080002f82900007a8000140020000000630002f8290007ab50102002f8291000010001330000005f0003800102"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD ] [02f729:0203 02f929:0304]", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD] [02f729:0203 02f929:0304]", /* X2AP-PDU: successfulOutcome_t @@ -226,7 +227,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { packedPdu: "2006003a000003001500080002f82900007a8000140017000000630002f8290007ab50102002f8290000010001330018000c1002f72902030002f9290304"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > > eutra_mode:TDD ] []", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{tdd:{ear_fcn:1 transmission_bandwidth:BW50 subframe_assignment:SA2 special_subframe_info:{special_subframe_patterns:SSP4 cyclic_prefix_dl:NORMAL cyclic_prefix_ul:EXTENDED}}} eutra_mode:TDD] []", /* X2AP-PDU: successfulOutcome_t @@ -266,7 +267,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { */ packedPdu: "2006002a000002001500080002f82900007a8000140017000000630002f8290007ab50102002f829400001320820"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: additional_special_subframe_info: > > eutra_mode:TDD ] []", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{tdd:{ear_fcn:1 transmission_bandwidth:BW50 subframe_assignment:SA2 special_subframe_info:{special_subframe_patterns:SSP4 cyclic_prefix_dl:EXTENDED cyclic_prefix_ul:NORMAL} additional_special_subframe_info:{additional_special_subframe_patterns:SSP9 cyclic_prefix_dl:NORMAL cyclic_prefix_ul:EXTENDED}}} eutra_mode:TDD] []", /* X2AP-PDU: successfulOutcome_t @@ -315,7 +316,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { packedPdu: "20060032000002001500080002f82900007a800014001f000000630002f8290007ab50102002f8295000013208800000006140021220"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > > eutra_mode:TDD ] []", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{tdd:{ear_fcn:2 transmission_bandwidth:BW50 subframe_assignment:SA2 special_subframe_info:{special_subframe_patterns:SSP4 cyclic_prefix_dl:EXTENDED cyclic_prefix_ul:NORMAL}}} eutra_mode:TDD] []", /* X2AP-PDU: successfulOutcome_t @@ -361,7 +362,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { packedPdu: "20060033000002001500080002f82900007a8000140020000000630002f8290007ab50102002f8295000013208800000005e0003800102"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: additional_special_subframe_extension_info: > > eutra_mode:TDD ] []", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{tdd:{ear_fcn:1 transmission_bandwidth:BW50 subframe_assignment:SA2 special_subframe_info:{special_subframe_patterns:SSP4 cyclic_prefix_dl:EXTENDED cyclic_prefix_ul:NORMAL} additional_special_subframe_extension_info:{additional_special_subframe_patterns_extension:SSP10 cyclic_prefix_dl:NORMAL cyclic_prefix_ul:NORMAL}}} eutra_mode:TDD] []", /* X2AP-PDU: successfulOutcome_t @@ -410,7 +411,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { packedPdu: "20060031000002001500080002f82900007a800014001e000000630002f8290007ab50102002f829500001320880000000b3400100"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: additional_special_subframe_info: additional_special_subframe_extension_info: > > eutra_mode:TDD ] []", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{tdd:{ear_fcn:2 transmission_bandwidth:BW50 subframe_assignment:SA2 special_subframe_info:{special_subframe_patterns:SSP4 cyclic_prefix_dl:EXTENDED cyclic_prefix_ul:NORMAL} additional_special_subframe_info:{additional_special_subframe_patterns:SSP9 cyclic_prefix_dl:NORMAL cyclic_prefix_ul:EXTENDED} additional_special_subframe_extension_info:{additional_special_subframe_patterns_extension:SSP10 cyclic_prefix_dl:NORMAL cyclic_prefix_ul:NORMAL}}} eutra_mode:TDD] []", /* X2AP-PDU: successfulOutcome_t @@ -471,7 +472,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { packedPdu: "2006003e000002001500080002f82900007a800014002b000000630002f8290007ab50102002f829500001320880000200b3400100006140021220005e0003800102"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80b0"}, - enb: "CONNECTED HOME_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD number_of_antenna_ports:AN1 pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode: > eutra_mode:FDD ] []", + enb: "CONNECTED HOME_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD number_of_antenna_ports:AN1 pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode:{fdd:{ulear_fcn:2 dlear_fcn:3 ul_transmission_bandwidth:BW75 dl_transmission_bandwidth:BW75}} eutra_mode:FDD] []", /* X2AP-PDU: successfulOutcome_t @@ -531,7 +532,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { packedPdu: "2006004b000002001500090002f82940007a80b000140037010800630002f8290007ab50102002f829000001000133000000294001000000640002f9290007ac50203202f82902f929000002000344"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a40"}, - enb: "CONNECTED SHORT_MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD number_of_antenna_ports:AN1 pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode: > eutra_mode:FDD prach_configuration: ] []", + enb: "CONNECTED SHORT_MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD number_of_antenna_ports:AN1 pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode:{fdd:{ulear_fcn:2 dlear_fcn:3 ul_transmission_bandwidth:BW75 dl_transmission_bandwidth:BW75}} eutra_mode:FDD prach_configuration:{root_sequence_index:15 zero_correlation_zone_configuration:7 high_speed_flag:true prach_frequency_offset:30}] []", /* X2AP-PDU: successfulOutcome_t @@ -600,7 +601,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { packedPdu: "20060056000002001500090002f8298003007a4000140042010800630002f8290007ab50102002f829000001000133000000294001000800640002f9290007ac50203202f82902f92900000200034400000037400500000f79e0"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a40"}, - enb: "CONNECTED SHORT_MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD number_of_antenna_ports:AN1 pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode: > eutra_mode:FDD mbsfn_subframe_infos: ] []", + enb: "CONNECTED SHORT_MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD number_of_antenna_ports:AN1 pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode:{fdd:{ulear_fcn:2 dlear_fcn:3 ul_transmission_bandwidth:BW75 dl_transmission_bandwidth:BW75}} eutra_mode:FDD mbsfn_subframe_infos:{radioframe_allocation_period:N8 radioframe_allocation_offset:3 subframe_allocation:\"28\" subframe_allocation_type:ONE_FRAME}] []", /* X2AP-PDU: successfulOutcome_t @@ -668,7 +669,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { */ packedPdu: "20060054000002001500090002f8298003007a4000140040010800630002f8290007ab50102002f829000001000133000000294001000800640002f9290007ac50203202f82902f929000002000344000000384003019850"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a40"}, - enb: "CONNECTED SHORT_MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD number_of_antenna_ports:AN1 mbsfn_subframe_infos: pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode: > eutra_mode:FDD ] []", + enb: "CONNECTED SHORT_MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD number_of_antenna_ports:AN1 mbsfn_subframe_infos:{radioframe_allocation_period:N8 radioframe_allocation_offset:3 subframe_allocation:\"28\" subframe_allocation_type:ONE_FRAME} pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode:{fdd:{ulear_fcn:2 dlear_fcn:3 ul_transmission_bandwidth:BW75 dl_transmission_bandwidth:BW75}} eutra_mode:FDD] []", /* X2AP-PDU: successfulOutcome_t @@ -735,7 +736,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { */ packedPdu: "20060052000002001500090002f8298003007a400014003e010800630002f8290007ab50102002f82900000100013300010029400100003840030198500000640002f9290007ac50203202f82902f929000002000344"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a40"}, - enb: "CONNECTED SHORT_MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD number_of_antenna_ports:AN1 prach_configuration: pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode: > eutra_mode:FDD ] []", + enb: "CONNECTED SHORT_MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD number_of_antenna_ports:AN1 prach_configuration:{root_sequence_index:15 zero_correlation_zone_configuration:7 high_speed_flag:true prach_frequency_offset:30} pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode:{fdd:{ulear_fcn:2 dlear_fcn:3 ul_transmission_bandwidth:BW75 dl_transmission_bandwidth:BW75}} eutra_mode:FDD] []", /* X2AP-PDU: successfulOutcome_t @@ -801,7 +802,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { */ packedPdu: "20060054000002001500090002f8298003007a4000140040010800630002f8290007ab50102002f829000001000133000100294001000037400500000f79e00000640002f9290007ac50203202f82902f929000002000344"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a08"}, - enb: "CONNECTED LONG_MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD prach_configuration: pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode: > eutra_mode:FDD ] []", + enb: "CONNECTED LONG_MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD prach_configuration:{root_sequence_index:15 zero_correlation_zone_configuration:7 high_speed_flag:true prach_frequency_offset:30 prach_configuration_index:60} pci:100 cell_id:\"02f929:0007ac50\" tac:\"0203\" broadcast_plmns:\"02f829\" broadcast_plmns:\"02f929\" choice_eutra_mode:{fdd:{ulear_fcn:2 dlear_fcn:3 ul_transmission_bandwidth:BW75 dl_transmission_bandwidth:BW75}} eutra_mode:FDD] []", /* X2AP-PDU: successfulOutcome_t @@ -866,7 +867,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { packedPdu: "20060050000002001500090002f829c003007a080014003c010800630002f8290007ab50102002f82900000100013300000037400640000f79ef000000640002f9290007ac50203202f82902f929000002000344"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD csg_id:\"0007aba0\" freq_band_indicator_priority:BROADCASTED bandwidth_reduced_si:SCHEDULED ] []", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD csg_id:\"0007aba0\" freq_band_indicator_priority:BROADCASTED bandwidth_reduced_si:SCHEDULED] []", /* X2AP-PDU: successfulOutcome_t @@ -917,7 +918,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { packedPdu: "2006003e000002001500080002f82900007a800014002b000800630002f8290007ab50102002f8290000010001330002004640040007aba000a040014000b4400100"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD mbms_service_area_identities:\"02f8\" mbms_service_area_identities:\"03f9\" multiband_infos:1 multiband_infos:2 multiband_infos:3 freq_band_indicator_priority:NOT_BROADCASTED ] []", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD mbms_service_area_identities:\"02f8\" mbms_service_area_identities:\"03f9\" multiband_infos:1 multiband_infos:2 multiband_infos:3 freq_band_indicator_priority:NOT_BROADCASTED] []", /* X2AP-PDU: successfulOutcome_t @@ -975,7 +976,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { */ packedPdu: "20060044000002001500080002f82900007a8000140031000800630002f8290007ab50102002f8290000010001330002004f40050102f803f900a040010000544006200000010002"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD neighbour_infos: neighbour_infos: ] []", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD neighbour_infos:{ecgi:\"02f829:0007ab50\" pci:99 ear_fcn:1} neighbour_infos:{ecgi:\"03f930:0008bc50\" pci:100 ear_fcn:2}] []", /* X2AP-PDU: successfulOutcome_t @@ -1026,7 +1027,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { packedPdu: "20060044000002001500080002f82900007a8000140031004000630002f8290007ab50102002f82900000100013300020002f8290007ab50006300010003f9300008bc5000640002"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD neighbour_infos: neighbour_infos: ] []", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD neighbour_infos:{ecgi:\"02f829:0007ab50\" pci:99 ear_fcn:1 tac:\"0102\"} neighbour_infos:{ecgi:\"03f930:0008bc50\" pci:100 ear_fcn:3}] []", /* X2AP-PDU: successfulOutcome_t @@ -1087,7 +1088,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { packedPdu: "20060055000002001500080002f82900007a8000140042004000630002f8290007ab50102002f82900000100013300024002f8290007ab50006300010000004c400201024003f9300008bc50006400020000005e0003800103"}, {key: &entities.GlobalNbId{PlmnId: "02f829", NbId: "007a80"}, - enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode: > eutra_mode:FDD neighbour_infos: neighbour_infos: ] []", + enb: "CONNECTED MACRO_ENB [pci:99 cell_id:\"02f829:0007ab50\" tac:\"0102\" broadcast_plmns:\"02f829\" choice_eutra_mode:{fdd:{ulear_fcn:1 dlear_fcn:1 ul_transmission_bandwidth:BW50 dl_transmission_bandwidth:BW50}} eutra_mode:FDD neighbour_infos:{ecgi:\"02f829:0007ab50\" pci:99 ear_fcn:1 tac:\"0102\"} neighbour_infos:{ecgi:\"03f930:0008bc50\" pci:100 ear_fcn:3}] []", /* X2AP-PDU: successfulOutcome_t @@ -1146,7 +1147,7 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { EARFCNExtension = 0x3 */ packedPdu: "20060055000002001500080002f82900007a8000140042004000630002f8290007ab50102002f82900000100013300024002f8290007ab50006300010000004c400201024003f9300008bc50006400020000005e0003800103", - /*failure: fmt.Errorf("getAtom for path [successfulOutcome_t X2SetupResponse protocolIEs_t ProtocolIE_Container_elm GlobalENB-ID pLMN_Identity_t] failed, rc = 2" /NO_SPACE_LEFT),*/ }, + /*failure: fmt.Errorf("getAtom for path [successfulOutcome_t X2SetupResponse protocolIEs_t ProtocolIE_Container_elm GlobalENB-ID pLMN_Identity_t] failed, rc = 2" /NO_SPACE_LEFT),*/}, } converter := NewX2SetupResponseConverter(logger) @@ -1191,7 +1192,14 @@ func TestUnpackX2SetupResponseAndExtract(t *testing.T) { nb.ConnectionStatus = entities.ConnectionStatus_CONNECTED nb.Configuration = &entities.NodebInfo_Enb{Enb: enb} embStr := fmt.Sprintf("%s %s %s %s", nb.ConnectionStatus, enb.EnbType, enb.ServedCells, enb.GuGroupIds) - if !strings.EqualFold(embStr, tc.enb) { + + space := regexp.MustCompile(`\s+`) + s1 := space.ReplaceAllString(embStr, " ") + s2 := space.ReplaceAllString(tc.enb," ") + + + + if !strings.EqualFold(s1, s2) { t.Errorf("want: enb=%s, got: %s", tc.enb, embStr) } } diff --git a/E2Manager/go.mod b/E2Manager/go.mod index 0339b3c..3be5810 100644 --- a/E2Manager/go.mod +++ b/E2Manager/go.mod @@ -1,13 +1,13 @@ module e2mgr require ( - gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.35 - gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.35 - gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.35 + gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.42 + gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.42 + gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.42 gerrit.o-ran-sc.org/r/ric-plt/sdlgo v0.5.2 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.4 + github.com/golang/protobuf v1.4.2 github.com/gorilla/mux v1.7.0 github.com/magiconair/properties v1.8.1 github.com/pelletier/go-toml v1.5.0 // indirect @@ -23,7 +23,6 @@ require ( google.golang.org/appengine v1.6.1 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/yaml.v2 v2.2.8 - k8s.io/apimachinery v0.17.0 k8s.io/client-go v0.17.0 ) diff --git a/E2Manager/go.sum b/E2Manager/go.sum index 4bb1c2a..5756914 100644 --- a/E2Manager/go.sum +++ b/E2Manager/go.sum @@ -1,12 +1,12 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.35 h1:TGXHb4DNY8on+ej4S9VUnk2HibIC/5chDy64OE+bQBQ= -gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.35/go.mod h1:QJ1uPPZosGbhxUWpUpeM5fLqFHdnWTrVnvW2DgyOCes= -gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.35 h1:tkM3yE8UzmuH4nf9TqAmiNBSuIZ2CtcMRH2eBIYIzpQ= -gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.35/go.mod h1:G+4sUBMbLfQ+RrGS65U15tKmbnP+/1b5oLTPmMfyfT4= -gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.35 h1:LcxnUUDwsCzYEISKmkjkyYfg/lnLt8ofkPiGK69vNIA= -gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.35/go.mod h1:2bSaXTpECbZieB8bMnubTqMwF3n+mMBxlTaAXvcduNg= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.42 h1:k3Qpj1BiBPgu+HnMJl3TAi6MlcNwxgij3nY8Kw4NYW0= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/common v1.0.42/go.mod h1:QJ1uPPZosGbhxUWpUpeM5fLqFHdnWTrVnvW2DgyOCes= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.42 h1:EPdPmvU3iXgB4b91lNN8wl+WSpXCLi7gDm4yJTOrl/o= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities v1.0.42/go.mod h1:YaQ+XEI4PcAoISxp9wUpUr2TP0J7JihpQTD0G1Lpd4A= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.42 h1:PyAnsgqXVV3w+1utUrtvh1KfxuVMCYvUXGYOFarChto= +gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/reader v1.0.42/go.mod h1:K0P3Xh2NXHCwdIDY47IxeElCBVZdT4KqapPBpS7g3JU= gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.5.2 h1:UK7awyRKIkVdokWvvkYvazlg3EWIfMnIqCcJxTnLlDA= gerrit.o-ran-sc.org/r/ric-plt/sdlgo.git v0.5.2/go.mod h1:y2WhrCvdLkAKdH+ySdHSOSehACJkTMyZghCGVcqoZzc= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= @@ -81,14 +81,23 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y 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/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= 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/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -305,6 +314,8 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -317,6 +328,13 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= 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= diff --git a/E2Manager/handlers/httpmsghandlers/set_general_configuration_handler.go b/E2Manager/handlers/httpmsghandlers/set_general_configuration_handler.go new file mode 100644 index 0000000..851dab1 --- /dev/null +++ b/E2Manager/handlers/httpmsghandlers/set_general_configuration_handler.go @@ -0,0 +1,68 @@ +// +// 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 httpmsghandlers + +import "C" +import ( + "e2mgr/e2managererrors" + "e2mgr/logger" + "e2mgr/models" + "e2mgr/services" +) + +type SetGeneralConfigurationHandler struct { + rnibDataService services.RNibDataService + logger *logger.Logger +} + +func NewSetGeneralConfigurationHandler(logger *logger.Logger, rnibDataService services.RNibDataService) *SetGeneralConfigurationHandler { + return &SetGeneralConfigurationHandler{ + logger: logger, + rnibDataService: rnibDataService, + } +} + +func (h *SetGeneralConfigurationHandler) Handle(request models.Request) (models.IResponse, error) { + h.logger.Infof("#SetGeneralConfigurationHandler.Handle - handling set general parameters") + + configuration := request.(models.GeneralConfigurationRequest) + + existingConfig, err := h.rnibDataService.GetGeneralConfiguration() + + if err != nil { + h.logger.Errorf("#SetGeneralConfigurationHandler.Handle - Error fetching general configuration from rNib: %s", err) + return nil, e2managererrors.NewRnibDbError() + } + + if existingConfig.EnableRic != configuration.EnableRic { + + existingConfig.EnableRic = configuration.EnableRic + err := h.rnibDataService.SaveGeneralConfiguration(existingConfig) + + if err != nil { + h.logger.Errorf("#SetGeneralConfigurationHandler.Handle - failed to save general configuration in RNIB. error: %s", err) + return nil, e2managererrors.NewRnibDbError() + } + + } + response := &models.GeneralConfigurationResponse{EnableRic: configuration.EnableRic} + + return response, nil +} diff --git a/E2Manager/handlers/httpmsghandlers/set_general_configuration_handler_test.go b/E2Manager/handlers/httpmsghandlers/set_general_configuration_handler_test.go new file mode 100644 index 0000000..284f922 --- /dev/null +++ b/E2Manager/handlers/httpmsghandlers/set_general_configuration_handler_test.go @@ -0,0 +1,102 @@ +// +// 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 httpmsghandlers + +import ( + "e2mgr/configuration" + "e2mgr/mocks" + "e2mgr/models" + "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/assert" + "testing" +) + +func setupSetGeneralConfigurationHandlerTest(t *testing.T) (*SetGeneralConfigurationHandler, *mocks.RnibReaderMock, *mocks.RnibWriterMock) { + log := initLog(t) + config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3} + readerMock := &mocks.RnibReaderMock{} + writerMock := &mocks.RnibWriterMock{} + rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock) + handler := NewSetGeneralConfigurationHandler(log, rnibDataService) + return handler, readerMock, writerMock +} + +func TestSetGeneralConfigurationFalse_Success(t *testing.T) { + handler, readerMock, writerMock := setupSetGeneralConfigurationHandlerTest(t) + + configuration := &entities.GeneralConfiguration{EnableRic: true} + readerMock.On("GetGeneralConfiguration").Return(configuration, nil) + + updated := &entities.GeneralConfiguration{EnableRic: false} + writerMock.On("SaveGeneralConfiguration", updated).Return(nil) + + response, err := handler.Handle(models.GeneralConfigurationRequest{EnableRic: false}) + + assert.Nil(t, err) + assert.NotNil(t, response) + assert.IsType(t, &models.GeneralConfigurationResponse{}, response) +} + +func TestSetGeneralConfigurationTrue_Success(t *testing.T) { + handler, readerMock, writerMock := setupSetGeneralConfigurationHandlerTest(t) + + configuration := &entities.GeneralConfiguration{EnableRic: false} + readerMock.On("GetGeneralConfiguration").Return(configuration, nil) + + updated := &entities.GeneralConfiguration{EnableRic: true} + writerMock.On("SaveGeneralConfiguration", updated).Return(nil) + + response, err := handler.Handle(models.GeneralConfigurationRequest{EnableRic: true}) + + assert.Nil(t, err) + assert.NotNil(t, response) + assert.IsType(t, &models.GeneralConfigurationResponse{}, response) +} + +func TestSetGeneralConfigurationIgnore_Success(t *testing.T) { + handler, readerMock, _ := setupSetGeneralConfigurationHandlerTest(t) + + configuration := &entities.GeneralConfiguration{EnableRic: false} + readerMock.On("GetGeneralConfiguration").Return(configuration, nil) + + response, err := handler.Handle(models.GeneralConfigurationRequest{EnableRic: false}) + + assert.Nil(t, err) + assert.NotNil(t, response) + assert.IsType(t, &models.GeneralConfigurationResponse{}, response) +} + +func TestSetGeneralConfigurationHandlerRnibError(t *testing.T) { + handler, readerMock, writerMock := setupSetGeneralConfigurationHandlerTest(t) + + configuration := &entities.GeneralConfiguration{EnableRic: false} + readerMock.On("GetGeneralConfiguration").Return(configuration, nil) + + updated := &entities.GeneralConfiguration{EnableRic: true} + writerMock.On("SaveGeneralConfiguration", updated).Return(common.NewInternalError(errors.New("error"))) + + response, err := handler.Handle(models.GeneralConfigurationRequest{EnableRic: true}) + + assert.NotNil(t, err) + assert.Nil(t, response) +} diff --git a/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler.go b/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler.go index 7cd5458..7420a29 100644 --- a/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler.go +++ b/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler.go @@ -38,6 +38,11 @@ import ( "strings" ) +var ( + emptyTagsToReplaceToSelfClosingTags = []string{"reject", "ignore", "transport-resource-unavailable", "om-intervention", + "v60s", "v20s", "v10s", "v5s", "v2s", "v1s"} +) + type E2SetupRequestNotificationHandler struct { logger *logger.Logger config *configuration.Configuration @@ -47,8 +52,8 @@ type E2SetupRequestNotificationHandler struct { e2tAssociationManager *managers.E2TAssociationManager } -func NewE2SetupRequestNotificationHandler(logger *logger.Logger, config *configuration.Configuration, e2tInstancesManager managers.IE2TInstancesManager, rmrSender *rmrsender.RmrSender, rNibDataService services.RNibDataService, e2tAssociationManager *managers.E2TAssociationManager) E2SetupRequestNotificationHandler { - return E2SetupRequestNotificationHandler{ +func NewE2SetupRequestNotificationHandler(logger *logger.Logger, config *configuration.Configuration, e2tInstancesManager managers.IE2TInstancesManager, rmrSender *rmrsender.RmrSender, rNibDataService services.RNibDataService, e2tAssociationManager *managers.E2TAssociationManager) *E2SetupRequestNotificationHandler { + return &E2SetupRequestNotificationHandler{ logger: logger, config: config, e2tInstancesManager: e2tInstancesManager, @@ -58,10 +63,23 @@ func NewE2SetupRequestNotificationHandler(logger *logger.Logger, config *configu } } -func (h E2SetupRequestNotificationHandler) Handle(request *models.NotificationRequest) { +func (h *E2SetupRequestNotificationHandler) Handle(request *models.NotificationRequest) { ranName := request.RanName h.logger.Infof("#E2SetupRequestNotificationHandler.Handle - RAN name: %s - received E2_SETUP_REQUEST. Payload: %x", ranName, request.Payload) + generalConfiguration, err := h.rNibDataService.GetGeneralConfiguration() + + if err != nil { + h.logger.Errorf("#E2SetupRequestNotificationHandler.Handle - Failed retrieving e2m general configuration. error: %s", err) + return + } + + if !generalConfiguration.EnableRic { + cause := models.Cause{Misc: &models.CauseMisc{OmIntervention: &struct{}{}}} + h.handleUnsuccessfulResponse(ranName, request, cause) + return + } + setupRequest, e2tIpAddress, err := h.parseSetupRequest(request.Payload) if err != nil { h.logger.Errorf(err.Error()) @@ -104,7 +122,8 @@ func (h E2SetupRequestNotificationHandler) Handle(request *models.NotificationRe h.logger.Errorf("#E2SetupRequestNotificationHandler.Handle - RAN name: %s - failed to associate E2T to nodeB entity. Error: %s", ranName, err) if _, ok := err.(*e2managererrors.RoutingManagerError); ok { - h.handleUnsuccessfulResponse(nodebInfo, request) + cause := models.Cause{Transport: &models.CauseTransport{TransportResourceUnavailable: &struct{}{}}} + h.handleUnsuccessfulResponse(nodebInfo.RanName, request, cause) } return } @@ -112,7 +131,7 @@ func (h E2SetupRequestNotificationHandler) Handle(request *models.NotificationRe h.handleSuccessfulResponse(ranName, request, setupRequest) } -func (h E2SetupRequestNotificationHandler) handleNewRan(ranName string, e2tIpAddress string, setupRequest *models.E2SetupRequestMessage) (*entities.NodebInfo, error) { +func (h *E2SetupRequestNotificationHandler) handleNewRan(ranName string, e2tIpAddress string, setupRequest *models.E2SetupRequestMessage) (*entities.NodebInfo, error) { nodebInfo, err := h.buildNodebInfo(ranName, e2tIpAddress, setupRequest) @@ -132,13 +151,8 @@ func (h E2SetupRequestNotificationHandler) handleNewRan(ranName string, e2tIpAdd return nodebInfo, nil } -func (h E2SetupRequestNotificationHandler) setGnbFunctions(nodebInfo *entities.NodebInfo, setupRequest *models.E2SetupRequestMessage) error { - ranFunctions, err := setupRequest.ExtractRanFunctionsList() - - if err != nil { - h.logger.Errorf("#E2SetupRequestNotificationHandler.setGnbFunctions - RAN name: %s - failed to update nodebInfo entity. Error: %s", nodebInfo.GetRanName(), err) - return err - } +func (h *E2SetupRequestNotificationHandler) setGnbFunctions(nodebInfo *entities.NodebInfo, setupRequest *models.E2SetupRequestMessage) error { + ranFunctions := setupRequest.ExtractRanFunctionsList() if ranFunctions != nil { nodebInfo.GetGnb().RanFunctions = ranFunctions @@ -147,7 +161,7 @@ func (h E2SetupRequestNotificationHandler) setGnbFunctions(nodebInfo *entities.N return nil } -func (h E2SetupRequestNotificationHandler) handleExistingRan(ranName string, nodebInfo *entities.NodebInfo, setupRequest *models.E2SetupRequestMessage) error { +func (h *E2SetupRequestNotificationHandler) handleExistingRan(ranName string, nodebInfo *entities.NodebInfo, setupRequest *models.E2SetupRequestMessage) error { if nodebInfo.GetConnectionStatus() == entities.ConnectionStatus_SHUTTING_DOWN { h.logger.Errorf("#E2SetupRequestNotificationHandler.Handle - RAN name: %s, connection status: %s - nodeB entity in incorrect state", ranName, nodebInfo.ConnectionStatus) return errors.New("nodeB entity in incorrect state") @@ -157,31 +171,33 @@ func (h E2SetupRequestNotificationHandler) handleExistingRan(ranName string, nod return err } -func (h E2SetupRequestNotificationHandler) handleUnsuccessfulResponse(nodebInfo *entities.NodebInfo, req *models.NotificationRequest) { - failureResponse := models.NewE2SetupFailureResponseMessage(models.TimeToWaitEnum.V60s) +func (h *E2SetupRequestNotificationHandler) handleUnsuccessfulResponse(ranName string, req *models.NotificationRequest, cause models.Cause) { + failureResponse := models.NewE2SetupFailureResponseMessage(models.TimeToWaitEnum.V60s, cause) h.logger.Debugf("#E2SetupRequestNotificationHandler.handleUnsuccessfulResponse - E2_SETUP_RESPONSE has been built successfully %+v", failureResponse) responsePayload, err := xml.Marshal(&failureResponse.E2APPDU) if err != nil { - h.logger.Warnf("#E2SetupRequestNotificationHandler.handleUnsuccessfulResponse - RAN name: %s - Error marshalling RIC_E2_SETUP_RESP. Payload: %s", nodebInfo.RanName, responsePayload) + h.logger.Warnf("#E2SetupRequestNotificationHandler.handleUnsuccessfulResponse - RAN name: %s - Error marshalling RIC_E2_SETUP_RESP. Payload: %s", ranName, responsePayload) } responsePayload = replaceEmptyTagsWithSelfClosing(responsePayload) - msg := models.NewRmrMessage(rmrCgo.RIC_E2_SETUP_FAILURE, nodebInfo.RanName, responsePayload, req.TransactionId, req.GetMsgSrc()) - h.logger.Infof("#E2SetupRequestNotificationHandler.handleUnsuccessfulResponse - RAN name: %s - RIC_E2_SETUP_RESP message has been built successfully. Message: %x", nodebInfo.RanName, msg) + h.logger.Infof("#E2SetupRequestNotificationHandler.handleUnsuccessfulResponse - payload: %s", responsePayload) + msg := models.NewRmrMessage(rmrCgo.RIC_E2_SETUP_FAILURE, ranName, responsePayload, req.TransactionId, req.GetMsgSrc()) + h.logger.Infof("#E2SetupRequestNotificationHandler.handleUnsuccessfulResponse - RAN name: %s - RIC_E2_SETUP_RESP message has been built successfully. Message: %x", ranName, msg) _ = h.rmrSender.WhSend(msg) } -func (h E2SetupRequestNotificationHandler) handleSuccessfulResponse(ranName string, req *models.NotificationRequest, setupRequest *models.E2SetupRequestMessage) { +func (h *E2SetupRequestNotificationHandler) handleSuccessfulResponse(ranName string, req *models.NotificationRequest, setupRequest *models.E2SetupRequestMessage) { + + plmnId := buildPlmnId(h.config.GlobalRicId.Mcc, h.config.GlobalRicId.Mnc) - ricNearRtId, err := convertTo20BitString(h.config.GlobalRicId.RicNearRtId) + ricNearRtId, err := convertTo20BitString(h.config.GlobalRicId.RicId) if err != nil { - h.logger.Errorf("#E2SetupRequestNotificationHandler.handleSuccessfulResponse - RAN name: %s - failed to convert RicNearRtId value %s to 20 bit string . Error: %s", ranName, h.config.GlobalRicId.RicNearRtId, err) return } - successResponse := models.NewE2SetupSuccessResponseMessage(h.config.GlobalRicId.PlmnId, ricNearRtId, setupRequest) + successResponse := models.NewE2SetupSuccessResponseMessage(plmnId, ricNearRtId, setupRequest) h.logger.Debugf("#E2SetupRequestNotificationHandler.handleSuccessfulResponse - E2_SETUP_RESPONSE has been built successfully %+v", successResponse) responsePayload, err := xml.Marshal(&successResponse.E2APPDU) @@ -191,23 +207,42 @@ func (h E2SetupRequestNotificationHandler) handleSuccessfulResponse(ranName stri responsePayload = replaceEmptyTagsWithSelfClosing(responsePayload) + h.logger.Infof("#E2SetupRequestNotificationHandler.handleSuccessfulResponse - payload: %s", responsePayload) + msg := models.NewRmrMessage(rmrCgo.RIC_E2_SETUP_RESP, ranName, responsePayload, req.TransactionId, req.GetMsgSrc()) h.logger.Infof("#E2SetupRequestNotificationHandler.handleSuccessfulResponse - RAN name: %s - RIC_E2_SETUP_RESP message has been built successfully. Message: %x", ranName, msg) _ = h.rmrSender.Send(msg) } +func buildPlmnId(mmc string, mnc string) string { + var b strings.Builder + + b.WriteByte(mmc[1]) + b.WriteByte(mmc[0]) + if len(mnc) == 2 { + b.WriteString("F") + } else { + b.WriteByte(mnc[2]) + } + b.WriteByte(mmc[2]) + b.WriteByte(mnc[1]) + b.WriteByte(mnc[0]) + + return b.String() +} + func replaceEmptyTagsWithSelfClosing(responsePayload []byte) []byte { - responseString := strings.NewReplacer( - "", "", - "", "", - "", "", - "", "", - "", "", - "", "", - "", "", - "", "", - "", "", - ).Replace(string(responsePayload)) + + emptyTagVsSelfClosingTagPairs := make([]string, len(emptyTagsToReplaceToSelfClosingTags)*2) + + j := 0 + + for i := 0; i < len(emptyTagsToReplaceToSelfClosingTags); i++ { + emptyTagVsSelfClosingTagPairs[j] = fmt.Sprintf("<%[1]s>", emptyTagsToReplaceToSelfClosingTags[i]) + emptyTagVsSelfClosingTagPairs[j+1] = fmt.Sprintf("<%s/>", emptyTagsToReplaceToSelfClosingTags[i]) + j += 2 + } + responseString := strings.NewReplacer(emptyTagVsSelfClosingTagPairs...).Replace(string(responsePayload)) return []byte(responseString) } @@ -219,7 +254,7 @@ func convertTo20BitString(ricNearRtId string) (string, error) { return fmt.Sprintf("%020b", r)[:20], nil } -func (h E2SetupRequestNotificationHandler) parseSetupRequest(payload []byte) (*models.E2SetupRequestMessage, string, error) { +func (h *E2SetupRequestNotificationHandler) parseSetupRequest(payload []byte) (*models.E2SetupRequestMessage, string, error) { pipInd := bytes.IndexByte(payload, '|') if pipInd < 0 { @@ -234,7 +269,7 @@ func (h E2SetupRequestNotificationHandler) parseSetupRequest(payload []byte) (*m h.logger.Infof("#E2SetupRequestNotificationHandler.parseSetupRequest - payload: %s", payload[pipInd+1:]) setupRequest := &models.E2SetupRequestMessage{} - err := xml.Unmarshal(payload[pipInd+1:], &setupRequest.E2APPDU) + err := xml.Unmarshal(normalizeXml(payload[pipInd+1:]), &setupRequest.E2APPDU) if err != nil { return nil, "", errors.New(fmt.Sprintf("#E2SetupRequestNotificationHandler.parseSetupRequest - Error unmarshalling E2 Setup Request payload: %x", payload)) } @@ -242,6 +277,12 @@ func (h E2SetupRequestNotificationHandler) parseSetupRequest(payload []byte) (*m return setupRequest, e2tIpAddress, nil } +func normalizeXml(payload []byte) []byte { + xmlStr := string(payload) + normalized := strings.NewReplacer("<", "<", ">", ">").Replace(xmlStr) + return []byte(normalized) +} + func (h E2SetupRequestNotificationHandler) buildNodebInfo(ranName string, e2tAddress string, request *models.E2SetupRequestMessage) (*entities.NodebInfo, error) { var err error @@ -251,7 +292,7 @@ func (h E2SetupRequestNotificationHandler) buildNodebInfo(ranName string, e2tAdd RanName: ranName, NodeType: entities.Node_GNB, Configuration: &entities.NodebInfo_Gnb{Gnb: &entities.Gnb{}}, - GlobalNbId: h.buildGlobalNbId(request), + GlobalNbId: h.buildGlobalNbId(request), } err = h.setGnbFunctions(nodebInfo, request) @@ -268,6 +309,6 @@ func (h E2SetupRequestNotificationHandler) buildGlobalNbId(setupRequest *models. func (h E2SetupRequestNotificationHandler) buildNbIdentity(ranName string, setupRequest *models.E2SetupRequestMessage) *entities.NbIdentity { return &entities.NbIdentity{ InventoryName: ranName, - GlobalNbId: h.buildGlobalNbId(setupRequest), + GlobalNbId: h.buildGlobalNbId(setupRequest), } } diff --git a/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler_test.go b/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler_test.go index 28dfe76..41ddcca 100644 --- a/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler_test.go +++ b/E2Manager/handlers/rmrmsghandlers/e2_setup_request_notification_handler_test.go @@ -20,6 +20,7 @@ package rmrmsghandlers import ( + "bytes" "e2mgr/configuration" "e2mgr/managers" "e2mgr/mocks" @@ -27,9 +28,11 @@ import ( "e2mgr/rmrCgo" "e2mgr/services" "e2mgr/tests" + "encoding/xml" "errors" "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/golang/protobuf/ptypes/wrappers" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "io/ioutil" @@ -38,14 +41,16 @@ import ( ) const ( - prefix = "10.0.2.15:9999|" - e2tInstanceFullAddress = "10.0.2.15:9999" - nodebRanName = "gnb:310-410-b5c67788" - GnbSetupRequestXmlPath = "../../tests/resources/setupRequest_gnb.xml" - GnbWithoutFunctionsSetupRequestXmlPath = "../../tests/resources/setupRequest_gnb_without_functions.xml" - EnGnbSetupRequestXmlPath = "../../tests/resources/setupRequest_en-gNB.xml" - NgEnbSetupRequestXmlPath = "../../tests/resources/setupRequest_ng-eNB.xml" - EnbSetupRequestXmlPath = "../../tests/resources/setupRequest_enb.xml" + prefix = "10.0.2.15:9999|" + e2tInstanceFullAddress = "10.0.2.15:9999" + nodebRanName = "gnb:310-410-b5c67788" + GnbSetupRequestXmlPath = "../../tests/resources/setupRequest_gnb.xml" + EnGnbSetupRequestXmlPath = "../../tests/resources/setupRequest_en-gNB.xml" + NgEnbSetupRequestXmlPath = "../../tests/resources/setupRequest_ng-eNB.xml" + EnbSetupRequestXmlPath = "../../tests/resources/setupRequest_enb.xml" + GnbWithoutFunctionsSetupRequestXmlPath = "../../tests/resources/setupRequest_gnb_without_functions.xml" + E2SetupFailureResponseWithMiscCause = "1131" + E2SetupFailureResponseWithTransportCause = "1131" ) func readXmlFile(t *testing.T, xmlPath string) []byte { @@ -66,8 +71,8 @@ func TestParseGnbSetupRequest_Success(t *testing.T) { handler, _, _, _, _, _ := initMocks(t) prefBytes := []byte(prefix) request, _, err := handler.parseSetupRequest(append(prefBytes, xmlGnb...)) - assert.Equal(t, "131014", request.GetPlmnId()) - assert.Equal(t, "10011001101010101011", request.GetNbId()) + assert.Equal(t, "02F829", request.GetPlmnId()) + assert.Equal(t, "001100000011000000110000", request.GetNbId()) assert.Nil(t, err) } @@ -120,51 +125,85 @@ func TestParseSetupRequest_UnmarshalFailure(t *testing.T) { assert.EqualError(t, err, "#E2SetupRequestNotificationHandler.parseSetupRequest - Error unmarshalling E2 Setup Request payload: 31302e302e322e31353a393939397c010203") } +func TestE2SetupRequestNotificationHandler_GetGeneralConfigurationFailure(t *testing.T) { + xmlGnb := readXmlFile(t, GnbSetupRequestXmlPath) + handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock := initMocks(t) + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{}, common.NewInternalError(errors.New("some error"))) + notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append([]byte(prefix), xmlGnb...)} + handler.Handle(notificationRequest) + rmrMessengerMock.AssertNotCalled(t, "SendMsg") + e2tInstancesManagerMock.AssertNotCalled(t, "GetE2TInstance") + routingManagerClientMock.AssertNotCalled(t, "AssociateRanToE2TInstance") + readerMock.AssertNotCalled(t, "GetNodeb") + writerMock.AssertNotCalled(t, "SaveNodeb") +} + +func getMbuf(msgType int, payloadStr string, request *models.NotificationRequest) *rmrCgo.MBuf { + payload := []byte(payloadStr) + mbuf := rmrCgo.NewMBuf(msgType, len(payload), nodebRanName,&payload,&request.TransactionId, request.GetMsgSrc() ) + return mbuf +} + +func TestE2SetupRequestNotificationHandler_EnableRicFalse(t *testing.T) { + xmlGnb := readXmlFile(t, GnbSetupRequestXmlPath) + handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock := initMocks(t) + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: false}, nil) + notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append([]byte(prefix), xmlGnb...)} + mbuf := getMbuf(rmrCgo.RIC_E2_SETUP_FAILURE, E2SetupFailureResponseWithMiscCause, notificationRequest) + rmrMessengerMock.On("WhSendMsg", mbuf, true).Return(&rmrCgo.MBuf{}, nil) + handler.Handle(notificationRequest) + rmrMessengerMock.AssertCalled(t, "WhSendMsg", mbuf,true ) + e2tInstancesManagerMock.AssertNotCalled(t, "GetE2TInstance") + routingManagerClientMock.AssertNotCalled(t, "AssociateRanToE2TInstance") + readerMock.AssertNotCalled(t, "GetNodeb") + writerMock.AssertNotCalled(t, "SaveNodeb") +} + func TestE2SetupRequestNotificationHandler_HandleNewGnbSuccess(t *testing.T) { xmlGnb := readXmlFile(t, GnbSetupRequestXmlPath) handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock := initMocks(t) - var e2tInstance = &entities.E2TInstance{} - e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(e2tInstance, nil) + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(&entities.E2TInstance{}, nil) var gnb *entities.NodebInfo readerMock.On("GetNodeb", mock.Anything).Return(gnb, common.NewResourceNotFoundError("Not found")) - writerMock.On("SaveNodeb", mock.Anything, mock.Anything).Return(nil) + notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append([]byte(prefix), xmlGnb...)} + nodebInfo := getExpectedNodebWithFunctionsForNewRan(notificationRequest.Payload) + writerMock.On("SaveNodeb", mock.Anything, nodebInfo).Return(nil) routingManagerClientMock.On("AssociateRanToE2TInstance", e2tInstanceFullAddress, mock.Anything).Return(nil) writerMock.On("UpdateNodebInfo", mock.Anything).Return(nil) e2tInstancesManagerMock.On("AddRansToInstance", mock.Anything, mock.Anything).Return(nil) - var errEmpty error - rmrMessage := &rmrCgo.MBuf{} - rmrMessengerMock.On("SendMsg", mock.Anything, mock.Anything).Return(rmrMessage, errEmpty) - prefBytes := []byte(prefix) - notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append(prefBytes, xmlGnb...)} + rmrMessengerMock.On("SendMsg", mock.Anything, mock.Anything).Return(&rmrCgo.MBuf{}, nil) handler.Handle(notificationRequest) + writerMock.AssertCalled(t, "SaveNodeb", mock.Anything, nodebInfo) assertNewNodebSuccessCalls(readerMock, t, e2tInstancesManagerMock, writerMock, routingManagerClientMock, rmrMessengerMock) } func TestE2SetupRequestNotificationHandler_HandleNewGnbWithoutFunctionsSuccess(t *testing.T) { xmlGnb := readXmlFile(t, GnbWithoutFunctionsSetupRequestXmlPath) handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock := initMocks(t) - var e2tInstance = &entities.E2TInstance{} - e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(e2tInstance, nil) + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(&entities.E2TInstance{}, nil) var gnb *entities.NodebInfo readerMock.On("GetNodeb", mock.Anything).Return(gnb, common.NewResourceNotFoundError("Not found")) - writerMock.On("SaveNodeb", mock.Anything, mock.Anything).Return(nil) + notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append([]byte(prefix), xmlGnb...)} + nodebInfo := getExpectedNodebWithFunctionsForNewRan(notificationRequest.Payload) + writerMock.On("SaveNodeb", mock.Anything, nodebInfo).Return(nil) routingManagerClientMock.On("AssociateRanToE2TInstance", e2tInstanceFullAddress, mock.Anything).Return(nil) writerMock.On("UpdateNodebInfo", mock.Anything).Return(nil) e2tInstancesManagerMock.On("AddRansToInstance", mock.Anything, mock.Anything).Return(nil) var errEmpty error rmrMessage := &rmrCgo.MBuf{} rmrMessengerMock.On("SendMsg", mock.Anything, mock.Anything).Return(rmrMessage, errEmpty) - prefBytes := []byte(prefix) - notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append(prefBytes, xmlGnb...)} handler.Handle(notificationRequest) + writerMock.AssertCalled(t, "SaveNodeb", mock.Anything, nodebInfo) assertNewNodebSuccessCalls(readerMock, t, e2tInstancesManagerMock, writerMock, routingManagerClientMock, rmrMessengerMock) } func TestE2SetupRequestNotificationHandler_HandleNewEnGnbSuccess(t *testing.T) { xmlEnGnb := readXmlFile(t, EnGnbSetupRequestXmlPath) handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock := initMocks(t) - var e2tInstance = &entities.E2TInstance{} - e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(e2tInstance, nil) + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(&entities.E2TInstance{}, nil) var gnb *entities.NodebInfo readerMock.On("GetNodeb", mock.Anything).Return(gnb, common.NewResourceNotFoundError("Not found")) writerMock.On("SaveNodeb", mock.Anything, mock.Anything).Return(nil) @@ -183,8 +222,8 @@ func TestE2SetupRequestNotificationHandler_HandleNewEnGnbSuccess(t *testing.T) { func TestE2SetupRequestNotificationHandler_HandleNewNgEnbSuccess(t *testing.T) { xmlNgEnb := readXmlFile(t, NgEnbSetupRequestXmlPath) handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock := initMocks(t) - var e2tInstance = &entities.E2TInstance{} - e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(e2tInstance, nil) + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(&entities.E2TInstance{}, nil) var gnb *entities.NodebInfo readerMock.On("GetNodeb", mock.Anything).Return(gnb, common.NewResourceNotFoundError("Not found")) writerMock.On("SaveNodeb", mock.Anything, mock.Anything).Return(nil) @@ -204,8 +243,8 @@ func TestE2SetupRequestNotificationHandler_HandleExistingGnbSuccess(t *testing.T xmlGnb := readXmlFile(t, GnbSetupRequestXmlPath) handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock := initMocks(t) - var e2tInstance = &entities.E2TInstance{} - e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(e2tInstance, nil) + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(&entities.E2TInstance{}, nil) var gnb = &entities.NodebInfo{ RanName: nodebRanName, AssociatedE2TInstanceAddress: e2tInstanceFullAddress, @@ -215,23 +254,88 @@ func TestE2SetupRequestNotificationHandler_HandleExistingGnbSuccess(t *testing.T } readerMock.On("GetNodeb", mock.Anything).Return(gnb, nil) routingManagerClientMock.On("AssociateRanToE2TInstance", e2tInstanceFullAddress, mock.Anything).Return(nil) - writerMock.On("UpdateNodebInfo", mock.Anything).Return(nil) + + notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append([]byte(prefix), xmlGnb...)} + gnbToUpdate := getExpectedNodebWithFunctionsForExistingRan(*gnb, notificationRequest.Payload) + writerMock.On("UpdateNodebInfo", gnbToUpdate).Return(nil) e2tInstancesManagerMock.On("AddRansToInstance", mock.Anything, mock.Anything).Return(nil) var errEmpty error - rmrMessage := &rmrCgo.MBuf{} - rmrMessengerMock.On("SendMsg", mock.Anything, mock.Anything).Return(rmrMessage, errEmpty) - prefBytes := []byte(prefix) - notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append(prefBytes, xmlGnb...)} + rmrMessengerMock.On("SendMsg", mock.Anything, mock.Anything).Return(&rmrCgo.MBuf{}, errEmpty) handler.Handle(notificationRequest) + writerMock.AssertCalled(t, "UpdateNodebInfo", gnbToUpdate) assertExistingNodebSuccessCalls(readerMock, t, e2tInstancesManagerMock, writerMock, routingManagerClientMock, rmrMessengerMock) } -func TestE2SetupRequestNotificationHandler_HandleParseError(t *testing.T) { +func TestE2SetupRequestNotificationHandler_HandleExistingGnbWithFunctionsSuccess(t *testing.T) { xmlGnb := readXmlFile(t, GnbSetupRequestXmlPath) handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock := initMocks(t) - prefBytes := []byte("invalid_prefix") - notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append(prefBytes, xmlGnb...)} + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(&entities.E2TInstance{}, nil) + var gnb = &entities.NodebInfo{ + RanName: nodebRanName, + AssociatedE2TInstanceAddress: e2tInstanceFullAddress, + ConnectionStatus: entities.ConnectionStatus_CONNECTED, + NodeType: entities.Node_GNB, + Configuration: &entities.NodebInfo_Gnb{Gnb: &entities.Gnb{RanFunctions: []*entities.RanFunction{ + { + RanFunctionId: &wrappers.UInt32Value{Value: 2}, + RanFunctionRevision: &wrappers.UInt32Value{Value: 2}, + }, + }}}, + } + readerMock.On("GetNodeb", mock.Anything).Return(gnb, nil) + routingManagerClientMock.On("AssociateRanToE2TInstance", e2tInstanceFullAddress, mock.Anything).Return(nil) + + notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append([]byte(prefix), xmlGnb...)} + gnbToUpdate := getExpectedNodebWithFunctionsForExistingRan(*gnb, notificationRequest.Payload) + + writerMock.On("UpdateNodebInfo", gnbToUpdate).Return(nil) + e2tInstancesManagerMock.On("AddRansToInstance", mock.Anything, mock.Anything).Return(nil) + var errEmpty error + rmrMessengerMock.On("SendMsg", mock.Anything, mock.Anything).Return(&rmrCgo.MBuf{}, errEmpty) + handler.Handle(notificationRequest) + writerMock.AssertCalled(t, "UpdateNodebInfo", gnbToUpdate) + assertExistingNodebSuccessCalls(readerMock, t, e2tInstancesManagerMock, writerMock, routingManagerClientMock, rmrMessengerMock) +} + +func getExpectedNodebWithFunctionsForExistingRan(nodeb entities.NodebInfo, payload []byte) *entities.NodebInfo { + pipInd := bytes.IndexByte(payload, '|') + setupRequest := &models.E2SetupRequestMessage{} + _ = xml.Unmarshal(normalizeXml(payload[pipInd+1:]), &setupRequest.E2APPDU) + nodeb.GetGnb().RanFunctions = setupRequest.ExtractRanFunctionsList() + return &nodeb +} + +func getExpectedNodebWithFunctionsForNewRan(payload []byte) *entities.NodebInfo { + pipInd := bytes.IndexByte(payload, '|') + setupRequest := &models.E2SetupRequestMessage{} + _ = xml.Unmarshal(normalizeXml(payload[pipInd+1:]), &setupRequest.E2APPDU) + + nodeb := &entities.NodebInfo{ + AssociatedE2TInstanceAddress: e2tInstanceFullAddress, + ConnectionStatus: entities.ConnectionStatus_CONNECTED, + RanName: nodebRanName, + NodeType: entities.Node_GNB, + Configuration: &entities.NodebInfo_Gnb{ + Gnb: &entities.Gnb{ + RanFunctions: setupRequest.ExtractRanFunctionsList(), + }, + }, + GlobalNbId: &entities.GlobalNbId{ + PlmnId: setupRequest.GetPlmnId(), + NbId: setupRequest.GetNbId(), + }, + } + + return nodeb +} + +func TestE2SetupRequestNotificationHandler_HandleParseError(t *testing.T) { + xmlGnb := readXmlFile(t, GnbSetupRequestXmlPath) + handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock := initMocks(t) + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil) + notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append([]byte("invalid_prefix"), xmlGnb...)} handler.Handle(notificationRequest) readerMock.AssertNotCalled(t, "GetNodeb", mock.Anything) writerMock.AssertNotCalled(t, "SaveNodeb", mock.Anything, mock.Anything) @@ -243,8 +347,8 @@ func TestE2SetupRequestNotificationHandler_HandleParseError(t *testing.T) { func TestE2SetupRequestNotificationHandler_HandleUnmarshalError(t *testing.T) { handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock := initMocks(t) - prefBytes := []byte(prefix) - notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append(prefBytes, "xmlGnb"...)} + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil) + notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append([]byte(prefix), "xmlGnb"...)} handler.Handle(notificationRequest) readerMock.AssertNotCalled(t, "GetNodeb", mock.Anything) writerMock.AssertNotCalled(t, "SaveNodeb", mock.Anything, mock.Anything) @@ -257,8 +361,8 @@ func TestE2SetupRequestNotificationHandler_HandleUnmarshalError(t *testing.T) { func TestE2SetupRequestNotificationHandler_HandleGetE2TInstanceError(t *testing.T) { xmlGnb := readXmlFile(t, GnbSetupRequestXmlPath) handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock := initMocks(t) - var e2tInstance *entities.E2TInstance - e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(e2tInstance, common.NewResourceNotFoundError("Not found")) + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(&entities.E2TInstance{}, common.NewResourceNotFoundError("Not found")) prefBytes := []byte(prefix) notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append(prefBytes, xmlGnb...)} handler.Handle(notificationRequest) @@ -273,14 +377,12 @@ func TestE2SetupRequestNotificationHandler_HandleGetE2TInstanceError(t *testing. func TestE2SetupRequestNotificationHandler_HandleGetNodebError(t *testing.T) { xmlGnb := readXmlFile(t, GnbSetupRequestXmlPath) - handler, readerMock, writerMock, routingManagerClientMock, e2tInstancesManagerMock, rmrMessengerMock := initMocks(t) - var e2tInstance = &entities.E2TInstance{} - e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(e2tInstance, nil) + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(&entities.E2TInstance{}, nil) var gnb *entities.NodebInfo readerMock.On("GetNodeb", mock.Anything).Return(gnb, common.NewInternalError(errors.New("some error"))) - prefBytes := []byte(prefix) - notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append(prefBytes, xmlGnb...)} + notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append([]byte(prefix), xmlGnb...)} handler.Handle(notificationRequest) e2tInstancesManagerMock.AssertCalled(t, "GetE2TInstance", e2tInstanceFullAddress) readerMock.AssertCalled(t, "GetNodeb", mock.Anything) @@ -295,8 +397,8 @@ func TestE2SetupRequestNotificationHandler_HandleAssociationError(t *testing.T) xmlGnb := readXmlFile(t, GnbSetupRequestXmlPath) handler, readerMock, writerMock, rmrMessengerMock, e2tInstancesManagerMock, routingManagerClientMock := initMocks(t) - var e2tInstance = &entities.E2TInstance{} - e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(e2tInstance, nil) + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(&entities.E2TInstance{}, nil) var gnb *entities.NodebInfo readerMock.On("GetNodeb", mock.Anything).Return(gnb, common.NewResourceNotFoundError("Not found")) writerMock.On("SaveNodeb", mock.Anything, mock.Anything).Return(nil) @@ -304,11 +406,9 @@ func TestE2SetupRequestNotificationHandler_HandleAssociationError(t *testing.T) e2tInstancesManagerMock.On("AddRansToInstance", mock.Anything, mock.Anything).Return(nil) routingManagerClientMock.On("AssociateRanToE2TInstance", e2tInstanceFullAddress, mock.Anything).Return(errors.New("association error")) var errEmpty error - rmrMessage := &rmrCgo.MBuf{} - rmrMessengerMock.On("WhSendMsg", mock.Anything, mock.Anything).Return(rmrMessage, errEmpty) - - prefBytes := []byte(prefix) - notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append(prefBytes, xmlGnb...)} + notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append([]byte(prefix), xmlGnb...)} + mbuf := getMbuf(rmrCgo.RIC_E2_SETUP_FAILURE, E2SetupFailureResponseWithTransportCause, notificationRequest) + rmrMessengerMock.On("WhSendMsg", mbuf, true).Return(&rmrCgo.MBuf{}, errEmpty) handler.Handle(notificationRequest) readerMock.AssertCalled(t, "GetNodeb", mock.Anything) e2tInstancesManagerMock.AssertCalled(t, "GetE2TInstance", e2tInstanceFullAddress) @@ -316,16 +416,17 @@ func TestE2SetupRequestNotificationHandler_HandleAssociationError(t *testing.T) routingManagerClientMock.AssertCalled(t, "AssociateRanToE2TInstance", e2tInstanceFullAddress, mock.Anything) writerMock.AssertCalled(t, "UpdateNodebInfo", mock.Anything) e2tInstancesManagerMock.AssertNotCalled(t, "AddRansToInstance", mock.Anything, mock.Anything) - rmrMessengerMock.AssertCalled(t, "WhSendMsg", mock.Anything, mock.Anything) + rmrMessengerMock.AssertCalled(t, "WhSendMsg", mbuf, true) } func TestE2SetupRequestNotificationHandler_ConvertTo20BitStringError(t *testing.T) { xmlEnGnb := readXmlFile(t, EnGnbSetupRequestXmlPath) logger := tests.InitLog(t) config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3, GlobalRicId: struct { - PlmnId string - RicNearRtId string - }{PlmnId: "131014", RicNearRtId: "10011001101010101011"}} + RicId string + Mcc string + Mnc string + }{Mcc: "327", Mnc: "94", RicId: "10011001101010101011"}} rmrMessengerMock := &mocks.RmrMessengerMock{} rmrSender := tests.InitRmrSender(rmrMessengerMock, logger) readerMock := &mocks.RnibReaderMock{} @@ -335,9 +436,8 @@ func TestE2SetupRequestNotificationHandler_ConvertTo20BitStringError(t *testing. e2tInstancesManagerMock := &mocks.E2TInstancesManagerMock{} e2tAssociationManager := managers.NewE2TAssociationManager(logger, rnibDataService, e2tInstancesManagerMock, routingManagerClientMock) handler := NewE2SetupRequestNotificationHandler(logger, config, e2tInstancesManagerMock, rmrSender, rnibDataService, e2tAssociationManager) - - var e2tInstance = &entities.E2TInstance{} - e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(e2tInstance, nil) + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(&entities.E2TInstance{}, nil) var gnb *entities.NodebInfo readerMock.On("GetNodeb", mock.Anything).Return(gnb, common.NewResourceNotFoundError("Not found")) writerMock.On("SaveNodeb", mock.Anything, mock.Anything).Return(nil) @@ -364,8 +464,8 @@ func TestE2SetupRequestNotificationHandler_HandleExistingGnbInvalidStatusError(t handler, readerMock, writerMock, routingManagerClientMock, e2tInstancesManagerMock, rmrMessengerMock := initMocks(t) var gnb = &entities.NodebInfo{RanName: nodebRanName, ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN} readerMock.On("GetNodeb", mock.Anything).Return(gnb, nil) - var e2tInstance = &entities.E2TInstance{} - e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(e2tInstance, nil) + readerMock.On("GetGeneralConfiguration").Return(&entities.GeneralConfiguration{EnableRic: true}, nil) + e2tInstancesManagerMock.On("GetE2TInstance", e2tInstanceFullAddress).Return(&entities.E2TInstance{}, nil) prefBytes := []byte(prefix) notificationRequest := &models.NotificationRequest{RanName: nodebRanName, Payload: append(prefBytes, xmlGnb...)} handler.Handle(notificationRequest) @@ -378,12 +478,13 @@ func TestE2SetupRequestNotificationHandler_HandleExistingGnbInvalidStatusError(t rmrMessengerMock.AssertNotCalled(t, "SendMsg", mock.Anything, mock.Anything) } -func initMocks(t *testing.T) (E2SetupRequestNotificationHandler, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.RmrMessengerMock, *mocks.E2TInstancesManagerMock, *mocks.RoutingManagerClientMock) { +func initMocks(t *testing.T) (*E2SetupRequestNotificationHandler, *mocks.RnibReaderMock, *mocks.RnibWriterMock, *mocks.RmrMessengerMock, *mocks.E2TInstancesManagerMock, *mocks.RoutingManagerClientMock) { logger := tests.InitLog(t) config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3, GlobalRicId: struct { - PlmnId string - RicNearRtId string - }{PlmnId: "131014", RicNearRtId: "556670"}} + RicId string + Mcc string + Mnc string + }{Mcc: "327", Mnc: "94", RicId: "AACCE"}} rmrMessengerMock := &mocks.RmrMessengerMock{} rmrSender := tests.InitRmrSender(rmrMessengerMock, logger) readerMock := &mocks.RnibReaderMock{} diff --git a/E2Manager/handlers/rmrmsghandlers/x2_reset_request_notification_handler.go b/E2Manager/handlers/rmrmsghandlers/x2_reset_request_notification_handler.go index 85255eb..1da8758 100644 --- a/E2Manager/handlers/rmrmsghandlers/x2_reset_request_notification_handler.go +++ b/E2Manager/handlers/rmrmsghandlers/x2_reset_request_notification_handler.go @@ -38,6 +38,8 @@ import ( "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" ) +const ResetRequesLogInfoElapsedTime = "#X2ResetRequestNotificationHandler.Handle - Summary: elapsed time for receiving and handling reset request message from E2 terminator: %f ms" + type X2ResetRequestNotificationHandler struct { logger *logger.Logger rnibDataService services.RNibDataService @@ -61,7 +63,7 @@ func (h X2ResetRequestNotificationHandler) Handle(request *models.NotificationRe nb, rNibErr := h.rnibDataService.GetNodeb(request.RanName) if rNibErr != nil { h.logger.Errorf("#X2ResetRequestNotificationHandler.Handle - failed to retrieve nodeB entity. RanName: %s. Error: %s", request.RanName, rNibErr.Error()) - 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.logger.Infof(ResetRequesLogInfoElapsedTime, utils.ElapsedTime(request.StartTime)) return } @@ -69,19 +71,19 @@ func (h X2ResetRequestNotificationHandler) Handle(request *models.NotificationRe if nb.ConnectionStatus == entities.ConnectionStatus_SHUTTING_DOWN { h.logger.Warnf("#X2ResetRequestNotificationHandler.Handle - nodeB entity in incorrect state. RanName %s, ConnectionStatus %s", nb.RanName, nb.ConnectionStatus) - 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.logger.Infof(ResetRequesLogInfoElapsedTime, utils.ElapsedTime(request.StartTime)) return } if nb.ConnectionStatus != entities.ConnectionStatus_CONNECTED { h.logger.Errorf("#X2ResetRequestNotificationHandler.Handle - nodeB entity in incorrect state. RanName %s, ConnectionStatus %s", nb.RanName, nb.ConnectionStatus) - 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.logger.Infof(ResetRequesLogInfoElapsedTime, utils.ElapsedTime(request.StartTime)) return } msg := models.NewRmrMessage(rmrCgo.RIC_X2_RESET_RESP, request.RanName, e2pdus.PackedX2ResetResponse, request.TransactionId, request.GetMsgSrc()) _ = 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.logger.Infof(ResetRequesLogInfoElapsedTime, utils.ElapsedTime(request.StartTime)) _ = h.ranStatusChangeManager.Execute(rmrCgo.RAN_RESTARTED, enums.RAN_TO_RIC, nb) } diff --git a/E2Manager/handlers/rmrmsghandlers/x2_reset_response_handler.go b/E2Manager/handlers/rmrmsghandlers/x2_reset_response_handler.go index 1097ed2..ca1b175 100644 --- a/E2Manager/handlers/rmrmsghandlers/x2_reset_response_handler.go +++ b/E2Manager/handlers/rmrmsghandlers/x2_reset_response_handler.go @@ -36,6 +36,8 @@ import ( "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" ) +const ResetResponseLogInfoElapsedTime = "#X2ResetResponseHandler.Handle - Summary: elapsed time for receiving and handling reset request message from E2 terminator: %f ms" + type X2ResetResponseHandler struct { logger *logger.Logger rnibDataService services.RNibDataService @@ -64,19 +66,19 @@ func (h X2ResetResponseHandler) Handle(request *models.NotificationRequest) { if nodebInfo.ConnectionStatus == entities.ConnectionStatus_SHUTTING_DOWN { h.logger.Warnf("#X2ResetResponseHandler.Handle - RAN name: %s, connection status: %s - nodeB entity in incorrect state", nodebInfo.RanName, nodebInfo.ConnectionStatus) - h.logger.Infof("#X2ResetResponseHandler.Handle - Summary: elapsed time for receiving and handling reset request message from E2 terminator: %f ms", utils.ElapsedTime(request.StartTime)) + h.logger.Infof(ResetResponseLogInfoElapsedTime, utils.ElapsedTime(request.StartTime)) return } if nodebInfo.ConnectionStatus != entities.ConnectionStatus_CONNECTED { h.logger.Errorf("#X2ResetResponseHandler.Handle - RAN name: %s, connection status: %s - nodeB entity in incorrect state", nodebInfo.RanName, nodebInfo.ConnectionStatus) - h.logger.Infof("#X2ResetResponseHandler.Handle - Summary: elapsed time for receiving and handling reset request message from E2 terminator: %f ms", utils.ElapsedTime(request.StartTime)) + h.logger.Infof(ResetResponseLogInfoElapsedTime, utils.ElapsedTime(request.StartTime)) return } isSuccessfulResetResponse, err := h.isSuccessfulResetResponse(ranName, request.Payload) - h.logger.Infof("#X2ResetResponseHandler.Handle - Summary: elapsed time for receiving and handling reset request message from E2 terminator: %f ms", utils.ElapsedTime(request.StartTime)) + h.logger.Infof(ResetResponseLogInfoElapsedTime, utils.ElapsedTime(request.StartTime)) if err != nil || !isSuccessfulResetResponse { return diff --git a/E2Manager/httpserver/http_server.go b/E2Manager/httpserver/http_server.go index a022ecb..320acd0 100644 --- a/E2Manager/httpserver/http_server.go +++ b/E2Manager/httpserver/http_server.go @@ -49,6 +49,7 @@ func initializeRoutes(router *mux.Router, rootController controllers.IRootContro rr.HandleFunc("/{ranName}", nodebController.GetNodeb).Methods(http.MethodGet) rr.HandleFunc("/{ranName}/update", nodebController.UpdateGnb).Methods(http.MethodPut) rr.HandleFunc("/shutdown", nodebController.Shutdown).Methods(http.MethodPut) + rr.HandleFunc("/parameters", nodebController.SetGeneralConfiguration).Methods(http.MethodPut) rrr := r.PathPrefix("/e2t").Subrouter() rrr.HandleFunc("/list", e2tController.GetE2TInstances).Methods(http.MethodGet) } diff --git a/E2Manager/httpserver/http_server_test.go b/E2Manager/httpserver/http_server_test.go index 3c0620b..cdca134 100644 --- a/E2Manager/httpserver/http_server_test.go +++ b/E2Manager/httpserver/http_server_test.go @@ -39,6 +39,7 @@ func setupRouterAndMocks() (*mux.Router, *mocks.RootControllerMock, *mocks.Nodeb nodebControllerMock.On("Shutdown").Return(nil) nodebControllerMock.On("GetNodeb").Return(nil) nodebControllerMock.On("GetNodebIdList").Return(nil) + nodebControllerMock.On("SetGeneralConfiguration").Return(nil) e2tControllerMock := &mocks.E2TControllerMock{} @@ -103,6 +104,19 @@ func TestRoutePutNodebShutdown(t *testing.T) { nodebControllerMock.AssertNumberOfCalls(t, "Shutdown", 1) } +func TestRoutePutNodebSetGeneralConfiguration(t *testing.T) { + router, _, nodebControllerMock, _ := setupRouterAndMocks() + + req, err := http.NewRequest("PUT", "/v1/nodeb/parameters", nil) + if err != nil { + t.Fatal(err) + } + rr := httptest.NewRecorder() + router.ServeHTTP(rr, req) + + nodebControllerMock.AssertNumberOfCalls(t, "SetGeneralConfiguration", 1) +} + func TestRouteNotFound(t *testing.T) { router, _, _,_ := setupRouterAndMocks() diff --git a/E2Manager/managers/ran_connect_status_change_manager.go b/E2Manager/managers/ran_connect_status_change_manager.go new file mode 100644 index 0000000..26d12b2 --- /dev/null +++ b/E2Manager/managers/ran_connect_status_change_manager.go @@ -0,0 +1,131 @@ +// +// 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 managers + +import ( + "e2mgr/logger" + "e2mgr/services" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" +) + +const ( + CONNECTED_RAW_EVENT = "CONNECTED" + DISCONNECTED_RAW_EVENT = "DISCONNECTED" + NONE_RAW_EVENT = "NONE" +) + +type RanConnectStatusChangeManager struct { + logger *logger.Logger + rnibDataService services.RNibDataService + ranListManager RanListManager + ranAlarmService services.RanAlarmService +} + +func NewRanConnectStatusChangeManager(logger *logger.Logger, rnibDataService services.RNibDataService, ranListManager RanListManager, ranAlarmService services.RanAlarmService) *RanConnectStatusChangeManager { + return &RanConnectStatusChangeManager{ + logger: logger, + rnibDataService: rnibDataService, + ranListManager: ranListManager, + ranAlarmService: ranAlarmService, + } +} + +func (m *RanConnectStatusChangeManager) ChangeStatus(nodebInfo *entities.NodebInfo, nextStatus entities.ConnectionStatus) error { + m.logger.Infof("#RanConnectStatusChangeManager.ChangeStatus - RAN name: %s, currentStatus: %s, nextStatus: %s", nodebInfo.RanName, nodebInfo.GetConnectionStatus(), nextStatus) + + // set the proper event + event := m.setEvent(nodebInfo, nextStatus) + isConnectivityEvent := event != NONE_RAW_EVENT + + // only after determining event we set next status + nodebInfo.ConnectionStatus = nextStatus; + if !isConnectivityEvent { + err := m.updateNodebInfo(nodebInfo) + if err != nil { + return err + } + } else { + err := m.updateNodebInfoOnConnectionStatusInversion(nodebInfo, event) + if err != nil { + return err + } + } + + // in any case, update RanListManager + m.logger.Infof("#RanConnectStatusChangeManager.ChangeStatus - RAN name: %s, updating RanListManager... status: %s", nodebInfo.RanName, nodebInfo.GetConnectionStatus()) + err := m.ranListManager.UpdateRanState(nodebInfo) + if err != nil { + m.logger.Errorf("#RanConnectStatusChangeManager.ChangeStatus - RAN name: %s - Failed updating RAN's connection status by RanListManager. Error: %v", nodebInfo.RanName, err) + // log and proceed... + } + + if isConnectivityEvent { + m.logger.Infof("#RanConnectStatusChangeManager.ChangeStatus - RAN name: %s, setting alarm at RanAlarmService... event: %s", nodebInfo.RanName, event) + err := m.ranAlarmService.SetConnectivityChangeAlarm(nodebInfo) + if err != nil { + m.logger.Errorf("#RanConnectStatusChangeManager.ChangeStatus - RAN name: %s - Failed setting an alarm by RanAlarmService. Error: %v", nodebInfo.RanName, err) + // log and proceed... + } + } + + return nil +} + +func (m *RanConnectStatusChangeManager) updateNodebInfoOnConnectionStatusInversion(nodebInfo *entities.NodebInfo, event string) error { + + err := m.rnibDataService.UpdateNodebInfoOnConnectionStatusInversion(nodebInfo, event) + + if err != nil { + m.logger.Errorf("#RanConnectStatusChangeManager.updateNodebInfoOnConnectionStatusInversion - RAN name: %s - Failed updating RAN's connection status in rNib. Error: %v", nodebInfo.RanName, err) + return err + } + + m.logger.Infof("#RanConnectStatusChangeManager.updateNodebInfoOnConnectionStatusInversion - RAN name: %s - Successfully updated rNib.", nodebInfo.RanName) + return nil +} + +func (m *RanConnectStatusChangeManager) updateNodebInfo(nodebInfo *entities.NodebInfo) error { + + err := m.rnibDataService.UpdateNodebInfo(nodebInfo) + + if err != nil { + m.logger.Errorf("#RanConnectStatusChangeManager.updateNodebInfo - RAN name: %s - Failed updating RAN's connection status in rNib. Error: %v", nodebInfo.RanName, err) + return err + } + + m.logger.Infof("#RanConnectStatusChangeManager.updateNodebInfo - RAN name: %s - Successfully updated rNib.", nodebInfo.RanName) + return nil +} + +func (m *RanConnectStatusChangeManager) setEvent(nodebInfo *entities.NodebInfo, nextState entities.ConnectionStatus) string { + currentConnectionStatus := nodebInfo.GetConnectionStatus() + + var event string + if currentConnectionStatus != entities.ConnectionStatus_CONNECTED && nextState == entities.ConnectionStatus_CONNECTED { + event = nodebInfo.RanName + "_" + CONNECTED_RAW_EVENT + } else if currentConnectionStatus == entities.ConnectionStatus_CONNECTED && nextState != entities.ConnectionStatus_CONNECTED { + event = nodebInfo.RanName + "_" + DISCONNECTED_RAW_EVENT + } else { + event = NONE_RAW_EVENT + } + + m.logger.Infof("#RanConnectStatusChangeManager.setEvent - Connectivity Event for RAN %s is: %s", nodebInfo.RanName, event) + return event +} diff --git a/E2Manager/managers/ran_connect_status_change_manager_test.go b/E2Manager/managers/ran_connect_status_change_manager_test.go new file mode 100644 index 0000000..b9295e3 --- /dev/null +++ b/E2Manager/managers/ran_connect_status_change_manager_test.go @@ -0,0 +1,187 @@ +// +// 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 managers + +import ( + "e2mgr/configuration" + "e2mgr/logger" + "e2mgr/mocks" + "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/assert" + "testing" +) + +const EventChannelForTest = "RAN_CONNECTION_STATUS_CHANGE" + +func initRanConnectStatusChangeManagerTest(t *testing.T) (*mocks.RnibWriterMock, *mocks.RanListManagerMock, *mocks.RanAlarmServiceMock, *RanConnectStatusChangeManager) { + log, err := logger.InitLogger(logger.DebugLevel) + if err != nil { + t.Errorf("#... - failed to initialize log, error: %s", err) + } + config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: 3, StateChangeMessageChannel: EventChannelForTest} + + readerMock := &mocks.RnibReaderMock{} + writerMock := &mocks.RnibWriterMock{} + rnibDataService := services.NewRnibDataService(log, config, readerMock, writerMock) + ranListManagerMock := &mocks.RanListManagerMock{} + ranAlarmServiceMock := &mocks.RanAlarmServiceMock{} + ranConnectStatusChangeManager := NewRanConnectStatusChangeManager(log, rnibDataService, ranListManagerMock, ranAlarmServiceMock) + return writerMock, ranListManagerMock, ranAlarmServiceMock, ranConnectStatusChangeManager +} + +func TestChangeStatusSuccessNewRan(t *testing.T) { + writerMock, ranListManagerMock, ranAlarmServiceMock, ranConnectStatusChangeManager := initRanConnectStatusChangeManagerTest(t) + + origNodebInfo := &entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_UNKNOWN_CONNECTION_STATUS} + updatedNodebInfo := *origNodebInfo + updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_CONNECTED + writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNodebInfo, EventChannelForTest, RanName + "_" + CONNECTED_RAW_EVENT).Return(nil) + ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(nil) + ranAlarmServiceMock.On("SetConnectivityChangeAlarm", &updatedNodebInfo).Return(nil) + err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_CONNECTED) + assert.Nil(t, err) + writerMock.AssertExpectations(t) + ranListManagerMock.AssertExpectations(t) + ranAlarmServiceMock.AssertExpectations(t) +} + +func TestChangeStatusSuccessEventNone1(t *testing.T) { + writerMock, ranListManagerMock, ranAlarmServiceMock, ranConnectStatusChangeManager := initRanConnectStatusChangeManagerTest(t) + + origNodebInfo := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN} + updatedNodebInfo := *origNodebInfo + updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_SHUT_DOWN + writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(nil) + ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(nil) + err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_SHUT_DOWN) + assert.Nil(t, err) + writerMock.AssertExpectations(t) + ranListManagerMock.AssertExpectations(t) + ranAlarmServiceMock.AssertExpectations(t) +} + +func TestChangeStatusSuccessEventNone2(t *testing.T) { + writerMock, ranListManagerMock, ranAlarmServiceMock, ranConnectStatusChangeManager := initRanConnectStatusChangeManagerTest(t) + + origNodebInfo := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED} + updatedNodebInfo := *origNodebInfo + updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_SHUT_DOWN + writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(nil) + ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(nil) + err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_SHUT_DOWN) + assert.Nil(t, err) + writerMock.AssertExpectations(t) + ranListManagerMock.AssertExpectations(t) + ranAlarmServiceMock.AssertExpectations(t) +} + +func TestChangeStatusSuccessEventConnected(t *testing.T) { + writerMock, ranListManagerMock, ranAlarmServiceMock, ranConnectStatusChangeManager := initRanConnectStatusChangeManagerTest(t) + + origNodebInfo := &entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED} + updatedNodebInfo := *origNodebInfo + updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_CONNECTED + writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNodebInfo, EventChannelForTest, RanName + "_" + CONNECTED_RAW_EVENT).Return(nil) + ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(nil) + ranAlarmServiceMock.On("SetConnectivityChangeAlarm", &updatedNodebInfo).Return(nil) + err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_CONNECTED) + assert.Nil(t, err) + writerMock.AssertExpectations(t) + ranListManagerMock.AssertExpectations(t) + ranAlarmServiceMock.AssertExpectations(t) +} + +func TestChangeStatusSuccessEventDisconnected(t *testing.T) { + writerMock, ranListManagerMock, ranAlarmServiceMock, ranConnectStatusChangeManager := initRanConnectStatusChangeManagerTest(t) + + origNodebInfo := &entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_CONNECTED} + updatedNodebInfo := *origNodebInfo + updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_DISCONNECTED + writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNodebInfo, EventChannelForTest, RanName + "_" + DISCONNECTED_RAW_EVENT).Return(nil) + ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(nil) + ranAlarmServiceMock.On("SetConnectivityChangeAlarm", &updatedNodebInfo).Return(nil) + err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_DISCONNECTED) + assert.Nil(t, err) + writerMock.AssertExpectations(t) + ranListManagerMock.AssertExpectations(t) + ranAlarmServiceMock.AssertExpectations(t) +} + +func TestChangeStatusRnibErrorEventNone(t *testing.T) { + writerMock, ranListManagerMock, ranAlarmServiceMock, ranConnectStatusChangeManager := initRanConnectStatusChangeManagerTest(t) + + origNodebInfo := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN} + updatedNodebInfo := *origNodebInfo + updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_SHUT_DOWN + writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(common.NewInternalError(errors.New("Error"))) + err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_SHUT_DOWN) + assert.NotNil(t, err) + writerMock.AssertExpectations(t) + ranListManagerMock.AssertExpectations(t) + ranAlarmServiceMock.AssertExpectations(t) +} + +func TestChangeStatusRnibErrorEventConnected(t *testing.T) { + writerMock, ranListManagerMock, ranAlarmServiceMock, ranConnectStatusChangeManager := initRanConnectStatusChangeManagerTest(t) + + origNodebInfo := &entities.NodebInfo{RanName: RanName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED} + updatedNodebInfo := *origNodebInfo + updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_CONNECTED + writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNodebInfo, EventChannelForTest, RanName + "_" + CONNECTED_RAW_EVENT).Return(common.NewInternalError(errors.New("Error"))) + err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_CONNECTED) + assert.NotNil(t, err) + writerMock.AssertExpectations(t) + ranListManagerMock.AssertExpectations(t) + ranAlarmServiceMock.AssertExpectations(t) +} + +func TestChangeStatusRanListManagerError(t *testing.T) { + writerMock, ranListManagerMock, ranAlarmServiceMock, ranConnectStatusChangeManager := initRanConnectStatusChangeManagerTest(t) + + origNodebInfo := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_SHUTTING_DOWN} + updatedNodebInfo := *origNodebInfo + updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_SHUT_DOWN + writerMock.On("UpdateNodebInfo", &updatedNodebInfo).Return(nil) + ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(common.NewInternalError(errors.New("Error"))) + err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_SHUT_DOWN) + assert.Nil(t, err) + writerMock.AssertExpectations(t) + ranListManagerMock.AssertExpectations(t) + ranAlarmServiceMock.AssertExpectations(t) +} + +func TestChangeStatusRanAlarmServiceErrorEventConnected(t *testing.T) { + writerMock, ranListManagerMock, ranAlarmServiceMock, ranConnectStatusChangeManager := initRanConnectStatusChangeManagerTest(t) + + origNodebInfo := &entities.NodebInfo{RanName: ranName, ConnectionStatus: entities.ConnectionStatus_DISCONNECTED} + updatedNodebInfo := *origNodebInfo + updatedNodebInfo.ConnectionStatus = entities.ConnectionStatus_CONNECTED + writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", &updatedNodebInfo, EventChannelForTest, RanName + "_" + CONNECTED_RAW_EVENT).Return(nil) + ranListManagerMock.On("UpdateRanState", &updatedNodebInfo).Return(nil) + ranAlarmServiceMock.On("SetConnectivityChangeAlarm", &updatedNodebInfo).Return(common.NewInternalError(errors.New("Error"))) + err := ranConnectStatusChangeManager.ChangeStatus(origNodebInfo, entities.ConnectionStatus_CONNECTED) + assert.Nil(t, err) + writerMock.AssertExpectations(t) + ranListManagerMock.AssertExpectations(t) + ranAlarmServiceMock.AssertExpectations(t) +} \ No newline at end of file diff --git a/E2Manager/managers/ran_list_manager.go b/E2Manager/managers/ran_list_manager.go new file mode 100644 index 0000000..9ad10f2 --- /dev/null +++ b/E2Manager/managers/ran_list_manager.go @@ -0,0 +1,44 @@ +// +// 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 managers + +import ( + "e2mgr/logger" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" +) + +type ranListManagerInstance struct { + logger *logger.Logger +} + +type RanListManager interface { + UpdateRanState(nodebInfo *entities.NodebInfo) error +} + +func NewRanListManager(logger *logger.Logger) RanListManager { + return &ranListManagerInstance{ + logger: logger, + } +} + +func (m *ranListManagerInstance) UpdateRanState(nodebInfo *entities.NodebInfo) error { + m.logger.Infof("#ranListManagerInstance.UpdateRanState - RAN name: %s - Updating state...", nodebInfo.RanName) + return nil +} diff --git a/E2Manager/mocks/nodeb_controller_mock.go b/E2Manager/mocks/nodeb_controller_mock.go index a164383..11130b3 100644 --- a/E2Manager/mocks/nodeb_controller_mock.go +++ b/E2Manager/mocks/nodeb_controller_mock.go @@ -81,3 +81,10 @@ func (c *NodebControllerMock) UpdateGnb(writer http.ResponseWriter, r *http.Requ c.Called() } + +func (c *NodebControllerMock) SetGeneralConfiguration(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/ran_alarm_service_mock.go b/E2Manager/mocks/ran_alarm_service_mock.go new file mode 100644 index 0000000..ed18c88 --- /dev/null +++ b/E2Manager/mocks/ran_alarm_service_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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +package mocks + +import ( + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "github.com/stretchr/testify/mock" +) + +type RanAlarmServiceMock struct { + mock.Mock +} + +func (m *RanAlarmServiceMock) SetConnectivityChangeAlarm(nodebInfo *entities.NodebInfo) error { + + args := m.Called(nodebInfo) + return args.Error(0) +} \ No newline at end of file diff --git a/E2Manager/mocks/ran_list_manager_mock.go b/E2Manager/mocks/ran_list_manager_mock.go new file mode 100644 index 0000000..6df5c4f --- /dev/null +++ b/E2Manager/mocks/ran_list_manager_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. + +// This source code is part of the near-RT RIC (RAN Intelligent Controller) +// platform project (RICP). + +package mocks + +import ( + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" + "github.com/stretchr/testify/mock" +) + +type RanListManagerMock struct { + mock.Mock +} + +func (m *RanListManagerMock) UpdateRanState(nodebInfo *entities.NodebInfo) error { + + args := m.Called(nodebInfo) + return args.Error(0) +} \ No newline at end of file diff --git a/E2Manager/mocks/rnibReaderMock.go b/E2Manager/mocks/rnibReaderMock.go index 59c635e..20a7f0a 100644 --- a/E2Manager/mocks/rnibReaderMock.go +++ b/E2Manager/mocks/rnibReaderMock.go @@ -156,3 +156,8 @@ func (m *RnibReaderMock) GetE2TAddresses() ([]string, error) { args := m.Called() return args.Get(0).([]string), args.Error(1) } + +func (m *RnibReaderMock) GetGeneralConfiguration() (*entities.GeneralConfiguration, error) { + args := m.Called() + return args.Get(0).(*entities.GeneralConfiguration), args.Error(1) +} \ No newline at end of file diff --git a/E2Manager/mocks/rnibWriterMock.go b/E2Manager/mocks/rnibWriterMock.go index 5c602bb..3503d10 100644 --- a/E2Manager/mocks/rnibWriterMock.go +++ b/E2Manager/mocks/rnibWriterMock.go @@ -92,3 +92,14 @@ func (rnibWriterMock *RnibWriterMock) RemoveServedNrCells(inventoryName string, return args.Error(0) } +func (rnibWriterMock *RnibWriterMock) UpdateNodebInfoOnConnectionStatusInversion(nodebInfo *entities.NodebInfo, stateChangeMessageChannel string, event string) error { + args := rnibWriterMock.Called(nodebInfo, stateChangeMessageChannel, event) + + return args.Error(0) +} + +func (rnibWriterMock *RnibWriterMock) SaveGeneralConfiguration(config *entities.GeneralConfiguration) error { + args := rnibWriterMock.Called(config) + + return args.Error(0) +} \ No newline at end of file diff --git a/E2Manager/models/cause.go b/E2Manager/models/cause.go new file mode 100644 index 0000000..15cd7d6 --- /dev/null +++ b/E2Manager/models/cause.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). + +package models + +import "encoding/xml" + +type Cause struct { + XMLName xml.Name `xml:"Cause"` + Text string `xml:",chardata"` + RicRequest *CauseRic `xml:"ricRequest"` + RicService *CauseRicService `xml:"ricService"` + Transport *CauseTransport `xml:"transport"` + Protocol *CauseProtocol `xml:"protocol"` + Misc *CauseMisc `xml:"misc"` +} + +type CauseTransport struct { + Text string `xml:",chardata"` + TransportResourceUnavailable *struct{} `xml:"transport-resource-unavailable"` + Unspecified *struct{} `xml:"unspecified"` +} + +type CauseMisc struct { + Text string `xml:",chardata"` + ControlProcessingOverload *struct{} `xml:"control-processing-overload"` + HardwareFailure *struct{} `xml:"hardware-failure"` + OmIntervention *struct{} `xml:"om-intervention"` + Unspecified *struct{} `xml:"unspecified"` +} + +type CauseProtocol struct { + Text string `xml:",chardata"` + TransferSyntaxError *struct{} `xml:"transfer-syntax-error"` + AbstractSyntaxErrorReject *struct{} `xml:"abstract-syntax-error-reject"` + AbstractSyntaxErrorIgnoreAndNotify *struct{} `xml:"abstract-syntax-error-ignore-and-notify"` + MessageNotCompatibleWithReceiverState *struct{} `xml:"message-not-compatible-with-receiver-state"` + SemanticError *struct{} `xml:"semantic-error"` + AbstractSyntaxErrorFalselyConstructedMessage *struct{} `xml:"abstract-syntax-error-falsely-constructed-message"` + Unspecified *struct{} `xml:"unspecified"` +} + +type CauseRicService struct { + Text string `xml:",chardata"` + FunctionNotRequired *struct{} `xml:"function-not-required"` + ExcessiveFunctions *struct{} `xml:"excessive-functions"` + RicResourceLimit *struct{} `xml:"ric-resource-limit"` +} + +type CauseRic struct { + Text string `xml:",chardata"` + RanFunctionIdInvalid *struct{} `xml:"ran-function-id-Invalid"` + ActionNotSupported *struct{} `xml:"action-not-supported"` + ExcessiveActions *struct{} `xml:"excessive-actions"` + DuplicateAction *struct{} `xml:"duplicate-action"` + DuplicateEvent *struct{} `xml:"duplicate-event"` + FunctionResourceLimit *struct{} `xml:"function-resource-limit"` + RequestIdUnknown *struct{} `xml:"request-id-unknown"` + InconsistentActionSubsequentActionSequence *struct{} `xml:"inconsistent-action-subsequent-action-sequence"` + ControlMessageInvalid *struct{} `xml:"control-message-invalid"` + CallProcessIdInvalid *struct{} `xml:"call-process-id-invalid"` + Unspecified *struct{} `xml:"unspecified"` +} diff --git a/E2Manager/models/e2_setup_request_message.go b/E2Manager/models/e2_setup_request_message.go index 32d05ca..e61d498 100644 --- a/E2Manager/models/e2_setup_request_message.go +++ b/E2Manager/models/e2_setup_request_message.go @@ -21,10 +21,8 @@ package models import ( "encoding/xml" - "errors" - "fmt" "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" - "strconv" + "github.com/golang/protobuf/ptypes/wrappers" "strings" ) @@ -134,10 +132,119 @@ type E2SetupRequestMessage struct { } type RanFunctionItem struct { - Text string `xml:",chardata"` - RanFunctionID string `xml:"ranFunctionID"` - RanFunctionDefinition string `xml:"ranFunctionDefinition"` - RanFunctionRevision string `xml:"ranFunctionRevision"` + Text string `xml:",chardata"` + RanFunctionID uint32 `xml:"ranFunctionID"` + RanFunctionDefinition RanFunctionDefinition `xml:"ranFunctionDefinition"` + RanFunctionRevision uint32 `xml:"ranFunctionRevision"` +} + +type RanFunctionDefinition struct { + Text string `xml:",chardata"` + E2smGnbNrtRanFunctionDefinition E2smGnbNrtRanFunctionDefinition `xml:"E2SM-gNB-NRT-RANfunction-Definition"` +} + +type RanFunctionName struct { + Text string `xml:",chardata"` + RanFunctionShortName string `xml:"ranFunction-ShortName"` + RanFunctionE2smOid string `xml:"ranFunction-E2SM-OID"` + RanFunctionDescription string `xml:"ranFunction-Description"` + RanFunctionInstance *uint32 `xml:"ranFunction-Instance"` +} + +type RicEventTriggerStyleList struct { + Text string `xml:",chardata"` + RicEventTriggerStyleType uint32 `xml:"ric-EventTriggerStyle-Type"` + RicEventTriggerStyleName string `xml:"ric-EventTriggerStyle-Name"` + RicEventTriggerFormatType uint32 `xml:"ric-EventTriggerFormat-Type"` +} + +type RanParameterDefItem struct { + Text string `xml:",chardata"` + RanParameterID uint32 `xml:"ranParameter-ID"` + RanParameterName string `xml:"ranParameter-Name"` + RanParameterType RanParameterType `xml:"ranParameter-Type"` +} + +type RanParameterType struct { + Text string `xml:",chardata"` + Boolean *struct{} `xml:"boolean,omitempty"` + Integer *struct{} `xml:"integer,omitempty"` + Enumerated *struct{} `xml:"enumerated,omitempty"` + BitString *struct{} `xml:"bit-string,omitempty"` + OctetString *struct{} `xml:"octet-string,omitempty"` + PrintableString *struct{} `xml:"printable-string,omitempty"` +} + +type RicReportStyleList struct { + Text string `xml:",chardata"` + RicReportStyleType uint32 `xml:"ric-ReportStyle-Type"` + RicReportStyleName string `xml:"ric-ReportStyle-Name"` + RicReportActionFormatType uint32 `xml:"ric-ReportActionFormat-Type"` + RicReportRanParameterDefList struct { + Text string `xml:",chardata"` + RanParameterDefItem []RanParameterDefItem `xml:"RANparameterDef-Item"` + } `xml:"ric-ReportRanParameterDef-List"` + RicIndicationHeaderFormatType uint32 `xml:"ric-IndicationHeaderFormat-Type"` + RicIndicationMessageFormatType uint32 `xml:"ric-IndicationMessageFormat-Type"` +} + +type RicInsertStyleList struct { + Text string `xml:",chardata"` + RicInsertStyleType uint32 `xml:"ric-InsertStyle-Type"` + RicInsertStyleName string `xml:"ric-InsertStyle-Name"` + RicInsertActionFormatType uint32 `xml:"ric-InsertActionFormat-Type"` + RicInsertRanParameterDefList struct { + Text string `xml:",chardata"` + RanParameterDefItem []RanParameterDefItem `xml:"RANparameterDef-Item"` + } `xml:"ric-InsertRanParameterDef-List"` + RicIndicationHeaderFormatType uint32 `xml:"ric-IndicationHeaderFormat-Type"` + RicIndicationMessageFormatType uint32 `xml:"ric-IndicationMessageFormat-Type"` + RicCallProcessIdFormatType uint32 `xml:"ric-CallProcessIDFormat-Type"` +} + +type RicControlStyleList struct { + Text string `xml:",chardata"` + RicControlStyleType uint32 `xml:"ric-ControlStyle-Type"` + RicControlStyleName string `xml:"ric-ControlStyle-Name"` + RicControlHeaderFormatType uint32 `xml:"ric-ControlHeaderFormat-Type"` + RicControlMessageFormatType uint32 `xml:"ric-ControlMessageFormat-Type"` + RicCallProcessIdFormatType uint32 `xml:"ric-CallProcessIDFormat-Type"` +} + +type RicPolicyStyleList struct { + Text string `xml:",chardata"` + RicPolicyStyleType uint32 `xml:"ric-PolicyStyle-Type"` + RicPolicyStyleName string `xml:"ric-PolicyStyle-Name"` + RicPolicyActionFormatType uint32 `xml:"ric-PolicyActionFormat-Type"` + RicPolicyRanParameterDefList struct { + Text string `xml:",chardata"` + RanParameterDefItem []RanParameterDefItem `xml:"RANparameterDef-Item"` + } `xml:"ric-PolicyRanParameterDef-List"` +} + +type E2smGnbNrtRanFunctionDefinition struct { + Text string `xml:",chardata"` + RanFunctionName RanFunctionName `xml:"ranFunction-Name"` + RicEventTriggerStyleList struct { + Text string `xml:",chardata"` + RicEventTriggerStyleList []RicEventTriggerStyleList `xml:"RIC-EventTriggerStyle-List"` + } `xml:"ric-EventTriggerStyle-List"` + RicReportStyleList struct { + Text string `xml:",chardata"` + RicReportStyleList []RicReportStyleList `xml:"RIC-ReportStyle-List"` + } `xml:"ric-ReportStyle-List"` + RicInsertStyleList struct { + Text string `xml:",chardata"` + RicInsertStyleList []RicInsertStyleList `xml:"RIC-InsertStyle-List"` + } `xml:"ric-InsertStyle-List"` + RicControlStyleList struct { + Text string `xml:",chardata"` + RicControlStyleList []RicControlStyleList `xml:"RIC-ControlStyle-List"` + } `xml:"ric-ControlStyle-List"` + RicPolicyStyleList struct { + Text string `xml:",chardata"` + RicPolicyStyleList []RicPolicyStyleList `xml:"RIC-PolicyStyle-List"` + } `xml:"ric-PolicyStyle-List"` } type RANfunctionsList struct { @@ -156,54 +263,219 @@ type RANfunctionsList struct { } `xml:"ProtocolIE-SingleContainer"` } -func (m *E2SetupRequestMessage) ExtractRanFunctionsList() ([]*entities.RanFunction, error) { +func (m *E2SetupRequestMessage) ExtractRanFunctionsList() []*entities.RanFunction { + // TODO: verify e2SetupRequestIEs structure with Adi + e2SetupRequestIes := m.E2APPDU.InitiatingMessage.Value.E2setupRequest.ProtocolIEs.E2setupRequestIEs + if len(e2SetupRequestIes) < 2 { + return nil + } + + ranFunctionsListContainer := e2SetupRequestIes[1].Value.RANfunctionsList.ProtocolIESingleContainer + funcs := make([]*entities.RanFunction, len(ranFunctionsListContainer)) + for i := 0; i < len(funcs); i++ { + ranFunctionItem := ranFunctionsListContainer[i].Value.RANfunctionItem + + funcs[i] = &entities.RanFunction{ + RanFunctionId: &wrappers.UInt32Value{Value: ranFunctionItem.RanFunctionID}, + RanFunctionDefinition: m.buildRanFunctionDefinitionProto(&ranFunctionItem.RanFunctionDefinition), + RanFunctionRevision: &wrappers.UInt32Value{Value: ranFunctionItem.RanFunctionRevision}, + } + } + return funcs +} + +func (m *E2SetupRequestMessage) buildRanFunctionDefinitionProto(def *RanFunctionDefinition) *entities.RanFunctionDefinition { + return &entities.RanFunctionDefinition{ + E2SmGnbNrtRanFunctionDefinition: &entities.E2SmGnbNrtRanFunctionDefinition{ + RanFunctionName: buildRanFunctionNameProto(def), + RicEventTriggerStyles: buildRicEventTriggerStylesProto(def), + RicReportStyles: buildRicReportStylesProto(def), + RicInsertStyles: buildRicInsertStylesProto(def), + RicControlStyles: buildRicControlStylesProto(def), + RicPolicyStyles: buildRicPolicyStylesProto(def), + }, + } +} - setupRequestIes := m.E2APPDU.InitiatingMessage.Value.E2setupRequest.ProtocolIEs.E2setupRequestIEs +func buildRanFunctionNameProto(def *RanFunctionDefinition) *entities.RanFunctionName { + defRanFunctionName := def.E2smGnbNrtRanFunctionDefinition.RanFunctionName + ranFunctionName := &entities.RanFunctionName{ + RanFunctionShortName: &wrappers.StringValue{Value: defRanFunctionName.RanFunctionShortName}, + RanFunctionE2SmOid: &wrappers.StringValue{Value: defRanFunctionName.RanFunctionE2smOid}, + RanFunctionDescription: &wrappers.StringValue{Value: defRanFunctionName.RanFunctionDescription}, + } - if len(setupRequestIes) < 2 { - return nil, nil + if defRanFunctionName.RanFunctionInstance != nil { + ranFunctionName.OptionalRanFunctionInstance = &entities.RanFunctionName_RanFunctionInstance{ + RanFunctionInstance: *defRanFunctionName.RanFunctionInstance, + } } - list := setupRequestIes[1].Value.RANfunctionsList.ProtocolIESingleContainer - funcs := make([]*entities.RanFunction, len(list)) - for i := 0; i < len(funcs); i++ { - funcs[i] = &entities.RanFunction{} - id, err := strconv.ParseUint(list[i].Value.RANfunctionItem.RanFunctionID, 10, 32) - if err != nil { - return nil, errors.New(fmt.Sprintf("#e2_setup_request_message.ExtractRanFunctionsList - Failed parse uint RanFunctionID from %s", list[i].Value.RANfunctionItem.RanFunctionID)) + return ranFunctionName +} + +func buildRicEventTriggerStylesProto(def *RanFunctionDefinition) []*entities.RicEventTriggerStyle { + defRicEventTriggerStyleList := def.E2smGnbNrtRanFunctionDefinition.RicEventTriggerStyleList.RicEventTriggerStyleList + ricEventTriggerStyles := make([]*entities.RicEventTriggerStyle, len(defRicEventTriggerStyleList)) + + for i, v := range defRicEventTriggerStyleList { + ricEventTriggerStyles[i] = &entities.RicEventTriggerStyle{ + RicEventTriggerStyleType: &wrappers.UInt32Value{Value: v.RicEventTriggerStyleType}, + RicEventTriggerStyleName: &wrappers.StringValue{Value: v.RicEventTriggerStyleName}, + RicEventTriggerFormatType: &wrappers.UInt32Value{Value: v.RicEventTriggerFormatType}, } - funcs[i].RanFunctionId = uint32(id) - rev, err := strconv.ParseUint(list[i].Value.RANfunctionItem.RanFunctionRevision, 10, 32) - if err != nil { - return nil, errors.New(fmt.Sprintf("#e2_setup_request_message.ExtractRanFunctionsList - Failed parse uint RanFunctionRevision from %s", list[i].Value.RANfunctionItem.RanFunctionRevision)) + } + + return ricEventTriggerStyles +} + +func buildRicReportStylesProto(def *RanFunctionDefinition) []*entities.RicReportStyle { + defRicReportStyleList := def.E2smGnbNrtRanFunctionDefinition.RicReportStyleList.RicReportStyleList + ricReportStyles := make([]*entities.RicReportStyle, len(defRicReportStyleList)) + + for i, v := range defRicReportStyleList { + ricReportStyles[i] = &entities.RicReportStyle{ + RicReportStyleType: &wrappers.UInt32Value{Value: v.RicReportStyleType}, + RicReportStyleName: &wrappers.StringValue{Value: v.RicReportStyleName}, + RicReportActionFormatType: &wrappers.UInt32Value{Value: v.RicReportActionFormatType}, + RicReportRanParameterDefs: buildRicReportRanParameterDefsProto(v), + RicIndicationHeaderFormatType: &wrappers.UInt32Value{Value: v.RicIndicationHeaderFormatType}, + RicIndicationMessageFormatType: &wrappers.UInt32Value{Value: v.RicIndicationMessageFormatType}, } - funcs[i].RanFunctionDefinition = m.trimSpaces(list[i].Value.RANfunctionItem.RanFunctionDefinition) - funcs[i].RanFunctionRevision = uint32(rev) } - return funcs, nil + + return ricReportStyles +} + +func buildRicReportRanParameterDefsProto(ricReportStyleList RicReportStyleList) []*entities.RanParameterDef { + ricReportRanParameterDefList := ricReportStyleList.RicReportRanParameterDefList.RanParameterDefItem + ranParameterDefs := make([]*entities.RanParameterDef, len(ricReportRanParameterDefList)) + + for i, v := range ricReportRanParameterDefList { + ranParameterDefs[i] = &entities.RanParameterDef{ + RanParameterId: &wrappers.UInt32Value{Value: v.RanParameterID}, + RanParameterName: &wrappers.StringValue{Value: v.RanParameterName}, + RanParameterType: getRanParameterTypeEnumValue(v.RanParameterType), + } + } + + return ranParameterDefs +} + +func getRanParameterTypeEnumValue(ranParameterType RanParameterType) entities.RanParameterType { + if ranParameterType.Boolean != nil { + return entities.RanParameterType_BOOLEAN + } + + if ranParameterType.BitString != nil { + return entities.RanParameterType_BIT_STRING + } + + if ranParameterType.Enumerated != nil { + return entities.RanParameterType_ENUMERATED + } + + if ranParameterType.Integer != nil { + return entities.RanParameterType_INTEGER + } + + if ranParameterType.OctetString != nil { + return entities.RanParameterType_OCTET_STRING + } + + if ranParameterType.PrintableString != nil { + return entities.RanParameterType_PRINTABLE_STRING + } + + return entities.RanParameterType_UNKNOWN_RAN_PARAMETER_TYPE +} + +func buildRicInsertStylesProto(def *RanFunctionDefinition) []*entities.RicInsertStyle { + defRicInsertStyleList := def.E2smGnbNrtRanFunctionDefinition.RicInsertStyleList.RicInsertStyleList + ricInsertStyles := make([]*entities.RicInsertStyle, len(defRicInsertStyleList)) + + for i, v := range defRicInsertStyleList { + ricInsertStyles[i] = &entities.RicInsertStyle{ + RicInsertStyleType: &wrappers.UInt32Value{Value: v.RicInsertStyleType}, + RicInsertStyleName: &wrappers.StringValue{Value: v.RicInsertStyleName}, + RicInsertActionFormatType: &wrappers.UInt32Value{Value: v.RicInsertActionFormatType}, + RicInsertRanParameterDefs: buildRicInsertRanParameterDefsProto(v), + RicIndicationHeaderFormatType: &wrappers.UInt32Value{Value: v.RicIndicationHeaderFormatType}, + RicIndicationMessageFormatType: &wrappers.UInt32Value{Value: v.RicIndicationMessageFormatType}, + RicCallProcessIdFormatType: &wrappers.UInt32Value{Value: v.RicCallProcessIdFormatType}, + } + } + + return ricInsertStyles +} + +func buildRicInsertRanParameterDefsProto(ricInsertStyleList RicInsertStyleList) []*entities.RanParameterDef { + ricInsertRanParameterDefList := ricInsertStyleList.RicInsertRanParameterDefList.RanParameterDefItem + ranParameterDefs := make([]*entities.RanParameterDef, len(ricInsertRanParameterDefList)) + + for i, v := range ricInsertRanParameterDefList { + ranParameterDefs[i] = &entities.RanParameterDef{ + RanParameterId: &wrappers.UInt32Value{Value: v.RanParameterID}, + RanParameterName: &wrappers.StringValue{Value: v.RanParameterName}, + RanParameterType: getRanParameterTypeEnumValue(v.RanParameterType), + } + } + + return ranParameterDefs +} + +func buildRicControlStylesProto(def *RanFunctionDefinition) []*entities.RicControlStyle { + defRicControlStyleList := def.E2smGnbNrtRanFunctionDefinition.RicControlStyleList.RicControlStyleList + ricControlStyles := make([]*entities.RicControlStyle, len(defRicControlStyleList)) + + for i, v := range defRicControlStyleList { + ricControlStyles[i] = &entities.RicControlStyle{ + RicControlStyleType: &wrappers.UInt32Value{Value: v.RicControlStyleType}, + RicControlStyleName: &wrappers.StringValue{Value: v.RicControlStyleName}, + RicControlHeaderFormatType: &wrappers.UInt32Value{Value: v.RicControlHeaderFormatType}, + RicControlMessageFormatType: &wrappers.UInt32Value{Value: v.RicControlMessageFormatType}, + RicCallProcessIdFormatType: &wrappers.UInt32Value{Value: v.RicCallProcessIdFormatType}, + } + } + + return ricControlStyles +} + +func buildRicPolicyRanParameterDefsProto(ricPolicyStyleList RicPolicyStyleList) []*entities.RanParameterDef { + ricPolicyRanParameterDefList := ricPolicyStyleList.RicPolicyRanParameterDefList.RanParameterDefItem + ranParameterDefs := make([]*entities.RanParameterDef, len(ricPolicyRanParameterDefList)) + + for i, v := range ricPolicyRanParameterDefList { + ranParameterDefs[i] = &entities.RanParameterDef{ + RanParameterId: &wrappers.UInt32Value{Value: v.RanParameterID}, + RanParameterName: &wrappers.StringValue{Value: v.RanParameterName}, + RanParameterType: getRanParameterTypeEnumValue(v.RanParameterType), + } + } + + return ranParameterDefs +} + +func buildRicPolicyStylesProto(def *RanFunctionDefinition) []*entities.RicPolicyStyle { + defRicPolicyStyleList := def.E2smGnbNrtRanFunctionDefinition.RicPolicyStyleList.RicPolicyStyleList + ricPolicyStyles := make([]*entities.RicPolicyStyle, len(defRicPolicyStyleList)) + + for i, v := range defRicPolicyStyleList { + ricPolicyStyles[i] = &entities.RicPolicyStyle{ + RicPolicyStyleType: &wrappers.UInt32Value{Value: v.RicPolicyStyleType}, + RicPolicyStyleName: &wrappers.StringValue{Value: v.RicPolicyStyleName}, + RicPolicyActionFormatType: &wrappers.UInt32Value{Value: v.RicPolicyActionFormatType}, + RicPolicyRanParameterDefs: buildRicPolicyRanParameterDefsProto(v), + } + } + + return ricPolicyStyles } func (m *E2SetupRequestMessage) getGlobalE2NodeId() GlobalE2NodeId { return m.E2APPDU.InitiatingMessage.Value.E2setupRequest.ProtocolIEs.E2setupRequestIEs[0].Value.GlobalE2nodeID } -//func (m *E2SetupRequestMessage) GetNodeType() entities.Node_Type { -// globalE2NodeId := m.getGlobalE2NodeId() -// if id := globalE2NodeId.GNB.GlobalGNBID.PlmnID; id != "" { -// return entities.Node_GNB -// } -// if id := globalE2NodeId.EnGNB.GlobalGNBID.PlmnID; id != "" { -// return entities.Node_GNB -// } -// if id := globalE2NodeId.ENB.GlobalENBID.PlmnID; id != "" { -// return entities.Node_ENB -// } -// if id := globalE2NodeId.NgENB.GlobalNgENBID.PlmnID; id != "" { -// return entities.Node_ENB -// } -// return entities.Node_UNKNOWN -//} - func (m *E2SetupRequestMessage) GetPlmnId() string { globalE2NodeId := m.getGlobalE2NodeId() if id := globalE2NodeId.GNB.GlobalGNBID.PlmnID; id != "" { diff --git a/E2Manager/models/e2_setup_response_message.go b/E2Manager/models/e2_setup_response_message.go index 798f784..04d63a1 100644 --- a/E2Manager/models/e2_setup_response_message.go +++ b/E2Manager/models/e2_setup_response_message.go @@ -71,9 +71,9 @@ func NewE2SetupSuccessResponseMessage(plmnId string, ricId string, request *E2Se outcome := SuccessfulOutcome{} outcome.ProcedureCode = "1" - setupRequestIes := request.E2APPDU.InitiatingMessage.Value.E2setupRequest.ProtocolIEs.E2setupRequestIEs + e2SetupRequestIes := request.E2APPDU.InitiatingMessage.Value.E2setupRequest.ProtocolIEs.E2setupRequestIEs - outcome.Value.E2setupResponse.ProtocolIEs.E2setupResponseIEs = make([]E2setupResponseIEs, len(setupRequestIes)) + outcome.Value.E2setupResponse.ProtocolIEs.E2setupResponseIEs = make([]E2setupResponseIEs, len(e2SetupRequestIes)) outcome.Value.E2setupResponse.ProtocolIEs.E2setupResponseIEs[0].ID = "4" outcome.Value.E2setupResponse.ProtocolIEs.E2setupResponseIEs[0].Value = GlobalRICID{GlobalRICID: struct { Text string `xml:",chardata"` @@ -81,27 +81,25 @@ func NewE2SetupSuccessResponseMessage(plmnId string, ricId string, request *E2Se RicID string `xml:"ric-ID"` }{PLMNIdentity: plmnId, RicID: ricId}} - if len(setupRequestIes) < 2 { + if len(e2SetupRequestIes) < 2 { return E2SetupResponseMessage{E2APPDU: E2APPDU{Outcome: outcome}} } - functionsIdList := extractRanFunctionsIDList(request) - outcome.Value.E2setupResponse.ProtocolIEs.E2setupResponseIEs[1].ID = "9" outcome.Value.E2setupResponse.ProtocolIEs.E2setupResponseIEs[1].Value = RANfunctionsIDList{RANfunctionsIDList: struct { Text string `xml:",chardata"` ProtocolIESingleContainer []ProtocolIESingleContainer `xml:"ProtocolIE-SingleContainer"` - }{ProtocolIESingleContainer: functionsIdList}} - + }{ProtocolIESingleContainer: extractRanFunctionsIDList(request)}} return E2SetupResponseMessage{E2APPDU: E2APPDU{Outcome: outcome}} } -func NewE2SetupFailureResponseMessage(timeToWait TimeToWait) E2SetupResponseMessage { +func NewE2SetupFailureResponseMessage(timeToWait TimeToWait, cause Cause) E2SetupResponseMessage { outcome := UnsuccessfulOutcome{} outcome.Value.E2setupFailure.ProtocolIEs.E2setupFailureIEs = make([]E2setupFailureIEs, 2) outcome.ProcedureCode = "1" outcome.Value.E2setupFailure.ProtocolIEs.E2setupFailureIEs[0].ID = "1" - outcome.Value.E2setupFailure.ProtocolIEs.E2setupFailureIEs[0].Value.Value = Cause{} + + outcome.Value.E2setupFailure.ProtocolIEs.E2setupFailureIEs[0].Value.Value = cause outcome.Value.E2setupFailure.ProtocolIEs.E2setupFailureIEs[1].ID = "31" outcome.Value.E2setupFailure.ProtocolIEs.E2setupFailureIEs[1].Value.Value = timeToWaitMap[timeToWait] return E2SetupResponseMessage{E2APPDU: E2APPDU{Outcome: outcome}} @@ -177,8 +175,8 @@ type ProtocolIESingleContainer struct { Text string `xml:",chardata"` RANfunctionIDItem struct { Text string `xml:",chardata"` - RanFunctionID string `xml:"ranFunctionID"` - RanFunctionRevision string `xml:"ranFunctionRevision"` + RanFunctionID uint32 `xml:"ranFunctionID"` + RanFunctionRevision uint32 `xml:"ranFunctionRevision"` } `xml:"RANfunctionID-Item"` } `xml:"value"` } @@ -216,17 +214,7 @@ type E2setupFailureIEs struct { } `xml:"value"` } -type Cause struct { - XMLName xml.Name `xml:"Cause"` - Text string `xml:",chardata"` - Transport struct { - Text string `xml:",chardata"` - TransportResourceUnavailable string `xml:"transport-resource-unavailable"` - } `xml:"transport"` -} - func extractRanFunctionsIDList(request *E2SetupRequestMessage) []ProtocolIESingleContainer { - list := &request.E2APPDU.InitiatingMessage.Value.E2setupRequest.ProtocolIEs.E2setupRequestIEs[1].Value.RANfunctionsList ids := make([]ProtocolIESingleContainer, len(list.ProtocolIESingleContainer)) for i := 0; i < len(ids); i++ { diff --git a/E2Manager/models/general_configuration_request.go b/E2Manager/models/general_configuration_request.go new file mode 100644 index 0000000..5a642ad --- /dev/null +++ b/E2Manager/models/general_configuration_request.go @@ -0,0 +1,23 @@ +// +// 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 GeneralConfigurationRequest struct { + EnableRic bool `json:"enableRic"` +} diff --git a/E2Manager/models/general_configuration_response.go b/E2Manager/models/general_configuration_response.go new file mode 100644 index 0000000..f19761c --- /dev/null +++ b/E2Manager/models/general_configuration_response.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 + +import ( + "e2mgr/e2managererrors" + "encoding/json" +) + +type GeneralConfigurationResponse struct { + EnableRic bool `json:"enableRic"` +} + +func (response *GeneralConfigurationResponse) Marshal() ([]byte, error) { + + data, err := json.Marshal(response) + + if err != nil { + return nil, e2managererrors.NewInternalError() + } + + return data, nil +} \ No newline at end of file diff --git a/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider.go b/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider.go index f5572cd..9e45372 100644 --- a/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider.go +++ b/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider.go @@ -34,14 +34,15 @@ import ( type IncomingRequest string const ( - ShutdownRequest IncomingRequest = "Shutdown" - ResetRequest IncomingRequest = "Reset" - X2SetupRequest IncomingRequest = "X2SetupRequest" - EndcSetupRequest IncomingRequest = "EndcSetupRequest" - GetNodebRequest IncomingRequest = "GetNodebRequest" - GetNodebIdListRequest IncomingRequest = "GetNodebIdListRequest" - GetE2TInstancesRequest IncomingRequest = "GetE2TInstancesRequest" - UpdateGnbRequest IncomingRequest = "UpdateGnbRequest" + SetGeneralConfigurationRequest IncomingRequest = "SetGeneralConfiguration" + ShutdownRequest IncomingRequest = "Shutdown" + ResetRequest IncomingRequest = "Reset" + X2SetupRequest IncomingRequest = "X2SetupRequest" + EndcSetupRequest IncomingRequest = "EndcSetupRequest" + GetNodebRequest IncomingRequest = "GetNodebRequest" + GetNodebIdListRequest IncomingRequest = "GetNodebIdListRequest" + GetE2TInstancesRequest IncomingRequest = "GetE2TInstancesRequest" + UpdateGnbRequest IncomingRequest = "UpdateGnbRequest" ) type IncomingRequestHandlerProvider struct { @@ -60,14 +61,15 @@ func NewIncomingRequestHandlerProvider(logger *logger.Logger, rmrSender *rmrsend func initRequestHandlerMap(logger *logger.Logger, rmrSender *rmrsender.RmrSender, config *configuration.Configuration, rNibDataService services.RNibDataService, ranSetupManager *managers.RanSetupManager, e2tInstancesManager managers.IE2TInstancesManager, e2tAssociationManager *managers.E2TAssociationManager, rmClient clients.IRoutingManagerClient) map[IncomingRequest]httpmsghandlers.RequestHandler { return map[IncomingRequest]httpmsghandlers.RequestHandler{ - ShutdownRequest: httpmsghandlers.NewDeleteAllRequestHandler(logger, rmrSender, config, rNibDataService, e2tInstancesManager, rmClient), - ResetRequest: httpmsghandlers.NewX2ResetRequestHandler(logger, rmrSender, rNibDataService), - X2SetupRequest: httpmsghandlers.NewSetupRequestHandler(logger, rNibDataService, ranSetupManager, entities.E2ApplicationProtocol_X2_SETUP_REQUEST, e2tInstancesManager, e2tAssociationManager), - EndcSetupRequest: httpmsghandlers.NewSetupRequestHandler(logger, rNibDataService, ranSetupManager, entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, e2tInstancesManager, e2tAssociationManager), - GetNodebRequest: httpmsghandlers.NewGetNodebRequestHandler(logger, rNibDataService), - GetNodebIdListRequest: httpmsghandlers.NewGetNodebIdListRequestHandler(logger, rNibDataService), - GetE2TInstancesRequest: httpmsghandlers.NewGetE2TInstancesRequestHandler(logger, e2tInstancesManager), - UpdateGnbRequest: httpmsghandlers.NewUpdateGnbRequestHandler(logger, rNibDataService), + ShutdownRequest: httpmsghandlers.NewDeleteAllRequestHandler(logger, rmrSender, config, rNibDataService, e2tInstancesManager, rmClient), + ResetRequest: httpmsghandlers.NewX2ResetRequestHandler(logger, rmrSender, rNibDataService), + X2SetupRequest: httpmsghandlers.NewSetupRequestHandler(logger, rNibDataService, ranSetupManager, entities.E2ApplicationProtocol_X2_SETUP_REQUEST, e2tInstancesManager, e2tAssociationManager), + EndcSetupRequest: httpmsghandlers.NewSetupRequestHandler(logger, rNibDataService, ranSetupManager, entities.E2ApplicationProtocol_ENDC_X2_SETUP_REQUEST, e2tInstancesManager, e2tAssociationManager), + GetNodebRequest: httpmsghandlers.NewGetNodebRequestHandler(logger, rNibDataService), + GetNodebIdListRequest: httpmsghandlers.NewGetNodebIdListRequestHandler(logger, rNibDataService), + GetE2TInstancesRequest: httpmsghandlers.NewGetE2TInstancesRequestHandler(logger, e2tInstancesManager), + UpdateGnbRequest: httpmsghandlers.NewUpdateGnbRequestHandler(logger, rNibDataService), + SetGeneralConfigurationRequest: httpmsghandlers.NewSetGeneralConfigurationHandler(logger, rNibDataService), } } diff --git a/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider_test.go b/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider_test.go index e06105f..3a04f0b 100644 --- a/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider_test.go +++ b/E2Manager/providers/httpmsghandlerprovider/incoming_request_handler_provider_test.go @@ -78,6 +78,18 @@ func TestShutdownRequestHandler(t *testing.T) { assert.True(t, ok) } +func TestSetGeneralConfigurationHandler(t *testing.T) { + provider := setupTest(t) + handler, err := provider.GetHandler(SetGeneralConfigurationRequest) + + assert.NotNil(t, provider) + assert.Nil(t, err) + + _, ok := handler.(*httpmsghandlers.SetGeneralConfigurationHandler) + + assert.True(t, ok) +} + func TestX2SetupRequestHandler(t *testing.T) { provider := setupTest(t) handler, err := provider.GetHandler(X2SetupRequest) diff --git a/E2Manager/rNibWriter/rNibWriter.go b/E2Manager/rNibWriter/rNibWriter.go index a44f388..3186d70 100644 --- a/E2Manager/rNibWriter/rNibWriter.go +++ b/E2Manager/rNibWriter/rNibWriter.go @@ -45,6 +45,8 @@ type RNibWriter interface { RemoveE2TInstance(e2tAddress string) error UpdateGnbCells(nodebInfo *entities.NodebInfo, servedNrCells []*entities.ServedNRCell) error RemoveServedNrCells(inventoryName string, servedNrCells []*entities.ServedNRCell) error + UpdateNodebInfoOnConnectionStatusInversion(nodebInfo *entities.NodebInfo, stateChangeMessageChannel string, event string) error + SaveGeneralConfiguration(config *entities.GeneralConfiguration) error } /* @@ -67,6 +69,17 @@ func (w *rNibWriterInstance) RemoveServedNrCells(inventoryName string, servedNrC return nil } +func (w *rNibWriterInstance) SaveGeneralConfiguration(config *entities.GeneralConfiguration) error { + + err := w.SaveWithKeyAndMarshal(common.BuildGeneralConfigurationKey(), config) + + if err != nil { + return common.NewInternalError(err) + } + + return nil +} + /* SaveNodeb saves nodeB entity data in the redis DB according to the specified data model */ @@ -315,6 +328,46 @@ func (w *rNibWriterInstance) RemoveE2TInstance(address string) error { return nil } +func (w *rNibWriterInstance) SaveWithKeyAndMarshal(key string, entity interface{}) error { + + data, err := json.Marshal(entity) + + 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 +} + +/* +UpdateNodebInfoOnConnectionStatusInversion... +*/ +func (w *rNibWriterInstance) UpdateNodebInfoOnConnectionStatusInversion(nodebInfo *entities.NodebInfo, stateChangeMessageChannel string, event string) error { + + pairs, err := buildUpdateNodebInfoPairs(nodebInfo) + + if err != nil { + return err + } + + err = w.sdl.SetAndPublish([]string{stateChangeMessageChannel, event}, pairs) + + if err != nil { + return common.NewInternalError(err) + } + + return nil +} + /* Close the writer */ @@ -366,4 +419,4 @@ func appendGnbCells(inventoryName string, cells []*entities.ServedNRCell, pairs func isNotEmpty(nbIdentity *entities.NbIdentity) bool { return nbIdentity.GlobalNbId != nil && nbIdentity.GlobalNbId.PlmnId != "" && nbIdentity.GlobalNbId.NbId != "" -} +} \ No newline at end of file diff --git a/E2Manager/rNibWriter/rNibWriter_test.go b/E2Manager/rNibWriter/rNibWriter_test.go index 257bb85..ec21c3f 100644 --- a/E2Manager/rNibWriter/rNibWriter_test.go +++ b/E2Manager/rNibWriter/rNibWriter_test.go @@ -564,13 +564,12 @@ func TestSaveNilEntityFailure(t *testing.T) { func TestSaveUnknownTypeEntityFailure(t *testing.T) { 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{} nb.Port = 5656 nb.Ip = "localhost" actualErr := w.SaveNodeb(nbIdentity, nb) - assert.Equal(t, expectedErr, actualErr) + assert.IsType(t, &common.ValidationError{}, actualErr) } func TestSaveEntityFailure(t *testing.T) { @@ -743,6 +742,114 @@ func TestRemoveE2TInstanceEmptyAddressFailure(t *testing.T) { sdlInstanceMock.AssertExpectations(t) } +func TestUpdateNodebInfoOnConnectionStatusInversionSuccess(t *testing.T) { + inventoryName := "name" + plmnId := "02f829" + nbId := "4a952a0a" + channelName := "RAN_CONNECT_STATE_CHANGE" + eventName := inventoryName + "_" + "CONNECTED" + w, sdlInstanceMock := initSdlInstanceMock(namespace) + nodebInfo := generateNodebInfo(inventoryName, entities.Node_ENB, plmnId, nbId) + data, err := proto.Marshal(nodebInfo) + if err != nil { + t.Errorf("#rNibWriter_test.TestUpdateNodebInfoOnConnectionStatusInversionSuccess - Failed to marshal NodeB entity. Error: %v", err) + } + var e error + var setExpected []interface{} + + nodebNameKey := fmt.Sprintf("RAN:%s", inventoryName) + nodebIdKey := fmt.Sprintf("ENB:%s:%s", plmnId, nbId) + setExpected = append(setExpected, nodebNameKey, data) + setExpected = append(setExpected, nodebIdKey, data) + + sdlInstanceMock.On("SetAndPublish", []string{channelName, eventName}, []interface{}{setExpected}).Return(e) + + rNibErr := w.UpdateNodebInfoOnConnectionStatusInversion(nodebInfo, channelName, eventName) + assert.Nil(t, rNibErr) +} + +func TestUpdateNodebInfoOnConnectionStatusInversionMissingInventoryNameFailure(t *testing.T) { + inventoryName := "name" + plmnId := "02f829" + nbId := "4a952a0a" + channelName := "RAN_CONNECT_STATE_CHANGE" + eventName := inventoryName + "_" + "CONNECTED" + w, sdlInstanceMock := initSdlInstanceMock(namespace) + nodebInfo := &entities.NodebInfo{} + data, err := proto.Marshal(nodebInfo) + if err != nil { + t.Errorf("#rNibWriter_test.TestUpdateNodebInfoOnConnectionStatusInversionMissingInventoryNameFailure - Failed to marshal NodeB entity. Error: %v", err) + } + var e error + var setExpected []interface{} + + nodebNameKey := fmt.Sprintf("RAN:%s", inventoryName) + nodebIdKey := fmt.Sprintf("ENB:%s:%s", plmnId, nbId) + setExpected = append(setExpected, nodebNameKey, data) + setExpected = append(setExpected, nodebIdKey, data) + + sdlInstanceMock.On("SetAndPublish", []string{channelName, eventName}, []interface{}{setExpected}).Return(e) + + rNibErr := w.UpdateNodebInfoOnConnectionStatusInversion(nodebInfo, channelName, eventName) + + assert.NotNil(t, rNibErr) + assert.IsType(t, &common.ValidationError{}, rNibErr) +} + +func TestUpdateNodebInfoOnConnectionStatusInversionMissingGlobalNbId(t *testing.T) { + inventoryName := "name" + channelName := "RAN_CONNECT_STATE_CHANGE" + eventName := inventoryName + "_" + "CONNECTED" + w, sdlInstanceMock := initSdlInstanceMock(namespace) + nodebInfo := &entities.NodebInfo{} + nodebInfo.RanName = inventoryName + data, err := proto.Marshal(nodebInfo) + if err != nil { + t.Errorf("#rNibWriter_test.TestUpdateNodebInfoOnConnectionStatusInversionMissingInventoryNameFailure - Failed to marshal NodeB entity. Error: %v", err) + } + var e error + var setExpected []interface{} + + nodebNameKey := fmt.Sprintf("RAN:%s", inventoryName) + setExpected = append(setExpected, nodebNameKey, data) + sdlInstanceMock.On("SetAndPublish", []string{channelName, eventName}, []interface{}{setExpected}).Return(e) + + rNibErr := w.UpdateNodebInfoOnConnectionStatusInversion(nodebInfo, channelName, eventName) + + assert.Nil(t, rNibErr) +} + +func TestSaveGeneralConfiguration(t *testing.T) { + w, sdlInstanceMock := initSdlInstanceMock(namespace) + + key := common.BuildGeneralConfigurationKey() + configurationData := "{\"enableRic\":true}" + configuration := &entities.GeneralConfiguration{} + configuration.EnableRic = true + + sdlInstanceMock.On("Set",[]interface{}{[]interface{}{key, []byte(configurationData)}}).Return(nil) + rNibErr := w.SaveGeneralConfiguration(configuration) + + assert.Nil(t, rNibErr) + sdlInstanceMock.AssertExpectations(t) +} + +func TestSaveGeneralConfigurationDbError(t *testing.T) { + w, sdlInstanceMock := initSdlInstanceMock(namespace) + + key := common.BuildGeneralConfigurationKey() + configurationData := "{\"enableRic\":true}" + configuration := &entities.GeneralConfiguration{} + configuration.EnableRic = true + + expectedErr := errors.New("expected error") + + sdlInstanceMock.On("Set",[]interface{}{[]interface{}{key, []byte(configurationData)}}).Return(expectedErr) + rNibErr := w.SaveGeneralConfiguration(configuration) + + assert.NotNil(t, rNibErr) +} + //Integration tests // //func TestSaveEnbGnbInteg(t *testing.T){ @@ -762,7 +869,7 @@ func TestRemoveE2TInstanceEmptyAddressFailure(t *testing.T) { // nb.Configuration = &entities.NodebInfo_Enb{Enb:&enb} // plmnId := 0x02f828 // nbId := 0x4a952a0a -// nbIdentity := &entities.NbIdentity{InventoryName: fmt.Sprintf("nameEnb%d" ,i), GlobalNbId:&entities.GlobalNbId{PlmnId:fmt.Sprintf("%02x", plmnId + i), NbId:fmt.Sprintf("%02x", nbId + i)}} +// nbIdentity := &entities.NbIdentity{InventoryName: fmt.Sprintf("nameEnb%d" ,i), GlobalNbId:&entities.GlobalNbId{RicId:fmt.Sprintf("%02x", plmnId + i), NbId:fmt.Sprintf("%02x", nbId + i)}} // err := w.SaveNodeb(nbIdentity, &nb) // if err != nil{ // t.Errorf("#rNibWriter_test.TestSaveEnbInteg - Failed to save NodeB entity. Error: %v", err) @@ -779,7 +886,7 @@ func TestRemoveE2TInstanceEmptyAddressFailure(t *testing.T) { // gCell3 := &entities.ServedNRCell{ServedNrCellInformation:&entities.ServedNRCellInformation{CellId:fmt.Sprintf("%02x",3333 + i), NrPci:uint32(3 + i)}} // gnb.ServedNrCells = []*entities.ServedNRCell{gCell1, gCell2, gCell3,} // nb1.Configuration = &entities.NodebInfo_Gnb{Gnb:&gnb} -// nbIdentity = &entities.NbIdentity{InventoryName: fmt.Sprintf("nameGnb%d" ,i), GlobalNbId:&entities.GlobalNbId{PlmnId:fmt.Sprintf("%02x", plmnId - i), NbId:fmt.Sprintf("%02x", nbId - i)}} +// nbIdentity = &entities.NbIdentity{InventoryName: fmt.Sprintf("nameGnb%d" ,i), GlobalNbId:&entities.GlobalNbId{RicId:fmt.Sprintf("%02x", plmnId - i), NbId:fmt.Sprintf("%02x", nbId - i)}} // err = w.SaveNodeb(nbIdentity, &nb1) // if err != nil{ // t.Errorf("#rNibWriter_test.TestSaveEnbInteg - Failed to save NodeB entity. Error: %v", err) diff --git a/E2Manager/resources/configuration.yaml b/E2Manager/resources/configuration.yaml index d79565b..6beba8f 100644 --- a/E2Manager/resources/configuration.yaml +++ b/E2Manager/resources/configuration.yaml @@ -15,5 +15,7 @@ keepAliveResponseTimeoutMs: 4500 keepAliveDelayMs: 1500 e2tInstanceDeletionTimeoutMs: 15000 globalRicId: - plmnId: 131014 - ricNearRtId: 556670 \ No newline at end of file + ricId: "AACCE" + mcc: "310" + mnc: "411" +stateChangeMessageChannel: RAN_CONNECTION_STATUS_CHANGE \ No newline at end of file diff --git a/E2Manager/services/ran_alarm_service.go b/E2Manager/services/ran_alarm_service.go new file mode 100644 index 0000000..046b183 --- /dev/null +++ b/E2Manager/services/ran_alarm_service.go @@ -0,0 +1,47 @@ +// +// 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 services + +import ( + "e2mgr/configuration" + "e2mgr/logger" + "gerrit.o-ran-sc.org/r/ric-plt/nodeb-rnib.git/entities" +) + +type ranAlarmServiceInstance struct { + logger *logger.Logger + config *configuration.Configuration +} + +type RanAlarmService interface { + SetConnectivityChangeAlarm(nodebInfo *entities.NodebInfo) error +} + +func NewRanAlarmService(logger *logger.Logger, config *configuration.Configuration) RanAlarmService { + return &ranAlarmServiceInstance{ + logger: logger, + config: config, + } +} + +func (m *ranAlarmServiceInstance) SetConnectivityChangeAlarm(nodebInfo *entities.NodebInfo) error { + m.logger.Infof("#ranAlarmServiceInstance.SetConnectivityChangeAlarm - RAN name: %s - Connectivity state was changed to %s", nodebInfo.RanName, nodebInfo.ConnectionStatus) + return nil +} diff --git a/E2Manager/services/rnib_data_service.go b/E2Manager/services/rnib_data_service.go index 7235028..dbc9e29 100644 --- a/E2Manager/services/rnib_data_service.go +++ b/E2Manager/services/rnib_data_service.go @@ -49,23 +49,28 @@ type RNibDataService interface { RemoveE2TInstance(e2tAddress string) error UpdateGnbCells(nodebInfo *entities.NodebInfo, servedNrCells []*entities.ServedNRCell) error RemoveServedNrCells(inventoryName string, servedNrCells []*entities.ServedNRCell) error + GetGeneralConfiguration() (*entities.GeneralConfiguration, error) + UpdateNodebInfoOnConnectionStatusInversion(nodebInfo *entities.NodebInfo, event string) error + SaveGeneralConfiguration(config *entities.GeneralConfiguration) error } type rNibDataService struct { - logger *logger.Logger - rnibReader reader.RNibReader - rnibWriter rNibWriter.RNibWriter - maxAttempts int - retryInterval time.Duration + logger *logger.Logger + rnibReader reader.RNibReader + rnibWriter rNibWriter.RNibWriter + maxAttempts int + retryInterval time.Duration + stateChangeMessageChannel string } func NewRnibDataService(logger *logger.Logger, config *configuration.Configuration, rnibReader reader.RNibReader, rnibWriter rNibWriter.RNibWriter) *rNibDataService { return &rNibDataService{ - logger: logger, - rnibReader: rnibReader, - rnibWriter: rnibWriter, - 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, + stateChangeMessageChannel: config.StateChangeMessageChannel, } } @@ -269,6 +274,32 @@ func (w *rNibDataService) RemoveE2TInstance(e2tAddress string) error { return err } +func (w *rNibDataService) GetGeneralConfiguration() (*entities.GeneralConfiguration, error) { + var generalConfiguration *entities.GeneralConfiguration = nil + + err := w.retry("GetGeneralConfiguration", func() (err error) { + generalConfiguration, err = w.rnibReader.GetGeneralConfiguration() + return + }) + + if err == nil { + w.logger.Infof("#RnibDataService.GetGeneralConfiguration - enableRic: %t", generalConfiguration.EnableRic) + } + + return generalConfiguration, err +} + +func (w *rNibDataService) SaveGeneralConfiguration(config *entities.GeneralConfiguration) error { + w.logger.Infof("#RnibDataService.SaveGeneralConfiguration - configuration: %+v", *config) + + err := w.retry("SaveGeneralConfiguration", func() (err error) { + err = w.rnibWriter.SaveGeneralConfiguration(config) + return + }) + + return err +} + func (w *rNibDataService) PingRnib() bool { err := w.retry("GetListNodebIds", func() (err error) { _, err = w.rnibReader.GetListNodebIds() @@ -278,6 +309,17 @@ func (w *rNibDataService) PingRnib() bool { return !isRnibConnectionError(err) } +func (w *rNibDataService) UpdateNodebInfoOnConnectionStatusInversion(nodebInfo *entities.NodebInfo, event string) error { + w.logger.Infof("#RnibDataService.UpdateNodebInfoOnConnectionStatusInversion - nodebInfo: %s", nodebInfo) + + err := w.retry("UpdateNodebInfoOnConnectionStatusInversion", func() (err error) { + err = w.rnibWriter.UpdateNodebInfoOnConnectionStatusInversion(nodebInfo, w.stateChangeMessageChannel, event) + return + }) + + return err +} + func (w *rNibDataService) retry(rnibFunc string, f func() error) (err error) { attempts := w.maxAttempts diff --git a/E2Manager/services/rnib_data_service_test.go b/E2Manager/services/rnib_data_service_test.go index ab67a32..f6529e3 100644 --- a/E2Manager/services/rnib_data_service_test.go +++ b/E2Manager/services/rnib_data_service_test.go @@ -33,6 +33,8 @@ import ( "testing" ) +const CHANNEL_NAME = "channel" + func setupRnibDataServiceTest(t *testing.T) (*rNibDataService, *mocks.RnibReaderMock, *mocks.RnibWriterMock) { return setupRnibDataServiceTestWithMaxAttempts(t, 3) } @@ -43,7 +45,7 @@ func setupRnibDataServiceTestWithMaxAttempts(t *testing.T, maxAttempts int) (*rN t.Errorf("#... - failed to initialize logger, error: %s", err) } - config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: maxAttempts} + config := &configuration.Configuration{RnibRetryIntervalMs: 10, MaxRnibConnectionAttempts: maxAttempts, StateChangeMessageChannel: CHANNEL_NAME} readerMock := &mocks.RnibReaderMock{} @@ -257,6 +259,29 @@ func TestPingRnibOkOtherError(t *testing.T) { assert.True(t, res) } +func TestSuccessfulUpdateNodebInfoOnConnectionStatusInversion(t *testing.T) { + rnibDataService, _, writerMock := setupRnibDataServiceTest(t) + event := "event" + + nodebInfo := &entities.NodebInfo{} + writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", nodebInfo, CHANNEL_NAME, event).Return(nil) + + rnibDataService.UpdateNodebInfoOnConnectionStatusInversion(nodebInfo, event) + writerMock.AssertNumberOfCalls(t, "UpdateNodebInfoOnConnectionStatusInversion", 1) +} + +func TestConnFailureUpdateNodebInfoOnConnectionStatusInversion(t *testing.T) { + rnibDataService, _, writerMock := setupRnibDataServiceTest(t) + event := "event" + + nodebInfo := &entities.NodebInfo{} + mockErr := &common.InternalError{Err: &net.OpError{Err: fmt.Errorf("connection error")}} + writerMock.On("UpdateNodebInfoOnConnectionStatusInversion", nodebInfo, CHANNEL_NAME, event).Return(mockErr) + + rnibDataService.UpdateNodebInfoOnConnectionStatusInversion(nodebInfo, event) + writerMock.AssertNumberOfCalls(t, "UpdateNodebInfoOnConnectionStatusInversion", 3) +} + //func TestConnFailureThenSuccessGetNodebIdList(t *testing.T) { // rnibDataService, readerMock, _ := setupRnibDataServiceTest(t) // diff --git a/E2Manager/tests/dataProvider.go b/E2Manager/tests/dataProvider.go index dfa637e..0adf3f9 100644 --- a/E2Manager/tests/dataProvider.go +++ b/E2Manager/tests/dataProvider.go @@ -55,4 +55,4 @@ func GetHttpRequest() *http.Request { _ = json.NewEncoder(b).Encode(data) req, _ := http.NewRequest("POST", "https://localhost:3800/request", b) return req -} +} \ No newline at end of file diff --git a/E2Manager/tests/resources/setupRequest_gnb.xml b/E2Manager/tests/resources/setupRequest_gnb.xml index b947ae2..faf4fc2 100644 --- a/E2Manager/tests/resources/setupRequest_gnb.xml +++ b/E2Manager/tests/resources/setupRequest_gnb.xml @@ -1,68 +1 @@ - - - 1 - - - - - - - - 3 - - - - - - - - 13 10 14 - - 10011001101010101011 - - - - - - - - 10 - - - - - - - 8 - - - - - - 1 - 334455 - 0 - - - - - 8 - - - - - - 7 - 334455 - 0 - - - - - - - - - - - \ No newline at end of file +1302 F8 29 001100000011000000110000 1081 gNB-X2 1.3.6.1.4.1.28458.99.0.21.3.3.1.2 gNB X2 Network Interface 0 1 Message Type only 1 1 Complete message 1 1 AddTimestamp 1 1 1 Complete message 1 1 AddTimestamp 1 1 1 1 Complete message 1 1 1 182 gNB-NRT 1.3.6.1.4.1.28458.99.0.21.3.3.3.3 gNB Neighbour Relation Table 1 Notification 1 1 Complete table 1 1 AddTimestamp 1 1 1 NRT modification 1 1 0 183 gNB-X2 1.3.6.1.4.1.28458.99.0.21.3.3.1.2 gNB X2 Network Interface 1 1 Message Type only 1 1 Message Admission 2 1 QCI1 2 ARP1 3 SPID 4 U-TEID1 10 Load_offset 1 \ No newline at end of file -- 2.16.6